summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/ffmpeg.texi26
-rw-r--r--fftools/ffmpeg.h6
-rw-r--r--fftools/ffmpeg_opt.c50
-rw-r--r--tests/fate/filter-video.mak2
4 files changed, 83 insertions, 1 deletions
diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi
index e9020b30d5..0367930a3b 100644
--- a/doc/ffmpeg.texi
+++ b/doc/ffmpeg.texi
@@ -912,6 +912,32 @@ If used together with @option{-vcodec copy}, it will affect the aspect ratio
stored at container level, but not the aspect ratio stored in encoded
frames, if it exists.
+@item -display_rotation[:@var{stream_specifier}] @var{rotation} (@emph{input,per-stream})
+Set video rotation metadata.
+
+@var{rotation} is a decimal number specifying the amount in degree by
+which the video should be rotated counter-clockwise before being
+displayed.
+
+This option overrides the rotation/display transform metadata stored in
+the file, if any. When the video is being transcoded (rather than
+copied) and @code{-autorotate} is enabled, the video will be rotated at
+the filtering stage. Otherwise, the metadata will be written into the
+output file if the muxer supports it.
+
+If the @code{-display_hflip} and/or @code{-display_vflip} options are
+given, they are applied after the rotation specified by this option.
+
+@item -display_hflip[:@var{stream_specifier}] (@emph{input,per-stream})
+Set whether on display the image should be horizontally flipped.
+
+See the @code{-display_rotation} option for more details.
+
+@item -display_vflip[:@var{stream_specifier}] (@emph{input,per-stream})
+Set whether on display the image should be vertically flipped.
+
+See the @code{-display_rotation} option for more details.
+
@item -vn (@emph{input/output})
As an input option, blocks all video streams of a file from being filtered or
being automatically selected or mapped for any output. See @code{-discard}
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 91c5cfa3ab..13a2100439 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -194,6 +194,12 @@ typedef struct OptionsContext {
int nb_force_fps;
SpecifierOpt *frame_aspect_ratios;
int nb_frame_aspect_ratios;
+ SpecifierOpt *display_rotations;
+ int nb_display_rotations;
+ SpecifierOpt *display_hflips;
+ int nb_display_hflips;
+ SpecifierOpt *display_vflips;
+ int nb_display_vflips;
SpecifierOpt *rc_overrides;
int nb_rc_overrides;
SpecifierOpt *intra_matrices;
diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
index 7fdbf08a18..ead4ee1b38 100644
--- a/fftools/ffmpeg_opt.c
+++ b/fftools/ffmpeg_opt.c
@@ -20,6 +20,7 @@
#include "config.h"
+#include <float.h>
#include <stdint.h>
#if HAVE_SYS_RESOURCE_H
@@ -44,6 +45,7 @@
#include "libavutil/avutil.h"
#include "libavutil/bprint.h"
#include "libavutil/channel_layout.h"
+#include "libavutil/display.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/fifo.h"
#include "libavutil/mathematics.h"
@@ -66,6 +68,9 @@ static const char *const opt_name_fix_sub_duration[] = {"fix_sub_durati
static const char *const opt_name_canvas_sizes[] = {"canvas_size", NULL};
static const char *const opt_name_guess_layout_max[] = {"guess_layout_max", NULL};
static const char *const opt_name_discard[] = {"discard", NULL};
+static const char *const opt_name_display_rotations[] = {"display_rotation", NULL};
+static const char *const opt_name_display_hflips[] = {"display_hflip", NULL};
+static const char *const opt_name_display_vflips[] = {"display_vflip", NULL};
HWDevice *filter_hw_device;
@@ -595,6 +600,39 @@ static int opt_recording_timestamp(void *optctx, const char *opt, const char *ar
return 0;
}
+static void add_display_matrix_to_stream(OptionsContext *o,
+ AVFormatContext *ctx, AVStream *st)
+{
+ double rotation = DBL_MAX;
+ int hflip = -1, vflip = -1;
+ int hflip_set = 0, vflip_set = 0, rotation_set = 0;
+ int32_t *buf;
+
+ MATCH_PER_STREAM_OPT(display_rotations, dbl, rotation, ctx, st);
+ MATCH_PER_STREAM_OPT(display_hflips, i, hflip, ctx, st);
+ MATCH_PER_STREAM_OPT(display_vflips, i, vflip, ctx, st);
+
+ rotation_set = rotation != DBL_MAX;
+ hflip_set = hflip != -1;
+ vflip_set = vflip != -1;
+
+ if (!rotation_set && !hflip_set && !vflip_set)
+ return;
+
+ buf = (int32_t *)av_stream_new_side_data(st, AV_PKT_DATA_DISPLAYMATRIX, sizeof(int32_t) * 9);
+ if (!buf) {
+ av_log(NULL, AV_LOG_FATAL, "Failed to generate a display matrix!\n");
+ exit_program(1);
+ }
+
+ av_display_rotation_set(buf,
+ rotation_set ? -(rotation) : -0.0f);
+
+ av_display_matrix_flip(buf,
+ hflip_set ? hflip : 0,
+ vflip_set ? vflip : 0);
+}
+
const AVCodec *find_codec_or_die(const char *name, enum AVMediaType type, int encoder)
{
const AVCodecDescriptor *desc;
@@ -729,6 +767,8 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
}
if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
+ add_display_matrix_to_stream(o, ic, st);
+
MATCH_PER_STREAM_OPT(hwaccels, str, hwaccel, ic, st);
MATCH_PER_STREAM_OPT(hwaccel_output_formats, str,
hwaccel_output_format, ic, st);
@@ -2127,6 +2167,16 @@ const OptionDef options[] = {
{ "pix_fmt", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_STRING | OPT_SPEC |
OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(frame_pix_fmts) },
"set pixel format", "format" },
+ { "display_rotation", OPT_VIDEO | HAS_ARG | OPT_DOUBLE | OPT_SPEC |
+ OPT_INPUT, { .off = OFFSET(display_rotations) },
+ "set pure counter-clockwise rotation in degrees for stream(s)",
+ "angle" },
+ { "display_hflip", OPT_VIDEO | OPT_BOOL | OPT_SPEC | OPT_INPUT, { .off = OFFSET(display_hflips) },
+ "set display horizontal flip for stream(s) "
+ "(overrides any display rotation if it is not set)"},
+ { "display_vflip", OPT_VIDEO | OPT_BOOL | OPT_SPEC | OPT_INPUT, { .off = OFFSET(display_vflips) },
+ "set display vertical flip for stream(s) "
+ "(overrides any display rotation if it is not set)"},
{ "vn", OPT_VIDEO | OPT_BOOL | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT,{ .off = OFFSET(video_disable) },
"disable video" },
{ "rc_override", OPT_VIDEO | HAS_ARG | OPT_EXPERT | OPT_STRING | OPT_SPEC |
diff --git a/tests/fate/filter-video.mak b/tests/fate/filter-video.mak
index 372c70bba7..f3c27ed1c8 100644
--- a/tests/fate/filter-video.mak
+++ b/tests/fate/filter-video.mak
@@ -691,7 +691,7 @@ fate-filter-metadata-avf-aphase-meter-out-of-phase: SRC = $(TARGET_SAMPLES)/filt
fate-filter-metadata-avf-aphase-meter-out-of-phase: CMD = run $(FILTER_METADATA_COMMAND) "amovie='$(SRC)',aphasemeter=video=0"
FATE_FILTER_SAMPLES-$(call TRANSCODE, RAWVIDEO H264, MOV, ARESAMPLE_FILTER AAC_FIXED_DECODER) += fate-filter-meta-4560-rotate0
-fate-filter-meta-4560-rotate0: CMD = transcode mov $(TARGET_SAMPLES)/filter/sample-in-issue-505.mov mov "-c copy -metadata:s:v:0 rotate=0" "-af aresample" "" "" "-flags +bitexact -c:a aac_fixed"
+fate-filter-meta-4560-rotate0: CMD = transcode "mov -display_rotation:v:0 0" $(TARGET_SAMPLES)/filter/sample-in-issue-505.mov mov "-c copy" "-af aresample" "" "" "-flags +bitexact -c:a aac_fixed"
FATE_FILTER_CMP_METADATA-$(CONFIG_BLOCKDETECT_FILTER) += fate-filter-refcmp-blockdetect-yuv
fate-filter-refcmp-blockdetect-yuv: CMD = cmp_metadata blockdetect yuv420p 0.015