diff mbox series

[FFmpeg-devel,RFC,4/5] tinterlace: Properly preserve CEA-708 closed captions

Message ID 20230317200941.3936-5-dheitmueller@ltnglobal.com
State New
Headers show
Series Properly handle CEA-708 caption data when transcoding | expand

Commit Message

Devin Heitmueller March 17, 2023, 8:09 p.m. UTC
Because the interlacing filter halves the effective framerate, we
need to ensure that no CEA-708 data is lost as frames are merged.

Make use of the new ccfifo mechanism to ensure that caption data
is properly preserved as frames pass through the filter.

Signed-off-by: Devin Heitmueller <dheitmueller@ltnglobal.com>
---
 libavfilter/tinterlace.h    |  2 ++
 libavfilter/vf_tinterlace.c | 10 ++++++++++
 2 files changed, 12 insertions(+)

Comments

Thomas Mundt March 18, 2023, 5:12 p.m. UTC | #1
Hi Devin,

Am Fr., 17. März 2023 um 21:10 Uhr schrieb Devin Heitmueller <
devin.heitmueller@ltnglobal.com>:

> Because the interlacing filter halves the effective framerate, we
> need to ensure that no CEA-708 data is lost as frames are merged.
>

Not all modes of tinterlace halve the frame rate. mergex2 and pad keep it,
interlacex2 even doubles it.


> Make use of the new ccfifo mechanism to ensure that caption data
> is properly preserved as frames pass through the filter.
>
> Signed-off-by: Devin Heitmueller <dheitmueller@ltnglobal.com>
> ---
>  libavfilter/tinterlace.h    |  2 ++
>  libavfilter/vf_tinterlace.c | 10 ++++++++++
>  2 files changed, 12 insertions(+)
>
> diff --git a/libavfilter/tinterlace.h b/libavfilter/tinterlace.h
> index 37b6c10c08..30574c2ebf 100644
> --- a/libavfilter/tinterlace.h
> +++ b/libavfilter/tinterlace.h
> @@ -30,6 +30,7 @@
>  #include "libavutil/bswap.h"
>  #include "libavutil/opt.h"
>  #include "libavutil/pixdesc.h"
> +#include "libavutil/ccfifo.h"
>  #include "drawutils.h"
>  #include "avfilter.h"
>
> @@ -77,6 +78,7 @@ typedef struct TInterlaceContext {
>      const AVPixFmtDescriptor *csp;
>      void (*lowpass_line)(uint8_t *dstp, ptrdiff_t width, const uint8_t
> *srcp,
>                           ptrdiff_t mref, ptrdiff_t pref, int clip_max);
> +    AVCCFifo *cc_fifo;
>  } TInterlaceContext;
>
>  void ff_tinterlace_init_x86(TInterlaceContext *interlace);
> diff --git a/libavfilter/vf_tinterlace.c b/libavfilter/vf_tinterlace.c
> index 032629279a..260386a889 100644
> --- a/libavfilter/vf_tinterlace.c
> +++ b/libavfilter/vf_tinterlace.c
> @@ -291,6 +291,9 @@ static int config_out_props(AVFilterLink *outlink)
>  #endif
>      }
>
> +    if (!(tinterlace->cc_fifo = av_ccfifo_alloc(&outlink->frame_rate,
> ctx)))
> +        av_log(ctx, AV_LOG_VERBOSE, "Failure to setup CC FIFO queue.
> Captions will be passed through\n");
> +
>      av_log(ctx, AV_LOG_VERBOSE, "mode:%d filter:%s h:%d -> h:%d\n",
> tinterlace->mode,
>             (tinterlace->flags & TINTERLACE_FLAG_CVLPF) ? "complex" :
>             (tinterlace->flags & TINTERLACE_FLAG_VLPF) ? "linear" : "off",
> @@ -375,6 +378,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame
> *picref)
>      tinterlace->cur  = tinterlace->next;
>      tinterlace->next = picref;
>
> +    av_ccfifo_extract(tinterlace->cc_fifo, picref);
> +
>      cur = tinterlace->cur;
>      next = tinterlace->next;
>      /* we need at least two frames */
> @@ -390,6 +395,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame
> *picref)
>          if (!out)
>              return AVERROR(ENOMEM);
>          av_frame_copy_props(out, cur);
> +        av_ccfifo_inject(tinterlace->cc_fifo, out);
>          out->height = outlink->h;
>          out->interlaced_frame = 1;
>          out->top_field_first = 1;
> @@ -423,6 +429,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame
> *picref)
>

