1. 首页 > 抖音热词

数字音频解码器有什么用,解码器的功能有哪些

  一、MediaCodec的工作原理。类似MediaCodec的Android提供了访问低级多媒体编码器/解码器的接口,这是Android低级多媒体架构的一部分。通常与MediaExtractor、MediaMuxer、AudioTrack配合使用,可以对H.264、H.265、AAC、3gp等常见音视频格式进行编解码。

  广义来说,MediaCodec的工作原理是处理输入数据生成输出数据。具体来说,MediaCodec在编解码过程中使用一组输入/输出缓冲区同步或异步处理数据:首先客户端将待编解码的数据写入获取的Codec的输入缓冲区并提交给codec,codec处理后传输到编码器的输出缓冲区,同时回收客户端对输入缓冲区的所有权;然后,客户端从获得编解码器输出缓冲区中读取编码后的数据进行处理,处理完成后,编解码器将客户端的所有权收回到输出缓冲区。重复整个过程,直到编码器停止工作或异常退出。

   MEDIC的功能是处理输入数据,生成输出数据。首先,生成输入数据缓冲区,并将数据填充到缓冲区中并提供给编解码器。编解码器将异步处理输入数据,然后将填充的输出缓冲区提供给消费者,消费者在消费后将缓冲区返回给编解码器。

  二、MediaCodec的编码过程在整个编解码过程中,MediaCodec的使用会经历配置、启动、数据处理、停止、释放等几个过程,对应的状态可以概括为停止、执行、释放三种状态。停止状态可以细分为未初始化、已配置和异常,执行状态也可以细分为读写数据(刷新)、运行和流结束。

   MediaCodec的整体状态结构图如下:

  从上图可以看出,MediaCodec创建时,会进入未初始化状态。设置好配置信息,调用start()启动后,MediaCodec将进入运行状态,可以读写数据。如果在此过程中出现错误,MediaCodec将进入停止状态。我们只需要使用reset方法重置编解码器,否则MediaCodec持有的资源最终会被释放。当然,如果正常使用MediaCodec,我们也可以向编解码器发送EOS指令,调用stop和release方法来终止编解码器的使用。

  第三,MediaCodec API表明MediaCodec可以处理特定的视频流。主要有这些方法:

   GetInputBuffers:获取待编码数据的输入流队列,返回一个ByteBuffer数组queueInputBuffer:input into queue dequeue input buffer:从输入流队列中获取数据进行编码操作getOutputBuffers:获取编码解码后数据的输出流队列,返回的是一个ByteBuffer数组dequeueOutputBuffer:将编码操作后的数据从输出队列中取出,releaseOutputBuffer:处理完成后,释放ByteBuffer数据。四、MediaCodec基本上使用所有同步模式。MediaCodec API遵循一种模式:

  创建和配置媒体编解码器对象循环,直到完成3360。如果输入缓冲区准备就绪,读取一个输入块并将其复制到输入缓冲区。如果输出缓冲区准备好了,复制输出缓冲区的数据以释放MediaCodec对象。

   (1) 创建编/解码器媒体编解码器主要提供了createEncoderByType(字符串类型)、createDecoderByType(字符串类型)两个方法来创建编解码器,它们均需要传入一个哑剧类型多媒体格式。常见的哑剧类型多媒体格式如下:"视频/x-vnd。on2。VP8”-VP8视频(即视频输入. webm)“视频/x-vnd。on2。VP9”-VP9视频(即视频输入. webm)"视频/AVC "-h . 264/AVC视频"视频/mp4v-es "-MPEG4视频"视频/3gpp "-h . 263视频"音频/3gpp "-AMR窄带音频“音频/AMR-WB”-AMR宽带音频“音频/mpeg”-mpeg 1/2音频层III “音频/mp4a-latm”-AAC音频(注意,这是原始AAC包,不在有限转角力矩电机打包!)"音频/vorbis"-vorbis音频"音频/g711-alaw"-g . 711 alaw音频"音频/g711-mlaw"-g . 711 ulaw音频当然,媒体编解码器还提供了一个createByCodecName(字符串名称)方法,支持使用组件的具体名称来创建编解码器。但

  是该方法使用起来有些麻烦,且官方是建议最好是配合MediaCodecList使用,因为MediaCodecList记录了所有可用的编解码器。当然,我们也可以使用该类对传入的minmeType参数进行判断,以匹配出MediaCodec对该mineType类型的编解码器是否支持。

  以指定MIME类型为“video/avc”为例,代码如下:

  private static MediaCodecInfo selectCodec(String mimeType) { // 获取所有支持编解码器数量 int numCodecs = MediaCodecList.getCodecCount(); for (int i = 0; i < numCodecs; i++) { // 编解码器相关性信息存储在MediaCodecInfo中 MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i); // 判断是否为编码器 if (!codecInfo.isEncoder()) { continue; } // 获取编码器支持的MIME类型,并进行匹配 String[] types = codecInfo.getSupportedTypes(); for (int j = 0; j < types.length; j++) { if (types[j].equalsIgnoreCase(mimeType)) { return codecInfo; } } } return null; }(2) 配置、启动编/解码器

  编解码器配置使用的是MediaCodec的configure方法,该方法首先对MediaFormat存储的数据map进行提取,然后调用本地方法native-configure实现对编解码器的配置工作。在配置时,configure方法需要传入format、surface、crypto、flags参数,其中format为MediaFormat的实例,它使用”key-value”键值对的形式存储多媒体数据格式信息;surface用于指明解码器的数据源来自于该surface;crypto用于指定一个MediaCrypto对象,以便对媒体数据进行安全解密;flags指明配置的是编码器(CONFIGURE_FLAG_ENCODE)。

  MediaFormat mFormat = MediaFormat.createVideoFormat("video/avc", 640 ,480); // 创建MediaFormatmFormat.setInteger(MediaFormat.KEY_BIT_RATE,600); // 指定比特率mFormat.setInteger(MediaFormat.KEY_FRAME_RATE,30); // 指定帧率mFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,mColorFormat); // 指定编码器颜色格式 mFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL,10); // 指定关键帧时间间隔mVideoEncodec.configure(mFormat,null,null,MediaCodec.CONFIGURE_FLAG_ENCODE);

  以上代码是在编码H.264时的配置方法,createVideoFormat(“video/avc”, 640 ,480)为”video/avc”类型(即H.264)编码器的MediaFormat对象,需要指定视频数据的宽高,如果编解码音频数据,则调用MediaFormat的createAudioFormat(String mime, int sampleRate,int channelCount)的方法。除了一些诸如视频帧率、音频采样率等配置参数,这里需要着重讲解一下MediaFormat.KEY_COLOR_FORMAT配置属性,该属性用于指明video编码器的颜色格式,具体选择哪种颜色格式与输入的视频数据源颜色格式有关。比如,我们都知道Camera预览采集的图像流通常为NV21或YV12,那么编码器需要指定相应的颜色格式,否则编码得到的数据可能会出现花屏、叠影、颜色失真等现象。MediaCodecInfo.CodecCapabilities.存储了编码器所有支持的颜色格式,常见颜色格式映射如下:

  原始数据 编码器 NV12(YUV420sp) ———> COLOR_FormatYUV420PackedSemiPlanar NV21 ———-> COLOR_FormatYUV420SemiPlanar YV12(I420) ———-> COLOR_FormatYUV420Planar

  当编解码器配置完毕后,就可以调用MediaCodec的start()方法,该方法会调用低层native_start()方法来启动编码器,并调用低层方法ByteBuffer[] getBuffers(input)来开辟一系列输入、输出缓存区。

  start()方法源码如下:

  public final void start() { native_start(); synchronized(mBufferLock) { cacheBuffers(true /* input */); cacheBuffers(false /* input */); } }(3) 数据处理

  MediaCodec支持两种模式编解码器,即同步synchronous、异步asynchronous,所谓同步模式是指编解码器数据的输入和输出是同步的,编解码器只有处理输出完毕才会再次接收输入数据;而异步编解码器数据的输入和输出是异步的,编解码器不会等待输出数据处理完毕才再次接收输入数据。这里,我们主要介绍下同步编解码,因为这种方式我们用得比较多。我们知道当编解码器被启动后,每个编解码器都会拥有一组输入和输出缓存区,但是这些缓存区暂时无法被使用,只有通过MediaCodec的dequeueInputBuffer/dequeueOutputBuffer方法获取输入输出缓存区授权,通过返回的ID来操作这些缓存区。下面我们通过一段官方提供的代码,进行扩展分析:

  MediaCodec codec = MediaCodec.createByCodecName(name); codec.configure(format, …); MediaFormat outputFormat = codec.getOutputFormat(); // option B codec.start(); for (;;) { int inputBufferId = codec.dequeueInputBuffer(timeoutUs); if (inputBufferId >= 0) { ByteBuffer inputBuffer = codec.getInputBuffer(…); // fill inputBuffer with valid data … codec.queueInputBuffer(inputBufferId, …); } int outputBufferId = codec.dequeueOutputBuffer(…); if (outputBufferId >= 0) { ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferId); MediaFormat bufferFormat = codec.getOutputFormat(outputBufferId); // option A // bufferFormat is identical to outputFormat // outputBuffer is ready to be processed or rendered. … codec.releaseOutputBuffer(outputBufferId, …); } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { // Subsequent data will conform to new format. // Can ignore if using getOutputFormat(outputBufferId) outputFormat = codec.getOutputFormat(); // option B } } codec.stop(); codec.release();

  从上面代码可知,当编解码器start后,会进入一个for(;;)循环,该循环是一个死循环,以实现不断地去从编解码器的输入缓存池中获取包含数据的一个缓存区,然后再从输出缓存池中获取编解码好的输出数据。

本文由 pos机办理 法律钓鱼技术指导

本文由发布,不代表新营销立场,转载联系作者并注明出处:https://www.newmarketingcn.com/douyin/221967.html

留言与评论(共有 0 条评论)
   
验证码: