JavaCV合并音频到视频封装成MP4

将音频合并到视频有两种情况:

一)音频的播放时长大于视频的播放时长

这种情况相对简单只要在控制音频的播放时长与视频对齐则可,这里主要难点主要在如何使用JavaCV来获取音频时长,代码如下:


		String imageInput = this.home + "01.mp4";//
		FFmpegFrameGrabber imageGrabber = new FFmpegFrameGrabber(imageInput);
		imageGrabber.start();
		String audioInput = this.home + "xiaolaba.mp3";
		FFmpegFrameGrabber audioGrabber = new FFmpegFrameGrabber(audioInput);
		audioGrabber.start();
		String outputPath = this.home + "testAudio.mp4";
		// 流媒体输出地址,分辨率(长,高),是否录制音频(0:单声道/1:立体声)
		FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputPath, imageGrabber.getImageWidth(), imageGrabber.getImageHeight(), 1);
		recorder.setInterleaved(true);
		recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
		recorder.setFormat("mp4");
		recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P); // yuv420p
		int frameRate = 25;
		recorder.setFrameRate(frameRate);
		recorder.setGopSize(frameRate * 2);
		recorder.setAudioOption("crf", "0");
		recorder.setAudioQuality(0);// 最高质量
		recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
		recorder.setAudioChannels(2);
		recorder.setSampleRate(44100);
		recorder.start();
		long videoTime = imageGrabber.getLengthInTime();
		Frame imageFrame = null;
		while ((imageFrame = imageGrabber.grabImage()) != null) {
			recorder.record(imageFrame);
		}
		Frame sampleFrame = null;
		while ((sampleFrame = audioGrabber.grabSamples()) != null) {
			recorder.record(sampleFrame);
			if (audioGrabber.getTimestamp() >= videoTime) {
				break;
			}
		}
		recorder.close();
		audioGrabber.close();
		imageGrabber.close();
	

二)视频的播放时长大于音频的播放时长

当音频流播放结束时sampleFrame将为空,此时调用音频抓取器的#restart方法可以重新操作,这样就能达到重新播放的效果,代码如下:


	
		String imageInput = this.home + "01.mp4";//
		String audioInput = this.home + "tt21.aac";
		String outputPath = this.home + "testAudio.mp4";
		// 流媒体输出地址,分辨率(长,高),是否录制音频(0:单声道/1:立体声)
		try (FFmpegFrameGrabber imageGrabber = new FFmpegFrameGrabber(imageInput);
				FFmpegFrameGrabber audioGrabber = new FFmpegFrameGrabber(audioInput)) {
			imageGrabber.start();
			audioGrabber.start();
			try (FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputPath, imageGrabber.getImageWidth(), imageGrabber.getImageHeight(),
					1);) {

				recorder.setInterleaved(true);
				recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
				recorder.setFormat("mp4");
				recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P); // yuv420p
				int frameRate = 25;
				recorder.setFrameRate(frameRate);
				recorder.setGopSize(frameRate * 2);
				recorder.setAudioOption("crf", "0");
				recorder.setAudioQuality(0);// 最高质量
				recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
				recorder.setAudioChannels(2);
				recorder.setSampleRate(44100);
				recorder.start();
				long videoTime = imageGrabber.getLengthInTime();
				Frame imageFrame = null;
				while ((imageFrame = imageGrabber.grabImage()) != null) {
					recorder.record(imageFrame);
				}
				long audioPlayTime = 0L;
				Frame sampleFrame = null;
				while ((sampleFrame = audioGrabber.grabSamples()) != null || audioPlayTime < videoTime) {
					if (sampleFrame == null) {
						audioGrabber.restart();//重新开始
						sampleFrame = audioGrabber.grabSamples();
						videoTime -= audioPlayTime;
					}
					recorder.record(sampleFrame);
					audioPlayTime = audioGrabber.getTimestamp();
					if (audioPlayTime >= videoTime) {
						break;
					}
				}
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}

	
	

总结

上述的两种情况都音视频是同步抓取的,如果想提高时效性可以并行抓取即音频和视频采用不同的线程并行抓取(注意只能是采集的时候并行),FFMpeg不能并行输出,但这样做缺点也是明显就是要耗费更多的内存,故实际需权衡利弊。

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

victorkevin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值