avcodec/idctdsp: Clear idct/idct_add for studio profile
[ffmpeg.git] / libavcodec / crystalhd.c
index 7cf2c75..e3c5955 100644 (file)
  * is not just a function of time, but also one of the dependency on additional
  * frames being fed into the decoder to satisfy the b-frame dependencies.
  *
- * As such, a pipeline will build up that is roughly equivalent to the required
- * DPB for the file being played. If that was all it took, things would still
- * be simple - so, of course, it isn't.
- *
- * The hardware has a way of indicating that a picture is ready to be copied out,
- * but this is unreliable - and sometimes the attempt will still fail so, based
- * on testing, the code will wait until 3 pictures are ready before starting
- * to copy out - and this has the effect of extending the pipeline.
- *
- * Finally, while it is tempting to say that once the decoder starts outputting
- * frames, the software should never fail to return a frame from a decode(),
- * this is a hard assertion to make, because the stream may switch between
- * differently encoded content (number of b-frames, interlacing, etc) which
- * might require a longer pipeline than before. If that happened, you could
- * deadlock trying to retrieve a frame that can't be decoded without feeding
- * in additional packets.
- *
- * As such, the code will return in the event that a picture cannot be copied
- * out, leading to an increase in the length of the pipeline. This in turn,
- * means we have to be sensitive to the time it takes to decode a picture;
- * We do not want to give up just because the hardware needed a little more
- * time to prepare the picture! For this reason, there are delays included
- * in the decode() path that ensure that, under normal conditions, the hardware
- * will only fail to return a frame if it really needs additional packets to
- * complete the decoding.
- *
- * Finally, to be explicit, we do not want the pipeline to grow without bound
- * for two reasons: 1) The hardware can only buffer a finite number of packets,
- * and 2) The client application may not be able to cope with arbitrarily long
- * delays in the video path relative to the audio path. For example. MPlayer
- * can only handle a 20 picture delay (although this is arbitrary, and needs
- * to be extended to fully support the CrystalHD where the delay could be up
- * to 32 pictures - consider PAFF H.264 content with 16 b-frames).
+ * As such, the hardware can only be used effectively with a decode API that
+ * doesn't assume a 1:1 relationship between input packets and output frames.
+ * The new avcodec decode API is such an API (an m:n API) while the old one is
+ * 1:1. Consequently, we no longer support the old API, which allows us to avoid
+ * the vicious hacks that are required to approximate 1:1 operation.
  */
 
 /*****************************************************************************
@@ -83,6 +55,7 @@
 #include <libcrystalhd/libcrystalhd_if.h>
 
 #include "avcodec.h"
+#include "decode.h"
 #include "internal.h"
 #include "libavutil/imgutils.h"
 #include "libavutil/intreadwrite.h"
@@ -119,15 +92,7 @@ typedef struct {
     AVCodecContext *avctx;
     HANDLE dev;
 
-    uint8_t *orig_extradata;
-    uint32_t orig_extradata_size;
-
-    AVBSFContext *bsfc;
-
     uint8_t is_70012;
-    uint8_t *sps_pps_buf;
-    uint32_t sps_pps_size;
-    uint8_t is_nal;
     uint8_t need_second_field;
     uint8_t draining;
 
@@ -136,7 +101,6 @@ typedef struct {
 
     /* Options */
     uint32_t sWidth;
-    uint8_t bframe_bug;
 } CHDContext;
 
 static const AVOption options[] = {
@@ -167,7 +131,7 @@ static inline BC_MEDIA_SUBTYPE id2subtype(CHDContext *priv, enum AVCodecID id)
     case AV_CODEC_ID_WMV3:
         return BC_MSUBTYPE_WMV3;
     case AV_CODEC_ID_H264:
-        return priv->is_nal ? BC_MSUBTYPE_AVC1 : BC_MSUBTYPE_H264;
+        return BC_MSUBTYPE_H264;
     default:
         return BC_MSUBTYPE_INVALID;
     }
@@ -322,25 +286,6 @@ static av_cold int uninit(AVCodecContext *avctx)
     DtsCloseDecoder(device);
     DtsDeviceClose(device);
 
