视频播放的软解与硬解功能,你知道多少?

来自:麻辣软硬件(微信号:VOSDeveloper),作者:达不优K

现在各种视频软件上都有硬解软解这两个选择,但它们有什么区别呢?用哪个好呢?今天就跟随小编一起了解了解吧。

首先,我们看下视频播放的基本流程:

解封装:就是将输入的封装格式的数据,分离成为音频流压缩编码数据和视频流压缩编码数据。如上图,将MP4和FLV格式解封装成视频数据H264、MPEG2和音频数据AAC、MP3格式。

解码:就是将视频/音频压缩的编码数据解码成为非压缩的视频/音频原始数据。如上图,将视频数据解码成YUV格式和音频数据解码成PCM格式。

音视频同步:就是根据解封装模块处理过程中获取到的参数信息,同步解码出来的视频和音频数据,并将视频音频数据送至系统的显卡和声卡播放出来。

所谓的软解硬解也就是在解码方式上的区别。下面我们说说软件硬解到底是什么,各有什么优缺点。

概述

软解:即通过软件让CPU来对视频进行解码处理;

硬解:是将原来全部交由CPU来处理的视频数据的部分交由GPU来做。

优缺点

硬解码效率非常高,这样不但能够减轻CPU的负担,还有着低功耗,发热少等特点。但是,由于硬解码起步比较晚,软件和驱动对他的支持度很低,往往会出现兼容性不好的问题。此外,硬解码的滤镜、字幕、画质方面都做的不够理想。

软解码需要对大量的视频信息进行运算,所以对CPU处理性能的要求非常高。巨大的运算量就会造成转换效率低,发热量高等问题。不过,软解码不需要过多的硬件支持,兼容性非常高。而且软解码拥有丰富的滤镜,字幕,画面处理优化等效果,只要你CPU够强悍,就能够实现更加出色的画面效果。

实现方式

软解码

我们最最常见的视频软解码开源库就是FFmpeg。目前基于FFmpeg的开源播放器有B站的ijkplayer。

ijkplayer的开源地址 : https://github.com/bilibili/ijkplayer

从下图中可以看到,ijkplayer内部利用了ffmpeg解码库。

基于ffmpeg实现主要接口

//创建ffmpeg codec,在ffmpeg中是根据codecid(aac,h264等注册的id)寻找合适的decoder,返回AVCodec对象
avcodec_find_decoder

/*这函数创建decode的context,返回的codecContext包含解码器所需要的各种配置信息,比如
  对于aac decode,context可以用来设置sample_rate,channels,profile等
  对于h264 decode,context可以用来设置width,height等*/

avcodec_alloc_context3

//用已经配置好的decoder的context,来configure解码器codec
avcodec_open2

//初始化一个pkt用于接收待解码的数据,用demux输出的数据,填充pkt的data,设置pkt的flag(是否包含key frame等)
av_init_packet(AVPacket *pkt)

//将填充满的pkt,发送给解码器
avcodec_send_packet

//从解码器接收decode后的数据,填充到AVFrame中。
avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame)

硬解码

MediaCodec

MediaCodec是安卓自带的视频编解码接口,由于使用的是硬解码,其效率相对FFMPEG高出来不少。而MediaCodec就很好拓展,我们可以根据流媒体的协议和设备硬件本身来自定义硬件解码,代表播放器就是Google的ExoPlayer。

ExoPlayer的开源地址 : https://github.com/google/ExoPlayer

基本流程:

1.创建和配置MediaCodec对象

2.进行以下循环:

    如果一个输入缓冲区准备好:

    读取部分数据,复制到缓冲区

    如果一个输出缓冲区准备好:

    复制到缓冲区

3.销毁MediaCodec对象


接口如下:

