Android MediaCodec实现多段音视频的截取与拼接

转自:https://mp.weixin.qq.com/s?__biz=MzI2OTQxMTM4OQ==&mid=2247484195&idx=1&sn=c73f910258f46fbddd895803f2b1ea2a&chksm=eae1f671dd967f67b73d7ce6042cfb9be10cfc10448fc00c0fbe61aca834e9b09a6dca8ac056&mpshare=1&scene=1&srcid=1111UG0UiOH3EBH9BNW5dEY8&pass_ticket=RUgMlJ%2FKdE4%2B5YiNAe9uVO8kOvzl2%2F4EGNxiLjPkD8D9wjj0UVQbMTBybNi9o2rl#rd  

  视音频编辑中,对多段媒体素材进行截取和拼接是非常常见的操作。截取和拼接实际上是对媒体文件数据重新进行组合的过程。

    要实现这些功能,就需要对媒体文件进行编解码操作,即先解码要处理的媒体文件数据,然后再按照某种规则对这些数据进行编码,以生成我们所需的目标。



    Android提供的MediaCodec及其相关类为我们提供了所需的方法,这些类主要包括:MediaCodec、MediaExtractor、MediaMuxer、MediaFormat。

    MediaCodec用于创建视音频编解码器,通过它可以对视音频数据进行编解码操作,它是编解码功能的核心类。

    MediaExtractor相当于一个reader,它用于读取媒体文件,并提取出其中的视音频数据。

    MediaMuxer相当于一个writer,它用于将内存中的视音频数据写到文件中。

    MediaFormat即媒体格式类,它用于描述媒体的格式参数,如视频帧率、音频采样率等。

    对视音频文件进行截取与拼接的主要过程是:先创建视音频编解码器,再分别启动视频线程和音频线程,以分别对视音频数据进行解码、编码,最后将编码好的数据写入文件。

    主要逻辑如下,关键是三处线程同步的地方,具体原因稍后解释。


    再来了解一下这几个类的“脾气”。

    一般用MediaCodec创建编解码器时,使用的都是createDecoderByType方法,但在用三星PAD(API LEVEL 18, Android version 4.3)调试时发现,调用该方法创建音频编码器时会出错。故改为使用createByCodecName("OMX.SEC.aac.enc")创建音频编码器。估计这是一个API bug。

    configure decoder时,第一个格式参数要与源的格式相同,这里可以先通过extractor将源的格式读出来,再直接传给configure方法。configure encoder时,需设定几个必要的参数,具体请参考官方说明。

    当把全部要处理的数据灌给编解码器后,使用queueInputBuffer(inputBufIndex,0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM)方法来通知编解码器结束工作。之后,在OutputBuffer的bufferInfo中,将携带这个标志,通过判断是否有这个标志,我们就可以断定数据是否都已处理完成,以进行后续操作。再之后,dequeueOutputBuffer的返回都将是INFO_TRY_AGAIN_LATER。当然,如果你自己有办法在OutputBuffer中判断数据是否灌完,也可以不使用此标志。

    当数据灌完后,要使用releaseOutputBuffer,把缓冲区释放掉。否则,你会发现queueInputBuffer总是返回-1,因为没有空闲的缓冲区了。

    MediaExtractor用来读取源文件,给定文件路径后,便可将其中的视音频数据拿出来。关键是它的seekTo方法,它用于对读取数据的游标进行定位,可以定位到指定点前的最后一个sync点、指定点后的第一个sync点,或者与指定点最近的sync点。对于H.264数据,sync点可以认为是视频关键帧的时码位置。

    MediaMuxer的使用非常简单,先创建,再添加视音频轨,然后start,再writeSampleData,最后stop。需要注意的是,必需先添加完所有的视音频轨后,再去start,而不能先start,再试图去addTrack,否则会出错。这也是为什么在本文的逻辑中,视频线程需要去wait音频线程添加完音频轨后再继续的原因。

    需要注意的是,不能在启动完编解码器后,立即调用getOutputFormat企图addTrack,而应该在dequeueOutputBuffer后的INFO_OUTPUT_FORMAT_CHANGED中调用,否则会出错。

    当要向文件中同时写入视频和音频数据时,必需先writeSampleData所有视频数据,再写音频数据,或者反之,即二者必需连续调用writeSampleData,不能交叉调用,否则写出的文件会有问题。这也是本文中为何muxer启动后,音频线程需等待视频线程先写完数据,自己才能继续干活的原因。

    当所有的writeSampleData完成后,不要忘记调用stop和release,否则写出的文件也会有问题。

    最后还要注意,这几个类中,时间单位都是微秒。

     下面我来补充mediaCodec的支持的格式,MediaCodec更多详情,会在Camera相关框架分析中,会隆重介绍的:

MediaCodec支持的格式:

  • "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

猜你喜欢

转载自blog.csdn.net/zhangzhuo1024/article/details/78620407