[PATCH] ffplay: support rotated video.
Trolled-by: Linus Torvalds --- doc/ffplay.texi | 4 ++++ ffplay.c | 47 +++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/doc/ffplay.texi b/doc/ffplay.texi index c26c68d..d73eadb 100644 --- a/doc/ffplay.texi +++ b/doc/ffplay.texi @@ -159,6 +159,10 @@ Force a specific video decoder. @item -scodec @var{codec_name} Force a specific subtitle decoder. + +@item -autorotate +Automatically rotate the video according to presentation metadata. Set by +default, use -noautorotate to disable. @end table @section While playing diff --git a/ffplay.c b/ffplay.c index 86b9126..520b337 100644 --- a/ffplay.c +++ b/ffplay.c @@ -327,6 +327,7 @@ static int cursor_hidden = 0; static char *vfilters = NULL; static char *afilters = NULL; #endif +static int autorotate = 1; /* current context */ static int is_full_screen; @@ -1773,7 +1774,7 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c char sws_flags_str[128]; char buffersrc_args[256]; int ret; - AVFilterContext *filt_src = NULL, *filt_out = NULL, *filt_crop; + AVFilterContext *filt_src = NULL, *filt_out = NULL, *last_filter = NULL; AVCodecContext *codec = is->video_st->codec; AVRational fr = av_guess_frame_rate(is->ic, is->video_st, NULL); @@ -1804,16 +1805,45 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c if ((ret = av_opt_set_int_list(filt_out, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0) goto fail; + last_filter = filt_out; + +#define INSERT_FILT(name, arg) do { \ + AVFilterContext *filt_ctx; \ + \ + ret = avfilter_graph_create_filter(&filt_ctx, \ + avfilter_get_by_name(name), \ + "ffplay_" name, arg, NULL, graph); \ + if (ret < 0) \ + goto fail; \ + \ + ret = avfilter_link(filt_ctx, 0, last_filter, 0); \ + if (ret < 0) \ + goto fail; \ + \ + last_filter = filt_ctx; \ +} while (0) + /* SDL YUV code is not handling odd width/height for some driver * combinations, therefore we crop the picture to an even width/height. */ - if ((ret = avfilter_graph_create_filter(&filt_crop, - avfilter_get_by_name("crop"), - "ffplay_crop", "floor(in_w/2)*2:floor(in_h/2)*2", NULL, graph)) < 0) - goto fail; - if ((ret = avfilter_link(filt_crop, 0, filt_out, 0)) < 0) - goto fail; + INSERT_FILT("crop", "floor(in_w/2)*2:floor(in_h/2)*2"); + + if (autorotate) { + AVDictionaryEntry *rotate_tag = av_dict_get(is->video_st->metadata, "rotate", NULL, 0); + if (rotate_tag) { + if (!strcmp(rotate_tag->value, "90")) { + INSERT_FILT("transpose", "1"); + } else if (!strcmp(rotate_tag->value, "180")) { + INSERT_FILT("hflip", NULL); + INSERT_FILT("vflip", NULL); + } else if (!strcmp(rotate_tag->value, "270")) { + INSERT_FILT("transpose", "2"); + } else { + INSERT_FILT("rotate", rotate_tag->value); + } + } + } - if ((ret = configure_filtergraph(graph, vfilters, filt_src, filt_crop)) < 0) + if ((ret = configure_filtergraph(graph, vfilters, filt_src, last_filter)) < 0) goto fail; is->in_video_filter = filt_src; @@ -3527,6 +3557,7 @@ static const OptionDef options[] = { { "acodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &audio_codec_name }, "force audio decoder", "decoder_name" }, { "scodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &subtitle_codec_name }, "force subtitle decoder", "decoder_name" }, { "vcodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &video_codec_name }, "force video decoder", "decoder_name" }, + { "autorotate", OPT_BOOL, { &autorotate }, "automatically rotate video", "" }, { NULL, }, }; -- 1.9.2
On Fri, Apr 18, 2014 at 11:15:54PM +0200, Clément Bœsch wrote:
Trolled-by: Linus Torvalds
(Context: https://plus.google.com/+LinusTorvalds/posts/H9oSRqwSfaM) [...]
+ if (autorotate) { + AVDictionaryEntry *rotate_tag = av_dict_get(is->video_st->metadata, "rotate", NULL, 0); + if (rotate_tag) { + if (!strcmp(rotate_tag->value, "90")) {
+ INSERT_FILT("transpose", "1");
"1" locally changed to "clock"
+ } else if (!strcmp(rotate_tag->value, "180")) { + INSERT_FILT("hflip", NULL); + INSERT_FILT("vflip", NULL); + } else if (!strcmp(rotate_tag->value, "270")) {
"2" locally changed to "cclock"
+ INSERT_FILT("transpose", "2"); + } else { + INSERT_FILT("rotate", rotate_tag->value); + } + } + } [...]
-- Clément B.
----- Original Message ----- From: "Clément Bosch" <u@pkh.me> To: <ffmpeg-devel@ffmpeg.org> Cc: "Clément Bosch" <u@pkh.me> Sent: Friday, April 18, 2014 5:15 PM Subject: [FFmpeg-devel] [PATCH] ffplay: support rotated video.
Trolled-by: Linus Torvalds --- doc/ffplay.texi | 4 ++++ ffplay.c | 47 +++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 43 insertions(+), 8 deletions(-)
diff --git a/doc/ffplay.texi b/doc/ffplay.texi index c26c68d..d73eadb 100644 --- a/doc/ffplay.texi +++ b/doc/ffplay.texi @@ -159,6 +159,10 @@ Force a specific video decoder.
@item -scodec @var{codec_name} Force a specific subtitle decoder. + +@item -autorotate +Automatically rotate the video according to presentation metadata. Set by +default, use -noautorotate to disable. @end table
@section While playing diff --git a/ffplay.c b/ffplay.c index 86b9126..520b337 100644 --- a/ffplay.c +++ b/ffplay.c @@ -327,6 +327,7 @@ static int cursor_hidden = 0; static char *vfilters = NULL; static char *afilters = NULL; #endif +static int autorotate = 1;
/* current context */ static int is_full_screen; @@ -1773,7 +1774,7 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c char sws_flags_str[128]; char buffersrc_args[256]; int ret; - AVFilterContext *filt_src = NULL, *filt_out = NULL, *filt_crop; + AVFilterContext *filt_src = NULL, *filt_out = NULL, *last_filter = NULL; AVCodecContext *codec = is->video_st->codec; AVRational fr = av_guess_frame_rate(is->ic, is->video_st, NULL);
@@ -1804,16 +1805,45 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c if ((ret = av_opt_set_int_list(filt_out, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0) goto fail;
+ last_filter = filt_out; + +#define INSERT_FILT(name, arg) do { \ + AVFilterContext *filt_ctx; \ + \ + ret = avfilter_graph_create_filter(&filt_ctx, \ + avfilter_get_by_name(name), \ + "ffplay_" name, arg, NULL, graph); \ + if (ret < 0) \ + goto fail; \ + \ + ret = avfilter_link(filt_ctx, 0, last_filter, 0); \ + if (ret < 0) \ + goto fail; \ + \ + last_filter = filt_ctx; \ +} while (0) + /* SDL YUV code is not handling odd width/height for some driver * combinations, therefore we crop the picture to an even width/height. */ - if ((ret = avfilter_graph_create_filter(&filt_crop, - avfilter_get_by_name("crop"), - "ffplay_crop", "floor(in_w/2)*2:floor(in_h/2)*2", NULL, graph)) < 0) - goto fail; - if ((ret = avfilter_link(filt_crop, 0, filt_out, 0)) < 0) - goto fail; + INSERT_FILT("crop", "floor(in_w/2)*2:floor(in_h/2)*2"); + + if (autorotate) { + AVDictionaryEntry *rotate_tag = av_dict_get(is->video_st->metadata, "rotate", NULL, 0); + if (rotate_tag) { + if (!strcmp(rotate_tag->value, "90")) { + INSERT_FILT("transpose", "1"); + } else if (!strcmp(rotate_tag->value, "180")) { + INSERT_FILT("hflip", NULL); + INSERT_FILT("vflip", NULL); + } else if (!strcmp(rotate_tag->value, "270")) { + INSERT_FILT("transpose", "2"); + } else { + INSERT_FILT("rotate", rotate_tag->value); + } + } + }
you might want to do this instead of stcmp. Catches values greater than 360 as well. int rotate = atoi(rotate_tag->value) % 360;
- if ((ret = configure_filtergraph(graph, vfilters, filt_src, filt_crop)) < 0) + if ((ret = configure_filtergraph(graph, vfilters, filt_src, last_filter)) < 0) goto fail;
is->in_video_filter = filt_src; @@ -3527,6 +3557,7 @@ static const OptionDef options[] = { { "acodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &audio_codec_name }, "force audio decoder", "decoder_name" }, { "scodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &subtitle_codec_name }, "force subtitle decoder", "decoder_name" }, { "vcodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &video_codec_name }, "force video decoder", "decoder_name" }, + { "autorotate", OPT_BOOL, { &autorotate }, "automatically rotate video", "" }, { NULL, }, };
-- 1.9.2
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
On Fri, Apr 18, 2014 at 05:43:35PM -0400, Don Moir wrote: [...]
+ if (autorotate) { + AVDictionaryEntry *rotate_tag = av_dict_get(is->video_st->metadata, "rotate", NULL, 0); + if (rotate_tag) { + if (!strcmp(rotate_tag->value, "90")) { + INSERT_FILT("transpose", "1"); + } else if (!strcmp(rotate_tag->value, "180")) { + INSERT_FILT("hflip", NULL); + INSERT_FILT("vflip", NULL); + } else if (!strcmp(rotate_tag->value, "270")) { + INSERT_FILT("transpose", "2"); + } else { + INSERT_FILT("rotate", rotate_tag->value); + } + } + }
you might want to do this instead of stcmp. Catches values greater than 360 as well.
int rotate = atoi(rotate_tag->value) % 360;
No I can't, it can be a floating value. [...] -- Clément B.
On Tue, May 20, 2014 at 07:54:05PM +0200, Clément Bœsch wrote:
On Fri, Apr 18, 2014 at 05:43:35PM -0400, Don Moir wrote: [...]
+ if (autorotate) { + AVDictionaryEntry *rotate_tag = av_dict_get(is->video_st->metadata, "rotate", NULL, 0); + if (rotate_tag) { + if (!strcmp(rotate_tag->value, "90")) { + INSERT_FILT("transpose", "1"); + } else if (!strcmp(rotate_tag->value, "180")) { + INSERT_FILT("hflip", NULL); + INSERT_FILT("vflip", NULL); + } else if (!strcmp(rotate_tag->value, "270")) { + INSERT_FILT("transpose", "2"); + } else { + INSERT_FILT("rotate", rotate_tag->value); + } + } + }
you might want to do this instead of stcmp. Catches values greater than 360 as well.
int rotate = atoi(rotate_tag->value) % 360;
No I can't, it can be a floating value.
fmod() could be used [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB Frequently ignored answer#1 FFmpeg bugs should be sent to our bugtracker. User questions about the command line tools should be sent to the ffmpeg-user ML. And questions about how to use libav* should be sent to the libav-user ML.
On Wed, May 21, 2014 at 05:18:30AM +0200, Michael Niedermayer wrote:
On Tue, May 20, 2014 at 07:54:05PM +0200, Clément Bœsch wrote:
On Fri, Apr 18, 2014 at 05:43:35PM -0400, Don Moir wrote: [...]
+ if (autorotate) { + AVDictionaryEntry *rotate_tag = av_dict_get(is->video_st->metadata, "rotate", NULL, 0); + if (rotate_tag) { + if (!strcmp(rotate_tag->value, "90")) { + INSERT_FILT("transpose", "1"); + } else if (!strcmp(rotate_tag->value, "180")) { + INSERT_FILT("hflip", NULL); + INSERT_FILT("vflip", NULL); + } else if (!strcmp(rotate_tag->value, "270")) { + INSERT_FILT("transpose", "2"); + } else { + INSERT_FILT("rotate", rotate_tag->value); + } + } + }
you might want to do this instead of stcmp. Catches values greater than 360 as well.
int rotate = atoi(rotate_tag->value) % 360;
No I can't, it can be a floating value.
fmod() could be used
Right, but I'm not sure it would be more reliable/simple that what i'm currently proposing. -- Clément B.
On Thu, May 22, 2014 at 09:30:05PM +0200, Clément Bœsch wrote:
On Wed, May 21, 2014 at 05:18:30AM +0200, Michael Niedermayer wrote:
On Tue, May 20, 2014 at 07:54:05PM +0200, Clément Bœsch wrote:
On Fri, Apr 18, 2014 at 05:43:35PM -0400, Don Moir wrote: [...]
+ if (autorotate) { + AVDictionaryEntry *rotate_tag = av_dict_get(is->video_st->metadata, "rotate", NULL, 0); + if (rotate_tag) { + if (!strcmp(rotate_tag->value, "90")) { + INSERT_FILT("transpose", "1"); + } else if (!strcmp(rotate_tag->value, "180")) { + INSERT_FILT("hflip", NULL); + INSERT_FILT("vflip", NULL); + } else if (!strcmp(rotate_tag->value, "270")) { + INSERT_FILT("transpose", "2"); + } else { + INSERT_FILT("rotate", rotate_tag->value); + } + } + }
you might want to do this instead of stcmp. Catches values greater than 360 as well.
int rotate = atoi(rotate_tag->value) % 360;
No I can't, it can be a floating value.
fmod() could be used
Right, but I'm not sure it would be more reliable/simple that what i'm currently proposing.
no objections, fmod() was just an idea ... [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB Into a blind darkness they enter who follow after the Ignorance, they as if into a greater darkness enter who devote themselves to the Knowledge alone. -- Isha Upanishad
On Thu, May 22, 2014 at 09:30:05PM +0200, Clément B?sch wrote:
On Wed, May 21, 2014 at 05:18:30AM +0200, Michael Niedermayer wrote:
On Tue, May 20, 2014 at 07:54:05PM +0200, Clément B?sch wrote:
On Fri, Apr 18, 2014 at 05:43:35PM -0400, Don Moir wrote: [...]
+ if (autorotate) { + AVDictionaryEntry *rotate_tag = av_dict_get(is->video_st->metadata, "rotate", NULL, 0); + if (rotate_tag) { + if (!strcmp(rotate_tag->value, "90")) { + INSERT_FILT("transpose", "1"); + } else if (!strcmp(rotate_tag->value, "180")) { + INSERT_FILT("hflip", NULL); + INSERT_FILT("vflip", NULL); + } else if (!strcmp(rotate_tag->value, "270")) { + INSERT_FILT("transpose", "2"); + } else { + INSERT_FILT("rotate", rotate_tag->value); + } + } + }
you might want to do this instead of stcmp. Catches values greater than 360 as well.
int rotate = atoi(rotate_tag->value) % 360;
No I can't, it can be a floating value.
fmod() could be used
Right, but I'm not sure it would be more reliable/simple that what i'm currently proposing.
Not sure if it matters if its floating or not. atoi ("180.0") equates to 180 if that is what you are refering to. With what you have a filter gets inserted for anything your logic does not understand including zero rotate. doing a mod on it catches zero easily and anything >= 360. Probably not a big deal except the inserting of filter for possible zero rotate value.
----- Original Message ----- From: "Don Moir" <donmoir@comcast.net> To: "FFmpeg development discussions and patches" <ffmpeg-devel@ffmpeg.org> Sent: Friday, May 23, 2014 12:40 AM Subject: Re: [FFmpeg-devel] [PATCH] ffplay: support rotated video. On Thu, May 22, 2014 at 09:30:05PM +0200, Clément B?sch wrote:
On Wed, May 21, 2014 at 05:18:30AM +0200, Michael Niedermayer wrote:
On Tue, May 20, 2014 at 07:54:05PM +0200, Clément B?sch wrote:
On Fri, Apr 18, 2014 at 05:43:35PM -0400, Don Moir wrote: [...]
+ if (autorotate) { + AVDictionaryEntry *rotate_tag = av_dict_get(is->video_st->metadata, "rotate", NULL, 0); + if (rotate_tag) { + if (!strcmp(rotate_tag->value, "90")) { + INSERT_FILT("transpose", "1"); + } else if (!strcmp(rotate_tag->value, "180")) { + INSERT_FILT("hflip", NULL); + INSERT_FILT("vflip", NULL); + } else if (!strcmp(rotate_tag->value, "270")) { + INSERT_FILT("transpose", "2"); + } else { + INSERT_FILT("rotate", rotate_tag->value); + } + } + }
you might want to do this instead of stcmp. Catches values greater than 360 as well.
int rotate = atoi(rotate_tag->value) % 360;
No I can't, it can be a floating value.
fmod() could be used
Right, but I'm not sure it would be more reliable/simple that what i'm currently proposing.
Not sure if it matters if its floating or not.
atoi ("180.0") equates to 180 if that is what you are refering to.
With what you have a filter gets inserted for anything your logic does not understand including zero rotate. doing a mod on it catches zero easily and anything >= 360. Probably not a big deal except the inserting of filter for possible zero rotate value.
I guess what you are saying it might be something like "90.5" or something. Could be one degree off. Not sure it would display where someone would notice a one degree difference. Can it be radians and how would you know that? Do you have a video with an odd rotate value ?
On Fri, May 23, 2014 at 12:52:42AM -0400, Don Moir wrote:
----- Original Message ----- From: "Don Moir" <donmoir@comcast.net> To: "FFmpeg development discussions and patches" <ffmpeg-devel@ffmpeg.org> Sent: Friday, May 23, 2014 12:40 AM Subject: Re: [FFmpeg-devel] [PATCH] ffplay: support rotated video.
On Thu, May 22, 2014 at 09:30:05PM +0200, Clément B?sch wrote:
On Wed, May 21, 2014 at 05:18:30AM +0200, Michael Niedermayer wrote:
On Tue, May 20, 2014 at 07:54:05PM +0200, Clément B?sch wrote:
On Fri, Apr 18, 2014 at 05:43:35PM -0400, Don Moir wrote: [...]
+ if (autorotate) { + AVDictionaryEntry *rotate_tag = av_dict_get(is->video_st->metadata, "rotate", NULL, 0); + if (rotate_tag) { + if (!strcmp(rotate_tag->value, "90")) { + INSERT_FILT("transpose", "1"); + } else if (!strcmp(rotate_tag->value, "180")) { + INSERT_FILT("hflip", NULL); + INSERT_FILT("vflip", NULL); + } else if (!strcmp(rotate_tag->value, "270")) { + INSERT_FILT("transpose", "2"); + } else { + INSERT_FILT("rotate", rotate_tag->value); + } + } + }
you might want to do this instead of stcmp. Catches values greater than 360 as well.
int rotate = atoi(rotate_tag->value) % 360;
No I can't, it can be a floating value.
fmod() could be used
Right, but I'm not sure it would be more reliable/simple that what i'm currently proposing.
Not sure if it matters if its floating or not.
atoi ("180.0") equates to 180 if that is what you are refering to.
With what you have a filter gets inserted for anything your logic does not understand including zero rotate. doing a mod on it catches zero easily and anything >= 360. Probably not a big deal except the inserting of filter for possible zero rotate value.
I guess what you are saying it might be something like "90.5" or something.
Yes. 90.999 would raise 90 too unless you round btw.
Could be one degree off. Not sure it would display where someone would notice a one degree difference.
There is no reason to drop that accuracy. The orientation matrix in MOV has a relatively high one, there is no reason to drop it just to save 3 strcmp on 2-3 characters called only once at the beginning of the program.
Can it be radians and how would you know that?
See the other thread where I sent the updated patchset. It should answer all your questions.
Do you have a video with an odd rotate value ?
Not yet, but it's almost free to deal with that. 90, 180, and 270 cases are just exception, and I don't want to catch them because of an inaccuracy. It's more complex to write a matrix leading to 90.1 degrees than 90 degrees, so there is no reason to rotate 90 instead of 90.1 in that situation. -- Clément B.
I guess what you are saying it might be something like "90.5" or something.
Yes. 90.999 would raise 90 too unless you round btw.
Could be one degree off. Not sure it would display where someone would notice a one degree difference.
There is no reason to drop that accuracy. The orientation matrix in MOV has a relatively high one, there is no reason to drop it just to save 3 strcmp on 2-3 characters called only once at the beginning of the program.
Thanks for your explanation and not arguing about the strcmp. I was not aware it could have fractional degrees. Now that I do though, I probably am still going to drop that fraction. I doubt it makes a difference but I might just see what it does if I add a fractional degree to it like .99. Maybe you could also fake it in the code to see what kind of difference it might make. Not sure why a video would have a fractional degree unless it was a bug. Just trying to be clear on it and dealing with width height display issues etc.
Can it be radians and how would you know that?
See the other thread where I sent the updated patchset. It should answer all your questions.
Do you have a video with an odd rotate value ?
Not yet, but it's almost free to deal with that. 90, 180, and 270 cases are just exception, and I don't want to catch them because of an inaccuracy.
It's more complex to write a matrix leading to 90.1 degrees than 90 degrees, so there is no reason to rotate 90 instead of 90.1 in that situation.
I think this is mis-stated. Almost free for 90 degree and more complex for 90.1 so no reason to rotate 90 instead of 90.1?
On Fri, May 23, 2014 at 02:40:35AM -0400, Don Moir wrote:
I guess what you are saying it might be something like "90.5" or something.
Yes. 90.999 would raise 90 too unless you round btw.
Could be one degree off. Not sure it would display where someone would notice a one degree difference.
There is no reason to drop that accuracy. The orientation matrix in MOV has a relatively high one, there is no reason to drop it just to save 3 strcmp on 2-3 characters called only once at the beginning of the program.
Thanks for your explanation and not arguing about the strcmp. I was not aware it could have fractional degrees. Now that I do though, I probably am still going to drop that fraction. I doubt it makes a difference but I might just see what it does if I add a fractional degree to it like .99. Maybe you could also fake it in the code to see what kind of difference it might make.
Not sure why a video would have a fractional degree unless it was a bug. Just trying to be clear on it and dealing with width height display issues etc.
Well, if the format has an orientation matrix with enough precision to say "this video stream should be rotated by 90.954123113 degrees" then it probably means that, otherwise the format would just have contained 2 bits for the 4 combinations of 0, 90, 180 and 270 degrees. You want to see the difference? Well, try ffplay -f lavfi testsrc -vf rotate="90.999*PI/180" I wonder why you are arguing so much for dropping that precision. And no I won't make that code rotate by 90 when the format says 90.0001 unless it's stated in the specifications. -- Clément B.
I wonder why you are arguing so much for dropping that precision. And no I won't make that code rotate by 90 when the format says 90.0001 unless it's stated in the specifications.
Not so much as arguing but discussing. I am thinking of possible float inacurracy that produced the fraction so I may need to deal with that better. Thanks though. I do appreicate your response.
On Fri, 18 Apr 2014, Clément Bœsch wrote:
Trolled-by: Linus Torvalds --- doc/ffplay.texi | 4 ++++ ffplay.c | 47 +++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 43 insertions(+), 8 deletions(-)
diff --git a/doc/ffplay.texi b/doc/ffplay.texi index c26c68d..d73eadb 100644 --- a/doc/ffplay.texi +++ b/doc/ffplay.texi @@ -159,6 +159,10 @@ Force a specific video decoder.
@item -scodec @var{codec_name} Force a specific subtitle decoder. + +@item -autorotate +Automatically rotate the video according to presentation metadata. Set by +default, use -noautorotate to disable. @end table
@section While playing diff --git a/ffplay.c b/ffplay.c index 86b9126..520b337 100644 --- a/ffplay.c +++ b/ffplay.c @@ -327,6 +327,7 @@ static int cursor_hidden = 0; static char *vfilters = NULL; static char *afilters = NULL; #endif +static int autorotate = 1;
/* current context */ static int is_full_screen; @@ -1773,7 +1774,7 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c char sws_flags_str[128]; char buffersrc_args[256]; int ret; - AVFilterContext *filt_src = NULL, *filt_out = NULL, *filt_crop; + AVFilterContext *filt_src = NULL, *filt_out = NULL, *last_filter = NULL; AVCodecContext *codec = is->video_st->codec; AVRational fr = av_guess_frame_rate(is->ic, is->video_st, NULL);
@@ -1804,16 +1805,45 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c if ((ret = av_opt_set_int_list(filt_out, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0) goto fail;
+ last_filter = filt_out; + +#define INSERT_FILT(name, arg) do { \
I think a comment would be useful describing that this actually adds a filter before the lastly added filter, so the processing order of the filters will be in reverse...
+ AVFilterContext *filt_ctx; \ + \ + ret = avfilter_graph_create_filter(&filt_ctx, \ + avfilter_get_by_name(name), \ + "ffplay_" name, arg, NULL, graph); \ + if (ret < 0) \ + goto fail; \ + \ + ret = avfilter_link(filt_ctx, 0, last_filter, 0); \ + if (ret < 0) \ + goto fail; \ + \ + last_filter = filt_ctx; \ +} while (0) + /* SDL YUV code is not handling odd width/height for some driver * combinations, therefore we crop the picture to an even width/height. */ - if ((ret = avfilter_graph_create_filter(&filt_crop, - avfilter_get_by_name("crop"), - "ffplay_crop", "floor(in_w/2)*2:floor(in_h/2)*2", NULL, graph)) < 0) - goto fail; - if ((ret = avfilter_link(filt_crop, 0, filt_out, 0)) < 0) - goto fail; + INSERT_FILT("crop", "floor(in_w/2)*2:floor(in_h/2)*2"); + + if (autorotate) { + AVDictionaryEntry *rotate_tag = av_dict_get(is->video_st->metadata, "rotate", NULL, 0); + if (rotate_tag) { + if (!strcmp(rotate_tag->value, "90")) { + INSERT_FILT("transpose", "1"); + } else if (!strcmp(rotate_tag->value, "180")) { + INSERT_FILT("hflip", NULL); + INSERT_FILT("vflip", NULL); + } else if (!strcmp(rotate_tag->value, "270")) { + INSERT_FILT("transpose", "2"); + } else {
You may want to check if the rotation is zero or emtpy string and not insert a filter in that case.
+ INSERT_FILT("rotate", rotate_tag->value); + } + } + }
- if ((ret = configure_filtergraph(graph, vfilters, filt_src, filt_crop)) < 0) + if ((ret = configure_filtergraph(graph, vfilters, filt_src, last_filter)) < 0) goto fail;
is->in_video_filter = filt_src; @@ -3527,6 +3557,7 @@ static const OptionDef options[] = { { "acodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &audio_codec_name }, "force audio decoder", "decoder_name" }, { "scodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &subtitle_codec_name }, "force subtitle decoder", "decoder_name" }, { "vcodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &video_codec_name }, "force video decoder", "decoder_name" }, + { "autorotate", OPT_BOOL, { &autorotate }, "automatically rotate video", "" }, { NULL, }, };
The used filters should be added to ffplay_select in configure. Regards, Marton
On Sat, Apr 19, 2014 at 12:15:50AM +0200, Marton Balint wrote: [...]
+ last_filter = filt_out; + +#define INSERT_FILT(name, arg) do { \
I think a comment would be useful describing that this actually adds a filter before the lastly added filter, so the processing order of the filters will be in reverse...
Added.
+ AVFilterContext *filt_ctx; \ + \ + ret = avfilter_graph_create_filter(&filt_ctx, \ + avfilter_get_by_name(name), \ + "ffplay_" name, arg, NULL, graph); \ + if (ret < 0) \ + goto fail; \ + \ + ret = avfilter_link(filt_ctx, 0, last_filter, 0); \ + if (ret < 0) \ + goto fail; \ + \ + last_filter = filt_ctx; \ +} while (0) + /* SDL YUV code is not handling odd width/height for some driver * combinations, therefore we crop the picture to an even width/height. */ - if ((ret = avfilter_graph_create_filter(&filt_crop, - avfilter_get_by_name("crop"), - "ffplay_crop", "floor(in_w/2)*2:floor(in_h/2)*2", NULL, graph)) < 0) - goto fail; - if ((ret = avfilter_link(filt_crop, 0, filt_out, 0)) < 0) - goto fail; + INSERT_FILT("crop", "floor(in_w/2)*2:floor(in_h/2)*2"); + + if (autorotate) { + AVDictionaryEntry *rotate_tag = av_dict_get(is->video_st->metadata, "rotate", NULL, 0); + if (rotate_tag) { + if (!strcmp(rotate_tag->value, "90")) { + INSERT_FILT("transpose", "1"); + } else if (!strcmp(rotate_tag->value, "180")) { + INSERT_FILT("hflip", NULL); + INSERT_FILT("vflip", NULL); + } else if (!strcmp(rotate_tag->value, "270")) { + INSERT_FILT("transpose", "2"); + } else {
You may want to check if the rotation is zero or emtpy string and not insert a filter in that case.
Added.
+ INSERT_FILT("rotate", rotate_tag->value); + } + } + }
- if ((ret = configure_filtergraph(graph, vfilters, filt_src, filt_crop)) < 0) + if ((ret = configure_filtergraph(graph, vfilters, filt_src, last_filter)) < 0) goto fail;
is->in_video_filter = filt_src; @@ -3527,6 +3557,7 @@ static const OptionDef options[] = { { "acodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &audio_codec_name }, "force audio decoder", "decoder_name" }, { "scodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &subtitle_codec_name }, "force subtitle decoder", "decoder_name" }, { "vcodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &video_codec_name }, "force video decoder", "decoder_name" }, + { "autorotate", OPT_BOOL, { &autorotate }, "automatically rotate video", "" }, { NULL, }, };
The used filters should be added to ffplay_select in configure.
Added. New patchset incoming, thanks. -- Clément B.
participants (4)
-
Clément Bœsch -
Don Moir -
Marton Balint -
Michael Niedermayer