bytedeco / javacv

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

the FFmpegFrameRecorder created video's quality is lower than originals #2041

Open gaojian010 opened 1 year ago

gaojian010 commented 1 year ago

I am using FFmpegFrameGrabber to grab frame images from a video, and doing some image processing, then using FFmpegFrameRecorder to record frames to a new video file.

And, I find that the created new video's quality is lower than the original video. I have tryed to set the recorder as same as the grabber, however, it is still lower than expected.

Is there anything I could do to make the recorder to create video as the same quality, under same frame rate/bit rate.

Here is my code, only recording the frame grabbed `public static void copyVideo(String inputVideoFile, String outputVideoFile) throws FFmpegFrameGrabber.Exception, FFmpegFrameRecorder.Exception { FFmpegFrameGrabber videoGrabber = FFmpegFrameGrabber.createDefault(inputVideoFile); videoGrabber.start();

    FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputVideoFile, videoGrabber.getAudioChannels());
    recorder.setFrameRate(videoGrabber.getFrameRate());
    recorder.setVideoCodec(videoGrabber.getVideoCodec());
    recorder.setVideoBitrate(videoGrabber.getVideoBitrate());
    recorder.setImageHeight(videoGrabber.getImageHeight());
    recorder.setImageWidth(videoGrabber.getImageWidth());
    recorder.setFormat(videoGrabber.getFormat());
    recorder.setVideoOptions(videoGrabber.getVideoOptions());
    recorder.setVideoMetadata(videoGrabber.getVideoMetadata());
    recorder.setVideoQuality(1);
    recorder.setVideoOption("profile", "high");

    recorder.start();

    Frame frame = null;
    while ((frame = videoGrabber.grabImage()) != null) {
        recorder.record(frame);
    }

    recorder.stop();
    videoGrabber.stop();
}`

Here is one frame of the new video, captured by screen shot tool from video player out

Here is the original's, same way to get ori

Here is the ffmpeg output log

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'ori.mp4': Metadata: major_brand : isom minor_version : 512 encoder : Lavf58.29.100 Duration: 02:08:53.13, start: 0.000000, bitrate: 1841 kb/s Stream #0:00x1: Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 1705 kb/s, 29.97 fps, 29.97 tbr, 90k tbn (default) Metadata: handler_name : VideoHandler vendor_id : [0][0][0][0] Stream #0:10x2: Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default) Metadata: handler_name : SoundHandler vendor_id : [0][0][0][0] [libopenh264 @ 00000176fe8cb2c0] Slice count will be set automatically [libopenh264 @ 00000176fe8cb2c0] [OpenH264] this = 0x00000176fe8ce200, Warning:bEnableFrameSkip = 0,bitrate can't be controlled for RC_QUALITY_MODE,RC_BITRATE_MODE and RC_TIMESTAMP_MODE without enabling skip frame. Output #0, mp4, to 'out.mp4': Metadata: encoder : Lavf59.27.100 Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 1920x1080, q=2-31, 1705 kb/s, 29.97 fps, 30k tbn Metadata: handler_name : VideoHandler vendor_id : [0][0][0][0] Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 64 kb/s

The differeces between input and output Input Stream #0:00x1: Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 1705 kb/s, 29.97 fps, 29.97 tbr, 90k tbn (default) Output Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 1920x1080, q=2-31, 1705 kb/s, 29.97 fps, 30k tbn

saudet commented 1 year ago

We can easily accomplish this with the ffmpeg program: http://bytedeco.org/javacpp-presets/ffmpeg/apidocs/org/bytedeco/ffmpeg/ffmpeg.html

gaojian010 commented 1 year ago

Thanks for your reply. Is there any sample code that I can refer. I think I need to use FFmpegFrameRecorder to create the video, because I need to do some image processing for each frame.