Are the drop modes missing?
Would it perhaps be clearer to put av_ccfifo_inject before ff_filter_frame?


>          if (!out)
>              return AVERROR(ENOMEM);
>          av_frame_copy_props(out, cur);
> +        av_ccfifo_inject(tinterlace->cc_fifo, out);
>          out->height = outlink->h;
>          out->sample_aspect_ratio = av_mul_q(cur->sample_aspect_ratio,
> av_make_q(2, 1));
>
> @@ -459,6 +466,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame
> *picref)
>          if (!out)
>              return AVERROR(ENOMEM);
>          av_frame_copy_props(out, cur);
> +        av_ccfifo_inject(tinterlace->cc_fifo, out);
>          out->interlaced_frame = 1;
>          out->top_field_first = tff;
>
> @@ -481,6 +489,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame
> *picref)
>          out = av_frame_clone(cur);
>          if (!out)
>              return AVERROR(ENOMEM);
> +        av_ccfifo_inject(tinterlace->cc_fifo, out);
>          out->interlaced_frame = 1;
>          if (cur->pts != AV_NOPTS_VALUE)
>              out->pts = cur->pts*2;
> @@ -495,6 +504,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame
> *picref)
>          if (!out)
>              return AVERROR(ENOMEM);
>          av_frame_copy_props(out, next);
> +        av_ccfifo_inject(tinterlace->cc_fifo, out);
>          out->interlaced_frame = 1;
>          out->top_field_first = !tff;
>
> --
>

Regards,
Thomas
Devin Heitmueller March 18, 2023, 11:22 p.m. UTC | #2
On Sat, Mar 18, 2023 at 1:12 PM Thomas Mundt <tmundt75@gmail.com> wrote:
> Not all modes of tinterlace halve the frame rate. mergex2 and pad keep it, interlacex2 even doubles it.

Sorry, I should have been more clear with the patch description in
that I realize that interlacing doesn't necessarily halve the
framerate, depending on the mode.  That said, I was pretty sure I got
it working with all the code paths, but if you think I've missed one
or more then please let me know.  Or if you have an alternative patch
which you think is cleaner for the tinterlace filter, I would be happy
to review it.

Thanks,

Devin
Thomas Mundt March 19, 2023, 4:50 p.m. UTC | #3
Am So., 19. März 2023 um 00:22 Uhr schrieb Devin Heitmueller <
devin.heitmueller@ltnglobal.com>:

> On Sat, Mar 18, 2023 at 1:12 PM Thomas Mundt <tmundt75@gmail.com> wrote:
> > Not all modes of tinterlace halve the frame rate. mergex2 and pad keep
> it, interlacex2 even doubles it.
>
> Sorry, I should have been more clear with the patch description in
> that I realize that interlacing doesn't necessarily halve the
> framerate, depending on the mode.  That said, I was pretty sure I got
> it working with all the code paths, but if you think I've missed one
> or more then please let me know.  Or if you have an alternative patch
> which you think is cleaner for the tinterlace filter, I would be happy
> to review it.
>
>
I haven't worked with closed captions yet and also don't have the expertise
to test them reliably.
I just would like to roughly understand as maintainer of the tinterlace
filter how your patch works in order not to break the functionality in
future changes.
Looking through it, I wonder for example why av_ccfifo_inject is set for
the interleave modes and not for the drop modes.
Under which conditions must av_ccfifo_inject be set? Whenever a frame is
created at the output of the filter, or are there other conditions?

Regards,
Thomas
Devin Heitmueller March 19, 2023, 5:33 p.m. UTC | #4
On Sun, Mar 19, 2023 at 12:50 PM Thomas Mundt <tmundt75@gmail.com> wrote:
> Looking through it, I wonder for example why av_ccfifo_inject is set for the interleave modes and not for the drop modes.
> Under which conditions must av_ccfifo_inject be set? Whenever a frame is created at the output of the filter, or are there other conditions?

