多媒体系统之MediaMuxer和MediaExtractor(五)

1,302 阅读3分钟

阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:space.bilibili.com/474380680
MediaExtractor主要用于提取音视频相关信息,分离音视频。
MediaMuxer主要复用和解复用音视频。

MediaExtractor使用一般步骤

1.//设置数据源
setDataSource
2.//分离轨道
getTrackCount,getTrackFormat
3.//选择轨道
selectTrack,unselectTrack
4.//读取数据
readSampleData
5.//下一帧
advance
6.//释放
release

举例说明:

int trackCount = mediaExtractor.getTrackCount();
for (int i = 0; i < trackCount; i++) {
      MediaFormat trackFormat = mediaExtractor.getTrackFormat(i);
      String mime = trackFormat.getString(MediaFormat.KEY_MIME);
      if (mime.startsWith("video/")) {
          mediaExtractor.selectTrack(i);
          break;
      } else if (mime.startsWith("audio/")) {
          mediaExtractor.selectTrack(i);
          break;
      }
  }

MediaMuxer使用一般步骤

1.//添加轨道
addTrack
2.写数据
writeSampleData
3.释放
release

注意点

 buffinfo 必须设置相应的有效值,不然会引发错误
 //写入数据大小
 bufferInfo.size = readSampleDataSize;
 //偏移量
 bufferInfo.offset = 0;
 //是否为关键帧
 bufferInfo.flags = mediaExtractor.getSampleFlags();
 //PTS 单位为微妙,必须为递增不然会报错
 bufferInfo.presentationTimeUs += videoSampleTime;
 mediaMuxer.writeSampleData(trackIndex, buffer, bufferInfo);

这里重点关注下
bufferInfo.presentationTimeUs
mediaExtractor.getSampleTime()
因为mediaExtractor的提取顺序应该是dts的顺序不是pts的顺序,如果视频中存在b帧则getSampleTime不可能递增的,所以bufferInfo.presentationTimeUs=mediaExtractor.getSampleTime()可能会报错,前面说了这个值必须递增。如果不存在b帧,pts==dts,使用没问题。

设置PTS的办法
1.算出帧时间距,github上看见的,排除i帧来计算不知道是为什么,不排除感觉也一样的

        long videoSampleTime;
//            mediaExtractor.readSampleData(buffer, 0);
//            //skip first I frame
//            if (mediaExtractor.getSampleFlags() == MediaExtractor.SAMPLE_FLAG_SYNC)
//                mediaExtractor.advance();
        mediaExtractor.readSampleData(buffer, 0);
        long firstVideoPTS = mediaExtractor.getSampleTime();
        mediaExtractor.advance();
        mediaExtractor.readSampleData(buffer, 0);
        long SecondVideoPTS = mediaExtractor.getSampleTime();
        videoSampleTime = Math.abs(SecondVideoPTS - firstVideoPTS);

2.通过帧率来计算

//每秒多少帧
int frameRate=mediaFormat=getInteger(MediaFormat.KEY_FRAME_RATE)
//得出平均每一帧间隔多少微妙
videoSampleTime=1000*1000/frameRate

