diff mbox

[FFmpeg-devel,v3] avcodec: add AV_CODEC_FLAG_DROPCHANGED to flags

Message ID ab490532-ba67-5df2-8e64-8efefe49667c@gyani.pro
State Accepted
Headers show

Commit Message

Gyan Doshi April 16, 2019, 7:42 a.m. UTC
Patch revised as per 
http://www.ffmpeg.org/pipermail/ffmpeg-devel/2019-April/242591.html

Gyan
From d97a89d0335cc6d11f111a7a6bebc891501837d2 Mon Sep 17 00:00:00 2001
From: Gyan Doshi <ffmpeg@gyani.pro>
Date: Sun, 14 Apr 2019 22:12:25 +0530
Subject: [PATCH v3] avcodec: add AV_CODEC_FLAG_DROPCHANGED to flags

Discard decoded frames which differ from first decoded frame in stream.
---
 doc/codecs.texi            |  2 ++
 libavcodec/avcodec.h       |  8 +++++++
 libavcodec/decode.c        | 47 +++++++++++++++++++++++++++++++++++++-
 libavcodec/internal.h      |  8 +++++++
 libavcodec/options_table.h |  1 +
 libavcodec/version.h       |  2 +-
 6 files changed, 66 insertions(+), 2 deletions(-)

Comments

Vittorio Giovara April 17, 2019, 5:44 p.m. UTC | #1
On Tue, Apr 16, 2019 at 3:42 AM Gyan <ffmpeg@gyani.pro> wrote:

> Patch revised as per
> http://www.ffmpeg.org/pipermail/ffmpeg-devel/2019-April/242591.html
>
> Gyan
>

sorry if i'm late to the party but why are these new fields in
avcodeccontext?
they seem to be perfect candidates for side data, or am i missing something?
Gyan Doshi April 17, 2019, 6:10 p.m. UTC | #2
On 17-04-2019 11:14 PM, Vittorio Giovara wrote:
> On Tue, Apr 16, 2019 at 3:42 AM Gyan <ffmpeg@gyani.pro> wrote:
>
>> Patch revised as per
>> http://www.ffmpeg.org/pipermail/ffmpeg-devel/2019-April/242591.html
>>
>> Gyan
>>
> sorry if i'm late to the party but why are these new fields in
> avcodeccontext?
> they seem to be perfect candidates for side data, or am i missing something?
The latest patch only adds a constant to avctx. New fields are in 
AVCodecInternal.

The purpose is to allow the user to discard decoded output which 
deviates from initial stream parameters - mainly useful when receiving 
an input over an unreliable transport. The demuxer doesn't always catch 
all corrupted payload, and neither does the decoder (e.g. a mpeg audio 
header with some bits flipped), so some frames with different parameters 
can get through. This causes the filtergraph to be configured, 
destroying its context. Timestamps can go haywire which is not 
acceptable in an ongoing streaming scenario.

Originally I submitted this as a ffmpeg.c patch, but Michael suggested 
that avcodec users may find it useful.

Gyan
Gyan Doshi April 19, 2019, 3:11 p.m. UTC | #3
On 16-04-2019 01:12 PM, Gyan wrote:
> Patch revised as per 
> http://www.ffmpeg.org/pipermail/ffmpeg-devel/2019-April/242591.html

If no more changes, plan to push tomorrow morning.

Gyan
Gyan Doshi April 20, 2019, 5:21 a.m. UTC | #4
On 19-04-2019 08:41 PM, Gyan wrote:
>
>
> On 16-04-2019 01:12 PM, Gyan wrote:
>> Patch revised as per 
>> http://www.ffmpeg.org/pipermail/ffmpeg-devel/2019-April/242591.html
>
> If no more changes, plan to push tomorrow morning.

Pushed as 3153a6502a28b20a0da822daf32bcd8f7c90d721

Gyan
Marton Balint April 20, 2019, 6:44 p.m. UTC | #5
On Sat, 20 Apr 2019, Gyan wrote:

>
>
> On 19-04-2019 08:41 PM, Gyan wrote:
>>
>>
>> On 16-04-2019 01:12 PM, Gyan wrote:
>>> Patch revised as per 
>>> http://www.ffmpeg.org/pipermail/ffmpeg-devel/2019-April/242591.html
>>
>> If no more changes, plan to push tomorrow morning.
>
> Pushed as 3153a6502a28b20a0da822daf32bcd8f7c90d721

Please clarify that you return error and not simply drop in codecs.texi.

Thanks,
Marton
Gyan Doshi April 21, 2019, 4:39 a.m. UTC | #6
On 21-04-2019 12:14 AM, Marton Balint wrote:
>
>
> On Sat, 20 Apr 2019, Gyan wrote:
>
>>
>>
>> On 19-04-2019 08:41 PM, Gyan wrote:
>>>
>>>
>>> On 16-04-2019 01:12 PM, Gyan wrote:
>>>> Patch revised as per 
>>>> http://www.ffmpeg.org/pipermail/ffmpeg-devel/2019-April/242591.html
>>>
>>> If no more changes, plan to push tomorrow morning.
>>
>> Pushed as 3153a6502a28b20a0da822daf32bcd8f7c90d721
>
> Please clarify that you return error and not simply drop in codecs.texi.

Added.

Regards,
Gyan
diff mbox

Patch

diff --git a/doc/codecs.texi b/doc/codecs.texi
index 572e561c1a..0baafee2e1 100644
--- a/doc/codecs.texi
+++ b/doc/codecs.texi
@@ -55,6 +55,8 @@  Do not draw edges.
 @item psnr
 Set error[?] variables during encoding.
 @item truncated
