javacv icon indicating copy to clipboard operation
javacv copied to clipboard

Problem of FFmpegFrameRecorder when using javaCV to call ffmpeg for audio codec and output audio

Open Wangxy013 opened this issue 3 years ago • 3 comments

Hello, I have a problem when using javaCV to call ffmpeg for audio transcoding. I don't know if it is a bug.

I built a FFmpegFrameGrabber and set the output parameters for it.

  • When I use stream output Using the following constructor
public FFmpegFrameRecorder(OutputStream outputStream, int audioChannels) {
        this(outputStream.toString(), audioChannels);
        this.outputStream = outputStream;
        this.closeOutputStream = true;
    }

, the final audio file will lack a ‘xing’ header data.

  • When I use filename to specify his output audio path, Call the following constructor
public FFmpegFrameRecorder(String filename, int audioChannels) {
        this(filename, 0, 0, audioChannels);
    }

the generated audio file has no problem, including the "xing" header information. The two files differ by 180 bytes.

Hope to get answers and help from everyone, thanks!

Wangxy013 avatar Apr 02 '21 10:04 Wangxy013

image The right side is the audio file I got when I used the stream for FFmpegFrameRecorder output. You can see that the right side lacks 'xing' header information than the left side. Other parts are consistent

Wangxy013 avatar Apr 02 '21 10:04 Wangxy013

Not all codecs and formats support streams well. Please report upstream.

saudet avatar Apr 02 '21 11:04 saudet

I met the same problem. When I use the constructor with the OutputStream and running the program,it will report an error: org.bytedeco.javacv.FFmpegFrameRecorder$Exception: avformat_write_header error() error -22: Could not write header to ''. When I use the constructor with String,Program running fine. Have you solved the problem yet?

Noooooooone avatar Apr 29 '22 06:04 Noooooooone

I met this same problem.Do you resolve this problem? this code does well.

frameGrabber.start();
recorder = new FFmpegFrameRecorder(out.getFile()), frameGrabber.getImageWidth(), frameGrabber.getImageHeight(), frameGrabber.getAudioChannels());

this code does not work.

frameGrabber.start();
recorder = new FFmpegFrameRecorder(Files.newOutputStream(out.getFile().toPath()), frameGrabber.getImageWidth(), frameGrabber.getImageHeight(), frameGrabber.getAudioChannels());

this is my full code