//根据视频编码创建解码器,这里是解码AVC编码的视频
MediaCodec mediaCodec =MediaCodec.createDecoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
//创建视频格式信息
MediaFormat mediaFormat = MediaFormat.createVideoFormat(mimeType, width, height);
//配置
mediaCodec.configure(mediaFormat, surfaceView.getHolder().getSurface(), null0);
mediaCodec.start();
//停止解码,此时可以再次调用configure()方法
mediaCodec.stop();
//释放内存
mediaCodec.release();
//一下是循环解码接口
getInputBuffers:获取需要编码数据的输入流队列,返回的是一个ByteBuffer数组 
queueInputBuffer:输入流入队列 
dequeueInputBuffer:从输入流队列中取数据进行编码操作 
getOutputBuffers:获取编解码之后的数据输出流队列,返回的是一个ByteBuffer数组 
dequeueOutputBuffer:从输出队列中取出编码操作之后的数据 
releaseOutputBuffer:处理完成,释放ByteBuffer数据 


用MediaCodec来实现的话,代码中主要通过上面的接口实现了媒体的播放过程。

实例可以参考:

https://blog.csdn.net/u014653815/article/details/81084161


下图是MediaCodec调用createDecoderByType创建过程。

由上图可知,MediaCodec并不是真正的codec,真正codec是在openMax。

OpenMax是一个多媒体应用程序的框架标准,通过使媒体加速组件能够在开发、集成和编程环节中实现跨多操作系统和处理器硬件平台,提供全面的流媒体编解码器和应用程序便携化。Android的多媒体引擎OpenCore和StageFright都可以使用OpenMax作为插件,主要用于编解码(Codec)处理。


下面我来看看硬件厂商又是如何将自己硬解码代码加载到OpenMax框架中的?

在加载软解码库的代码中,可以看到有加载libstagefrighthw.so的代码,其是加载硬件解码plugin,每个平台都有自己libstagefrighthw.so的实现,以实现硬编解码。

MediaPlayer

MediaPlayer是Android中的一个多媒体播放类,我们能通过它控制音视频流或本地音视频资源的播放过程。

以下是mediaPlayer接口:

MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(url);
mediaPlayer.prepare(); // might take long! (for buffering, etc)
mediaPlayer.start();

用MediaPlayer来实现的话,代码中主要通过5个步骤实现了媒体的播放功能。底层是如何实现的呢?下面我们就来看看。

不同的平台,硬件厂商也会实现自己的播放器。下图是MediaPlayer框架图:

MediaPlayer通过Binder通信,最后调用到MediaPlayerService。这里以Hiplayer为例,展开说明下厂商是如何在android 的 mediaplayer中注入自己播放器的。


从上图中可以看到,海思自己实现了一个HiMediaPlayerManage,然后实现了HiMediaPlayerFactory来创建HiMediaPlayerManage,HiMediaPlayerFactory是在MediaPlayerFactory中被注册进去的。这样就完成了厂商自己播放器注入到android框架中去。

MediaPlayerFactory也是使用了android设计模式中经典的工厂模式。

HiMediaPlayerFactory都实现了IFactory的接口,其中最重要的是ScoreFactory和CreatePlayer。其中ScoreFactory是根据播放类型参数来选择播放方式,CreatePlayer创建播放器。

HiMediaPlayerManage就是播放器的具体实现了,用来对接Android标准的MediaPlayer接口。

结束语

在Android设备硬件支持的情况下优先使用Android设备的硬件解码,减少CPU的占用,更加省电。

在Android设备硬解不支持的情况下选择使用软解码,不管怎么样,视频至少能够播放,具有更好的适应性,但是增加了CPU的占用,更加费电,软硬结合才是王道,根据实际情况合理选择。

读完了这篇文章,是否对视频应用的软解硬解有了了解呢?在视频软件的设置中能切换软解硬解,赶紧去试下软解硬解功能吧!

推荐↓↓↓
安卓开发
上一篇:Android系统内存泄露之必备调试工具 下一篇:放荡不羁SVG讲解与实战——Android高级UI