bytedeco / javacpp

The missing bridge between Java and native C++
Other
4.48k stars 581 forks source link

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

Open zhhades opened 3 months ago

zhhades commented 3 months 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?

```xml org.bytedeco javacpp 1.5.10 org.bytedeco ffmpeg-platform 6.1.1-1.5.10 org.bytedeco ffmpeg-platform-gpl 6.1.1-1.5.10 org.bytedeco cuda 12.1-8.9-1.5.9 ``` ```java 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) 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; } ```