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>
... | ... |
@@ -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 |