最后提供2个简单的运用示例
有耗时,不要ui线程使用,只是演示

    /**
     * 提取音/视频
     *
     * @param inPath
     * @param outPath
     * @param isVideo
     */
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
    public static void trackExtractor(String inPath, String outPath, boolean isVideo) {
        //提取器
        MediaExtractor mediaExtractor = new MediaExtractor();
        try {
            mediaExtractor.setDataSource(inPath);
        } catch (IOException e) {
            e.printStackTrace();
        }

        MediaMuxer mediaMuxer = null;
        //复用器
        try {
            mediaMuxer = new MediaMuxer(outPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
        } catch (IOException e) {
            e.printStackTrace();
        }

        int trackIndex = 0;
        int trackCount = mediaExtractor.getTrackCount();
        for (int i = 0; i < trackCount; i++) {
            MediaFormat trackFormat = mediaExtractor.getTrackFormat(i);
            String mime = trackFormat.getString(MediaFormat.KEY_MIME);
            if (mime.startsWith("video/") && isVideo) {
                trackIndex = mediaMuxer.addTrack(trackFormat);
                mediaExtractor.selectTrack(i);
                break;
            } else if (mime.startsWith("audio/") && !isVideo) {
                trackIndex = mediaMuxer.addTrack(trackFormat);
                mediaExtractor.selectTrack(i);
                break;
            }
        }
        mediaMuxer.start();

        ByteBuffer buffer = ByteBuffer.allocate(1024 * 1000);
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();

        long videoSampleTime=getSampleTime(mediaExtractor,buffer);
        while (true) {
            int readSampleDataSize = mediaExtractor.readSampleData(buffer, 0);
            if (readSampleDataSize < 0) {
                break;
            }
            bufferInfo.size = readSampleDataSize;
            bufferInfo.offset = 0;
            bufferInfo.flags = mediaExtractor.getSampleFlags();
            bufferInfo.presentationTimeUs += videoSampleTime;
            mediaMuxer.writeSampleData(trackIndex, buffer, bufferInfo);
            mediaExtractor.advance();
        }

        mediaExtractor.release();
        mediaMuxer.stop();
        //内部也会执行stop,所以可以不用执行stop
        mediaMuxer.release();


    }

    private static long getSampleTime(MediaExtractor mediaExtractor, ByteBuffer buffer) {
        long videoSampleTime;
//            mediaExtractor.readSampleData(buffer, 0);
//            //skip first I frame
//            if (mediaExtractor.getSampleFlags() == MediaExtractor.SAMPLE_FLAG_SYNC)
//                mediaExtractor.advance();
        mediaExtractor.readSampleData(buffer, 0);
        long firstVideoPTS = mediaExtractor.getSampleTime();
        mediaExtractor.advance();
        mediaExtractor.readSampleData(buffer, 0);
        long SecondVideoPTS = mediaExtractor.getSampleTime();
        videoSampleTime = Math.abs(SecondVideoPTS - firstVideoPTS);
        Log.d("MediaMuxerUtil", "videoSampleTime is " + videoSampleTime);
        return videoSampleTime;
    }


    /**
     * 合成音视频
     *
     * @param videoPath
     * @param audioPath
     * @param outPath
     */
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
    public static void trackMuxer(String videoPath, String audioPath, String outPath) {
        MediaExtractor videoExtractor = new MediaExtractor();
        try {
            videoExtractor.setDataSource(videoPath);
        } catch (IOException e) {
            e.printStackTrace();
        }
        MediaFormat videoFormat = null;
        int videoTrackIndex = -1;
        int videoTrackCount = videoExtractor.getTrackCount();
        for (int i = 0; i < videoTrackCount; i++) {
            videoFormat = videoExtractor.getTrackFormat(i);
            String mime = videoFormat.getString(MediaFormat.KEY_MIME);
            if (mime.startsWith("video/")) {
                videoTrackIndex = i;
                break;
            }
        }

        MediaExtractor audioExtractor = new MediaExtractor();
        try {
            audioExtractor.setDataSource(audioPath);
        } catch (IOException e) {
            e.printStackTrace();
        }
        MediaFormat audioFormat = null;
        int audioTrackIndex = -1;
        int audioTrackCount = audioExtractor.getTrackCount();
        for (int i = 0; i < audioTrackCount; i++) {
            audioFormat = audioExtractor.getTrackFormat(i);
            String mime = audioFormat.getString(MediaFormat.KEY_MIME);
            if (mime.startsWith("audio/")) {
                audioTrackIndex = i;
                break;
            }
        }

        videoExtractor.selectTrack(videoTrackIndex);
        audioExtractor.selectTrack(audioTrackIndex);

        MediaCodec.BufferInfo videoBufferInfo = new MediaCodec.BufferInfo();
        MediaCodec.BufferInfo audioBufferInfo = new MediaCodec.BufferInfo();

        MediaMuxer mediaMuxer = null;
        try {
            mediaMuxer = new MediaMuxer(outPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
        } catch (IOException e) {
            e.printStackTrace();
        }
        int writeVideoTrackIndex = mediaMuxer.addTrack(videoFormat);
        int writeAudioTrackIndex = mediaMuxer.addTrack(audioFormat);
        mediaMuxer.start();
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 1000);
        long videoSampleTime=getSampleTime(videoExtractor,byteBuffer);
        while (true) {
            int readVideoSampleSize = videoExtractor.readSampleData(byteBuffer, 0);
            if (readVideoSampleSize < 0) {
                break;
            }
            videoBufferInfo.size = readVideoSampleSize;
            videoBufferInfo.presentationTimeUs +=videoSampleTime;
            videoBufferInfo.offset = 0;
            videoBufferInfo.flags = videoExtractor.getSampleFlags();
            mediaMuxer.writeSampleData(writeVideoTrackIndex, byteBuffer, videoBufferInfo);
            videoExtractor.advance();
        }
        long audioSampleTime=getSampleTime(audioExtractor,byteBuffer);
        while (true) {
            int readAudioSampleSize = audioExtractor.readSampleData(byteBuffer, 0);
            if (readAudioSampleSize < 0) {
                break;
            }

            audioBufferInfo.size = readAudioSampleSize;
            audioBufferInfo.presentationTimeUs += audioSampleTime;
            audioBufferInfo.offset = 0;
            audioBufferInfo.flags = audioExtractor.getSampleFlags();
            mediaMuxer.writeSampleData(writeAudioTrackIndex, byteBuffer, audioBufferInfo);
            audioExtractor.advance();
        }

        mediaMuxer.stop();
        mediaMuxer.release();
        videoExtractor.release();
        audioExtractor.release();
    }

原文链接:blog.csdn.net/u012098794/…
阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:space.bilibili.com/474380680