5

インターネットで見つけたライブラリを変更した単純なライブラリを開発しました。

怖いのは、aviを再生すると、ビデオが終了すると再生されてメモリが解放されますが、ビデオを再生すると、メモリリークのようなものです。ビデオが終了し、FreeAllメソッド(コンテキストなどを削除する関数など)が呼び出されたにもかかわらず、138MBに増加します。

メモリリークの原因となっているメソッドのコードは次のとおりです。

int VideoGL::NextVideoFrame(){
int frameDone = 0;
int result = 0;
double pts = 0;

if(!this->ended){

if (!_started) return 0;
AVPacket* packet;

// Get the number of milliseconds passed and see if we should display a new frame
int64_t msPassed = (1000 * (clock() - _baseTime)) / CLOCKS_PER_SEC;
if (msPassed >= _currentPts)
{
    // If this is not the current frame, copy it to the buffer
    if (_currentFramePts != _currentPts){
        _currentFramePts = _currentPts;
        memcpy(buffer_a,buffer, 3 * _codec_context_video->width * _codec_context_video->height);
        result = 1;
    }

    // Try to load a new frame from the video packet queue
    bool goodop=false;
    AVFrame *_n_frame = avcodec_alloc_frame();
    while (!frameDone && (packet = this->DEQUEUE(VIDEO)) != NULL)
    {
        if (packet == (AVPacket*)-1) return -1;

        goodop=true;

        _s_pts = packet->pts;
        avcodec_decode_video2(_codec_context_video, _n_frame, &frameDone, packet);
        av_free_packet(packet);

        if (packet->dts == AV_NOPTS_VALUE)
        {
            if (_n_frame->opaque && *(uint64_t*)_n_frame->opaque != AV_NOPTS_VALUE) pts = (double) *(uint64_t*)_n_frame->opaque;
            else pts = 0;
        }
        else pts = (double) packet->dts;

        pts *= av_q2d(_codec_context_video->time_base);

    }

    if (frameDone)
    {
        // if a frame was loaded scale it to the current texture frame buffer, but also set the pts so that it won't be copied to the texture until it's time
        sws_scale(sws_ctx,_n_frame->data, _n_frame->linesize, 0, _codec_context_video->height, _rgb_frame->data, _rgb_frame->linesize);


        double nts = 1.0/av_q2d(_codec_context_video->time_base);
        _currentPts = (uint64_t) (pts*nts);

    }

    avcodec_free_frame(&_n_frame);
    av_free(_n_frame);

    if(!goodop){
        ended=true;
    }
}
}

return result;
}

答えを待っています、ありがとう。

4

3 に答える 3

2

メモリリークの問題もありました。私にとっては、次のコマンドを含めたときに割り当て解除が機能しました。

クラスメンバー:

AVPacket avpkt;
AVFrame *frame;
AVCodecContext *avctx;
AVCodec *codec;

コンストラクタ:

av_init_packet(&avpkt);
avcodec_open2(avctx, codec, NULL);
frame = avcodec_alloc_frame();

デストラクタ:

av_free_packet(&avpkt);
avcodec_free_frame(&frame);
av_free(frame);
avcodec_close(avctx);
于 2015-09-10T11:21:48.233 に答える
1

メモリリークするFFmpegを使用した同様のルーチンがありました。avcodec_decode_video2 を呼び出すたびに、フレーム オブジェクトとパケット オブジェクトのメモリの割り当てを解除することで解決策を見つけました。

コードでは、パケット オブジェクトは解放されますが、フレームは解放されません。avcodec_decode_video2 の前に次の行を追加すると、メモリ リークが解決するはずです。既に割り当てが解除されているフレーム オブジェクトで avcodec_free_frame を呼び出しても安全であることがわかりました。while ループの前にフレームの割り当てを削除できます。

avcodec_free_frame(&_n_frame);
_n_frame = avcodec_alloc_frame();
avcodec_decode_video2(_codec_context_video, _n_frame, &frameDone, packet);
于 2015-06-12T13:14:21.970 に答える
1

私も同じ問題を抱えていました。ffplay.c によると、呼び出す必要があります

av_frame_unref(pFrame);
avcodec_get_frame_defaults(pFrame);

すべてのsw_scale呼び出しの後。これにより、デコード中にすべての malloc が解放されます。

于 2013-06-08T03:46:54.450 に答える