[FFmpeg-cvslog] avcodec/cuvid: implement new send_packet/receive_frame api

Timo Rothenpieler git at videolan.org
Wed Sep 21 19:28:32 EEST 2016


ffmpeg | branch: master | Timo Rothenpieler <timo at rothenpieler.org> | Sun Sep 18 00:52:10 2016 +0200| [3b24020b54a9b5b02d36d11a6c4160b833231aac] | committer: Timo Rothenpieler

avcodec/cuvid: implement new send_packet/receive_frame api

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

 libavcodec/cuvid.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 83 insertions(+), 11 deletions(-)

diff --git a/libavcodec/cuvid.c b/libavcodec/cuvid.c
index 540f2b7..78efc77 100644
--- a/libavcodec/cuvid.c
+++ b/libavcodec/cuvid.c
@@ -47,6 +47,7 @@ typedef struct CuvidContext
 
     int internal_error;
     int ever_flushed;
+    int decoder_flushing;
 
     cudaVideoCodec codec_type;
     cudaVideoChromaFormat chroma_format;
@@ -217,20 +218,26 @@ static int CUDAAPI cuvid_handle_picture_display(void *opaque, CUVIDPARSERDISPINF
     return 1;
 }
 
-static int cuvid_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
+static int cuvid_decode_packet(AVCodecContext *avctx, const AVPacket *avpkt)
 {
     CuvidContext *ctx = avctx->priv_data;
     AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)ctx->hwdevice->data;
     AVCUDADeviceContext *device_hwctx = device_ctx->hwctx;
     CUcontext dummy, cuda_ctx = device_hwctx->cuda_ctx;
-    AVFrame *frame = data;
     CUVIDSOURCEDATAPACKET cupkt;
     AVPacket filter_packet = { 0 };
     AVPacket filtered_packet = { 0 };
-    CUdeviceptr mapped_frame = 0;
-    int ret = 0, eret = 0;
+    int ret = 0, eret = 0, is_flush = ctx->decoder_flushing;
 
-    if (ctx->bsf && avpkt->size) {
+    av_log(avctx, AV_LOG_TRACE, "cuvid_decode_packet\n");
+
+    if (is_flush && avpkt && avpkt->size)
+        return AVERROR_EOF;
+
+    if (av_fifo_size(ctx->frame_queue) / sizeof(CUVIDPARSERDISPINFO) > MAX_FRAME_COUNT - 2 && avpkt && avpkt->size)
+        return AVERROR(EAGAIN);
+
+    if (ctx->bsf && avpkt && avpkt->size) {
         if ((ret = av_packet_ref(&filter_packet, avpkt)) < 0) {
             av_log(avctx, AV_LOG_ERROR, "av_packet_ref failed\n");
             return ret;
@@ -258,7 +265,7 @@ static int cuvid_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
 
     memset(&cupkt, 0, sizeof(cupkt));
 
-    if (avpkt->size) {
+    if (avpkt && avpkt->size) {
         cupkt.payload_size = avpkt->size;
         cupkt.payload = avpkt->data;
 
@@ -271,15 +278,15 @@ static int cuvid_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
         }
     } else {
         cupkt.flags = CUVID_PKT_ENDOFSTREAM;
+        ctx->decoder_flushing = 1;
     }
 
     ret = CHECK_CU(cuvidParseVideoData(ctx->cuparser, &cupkt));
 
     av_packet_unref(&filtered_packet);
 
-    if (ret < 0) {
+    if (ret < 0)
         goto error;
-    }
 
     // cuvidParseVideoData doesn't return an error just because stuff failed...
     if (ctx->internal_error) {
@@ -288,6 +295,40 @@ static int cuvid_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
         goto error;
     }
 
+error:
+    eret = CHECK_CU(cuCtxPopCurrent(&dummy));
+
+    if (eret < 0)
+        return eret;
+    else if (ret < 0)
+        return ret;
+    else if (is_flush)
+        return AVERROR_EOF;
+    else
+        return 0;
+}
+
+static int cuvid_output_frame(AVCodecContext *avctx, AVFrame *frame)
+{
+    CuvidContext *ctx = avctx->priv_data;
+    AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)ctx->hwdevice->data;
+    AVCUDADeviceContext *device_hwctx = device_ctx->hwctx;
+    CUcontext dummy, cuda_ctx = device_hwctx->cuda_ctx;
+    CUdeviceptr mapped_frame = 0;
+    int ret = 0, eret = 0;
+
+    av_log(avctx, AV_LOG_TRACE, "cuvid_output_frame\n");
+
+    if (ctx->decoder_flushing) {
+        ret = cuvid_decode_packet(avctx, NULL);
+        if (ret < 0 && ret != AVERROR_EOF)
+            return ret;
+    }
+
+    ret = CHECK_CU(cuCtxPushCurrent(cuda_ctx));
+    if (ret < 0)
+        return ret;
+
     if (av_fifo_size(ctx->frame_queue)) {
         CUVIDPARSERDISPINFO dispinfo;
         CUVIDPROCPARAMS params;
@@ -394,10 +435,10 @@ static int cuvid_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
 
         if (!dispinfo.progressive_frame)
             frame->top_field_first = dispinfo.top_field_first;
-
-        *got_frame = 1;
+    } else if (ctx->decoder_flushing) {
+        ret = AVERROR_EOF;
     } else {
-        *got_frame = 0;
+        ret = AVERROR(EAGAIN);
     }
 
 error:
@@ -412,6 +453,32 @@ error:
         return ret;
 }
 
+static int cuvid_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
+{
+    CuvidContext *ctx = avctx->priv_data;
+    AVFrame *frame = data;
+    int ret = 0;
+
+    av_log(avctx, AV_LOG_TRACE, "cuvid_decode_frame\n");
+
+    if (!ctx->decoder_flushing) {
+        ret = cuvid_decode_packet(avctx, avpkt);
+        if (ret < 0)
+            return ret;
+    }
+
+    ret = cuvid_output_frame(avctx, frame);
+    if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
+        *got_frame = 0;
+    } else if (ret < 0) {
+        return ret;
+    } else {
+        *got_frame = 1;
+    }
+
+    return 0;
+}
+
 static av_cold int cuvid_decode_end(AVCodecContext *avctx)
 {
     CuvidContext *ctx = avctx->priv_data;
@@ -756,6 +823,9 @@ static void cuvid_flush(AVCodecContext *avctx)
     if (ret < 0)
         goto error;
 
+    ctx->prev_pts = INT64_MIN;
+    ctx->decoder_flushing = 0;
+
     return;
  error:
     av_log(avctx, AV_LOG_ERROR, "CUDA reinit on flush failed\n");
@@ -777,6 +847,8 @@ static void cuvid_flush(AVCodecContext *avctx)
         .init           = cuvid_decode_init, \
         .close          = cuvid_decode_end, \
         .decode         = cuvid_decode_frame, \
+        .send_packet    = cuvid_decode_packet, \
+        .receive_frame  = cuvid_output_frame, \
         .flush          = cuvid_flush, \
         .capabilities   = AV_CODEC_CAP_DELAY, \
         .pix_fmts       = (const enum AVPixelFormat[]){ AV_PIX_FMT_CUDA, \



More information about the ffmpeg-cvslog mailing list