Android中音视频合成的几种方案详析

  

  

最近工作中遇到了音视频处理的需求,Android下音视频合成,在当前调研方案中主要有三大类方法:MediaMux硬解码,mp4parser, FFmepg。三种方法均可实现,但是也有不同的局限和问题,先将实现和问题记录于此,便于之后的总结学习。下面话不多说了,来一起看看详细的介绍吧。
  

  


  

  

利用MediaMux实现音视频的合成。
  

  

效果:可以实现音视频的合并,利用Android原生的VideoView和SurfaceView播放正常,大部分的播放器也播放正常,但是,但是,在上传Youtube就会出现问题:音频不连续,分析主要是上Youtube时传会被再次的压缩,可能在压缩的过程中出现音频的帧率出现问题。
  

  

分析:在MediaCodec.BufferInfo的处理中,时间戳presentationTimeUs出现问题,导致Youtube的压缩造成音频的紊乱。

        公共静态孔隙muxVideoAndAudio (audioPath videoPath的字符串,字符串,字符串muxPath) {   尝试{   MediaExtractor videoExtractor=new MediaExtractor ();   videoExtractor.setDataSource (videoPath);   MediaFormat videoFormat=零;   int videoTrackIndex=1;   int videoTrackCount=videoExtractor.getTrackCount ();   for (int i=0;我& lt;videoTrackCount;我+ +){   videoFormat=videoExtractor.getTrackFormat(我);   字符串mimeType=videoFormat.getString (MediaFormat.KEY_MIME);   如果(mimeType.startsWith(视频/)){   videoTrackIndex=我;   打破;   }   }   MediaExtractor audioExtractor=new MediaExtractor ();   audioExtractor.setDataSource (audioPath);   MediaFormat audioFormat=零;   int audioTrackIndex=1;   int audioTrackCount=audioExtractor.getTrackCount ();   for (int i=0;我& lt;audioTrackCount;我+ +){   audioFormat=audioExtractor.getTrackFormat(我);   字符串mimeType=audioFormat.getString (MediaFormat.KEY_MIME);   如果(mimeType.startsWith(音频/)){   audioTrackIndex=我;   打破;   }   }   videoExtractor.selectTrack (videoTrackIndex);   audioExtractor.selectTrack (audioTrackIndex);   MediaCodec。BufferInfo videoBufferInfo=new MediaCodec.BufferInfo ();   MediaCodec。BufferInfo audioBufferInfo=new MediaCodec.BufferInfo ();   MediaMuxer MediaMuxer=new MediaMuxer (muxPath MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);   int writeVideoTrackIndex=mediaMuxer.addTrack (videoFormat);   int writeAudioTrackIndex=mediaMuxer.addTrack (audioFormat);   mediaMuxer.start ();   ByteBuffer ByteBuffer=ByteBuffer。分配(500 * 1024);   长sampleTime=0;   {   videoExtractor。readSampleData (byteBuffer, 0);   如果(videoExtractor.getSampleFlags ()==MediaExtractor.SAMPLE_FLAG_SYNC) {   videoExtractor.advance ();   }   videoExtractor。readSampleData (byteBuffer, 0);   长secondTime=videoExtractor.getSampleTime ();   videoExtractor.advance ();   长thirdTime=videoExtractor.getSampleTime ();   sampleTime=数学。abs (thirdTime secondTime);   }   videoExtractor.unselectTrack (videoTrackIndex);   videoExtractor.selectTrack (videoTrackIndex);   而(真){   int readVideoSampleSize=videoExtractor。readSampleData (byteBuffer, 0);   如果(readVideoSampleSize & lt;0){   打破;   }   videoBufferInfo。大?readVideoSampleSize;   videoBufferInfo。presentationTimeUs +=sampleTime;   videoBufferInfo。抵消=0;//noinspection WrongConstant   videoBufferInfo。旗帜=MediaCodec.BUFFER_FLAG_SYNC_FRAME;//videoExtractor.getSampleFlags ()   mediaMuxer。writeSampleData (writeVideoTrackIndex byteBuffer, videoBufferInfo);   videoExtractor.advance ();   }   而(真){   int readAudioSampleSize=audioExtractor。readSampleData (byteBuffer, 0);   如果(readAudioSampleSize & lt;0){   打破;   }   audioBufferInfo。大?readAudioSampleSize;   audioBufferInfo。presentationTimeUs +=sampleTime;   audioBufferInfo。抵消=0;//noinspection WrongConstant   audioBufferInfo。旗帜=MediaCodec.BUFFER_FLAG_SYNC_FRAME;//videoExtractor.getSampleFlags ()   mediaMuxer。writeSampleData (writeAudioTrackIndex byteBuffer, audioBufferInfo);   audioExtractor.advance ();   }   mediaMuxer.stop ();   mediaMuxer.release ();   videoExtractor.release ();   audioExtractor.release ();   }捕捉(IOException e) {   e.printStackTrace ();   }   }      

        公共静态孔隙muxVideoAudio (audioFilePath videoFilePath的字符串,字符串,字符串outputFile) {   尝试{   MediaExtractor videoExtractor=new MediaExtractor ();   videoExtractor.setDataSource (videoFilePath);   MediaExtractor audioExtractor=new MediaExtractor ();   audioExtractor.setDataSource (audioFilePath);   MediaMuxer mux=new MediaMuxer (outputFile 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);   LogUtil。d(标签,“视频格式”+ videoFormat.toString ());   LogUtil。d(标签,“音频格式”+ audioFormat.toString ());   布尔sawEOS=false;   int frameCount=0;   int抵消=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。希望(0,MediaExtractor.SEEK_TO_CLOSEST_SYNC);   audioExtractor。希望(0,MediaExtractor.SEEK_TO_CLOSEST_SYNC);   muxer.start ();   而(! sawEOS) {   videoBufferInfo。抵消=抵消;   videoBufferInfo。=videoExtractor大小。readSampleData (videoBuf抵消);   如果(videoBufferInfo。大小& lt;0 | | audioBufferInfo。大小& lt;0){   sawEOS=true;   videoBufferInfo。大?0;   其他}{   videoBufferInfo。null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null

Android中音视频合成的几种方案详析