summaryrefslogtreecommitdiff
path: root/ffplay.c
diff options
context:
space:
mode:
authorClément Bœsch <u@pkh.me>2014-04-18 23:15:54 +0200
committerClément Bœsch <u@pkh.me>2014-05-23 23:30:21 +0200
commit08c51e12b1c3f3e3e68e33eb46be7131df5b3682 (patch)
tree68a3778e428660bb28c298e01951224af7714b27 /ffplay.c
parente63a17bfdc99441ff25e188d2398bf1a8f1fbb7e (diff)
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
Diffstat (limited to 'ffplay.c')
-rw-r--r--ffplay.c51
1 files changed, 43 insertions, 8 deletions
diff --git a/ffplay.c b/ffplay.c
index 9aa87cccf9..fb07d41f99 100644
--- a/ffplay.c
+++ b/ffplay.c
@@ -329,6 +329,7 @@ static const char **vfilters_list = NULL;
static int nb_vfilters = 0;
static char *afilters = NULL;
#endif
+static int autorotate = 1;
/* current context */
static int is_full_screen;
@@ -1784,7 +1785,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);
@@ -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)
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
* 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 && *rotate_tag->value && strcmp(rotate_tag->value, "0")) {
+ 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;
is->in_video_filter = filt_src;
@@ -3564,6 +3598,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, },
};