Android音视频分离和合成
mp4音频是由视频和音频组成,Android 提供了 MediaExtractor 和 MediaMuxer 以及MediaFormat类,用来把音频或视频单独抽取出来,然后合成新的视频。下面分别介绍视频的分解和合成,效果如下:
一、视频的分解
1、设置数据源获取音轨数据
MediaExtractor extractor = new MediaExtractor();try {//设置数据源extractor.setDataSource(file.getAbsolutePath());} catch (IOException e) {e.printStackTrace();}//获取轨道数量trackCount = extractor.getTrackCount();
2、遍历音轨数量,得到想要的轨道
//查找需要的视频轨道与音频轨道indexfor (int i = 0; i < trackCount; i++) {//遍历所以轨道MediaFormat itemMediaFormat = extractor.getTrackFormat(i);String itemMime = itemMediaFormat.getString(MediaFormat.KEY_MIME);if (itemMime.startsWith("video")) {//获取视频轨道位置videoTrackIndex = i;videoMediaFormat = itemMediaFormat;continue;}if (itemMime.startsWith("audio")) {//获取音频轨道位置audioTrackIndex = i;audioMediaFormat = itemMediaFormat;continue;}}
3、创建输出音视频文件夹
File videoFile = new File(videoPath);File audioFile = new File(audioPath);if (videoFile.exists()) {videoFile.delete();}if (audioFile.exists()) {audioFile.delete();}
4、写入数据释放资源
/**** @param extractor 源数据* @param format 需要分离的音视频或者视频* @param path 视频或者音频输出路径* @param index 轨道下标* @throws IOException*/private void muxerAudio(MediaExtractor extractor, MediaFormat format, String path, int index) throws IOException {MediaFormat trackFormat = extractor.getTrackFormat(index);MediaMuxer mediaMuxer = new MediaMuxer(path, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);int trackIndex = mediaMuxer.addTrack(trackFormat);extractor.selectTrack(index);mediaMuxer.start();int maxVideoBufferCount = format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);ByteBuffer byteBuffer = ByteBuffer.allocate(maxVideoBufferCount);MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();//时长:这里需要区分音频或者视频,两个是根据不同的计算方法,否则会导致分离的音频或者视频时长不一致或者崩溃long videoSampleTime = 0;try {videoSampleTime = getSampleTime(trackFormat);} catch (Exception e) {videoSampleTime = getSampleTime(extractor, byteBuffer);}while (true) {int readSampleDataSize = extractor.readSampleData(byteBuffer, 0);if (readSampleDataSize < 0) {break;}bufferInfo.size = readSampleDataSize;bufferInfo.offset = 0;bufferInfo.flags = extractor.getSampleFlags();bufferInfo.presentationTimeUs += videoSampleTime;mediaMuxer.writeSampleData(trackIndex, byteBuffer, bufferInfo);//该方法放在前面会导致首帧录屏extractor.advance();}//释放音轨extractor.unselectTrack(index);mediaMuxer.stop();//内部也会执行stop,所以可以不用执行stopmediaMuxer.release();}
附上两种时间的计算方法:
/*** 通过帧率来计算:适用于视频*/private long getSampleTime(MediaFormat mediaFormat) {//每秒多少帧int frameRate = mediaFormat.getInteger(MediaFormat.KEY_FRAME_RATE);//得出平均每一帧间隔多少微妙return 1000 * 1000 / frameRate;}/*** 通过设置PTS的办法:适用于音频,该方法使得视频播放变慢*/private long getSampleTime(MediaExtractor audioExtractor, ByteBuffer buffer) {long videoSampleTime;audioExtractor.readSampleData(buffer, 0);//skip first I frameif (audioExtractor.getSampleFlags() == MediaExtractor.SAMPLE_FLAG_SYNC)audioExtractor.advance();audioExtractor.readSampleData(buffer, 0);long firstVideoPTS = audioExtractor.getSampleTime();audioExtractor.advance();audioExtractor.readSampleData(buffer, 0);long SecondVideoPTS = audioExtractor.getSampleTime();videoSampleTime = Math.abs(SecondVideoPTS - firstVideoPTS);return videoSampleTime;}
二、视频的合成
视频和合成和上面比较类似,是分别设置数据源到MediaExtractor,然后获取对应的轨道数据,最后同步写入。
/*** @param videoPath 源视频路径* @param audioPath 源音频路径* @param outPath 输出路径*/private void startComposeTrack(String videoPath, String audioPath,String outPath) {try {MediaExtractor videoExtractor = new MediaExtractor();videoExtractor.setDataSource(videoPath);MediaExtractor audioExtractor = new MediaExtractor();audioExtractor.setDataSource(audioPath);MediaMuxer muxer = new MediaMuxer(outPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);videoExtractor.selectTrack(0);MediaFormat videoFormat = videoExtractor.getTrackFormat(0);int videoTrack = muxer.addTrack(videoFormat);audioExtractor.selectTrack(0);MediaFormat audioFormat = audioExtractor.getTrackFormat(0);int audioTrack = muxer.addTrack(audioFormat);boolean sawEOS = false;int frameCount = 0;int offset = 100;int sampleSize = 256 * 1024;ByteBuffer videoBuf = ByteBuffer.allocate(sampleSize);ByteBuffer audioBuf = ByteBuffer.allocate(sampleSize);MediaCodec.BufferInfo videoBufferInfo = new MediaCodec.BufferInfo();MediaCodec.BufferInfo audioBufferInfo = new MediaCodec.BufferInfo();videoExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);audioExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);muxer.start();while (!sawEOS) {videoBufferInfo.offset = offset;videoBufferInfo.size = videoExtractor.readSampleData(videoBuf, offset);if (videoBufferInfo.size < 0 || audioBufferInfo.size < 0) {sawEOS = true;videoBufferInfo.size = 0;} else {videoBufferInfo.presentationTimeUs = videoExtractor.getSampleTime();//noinspection WrongConstantvideoBufferInfo.flags = videoExtractor.getSampleFlags();muxer.writeSampleData(videoTrack, videoBuf, videoBufferInfo);videoExtractor.advance();frameCount++;}}boolean sawEOS2 = false;int frameCount2 = 0;while (!sawEOS2) {frameCount2++;audioBufferInfo.offset = offset;audioBufferInfo.size = audioExtractor.readSampleData(audioBuf, offset);if (videoBufferInfo.size < 0 || audioBufferInfo.size < 0) {sawEOS2 = true;audioBufferInfo.size = 0;} else {audioBufferInfo.presentationTimeUs = audioExtractor.getSampleTime();audioBufferInfo.flags = audioExtractor.getSampleFlags();muxer.writeSampleData(audioTrack, audioBuf, audioBufferInfo);audioExtractor.advance();}}muxer.stop();muxer.release();audioExtractor.release();} catch (IOException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}}
这里比较耗时,需要在子线程进行。
Android音视频分离和合成相关推荐
- ffmpeg 音视频分离、合成
ffmpeg 音视频分离.合成 抽取音频 ffmpeg -i 3.mp4 -vn -y -acodec copy 3.aac ffmpeg -i 3.mp4 -vn -y -acodec copy 3 ...
- Android 音视频配音之音频提取、截断、混音、合并、合成(一)——从视频中提取音频文件
目录 前言 提取前提----了解提取需要用到的工具类:MediaExtractor.MediaCodec 1.MediaExtractor 2.MediaCodec 3.释放 具体提取转码代码 调用 ...
- Android 音视频配音之音频提取、截断、混音、合并、合成(二)——将提取的PCM根据时间戳截断
前言 通过上篇文章我们知道了如何从MP4视频中如何提取出PCM或者WAV,那么这篇文章则是如何截断PCM音频 该文章系列是视频配音,涉及到把背景音频从视频中提取出来.背景音频根据台词时间戳进行截断.截 ...
- Android 音视频开发(三) -- Camera2 实现预览、拍照功能
音视频 系列文章 Android 音视频开发(一) – 使用AudioRecord 录制PCM(录音):AudioTrack播放音频 Android 音视频开发(二) – Camera1 实现预览.拍 ...
- Android 音视频入门/进阶教程
后续的音视频文章,都会在这里更新 作为安卓开发仔,对音视频这块,一直是比较感兴趣的,所以,本着学习和记录的态度,我也把我所学的知识记录起来,希望对想音视频感兴趣的小伙伴有所帮忙. 一. 基础文章系列 ...
- Android 音视频开发(二) -- Camera1 实现预览、拍照功能
音视频 系列文章 Android 音视频开发(一) – 使用AudioRecord 录制PCM(录音):AudioTrack播放音频 Android 音视频开发(二) – Camera1 实现预览.拍 ...
- Android 音视频编解码(一) -- MediaCodec 初探
音视频 系列文章 Android 音视频开发(一) – 使用AudioRecord 录制PCM(录音):AudioTrack播放音频 Android 音视频开发(二) – Camera1 实现预览.拍 ...
- Android音视频API - MediaCodec/MediaMuxer/MediaStore/MediaController等
AudioTrack播放音频PCM.[Android] 混音器AudioMixer. MediaPlayer/MediaRecorder, AudioTrack/AudioRecorder, Medi ...
- Android 音视频开发(一) -- 使用AudioRecord 录制PCM(录音);AudioTrack播放音频
前言,音视频这块,确实比较难入门,本着学习的态度,我这边也跟着 Android 音视频开发入门指南 打怪升级,留下个脚印,大家共勉. 音视频 系列文章 Android 音视频开发(一) – 使用Aud ...
最新文章
- c# typescript_在任何IDE中从C#,Java或Python代码获取TypeScript接口的简单方法
- oracle和mysql登录方式_使用普通方式和连接池方式获取Oracle和Mysql链接
- 传统方法怎么玩计算机审美
- 关闭 启动_Steam如何关闭开机自动启动
- synchronized 和Lock区别
- SSE事件作用,错误分析
- 迭代器模式在 Java 容器中的实现
- SharePoint 2010新特性文档集
- 日常生活 - 打印机如何扫描文件到电脑上
- 家用计算机按键不灵怎么修,空格键失灵了怎么办?电脑键盘按键失灵的解决办法...
- Supervised Sequence Labelling with Recurrent Neural Networks 笔记 -LSTM
- python opencv将图片转为灰度图
- 什么是SMART原则?SMART原则是什么意思?
- 使用jsp实现用户注册及登录
- docker原理及基本概念
- 2020JAVA面试题附答案(持续更新版)
- 42个机器学习练手项目
- 关于J2EE,J2SE,J2ME
- 考研英语小程序哪个好用?
- 连锁零售行业IT运维管理四大困境