bytedeco/javacpp

there may be a memory leak in the av_read_frame code

Open

#763 aperta il 20 giu 2024

Vedi su GitHub
 (0 commenti) (0 reazioni) (0 assegnatari)Java (620 fork)batch import
help wantedquestion

Metriche repository

Star
 (4279 star)
Metriche merge PR
 (Merge medio 2g) (1 PR mergiata in 30 g)

Descrizione

<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;
}

Guida contributor