---
 avconv.c              |   11 +++++------
 libavcodec/internal.h |   14 ++++++++++++++
 libavcodec/utils.c    |   15 +++++++++++++++
 3 files changed, 34 insertions(+), 6 deletions(-)

diff --git a/avconv.c b/avconv.c
index a1efce2..6a72af5 100644
--- a/avconv.c
+++ b/avconv.c
@@ -1105,15 +1105,14 @@ static int decode_audio(InputStream *ist, AVPacket 
*pkt, int *got_output)
         return ret;
     }
 
-    /* if the decoder provides a pts, use it instead of the last packet pts.
-       the decoder could be delaying output by a packet or more. */
+    /* If the decoder provides a pts, use it instead of the last packet pts.
+       Libavcodec can interpolate timestamps for multiple frames in the same
+       packet. Also, the decoder could be delaying output. */
     if (decoded_frame->pts != AV_NOPTS_VALUE)
         ist->next_dts = av_rescale_q(decoded_frame->pts, avctx->time_base,
                                      AV_TIME_BASE_Q);
-    else if (pkt->pts != AV_NOPTS_VALUE) {
-        decoded_frame->pts = pkt->pts;
-        pkt->pts           = AV_NOPTS_VALUE;
-    }
+    pkt->pts = AV_NOPTS_VALUE;
+
     if (ist->next_dts != AV_NOPTS_VALUE)
         ist->next_dts += av_rescale_q(decoded_frame->nb_samples, 
avctx->time_base,
                                       AV_TIME_BASE_Q);
diff --git a/libavcodec/internal.h b/libavcodec/internal.h
index 0bfc924..d03c256 100644
--- a/libavcodec/internal.h
+++ b/libavcodec/internal.h
@@ -76,6 +76,20 @@ typedef struct AVCodecInternal {
      * padded with silence. Reject all subsequent frames.
      */
     int last_audio_frame;
+
+    /**
+     * pts of the last packet passed to the decoder (audio only)
+     * This is used to detect duplicate pts for timestamp interpolation.
+     * It is reset to AV_NOPTS_VALUE on flush.
+     */
+    int64_t last_pts;
+
+    /**
+     * Interpolated pts for the next decoded frame (audio only).
+     * This is used when there are multiple frames per packet or duplicate pts
+     * in subsequent packets.
+     */
+    int64_t next_pts;
 } AVCodecInternal;
 
 struct AVCodecDefault {
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index cb386a6..1b8cf38 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -716,6 +716,7 @@ int attribute_align_arg avcodec_open2(AVCodecContext 
*avctx, const AVCodec *code
         ret = AVERROR(ENOMEM);
         goto end;
     }
+    avctx->internal->last_pts = avctx->internal->next_pts = AV_NOPTS_VALUE;
 
     if (codec->priv_data_size > 0) {
         if (!avctx->priv_data) {
@@ -1387,10 +1388,23 @@ int attribute_align_arg 
avcodec_decode_audio4(AVCodecContext *avctx,
     if ((avctx->codec->capabilities & CODEC_CAP_DELAY) || avpkt->size) {
         ret = avctx->codec->decode(avctx, frame, got_frame_ptr, avpkt);
         if (ret >= 0 && *got_frame_ptr) {
+            AVCodecInternal *avci = avctx->internal;
+
             avctx->frame_number++;
             frame->pkt_dts = avpkt->dts;
             if (frame->format == AV_SAMPLE_FMT_NONE)
                 frame->format = avctx->sample_fmt;
+
+            /* timestamp interpolation */
+            if (frame->pts == AV_NOPTS_VALUE) {
+                if (avpkt->pts == AV_NOPTS_VALUE || avci->last_pts == 
avpkt->pts)
+                    frame->pts = avci->next_pts;
+                else
+                    frame->pts = avpkt->pts;
+            }
+            if (frame->pts != AV_NOPTS_VALUE)
+                avci->next_pts = frame->pts + frame->nb_samples;
+            avci->last_pts = avpkt->pts;
         }
     }
 
@@ -1727,6 +1741,7 @@ void avcodec_flush_buffers(AVCodecContext *avctx)
         ff_thread_flush(avctx);
     else if (avctx->codec->flush)
         avctx->codec->flush(avctx);
+    avctx->internal->last_pts = avctx->internal->next_pts = AV_NOPTS_VALUE;
 }
 
 static void video_free_buffers(AVCodecContext *s)
-- 
1.7.1

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to