C# FFmpeg,通过Unity运行时av_frame_free上的访问冲突
我正在使用ffmpeg为Unity开发一个视频录制插件。我是视频编码领域的新手,今天刚开始使用我的代码。但我认为a可能有一些内存泄漏,并试图修复它们C# FFmpeg,通过Unity运行时av_frame_free上的访问冲突,c#,c++,unity3d,memory-leaks,ffmpeg,C#,C++,Unity3d,Memory Leaks,Ffmpeg,我正在使用ffmpeg为Unity开发一个视频录制插件。我是视频编码领域的新手,今天刚开始使用我的代码。但我认为a可能有一些内存泄漏,并试图修复它们 插件是用C++编写的(作为外部的C代码),并在一个C语言脚本中导入一个简单的DLIMPOLT。再说一次,这也不是我的舒适区,但它很有效 当呈现一个屏幕缓冲区时,我放进一个RGB24缓冲区并将其发送给我的C++函数,这个函数: int encode_frame(uint8_t* rgb24Data) { AVFrame *frame = av
插件是用C++编写的(作为外部的C代码),并在一个C语言脚本中导入一个简单的DLIMPOLT。再说一次,这也不是我的舒适区,但它很有效
当呈现一个屏幕缓冲区时,我放进一个RGB24缓冲区并将其发送给我的C++函数,这个函数:
int encode_frame(uint8_t* rgb24Data)
{
AVFrame *frame = av_frame_alloc();
if (!frame)
return COULD_NOT_ALLOCATE_FRAME;
frame->format = codec_context->pix_fmt;
frame->width = codec_context->width;
frame->height = codec_context->height;
int ret = av_image_alloc(frame->data, frame->linesize, codec_context->width, codec_context->height, codec_context->pix_fmt, 32);
if (ret < 0)
return COULD_NOT_ALLOCATE_PIC_BUF;
SwsContext * ctx = sws_getContext(codec_context->width, codec_context->height,
AV_PIX_FMT_RGB24, codec_context->width, codec_context->height,
AV_PIX_FMT_YUV420P, 0, 0, 0, 0);
uint8_t * inData[1] = { rgb24Data };
int inLinesize[1] = { 3 * codec_context->width };
sws_scale(ctx, inData, inLinesize, 0, codec_context->height, frame->data, frame->linesize); // From RGB to YUV
frame->pts = frame_counter++;
ret = avcodec_send_frame(codec_context, frame);
if (ret < 0)
return ERROR_ENCODING_FRAME_SEND;
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
while (true)
{
ret = avcodec_receive_packet(codec_context, &pkt);
if (!ret)
{
if (pkt.pts != AV_NOPTS_VALUE)
pkt.pts = av_rescale_q(pkt.pts, codec_context->time_base, video_st->time_base);
if (pkt.dts != AV_NOPTS_VALUE)
pkt.dts = av_rescale_q(pkt.dts, codec_context->time_base, video_st->time_base);
av_write_frame(outctx, &pkt);
av_packet_unref(&pkt);
}
else if (ret == AVERROR(EAGAIN))
{
frame->pts = frame_counter++;
ret = avcodec_send_frame(codec_context, frame);
if (ret < 0)
return ERROR_ENCODING_FRAME_SEND;
}
else if (ret < 0)
return ERROR_ENCODING_FRAME_RECEIVE;
else
break;
}
// This one
av_frame_free(&frame);
}
int编码帧(uint8*rgb24Data)
{
AVFrame*frame=av_frame_alloc();
如果(!帧)
返回无法分配帧;
帧->格式=编解码器\u上下文->pix\u fmt;
帧->宽度=编解码器上下文->宽度;
帧->高度=编解码器上下文->高度;
int-ret=av_-image_-alloc(帧->数据,帧->线宽,编解码器上下文->宽度,编解码器上下文->高度,编解码器上下文->pix_fmt,32);
如果(ret<0)
返回不能分配图片;
SwsContext*ctx=sws\u getContext(编解码器上下文->宽度,编解码器上下文->高度,
AV_PIX_FMT_RGB24,编解码器上下文->宽度,编解码器上下文->高度,
AV_PIX_FMT_YUV420P,0,0,0);
uint8_t*inData[1]={rgb24Data};
int inLinesize[1]={3*codec_context->width};
sws_比例(ctx、inData、inLinesize、0、编解码器_上下文->高度、帧->数据、帧->线宽);//从RGB到YUV
frame->pts=frame_counter++;
ret=avcodec\u发送\u帧(codec\u上下文,帧);
如果(ret<0)
返回错误\u编码\u帧\u发送;
AVPacket-pkt;
av_初始_数据包(&pkt);
pkt.data=NULL;
pkt.size=0;
while(true)
{
ret=avcodec\u receive\u数据包(codec\u上下文和pkt);
如果(!ret)
{
如果(pkt.pts!=平均值)
pkt.pts=av_rescale_q(pkt.pts,编解码器上下文->时基,视频->时基);
如果(pkt.dts!=平均值)
pkt.dts=av_rescale_q(pkt.dts,编解码器上下文->时基,视频->时基);
av写入帧(outctx和pkt);
av_数据包_unref(&pkt);
}
else if(ret==averor(EAGAIN))
{
frame->pts=frame_counter++;
ret=avcodec\u发送\u帧(codec\u上下文,帧);
如果(ret<0)
返回错误\u编码\u帧\u发送;
}
否则如果(ret<0)
返回错误\u编码\u帧\u接收;
其他的
打破
}
//这个
av_无帧(&帧);
}
现在,这段代码可能有很多我不知道的问题,如果您愿意,您可以自由地指出它们。但给出错误的行是av\u frame\u free(&frame)代码>
如果我用C++编写的合成测试应用程序运行,它就可以工作了。我甚至可以用C语言合成测试程序(就像C++一样)运行,它是有效的。但是如果我通过Unity运行它,它会在第一帧崩溃。日志显示“从位置fe7f8097读取导致访问冲突。”
我试过使用av\u freep()
和av\u free()
。不确定到底是什么使它们不同(不同的示例代码使用不同的代码),但都不起作用
那么,我错过了什么?如果我没有正确释放框架
会泄漏吗?但为什么它会在统一中崩溃呢
如果我没有av\u-frame\u-free(&frame),那么整件事在统一中工作得非常好代码>。结果视频看起来很棒
另外,据我所知,如果出现故障并返回错误代码,帧也会泄漏。但每次只做一件事。出于某种原因,您对同一帧进行了多次编码-这似乎是错误的,但不应导致崩溃。我看不出这个代码还有什么问题。作为一个无害的想法-尝试使用av\u frame\u get\u buffer
而不是av\u image\u alloc
,也许会有所帮助;“AVERROR(EAGAIN)返回值表示需要新的输入数据才能返回新的输出。在这种情况下,继续发送输入”。我应该一次发送更多的帧。呃,不。这只是意味着到目前为止编码器必须提供的一切都得到了。您应该在有新帧时继续发送它们,而不是重新发送您已经发送的帧。此函数中应该只有一个avcodec\u send\u frame
调用。谢谢!我没有意识到我看错了。我现在已经修复了它,问题可能是在编码完成之前,帧
数据还没有准备好发布。因为当我重用帧
对象,并且仅在编码完成后才取消分配它时(avcodec\u receive\u packet89()
返回NULL
),它工作了!根据文件,情况不应该如此;但至少有一个编码器有一个错误与非refcounted数据(h264_qsv)。因此,我建议使用av\u frame\u get\u buffer
——这将使您的图像数据重新计数,并与frame
对象更不耦合;这也可能让一切变得更快。