int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame) { AVFrame *tmp; int ret; av_assert0(avctx->codec_type == AVMEDIA_TYPE_VIDEO); if (!frame->data[0]) return ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF); if (av_frame_is_writable(frame)) return ff_decode_frame_props(avctx, frame); tmp = av_frame_alloc(); if (!tmp) return AVERROR(ENOMEM); av_frame_move_ref(tmp, frame); ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF); if (ret < 0) { av_frame_free(&tmp); return ret; } av_frame_copy(frame, tmp); av_frame_free(&tmp); return 0; }
static int ffmal_copy_frame(AVCodecContext *avctx, AVFrame *frame, MMAL_BUFFER_HEADER_T *buffer) { MMALDecodeContext *ctx = avctx->priv_data; int ret = 0; if (avctx->pix_fmt == AV_PIX_FMT_MMAL) { if (!ctx->pool_out) return AVERROR_UNKNOWN; // format change code failed with OOM previously if ((ret = ff_decode_frame_props(avctx, frame)) < 0) goto done; if ((ret = ffmmal_set_ref(frame, ctx->pool_out, buffer)) < 0) goto done; } else { int w = FFALIGN(avctx->width, 32); int h = FFALIGN(avctx->height, 16); char *ptr; int plane; int i; if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) goto done; ptr = buffer->data + buffer->type->video.offset[0]; for (i = 0; i < avctx->height; i++) memcpy(frame->data[0] + frame->linesize[0] * i, ptr + w * i, avctx->width); ptr += w * h; for (plane = 1; plane < 3; plane++) { for (i = 0; i < avctx->height / 2; i++) memcpy(frame->data[plane] + frame->linesize[plane] * i, ptr + w / 2 * i, (avctx->width + 1) / 2); ptr += w / 2 * h / 2; } } if (buffer->pts != MMAL_TIME_UNKNOWN) { frame->pkt_pts = buffer->pts; frame->pts = buffer->pts; } done: return ret; }
static int ffmal_copy_frame(AVCodecContext *avctx, AVFrame *frame, MMAL_BUFFER_HEADER_T *buffer) { MMALDecodeContext *ctx = avctx->priv_data; int ret = 0; if (avctx->pix_fmt == AV_PIX_FMT_MMAL) { if (!ctx->pool_out) return AVERROR_UNKNOWN; // format change code failed with OOM previously if ((ret = ff_decode_frame_props(avctx, frame)) < 0) goto done; if ((ret = ffmmal_set_ref(frame, ctx->pool_out, buffer)) < 0) goto done; } else { int w = FFALIGN(avctx->width, 32); int h = FFALIGN(avctx->height, 16); uint8_t *src[4]; int linesize[4]; if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) goto done; av_image_fill_arrays(src, linesize, buffer->data + buffer->type->video.offset[0], avctx->pix_fmt, w, h, 1); av_image_copy(frame->data, frame->linesize, src, linesize, avctx->pix_fmt, avctx->width, avctx->height); } frame->pts = buffer->pts == MMAL_TIME_UNKNOWN ? AV_NOPTS_VALUE : buffer->pts; #if FF_API_PKT_PTS FF_DISABLE_DEPRECATION_WARNINGS frame->pkt_pts = frame->pts; FF_ENABLE_DEPRECATION_WARNINGS #endif frame->pkt_dts = AV_NOPTS_VALUE; done: return ret; }
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)) { CuvidParsedFrame parsed_frame; CUVIDPROCPARAMS params; unsigned int pitch = 0; int offset = 0; int i; av_fifo_generic_read(ctx->frame_queue, &parsed_frame, sizeof(CuvidParsedFrame), NULL); memset(¶ms, 0, sizeof(params)); params.progressive_frame = parsed_frame.dispinfo.progressive_frame; params.second_field = parsed_frame.second_field; params.top_field_first = parsed_frame.dispinfo.top_field_first; ret = CHECK_CU(cuvidMapVideoFrame(ctx->cudecoder, parsed_frame.dispinfo.picture_index, &mapped_frame, &pitch, ¶ms)); if (ret < 0) goto error; if (avctx->pix_fmt == AV_PIX_FMT_CUDA) { ret = av_hwframe_get_buffer(ctx->hwframe, frame, 0); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "av_hwframe_get_buffer failed\n"); goto error; } ret = ff_decode_frame_props(avctx, frame); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "ff_decode_frame_props failed\n"); goto error; } for (i = 0; i < 2; i++) { CUDA_MEMCPY2D cpy = { .srcMemoryType = CU_MEMORYTYPE_DEVICE, .dstMemoryType = CU_MEMORYTYPE_DEVICE, .srcDevice = mapped_frame, .dstDevice = (CUdeviceptr)frame->data[i], .srcPitch = pitch, .dstPitch = frame->linesize[i], .srcY = offset, .WidthInBytes = FFMIN(pitch, frame->linesize[i]), .Height = avctx->height >> (i ? 1 : 0), }; ret = CHECK_CU(cuMemcpy2D(&cpy)); if (ret < 0) goto error; offset += avctx->coded_height; } } else if (avctx->pix_fmt == AV_PIX_FMT_NV12) {
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags) { const AVHWAccel *hwaccel = avctx->hwaccel; int override_dimensions = 1; int ret; switch (avctx->codec_type) { case AVMEDIA_TYPE_VIDEO: if (frame->width <= 0 || frame->height <= 0) { frame->width = FFMAX(avctx->width, avctx->coded_width); frame->height = FFMAX(avctx->height, avctx->coded_height); override_dimensions = 0; } if (frame->format < 0) frame->format = avctx->pix_fmt; if (!frame->sample_aspect_ratio.num) frame->sample_aspect_ratio = avctx->sample_aspect_ratio; if (av_image_check_sar(frame->width, frame->height, frame->sample_aspect_ratio) < 0) { av_log(avctx, AV_LOG_WARNING, "ignoring invalid SAR: %u/%u\n", frame->sample_aspect_ratio.num, frame->sample_aspect_ratio.den); frame->sample_aspect_ratio = (AVRational){ 0, 1 }; } if ((ret = av_image_check_size(avctx->width, avctx->height, 0, avctx)) < 0) return ret; break; case AVMEDIA_TYPE_AUDIO: if (!frame->sample_rate) frame->sample_rate = avctx->sample_rate; if (frame->format < 0) frame->format = avctx->sample_fmt; if (!frame->channel_layout) { if (avctx->channel_layout) { if (av_get_channel_layout_nb_channels(avctx->channel_layout) != avctx->channels) { av_log(avctx, AV_LOG_ERROR, "Inconsistent channel " "configuration.\n"); return AVERROR(EINVAL); } frame->channel_layout = avctx->channel_layout; } else { if (avctx->channels > FF_SANE_NB_CHANNELS) { av_log(avctx, AV_LOG_ERROR, "Too many channels: %d.\n", avctx->channels); return AVERROR(ENOSYS); } frame->channel_layout = av_get_default_channel_layout(avctx->channels); if (!frame->channel_layout) frame->channel_layout = (1ULL << avctx->channels) - 1; } } break; default: return AVERROR(EINVAL); } ret = ff_decode_frame_props(avctx, frame); if (ret < 0) return ret; if (hwaccel) { if (hwaccel->alloc_frame) { ret = hwaccel->alloc_frame(avctx, frame); goto end; } } else avctx->sw_pix_fmt = avctx->pix_fmt; ret = avctx->get_buffer2(avctx, frame, flags); if (ret < 0) goto end; ret = attach_decode_data(frame); if (ret < 0) goto end; end: if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions && !(avctx->codec->caps_internal & FF_CODEC_CAP_EXPORTS_CROPPING)) { frame->width = avctx->width; frame->height = avctx->height; } if (ret < 0) av_frame_unref(frame); return ret; }
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; } if (!cuvid_is_buffer_full(avctx)) { AVPacket pkt = {0}; ret = ff_decode_get_packet(avctx, &pkt); if (ret < 0 && ret != AVERROR_EOF) return ret; ret = cuvid_decode_packet(avctx, &pkt); av_packet_unref(&pkt); // cuvid_is_buffer_full() should avoid this. if (ret == AVERROR(EAGAIN)) ret = AVERROR_EXTERNAL; if (ret < 0 && ret != AVERROR_EOF) return ret; } ret = CHECK_CU(ctx->cudl->cuCtxPushCurrent(cuda_ctx)); if (ret < 0) return ret; if (av_fifo_size(ctx->frame_queue)) { const AVPixFmtDescriptor *pixdesc; CuvidParsedFrame parsed_frame; CUVIDPROCPARAMS params; unsigned int pitch = 0; int offset = 0; int i; av_fifo_generic_read(ctx->frame_queue, &parsed_frame, sizeof(CuvidParsedFrame), NULL); memset(¶ms, 0, sizeof(params)); params.progressive_frame = parsed_frame.dispinfo.progressive_frame; params.second_field = parsed_frame.second_field; params.top_field_first = parsed_frame.dispinfo.top_field_first; ret = CHECK_CU(ctx->cvdl->cuvidMapVideoFrame(ctx->cudecoder, parsed_frame.dispinfo.picture_index, &mapped_frame, &pitch, ¶ms)); if (ret < 0) goto error; if (avctx->pix_fmt == AV_PIX_FMT_CUDA) { ret = av_hwframe_get_buffer(ctx->hwframe, frame, 0); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "av_hwframe_get_buffer failed\n"); goto error; } ret = ff_decode_frame_props(avctx, frame); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "ff_decode_frame_props failed\n"); goto error; } pixdesc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); for (i = 0; i < pixdesc->nb_components; i++) { int height = avctx->height >> (i ? pixdesc->log2_chroma_h : 0); CUDA_MEMCPY2D cpy = { .srcMemoryType = CU_MEMORYTYPE_DEVICE, .dstMemoryType = CU_MEMORYTYPE_DEVICE, .srcDevice = mapped_frame, .dstDevice = (CUdeviceptr)frame->data[i], .srcPitch = pitch, .dstPitch = frame->linesize[i], .srcY = offset, .WidthInBytes = FFMIN(pitch, frame->linesize[i]), .Height = height, }; ret = CHECK_CU(ctx->cudl->cuMemcpy2DAsync(&cpy, device_hwctx->stream)); if (ret < 0) goto error; offset += height; } } else if (avctx->pix_fmt == AV_PIX_FMT_NV12 || avctx->pix_fmt == AV_PIX_FMT_P010 || avctx->pix_fmt == AV_PIX_FMT_P016 || avctx->pix_fmt == AV_PIX_FMT_YUV444P || avctx->pix_fmt == AV_PIX_FMT_YUV444P16) { unsigned int offset = 0; AVFrame *tmp_frame = av_frame_alloc(); if (!tmp_frame) { av_log(avctx, AV_LOG_ERROR, "av_frame_alloc failed\n"); ret = AVERROR(ENOMEM); goto error; } pixdesc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); tmp_frame->format = AV_PIX_FMT_CUDA; tmp_frame->hw_frames_ctx = av_buffer_ref(ctx->hwframe); tmp_frame->width = avctx->width; tmp_frame->height = avctx->height; /* * Note that the following logic would not work for three plane * YUV420 because the pitch value is different for the chroma * planes. */ for (i = 0; i < pixdesc->nb_components; i++) { tmp_frame->data[i] = (uint8_t*)mapped_frame + offset; tmp_frame->linesize[i] = pitch; offset += pitch * (avctx->height >> (i ? pixdesc->log2_chroma_h : 0)); } ret = ff_get_buffer(avctx, frame, 0); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "ff_get_buffer failed\n"); av_frame_free(&tmp_frame); goto error; } ret = av_hwframe_transfer_data(frame, tmp_frame, 0); if (ret) { av_log(avctx, AV_LOG_ERROR, "av_hwframe_transfer_data failed\n"); av_frame_free(&tmp_frame); goto error; } av_frame_free(&tmp_frame); } else {
static int cuvid_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, 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; if (ctx->bsf && avpkt->size) { if ((ret = av_packet_ref(&filter_packet, avpkt)) < 0) { av_log(avctx, AV_LOG_ERROR, "av_packet_ref failed\n"); return ret; } if ((ret = av_bsf_send_packet(ctx->bsf, &filter_packet)) < 0) { av_log(avctx, AV_LOG_ERROR, "av_bsf_send_packet failed\n"); av_packet_unref(&filter_packet); return ret; } if ((ret = av_bsf_receive_packet(ctx->bsf, &filtered_packet)) < 0) { av_log(avctx, AV_LOG_ERROR, "av_bsf_receive_packet failed\n"); return ret; } avpkt = &filtered_packet; } ret = CHECK_CU(cuCtxPushCurrent(cuda_ctx)); if (ret < 0) { av_packet_unref(&filtered_packet); return ret; } memset(&cupkt, 0, sizeof(cupkt)); if (avpkt->size) { cupkt.payload_size = avpkt->size; cupkt.payload = avpkt->data; if (avpkt->pts != AV_NOPTS_VALUE) { cupkt.flags = CUVID_PKT_TIMESTAMP; 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; } ret = CHECK_CU(cuvidParseVideoData(ctx->cuparser, &cupkt)); av_packet_unref(&filtered_packet); if (ret < 0) { 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; } if (av_fifo_size(ctx->frame_queue)) { CUVIDPARSERDISPINFO dispinfo; CUVIDPROCPARAMS params; unsigned int pitch = 0; int offset = 0; int i; av_fifo_generic_read(ctx->frame_queue, &dispinfo, sizeof(CUVIDPARSERDISPINFO), NULL); memset(¶ms, 0, sizeof(params)); params.progressive_frame = dispinfo.progressive_frame; params.second_field = 0; params.top_field_first = dispinfo.top_field_first; ret = CHECK_CU(cuvidMapVideoFrame(ctx->cudecoder, dispinfo.picture_index, &mapped_frame, &pitch, ¶ms)); if (ret < 0) goto error; if (avctx->pix_fmt == AV_PIX_FMT_CUDA) { ret = av_hwframe_get_buffer(ctx->hwframe, frame, 0); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "av_hwframe_get_buffer failed\n"); goto error; } ret = ff_decode_frame_props(avctx, frame); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "ff_decode_frame_props failed\n"); goto error; } for (i = 0; i < 2; i++) { CUDA_MEMCPY2D cpy = { .srcMemoryType = CU_MEMORYTYPE_DEVICE, .dstMemoryType = CU_MEMORYTYPE_DEVICE, .srcDevice = mapped_frame, .dstDevice = (CUdeviceptr)frame->data[i], .srcPitch = pitch, .dstPitch = frame->linesize[i], .srcY = offset, .WidthInBytes = FFMIN(pitch, frame->linesize[i]), .Height = avctx->coded_height >> (i ? 1 : 0), }; ret = CHECK_CU(cuMemcpy2D(&cpy)); if (ret < 0) goto error; offset += avctx->coded_height; } } else if (avctx->pix_fmt == AV_PIX_FMT_NV12) {