nyanmisaka / ffmpeg-rockchip

FFmpeg with async and zero-copy Rockchip MPP & RGA support
Other
325 stars 47 forks source link

请教使用scale_rkrga进行YUV420P/nv12转BGR24 #42

Closed szaipcljl closed 3 months ago

szaipcljl commented 3 months ago

下面代码是我编写的一个YUV420P转BGR24的方法,请问下使用scale_rkrga的硬件方式是这样的编写的吗? int DRtspDecoder::YUV420p2BGR24(AVFrame *src_frame, AVFrame **dst_frame) { if ((src_frame == NULL) || (dst_frame == NULL)) { std::cerr << "invalid input parameter" << std::endl; return -1; }

*dst_frame = NULL;
AVFilterContext *buffersink_ctx = NULL;
AVFilterContext *buffersrc_ctx = NULL;
AVFilterGraph *filter_graph = NULL;
const char *filter_descr = "scale_rkrga=format=bgr24";

// 初始化filter graph
filter_graph = avfilter_graph_alloc();
if (!filter_graph) {
    std::cerr << "failed to allocate filter graph" << std::endl;
    return -2;
}

// 创建buffersrc上下文
AVStream *input_stream = src_frame->opaque;  // 从源帧的opaque字段获取输入流信息
AVCodecParameters *input_codecpar = input_stream->codecpar;
AVPixelFormat input_pix_fmt = static_cast<AVPixelFormat>(input_codecpar->format);

AVFilter *buffersrc = avfilter_get_by_name("buffer");
if (!buffersrc) {
    std::cerr << "failed to get buffer filter" << std::endl;
    return -3;
}

AVCodecContext *codec_ctx = input_stream->codec;
char args[512];
snprintf(args, sizeof(args),
         "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
         codec_ctx->width, codec_ctx->height, input_pix_fmt,
         input_stream->time_base.num, input_stream->time_base.den,
         codec_ctx->sample_aspect_ratio.num, codec_ctx->sample_aspect_ratio.den);

int ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
                                       args, NULL, filter_graph);
if (ret < 0) {
    std::cerr << "failed to create buffer source filter" << std::endl;
    avfilter_graph_free(&filter_graph);
    return -4;
}

// 创建buffersink上下文
AVFilter *buffersink = avfilter_get_by_name("buffersink");
if (!buffersink) {
    std::cerr << "failed to get buffer sink filter" << std::endl;
    return -5;
}

AVPixelFormat output_pix_fmt = AV_PIX_FMT_BGR24;
AVCodecContext *output_codec_ctx = (*dst_frame)->opaque;  // 从目标帧的opaque字段获取输出流信息

ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
                                   NULL, NULL, filter_graph);
if (ret < 0) {
    std::cerr << "failed to create buffer sink filter" << std::endl;
    avfilter_graph_free(&filter_graph);
    return -6;
}

// 链接filters
ret = avfilter_link(buffersrc_ctx, 0, buffersink_ctx, 0);
if (ret < 0) {
    std::cerr << "failed to link filters" << std::endl;
    avfilter_graph_free(&filter_graph);
    return -7;
}

// 配置filter graph
ret = avfilter_graph_config(filter_graph, NULL);
if (ret < 0) {
    std::cerr << "failed to configure filter graph" << std::endl;
    avfilter_graph_free(&filter_graph);
    return -8;
}

AVFrame *temp_frame = av_frame_alloc();
if (!temp_frame) {
    std::cerr << "failed to allocate temporary frame" << std::endl;
    avfilter_graph_free(&filter_graph);
    return -9;
}

// 将输入帧数据填充到buffersrc_ctx中
ret = av_buffersrc_add_frame_flags(buffersrc_ctx, src_frame,
                                   AV_BUFFERSRC_FLAG_KEEP_REF);
if (ret < 0) {
    std::cerr << "failed to send source frame to buffer source filter" << std::endl;
    av_frame_free(&temp_frame);
    avfilter_graph_free(&filter_graph);
    return -10;
}

// 从buffersink_ctx中读取输出帧数据
ret = av_buffersink_get_frame(buffersink_ctx, temp_frame);
if (ret < 0) {
    std::cerr << "failed to get destination frame from buffer sink filter" << std::endl;
    av_frame_free(&temp_frame);
    avfilter_graph_free(&filter_graph);
    return -11;
}

// 分配目标帧并复制颜色转换后的数据
*dst_frame = av_frame_alloc();
if (!*dst_frame) {
    std::cerr << "failed to allocate destination frame" << std::endl;
    av_frame_free(&temp_frame);
    avfilter_graph_free(&filter_graph);
    return -12;
}

(*dst_frame)->width = output_codec_ctx->width;
(*dst_frame)->height = output_codec_ctx->height;
(*dst_frame)->format = output_pix_fmt;

ret = av_frame_get_buffer(*dst_frame, 0);
if (ret < 0) {
    std::cerr << "failed to allocate destination frame buffer" << std::endl;
    av_frame_free(&temp_frame);
    av_frame_free(&*dst_frame);
    avfilter_graph_free(&filter_graph);
    return -13;
}

ret = av_frame_copy_props(*dst_frame, temp_frame);
if (ret < 0) {
    std::cerr << "failed to copy frame properties" << std::endl;
    av_frame_free(&temp_frame);
    av_frame_free(&*dst_frame);
    avfilter_graph_free(&filter_graph);
    return -14;
}

// 将颜色转换后的数据复制到目标帧
ret = av_frame_copy(*dst_frame, temp_frame);
if (ret < 0) {
    std::cerr << "failed to copy destination frame" << std::endl;
    av_frame_free(&temp_frame);
    av_frame_free(&*dst_frame);
    avfilter_graph_free(&filter_graph);
    return -15;
}

av_frame_free(&temp_frame);
avfilter_graph_free(&filter_graph);
return 0;

}

nyanmisaka commented 3 months ago

No. The rkrga hardware filters only accept AV_PIX_FMT_DRM_PRIME input and produce AV_PIX_FMT_DRM_PRIME output.

nyanmisaka commented 3 months ago

Closing as it's not an issue.