簡體   English   中英

FFMpeg DVB字幕內存泄漏

[英]FFMpeg DVB Subtitles memory leak

當從mpegts udp mutlicast流解碼字幕軌道時,我使用avcodec_decode_subtitle2遇到內存泄漏。 音頻和視頻流很好。 通過預分配所有緩沖區,對這三個流進行手動內存管理。

關於的信息很少,但我確實相信某個地方有補丁。

我目前正在使用為armv7-a編譯的ffmpeg 2.0.4。

在此過程中,我發現視頻流具有不同的分辨率,即720x576或576x576,現在這無關緊要,因為我將字幕分別渲染為視頻的疊加層。 我原來的解碼功能(正在更改以渲染單獨的疊加層)是:

void ffProcessSubtitlePacket( AVPacket *pkt )
{
    //LOGI("NATIVE FFMPEG SUBTITLE - Decoding subtitle packet");

    int got = 0;

    avcodec_decode_subtitle2(ffSubtitleContext, &ffSubtitleFrame, &got, pkt);

    if ( got )
    {
        //LOGI("NATIVE FFMPEG SUBTITLE - Got subtitle frame");
        //LOGI("NATIVE FFMPEG SUBTITLE - Format = %d, Start = %d, End = %d, Rects = %d, PTS = %llu, AudioPTS = %llu, PacketPTS = %llu",
        //      ffSubtitleFrame.format, ffSubtitleFrame.start_display_time,
        //      ffSubtitleFrame.end_display_time, ffSubtitleFrame.num_rects,
        //      ffSubtitleFrame.pts, ffAudioGetPTS(), pkt->pts);

        // now add the subtitle data to the list ready

        for ( int s = 0; s < ffSubtitleFrame.num_rects; s++ )
        {
            ffSubtitle *sub = (ffSubtitle*)mmAlloc(sizeof(ffSubtitle)); //new ffSubtitle;

            if ( sub )
            {
                AVSubtitleRect *r = ffSubtitleFrame.rects[s];
                AVPicture *p = &r->pict;

                // set main data

                sub->startPTS   = pkt->pts + (uint64_t)ffSubtitleFrame.start_display_time;
                sub->endPTS     = pkt->pts + (uint64_t)ffSubtitleFrame.end_display_time * (uint64_t)500;
                sub->nb_colors  = r->nb_colors;
                sub->xpos       = r->x;
                sub->ypos       = r->y;
                sub->width      = r->w;
                sub->height     = r->h;

                // allocate space for CLUT and image all in one chunk

                sub->data       = mmAlloc(r->nb_colors * 4 + r->w * r->h); //new char[r->nb_colors * 4 + r->w * r->h];

                if ( sub->data )
                {
                    // copy the CLUT data

                    memcpy(sub->data, p->data[1], r->nb_colors * 4);

                    // copy the bitmap onto the end

                    memcpy(sub->data + r->nb_colors * 4, p->data[0], r->w * r->h);

                    // check for duplicate subtitles and remove them as this
                    // one replaces it with a new bitmap data

                    int pos = ffSubtitles.size();

                    while ( pos-- )
                    {
                        ffSubtitle *s = ffSubtitles[pos];
                        if ( s->xpos == sub->xpos &&
                             s->ypos == sub->ypos &&
                             s->width == sub->width &&
                             s->height == sub->height )
                        {
                            //delete s;
                            ffSubtitles.erase( ffSubtitles.begin() + pos );

                            //LOGI("NATIVE FFMPEG SUBTITLE - Removed old duplicate subtitle, size %d", ffSubtitles.size());
                        }
                    }

                    // append to subtitles list

                    ffSubtitles.push_back( sub );

                    char *dat;  // data pointer used for the CLUT table

                    //LOGI("NATIVE FFMPEG SUBTITLE - Added %d,%d - %d,%d, Queue %d, Length = %d",
                    //  r->x, r->y, r->w, r->h, ffSubtitles.size(), ffSubtitleFrame.end_display_time);

                    // convert the CLUT (RGB) to YUV values

                    dat = sub->data;

                    for ( int c = 0; c < r->nb_colors; c++ )
                    {
                        int r = dat[0];
                        int g = dat[1];
                        int b = dat[2];

                        int y = ( (  65 * r + 128 * g +  24 * b + 128) >> 8) +  16;
                        int u = ( ( -37 * r -  74 * g + 112 * b + 128) >> 8) + 128;
                        int v = ( ( 112 * r -  93 * g -  18 * b + 128) >> 8) + 128;

                        *dat++ = (char)y;
                        *dat++ = (char)u;
                        *dat++ = (char)v;
                        dat++;  // skip the alpha channel
                    }
                }
                else
                {
                    //delete sub;
                    sub = 0;
                    LOGI("NATIVE FFMPEG SUBTITLE - Memory allocation error CLUT and BITMAP");
                }
            }
            else
            {
                LOGI("NATIVE FFMPEG SUBTITLE - Memory allocation error ffSubtitle struct");
                mmGarbageCollect();
                ffSubtitles.clear();
            }
        }
    }
}

