I have implemented a class which spawns a thread for reading and queuing frames, and the main thread displays these frames via OpenGL. I try to free the allocated memory after binding the image data to a OpenGL texture, but it seems some memory is not freed properly. The memory usage keeps growing until the system runs out of memory and eventually the frame reader thread cannot grab new frames due to memory allocation failure. Would someone please help me on what I might have missed? Thank you.

This is the code for the frame reader thread:

```
void AVIReader::frameReaderThreadFunc()
{
    AVPacket packet;

    while (readFrames) {
        // Allocate necessary memory
        AVFrame* pFrame = av_frame_alloc();
        if (pFrame == nullptr)
        {
            continue;
        }

        AVFrame* pFrameRGB = av_frame_alloc();
        if (pFrameRGB == nullptr)
        {
            av_frame_free(&pFrame);
            continue;
        }

        // Determine required buffer size and allocate buffer
        int numBytes = avpicture_get_size(AV_PIX_FMT_RGB24, pCodecCtx->width,
            pCodecCtx->height);
        uint8_t* buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));

        if (buffer == nullptr)
        {
            av_frame_free(&pFrame);
            av_frame_free(&pFrameRGB);
            continue;
        }

        // Assign appropriate parts of buffer to image planes in pFrameRGB
        // Note that pFrameRGB is an AVFrame, but AVFrame is a superset
        // of AVPicture
        avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_RGB24,
            pCodecCtx->width, pCodecCtx->height);

        if (av_read_frame(pFormatCtx, &packet) >= 0) {
            // Is this a packet from the video stream?
            if (packet.stream_index == videoStream) {
                // Decode video frame
                int frameFinished;
                avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);

                if (frameFinished) {
                    // Convert the image from its native format to RGB
                    sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
                        pFrame->linesize, 0, pCodecCtx->height,
                        pFrameRGB->data, pFrameRGB->linesize);

                    VideoFrame vf;
                    vf.frame = pFrameRGB;
                    vf.pts = av_frame_get_best_effort_timestamp(pFrame) * time_base;
                    frameQueue.enqueue(vf);

                    av_frame_unref(pFrame);
                    av_frame_free(&pFrame);
                }
            }
            //av_packet_unref(&packet);
            av_free_packet(&packet);
        }
    }
}

```

This is the code that grabs the queued frames and binds it to an OpenGL texture. I explicitly save the previous frame until I switch it out with the next frame. Otherwise, it seems to cause a segfault.

```
void AVIReader::GrabAVIFrame()
{
    if (curFrame.pts >= clock_pts)
    {
        return;
    }

    if (frameQueue.empty())
        return;

    // Get a packet from the queue
    VideoFrame videoFrame = frameQueue.top();
    while (!frameQueue.empty() && frameQueue.top().pts < clock_pts)
    {
        videoFrame = frameQueue.dequeue();
    }

    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, videoFrame.frame->data[0]);

    // release previous frame
    if (curFrame.frame)
    {
        av_free(curFrame.frame->data[0]);
    }
    av_frame_unref(curFrame.frame);

    // set current frame to new frame
    curFrame = videoFrame;
}

```

The frameQueue is a thread-safe priority queue that holds VideoFrame defined as:

```
class VideoFrame {
public:
    AVFrame* frame;
    double pts;
};

```

**Update:** There was a silly error in the ordering of setting current frame to new frame. I forgot to switch it back after trying some things out. I also incorporated @ivan\_onys's suggestion, but that does not seem to fix the problem.

---

**Update 2:** I adopted @Al Bundy's suggestion to release pFrame and packet unconditionally, but the issue still persists. 

Since buffer is what contains the actual image data which needs to be used in glTexSubImage2D(), I cannot release it until I am done displaying it on the screen (otherwise I get a segfault). avpicture\_fill() assigns frame->data[0] = buffer, so I think calling av\_free(curFrame.frame->data[0]); on the previous frame after texture mapping the new frame should release the allocated buffer.

Here is the updated frame reader thread code:

```
void AVIReader::frameReaderThreadFunc()
{
    AVPacket packet;

    while (readFrames) {
        // Allocate necessary memory
        AVFrame* pFrame = av_frame_alloc();
        if (pFrame == nullptr)
        {
            continue;
        }

        AVFrame* pFrameRGB = av_frame_alloc();
        if (pFrameRGB == nullptr)
        {
            av_frame_free(&pFrame);
            continue;
        }

        // Determine required buffer size and allocate buffer
        int numBytes = avpicture_get_size(AV_PIX_FMT_RGB24, pCodecCtx->width,
            pCodecCtx->height);
        uint8_t* buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));

        if (buffer == nullptr)
        {
            av_frame_free(&pFrame);
            av_frame_free(&pFrameRGB);
            continue;
        }

        // Assign appropriate parts of buffer to image planes in pFrameRGB
        // Note that pFrameRGB is an AVFrame, but AVFrame is a superset
        // of AVPicture
        avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_RGB24,
            pCodecCtx->width, pCodecCtx->height);

        if (av_read_frame(pFormatCtx, &packet) >= 0) {
            // Is this a packet from the video stream?
            if (packet.stream_index == videoStream) {
                // Decode video frame
                int frameFinished;
                avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);

                if (frameFinished) {
                    // Convert the image from its native format to RGB
                    sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
                        pFrame->linesize, 0, pCodecCtx->height,
                        pFrameRGB->data, pFrameRGB->linesize);

                    VideoFrame vf;
                    vf.frame = pFrameRGB;
                    vf.pts = av_frame_get_best_effort_timestamp(pFrame) * time_base;
                    frameQueue.enqueue(vf);
                }
            }
        }
        av_frame_unref(pFrame);
        av_frame_free(&pFrame);
        av_packet_unref(&packet);
        av_free_packet(&packet);
    }
}

```

---

**Solved:** It turned out the leaks were happening when the packet was from a non-video stream (e.g. audio). I also needed to free resources on frames that are skipped in the while-loop of GrabAVIFrame().