bytedeco / javacv

Java interface to OpenCV, FFmpeg, and more
Other
7.4k stars 1.57k forks source link

Low GPU Utilization When Transcoding Videos Using javacv ffmpeg #2189

Open shih6 opened 4 months ago

shih6 commented 4 months ago

When I use the following code to transcode videos, I find that the GPU utilization is much lower compared to directly using cmd to call ffmpeg.

    public boolean convert(String inputFileUrl, String outPutUrl, String hlsBaseUrl, String segmentFilename, int hlsTime, ConvertObserver convertObserver) {
        MyFFmpegLogBack.setLevel(AV_LOG_INFO);
        MyFFmpegLogBack.set();
        try (FFmpegFrameGrabber grabber=new FFmpegFrameGrabber(inputFileUrl)){
            grabber.start();
            var videoBitrate = grabber.getVideoBitrate();
            grabber.setVideoCodecName("h264_cuvid");
            grabber.restart();
            String m3u8SaveUrl=outPutUrl+"index.m3u8";
            String segmentSaveFileUrl=(outPutUrl+hlsBaseUrl+segmentFilename).toString();
            try(FFmpegFrameRecorder recorder=new FFmpegFrameRecorder(m3u8SaveUrl,grabber.getImageWidth(),grabber.getImageHeight(), grabber.getAudioChannels())){
                recorder.setVideoCodecName("h264_nvenc");
                Integer selectedFormat = null;
                AVCodec enc = avcodec_find_encoder_by_name(recorder.getVideoCodecName());
                if(enc!=null){
                    IntPointer formats = enc.pix_fmts();
                    int i = 0;
                    while (true) {
                        int format = formats.get(i++);
                        // always prefer yuv420p, if available
                        if(format == avutil.AV_PIX_FMT_YUV420P) {
                            selectedFormat = avutil.AV_PIX_FMT_YUV420P;
                            break;
                        }
                        if(format ==  avutil.AV_PIX_FMT_NONE) {
                            selectedFormat = avcodec.avcodec_find_best_pix_fmt_of_list(formats, avutil.AV_PIX_FMT_YUV420P, 0, null);
                            break;
                        }
                    }
                }
                if(selectedFormat==null){
                    selectedFormat = avutil.AV_PIX_FMT_YUV420P;
                }
                recorder.setPixelFormat(selectedFormat);

                recorder.setVideoOption("threads", "10");
                recorder.setFormat("hls");
                recorder.setOption("hls_playlist_type","vod");
                recorder.setOption("hls_list_size", "0");
                recorder.setOption("hls_flags", "delete_segments");
                recorder.setOption("hls_delete_threshold", "1");
                recorder.setOption("hls_segment_type", "mpegts");
                recorder.setOption("hls_time", String.valueOf(hlsTime));
                recorder.setOption("hls_segment_filename",segmentSaveFileUrl);
                recorder.setFrameRate(25);
                recorder.setVideoBitrate(2000000);
                recorder.setGopSize(hlsTime);
                recorder.start();

                Frame capturedFrame;
                while (true) {
                    capturedFrame = grabber.grabFrame();
                    if (capturedFrame == null) {
                        log.info("success");
                        recorder.stop();
                        recorder.release();
                        grabber.stop();
                        grabber.release();
                        break;
                    }
                    recorder.record(capturedFrame);
                }
                return true;

            }catch (Exception e){
            }
        }catch (Exception e){
        }

        return false;
    }

i use nvidia-smi dmon to watch utilization this use javacv GPU Utilization: 1

this is use command line: 2

my gpu is Nvidia GTX2060SUPER