美文网首页
Android从视频中提取出音频

Android从视频中提取出音频

作者: 奔跑的佩恩 | 来源:发表于2021-03-10 08:51 被阅读0次

前言

Android开发过程中,我们偶尔会遇到需要从一个mp4视频文件中提取出mp3音频用于单独播放的需求。这里我封装了一个工具类——SplitMediaFile。此类可用于从一个有声mp4视频文件中提取出无声mp4视频文件mp3音频文件。下面就来学习下它的使用吧

今天涉及内容:

  1. 视频分离基础
  2. 用户权限
  3. SplitMediaFile方法简介
  4. SplitMediaFile 在 Activity 中的使用
  5. 效果图和项目结构图
  6. SplitMediaFile 源码

来波生成的文件图


效果图.png

一. 视频分离基础

1.1 MediaExtractor

MediaExtractor可用于分离视频文件的音轨和视频轨道。用selectTrack方法选中 视频/音频 轨道,然后用readSampleData读出数据,就可以得到一个没有声音的视频或者一个音频。

1.2 MediaFormat

MediaFormat封装了Media data的描述信息,通过描述信息可以分辨Meida data 是一个音频还是视频。描述信息是一个键值对,可以通过MediaFormatgetXX函数获取。
通过String mime = mediaFormat.getString(MediaFormat.KEY_MIME);可以获得视频中分离出的轨道类型,其中常见的mime类型多媒体格式如下(以audio开头的是音频,以video开头的是视频):

“video/x-vnd.on2.vp8” - VP8 video (i.e. video in .webm)
“video/x-vnd.on2.vp9” - VP9 video (i.e. video in .webm)
“video/avc” - H.264/AVC video
“video/mp4v-es” - MPEG4 video
“video/3gpp” - H.263 video
“audio/3gpp” - AMR narrowband audio
“audio/amr-wb” - AMR wideband audio
“audio/mpeg” - MPEG1/2 audio layer III
“audio/mp4a-latm” - AAC audio (note, this is raw AAC packets, not packaged in LATM!)
“audio/vorbis” - vorbis audio
“audio/g711-alaw” - G.711 alaw audio
“audio/g711-mlaw” - G.711 ulaw audio
。。。还有很多格式请参考MediaFormat中的格式常量
字幕Track格式:
MIMETYPE_TEXT_VTT = “text/vtt”;
MIMETYPE_TEXT_CEA_608 = “text/cea-608”;
MIMETYPE_TEXT_CEA_708 = “text/cea-708”;

MediaFormatmime有对应的常量,MIMETYPE_AUDIO_AAC对应audio/mp4a-latmMIMETYPE_VIDEO_AVC对应 "video/avc"等等,其他对应参考MediaFormat内常量。

1.3 MediaMuxer

MediaMuxer主要用于对 视频/音频 的封装。其主要有以下几个方法:

//添加一个视频或音频轨道
int addTrack(@NonNull MediaFormat format)

//开始写入数据(此方法调用后,无法再调用`addTrack`)
start()

//向Muxer写入编码后的音视频数据
 writeSampleData(int trackIndex, @NonNull ByteBuffer byteBuf,
@NonNull BufferInfo bufferInfo)

//停止写入数据,并生成文件
stop()

//释放Muxer资源
release()
1.4 需要注意的问题

MediaExtractor分离出的文件根据类型不同,可能生成的文件为.aac格式的音频,或者是.h264格式的视频文件或者其他的格式,当生成的.aac还涉及到是否添加adts字节头的问题(adts字节头添加的话,大家可以自行搜索),由于我加了后生成的.aac文件仍没法播放,所以我采用MediaMuxer对分离出的音频/视频再度处理,最后生成了可直接播放的.mp4.mp3文件。

二.用户权限

涉及到文件读写问题,先是要在你项目的androidmainfast.xml中添加读写权限,如下:

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

然后需要添加手动权限库,这里我使用的是PermissionsDispatcher,手动库的添加大家可以参考以下文章:
PermissionsDispatcher动态权限申请kotlin版
接着需要添加FileProvider相关处理,大家可参考以下文章
SpUtil多样加密存储,兼容android9.0

三. SplitMediaFile方法简介

SplitMediaFile作为一个视频分离帮助类,拥有以下方法:

//初始化
SplitMediaFile()

    /****
     * 分离视频的方法
     *
     * @param sourceFilePath 要分离成音频和无声视频的视频源文件地址
     *                       路径中含文件后缀。
     *
     * @param videoFilePath 要存储的无声视频文件地址,为 null 表示不分离出无声视频文件
     *                      路径中不含文件后缀。(生成新的视频文件格式为 MP4)
     *
     * @param audioFilePath 要存储的音频文件地址,为 null 表示不分离出音频文件
     *                      路径中不含文件后缀。(生成新的视频文件格式为 MP3)
     */
    public void split(String sourceFilePath,String videoFilePath,String audioFilePath) 

需要在注意的是,split(String sourceFilePath,String videoFilePath,String audioFilePath)方法再生成 音/视 频的调用如下:

                //仅分离出音频(mp3格式)
                mSplitMediaFile.split(path,null,audioFilePath);
                //仅分离出视频(无声MP4)
                mSplitMediaFile.split(path,videoFilePath,null);
                //分离出视频和音频
                mSplitMediaFile.split(path,videoFilePath,audioFilePath);

四.SplitMediaFile 在 Activity 中的使用

SplitMediaFileTempActivity 中的使用代码如下:

public class TempActivity extends AppCompatActivity {

    private TextView mTvTest;
    private Button mBtnTest;
    private Button mBtnTest2;
    private VideoView mVideoView;

    private SplitMediaFile mSplitMediaFile;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_temp);

        //初始化控件
        initView();
        //初始化数据
        initData();
        //控件监听
        setListener();
    }

    /**
     * 初始化控件
     **/
    private void initView() {
        mTvTest = findViewById(R.id.mTvTest);
        mBtnTest = findViewById(R.id.mBtnTest);
        mBtnTest2 = findViewById(R.id.mBtnTest2);
        mVideoView = findViewById(R.id.mVideoView);
    }

    private void initData() {
        mSplitMediaFile=new SplitMediaFile();
    }

    /**
     * 控件监听
     **/
    private void setListener() {
        //播放视频
        mBtnTest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

        //分离 视频/音频
        mBtnTest2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String path="/data/user/0/com.testdemo/cache/test.mp4";
                LogUtil.i("========path="+path);
                //设置分离文件路径
                String tempPath=path.substring(0,path.lastIndexOf("/")+1);
                //视频文件路径
                String videoFilePath=tempPath+"test_video";
                //音频文件路径
                String audioFilePath=tempPath+"test_audio";

//                //仅分离出音频(mp3格式)
//                mSplitMediaFile.split(path,null,audioFilePath);
//                //仅分离出视频(无声MP4)
//                mSplitMediaFile.split(path,videoFilePath,null);
                //分离出视频和音频
                mSplitMediaFile.split(path,videoFilePath,audioFilePath);
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
}

五.效果图和项目结构图

效果图.png 项目结构图.png

测试使用视频地址如下(当然,大家也可以自己下一个mp4文件测试):
测试视频

六.SplitMediaFile 源码

下面贴出SplitMediaFile 源码:

相关文章

网友评论

      本文标题:Android从视频中提取出音频

      本文链接:https://www.haomeiwen.com/subject/veyvqltx.html