X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fcuvid.c;h=19a7772258edf84b2d817d0810a08c81ab984e9a;hb=e85c4a470651b58963095eb4dafb709313f33474;hp=1da0e87f7609a99399fae718c753fead76ae6b3b;hpb=475a686a0157a4f0243a0df4a02fadf469e5159c;p=ffmpeg diff --git a/libavcodec/cuvid.c b/libavcodec/cuvid.c index 1da0e87f760..19a7772258e 100644 --- a/libavcodec/cuvid.c +++ b/libavcodec/cuvid.c @@ -46,9 +46,13 @@ typedef struct CuvidContext AVFifoBuffer *frame_queue; int internal_error; + int ever_flushed; cudaVideoCodec codec_type; cudaVideoChromaFormat chroma_format; + + CUVIDPARSERPARAMS cuparseinfo; + CUVIDEOFORMATEX cuparse_ext; } CuvidContext; static int check_cu(AVCodecContext *avctx, CUresult err, const char *func) @@ -127,7 +131,7 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form return 0; } - if (hwframe_ctx->pool) { + if (hwframe_ctx->pool && !ctx->ever_flushed) { av_log(avctx, AV_LOG_ERROR, "AVHWFramesContext is already initialized\n"); ctx->internal_error = AVERROR(EINVAL); return 0; @@ -164,14 +168,16 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form if (ctx->internal_error < 0) return 0; - hwframe_ctx->format = AV_PIX_FMT_CUDA; - hwframe_ctx->sw_format = AV_PIX_FMT_NV12; - hwframe_ctx->width = FFALIGN(avctx->coded_width, 32); - hwframe_ctx->height = FFALIGN(avctx->coded_height, 32); + if (!hwframe_ctx->pool) { + hwframe_ctx->format = AV_PIX_FMT_CUDA; + hwframe_ctx->sw_format = AV_PIX_FMT_NV12; + hwframe_ctx->width = FFALIGN(avctx->coded_width, 32); + hwframe_ctx->height = FFALIGN(avctx->coded_height, 32); - if ((ctx->internal_error = av_hwframe_ctx_init(ctx->hwframe)) < 0) { - av_log(avctx, AV_LOG_ERROR, "av_hwframe_ctx_init failed\n"); - return 0; + if ((ctx->internal_error = av_hwframe_ctx_init(ctx->hwframe)) < 0) { + av_log(avctx, AV_LOG_ERROR, "av_hwframe_ctx_init failed\n"); + return 0; + } } return 1; @@ -252,7 +258,10 @@ static int cuvid_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, if (avpkt->pts != AV_NOPTS_VALUE) { cupkt.flags = CUVID_PKT_TIMESTAMP; - cupkt.timestamp = av_rescale_q(avpkt->pts, avctx->time_base, (AVRational){1, 10000000}); + if (avctx->pkt_timebase.num && avctx->pkt_timebase.den) + cupkt.timestamp = av_rescale_q(avpkt->pts, avctx->pkt_timebase, (AVRational){1, 10000000}); + else + cupkt.timestamp = avpkt->pts; } } else { cupkt.flags = CUVID_PKT_ENDOFSTREAM; @@ -263,8 +272,13 @@ static int cuvid_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, av_packet_unref(&filtered_packet); if (ret < 0) { - if (ctx->internal_error) - ret = ctx->internal_error; + goto error; + } + + // cuvidParseVideoData doesn't return an error just because stuff failed... + if (ctx->internal_error) { + av_log(avctx, AV_LOG_ERROR, "cuvid decode callback error\n"); + ret = ctx->internal_error; goto error; } @@ -357,7 +371,10 @@ static int cuvid_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, frame->width = avctx->width; frame->height = avctx->height; - frame->pts = av_rescale_q(dispinfo.timestamp, (AVRational){1, 10000000}, avctx->time_base); + if (avctx->pkt_timebase.num && avctx->pkt_timebase.den) + frame->pts = av_rescale_q(dispinfo.timestamp, (AVRational){1, 10000000}, avctx->pkt_timebase); + else + frame->pts = dispinfo.timestamp; /* CUVIDs opaque reordering breaks the internal pkt logic. * So set pkt_pts and clear all the other pkt_ fields. @@ -461,8 +478,6 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx) AVCUDADeviceContext *device_hwctx; AVHWDeviceContext *device_ctx; AVHWFramesContext *hwframe_ctx; - CUVIDPARSERPARAMS cuparseinfo; - CUVIDEOFORMATEX cuparse_ext; CUVIDSOURCEDATAPACKET seq_pkt; CUdevice device; CUcontext cuda_ctx = NULL; @@ -550,36 +565,61 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx) } } - memset(&cuparseinfo, 0, sizeof(cuparseinfo)); - memset(&cuparse_ext, 0, sizeof(cuparse_ext)); + memset(&ctx->cuparseinfo, 0, sizeof(ctx->cuparseinfo)); + memset(&ctx->cuparse_ext, 0, sizeof(ctx->cuparse_ext)); memset(&seq_pkt, 0, sizeof(seq_pkt)); - cuparseinfo.pExtVideoInfo = &cuparse_ext; + ctx->cuparseinfo.pExtVideoInfo = &ctx->cuparse_ext; switch (avctx->codec->id) { +#if CONFIG_H263_CUVID_DECODER + case AV_CODEC_ID_H263: + ctx->cuparseinfo.CodecType = cudaVideoCodec_MPEG4; + break; +#endif #if CONFIG_H264_CUVID_DECODER case AV_CODEC_ID_H264: - cuparseinfo.CodecType = cudaVideoCodec_H264; + ctx->cuparseinfo.CodecType = cudaVideoCodec_H264; break; #endif #if CONFIG_HEVC_CUVID_DECODER case AV_CODEC_ID_HEVC: - cuparseinfo.CodecType = cudaVideoCodec_HEVC; + ctx->cuparseinfo.CodecType = cudaVideoCodec_HEVC; + break; +#endif +#if CONFIG_MJPEG_CUVID_DECODER + case AV_CODEC_ID_MJPEG: + ctx->cuparseinfo.CodecType = cudaVideoCodec_JPEG; + break; +#endif +#if CONFIG_MPEG1_CUVID_DECODER + case AV_CODEC_ID_MPEG1VIDEO: + ctx->cuparseinfo.CodecType = cudaVideoCodec_MPEG1; + break; +#endif +#if CONFIG_MPEG2_CUVID_DECODER + case AV_CODEC_ID_MPEG2VIDEO: + ctx->cuparseinfo.CodecType = cudaVideoCodec_MPEG2; + break; +#endif +#if CONFIG_MPEG4_CUVID_DECODER + case AV_CODEC_ID_MPEG4: + ctx->cuparseinfo.CodecType = cudaVideoCodec_MPEG4; break; #endif #if CONFIG_VP8_CUVID_DECODER case AV_CODEC_ID_VP8: - cuparseinfo.CodecType = cudaVideoCodec_VP8; + ctx->cuparseinfo.CodecType = cudaVideoCodec_VP8; break; #endif #if CONFIG_VP9_CUVID_DECODER case AV_CODEC_ID_VP9: - cuparseinfo.CodecType = cudaVideoCodec_VP9; + ctx->cuparseinfo.CodecType = cudaVideoCodec_VP9; break; #endif #if CONFIG_VC1_CUVID_DECODER case AV_CODEC_ID_VC1: - cuparseinfo.CodecType = cudaVideoCodec_VC1; + ctx->cuparseinfo.CodecType = cudaVideoCodec_VC1; break; #endif default: @@ -605,38 +645,38 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx) goto error; } - cuparse_ext.format.seqhdr_data_length = ctx->bsf->par_out->extradata_size; - memcpy(cuparse_ext.raw_seqhdr_data, + ctx->cuparse_ext.format.seqhdr_data_length = ctx->bsf->par_out->extradata_size; + memcpy(ctx->cuparse_ext.raw_seqhdr_data, ctx->bsf->par_out->extradata, - FFMIN(sizeof(cuparse_ext.raw_seqhdr_data), ctx->bsf->par_out->extradata_size)); + FFMIN(sizeof(ctx->cuparse_ext.raw_seqhdr_data), ctx->bsf->par_out->extradata_size)); } else if (avctx->extradata_size > 0) { - cuparse_ext.format.seqhdr_data_length = avctx->extradata_size; - memcpy(cuparse_ext.raw_seqhdr_data, + ctx->cuparse_ext.format.seqhdr_data_length = avctx->extradata_size; + memcpy(ctx->cuparse_ext.raw_seqhdr_data, avctx->extradata, - FFMIN(sizeof(cuparse_ext.raw_seqhdr_data), avctx->extradata_size)); + FFMIN(sizeof(ctx->cuparse_ext.raw_seqhdr_data), avctx->extradata_size)); } - cuparseinfo.ulMaxNumDecodeSurfaces = MAX_FRAME_COUNT; - cuparseinfo.ulMaxDisplayDelay = 4; - cuparseinfo.pUserData = avctx; - cuparseinfo.pfnSequenceCallback = cuvid_handle_video_sequence; - cuparseinfo.pfnDecodePicture = cuvid_handle_picture_decode; - cuparseinfo.pfnDisplayPicture = cuvid_handle_picture_display; + ctx->cuparseinfo.ulMaxNumDecodeSurfaces = MAX_FRAME_COUNT; + ctx->cuparseinfo.ulMaxDisplayDelay = 4; + ctx->cuparseinfo.pUserData = avctx; + ctx->cuparseinfo.pfnSequenceCallback = cuvid_handle_video_sequence; + ctx->cuparseinfo.pfnDecodePicture = cuvid_handle_picture_decode; + ctx->cuparseinfo.pfnDisplayPicture = cuvid_handle_picture_display; ret = CHECK_CU(cuCtxPushCurrent(cuda_ctx)); if (ret < 0) goto error; - ret = cuvid_test_dummy_decoder(avctx, &cuparseinfo); + ret = cuvid_test_dummy_decoder(avctx, &ctx->cuparseinfo); if (ret < 0) goto error; - ret = CHECK_CU(cuvidCreateVideoParser(&ctx->cuparser, &cuparseinfo)); + ret = CHECK_CU(cuvidCreateVideoParser(&ctx->cuparser, &ctx->cuparseinfo)); if (ret < 0) goto error; - seq_pkt.payload = cuparse_ext.raw_seqhdr_data; - seq_pkt.payload_size = cuparse_ext.format.seqhdr_data_length; + seq_pkt.payload = ctx->cuparse_ext.raw_seqhdr_data; + seq_pkt.payload_size = ctx->cuparse_ext.format.seqhdr_data_length; if (seq_pkt.payload && seq_pkt.payload_size) { ret = CHECK_CU(cuvidParseVideoData(ctx->cuparser, &seq_pkt)); @@ -648,6 +688,11 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx) if (ret < 0) goto error; + ctx->ever_flushed = 0; + + if (!avctx->pkt_timebase.num || !avctx->pkt_timebase.den) + av_log(avctx, AV_LOG_WARNING, "Invalid pkt_timebase, passing timestamps as-is.\n"); + return 0; error: @@ -655,6 +700,51 @@ error: return ret; } +static void cuvid_flush(AVCodecContext *avctx) +{ + 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; + int ret; + + ctx->ever_flushed = 1; + + ret = CHECK_CU(cuCtxPushCurrent(cuda_ctx)); + if (ret < 0) + goto error; + + av_fifo_freep(&ctx->frame_queue); + + ctx->frame_queue = av_fifo_alloc(MAX_FRAME_COUNT * sizeof(CUVIDPARSERDISPINFO)); + if (!ctx->frame_queue) { + av_log(avctx, AV_LOG_ERROR, "Failed to recreate frame queue on flush\n"); + return; + } + + if (ctx->cudecoder) { + cuvidDestroyDecoder(ctx->cudecoder); + ctx->cudecoder = NULL; + } + + if (ctx->cuparser) { + cuvidDestroyVideoParser(ctx->cuparser); + ctx->cuparser = NULL; + } + + ret = CHECK_CU(cuvidCreateVideoParser(&ctx->cuparser, &ctx->cuparseinfo)); + if (ret < 0) + goto error; + + ret = CHECK_CU(cuCtxPopCurrent(&dummy)); + if (ret < 0) + goto error; + + return; + error: + av_log(avctx, AV_LOG_ERROR, "CUDA reinit on flush failed\n"); +} + #define DEFINE_CUVID_CODEC(x, X) \ AVHWAccel ff_##x##_cuvid_hwaccel = { \ .name = #x "_cuvid", \ @@ -671,6 +761,7 @@ error: .init = cuvid_decode_init, \ .close = cuvid_decode_end, \ .decode = cuvid_decode_frame, \ + .flush = cuvid_flush, \ .capabilities = AV_CODEC_CAP_DELAY, \ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_CUDA, \ AV_PIX_FMT_NV12, \ @@ -681,10 +772,30 @@ error: DEFINE_CUVID_CODEC(hevc, HEVC) #endif +#if CONFIG_H263_CUVID_DECODER +DEFINE_CUVID_CODEC(h263, H263) +#endif + #if CONFIG_H264_CUVID_DECODER DEFINE_CUVID_CODEC(h264, H264) #endif +#if CONFIG_MJPEG_CUVID_DECODER +DEFINE_CUVID_CODEC(mjpeg, MJPEG) +#endif + +#if CONFIG_MPEG1_CUVID_DECODER +DEFINE_CUVID_CODEC(mpeg1, MPEG1VIDEO) +#endif + +#if CONFIG_MPEG2_CUVID_DECODER +DEFINE_CUVID_CODEC(mpeg2, MPEG2VIDEO) +#endif + +#if CONFIG_MPEG4_CUVID_DECODER +DEFINE_CUVID_CODEC(mpeg4, MPEG4) +#endif + #if CONFIG_VP8_CUVID_DECODER DEFINE_CUVID_CODEC(vp8, VP8) #endif