【干货】关于软解(ffmpeg)和硬解(MediaCodec、MediaPlayer)以及底层(OpenMax)的那点事
现在各种视频软件上都有硬解软解这两个选择,但它们有什么区别呢?用哪个好呢?今天就跟随小编一起了解了解吧。
首先,了解下播放视频的基本流程:
解封装:就是将输入的封装格式的数据,分离成为音频流压缩编码数据和视频流压缩编码数据。如上图,将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(), null, 0);
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(由于篇幅问题,其过程这里就不展开讲了,可以参考小编的另一篇文章:【android系统】binder通信机制--记一次项目开发中用到的实例)。这里以Hiplayer为例,展开说明下厂商是如何在android 的 mediaplayer中注入自己播放器的。
从上图中可以看到,海思自己实现了一个HiMediaPlayerManage,然后实现了HiMediaPlayerFactory来创建HiMediaPlayerManage,HiMediaPlayerFactory是在MediaPlayerFactory中被注册进去的。这样就完成了厂商自己播放器注入到android框架中去。
MediaPlayerFactory也是使用了android设计模式中经典的工厂模式(如果有兴趣关注我们,回复"android设计模式")。
HiMediaPlayerFactory都实现了IFactory的接口,其中最重要的是ScoreFactory和CreatePlayer。其中ScoreFactory是根据播放类型参数来选择播放方式,CreatePlayer创建播放器。
HiMediaPlayerManage就是播放器的具体实现了,用来对接Android标准的MediaPlayer接口。
结束语
在Android设备硬件支持的情况下优先使用Android设备的硬件解码,减少CPU的占用,更加省电。
在Android设备硬解不支持的情况下选择使用软解码,不管怎么样,视频至少能够播放,具有更好的适应性,但是增加了CPU的占用,更加费电,软硬结合才是王道,根据实际情况合理选择。
读完了这篇文章,是否对视频应用的软解硬解有了了解呢?赶紧去试下软解硬解功能吧,你更喜欢哪一个?欢迎大家扫描关注下方二维码和我分享交流吧!也欢迎大家下方留言评论,谢谢!
- END -
干货满满!关注一下呗~
【干货】关于软解(ffmpeg)和硬解(MediaCodec、MediaPlayer)以及底层(OpenMax)的那点事相关推荐
- Ubuntu18使用FFMPEG实现QSV硬解
前言 由于项目需要,需要在一块I7-8850H上进行H264解码成YUV并显示的功能.由于系统是Ubuntu18,故打算使用QT+FFMPEG来实现.先前的一路软解发现CPU占用率去到了20%以上,我 ...
- ffmpeg mediacodec 硬解初探
http://www.cnblogs.com/elesos/p/6860865.html ffmpeg mediacodec 硬解初探 1编译: ffmpeg自3.1版本加入了android medi ...
- android播放器和视频拍摄中的硬解和软解以及硬编和软编的区别
转载 原文地址:https://blog.csdn.net/ltym2014/article/details/82354606 https://blog.csdn.net/lipengshiwo/ar ...
- 播放器解码硬解跟软解有什么区别
1.什么是硬解?硬解是要机器中的专门的解码芯片来完成,质量因厂家的技术能力而定,部分厂商技术实力强,兼容性和解码效果做的比较好,而有些厂商技术实力稍差,兼容性和解码效果做的就不尽如意. 2.什么是软解 ...
- Linux安装jellyfin硬件加速,ESXi7,黑群晖,Jellyfin与NVIDIA硬解的解决方案
Last updated on 2021年1月25日 这是一片没有人的领地,基本没有现成的文章和教程,参考了网络上几乎所有相关教程,总结如下. 关于实现之后的效果,可以参考:https://www.l ...
- Win7codecs设置教程-开启高清的详细步骤--硬解
下载最新版本Win7codecs(解码器)有了这款解码器你不用安装别的播放器了Windows Media Player通吃! 下载好了为什么要设置硬解呢?一般安装好Win7codecs已经默认硬解了, ...
- FFmpeg之硬解码
导读 前面我们已经使用NDK编译出了FFmpeg并且已经集成到了Android Studio中去,相关文章:NDK21编译ffmpeg5.0.1 众所周知,软解码虽然兼容性一流,但是却非常依赖CPU, ...
- 基于ffmpeg与nvidia-video-sdk-8.1.24视频硬解与软解多路rtsp,支持Qt的QOpenglWidget与qml接口显示
https://blog.csdn.net/wanghualin033/article/details/82050448 为了解决工程上的一个问题,我研究了nvidia较新的video-sdk-8.1 ...
- ffmpeg解码的软解及硬解(cuda和qsv)使用方法
对ffmpeg不是很熟悉,在使用的过程中遇到了很多坑,总结下,避免以后再遇到类似情况 版本兼容问题: 本次使用的ffmpeg版本是4.2,解码的调用方式为: int32_t iRet = -1;// ...
最新文章
- uefi怎么添加linux启动项,LINUX下EFIBOOTMGR的使用,删除UEFI主板多余启动项和添加启动项...
- android Java BASE64编码和解码一:基础
- 解决ueditor jquery javascript 取值问题
- java json乱码_Java Http请求传json数据乱码问题的解决
- 他:32岁,公司骨干技术,月薪1万,加班猝死
- 加密 CryptoJS DES
- java解析json字符串详解(两种方法)
- 引入高速缓存的目的_计算机中高速缓存的作用?
- 盘点安卓手机被吐槽最多的三大奇葩设计
- 车轱辘APP提交到各应用市场的心得~
- 苹果内购那些事儿(二)
- Ant Counting
- Unity2D:物体旋转方法
- Python中%是什么意思?如何使用?
- python二级第七套答案
- 使用Nexus搭建Maven私服、私服下载与上传
- Android 高级工程师面试(一)
- 软件开发README文档书写模板
- freebsd 启用网关
- python csv 转换 excel
热门文章
- Promise介绍和详解
- IDEA项目结构出现 0% methods,0% lines covered
- 计算机图形学期末作业
- Visual Studio+oneAPI搭建fortran环境以及部分oneAPI无法集成到Visual Studio中问题
- 描述点云配准的正太分布变换和著名的ICP点云配准原理
- agetty --noclear tty1进程不结束导致树莓派ubuntu的cpu占用率高
- C 库函数 - perror()
- LeetCode 203 移除链表元素 HERODING的LeetCode之路
- zotero文献管理软件插件配置终极教程
- 一个比较有趣的 Android 动画效果