void ffSubtitleRenderCheck(int bpos)
{
    if ( ffSubtitleID == -1 || !usingSubtitles )
    {
        // empty the list in case of memory leaks

        ffSubtitles.clear();
        mmGarbageCollect();
        return;
    }

    uint64_t audioPTS = ffAudioGetPTS();
    int pos = 0;

    // draw the subtitle list to the YUV frames

    char *yframe = ffVideoBuffers[bpos].yFrame;
    char *uframe = ffVideoBuffers[bpos].uFrame;
    char *vframe = ffVideoBuffers[bpos].vFrame;

    int ywidth = fv.frameActualWidth;   // actual width with padding
    int uvwidth = fv.frameAWidthHalf;   // and for uv frames

    while ( pos < ffSubtitles.size() )
    {
        ffSubtitle *sub = ffSubtitles[pos];

        if ( sub->startPTS >= audioPTS ) // okay to draw this one?
        {
            //LOGI("NATIVE FFMPEG SUBTITLE - Rendering subtitle bitmap %d", pos);

            char *clut = sub->data;     // colour table
            char *dat = clut + sub->nb_colors * 4; // start of bitmap data

            int w = sub->width;
            int h = sub->height;
            int x = sub->xpos;
            int y = sub->ypos;

            for ( int xpos = 0; xpos < w; xpos++ )
            {
                for ( int ypos = 0; ypos < h; ypos++ )
                {
                    // get colour for pixel
                    char bcol = dat[ypos * w + xpos];

                    if ( bcol != 0 )    // ignore 0 pixels
                    {
                        char cluty = clut[bcol * 4 + 0];    // get colours from CLUT
                        char clutu = clut[bcol * 4 + 1];
                        char clutv = clut[bcol * 4 + 2];

                        // draw to Y frame

                        int newx = x + xpos;
                        int newy = y + ypos;

                        yframe[newy * ywidth + newx] = cluty;

                        // draw to uv frames if we have a quarter pixel only

                        if ( ( newy & 1 ) && ( newx & 1 ) )
                        {
                            uframe[(newy >> 1) * uvwidth + (newx >> 1)] = clutu;
                            vframe[(newy >> 1) * uvwidth + (newx >> 1)] = clutv;
                        }
                    }
                }
            }
        }

        pos++;
    }

    // Last thing is to erase timed out subtitles

    pos = ffSubtitles.size();

    while ( pos-- )
    {
        ffSubtitle *sub = ffSubtitles[pos];

        if ( sub->endPTS < audioPTS )
        {
            //delete sub;
            ffSubtitles.erase( ffSubtitles.begin() + pos );

            //LOGI("NATIVE FFMPEG SUBTITLE - Removed timed out subtitle");
        }
    }

    if ( ffSubtitles.size() == 0 )
    {
        // garbage collect the custom memory pool

        mmGarbageCollect();
    }

    //LOGI("NATIVE FFMPEG SUBTITLE - Size of subtitle list = %d", ffSubtitles.size());
}

任何信息將不勝感激,還是我必須升級到ffmpeg的更高版本?

瀏覽完ffmpeg源代碼本身后,我發現了為什么內存泄漏。

事實證明,在解碼字幕幀時,在處理了獲得的幀中的信息之后,我所缺少的只是:

avsubtitle_free( &ffSubtitleFrame );

現在,我可以繼續進行項目的其余部分,並重寫字幕解碼器和渲染器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM