当前位置: 代码迷 >> 综合 >> Android-音视频(6):用 MediaExtractor 和 MediaMuxer API 解析和封装 mp4 文件
  详细解决方案

Android-音视频(6):用 MediaExtractor 和 MediaMuxer API 解析和封装 mp4 文件

热度:65   发布时间:2023-12-14 13:22:31.0

1.MediaExtractor API的作用


作用:

  • 可以把音视频文件的音频和视频分离,并抽取相应的数据通道,然后进行操作。

如何使用:

  1. 先要知道是针对哪个文件操作,所以要用 setDataSource(String filePath) 设置目标文件。
  2. 然后需要知道这个文件所有的通道数,用 getTrackCount() 得到,通过遍历,得到需要的通道 int i。
  3. 根据得到的通道,用 getTrackFirmat(int i ) 得到这个通道的数据格式(MediaFormat mediaFormat)。
  4. 然后把MediaExtractor对准这个通道 用 selectTack(int i),准备读取数据。
  5. readSampleData(ByteBuffer byteBuffer , int offset) 把指定通道中的数据按偏移量读取到byteBuffer中,这只是一帧的数据。
  6. 有了这个byteBuffer数据,之后的事就交给MediaMuxer去操作这一帧的数据,之后调用 adVance()调取下一帧,重复5、6。
  7. 操作完之后,记得释放 release()。

代码示例将在下面和MediaMuxer一起给出。

 

2.MediaMuxer API的作用


作用:

  • 生成一个音频或视频文件;还可以把音频与视频混合成一个音视频文件

如何使用:

  1. 因为是生成一个文件,所以构造一个MediaMuxer的时候需要传入文件的路径,和文件的格式如:new MediaMuxer(String newfilepath, int format)  格式一般为: MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4
  2. 然后需要添加通道,记录一个数据通道的格式(MediaExtracktor第3步得到) addTrack(MediaFormat format)并得到一个trackIndex,之后用这个判断用哪个通道写入数据。
  3. start():开始合成文件
  4. 每当MediaExtracktor的第5步后,用 writeSampleData(int trackIndex, ByteBuffer byteBuf, MediaCodec.BufferInfo bufferInfo):把ByteBuffer中的数据写入之前设置的文件中。
  5. 数据写入完成,stop():停止合成文件   release():释放资源

3.结合的示例代码如下:


String mp4FilePath = Environment.getExternalStorageDirectory().getAbsolutePath()+ File.separator+"test.mp4";
String newVideoFilePath = Environment.getExternalStorageDirectory().getAbsolutePath()+File.separator+"testVideo.mp4";private void startGetVideo() { //抽取mp4文件的视频数据,并生成新的mp4文件,但是没有声音。File videofile = new File(newVideoFilePath);if (videofile.exists()){videofile.delete();try {videofile.createNewFile();} catch (IOException e) {e.printStackTrace();}}getVideoThread = new Thread(){@Overridepublic void run() {try {mediaExtractor = new MediaExtractor();//设置视频文件,用于提取视频轨道数据mediaExtractor.setDataSource(mp4FilePath);int videoTrackIndex = -1;int framerate = 0;for (int i = 0 ; i < mediaExtractor.getTrackCount() ; i++){MediaFormat mediaformat = mediaExtractor.getTrackFormat(i);//跳过不是视频轨道的轨道if (!(mediaformat.getString(MediaFormat.KEY_MIME)).startsWith("video/")){continue;}//几帧/秒framerate = mediaformat.getInteger(MediaFormat.KEY_FRAME_RATE);//选择视频轨道mediaExtractor.selectTrack(i);//设置视频轨道的输出位置和格式mediaMuxer = new MediaMuxer(newVideoFilePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);//记录视频轨道值,之后要用这个值判断写入数据videoTrackIndex = mediaMuxer.addTrack(mediaformat);mediaMuxer.start();}if (mediaMuxer == null){return;}//读取轨道信息时,以及向新文件写入轨道信息时。用于保存每一帧的信息(如时长,size,flag)MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();//当前演示时长 初始化为0info.presentationTimeUs = 0;int sampleSize = 0;//申请一个空间保存每一帧视频数据,然后写入新文件ByteBuffer buffer = ByteBuffer.allocate(500*1024);while((sampleSize = mediaExtractor.readSampleData(buffer,0)) > 0){//保存帧信息info.size = sampleSize;info.flags = MediaCodec.BUFFER_FLAG_SYNC_FRAME;info.presentationTimeUs += 1000*1000 / framerate; // (1000*1000 / framerate) 是一帧的微秒时长//保存帧数据(向指定的视频轨道写入)mediaMuxer.writeSampleData(videoTrackIndex,buffer,info);mediaExtractor.advance(); //下一帧}mediaExtractor.release();mediaMuxer.stop();mediaMuxer.release();runOnUiThread(new Runnable() {@Overridepublic void run() {showInfor.append("\n"+"testVideo.mp4 视频轨道数据提取成功");}});} catch (IOException e) {e.printStackTrace();}finally {getVideoThread = null;}}};getVideoThread.start();}

 

 

 

  相关解决方案