[FFmpeg-devel] [PATCH] Implement guessed_pts in avcodec_decode_video2.

Nicolas George nicolas.george
Sun Jan 30 20:28:39 CET 2011


Signed-off-by: Nicolas George <nicolas.george at normalesup.org>
---
 cmdutils.c           |   27 ---------------------------
 cmdutils.h           |   24 ------------------------
 ffmpeg.c             |   14 ++++++--------
 ffplay.c             |   10 +++-------
 libavcodec/avcodec.h |   20 ++++++++++++++++++++
 libavcodec/utils.c   |   43 ++++++++++++++++++++++++++++++++++++++++++-
 6 files changed, 71 insertions(+), 67 deletions(-)

This patch moves the guess_correct_pts function from cmdutils to libavcodec.
The feature is available through a new field in AVFrame, guessed_pts.

make test and ffplay still work, but I would like to have some more time to
read it carefully, but I have things to do in the next few days, and this
feature was discussed in another thread, so here the current version. It
will conflict with some patches that will certainly soon be applied, so I
will update and submit it again anyway.

Regards,

-- 
  Nicolas George

diff --git a/cmdutils.c b/cmdutils.c
index 58fe85c..8da138a 100644
--- a/cmdutils.c
+++ b/cmdutils.c
@@ -739,33 +739,6 @@ int read_file(const char *filename, char **bufptr, size_t *size)
     return 0;
 }
 