I'll have to double check the logic in tinterlace.  The intention is
that whenever a frame arrives on the input we should be calling
extract, and whenever we generate a frame on the output we should be
calling inject.  If I've missed a case, then I will have to take care
of that.

Devin
diff mbox series

Patch

diff --git a/libavfilter/tinterlace.h b/libavfilter/tinterlace.h
index 37b6c10c08..30574c2ebf 100644
--- a/libavfilter/tinterlace.h
+++ b/libavfilter/tinterlace.h
@@ -30,6 +30,7 @@ 
 #include "libavutil/bswap.h"
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
+#include "libavutil/ccfifo.h"
 #include "drawutils.h"
 #include "avfilter.h"
 
@@ -77,6 +78,7 @@  typedef struct TInterlaceContext {
     const AVPixFmtDescriptor *csp;
     void (*lowpass_line)(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp,
                          ptrdiff_t mref, ptrdiff_t pref, int clip_max);
+    AVCCFifo *cc_fifo;
 } TInterlaceContext;
 
 void ff_tinterlace_init_x86(TInterlaceContext *interlace);
diff --git a/libavfilter/vf_tinterlace.c b/libavfilter/vf_tinterlace.c
index 032629279a..260386a889 100644
--- a/libavfilter/vf_tinterlace.c
+++ b/libavfilter/vf_tinterlace.c
@@ -291,6 +291,9 @@  static int config_out_props(AVFilterLink *outlink)
 #endif
     }
 
+    if (!(tinterlace->cc_fifo = av_ccfifo_alloc(&outlink->frame_rate, ctx)))
+        av_log(ctx, AV_LOG_VERBOSE, "Failure to setup CC FIFO queue.  Captions will be passed through\n");
+
     av_log(ctx, AV_LOG_VERBOSE, "mode:%d filter:%s h:%d -> h:%d\n", tinterlace->mode,
            (tinterlace->flags & TINTERLACE_FLAG_CVLPF) ? "complex" :
            (tinterlace->flags & TINTERLACE_FLAG_VLPF) ? "linear" : "off",
@@ -375,6 +378,8 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
     tinterlace->cur  = tinterlace->next;
     tinterlace->next = picref;
 
+    av_ccfifo_extract(tinterlace->cc_fifo, picref);
+
     cur = tinterlace->cur;
     next = tinterlace->next;
     /* we need at least two frames */
@@ -390,6 +395,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
         if (!out)
             return AVERROR(ENOMEM);
         av_frame_copy_props(out, cur);
+        av_ccfifo_inject(tinterlace->cc_fifo, out);
         out->height = outlink->h;
         out->interlaced_frame = 1;
         out->top_field_first = 1;
@@ -423,6 +429,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
         if (!out)
             return AVERROR(ENOMEM);
         av_frame_copy_props(out, cur);
+        av_ccfifo_inject(tinterlace->cc_fifo, out);
         out->height = outlink->h;
         out->sample_aspect_ratio = av_mul_q(cur->sample_aspect_ratio, av_make_q(2, 1));
 
@@ -459,6 +466,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
         if (!out)
             return AVERROR(ENOMEM);
         av_frame_copy_props(out, cur);
+        av_ccfifo_inject(tinterlace->cc_fifo, out);
         out->interlaced_frame = 1;
         out->top_field_first = tff;
 
@@ -481,6 +489,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
         out = av_frame_clone(cur);
         if (!out)
             return AVERROR(ENOMEM);
+        av_ccfifo_inject(tinterlace->cc_fifo, out);
         out->interlaced_frame = 1;
         if (cur->pts != AV_NOPTS_VALUE)
             out->pts = cur->pts*2;
@@ -495,6 +504,7 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
         if (!out)
             return AVERROR(ENOMEM);
         av_frame_copy_props(out, next);
+        av_ccfifo_inject(tinterlace->cc_fifo, out);
         out->interlaced_frame = 1;
         out->top_field_first = !tff;