@Component
public class StandardTranscodingComponent extends AbstractTranscoding<InComponent, FileOutComponent> {
    @Override
    protected FileOutComponent doTrans(InComponent in, FileOutComponent out) {
        final CodecComponent codec = out.codec();
        //FFmpegLogCallback.set();
        //avutil.av_log_set_level(AV_LOG_ERROR);
        FFmpegFrameGrabber frameGrabber = new FFmpegFrameGrabber(in.getInputStream());
        Frame captured_frame;
        FFmpegFrameRecorder recorder = null;
        try {
            frameGrabber.start();
            //this code does well
            //recorder = new FFmpegFrameRecorder(out.getFile(), frameGrabber.getImageWidth(), frameGrabber.getImageHeight(), frameGrabber.getAudioChannels());
            //this code does not work
            recorder = new FFmpegFrameRecorder(Files.newOutputStream(out.getFile().toPath()), frameGrabber.getImageWidth(), frameGrabber.getImageHeight(), frameGrabber.getAudioChannels());
            //video
            recorder.setVideoCodec(codec.getVideoCodec() == null ? frameGrabber.getVideoCodec() : codec.getVideoCodec());
            recorder.setFormat(codec.getVideoFormat());
            recorder.setFrameRate(codec.getVideoFrameRate() == null ? frameGrabber.getFrameRate() : codec.getVideoFrameRate());
            recorder.setVideoBitrate(codec.getVideoBitrate() == null ? frameGrabber.getVideoBitrate() : codec.getVideoBitrate());
            recorder.setVideoOptions(frameGrabber.getVideoOptions());
            //audio
            recorder.setAudioBitrate(codec.getAudioBitrate() == null ? frameGrabber.getAudioBitrate() : codec.getAudioBitrate());
            recorder.setAudioOptions(codec.getAudioOptions() == null ? frameGrabber.getAudioOptions() : codec.getAudioOptions());
            recorder.setAudioQuality(codec.getAudioQuality() == null ? 0 : codec.getAudioQuality());
            recorder.setSampleRate(codec.getAudioSampleRate() == null ? frameGrabber.getSampleRate() : codec.getAudioSampleRate());
            recorder.setAudioCodec(codec.getAudioCodec() == null ? frameGrabber.getAudioCodec() : codec.getAudioCodec());
            recorder.start();
            while (true) {
                try {
                    captured_frame = frameGrabber.grabFrame();
                    if (captured_frame == null) {
                        break;
                    }
                    recorder.record(captured_frame);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (recorder != null)
                    recorder.stop();
            } catch (Exception ignored) {

            }
            try {
                if (recorder != null)
                    recorder.release();
            } catch (Exception ignored) {

            }
            try {
                frameGrabber.stop();
            } catch (Exception ignored) {

            }
            try {
                frameGrabber.release();
            } catch (Exception ignored) {

            }
            try {
                if (recorder != null)
                    recorder.close();
            } catch (Exception ignored) {

            }
            try {
                frameGrabber.close();
            } catch (Exception ignored) {

            }
        }
        return out;
    }
}

this is the logs

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'java.io.BufferedInputStream@7dd20faf':
  Metadata:
    major_brand     : qt  
    minor_version   : 0
    compatible_brands: qt  
    creation_time   : 2023-04-06T06:53:54.000000Z
    com.apple.quicktime.location.accuracy.horizontal: 35.000000
    com.apple.quicktime.location.ISO6709: +30.5429+104.0525+471.564/
    com.apple.quicktime.make: Apple
    com.apple.quicktime.model: iPhone 12 Pro
    com.apple.quicktime.software: 16.3.1
    com.apple.quicktime.creationdate: 2023-04-06T14:53:53+0800
  Duration: 00:00:11.11, start: 0.000000, bitrate: 10695 kb/s
  Stream #0:0[0x1](und): Video: hevc (Main) (hvc1 / 0x31637668), yuvj420p(pc, smpte170m/smpte432/bt709), 1920x1440, 9921 kb/s, 29.96 fps, 29.97 tbr, 600 tbn (default)
    Metadata:
      creation_time   : 2023-04-06T06:53:54.000000Z
      handler_name    : Core Media Video
      vendor_id       : [0][0][0][0]
      encoder         : HEVC
    Side data:
      displaymatrix: rotation of -90.00 degrees
  Stream #0:1[0x2](und): Audio: pcm_s16le (lpcm / 0x6D63706C), 44100 Hz, 1 channels, s16, 705 kb/s (default)
    Metadata:
      creation_time   : 2023-04-06T06:53:54.000000Z
      handler_name    : Core Media Audio
      vendor_id       : [0][0][0][0]
  Stream #0:2[0x3](und): Data: none (mebx / 0x7862656D), 0 kb/s (default)
    Metadata:
      creation_time   : 2023-04-06T06:53:54.000000Z
      handler_name    : Core Media Metadata
  Stream #0:3[0x4](und): Data: none (mebx / 0x7862656D), 52 kb/s (default)
    Metadata:
      creation_time   : 2023-04-06T06:53:54.000000Z
      handler_name    : Core Media Metadata
[libopenh264 @ 0000025a84448500] Slice count will be set automatically
[libopenh264 @ 0000025a84448500] [OpenH264] this = 0x0000025aef39ed20, Warning:layerId(0) doesn't support profile(578), change to UNSPECIFIC profile
[libopenh264 @ 0000025a84448500] [OpenH264] this = 0x0000025aef39ed20, Warning:bEnableFrameSkip = 0,bitrate can't be controlled for RC_QUALITY_MODE,RC_BITRATE_MODE and RC_TIMESTAMP_MODE without enabling skip frame.
[mp4 @ 0000025a84b90c80] muxer does not support non seekable output
[aac @ 0000025a84448900] Qavg: nan

the format of InputStream is MOV the format of OutStream is H264,Mp4

EricMo avatar Apr 07 '23 07:04 EricMo