1 简介

​ 本文以 mp4 文件为例,讲解去音频操作。mp4 是一种视频封装的容器,里面包含音频(audio)和视频(video)数据,对应的数据编码格式分别为 aac 和 h264。在去音频过程中,主要使用到 MediaFormat、MediaExtractor、MediaMuxer,其作用如下:

  • MediaFormat:用于存储视频轨或音频轨的信息(MIME、时长、帧率、比特率、关键帧间隔、视频宽高等);
  • MediaExtractor:媒体分离器,用于分离音频和视频数据,并且能够遍历帧数据;
  • MediaMuxer:媒体复合器,用于合成音频和视频数据。

(1)MediaFormat

//初始化
MediaFormat mediaFormat = new MediaFormat()
MediaFormat mediaFormat = mediaExtractor.getTrackFormat(i) //获取MIME
String mime = mediaFormat.getString(MediaFormat.KEY_MIME) //获取总时长(单位:微秒us)
long durationTime = mediaFormat.getLong(MediaFormat.KEY_DURATION) //获取帧率
int frameRate = mediaFormat.getInteger(MediaFormat.KEY_FRAME_RATE) //获取比特率
int bitRate = mediaFormat.getInteger(MediaFormat.KEY_BIT_RATE) //获取视频宽度(像素:px)
int width = mediaFormat.getInteger(MediaFormat.KEY_WIDTH) //获取视频高度(像素:px)
int height = mediaFormat.getInteger(MediaFormat.KEY_HEIGHT) //获取关键帧间隔(单位:秒)
int iFrameInterval = mediaFormat.getInteger(MediaFormat.KEY_I_FRAME_INTERVAL)

​ 用户也可以调用 mediaFormat.setX()方法注入属性。

(2)MediaExtractor

//初始化
MediaExtractor mediaExtractor = new MediaExtractor() //设置资源
setDataSource(String input_path)
mediaExtractor.setDataSource("/sdcard/Pictures/WeiXin/a.mp4") //获取轨道数
mediaExtractor.getTrackCount() //获取 mediaFormat
MediaFormat mediaFormat = mediaExtractor.getTrackFormat(index) //index为轨道编号 //选择轨道
mediaExtractor.selectTrack(index) //index为轨道编号 //读取1帧数据到buffer
int input_size = format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE) //获取最大输入缓存大小
ByteBuffer buffer = ByteBuffer.allocate(input_size)
int sampleSize = mediaExtractor.readSampleData(buffer, offset) //offset一般取0 //读取下一帧数据
mediaExtractor.advance() //定位到timeUs附近的关键帧
mediaExtractor.seekTo(timeUs, mode) //mode一般取 MediaExtractor.SEEK_TO_CLOSEST_SYNC //释放资源
mediaExtractor.release()

(3)MediaMuxer