+@item drop_changed
+Don't output frames whose parameters differ from first decoded frame in stream.
 
 @item ildct
 Use interlaced DCT.
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 9e37466641..b749946633 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -859,6 +859,11 @@  typedef struct RcOverride{
  * Use qpel MC.
  */
 #define AV_CODEC_FLAG_QPEL            (1 <<  4)
+/**
+ * Don't output frames whose parameters differ from first
+ * decoded frame in stream.
+ */
+#define AV_CODEC_FLAG_DROPCHANGED     (1 <<  5)
 /**
  * Use internal 2pass ratecontrol in first pass mode.
  */
@@ -4918,6 +4923,9 @@  int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt);
  *      AVERROR_EOF:       the decoder has been fully flushed, and there will be
  *                         no more output frames
  *      AVERROR(EINVAL):   codec not opened, or it is an encoder
+ *      AVERROR_INPUT_CHANGED:   current decoded frame has changed parameters
+ *                               with respect to first decoded frame. Applicable
+ *                               when flag AV_CODEC_FLAG_DROPCHANGED is set.
  *      other negative values: legitimate decoding errors
  */
 int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame);
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index a32ff2fcd3..6c31166ec2 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -740,7 +740,7 @@  static int apply_cropping(AVCodecContext *avctx, AVFrame *frame)
 int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame)
 {
     AVCodecInternal *avci = avctx->internal;
-    int ret;
+    int ret, changed;
 
     av_frame_unref(frame);
 
@@ -765,6 +765,51 @@  int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *fr
 
     avctx->frame_number++;
 
+    if (avctx->flags & AV_CODEC_FLAG_DROPCHANGED) {
+
+        if (avctx->frame_number == 1) {
+            avci->initial_format = frame->format;
+            switch(avctx->codec_type) {
+            case AVMEDIA_TYPE_VIDEO:
+                avci->initial_width  = frame->width;
+                avci->initial_height = frame->height;
+                break;
+            case AVMEDIA_TYPE_AUDIO:
+                avci->initial_sample_rate = frame->sample_rate ? frame->sample_rate :
+                                                                 avctx->sample_rate;
+                avci->initial_channels       = frame->channels;
+                avci->initial_channel_layout = frame->channel_layout;
+                break;
+            }
+        }
+
+        if (avctx->frame_number > 1) {
+            changed = avci->initial_format != frame->format;
+
+           switch(avctx->codec_type) {
+            case AVMEDIA_TYPE_VIDEO:
+                changed |= avci->initial_width  != frame->width ||
+                           avci->initial_height != frame->height;
+                break;
+            case AVMEDIA_TYPE_AUDIO:
+                changed |= avci->initial_sample_rate    != frame->sample_rate ||
+                           avci->initial_sample_rate    != avctx->sample_rate ||
+                           avci->initial_channels       != frame->channels ||
+                           avci->initial_channel_layout != frame->channel_layout;
+                break;
+            }
+
+            if (changed) {
+                avci->changed_frames_dropped++;
+                av_log(avctx, AV_LOG_INFO, "dropped changed frame #%d pts %"PRId64
+                                            " drop count: %d \n",
+                                            avctx->frame_number, frame->pts,
+                                            avci->changed_frames_dropped);
+                av_frame_unref(frame);
+                return AVERROR_INPUT_CHANGED;
+            }
+        }
+    }
     return 0;
 }
 
diff --git a/libavcodec/internal.h b/libavcodec/internal.h
index f2e6f00ace..5096ffa1d9 100644
--- a/libavcodec/internal.h
+++ b/libavcodec/internal.h
@@ -218,6 +218,14 @@  typedef struct AVCodecInternal {
 
     /* to prevent infinite loop on errors when draining */
     int nb_draining_errors;
+
+    /* used when avctx flag AV_CODEC_FLAG_DROPCHANGED is set */
+    int changed_frames_dropped;
+    int initial_format;
+    int initial_width, initial_height;
+    int initial_sample_rate;
+    int initial_channels;
+    uint64_t initial_channel_layout;
 } AVCodecInternal;
 
 struct AVCodecDefault {
diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h
index a3235bcd57..4a266eca16 100644
--- a/libavcodec/options_table.h
+++ b/libavcodec/options_table.h
@@ -67,6 +67,7 @@  static const AVOption avcodec_options[] = {
 {"ilme", "interlaced motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_INTERLACED_ME }, INT_MIN, INT_MAX, V|E, "flags"},
 {"cgop", "closed GOP", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_CLOSED_GOP }, INT_MIN, INT_MAX, V|E, "flags"},
 {"output_corrupt", "Output even potentially corrupted frames", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_OUTPUT_CORRUPT }, INT_MIN, INT_MAX, V|D, "flags"},
+{"drop_changed", "Drop frames whose parameters differ from first decoded frame", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_DROPCHANGED }, INT_MIN, INT_MAX, A|V|D, "flags"},
 {"flags2", NULL, OFFSET(flags2), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT}, 0, UINT_MAX, V|A|E|D, "flags2"},
 {"fast", "allow non-spec-compliant speedup tricks", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_FAST }, INT_MIN, INT_MAX, V|E, "flags2"},
 {"noout", "skip bitstream encoding", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_NO_OUTPUT }, INT_MIN, INT_MAX, V|E, "flags2"},
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 1b60202dee..195e21bfbe 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -28,7 +28,7 @@ 
 #include "libavutil/version.h"
 
 #define LIBAVCODEC_VERSION_MAJOR  58
-#define LIBAVCODEC_VERSION_MINOR  51
+#define LIBAVCODEC_VERSION_MINOR  52
 #define LIBAVCODEC_VERSION_MICRO 100
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \