[FFmpeg-cvslog] CrystalHD: Add heuristics to try and distinguish h.264 PAFF variants.

Philip Langdale git at videolan.org
Sun Mar 27 00:02:48 CET 2011


ffmpeg | branch: master | Philip Langdale <philipl at overt.org> | Wed Mar 16 22:27:51 2011 -0700| [4ab57cffba1d151898837a9a07a6a72f78716702] | committer: Philip Langdale

CrystalHD: Add heuristics to try and distinguish h.264 PAFF variants.

As previously discussed, the CrystalHD hardware treats some PAFF
clips different from others; even when input fields are always in
separate packets, the hardware might return a single fieldpair for
one clip and individual fields for another.

Given the bogus flags set by the hardware, it is impossible to
distinguish these two cases without knowing about the current
picture and the next one. The hardware can usually provide the
picture number of the next picture and when that is available,
we can detect the two cases.

When it is not available, we have to guess - and find out later
if we were right or wrong.

With this change, clips will play correctly unless they are PAFF
where individual fields are returned *and* no next picture number
is available. Generally speaking, the incorrect cases arise in
the first couple of seconds of a clip as the delay calibration takes
place. Once that's set, things work fine.

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=4ab57cffba1d151898837a9a07a6a72f78716702
---

 libavcodec/crystalhd.c |   59 +++++++++++++++++++++++++++++++++++------------
 1 files changed, 44 insertions(+), 15 deletions(-)

diff --git a/libavcodec/crystalhd.c b/libavcodec/crystalhd.c
index 452edef..132923c 100644
--- a/libavcodec/crystalhd.c
+++ b/libavcodec/crystalhd.c
@@ -506,23 +506,13 @@ static av_cold int init(AVCodecContext *avctx)
 }
 
 
-/*
- * The CrystalHD doesn't report interlaced H.264 content in a way that allows
- * us to distinguish between specific cases that require different handling.
- * So, for now, we have to hard-code the behaviour we want.
- *
- * Specifically, there are PAFF samples where input is always separate fields
- * but the hardware returns separate fields on one occasion and a field-pair
- * on another. The code assumes the first case and define
- * ASSUME_TWO_INPUTS_ONE_OUTPUT to assume the second case.
- */
-#define ASSUME_TWO_INPUTS_ONE_OUTPUT 0
 static inline CopyRet copy_frame(AVCodecContext *avctx,
                                  BC_DTS_PROC_OUT *output,
                                  void *data, int *data_size)
 {
     BC_STATUS ret;
     BC_DTS_STATUS decoder_status;
+    uint8_t confirmed_interlaced;
     uint8_t ignore_interlaced;
     uint8_t interlaced;
 
@@ -571,15 +561,47 @@ static inline CopyRet copy_frame(AVCodecContext *avctx,
     }
 
     /*
+     * If we're expecting a second field, or we know that the next
+     * picture has the same number as the current picture, then we're
+     * definitely interlaced.
+     *
+     * Note that this test can return false negatives if the hardware
+     * hasn't decoded the next picture or if there is a corruption in
+     * the stream. (In either case a 0 will be returned for the next
+     * picture number)
+     */
+    confirmed_interlaced = ((decoder_status.picNumFlags & ~0x40000000) ==
+                            output->PicInfo.picture_number) ||
+                            priv->need_second_field;
+
+    /*
+     * If we got a false negative for confirmed_interlaced on the first field,
+     * we will realise our mistake here when we see that the picture number is that
+     * of the previous picture. We cannot recover the frame and should discard the
+     * second field to keep the correct number of output frames.
+     */
+    if (output->PicInfo.picture_number == priv->last_picture && !priv->need_second_field) {
+        av_log(avctx, AV_LOG_WARNING,
+               "Incorrectly guessed progressie frame. Discarding second field\n");
+        /* Returning without providing a picture. */
+        return RET_OK;
+    }
+
+    /*
      * Testing has, so far, shown that we can't trust the interlaced flag for
      * H.264 content when VDEC_FLAG_UNKNOWN_SRC is set.
      */
     ignore_interlaced = avctx->codec->id == CODEC_ID_H264 &&
                         (output->PicInfo.flags & VDEC_FLAG_UNKNOWN_SRC) &&
                         (pic_type == 0 || pic_type == PICT_FRAME ||
-                         ASSUME_TWO_INPUTS_ONE_OUTPUT);
+                         !confirmed_interlaced);
     interlaced        = (output->PicInfo.flags & VDEC_FLAG_INTERLACED_SRC) &&
-                        !ignore_interlaced;
+                        (!ignore_interlaced || confirmed_interlaced);
+
+    if (ignore_interlaced && (decoder_status.picNumFlags & ~0x40000000) == 0) {
+        av_log(avctx, AV_LOG_WARNING,
+               "Next picture number unknown. Assuming progressive frame.\n");
+    }
 
     av_log(avctx, AV_LOG_VERBOSE, "Interlaced state: %d | ignore_interlaced %d\n",
            interlaced, ignore_interlaced);
@@ -650,8 +672,15 @@ static inline CopyRet copy_frame(AVCodecContext *avctx,
         *(AVFrame *)data = priv->pic;
     }
 
-    if (ASSUME_TWO_INPUTS_ONE_OUTPUT &&
-        output->PicInfo.flags & VDEC_FLAG_UNKNOWN_SRC) {
+    /*
+     * Two types of PAFF content have been observed. One form causes the
+     * hardware to return a field pair and the other individual fields,
+     * even though the input is always individual fields. We must skip
+     * copying on the next decode() call to maintain pipeline length in
+     * the first case.
+     */
+    if (!interlaced && (output->PicInfo.flags & VDEC_FLAG_UNKNOWN_SRC) &&
+        (pic_type == PICT_TOP_FIELD || pic_type == PICT_BOTTOM_FIELD)) {
         av_log(priv->avctx, AV_LOG_VERBOSE, "Fieldpair from two packets.\n");
         return RET_SKIP_NEXT_COPY;
     }




More information about the ffmpeg-cvslog mailing list