//初始化
MediaMuxer(String output_path, int format)
MediaMuxer mediaMuxer = new MediaMuxer("/sdcard/a.mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4) //添加轨道
int videoTrackIndex = mediaMuxer.addTrack(mediaFormat) //开始合成文件
mediaMuxer.start() //写入数据
writeSampleData(int trackIndex, ByteBuffer byteBuf, MediaCodec.BufferInfo bufferInfo) //释放资源
mediaMuxer.stop()
mediaMuxer.release()

2 案例

@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
private void get_video() throws IOException {
String input_path = "/sdcard/Pictures/WeiXin/a.mp4"; //源视频素材
String output_path = "/sdcard/a.mp4"; //去音频后的素材
MediaExtractor mediaExtractor = new MediaExtractor();
mediaExtractor.setDataSource(input_path);
MediaMuxer mediaMuxer = new MediaMuxer(output_path, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
int input_size =0;
int videoTrackIndex = -1;
int count = mediaExtractor.getTrackCount(); //获取轨道数
for (int i = 0; i < count; i++) {
MediaFormat format = mediaExtractor.getTrackFormat(i);
String mime = format.getString(MediaFormat.KEY_MIME);
if (mime.startsWith("video/")) { // mp4为“video/avc”
input_size = format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
mediaExtractor.selectTrack(i);
videoTrackIndex = mediaMuxer.addTrack(format);
break;
}
}
mediaMuxer.start();
int sampleSize = 0;
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
ByteBuffer buffer = ByteBuffer.allocate(input_size); //也可以设置为:500*1024
while ((sampleSize = mediaExtractor.readSampleData(buffer, 0)) > 0) {
info.offset = 0;
info.size = sampleSize;
info.flags = mediaExtractor.getSampleFlags();
info.presentationTimeUs = mediaExtractor.getSampleTime();
mediaMuxer.writeSampleData(videoTrackIndex, buffer, info); //写入数据
mediaExtractor.advance(); //下一帧
}
mediaExtractor.release();
mediaMuxer.stop();
mediaMuxer.release();
}

3 拓展

​ 可以通过修改 BufferInfo 的 presentationTimeUs 属性,实现倍速导出视频,如下:

float speed = 3.0f; //播放速度
info.presentationTimeUs = (long)(mediaExtractor.getSampleTime()/speed);
mediaMuxer.writeSampleData(videoTrackIndex, buffer, info); //写入数据

​ 特别注意:不要试图通过修改 BufferInfo 的 flags 属性改变帧标签(I帧、P帧、B帧),若想修改帧标签,需要使用 Mediacodec 重新解码和编码。

​ 声明:本文转自【Android】使用MediaExtractor、MediaMuxer去掉视频文件中的音频数据

【Android】使用MediaExtractor、MediaMuxer去掉视频文件中的音频数据的更多相关文章

  1. 从视频文件中读入数据-->将数据转换为灰度图-->对图像做canny边缘检测-->将这三个结构显示在一个图像中

    //从视频文件中读入数据-->将数据转换为灰度图-->对图像做canny边缘检测-->将这三个结构显示在一个图像中 //作者:sandy //时间:2015-10-10 #inclu ...

  2. [SimplePlayer] 4. 从视频文件中提取音频

    提取音频,具体点来说就是提取音频帧.提取方法与从视频文件中提取图像的方法基本一样,这里仅列出其中的不同点: 1. 由于目的提取音频,因此在demux的时候需要指定的是提取audio stream Au ...

  3. Atitit.android播放smb 网络邻居视频文件解决方案

    Atitit.android播放smb 网络邻居视频文件解决方案 Android4.4 1.1. Android4视频播放器不能直接地支持smb协议..子好先转换成个http流 1.2. ES文件浏览 ...

  4. Android 自定义View及其在布局文件中的使用示例(三):结合Android 4.4.2_r1源码分析onMeasure过程

    转载请注明出处 http://www.cnblogs.com/crashmaker/p/3549365.html From crash_coder linguowu linguowu0622@gami ...

  5. Android 自定义View及其在布局文件中的使用示例(二)

    转载请注明出处 http://www.cnblogs.com/crashmaker/p/3530213.html From crash_coder linguowu linguowu0622@gami ...

  6. (转载)[FFmpeg]使用ffmpeg从各种视频文件中直接截取视频图片

    你曾想过从一个视频文件中提取图片吗?在Linux下就可以,在这个教程中我将使用ffmpeg来从视频中获取图片. 什么是ffmpeg?What is ffmpeg? ffmpeg是一个非常有用的命令行程 ...

  7. [SimplePlayer] 1. 从视频文件中提取图像

    在开始之前,我们需要了解视频文件的格式.视频文件的格式众多,无法三言两语就能详细分析其结构,尽管如此,ffmpeg却很好地提取了各类视频文件的共同特性,并对其进行了抽象描述. 视频文件格式,统称为co ...

  8. 代码实现将键盘录入的数据拷贝到当前项目下的text.txt文件中,键盘录入数据当遇到quit时就退出

    package com.looaderman.test; import java.io.FileNotFoundException; import java.io.FileOutputStream; ...

  9. Tensorflow 从文件中载入训练数据

    本节包含: 用纯文本文件准备训练数据 加载文件中的训练数据 一.用纯文本文件准备训练数据 1.数据的数字化 比如,“是” —— “1”,“否” —— “0” “优”,“中”,“差” —— 1 2 3  ...

  10. api进阶Day2(低级流)文件流的输出流、读取流。向文件中写入文本数据、读取文件中的字符串、用lambda表达式创建文件过滤器。

    文件流:输出流: package io; import java.io.FileNotFoundException; import java.io.FileOutputStream; import j ...

随机推荐

  1. 问题--C中结构体想要嵌套一个该结构体指针,但是系统无法识别该类型

    代码如下: typedef struct_Person{ char name[64]; int age; //Person* person; //这里会出现一个问题,由于Person是在末尾定义的,那 ...

  2. [转帖]Linux内存管理(一)——从硬件角度看内存管理

    从硬件角度看内存管理 ①.在操作系统还没有出来之前,程序都是被存放在卡片上,计算机读取一张卡片就运行一条指令.这种从外部存储介质上直接运行指令的方法效率很低 ②.单道编程的内存管理 所谓单道,就是整个 ...

  3. [转帖]k8s ipv4/ipv6双栈实践

    https://www.iceyao.com.cn/post/2020-11-28-k8s_dual_stack/ Posted by 爱折腾的工程师 on Saturday, November 28 ...

  4. [转帖]Export Prometheus metrics from SQL queries

    https://github.com/albertodonato/query-exporter query-exporter is a Prometheus exporter which allows ...

  5. [转帖]学习如何编写 Shell 脚本(进阶篇)

    https://juejin.cn/post/6935365727205457928 前言 在<学习如何编写 Shell 脚本(基础篇)>一文中已经讲解了 Shell 脚本编程的基础知识, ...

  6. [转帖]TNS-12535 TNS-00505的处理方法

    硬件说明: 操作系统版本:ORACLE LINUX 6.3  64位 数据库版本:11.2.0.3   64位 问题说明: 在检查数据库的alert日志的时候,发现大量的12170和TNS-12535 ...

  7. [转帖]Linux_Redhat8——常用命令:ls、ll、vim、ps、top、grep、tail

    Linux_Redhat8-常用命令: ls.ll.vim.ps.top.grep 一.ls(list):查看目录下的文件 ls:仅罗列出当前文件名或目录名. ll:罗列出当前文件或目录的详细信息,包 ...

  8. [转帖]【MySQL 8】MySQL 5.7都即将停只维护了,是时候学习一波MySQL 8了!

    https://juejin.cn/post/7111255789876019208 MySQL 8新特性 选择MySQL 8的背景:MySQL 5.6已经停止版本更新了,对于 MySQL 5.7 版 ...

  9. 非root用户搭建sftp以及进行简要使用的介绍

    sftp的简介 关于sftp sftp是Secure FileTransferProtocol的缩写,安全文件传送协议,可以为传输文件提供一种安全的加密方法. sftp与 ftp有着几乎一样的语法和功 ...

  10. 结论&定理大全

    定理 1:包含 \(0\) 与 \(2^k-1\) 的按位与或空间和 \(k\) 个点的有传递性的有向图形成双射 证明: 空间->传递闭包:对于任意两个位 \(i,j\),若某个数包含 \(i\ ...