summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changelog1
-rw-r--r--doc/ffmpeg.texi3
-rw-r--r--ffmpeg.c2
-rw-r--r--ffmpeg.h3
-rw-r--r--ffmpeg_filter.c43
-rw-r--r--ffmpeg_opt.c6
6 files changed, 58 insertions, 0 deletions
diff --git a/Changelog b/Changelog
index 02dd77b235..623d10ade1 100644
--- a/Changelog
+++ b/Changelog
@@ -18,6 +18,7 @@ version <next>:
- nvenc level and tier options
- chorus filter
- Canopus HQ/HQA decoder
+- Automatically rotate videos based on metadata in ffmpeg
version 2.6:
diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi
index c66cb16d64..7cd81b080a 100644
--- a/doc/ffmpeg.texi
+++ b/doc/ffmpeg.texi
@@ -462,6 +462,9 @@ Technical note -- attachments are implemented as codec extradata, so this
option can actually be used to extract extradata from any stream, not just
attachments.
+@item -noautorotate
+Disable automatically rotating video based on file metadata.
+
@end table
@section Video Options
diff --git a/ffmpeg.c b/ffmpeg.c
index 7e5b16d0ec..8c288ae366 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -3647,6 +3647,8 @@ static int process_input(int file_index)
if (av_packet_get_side_data(&pkt, src_sd->type, NULL))
continue;
+ if (ist->autorotate && src_sd->type == AV_PKT_DATA_DISPLAYMATRIX)
+ continue;
dst_data = av_packet_new_side_data(&pkt, src_sd->type, src_sd->size);
if (!dst_data)
diff --git a/ffmpeg.h b/ffmpeg.h
index 71061daff6..800bd0ab0e 100644
--- a/ffmpeg.h
+++ b/ffmpeg.h
@@ -122,6 +122,8 @@ typedef struct OptionsContext {
int nb_hwaccels;
SpecifierOpt *hwaccel_devices;
int nb_hwaccel_devices;
+ SpecifierOpt *autorotate;
+ int nb_autorotate;
/* output options */
StreamMap *stream_maps;
@@ -276,6 +278,7 @@ typedef struct InputStream {
int top_field_first;
int guess_layout_max;
+ int autorotate;
int resample_height;
int resample_width;
int resample_pix_fmt;
diff --git a/ffmpeg_filter.c b/ffmpeg_filter.c
index 264840b2e9..6a891d3d10 100644
--- a/ffmpeg_filter.c
+++ b/ffmpeg_filter.c
@@ -31,6 +31,7 @@
#include "libavutil/avstring.h"
#include "libavutil/bprint.h"
#include "libavutil/channel_layout.h"
+#include "libavutil/display.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
#include "libavutil/pixfmt.h"
@@ -339,6 +340,28 @@ static int insert_trim(int64_t start_time, int64_t duration,
return 0;
}
+static int insert_filter(AVFilterContext **last_filter, int *pad_idx,
+ const char *filter_name, const char *args)
+{
+ AVFilterGraph *graph = (*last_filter)->graph;
+ AVFilterContext *ctx;
+ int ret;
+
+ ret = avfilter_graph_create_filter(&ctx,
+ avfilter_get_by_name(filter_name),
+ filter_name, args, NULL, graph);
+ if (ret < 0)
+ return ret;
+
+ ret = avfilter_link(*last_filter, *pad_idx, ctx, 0);
+ if (ret < 0)
+ return ret;
+
+ *last_filter = ctx;
+ *pad_idx = 0;
+ return 0;
+}
+
static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
{
char *pix_fmts;
@@ -676,6 +699,26 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
return ret;
last_filter = ifilter->filter;
+ if (ist->autorotate) {
+ uint8_t* displaymatrix = av_stream_get_side_data(ist->st,
+ AV_PKT_DATA_DISPLAYMATRIX, NULL);
+ if (displaymatrix) {
+ double rot = av_display_rotation_get((int32_t*) displaymatrix);
+ if (rot < -135 || rot > 135) {
+ ret = insert_filter(&last_filter, &pad_idx, "vflip", NULL);
+ if (ret < 0)
+ return ret;
+ ret = insert_filter(&last_filter, &pad_idx, "hflip", NULL);
+ } else if (rot < -45) {
+ ret = insert_filter(&last_filter, &pad_idx, "transpose", "dir=clock");
+ } else if (rot > 45) {
+ ret = insert_filter(&last_filter, &pad_idx, "transpose", "dir=cclock");
+ }
+ if (ret < 0)
+ return ret;
+ }
+ }
+
if (ist->framerate.num) {
AVFilterContext *setpts;
diff --git a/ffmpeg_opt.c b/ffmpeg_opt.c
index 75c80e792e..f59b93bba6 100644
--- a/ffmpeg_opt.c
+++ b/ffmpeg_opt.c
@@ -602,6 +602,9 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
ist->ts_scale = 1.0;
MATCH_PER_STREAM_OPT(ts_scale, dbl, ist->ts_scale, ic, st);
+ ist->autorotate = 1;
+ MATCH_PER_STREAM_OPT(autorotate, i, ist->autorotate, ic, st);
+
MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, ic, st);
if (codec_tag) {
uint32_t tag = strtol(codec_tag, &next, 0);
@@ -3069,6 +3072,9 @@ const OptionDef options[] = {
#if HAVE_VDPAU_X11
{ "vdpau_api_ver", HAS_ARG | OPT_INT | OPT_EXPERT, { &vdpau_api_ver }, "" },
#endif
+ { "autorotate", HAS_ARG | OPT_BOOL | OPT_SPEC |
+ OPT_EXPERT | OPT_INPUT, { .off = OFFSET(autorotate) },
+ "automatically insert correct rotate filters" },
/* audio options */
{ "aframes", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_audio_frames },