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音视频分离和合成相关推荐

  1. ffmpeg 音视频分离、合成

    ffmpeg 音视频分离.合成 抽取音频 ffmpeg -i 3.mp4 -vn -y -acodec copy 3.aac ffmpeg -i 3.mp4 -vn -y -acodec copy 3 ...

  2. Android 音视频配音之音频提取、截断、混音、合并、合成(一)——从视频中提取音频文件

    目录 前言 提取前提----了解提取需要用到的工具类:MediaExtractor.MediaCodec 1.MediaExtractor 2.MediaCodec 3.释放 具体提取转码代码 调用 ...

  3. Android 音视频配音之音频提取、截断、混音、合并、合成(二)——将提取的PCM根据时间戳截断

    前言 通过上篇文章我们知道了如何从MP4视频中如何提取出PCM或者WAV,那么这篇文章则是如何截断PCM音频 该文章系列是视频配音,涉及到把背景音频从视频中提取出来.背景音频根据台词时间戳进行截断.截 ...

  4. Android 音视频开发(三) -- Camera2 实现预览、拍照功能

    音视频 系列文章 Android 音视频开发(一) – 使用AudioRecord 录制PCM(录音):AudioTrack播放音频 Android 音视频开发(二) – Camera1 实现预览.拍 ...

  5. Android 音视频入门/进阶教程

    后续的音视频文章,都会在这里更新 作为安卓开发仔,对音视频这块,一直是比较感兴趣的,所以,本着学习和记录的态度,我也把我所学的知识记录起来,希望对想音视频感兴趣的小伙伴有所帮忙. 一. 基础文章系列 ...

  6. Android 音视频开发(二) -- Camera1 实现预览、拍照功能

    音视频 系列文章 Android 音视频开发(一) – 使用AudioRecord 录制PCM(录音):AudioTrack播放音频 Android 音视频开发(二) – Camera1 实现预览.拍 ...

  7. Android 音视频编解码(一) -- MediaCodec 初探

    音视频 系列文章 Android 音视频开发(一) – 使用AudioRecord 录制PCM(录音):AudioTrack播放音频 Android 音视频开发(二) – Camera1 实现预览.拍 ...

  8. Android音视频API - MediaCodec/MediaMuxer/MediaStore/MediaController等

    AudioTrack播放音频PCM.[Android] 混音器AudioMixer. MediaPlayer/MediaRecorder, AudioTrack/AudioRecorder, Medi ...

  9. Android 音视频开发(一) -- 使用AudioRecord 录制PCM(录音);AudioTrack播放音频

    前言,音视频这块,确实比较难入门,本着学习的态度,我这边也跟着 Android 音视频开发入门指南 打怪升级,留下个脚印,大家共勉. 音视频 系列文章 Android 音视频开发(一) – 使用Aud ...

最新文章

  1. c# typescript_在任何IDE中从C#,Java或Python代码获取TypeScript接口的简单方法
  2. oracle和mysql登录方式_使用普通方式和连接池方式获取Oracle和Mysql链接
  3. 传统方法怎么玩计算机审美
  4. 关闭 启动_Steam如何关闭开机自动启动
  5. synchronized 和Lock区别
  6. SSE事件作用,错误分析
  7. 迭代器模式在 Java 容器中的实现
  8. SharePoint 2010新特性文档集
  9. 日常生活 - 打印机如何扫描文件到电脑上
  10. 家用计算机按键不灵怎么修,空格键失灵了怎么办?电脑键盘按键失灵的解决办法...
  11. Supervised Sequence Labelling with Recurrent Neural Networks 笔记 -LSTM
  12. python opencv将图片转为灰度图
  13. 什么是SMART原则?SMART原则是什么意思?
  14. 使用jsp实现用户注册及登录
  15. docker原理及基本概念
  16. 2020JAVA面试题附答案(持续更新版)
  17. 42个机器学习练手项目
  18. 关于J2EE,J2SE,J2ME
  19. 考研英语小程序哪个好用?
  20. 连锁零售行业IT运维管理四大困境

热门文章

  1. 三河一中2021高考成绩如何查询,2021年廊坊高中学校排名及录取分数线排名
  2. 《新相亲大会》引发婚恋观讨论,珍爱网传递正向情感价值观
  3. DEDECMS织梦内容管理系统添加新文章白屏
  4. workbench小教程
  5. chrome扩展开发(2)- manifest.json文件简述
  6. Unity人工智能编程精粹学习笔记 寻找最短路径并避开障碍物——A*寻路
  7. 中国地铁换乘网——免费提供地铁查询代码下载
  8. 赚钱之路之c语言第一步
  9. 【时间序列】时间序列中如何进行交叉验证
  10. OBIEE 10G 安装RPD客户端