]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/decode.c
avcodec/decode: set best_effort_timestamp on output frames for all decoders
[ffmpeg] / libavcodec / decode.c
index e438135b53f7815acf332bfc5d53e441fc9af2e1..d804b0bed0c6d21fb0dc2f7173cf2303bfd9efba 100644 (file)
@@ -43,6 +43,7 @@
 #include "decode.h"
 #include "hwconfig.h"
 #include "internal.h"
+#include "packet_internal.h"
 #include "thread.h"
 
 typedef struct FramePool {
@@ -66,7 +67,7 @@ typedef struct FramePool {
 
 static int apply_param_change(AVCodecContext *avctx, const AVPacket *avpkt)
 {
-    int size = 0, ret;
+    int size, ret;
     const uint8_t *data;
     uint32_t flags;
     int64_t val;
@@ -142,15 +143,24 @@ fail2:
     return 0;
 }
 
-static int extract_packet_props(AVCodecInternal *avci, const AVPacket *pkt)
+#define IS_EMPTY(pkt) (!(pkt)->data)
+
+static int extract_packet_props(AVCodecInternal *avci, AVPacket *pkt)
 {
     int ret = 0;
 
-    av_packet_unref(avci->last_pkt_props);
-    if (pkt) {
-        ret = av_packet_copy_props(avci->last_pkt_props, pkt);
-        if (!ret)
-            avci->last_pkt_props->size = pkt->size; // HACK: Needed for ff_decode_frame_props().
+    ret = avpriv_packet_list_put(&avci->pkt_props, &avci->pkt_props_tail, pkt,
+                                 av_packet_copy_props, 0);
+    if (ret < 0)
+        return ret;
+    avci->pkt_props_tail->pkt.size = pkt->size; // HACK: Needed for ff_decode_frame_props().
+    avci->pkt_props_tail->pkt.data = (void*)1;  // HACK: Needed for IS_EMPTY().
+
+    if (IS_EMPTY(avci->last_pkt_props)) {
+        ret = avpriv_packet_list_get(&avci->pkt_props,
+                                     &avci->pkt_props_tail,
+                                     avci->last_pkt_props);
+        av_assert0(ret != AVERROR(EAGAIN));
     }
     return ret;
 }
@@ -308,7 +318,7 @@ static int64_t guess_correct_pts(AVCodecContext *ctx,
  * returning any output, so this function needs to be called in a loop until it
  * returns EAGAIN.
  **/
-static inline int decode_simple_internal(AVCodecContext *avctx, AVFrame *frame)
+static inline int decode_simple_internal(AVCodecContext *avctx, AVFrame *frame, int64_t *discarded_samples)
 {
     AVCodecInternal   *avci = avctx->internal;
     DecodeSimpleContext *ds = &avci->ds;
@@ -362,10 +372,6 @@ static inline int decode_simple_internal(AVCodecContext *avctx, AVFrame *frame)
     if (avctx->codec->type == AVMEDIA_TYPE_VIDEO) {
         if (frame->flags & AV_FRAME_FLAG_DISCARD)
             got_frame = 0;
-        if (got_frame)
-            frame->best_effort_timestamp = guess_correct_pts(avctx,
-                                                             frame->pts,
-                                                             frame->pkt_dts);
     } else if (avctx->codec->type == AVMEDIA_TYPE_AUDIO) {
         uint8_t *side;
         int side_size;
@@ -374,9 +380,6 @@ static inline int decode_simple_internal(AVCodecContext *avctx, AVFrame *frame)
         uint8_t discard_reason = 0;
 
         if (ret >= 0 && got_frame) {
-            frame->best_effort_timestamp = guess_correct_pts(avctx,
-                                                             frame->pts,
-                                                             frame->pkt_dts);
             if (frame->format == AV_SAMPLE_FMT_NONE)
                 frame->format = avctx->sample_fmt;
             if (!frame->channel_layout)
@@ -401,12 +404,14 @@ static inline int decode_simple_internal(AVCodecContext *avctx, AVFrame *frame)
             !(avctx->flags2 & AV_CODEC_FLAG2_SKIP_MANUAL)) {
             avci->skip_samples = FFMAX(0, avci->skip_samples - frame->nb_samples);
             got_frame = 0;
+            *discarded_samples += frame->nb_samples;
         }
 
         if (avci->skip_samples > 0 && got_frame &&
             !(avctx->flags2 & AV_CODEC_FLAG2_SKIP_MANUAL)) {
             if(frame->nb_samples <= avci->skip_samples){
                 got_frame = 0;
+                *discarded_samples += frame->nb_samples;
                 avci->skip_samples -= frame->nb_samples;
                 av_log(avctx, AV_LOG_DEBUG, "skip whole frame, skip left: %d\n",
                        avci->skip_samples);
@@ -434,6 +439,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
                 }
                 av_log(avctx, AV_LOG_DEBUG, "skip %d/%d samples\n",
                        avci->skip_samples, frame->nb_samples);
+                *discarded_samples += avci->skip_samples;
                 frame->nb_samples -= avci->skip_samples;
                 avci->skip_samples = 0;
             }
@@ -442,6 +448,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
         if (discard_padding > 0 && discard_padding <= frame->nb_samples && got_frame &&
             !(avctx->flags2 & AV_CODEC_FLAG2_SKIP_MANUAL)) {
             if (discard_padding == frame->nb_samples) {
+                *discarded_samples += frame->nb_samples;
                 got_frame = 0;
             } else {
                 if(avctx->pkt_timebase.num && avctx->sample_rate) {
@@ -512,6 +519,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
 
     if (ret >= pkt->size || ret < 0) {
         av_packet_unref(pkt);
+        av_packet_unref(avci->last_pkt_props);
     } else {
         int consumed = ret;
 
@@ -533,9 +541,12 @@ FF_ENABLE_DEPRECATION_WARNINGS
 static int decode_simple_receive_frame(AVCodecContext *avctx, AVFrame *frame)
 {
     int ret;
+    int64_t discarded_samples = 0;
 
     while (!frame->buf[0]) {
-        ret = decode_simple_internal(avctx, frame);
+        if (discarded_samples > avctx->max_samples)
+            return AVERROR(EAGAIN);
+        ret = decode_simple_internal(avctx, frame, &discarded_samples);
         if (ret < 0)
             return ret;
     }
@@ -550,15 +561,21 @@ static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame)
 
     av_assert0(!frame->buf[0]);
 
-    if (avctx->codec->receive_frame)
+    if (avctx->codec->receive_frame) {
         ret = avctx->codec->receive_frame(avctx, frame);
-    else
+        if (ret != AVERROR(EAGAIN))
+            av_packet_unref(avci->last_pkt_props);
+    } else
         ret = decode_simple_receive_frame(avctx, frame);
 
     if (ret == AVERROR_EOF)
         avci->draining_done = 1;
 
     if (!ret) {
+        frame->best_effort_timestamp = guess_correct_pts(avctx,
+                                                         frame->pts,
+                                                         frame->pkt_dts);
+
         /* the only case where decode data is not set should be decoders
          * that do not call ff_get_buffer() */
         av_assert0((frame->private_ref && frame->private_ref->size == sizeof(FrameDecodeData)) ||
@@ -1471,12 +1488,12 @@ static int update_frame_pool(AVCodecContext *avctx, AVFrame *frame)
 
     switch (avctx->codec_type) {
     case AVMEDIA_TYPE_VIDEO: {
-        uint8_t *data[4];
         int linesize[4];
-        int size[4] = { 0 };
         int w = frame->width;
         int h = frame->height;
-        int tmpsize, unaligned;
+        int unaligned;
+        ptrdiff_t linesize1[4];
+        size_t size[4];
 
         avcodec_align_dimensions2(avctx, &w, &h, pool->stride_align);
 
@@ -1494,20 +1511,19 @@ static int update_frame_pool(AVCodecContext *avctx, AVFrame *frame)
                 unaligned |= linesize[i] % pool->stride_align[i];
         } while (unaligned);
 
-        tmpsize = av_image_fill_pointers(data, avctx->pix_fmt, h,
-                                         NULL, linesize);
-        if (tmpsize < 0) {
-            ret = tmpsize;
+        for (i = 0; i < 4; i++)
+            linesize1[i] = linesize[i];
+        ret = av_image_fill_plane_sizes(size, avctx->pix_fmt, h, linesize1);
+        if (ret < 0)
             goto fail;
-        }
-
-        for (i = 0; i < 3 && data[i + 1]; i++)
-            size[i] = data[i + 1] - data[i];
-        size[i] = tmpsize - (data[i] - data[0]);
 
         for (i = 0; i < 4; i++) {
             pool->linesize[i] = linesize[i];
             if (size[i]) {
+                if (size[i] > INT_MAX - (16 + STRIDE_ALIGN - 1)) {
+                    ret = AVERROR(EINVAL);
+                    goto fail;
+                }
                 pool->pools[i] = av_buffer_pool_init(size[i] + 16 + STRIDE_ALIGN - 1,
                                                      CONFIG_MEMORY_POISONING ?
                                                         NULL :
@@ -1684,7 +1700,7 @@ static int add_metadata_from_side_data(const AVPacket *avpkt, AVFrame *frame)
 
 int ff_decode_frame_props(AVCodecContext *avctx, AVFrame *frame)
 {
-    const AVPacket *pkt = avctx->internal->last_pkt_props;
+    AVPacket *pkt = avctx->internal->last_pkt_props;
     int i;
     static const struct {
         enum AVPacketSideDataType packet;
@@ -1699,8 +1715,14 @@ int ff_decode_frame_props(AVCodecContext *avctx, AVFrame *frame)
         { AV_PKT_DATA_CONTENT_LIGHT_LEVEL,        AV_FRAME_DATA_CONTENT_LIGHT_LEVEL },
         { AV_PKT_DATA_A53_CC,                     AV_FRAME_DATA_A53_CC },
         { AV_PKT_DATA_ICC_PROFILE,                AV_FRAME_DATA_ICC_PROFILE },
+        { AV_PKT_DATA_S12M_TIMECODE,              AV_FRAME_DATA_S12M_TIMECODE },
     };
 
+    if (IS_EMPTY(pkt))
+        avpriv_packet_list_get(&avctx->internal->pkt_props,
+                               &avctx->internal->pkt_props_tail,
+                               pkt);
+
     if (pkt) {
         frame->pts = pkt->pts;
 #if FF_API_PKT_PTS
@@ -1858,7 +1880,8 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
     int ret;
 
     if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
-        if ((ret = av_image_check_size2(FFALIGN(avctx->width, STRIDE_ALIGN), avctx->height, avctx->max_pixels, AV_PIX_FMT_NONE, 0, avctx)) < 0 || avctx->pix_fmt<0) {
+        if ((unsigned)avctx->width > INT_MAX - STRIDE_ALIGN ||
+            (ret = av_image_check_size2(FFALIGN(avctx->width, STRIDE_ALIGN), avctx->height, avctx->max_pixels, AV_PIX_FMT_NONE, 0, avctx)) < 0 || avctx->pix_fmt<0) {
             av_log(avctx, AV_LOG_ERROR, "video_get_buffer: image parameters invalid\n");
             ret = AVERROR(EINVAL);
             goto fail;
@@ -1889,7 +1912,7 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
     if (hwaccel) {
         if (hwaccel->alloc_frame) {
             ret = hwaccel->alloc_frame(avctx, frame);
-            goto fail;
+            goto end;
         }
     } else
         avctx->sw_pix_fmt = avctx->pix_fmt;
@@ -1904,16 +1927,19 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
     if (ret < 0)
         goto fail;
 
+end:
     if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions &&
         !(avctx->codec->caps_internal & FF_CODEC_CAP_EXPORTS_CROPPING)) {
         frame->width  = avctx->width;
         frame->height = avctx->height;
     }
 
-    return 0;
 fail:
-    av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
-    av_frame_unref(frame);
+    if (ret < 0) {
+        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+        av_frame_unref(frame);
+    }
+
     return ret;
 }