[FFmpeg-devel] [PATCH v1 2/2] fftools/ffmpeg: add exif orientation support per frame's metadata

Jun Li junli1026 at gmail.com
Sun May 26 07:36:03 EEST 2019


On Sat, May 25, 2019 at 2:53 AM Nicolas George <george at nsup.org> wrote:

> Jun Li (12019-05-24):
> > Fix #6945
> > Rotate or/and flip frame according to frame's metadata orientation
>
> Since ffmpeg does not handle resolution changes very well, do we want
> this enabled by default?


Thanks Nicolas for review.
I believe it has been enabled by default, the 'autorotate' value is true by
default.

> ---
> >  fftools/ffmpeg.c        |  3 ++-
> >  fftools/ffmpeg.h        |  3 ++-
> >  fftools/ffmpeg_filter.c | 19 ++++++++++++++++++-
> >  3 files changed, 22 insertions(+), 3 deletions(-)
> >
> > diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
> > index 01f04103cf..da4c19c782 100644
> > --- a/fftools/ffmpeg.c
> > +++ b/fftools/ffmpeg.c
> > @@ -2142,7 +2142,8 @@ static int ifilter_send_frame(InputFilter
> *ifilter, AVFrame *frame)
> >          break;
> >      case AVMEDIA_TYPE_VIDEO:
> >          need_reinit |= ifilter->width  != frame->width ||
> > -                       ifilter->height != frame->height;
> > +                       ifilter->height != frame->height ||
>
> > +                       ifilter->orientation !=
> get_frame_orientation(frame);
>
> I the filter chain does not really need reinit if the orientation change
> does not change the output resolution.
>
> It can happen for photos who were all taken in portrait mode, but
> sometimes by leaning on the left and sometimes leaning on the right. I
> am sorry if these questions I raise seem to complicate matters, but it
> is not on purpose: automatic transformation is an issue that has many
> direct consequences on the usability of the tools, they need to be at
> least considered in the solution.
>

Do you mean the orientation case 1, 2, 3, 4 have the same resolution and 5,
6, 7, 8 are rotated, so the reinit is only necessary when switch between
these two cases?
I think it is doable. That transpose filter can do partially dynamic
processing based on frame's orientation, but the filter args still need to
set resolution info.

Correct me if I wrongly understand you question. Thanks.



> >          break;
> >      }
> >
> > diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
> > index eb1eaf6363..54532ef0eb 100644
> > --- a/fftools/ffmpeg.h
> > +++ b/fftools/ffmpeg.h
> > @@ -244,7 +244,7 @@ typedef struct InputFilter {
> >      // parameters configured for this input
> >      int format;
> >
> > -    int width, height;
> > +    int width, height, orientation;
> >      AVRational sample_aspect_ratio;
> >
> >      int sample_rate;
> > @@ -649,6 +649,7 @@ int init_complex_filtergraph(FilterGraph *fg);
> >  void sub2video_update(InputStream *ist, AVSubtitle *sub);
> >
> >  int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame
> *frame);
> > +int get_frame_orientation(const AVFrame* frame);
> >
> >  int ffmpeg_parse_options(int argc, char **argv);
> >
> > diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
> > index 72838de1e2..b230dafdc9 100644
> > --- a/fftools/ffmpeg_filter.c
> > +++ b/fftools/ffmpeg_filter.c
> > @@ -743,6 +743,18 @@ static int sub2video_prepare(InputStream *ist,
> InputFilter *ifilter)
> >      return 0;
> >  }
> >
> > +int get_frame_orientation(const AVFrame *frame)
> > +{
> > +    AVDictionaryEntry *entry = NULL;
> > +    int orientation = 1; // orientation indicates 'Normal'
> > +
> > +    // read exif orientation data
> > +    entry = av_dict_get(frame->metadata, "Orientation", NULL, 0);
>
> > +    if (entry)
> > +        orientation = atoi(entry->value);
> > +    return orientation > 8 ? 1 : orientation;
>
> I do not like the defensive programming here. If orientation is invalid,
> then it should not be invented, even a same default value.
>
Addressed in the new version.

> +}
> > +
> >  static int configure_input_video_filter(FilterGraph *fg, InputFilter
> *ifilter,
> >                                          AVFilterInOut *in)
> >  {
> > @@ -809,7 +821,11 @@ static int configure_input_video_filter(FilterGraph
> *fg, InputFilter *ifilter,
> >      if (ist->autorotate) {
> >          double theta = get_rotation(ist->st);
> >
>
> > -        if (fabs(theta - 90) < 1.0) {
> > +        if (fabs(theta) < 1.0) { // no rotation info in stream meta
> > +            char transpose_args[32];
> > +            snprintf(transpose_args, sizeof(transpose_args),
> "orientation=%i", ifilter->orientation);
> > +            ret = insert_filter(&last_filter, &pad_idx, "transpose",
> transpose_args);
>
> If the frame does not contain orientation metadata, I think the filter
> should not be inserted.
>
Addressed in the new version.


> > +        } else if (fabs(theta - 90) < 1.0) {
> >              ret = insert_filter(&last_filter, &pad_idx, "transpose",
> "clock");
> >          } else if (fabs(theta - 180) < 1.0) {
> >              ret = insert_filter(&last_filter, &pad_idx, "hflip", NULL);
>
> If transpose can take care of all cases, then the other cases need to be
> removed, or am I missing something?
>
Fixed in the new version.

Thanks for the review !

Best Regards,
-Jun

> > @@ -1191,6 +1207,7 @@ int ifilter_parameters_from_frame(InputFilter
> *ifilter, const AVFrame *frame)
> >      ifilter->width               = frame->width;
> >      ifilter->height              = frame->height;
> >      ifilter->sample_aspect_ratio = frame->sample_aspect_ratio;
> > +    ifilter->orientation         = get_frame_orientation(frame);
> >
> >      ifilter->sample_rate         = frame->sample_rate;
> >      ifilter->channels            = frame->channels;
>
> Regards,
>
> --
>   Nicolas George
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe".


More information about the ffmpeg-devel mailing list