crystalhd: Revert back to letting hardware handle packed b-frames
authorPhilip Langdale <philipl@overt.org>
Sat, 15 Oct 2016 22:50:29 +0000 (15:50 -0700)
committerPhilip Langdale <philipl@overt.org>
Wed, 2 Nov 2016 20:47:57 +0000 (13:47 -0700)
I'm not sure why, but the mpeg4_unpack_bframes bsf is not
interacting well with seeking. Looking at the code, it should be
ok, with possibly one warning shown, but I see it getting stuck
for an extended period of time after a seek where a packed frame
is cached to be shown later.

So, I gave up on that and went back to making the old hardware
based path work. Turns out that it wasn't broken except that some
samples have a 6 byte drop packet which I wasn't accounting for.

Now it works again and seeks are good.

libavcodec/crystalhd.c

index dca58f2..c1ca066 100644 (file)
@@ -140,6 +140,7 @@ typedef struct {
 
     /* Options */
     uint32_t sWidth;
+    uint8_t bframe_bug;
 } CHDContext;
 
 static const AVOption options[] = {
@@ -460,14 +461,6 @@ static av_cold int init(AVCodecContext *avctx)
         format.pMetaData  = avctx->extradata;
         format.metaDataSz = avctx->extradata_size;
         break;
-    case BC_MSUBTYPE_DIVX:
-        avret = init_bsf(avctx, "mpeg4_unpack_bframes");
-        if (avret != 0) {
-            return avret;
-        }
-        format.pMetaData  = avctx->extradata;
-        format.metaDataSz = avctx->extradata_size;
-        break;
     case BC_MSUBTYPE_H264:
         format.startCodeSz = 4;
         // Fall-through
@@ -476,6 +469,7 @@ static av_cold int init(AVCodecContext *avctx)
     case BC_MSUBTYPE_WMV3:
     case BC_MSUBTYPE_WMVA:
     case BC_MSUBTYPE_MPEG2VIDEO:
+    case BC_MSUBTYPE_DIVX:
     case BC_MSUBTYPE_DIVX311:
         format.pMetaData  = avctx->extradata;
         format.metaDataSz = avctx->extradata_size;
@@ -829,6 +823,17 @@ static inline CopyRet receive_frame(AVCodecContext *avctx,
                 priv->last_picture = output.PicInfo.picture_number - 1;
             }
 
+            if (avctx->codec->id == AV_CODEC_ID_MPEG4 &&
+                output.PicInfo.timeStamp == 0 && priv->bframe_bug) {
+                if (!priv->bframe_bug) {
+                    av_log(avctx, AV_LOG_VERBOSE,
+                           "CrystalHD: Not returning packed frame twice.\n");
+                }
+                priv->last_picture++;
+                DtsReleaseOutputBuffs(dev, NULL, FALSE);
+                return RET_COPY_AGAIN;
+            }
+
             print_frame_info(priv, &output);
 
             if (priv->last_picture + 1 < output.PicInfo.picture_number) {
@@ -879,6 +884,22 @@ static int crystalhd_decode_packet(AVCodecContext *avctx, const AVPacket *avpkt)
     if (avpkt && avpkt->size) {
         int32_t tx_free = (int32_t)DtsTxFreeSize(dev);
 
+        if (!priv->bframe_bug && (avpkt->size == 6 || avpkt->size == 7)) {
+            /*
+             * Drop frames trigger the bug
+             */
+            av_log(avctx, AV_LOG_WARNING,
+                   "CrystalHD: Enabling work-around for packed b-frame bug\n");
+            priv->bframe_bug = 1;
+        } else if (priv->bframe_bug && avpkt->size == 8) {
+            /*
+             * Delay frames don't trigger the bug
+             */
+            av_log(avctx, AV_LOG_WARNING,
+                   "CrystalHD: Disabling work-around for packed b-frame bug\n");
+            priv->bframe_bug = 0;
+        }
+
         if (priv->bsfc) {
             AVPacket filter_packet = { 0 };