Утечка памяти при декодировании потока RTSP ffmpeg - PullRequest
0 голосов
/ 06 февраля 2019

Мне нужно декодировать поток rtsp с Ip-камеры с помощью ffmpeg, ниже приведен код для декодера

ffmpeg_decoder.h

class ffmpeg_decoder
{
public:
    ffmpeg_decoder();
    int initial(QString & url);
    int h264Decodec();
    void close_stream();
    virtual ~ffmpeg_decoder();
    AVPicture  picture;
    int width;
    int height;
    QMutex mutex;
    QImage imageDecoded;

private:
    AVFormatContext *pFormatCtx;
    AVCodecContext *pCodecCtx;
    AVFrame *pFrame;
    AVPacket packet;


    SwsContext * pSwsCtx;
    int videoStream;

    QString rtspURL;

};

ffmpeg_decoder.cpp

ffmpeg_decoder::ffmpeg_decoder()
{
    pCodecCtx = NULL;
    videoStream=-1;

}

ffmpeg_decoder::~ffmpeg_decoder()
{
    sws_freeContext(pSwsCtx);
}

int ffmpeg_decoder::initial(QString & url)
{
    int err;
    rtspURL=url;
    AVCodec *pCodec;
    av_register_all();
    avformat_network_init();
    pFormatCtx = avformat_alloc_context();
    pFrame = av_frame_alloc();
    err = avformat_open_input(&pFormatCtx, rtspURL.toStdString().c_str(), NULL,
                              NULL);
    if (err < 0)
    {
        printf("Can not open this file");
        return -1;
    }
    if (avformat_find_stream_info(pFormatCtx,NULL) < 0)
    {
        printf("Unable to get stream info");
        return -1;
    }
    int i = 0;
    videoStream = -1;
    for (i = 0; i < pFormatCtx->nb_streams; i++)
    {
        if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            videoStream = i;
            break;
        }
    }
    if (videoStream == -1)
    {
        printf("Unable to find video stream");
        return -1;
    }
    pCodecCtx = pFormatCtx->streams[videoStream]->codec;

    width=pCodecCtx->width;
    height=pCodecCtx->height;
    avpicture_alloc(&picture,PIX_FMT_RGB24,pCodecCtx->width,pCodecCtx->height);
    pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
    pSwsCtx = sws_getContext(width, height, PIX_FMT_YUV420P, width,
            height, PIX_FMT_RGB24,
            SWS_BICUBIC, 0, 0, 0);

    if (pCodec == NULL)
    {
        printf("Unsupported codec");
        return -1;
    }
    printf("video size : width=%d height=%d \n", pCodecCtx->width,
           pCodecCtx->height);
    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
    {
        printf("Unable to open codec");
        return -1;
    }
    printf("initial successfully");
    return 0;
}

int ffmpeg_decoder::h264Decodec()
{
    int frameFinished=0;
   // while (av_read_frame(pFormatCtx, &packet) >= 0)

    if(av_read_frame(pFormatCtx, &packet) >= 0)
    {
        if(packet.stream_index==videoStream)
        {
            avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
            if (frameFinished)
            {
                printf("***************ffmpeg decodec*******************\n");
                mutex.lock();
                int rs = sws_scale(pSwsCtx, (const uint8_t* const *) pFrame->data,
                                   pFrame->linesize, 0,
                                   height, picture.data, picture.linesize);

               imageDecoded = QImage();
               imageDecoded= QImage(this->picture.data[0],this->width,this->height,QImage::Format_RGB888);
               //imageDecoded = imageDecoded.copy();
                mutex.unlock();

                if (rs == -1)
                {
                    printf("__________Can open to change to des imag_____________e\n");
                    return -1;
                }
            }
        }
    }
    av_free_packet(&packet);
    av_frame_unref(pFrame);
    av_packet_unref(&packet);
    avpicture_free(&picture);


    return 1;

}

void ffmpeg_decoder::close_stream(){

    /*if (pFrame)
        av_free(&pFrame);*/

    if (pCodecCtx)
        avcodec_close(pCodecCtx);

    if (pSwsCtx)
        sws_freeContext(pSwsCtx);

    avpicture_free(&picture);

    if (pFormatCtx)
        avformat_close_input(&pFormatCtx);



}

Ниже приведен основной поток, который выполняет декодирование.

Я использую Qt для создания потока и выполняю декодирование

ffmpeg_decoder * ffmpeg =  new ffmpeg_decoder();;

if(ffmpeg->initial(rtspURL)==0){
    while (1) {

        ffmpeg->h264Decodec();
        //get frame and do processing right now it disabled, and still see the memory leak.
           .......

        if(stopFlg.load()==1)
            break;

    }
    //close stream if break
    ffmpeg->close_stream();

   }
   else {

       ffmpeg->close_stream();
   }

Когда язапустить поток 36 с другим URL. Я вижу, как со временем увеличивается использование памяти программой.

Я использовал valgrind для обнаружения утечки, и вот соответствующая часть журнала

Этопервое место утечки памяти

=14402==    by 0x692017F: av_malloc (in /usr/lib/x86_64-linux-gnu/libavutil-ffmpeg.so.54.31.100)
==14402==    by 0x692048D: av_mallocz (in /usr/lib/x86_64-linux-gnu/libavutil-ffmpeg.so.54.31.100)
==14402==    by 0x691915E: av_frame_alloc (in /usr/lib/x86_64-linux-gnu/libavutil-ffmpeg.so.54.31.100)
==14402==    by 0x419663: ffmpeg_decoder::initial(QString&) (ffmpeg_decoder.cpp:24)
==14402==    by 0x41ABEC: RTSP_Player_Object::run() (rtsp_player_object.cpp:15)

Другое

==14402== 2,176 bytes in 16 blocks are indirectly lost in loss record 23,113 of 23,379
==14402==    at 0x4C2E0EF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14402==    by 0x7780A4E: QImageData::create(unsigned char*, int, int, int, QImage::Format, bool, void (*)(void*), void*) (in /home/vapplica/Qt5.11.1/5.11.1/gcc_64/lib/libQt5Gui.so.5.11.1)
==14402==    by 0x7780C30: QImage::QImage(unsigned char*, int, int, QImage::Format, void (*)(void*), void*) (in /home/vapplica/Qt5.11.1/5.11.1/gcc_64/lib/libQt5Gui.so.5.11.1)
==14402==    by 0x419B21: ffmpeg_decoder::h264Decodec() (ffmpeg_decoder.cpp:96)

Я проверил документацию и пример на сайте ffmpeg и думаю, что освобождаю выделенную память, но все же могуувидеть утечку памяти при запуске программы.

...