Browse code

avconv: Add an option for automatically rotating video according to display matrix

The option is enabled by default, but can be disabled.

If this is enabled, such side data isn't copied into the output stream
(except when doing stream copy).

Signed-off-by: Martin Storsjö <martin@martin.st>

Martin Storsjö authored on 2015/04/29 23:59:01
Showing 6 changed files
... ...
@@ -28,6 +28,7 @@ version <next>:
28 28
 - MMAL-accelerated H.264 decoding
29 29
 - DTS decoding through libdcadec
30 30
 - Canopus HQ/HQA decoder
31
+- Automatically rotate videos based on metadata in avconv
31 32
 
32 33
 
33 34
 version 11:
... ...
@@ -2433,6 +2433,8 @@ static int process_input(void)
2433 2433
 
2434 2434
             if (av_packet_get_side_data(&pkt, src_sd->type, NULL))
2435 2435
                 continue;
2436
+            if (ist->autorotate && src_sd->type == AV_PKT_DATA_DISPLAYMATRIX)
2437
+                continue;
2436 2438
 
2437 2439
             dst_data = av_packet_new_side_data(&pkt, src_sd->type, src_sd->size);
2438 2440
             if (!dst_data)
... ...
@@ -113,6 +113,8 @@ typedef struct OptionsContext {
113 113
     int        nb_hwaccels;
114 114
     SpecifierOpt *hwaccel_devices;
115 115
     int        nb_hwaccel_devices;
116
+    SpecifierOpt *autorotate;
117
+    int        nb_autorotate;
116 118
 
117 119
     /* output options */
118 120
     StreamMap *stream_maps;
... ...
@@ -236,6 +238,7 @@ typedef struct InputStream {
236 236
     AVDictionary *decoder_opts;
237 237
     AVRational framerate;               /* framerate forced with -r */
238 238
 
239
+    int autorotate;
239 240
     int resample_height;
240 241
     int resample_width;
241 242
     int resample_pix_fmt;
... ...
@@ -29,6 +29,7 @@
29 29
 #include "libavutil/avassert.h"
30 30
 #include "libavutil/avstring.h"
31 31
 #include "libavutil/channel_layout.h"
32
+#include "libavutil/display.h"
32 33
 #include "libavutil/opt.h"
33 34
 #include "libavutil/pixdesc.h"
34 35
 #include "libavutil/pixfmt.h"
... ...
@@ -226,6 +227,28 @@ static int insert_trim(int64_t start_time, int64_t duration,
226 226
     return 0;
227 227
 }
228 228
 
229
+static int insert_filter(AVFilterContext **last_filter, int *pad_idx,
230
+                         const char *filter_name, const char *args)
231
+{
232
+    AVFilterGraph *graph = (*last_filter)->graph;
233
+    AVFilterContext *ctx;
234
+    int ret;
235
+
236
+    ret = avfilter_graph_create_filter(&ctx,
237
+                                       avfilter_get_by_name(filter_name),
238
+                                       filter_name, args, NULL, graph);
239
+    if (ret < 0)
240
+        return ret;
241
+
242
+    ret = avfilter_link(*last_filter, *pad_idx, ctx, 0);
243
+    if (ret < 0)
244
+        return ret;
245
+
246
+    *last_filter = ctx;
247
+    *pad_idx     = 0;
248
+    return 0;
249
+}
250
+
229 251
 static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
230 252
 {
231 253
     char *pix_fmts;
... ...
@@ -446,6 +469,26 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
446 446
         return ret;
447 447
     last_filter = ifilter->filter;
448 448
 
449
+    if (ist->autorotate) {
450
+        uint8_t* displaymatrix = av_stream_get_side_data(ist->st,
451
+                                                         AV_PKT_DATA_DISPLAYMATRIX, NULL);
452
+        if (displaymatrix) {
453
+            double rot = av_display_rotation_get((int32_t*) displaymatrix);
454
+            if (rot < -135 || rot > 135) {
455
+                ret = insert_filter(&last_filter, &pad_idx, "vflip", NULL);
456
+                if (ret < 0)
457
+                    return ret;
458
+                ret = insert_filter(&last_filter, &pad_idx, "hflip", NULL);
459
+            } else if (rot < -45) {
460
+                ret = insert_filter(&last_filter, &pad_idx, "transpose", "dir=clock");
461
+            } else if (rot > 45) {
462
+                ret = insert_filter(&last_filter, &pad_idx, "transpose", "dir=cclock");
463
+            }
464
+            if (ret < 0)
465
+                return ret;
466
+        }
467
+    }
468
+
449 469
     if (ist->framerate.num) {
450 470
         AVFilterContext *setpts;
451 471
 
... ...
@@ -488,6 +488,9 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
488 488
         ist->ts_scale = 1.0;
489 489
         MATCH_PER_STREAM_OPT(ts_scale, dbl, ist->ts_scale, ic, st);
490 490
 
491
+        ist->autorotate = 1;
492
+        MATCH_PER_STREAM_OPT(autorotate, i, ist->autorotate, ic, st);
493
+
491 494
         MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, ic, st);
492 495
         if (codec_tag) {
493 496
             uint32_t tag = strtol(codec_tag, &next, 0);
... ...
@@ -2372,6 +2375,9 @@ const OptionDef options[] = {
2372 2372
     { "hwaccel_device",   OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT |
2373 2373
                           OPT_SPEC | OPT_INPUT,                                  { .off = OFFSET(hwaccel_devices) },
2374 2374
         "select a device for HW acceleration" "devicename" },
2375
+    { "autorotate",       HAS_ARG | OPT_BOOL | OPT_SPEC |
2376
+                          OPT_EXPERT | OPT_INPUT,                                { .off = OFFSET(autorotate) },
2377
+        "automatically insert correct rotate filters" },
2375 2378
 
2376 2379
     /* audio options */
2377 2380
     { "aframes",        OPT_AUDIO | HAS_ARG  | OPT_PERFILE | OPT_OUTPUT,           { .func_arg = opt_audio_frames },
... ...
@@ -401,6 +401,9 @@ Technical note -- attachments are implemented as codec extradata, so this
401 401
 option can actually be used to extract extradata from any stream, not just
402 402
 attachments.
403 403
 
404
+@item -noautorotate
405
+Disable automatically rotating video based on file metadata.
406
+
404 407
 @end table
405 408
 
406 409
 @section Video Options