今天在做编解码时,遇到一个奇怪的问题,就是av_image_alloc 导致内存泄漏,这点比较纳闷,场景是这样的,在视频传输过程中,需要根据网速来切换码流大小哦,如果带宽不够自动切换低码流传输,于是我将采集的1080p的视频转化成yuv格式发送。
过程如下:
首先初始化编解码环境:
if (_thumbCodecContext != nullptr && _thumbCodec != nullptr)
{
return 0;
}
int ret;
AVCodecID codec_id = AV_CODEC_ID_MJPEG;
int in_w = width, in_h = height;
_width = width;
_height = height;
int framenum = 1;
_thumbCodec = avcodec_find_encoder(codec_id);
if (!_thumbCodec) {
return 40;
}
_thumbCodecContext = avcodec_alloc_context3(_thumbCodec);
if (!_thumbCodecContext) {
return 40;
}
_thumbCodecContext->bit_rate = 1024 *1024 * 10;
_thumbCodecContext->width = scaleWidth;
_thumbCodecContext->height = scaleHeight;
_thumbCodecContext->time_base.num = 1;
_thumbCodecContext->time_base.den = 11;
_thumbCodecContext->gop_size = 10;
_thumbCodecContext->qcompress = 0.1;
_thumbCodecContext->pix_fmt = AV_PIX_FMT_YUVJ420P;
if (avcodec_open2(_thumbCodecContext, _thumbCodec, NULL) < 0) {
return 40;
}
_pktJPG = av_packet_alloc();
_thumbSwsContext = sws_getContext(in_w, in_h, AV_PIX_FMT_BGRA, _thumbCodecContext->width, _thumbCodecContext->height, AV_PIX_FMT_YUVJ420P, SWS_BICUBIC, NULL, NULL, NULL);
return 0;
然后进行视频的缩放以及编码:
static int pts = 1;
if (pts > 65535)
{
pts = 1;
}
// AVPacket *pkt = av_packet_alloc();
// avcodec_open2(_thumbCodecContext, _thumbCodec, nullptr);
// av_init_packet(_pktJPG);
// _pktJPG->data = nullptr;
// _pktJPG->size = 0;
int ret = 0;
AVFrame* _frameJPG = av_frame_alloc();
if (!_frameJPG) {
std::cout << "the frame jpg alloc is failure " << pts << " " << endl;
return 40;
}
_frameJPG->format = _thumbCodecContext->pix_fmt;
_frameJPG->width = _thumbCodecContext->width;
_frameJPG->height = _thumbCodecContext->height;
av_frame_get_buffer(_frameJPG, 1);
/*ret = av_image_alloc(_frameJPG->data, _frameJPG->linesize, _thumbCodecContext->width, _thumbCodecContext->height,
_thumbCodecContext->pix_fmt, 16);
if (ret < 0) {
std::cout << "the frame jpg data alloc is failure " << pts << " " << endl;
return 40;
}*/
//AVFrame *_frameRGB = av_frame_alloc();
//if (!_frameRGB) {
// std::cout << "the frame rgb alloc is failure " << pts << " " << endl;
// return 40;
//}
//_frameRGB->format = AV_PIX_FMT_BGRA;
//_frameRGB->width = _width;
//_frameRGB->height = _height;
//ret = av_image_alloc(_frameRGB->data, _frameRGB->linesize, _width, _height,
// AV_PIX_FMT_BGRA, 32);
//if (ret < 0) {
// std::cout << "the frame rgb data alloc is failure " << pts << " " << endl;
// return 40;
//}
//int file_size = 0;
//_frameRGB->data[0] = (unsigned char *)src;
//_frameRGB->data[0] += _frameRGB->linesize[0] * (_height - 1);
//_frameRGB->linesize[0] *= -1;
//_frameRGB->data[1] += _frameRGB->linesize[1] * (_height / 2 - 1);
//_frameRGB->linesize[1] *= -1;
//_frameRGB->data[2] += _frameRGB->linesize[2] * (_height / 2 - 1);
//_frameRGB->linesize[2] *= -1;
unsigned char *srcBuff[4] = { (unsigned char *)src,nullptr,nullptr,nullptr };
int srcStride[4] = { 4 * _width,0,0,0 };
sws_scale(_thumbSwsContext, (const uint8_t* const*)srcBuff, srcStride, 0, _height, _frameJPG->data, _frameJPG->linesize);
_frameJPG->pts = pts++;
avcodec_send_frame(_thumbCodecContext, _frameJPG);
ret = avcodec_receive_packet(_thumbCodecContext, _pktJPG);
if (ret < 0) {
std::cout << "the frame jpg encode is failure " << pts << " " << endl;
return 40;
}
size = _pktJPG->size;
//
memcpy(dst, _pktJPG->data, size);
// av_freep(pkt);
//// av_packet_unref(pkt);
av_frame_unref(_frameJPG);
// av_frame_unref(_frameRGB);
// avcodec_close(_thumbCodecContext);
av_frame_free(&_frameJPG);
// av_frame_free(&_frameRGB);
// av_frame_unref(_frameJPG);
// av_frame_unref(_frameRGB);
return 0;
这里我先将原来的码流进行缩放,然后进行编码,最后将裸码流拷贝出来即可。
一开始我将AVPacket的申请和管理放在每次编解码的时候,每次都会av_image_alloc后面在进行释放,此时会产生内存泄漏,而且相当大,基本相当于每次的原始码流。
更有奇葩的现象是这样,我将收到的原始裸流放到AVFrame中,通过sws_scale缩放倒另一个待编码AVFrame中,此时进行编码,会产生崩溃。大致意思是coremessaging.dll不能分配更多的内存,然后我直接将原始裸流进行缩放,此现象消失。
第三个问题是这样的,原始裸流存为AVFrame并缩放为目标AVFrame时,经过编码图像倒置。此时必须提前把原始裸流的
_frameRGB->data[0] = (unsigned char *)src;
//_frameRGB->data[0] += _frameRGB->linesize[0] * (_height - 1);
//_frameRGB->linesize[0] *= -1;
//_frameRGB->data[1] += _frameRGB->linesize[1] * (_height / 2 - 1);
//_frameRGB->linesize[1] *= -1;
//_frameRGB->data[2] += _frameRGB->linesize[2] * (_height / 2 - 1);
//_frameRGB->linesize[2] *= -1;
linesize 进行如下的操作,方可恢复正常。是因为rgb本来就是倒置扫描的,此时将linesize进行倒置即可。