FFmpeg中sws_scale后的AVFrame调用av_frame_copy返回-22如何解决
问题原因
返回值-22对应EINVAL(无效参数),触发原因是你调用av_frame_alloc()仅分配了AVFrame结构体本身的内存,没有为目标帧的像素数据分配实际缓冲区,也没有同步源帧的格式、宽高等核心参数。av_frame_copy()只会拷贝像素数据,不会自动完成缓冲区分配和参数同步,因此参数校验失败返回错误。av_frame_clone()内部会自动完成参数同步、缓冲区分配、数据拷贝全流程,它返回空说明你的源frameYUV本身的核心参数(格式、宽、高)存在非法值,需要先校验源帧的合法性。
正确复制流程(完全独立备份,新旧帧修改互不影响)
- 分配空AVFrame结构体
- 同步源帧的核心格式参数
- 为目标帧分配像素数据缓冲区
- 拷贝元数据和像素数据
修正后的代码示例
if ( packet && packet->stream_index == this->ctl->index ) { if ( avcodec_send_packet(this->ctl->context, packet) == 0 ) { while (1) { int ret = avcodec_receive_frame(this->ctl->context, this->ctl->frame); if ( ret == AVERROR(EAGAIN) || ret == AVERROR_EOF ) { break; } if ( ret == 0 ) { sws_scale(this->ctl->convertCtx, (const unsigned char* const*)this->ctl->frame->data, this->ctl->frame->linesize, 0, this->ctl->context->height, this->ctl->frameYUV->data, this->ctl->frameYUV->linesize); // 先校验源帧合法性,避免后续操作失败 if (this->ctl->frameYUV->width <= 0 || this->ctl->frameYUV->height <= 0 || this->ctl->frameYUV->format < 0) { break; } AVFrame* nf = av_frame_alloc(); if (!nf) { // 结构体分配失败,自行补充错误处理逻辑 break; } // 同步源帧核心参数 nf->format = this->ctl->frameYUV->format; nf->width = this->ctl->frameYUV->width; nf->height = this->ctl->frameYUV->height; // 分配像素数据缓冲区,第二个参数为对齐值,0表示自动选择默认对齐 ret = av_frame_get_buffer(nf, 0); if (ret < 0) { av_frame_free(&nf); // 缓冲区分配失败,自行补充错误处理逻辑 break; } // 拷贝元数据 int re1 = av_frame_copy_props(nf, this->ctl->frameYUV); // 拷贝像素数据 int re2 = av_frame_copy(nf, this->ctl->frameYUV); qDebug("result %d == %d ", re1, re2); emit decodeVideoFrame(this->ctl->frameYUV); usleep(21750); } } } }
可选简化方案
- 如果不需要完全独立的缓冲区,只是要延长源帧的生命周期,可以用
av_frame_ref(nf, this->ctl->frameYUV),此时新旧帧共享像素缓冲区,修改其中一帧会影响另一帧,不需要的时候分别调用av_frame_free()释放即可。 - 如果源帧参数完全合法,
av_frame_clone(this->ctl->frameYUV)可以替代上面所有分配、参数同步、拷贝的流程,返回的帧就是完全独立的备份,只需要后续记得释放即可。如果该接口返回空,优先排查源frameYUV的初始化逻辑,确认你在分配frameYUV的时候有没有正确设置format/width/height参数,再调用av_frame_get_buffer分配缓冲区。
内容的提问来源于stack exchange,提问作者anduinChan
相关产品推荐
相关产品推荐

