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)
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;
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;
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;
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;
}
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.
AVCUDADeviceContext *device_hwctx;
AVHWDeviceContext *device_ctx;
AVHWFramesContext *hwframe_ctx;
- CUVIDPARSERPARAMS cuparseinfo;
- CUVIDEOFORMATEX cuparse_ext;
CUVIDSOURCEDATAPACKET seq_pkt;
CUdevice device;
CUcontext cuda_ctx = NULL;
}
}
- 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:
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));
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:
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", \
.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, \
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