bytedeco / javacv

Java interface to OpenCV, FFmpeg, and more
Other
7.39k stars 1.56k forks source link

there may be a memory leak in the av_read_frame code #2242

Closed zhhades closed 1 week ago

zhhades commented 1 week ago

Hello, first of all, thank you for your dedication to the open source industry. Currently, I am using javacpp1.5.10 & ffmpeg-platform 1.5.10 & ffmpeg-platform-gpl 1.5.10 & Cuda 12.1-8.9-1.5.9 for video stream decoding development work. In the following code, I have found that there may be a memory leak. Can you help me take a look?

<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>javacpp</artifactId>
    <version>1.5.10</version>
</dependency>
<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>ffmpeg-platform</artifactId>
    <version>6.1.1-1.5.10</version>
</dependency>

<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>ffmpeg-platform-gpl</artifactId>
    <version>6.1.1-1.5.10</version>
</dependency>

<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>cuda</artifactId>
    <version>12.1-8.9-1.5.9</version>
</dependency>
public void doDecoder() throws NeedRetryException {

    AVFormatContext pFormatCtx = null;
    AVCodecContext pCodecCtx = null;
    AVPacket packet = av_packet_alloc();
    AVDictionary options = new AVDictionary(null);
    try {

        // due to network limitations, the TCP protocol must be used
        av_dict_set(options, "rtsp_transport", "tcp", 0);
        av_dict_set(options, "buffer_size", "2048000", 0);
        pFormatCtx = getFormatContext(decoderTask.getVideoUrl(), options);
        int videoStreamIndex = getVideoStreamIndex(pFormatCtx);
        if (videoStreamIndex < 0) {
            log.error("video streams has no stream video");
            return;
        }
        pCodecCtx = getCodecContext(pFormatCtx, videoStreamIndex, useGpu,options);
        if (null == pCodecCtx) {
            return;
        }
        int ret = 0;
        while (( ret = av_read_frame(pFormatCtx, packet))>=0) {
            try {
                if (packet.stream_index() == videoStreamIndex) {
                    ret = avcodec_send_packet(pCodecCtx,packet);
                    // to  test the mem leak , annotate this line
                    // decode(seiInfo,frameNumber,pCodecCtx,executorService);
                }
            }catch (Exception e){
                // ignore
            }finally {
                av_packet_unref(packet);
            }
        }
        av_packet_unref(packet);
        if (ret == AVERROR_EOF()) {
            if(decoderTask.getFileFlag()){
                decode(seiInfo,frameNumber,pCodecCtx,executorService);
            }else {
                throw new NeedRetryException("av_read_frame res "+ ret);
            }
        }
        log.warn("video split task[{}] run finished", JSONObject.toJSONString(decoderTask));
    } catch (NeedRetryException needRetryException) {
        throw needRetryException;
    } catch (Exception e) {
        log.error("video split  bizId = {}, error[{}]", decoderTask.getBizId(), e.getMessage());
    } finally {
        release(true, packet, null, pCodecCtx, pFormatCtx, null, null);
    }
}

private AVFormatContext getFormatContext(String url, AVDictionary avDictionary) {
    AVFormatContext pFormatCtx = new AVFormatContext(null);

    if (avformat_open_input(pFormatCtx, url, null, avDictionary) != 0) {
        log.error("open media stream has error");
        throw new NeedRetryException("open media stream has error");
    }

    if (avformat_find_stream_info(pFormatCtx, (PointerPointer<Pointer>) null) < 0) {
        log.error("avformat_find_stream_info has error");
        throw new NeedRetryException("read media stream has error");
    }
    return pFormatCtx;
}

public static int getVideoStreamIndex(AVFormatContext pFormatCtx) {
    int videoStream = -1;
    for (int i = 0; i < pFormatCtx.nb_streams(); i++) {
        if (pFormatCtx.streams(i).codecpar().codec_type() == AVMEDIA_TYPE_VIDEO) {
            videoStream = i;
            break;
        }
    }
    return videoStream;
}

public static AVCodecContext getCodecContext(AVFormatContext pFormatCtx, int videoStreamIndex,Boolean useGpu,AVDictionary dictionary) {
    AVCodec pCodec;

    AVCodecContext pCodecCtx = avcodec_alloc_context3(null);
    avcodec_parameters_to_context(pCodecCtx, pFormatCtx.streams(videoStreamIndex).codecpar());

    if(useGpu){
        int codecId = pCodecCtx.codec_id();
        if(codecId == AV_CODEC_ID_H264){
            pCodec = avcodec_find_decoder_by_name("h264_cuvid");
        }else if (codecId == AV_CODEC_ID_H265) {
            pCodec=  avcodec_find_decoder_by_name("hevc_cuvid");
        }else {
            pCodec = avcodec_find_decoder(pCodecCtx.codec_id());
        }
    }else {
        pCodec = avcodec_find_decoder(pCodecCtx.codec_id());
    }

    if (pCodec == null) {
        return null;
    }
    if (avcodec_open2(pCodecCtx, pCodec,dictionary) < 0) {
        return null;
    }

    return pCodecCtx;
}
zhhades commented 1 week ago

I am so sorry,this issue should not be created here, it should be created in javacpp

saudet commented 1 week ago

Duplicate of https://github.com/bytedeco/javacpp/issues/763