-void init_pts_correction(PtsCorrectionContext *ctx)
-{
-    ctx->num_faulty_pts = ctx->num_faulty_dts = 0;
-    ctx->last_pts = ctx->last_dts = INT64_MIN;
-}
-
-int64_t guess_correct_pts(PtsCorrectionContext *ctx, int64_t reordered_pts, int64_t dts)
-{
-    int64_t pts = AV_NOPTS_VALUE;
-
-    if (dts != AV_NOPTS_VALUE) {
-        ctx->num_faulty_dts += dts <= ctx->last_dts;
-        ctx->last_dts = dts;
-    }
-    if (reordered_pts != AV_NOPTS_VALUE) {
-        ctx->num_faulty_pts += reordered_pts <= ctx->last_pts;
-        ctx->last_pts = reordered_pts;
-    }
-    if ((ctx->num_faulty_pts<=ctx->num_faulty_dts || dts == AV_NOPTS_VALUE)
-       && reordered_pts != AV_NOPTS_VALUE)
-        pts = reordered_pts;
-    else
-        pts = dts;
-
-    return pts;
-}
-
 FILE *get_preset_file(char *filename, size_t filename_size,
                       const char *preset_name, int is_path, const char *codec_name)
 {
diff --git a/cmdutils.h b/cmdutils.h
index c3d8a42..b35b99b 100644
--- a/cmdutils.h
+++ b/cmdutils.h
@@ -235,30 +235,6 @@ int read_yesno(void);
  */
 int read_file(const char *filename, char **bufptr, size_t *size);
 
-typedef struct {
-    int64_t num_faulty_pts; /// Number of incorrect PTS values so far
-    int64_t num_faulty_dts; /// Number of incorrect DTS values so far
-    int64_t last_pts;       /// PTS of the last frame
-    int64_t last_dts;       /// DTS of the last frame
-} PtsCorrectionContext;
-
-/**
- * Reset the state of the PtsCorrectionContext.
- */
-void init_pts_correction(PtsCorrectionContext *ctx);
-
-/**
- * Attempt to guess proper monotonic timestamps for decoded video frames
- * which might have incorrect times. Input timestamps may wrap around, in
- * which case the output will as well.
- *
- * @param pts the pts field of the decoded AVPacket, as passed through
- * AVCodecContext.reordered_opaque
- * @param dts the dts field of the decoded AVPacket
- * @return one of the input values, may be AV_NOPTS_VALUE
- */
-int64_t guess_correct_pts(PtsCorrectionContext *ctx, int64_t pts, int64_t dts);
-
 /**
  * Get a file corresponding to a preset file.
  *
diff --git a/ffmpeg.c b/ffmpeg.c
index 691b73e..51f24b8 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -320,7 +320,6 @@ typedef struct AVInputStream {
     int64_t       next_pts;  /* synthetic pts for cases where pkt.pts
                                 is not defined */
     int64_t       pts;       /* current pts */
-    PtsCorrectionContext pts_ctx;
     int is_start;            /* is 1 at the start and after a discontinuity */
     int showed_multi_packet_warning;
     int is_past_recording_time;
@@ -1470,7 +1469,6 @@ static int output_packet(AVInputStream *ist, int ist_index,
     void *buffer_to_free;
     static unsigned int samples_size= 0;
     AVSubtitle subtitle, *subtitle_to_free;
-    int64_t pkt_pts = AV_NOPTS_VALUE;
 #if CONFIG_AVFILTER
     int frame_available;
 #endif
@@ -1486,6 +1484,8 @@ static int output_packet(AVInputStream *ist, int ist_index,
         av_init_packet(&avpkt);
         avpkt.data = NULL;
         avpkt.size = 0;
+        avpkt.dts = av_rescale_q(ist->next_pts, AV_TIME_BASE_Q,
+                                 ist->st->time_base);
         goto handle_eof;
     } else {
         avpkt = *pkt;
@@ -1493,8 +1493,6 @@ static int output_packet(AVInputStream *ist, int ist_index,
 
     if(pkt->dts != AV_NOPTS_VALUE)
         ist->next_pts = ist->pts = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q);
-    if(pkt->pts != AV_NOPTS_VALUE)
-        pkt_pts = av_rescale_q(pkt->pts, ist->st->time_base, AV_TIME_BASE_Q);
 
     //while we have more to decode or while the decoder did output something on EOF
     while (avpkt.size > 0 || (!pkt && ist->next_pts != ist->pts)) {
@@ -1547,8 +1545,6 @@ static int output_packet(AVInputStream *ist, int ist_index,
                     decoded_data_size = (ist->st->codec->width * ist->st->codec->height * 3) / 2;
                     /* XXX: allocate picture correctly */
                     avcodec_get_frame_defaults(&picture);
-                    ist->st->codec->reordered_opaque = pkt_pts;
-                    pkt_pts = AV_NOPTS_VALUE;
 
                     ret = avcodec_decode_video2(ist->st->codec,
                                                 &picture, &got_picture, &avpkt);
@@ -1559,7 +1555,10 @@ static int output_packet(AVInputStream *ist, int ist_index,
                         /* no picture yet */
                         goto discard_packet;
                     }
-                    ist->next_pts = ist->pts = guess_correct_pts(&ist->pts_ctx, picture.reordered_opaque, ist->pts);
+                    ist->next_pts = ist->pts =
+                        picture.guessed_pts == AV_NOPTS_VALUE ? AV_NOPTS_VALUE :
+                        av_rescale_q(picture.guessed_pts, ist->st->time_base,
+                                     AV_TIME_BASE_Q);;
                     if (ist->st->codec->time_base.num != 0) {
                         int ticks= ist->st->parser ? ist->st->parser->repeat_pict+1 : ist->st->codec->ticks_per_frame;
                         ist->next_pts += ((int64_t)AV_TIME_BASE *
@@ -2362,7 +2361,6 @@ static int transcode(AVFormatContext **output_files,
         st= ist->st;
         ist->pts = st->avg_frame_rate.num ? - st->codec->has_b_frames*AV_TIME_BASE / av_q2d(st->avg_frame_rate) : 0;
         ist->next_pts = AV_NOPTS_VALUE;
-        init_pts_correction(&ist->pts_ctx);
         ist->is_start = 1;
     }
 
diff --git a/ffplay.c b/ffplay.c
index 840df66..6ee577f 100644
--- a/ffplay.c
+++ b/ffplay.c
@@ -207,8 +207,6 @@ typedef struct VideoState {
     char filename[1024];
     int width, height, xleft, ytop;
 
-    PtsCorrectionContext pts_ctx;
-
 #if CONFIG_AVFILTER
     AVFilterContext *out_video_filter;          ///<the last filter in the video chain
 #endif
@@ -1285,7 +1283,7 @@ retry:
             if (is->audio_st && is->video_st)
                 av_diff = get_audio_clock(is) - get_video_clock(is);
             printf("%7.2f A-V:%7.3f s:%3.1f aq=%5dKB vq=%5dKB sq=%5dB f=%"PRId64"/%"PRId64"   \r",
-                   get_master_clock(is), av_diff, FFMAX(is->skip_frames-1, 0), aqsize / 1024, vqsize / 1024, sqsize, is->pts_ctx.num_faulty_dts, is->pts_ctx.num_faulty_pts);
+                   get_master_clock(is), av_diff, FFMAX(is->skip_frames-1, 0), aqsize / 1024, vqsize / 1024, sqsize, is->video_st->codec->pts_correction.num_faulty_dts, is->video_st->codec->pts_correction.num_faulty_pts);
             fflush(stdout);
             last_time = cur_time;
         }
@@ -1560,7 +1558,6 @@ static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacke
         is->video_current_pos = -1;
         SDL_UnlockMutex(is->pictq_mutex);
 
-        init_pts_correction(&is->pts_ctx);
         is->frame_last_pts = AV_NOPTS_VALUE;
         is->frame_last_delay = 0;
         is->frame_timer = (double)av_gettime() / 1000000.0;
@@ -1569,16 +1566,15 @@ static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacke
         return 0;
     }
 
-    is->video_st->codec->reordered_opaque = pkt->pts;
     len1 = avcodec_decode_video2(is->video_st->codec,
                                  frame, &got_picture,
                                  pkt);
 
     if (got_picture) {
         if (decoder_reorder_pts == -1) {
-            *pts = guess_correct_pts(&is->pts_ctx, frame->reordered_opaque, pkt->dts);
+            *pts = frame->guessed_pts;
         } else if (decoder_reorder_pts) {
-            *pts = frame->reordered_opaque;
+            *pts = frame->pkt_pts;
         } else {
             *pts = pkt->dts;
         }
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 601f8ed..c857de1 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -1025,6 +1025,13 @@ typedef struct AVPanScan{
      * - decoding: Read by user.\
      */\
     int64_t pkt_dts;\
+\
+    /**\
+     * pts estimated using various heuristics, in stream time base\
+     * - encoding: unused\
+     * - decoding: set by libavcodec, read by user.\
+     */\
+    int64_t guessed_pts;\
 
 
 #define FF_QSCALE_TYPE_MPEG1 0
@@ -2817,6 +2824,19 @@ typedef struct AVCodecContext {
      * - encoding: unused
      */
     AVPacket *pkt;
+
+    /**
+     * Current statistics for PTS correction.
+     * - decoding: maintained and used by libavcodec
+     * - encoding: unused
+     */
+    struct av_pts_correction_context {
+        int64_t num_faulty_pts; /// Number of incorrect PTS values so far
+        int64_t num_faulty_dts; /// Number of incorrect DTS values so far
+        int64_t last_pts;       /// PTS of the last frame
+        int64_t last_dts;       /// DTS of the last frame
+    } pts_correction;
+
 } AVCodecContext;
 
 /**
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index 53a0674..4390601 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -446,7 +446,7 @@ enum PixelFormat avcodec_default_get_format(struct AVCodecContext *s, const enum
 void avcodec_get_frame_defaults(AVFrame *pic){
     memset(pic, 0, sizeof(AVFrame));
 
-    pic->pts= AV_NOPTS_VALUE;
+    pic->pts = pic->guessed_pts = AV_NOPTS_VALUE;
     pic->key_frame= 1;
 }
 
@@ -536,6 +536,11 @@ int attribute_align_arg avcodec_open(AVCodecContext *avctx, AVCodec *codec)
         goto free_and_end;
     }
 
+    avctx->pts_correction.num_faulty_pts =
+    avctx->pts_correction.num_faulty_dts = 0;
+    avctx->pts_correction.last_pts =
+    avctx->pts_correction.last_dts = INT64_MIN;
+
     if(avctx->codec->init){
         ret = avctx->codec->init(avctx);
         if (ret < 0) {
@@ -606,6 +611,39 @@ int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size,
     return ret;
 }
 
+/**
+ * Attempt to guess proper monotonic timestamps for decoded video frames
+ * which might have incorrect times. Input timestamps may wrap around, in
+ * which case the output will as well.
+ *
+ * @param pts the pts field of the decoded AVPacket, as passed through
+ * AVFrame.pkt_pts
+ * @param dts the dts field of the decoded AVPacket
+ * @return one of the input values, may be AV_NOPTS_VALUE
+ */
+static int64_t guess_correct_pts(struct av_pts_correction_context *ctx,
+                                 int64_t reordered_pts, int64_t dts)
+{
+    int64_t pts = AV_NOPTS_VALUE;
+
+    if (dts != AV_NOPTS_VALUE) {
+        ctx->num_faulty_dts += dts <= ctx->last_dts;
+        ctx->last_dts = dts;
+    }
+    if (reordered_pts != AV_NOPTS_VALUE) {
+        ctx->num_faulty_pts += reordered_pts <= ctx->last_pts;
+        ctx->last_pts = reordered_pts;
+    }
+    if ((ctx->num_faulty_pts<=ctx->num_faulty_dts || dts == AV_NOPTS_VALUE)
+       && reordered_pts != AV_NOPTS_VALUE)
+        pts = reordered_pts;
+    else
+        pts = dts;
+
+    return pts;
+}
+
+
 #if FF_API_VIDEO_OLD
 int attribute_align_arg avcodec_decode_video(AVCodecContext *avctx, AVFrame *picture,
                          int *got_picture_ptr,
@@ -641,6 +679,9 @@ int attribute_align_arg avcodec_decode_video2(AVCodecContext *avctx, AVFrame *pi
         emms_c(); //needed to avoid an emms_c() call before every return;
 
         picture->pkt_dts= avpkt->dts;
+        picture->guessed_pts = guess_correct_pts(&avctx->pts_correction,
+                                                 picture->pkt_pts,
+                                                 picture->pkt_dts);
 
         if (*got_picture_ptr)
             avctx->frame_number++;
-- 
1.7.2.3




More information about the ffmpeg-devel mailing list