今天在做编解码时,遇到一个奇怪的问题,就是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进行倒置即可。