-    /*
-     * Restore original extradata, so that if the decoder is
-     * reinitialised, the bitstream detection and filtering
-     * will work as expected.
-     */
-    if (priv->orig_extradata) {
-        av_free(avctx->extradata);
-        avctx->extradata = priv->orig_extradata;
-        avctx->extradata_size = priv->orig_extradata_size;
-        priv->orig_extradata = NULL;
-        priv->orig_extradata_size = 0;
-    }
-
-    if (priv->bsfc) {
-        av_bsf_free(&priv->bsfc);
-    }
-
-    av_freep(&priv->sps_pps_buf);
-
     if (priv->head) {
        OpaqueList *node = priv->head;
        while (node) {
@@ -353,60 +298,9 @@ static av_cold int uninit(AVCodecContext *avctx)
     return 0;
 }
 
-
-static av_cold int init_bsf(AVCodecContext *avctx, const char *bsf_name)
-{
-    CHDContext *priv = avctx->priv_data;
-    const AVBitStreamFilter *bsf;
-    int avret;
-    void *extradata = NULL;
-    size_t size = 0;
-
-    bsf = av_bsf_get_by_name(bsf_name);
-    if (!bsf) {
-        av_log(avctx, AV_LOG_ERROR,
-               "Cannot open the %s BSF!\n", bsf_name);
-        return AVERROR_BSF_NOT_FOUND;
-    }
-
-    avret = av_bsf_alloc(bsf, &priv->bsfc);
-    if (avret != 0) {
-        return avret;
-    }
-
-    avret = avcodec_parameters_from_context(priv->bsfc->par_in, avctx);
-    if (avret != 0) {
-        return avret;
-    }
-
-    avret = av_bsf_init(priv->bsfc);
-    if (avret != 0) {
-        return avret;
-    }
-
-    /* Back up the extradata so it can be restored at close time. */
-    priv->orig_extradata = avctx->extradata;
-    priv->orig_extradata_size = avctx->extradata_size;
-
-    size = priv->bsfc->par_out->extradata_size;
-    extradata = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
-    if (!extradata) {
-        av_log(avctx, AV_LOG_ERROR,
-               "Failed to allocate copy of extradata\n");
-        return AVERROR(ENOMEM);
-    }
-    memcpy(extradata, priv->bsfc->par_out->extradata, size);
-
-    avctx->extradata = extradata;
-    avctx->extradata_size = size;
-
-    return 0;
-}
-
 static av_cold int init(AVCodecContext *avctx)
 {
     CHDContext* priv;
-    int avret;
     BC_STATUS ret;
     BC_INFO_CRYSTAL version;
     BC_INPUT_FORMAT format = {
@@ -434,21 +328,10 @@ static av_cold int init(AVCodecContext *avctx)
     /* Initialize the library */
     priv               = avctx->priv_data;
     priv->avctx        = avctx;
-    priv->is_nal       = avctx->extradata_size > 0 && *(avctx->extradata) == 1;
     priv->draining     = 0;
 
     subtype = id2subtype(priv, avctx->codec->id);
     switch (subtype) {
-    case BC_MSUBTYPE_AVC1:
-        avret = init_bsf(avctx, "h264_mp4toannexb");
-        if (avret != 0) {
-            return avret;
-        }
-        subtype = BC_MSUBTYPE_H264;
-        format.startCodeSz = 4;
-        format.pMetaData  = avctx->extradata;
-        format.metaDataSz = avctx->extradata_size;
-        break;
     case BC_MSUBTYPE_H264:
         format.startCodeSz = 4;
         // Fall-through
@@ -596,6 +479,9 @@ static inline CopyRet copy_frame(AVCodecContext *avctx,
     }
 
     bwidth = av_image_get_linesize(avctx->pix_fmt, width, 0);
+    if (bwidth < 0)
+       return RET_ERROR;
+
     if (priv->is_70012) {
         int pStride;
 
@@ -605,6 +491,8 @@ static inline CopyRet copy_frame(AVCodecContext *avctx,
             pStride = 1280;
         else pStride = 1920;
         sStride = av_image_get_linesize(avctx->pix_fmt, pStride, 0);
+        if (sStride < 0)
+            return RET_ERROR;
     } else {
         sStride = bwidth;
     }
@@ -648,17 +536,16 @@ static inline CopyRet copy_frame(AVCodecContext *avctx,
     if (interlaced)
         frame->top_field_first = !bottom_first;
 
-    if (pkt_pts != AV_NOPTS_VALUE) {
-        frame->pts = pkt_pts;
+    frame->pts = pkt_pts;
 #if FF_API_PKT_PTS
 FF_DISABLE_DEPRECATION_WARNINGS
-        frame->pkt_pts = pkt_pts;
+    frame->pkt_pts = pkt_pts;
 FF_ENABLE_DEPRECATION_WARNINGS
 #endif
-    }
-    av_frame_set_pkt_pos(frame, -1);
-    av_frame_set_pkt_duration(frame, 0);
-    av_frame_set_pkt_size(frame, -1);
+
+    frame->pkt_pos = -1;
+    frame->pkt_duration = 0;
+    frame->pkt_size = -1;
 
     if (!priv->need_second_field) {
         *got_frame       = 1;
@@ -743,16 +630,6 @@ static inline CopyRet receive_frame(AVCodecContext *avctx,
     } else if (ret == BC_STS_SUCCESS) {
         int copy_ret = -1;
         if (output.PoutFlags & BC_POUT_FLAGS_PIB_VALID) {
-            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");
-                }
-                DtsReleaseOutputBuffs(dev, NULL, FALSE);
-                return RET_COPY_AGAIN;
-            }
-
             print_frame_info(priv, &output);
 
             copy_ret = copy_frame(avctx, &output, frame, got_frame);
@@ -786,85 +663,35 @@ static int crystalhd_decode_packet(AVCodecContext *avctx, const AVPacket *avpkt)
     av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: decode_packet\n");
 
     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 };
-
-            ret = av_packet_ref(&filter_packet, avpkt);
-            if (ret < 0) {
-                av_log(avctx, AV_LOG_ERROR, "CrystalHD: mpv4toannexb filter "
-                       "failed to ref input packet\n");
-                goto exit;
-            }
-
-            ret = av_bsf_send_packet(priv->bsfc, &filter_packet);
-            if (ret < 0) {
-                av_log(avctx, AV_LOG_ERROR, "CrystalHD: mpv4toannexb filter "
-                       "failed to send input packet\n");
-                goto exit;
-            }
-
-            ret = av_bsf_receive_packet(priv->bsfc, &filtered_packet);
-            if (ret < 0) {
-                av_log(avctx, AV_LOG_ERROR, "CrystalHD: mpv4toannexb filter "
-                       "failed to receive output packet\n");
-                goto exit;
-            }
-
-            avpkt = &filtered_packet;
-            av_packet_unref(&filter_packet);
+        uint64_t pts;
+
+        /*
+         * Despite being notionally opaque, either libcrystalhd or
+         * the hardware itself will mangle pts values that are too
+         * small or too large. The docs claim it should be in units
+         * of 100ns. Given that we're nominally dealing with a black
+         * box on both sides, any transform we do has no guarantee of
+         * avoiding mangling so we need to build a mapping to values
+         * we know will not be mangled.
+         */
+        pts = opaque_list_push(priv, avpkt->pts);
+        if (!pts) {
+            ret = AVERROR(ENOMEM);
+            goto exit;
         }
-
-        if (avpkt->size < tx_free) {
-            /*
-             * Despite being notionally opaque, either libcrystalhd or
-             * the hardware itself will mangle pts values that are too
-             * small or too large. The docs claim it should be in units
-             * of 100ns. Given that we're nominally dealing with a black
-             * box on both sides, any transform we do has no guarantee of
-             * avoiding mangling so we need to build a mapping to values
-             * we know will not be mangled.
-             */
-            uint64_t pts = opaque_list_push(priv, avpkt->pts);
-            if (!pts) {
-                ret = AVERROR(ENOMEM);
-                goto exit;
-            }
-            av_log(priv->avctx, AV_LOG_VERBOSE,
-                   "input \"pts\": %"PRIu64"\n", pts);
-            bc_ret = DtsProcInput(dev, avpkt->data, avpkt->size, pts, 0);
-            if (bc_ret == BC_STS_BUSY) {
-                av_log(avctx, AV_LOG_WARNING,
-                       "CrystalHD: ProcInput returned busy\n");
-                ret = AVERROR(EAGAIN);
-                goto exit;
-            } else if (bc_ret != BC_STS_SUCCESS) {
-                av_log(avctx, AV_LOG_ERROR,
-                       "CrystalHD: ProcInput failed: %u\n", ret);
-                ret = -1;
-                goto exit;
-            }
-        } else {
-            av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Input buffer full\n");
+        av_log(priv->avctx, AV_LOG_VERBOSE,
+               "input \"pts\": %"PRIu64"\n", pts);
+        bc_ret = DtsProcInput(dev, avpkt->data, avpkt->size, pts, 0);
+        if (bc_ret == BC_STS_BUSY) {
+            av_log(avctx, AV_LOG_WARNING,
+                   "CrystalHD: ProcInput returned busy\n");
             ret = AVERROR(EAGAIN);
             goto exit;
+        } else if (bc_ret != BC_STS_SUCCESS) {
+            av_log(avctx, AV_LOG_ERROR,
+                   "CrystalHD: ProcInput failed: %u\n", ret);
+            ret = -1;
+            goto exit;
         }
     } else {
         av_log(avctx, AV_LOG_INFO, "CrystalHD: No more input data\n");
@@ -885,9 +712,35 @@ static int crystalhd_receive_frame(AVCodecContext *avctx, AVFrame *frame)
     CHDContext *priv   = avctx->priv_data;
     HANDLE dev         = priv->dev;
     int got_frame = 0;
+    int ret = 0;
+    AVPacket pkt = {0};
 
     av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: receive_frame\n");
 
+    ret = ff_decode_get_packet(avctx, &pkt);
+    if (ret < 0 && ret != AVERROR_EOF) {
+        return ret;
+    }
+
+    while (pkt.size > DtsTxFreeSize(dev)) {
+        /*
+         * Block until there is space in the buffer for the next packet.
+         * We assume that the hardware will make forward progress at this
+         * point, although in pathological cases that may not happen.
+         */
+        av_log(avctx, AV_LOG_TRACE, "CrystalHD: Waiting for space in input buffer\n");
+    }
+
+    ret = crystalhd_decode_packet(avctx, &pkt);
+    av_packet_unref(&pkt);
+    // crystalhd_is_buffer_full() should avoid this.
+    if (ret == AVERROR(EAGAIN)) {
+        ret = AVERROR_EXTERNAL;
+    }
+    if (ret < 0 && ret != AVERROR_EOF) {
+        return ret;
+    }
+
     do {
         bc_ret = DtsGetDriverStatus(dev, &decoder_status);
         if (bc_ret != BC_STS_SUCCESS) {
@@ -896,7 +749,7 @@ static int crystalhd_receive_frame(AVCodecContext *avctx, AVFrame *frame)
         }
 
         if (decoder_status.ReadyListCount == 0) {
-            av_log(avctx, AV_LOG_INFO, "CrystalHD: Insufficient frames ready. Returning\n");
+            av_log(avctx, AV_LOG_VERBOSE, "CrystalHD: Insufficient frames ready. Returning\n");
             got_frame = 0;
             rec_ret = RET_OK;
             break;
@@ -914,7 +767,7 @@ static int crystalhd_receive_frame(AVCodecContext *avctx, AVFrame *frame)
     }
 }
 
-#define DEFINE_CRYSTALHD_DECODER(x, X) \
+#define DEFINE_CRYSTALHD_DECODER(x, X, bsf_name) \
     static const AVClass x##_crystalhd_class = { \
         .class_name = #x "_crystalhd", \
         .item_name = av_default_item_name, \
@@ -930,33 +783,34 @@ static int crystalhd_receive_frame(AVCodecContext *avctx, AVFrame *frame)
         .priv_class     = &x##_crystalhd_class, \
         .init           = init, \
         .close          = uninit, \
-        .send_packet    = crystalhd_decode_packet, \
         .receive_frame  = crystalhd_receive_frame, \
         .flush          = flush, \
-        .capabilities   = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \
+        .bsfs           = bsf_name, \
+        .capabilities   = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \
         .pix_fmts       = (const enum AVPixelFormat[]){AV_PIX_FMT_YUYV422, AV_PIX_FMT_NONE}, \
+        .wrapper_name   = "crystalhd", \
     };
 
 #if CONFIG_H264_CRYSTALHD_DECODER
-DEFINE_CRYSTALHD_DECODER(h264, H264)
+DEFINE_CRYSTALHD_DECODER(h264, H264, "h264_mp4toannexb")
 #endif
 
 #if CONFIG_MPEG2_CRYSTALHD_DECODER
-DEFINE_CRYSTALHD_DECODER(mpeg2, MPEG2VIDEO)
+DEFINE_CRYSTALHD_DECODER(mpeg2, MPEG2VIDEO, NULL)
 #endif
 
 #if CONFIG_MPEG4_CRYSTALHD_DECODER
-DEFINE_CRYSTALHD_DECODER(mpeg4, MPEG4)
+DEFINE_CRYSTALHD_DECODER(mpeg4, MPEG4, "mpeg4_unpack_bframes")
 #endif
 
 #if CONFIG_MSMPEG4_CRYSTALHD_DECODER
-DEFINE_CRYSTALHD_DECODER(msmpeg4, MSMPEG4V3)
+DEFINE_CRYSTALHD_DECODER(msmpeg4, MSMPEG4V3, NULL)
 #endif
 
 #if CONFIG_VC1_CRYSTALHD_DECODER
-DEFINE_CRYSTALHD_DECODER(vc1, VC1)
+DEFINE_CRYSTALHD_DECODER(vc1, VC1, NULL)
 #endif
 
 #if CONFIG_WMV3_CRYSTALHD_DECODER
-DEFINE_CRYSTALHD_DECODER(wmv3, WMV3)
+DEFINE_CRYSTALHD_DECODER(wmv3, WMV3, NULL)
 #endif