diff options
-rw-r--r-- | doc/ffmpeg.texi | 26 | ||||
-rw-r--r-- | fftools/ffmpeg.h | 6 | ||||
-rw-r--r-- | fftools/ffmpeg_opt.c | 50 | ||||
-rw-r--r-- | tests/fate/filter-video.mak | 2 |
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 |