2015-01-13 2 views
1

mpegts udp mutlicast 스트림에서 자막 트랙을 디코딩 할 때 avcodec_decode_subtitle2를 사용하여 메모리 누수가 발생합니다. 오디오 및 비디오 스트림은 문제가 없습니다. 그리고 세 개의 모든 스트림은 모든 버퍼를 미리 할당함으로써 수동으로 메모리 관리됩니다.FFMpeg DVB 자막 메모리 누수

정보가 거의 없지만 어딘가에 패치가 있다고 생각합니다.

저는 현재 안드로이드 용 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의 최신 버전으로 업그레이드해야?

답변

1

ffmpeg 소스 코드 자체를 살펴본 후 왜 메모리 누수가 발생하는지 알게되었습니다.

그것은 가지고 프레임의 정보를 처리 한 후, 자막 프레임을 디코딩 할 때 모든 I가 누락 된 것은이라고 밝혀 :

이제
avsubtitle_free(&ffSubtitleFrame); 

내가 프로젝트의 나머지 부분에 얻고 자막을 재 작성 할 수 있습니다 디코더 및 렌더러.