Commit 08c51e12 authored by Clément Bœsch's avatar Clément Bœsch

ffplay: support rotated video.

with -f lavfi -i testsrc=s=hd1080 as source:
  rotate=90*PI/180  vs transpose=clock:   42fps -> 64fps
  rotate=180*PI/180 vs vflip,hflip:       75fps -> 77fps
  rotate=270*PI/180 vs transpose=cclock:  43fps -> 63fps
parent e63a17bf
...@@ -2565,7 +2565,7 @@ ffmpeg_select="aformat_filter anull_filter atrim_filter format_filter ...@@ -2565,7 +2565,7 @@ ffmpeg_select="aformat_filter anull_filter atrim_filter format_filter
setpts_filter trim_filter" setpts_filter trim_filter"
ffplay_deps="avcodec avformat swscale swresample sdl" ffplay_deps="avcodec avformat swscale swresample sdl"
ffplay_libs='$sdl_libs' ffplay_libs='$sdl_libs'
ffplay_select="rdft crop_filter" ffplay_select="rdft crop_filter transpose_filter hflip_filter vflip_filter rotate_filter"
ffprobe_deps="avcodec avformat" ffprobe_deps="avcodec avformat"
ffserver_deps="avformat fork sarestart" ffserver_deps="avformat fork sarestart"
ffserver_select="ffm_muxer rtp_protocol rtsp_demuxer" ffserver_select="ffm_muxer rtp_protocol rtsp_demuxer"
......
...@@ -162,6 +162,10 @@ Force a specific video decoder. ...@@ -162,6 +162,10 @@ Force a specific video decoder.
@item -scodec @var{codec_name} @item -scodec @var{codec_name}
Force a specific subtitle decoder. Force a specific subtitle decoder.
@item -autorotate
Automatically rotate the video according to presentation metadata. Set by
default, use -noautorotate to disable.
@end table @end table
@section While playing @section While playing
......
...@@ -329,6 +329,7 @@ static const char **vfilters_list = NULL; ...@@ -329,6 +329,7 @@ static const char **vfilters_list = NULL;
static int nb_vfilters = 0; static int nb_vfilters = 0;
static char *afilters = NULL; static char *afilters = NULL;
#endif #endif
static int autorotate = 1;
/* current context */ /* current context */
static int is_full_screen; static int is_full_screen;
...@@ -1784,7 +1785,7 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c ...@@ -1784,7 +1785,7 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c
char sws_flags_str[128]; char sws_flags_str[128];
char buffersrc_args[256]; char buffersrc_args[256];
int ret; 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; AVCodecContext *codec = is->video_st->codec;
AVRational fr = av_guess_frame_rate(is->ic, is->video_st, NULL); AVRational fr = av_guess_frame_rate(is->ic, is->video_st, NULL);
...@@ -1815,16 +1816,49 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c ...@@ -1815,16 +1816,49 @@ 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) if ((ret = av_opt_set_int_list(filt_out, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0)
goto fail; goto fail;
last_filter = filt_out;
/* Note: this macro adds a filter before the lastly added filter, so the
* processing order of the filters is in reverse */
#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 /* SDL YUV code is not handling odd width/height for some driver
* combinations, therefore we crop the picture to an even width/height. */ * combinations, therefore we crop the picture to an even width/height. */
if ((ret = avfilter_graph_create_filter(&filt_crop, INSERT_FILT("crop", "floor(in_w/2)*2:floor(in_h/2)*2");
avfilter_get_by_name("crop"),
"ffplay_crop", "floor(in_w/2)*2:floor(in_h/2)*2", NULL, graph)) < 0) if (autorotate) {
goto fail; AVDictionaryEntry *rotate_tag = av_dict_get(is->video_st->metadata, "rotate", NULL, 0);
if ((ret = avfilter_link(filt_crop, 0, filt_out, 0)) < 0) if (rotate_tag && *rotate_tag->value && strcmp(rotate_tag->value, "0")) {
goto fail; if (!strcmp(rotate_tag->value, "90")) {
INSERT_FILT("transpose", "clock");
} 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", "cclock");
} else {
char rotate_buf[64];
snprintf(rotate_buf, sizeof(rotate_buf), "%s*PI/180", rotate_tag->value);
INSERT_FILT("rotate", rotate_buf);
}
}
}
if ((ret = configure_filtergraph(graph, vfilters, filt_src, filt_crop)) < 0) if ((ret = configure_filtergraph(graph, vfilters, filt_src, last_filter)) < 0)
goto fail; goto fail;
is->in_video_filter = filt_src; is->in_video_filter = filt_src;
...@@ -3564,6 +3598,7 @@ static const OptionDef options[] = { ...@@ -3564,6 +3598,7 @@ static const OptionDef options[] = {
{ "acodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &audio_codec_name }, "force audio decoder", "decoder_name" }, { "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" }, { "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" }, { "vcodec", HAS_ARG | OPT_STRING | OPT_EXPERT, { &video_codec_name }, "force video decoder", "decoder_name" },
{ "autorotate", OPT_BOOL, { &autorotate }, "automatically rotate video", "" },
{ NULL, }, { NULL, },
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment