Commit 3b24020b authored by Timo Rothenpieler's avatar Timo Rothenpieler

avcodec/cuvid: implement new send_packet/receive_frame api

parent 47ffcdda
...@@ -47,6 +47,7 @@ typedef struct CuvidContext ...@@ -47,6 +47,7 @@ typedef struct CuvidContext
int internal_error; int internal_error;
int ever_flushed; int ever_flushed;
int decoder_flushing;
cudaVideoCodec codec_type; cudaVideoCodec codec_type;
cudaVideoChromaFormat chroma_format; cudaVideoChromaFormat chroma_format;
...@@ -217,20 +218,26 @@ static int CUDAAPI cuvid_handle_picture_display(void *opaque, CUVIDPARSERDISPINF ...@@ -217,20 +218,26 @@ static int CUDAAPI cuvid_handle_picture_display(void *opaque, CUVIDPARSERDISPINF
return 1; 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; CuvidContext *ctx = avctx->priv_data;
AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)ctx->hwdevice->data; AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)ctx->hwdevice->data;
AVCUDADeviceContext *device_hwctx = device_ctx->hwctx; AVCUDADeviceContext *device_hwctx = device_ctx->hwctx;
CUcontext dummy, cuda_ctx = device_hwctx->cuda_ctx; CUcontext dummy, cuda_ctx = device_hwctx->cuda_ctx;
AVFrame *frame = data;
CUVIDSOURCEDATAPACKET cupkt; CUVIDSOURCEDATAPACKET cupkt;
AVPacket filter_packet = { 0 }; AVPacket filter_packet = { 0 };
AVPacket filtered_packet = { 0 }; AVPacket filtered_packet = { 0 };
CUdeviceptr mapped_frame = 0; int ret = 0, eret = 0, is_flush = ctx->decoder_flushing;
int ret = 0, eret = 0;
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) { if ((ret = av_packet_ref(&filter_packet, avpkt)) < 0) {
av_log(avctx, AV_LOG_ERROR, "av_packet_ref failed\n"); av_log(avctx, AV_LOG_ERROR, "av_packet_ref failed\n");
return ret; return ret;
...@@ -258,7 +265,7 @@ static int cuvid_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, ...@@ -258,7 +265,7 @@ static int cuvid_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
memset(&cupkt, 0, sizeof(cupkt)); memset(&cupkt, 0, sizeof(cupkt));
if (avpkt->size) { if (avpkt && avpkt->size) {
cupkt.payload_size = avpkt->size; cupkt.payload_size = avpkt->size;
cupkt.payload = avpkt->data; cupkt.payload = avpkt->data;
...@@ -271,15 +278,15 @@ static int cuvid_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, ...@@ -271,15 +278,15 @@ static int cuvid_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
} }
} else { } else {
cupkt.flags = CUVID_PKT_ENDOFSTREAM; cupkt.flags = CUVID_PKT_ENDOFSTREAM;
ctx->decoder_flushing = 1;
} }
ret = CHECK_CU(cuvidParseVideoData(ctx->cuparser, &cupkt)); ret = CHECK_CU(cuvidParseVideoData(ctx->cuparser, &cupkt));
av_packet_unref(&filtered_packet); av_packet_unref(&filtered_packet);
if (ret < 0) { if (ret < 0)
goto error; goto error;
}
// cuvidParseVideoData doesn't return an error just because stuff failed... // cuvidParseVideoData doesn't return an error just because stuff failed...
if (ctx->internal_error) { if (ctx->internal_error) {
...@@ -288,6 +295,40 @@ static int cuvid_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, ...@@ -288,6 +295,40 @@ static int cuvid_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
goto error; 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)) { if (av_fifo_size(ctx->frame_queue)) {
CUVIDPARSERDISPINFO dispinfo; CUVIDPARSERDISPINFO dispinfo;
CUVIDPROCPARAMS params; CUVIDPROCPARAMS params;
...@@ -394,10 +435,10 @@ static int cuvid_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, ...@@ -394,10 +435,10 @@ static int cuvid_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
if (!dispinfo.progressive_frame) if (!dispinfo.progressive_frame)
frame->top_field_first = dispinfo.top_field_first; frame->top_field_first = dispinfo.top_field_first;
} else if (ctx->decoder_flushing) {
*got_frame = 1; ret = AVERROR_EOF;
} else { } else {
*got_frame = 0; ret = AVERROR(EAGAIN);
} }
error: error:
...@@ -412,6 +453,32 @@ error: ...@@ -412,6 +453,32 @@ error:
return ret; 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) static av_cold int cuvid_decode_end(AVCodecContext *avctx)
{ {
CuvidContext *ctx = avctx->priv_data; CuvidContext *ctx = avctx->priv_data;
...@@ -756,6 +823,9 @@ static void cuvid_flush(AVCodecContext *avctx) ...@@ -756,6 +823,9 @@ static void cuvid_flush(AVCodecContext *avctx)
if (ret < 0) if (ret < 0)
goto error; goto error;
ctx->prev_pts = INT64_MIN;
ctx->decoder_flushing = 0;
return; return;
error: error:
av_log(avctx, AV_LOG_ERROR, "CUDA reinit on flush failed\n"); av_log(avctx, AV_LOG_ERROR, "CUDA reinit on flush failed\n");
...@@ -777,6 +847,8 @@ static void cuvid_flush(AVCodecContext *avctx) ...@@ -777,6 +847,8 @@ static void cuvid_flush(AVCodecContext *avctx)
.init = cuvid_decode_init, \ .init = cuvid_decode_init, \
.close = cuvid_decode_end, \ .close = cuvid_decode_end, \
.decode = cuvid_decode_frame, \ .decode = cuvid_decode_frame, \
.send_packet = cuvid_decode_packet, \
.receive_frame = cuvid_output_frame, \
.flush = cuvid_flush, \ .flush = cuvid_flush, \
.capabilities = AV_CODEC_CAP_DELAY, \ .capabilities = AV_CODEC_CAP_DELAY, \
.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_CUDA, \ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_CUDA, \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment