安卓硬解码播放H264

最近在学习ing,加油硬件和软件编解码器在介绍之前,我们需要知道什么是硬编解码器和软编解码器?1.软编解码器:使用软件本身或使用CPU的方式对原始视频进行编解码。优点:兼容性好。.缺点:CPU占用率高,app内存占用较高,可能是因为CPU发

最近在学ing。开始

硬件和软件编解码器在介绍之前,我们需要知道什么是硬编解码器和软编解码器?

1.软编解码:利用软件本身或CPU对原始视频进行编解码。

优点:兼容性好。

缺点:CPU利用率高,app内存高,可能是因为CPU发热导致降频,卡顿,无法流畅录制和播放视频等。

2.硬编解码:使用非CPU编码,如显卡GPU、专用DSP芯片、厂商芯片等。一般编解码算法是固定的,所以采用芯片处理。

优点:非常快速高效,CPU占用率低,即使长时间录制高清视频,手机也不会发热。

缺点:但是兼容性不好,画面往往不够精细(但是看不出来)。

MEDIC硬编解码一般安卓直播采集终端/短视频编辑软件默认使用硬编解码,如果手机不支持软编解码。硬编解码才是王道。

AndroidMediaCodec类中使用编码和解码。军医,怎么了?MEDIC是Android音视频编解码类,通过访问底层编解码器实现编解码器的功能。比如你需要将摄像头的视频yuv数据编码为aac,h264/h265,脉码调制为aac,H264/H265解码时等待yuv,AAC解码时等待pcm。Android 4.1 API16引入了MediaCodec,Android 5.0 API21加入了异步模式。

Mediaccall是系统注册的编解码器。硬件厂商在系统中注册自己的硬编解码器,称为硬编解码器。如果硬件制造商注册了软件编解码器,它们就是软件编解码器。通常不同的硬件厂商是不一样的。然后MediaCodec负责调用。

获取手机支持的编解码器。手机支持的编解码器不同。我如何获得手机支持的编解码器?如下所示:

@RequiresApi(Build。版本代码。棒棒糖)私趣getSupportCodec(){ val list=MediaCodecList(MediaCodecList。REGULAR _ CODECS)val CODECS=list . codecinfos log . d(TAG,’ decoders : ‘)for(CODECS中的codec){ if(!Codec.isencoder) log.d (tag,codec.name)} log.d (tag,’ coder:’) for(编解码器中的编解码器){if (codec.isencoder) log.d (tag,codec.name)}} output

2020-12-25 19:16:00.914 13115-13115/com。bj。gxz。h 264解码器演示D/h 264:解码器336020-12-25 19:16:00.914 13115-13115/com。bj。gxz。h 266 19:16:00.915 13115-13115/com。bj。gxz。h 264解码器演示D/h 264: omx。他的。视频。解码器。VP 82020-12-25 19:16:00.915 13115-13115/com。bj。gxz。h 264解码器演示看一下命名,软解码器通常都是谷歌以开头的,就像上面那个一样OMX.google.h264。解码器。硬解码器是基于OMX .[硬件_供应商]一开始的,像上面那个应该是海思芯片OMX.hisi.video.decoder.avc。

当然也有一些hisi不遵循这个规则,系统会认为是软解码器。编码器的名称是相同的。规则可以通过来自Android系统的源代码来判断。源代码地址:http ://Android OS . net.cn/Android/6 . 0 . 1 _ R16/xref/Frameworks/AV/media/libstagefright/omx codec . CPP。

static bool IsSoftwareCodec(const char * component name){ if(!strncmp(‘OMX.google . ‘,componentName,11)){ return true;}如果(!strncmp(‘OMX ‘,componentName,4)) {返回false}返回true} MediaCodec处理的数据类型media codec非常强大。支持的编解码数据类型有:压缩音频数据、压缩视频数据、原始音频数据、原始视频数据,支持不同封装格式的编解码。如前所述,如果是硬解码,当然也需要手机厂商的支持。您可以通过设置表面来获取/呈现原始视频数据。MediaCodec对于API的每个方法和参数都有自己的含义。可以慢慢深入的用。

下面Android官方文档提供了MEDIC的编解码流程,官方文档非常详细。https://developer . Android . Google.cn/reference/Android/media/media codec?hl=en

MEDIC处理输入数据以生成输出数据。当异步处理数据时,它使用一组输入和输出ByteBuffer。该过程通常是

将数据填充到预设的ByteBuffer中,输入缓冲区填满数据后,传输到MediaCodec进行编解码。经过编码和解码,它将在。然后用户可以得到编码和解码后的数据,然后将ByteBuffer释放回MediaCodec,如此循环往复。需要注意的是,Buffer并不是我们自己对MediaCodec的新对象,它是MediaCodec。为了更好地控制缓冲区的处理,我们需要使用MediaCodec提供的方法来获取它,然后向其中插入数据并获取数据。

媒体编解码器的创建API Media codec CreateCodeByType/CreateCodeByType:根据具体的MIME类型(如“video/avc”)建立编解码器。解码器是解码器,编码器是编码器。CreateByCodecName:当组件的确切名称(如OMX.google.h264.decoder)已知时,它是根据组件名称编解码器创建的。如上所述,使用MediaCodecList获取组件的名称。配置:配置解码器或编码器。例如,您可以配置要在图面上显示的解码数据。本文接下来的部分是解码h264配置表面在表面渲染yuv数据的演示。开始:开始编解码,等待数据。数据处理,开始编码和解码dequeueInputBuffer:返回有效输入缓冲区的索引queueInputBuffer:输入到队列中。通常用data dequeueOutputBuffer填充:编码/解码后的数据从输出队列中取出,如果输入数据较多,可能需要循环读取。一般写代码时需要调用循环releaseOutputBuffer:释放ByteBuffer数据并返回给MediaCodecgetInputBuffers:获取需要对数据进行编解码的输入流队列,返回一个ByteBuffer ArrayGetOutputBuffers:获取编解码后的数据输出流队列,返回一个byte buffer数组flush:清空输入输出队列buffer stop:停止编解码释放:发布编解码器从上面的api中我可以看到电影MediaCodec编解码器API的生命周期,再看看官网,

MEDIC的同步和异步编解码器同步模式的官方示例

媒体编解码器=媒体编解码器。createbycodecname(名称);codec.configure(format,…);媒体格式输出格式=编解码器。获取输出格式();//选项b编解码器。start();for(;){ int input bufferid=编解码器。输入缓冲区出队(超时用户);if(输入缓冲id=0){字节缓冲输入缓冲=编解码器。getinputbuffer(…);//用有效数据填充输入缓冲器…编解码器。queueinputbuffer(输入缓冲id,…);} int output bufferid=编解码器。输出缓冲区出队(…);if(输出缓冲id=0){字节缓冲输出缓冲=编解码器。获取输出缓冲区(输出缓冲区id);媒体格式缓冲格式=编解码器。获取输出格式(输出缓冲id);//选项a//buffer performat与输出格式相同//输出缓冲区已准备好进行处理或呈现…编解码器。释放输出缓冲区(输出缓冲区id,…);} else if(输出缓冲区id==媒体编解码器.INFO_OUTPUT_FORMAT_CHANGED) { //后续数据将符合新格式。//如果使用getoutput format(output bufferid)输出格式=编解码器。getoutput format(),可以忽略;//选项B } }编解码器。stop();编解码器。发布();流程如下:

-创建和配置媒体编解码器对象-循环,直到它完成:-如果输入缓冲区在上面-读取一段输入,用输入缓冲区填充它在系统中执行编码和解码-如果输出缓冲区在上面:-从输出缓冲区获取编码和解码后的数据以进行处理。-处理后,销毁媒体编解码器对象。异步方式在安卓5.0,API21,引入异步模式。官方样品:

媒体编解码器=媒体编解码器。createbycodecname(名称);MediaFormat mOutputFormat//成员变量codec.setCallback(新媒体编解码器.callback(){ @ Override void onInputBufferAvailable(media codec MC,int input buffer id){ byte buffer input buffer=codec。getinputbuffer(输入缓冲区id);//用有效数据填充输入缓冲器…编解码器。queueinputbuffer(输入缓冲id,…);} @ Override void onOutputBufferAvailable(media codec MC,int outputBufferId,…){ byte buffer output buffer=codec。getoutputbuffer(输出缓冲区id);媒体格式缓冲格式=编解码器。获取输出格式(输出缓冲id);//选项a//buffer performat相当于mOutputFormat //outputBuffer准备处理或渲染…编解码器。释放输出缓冲区(输出缓冲区id,…);} @ Override void onOutputFormatChanged(媒体编解码器MC,媒体格式格式){ //后续数据将符合新格式。//如果使用getOutputFormat(outputBufferId)mOutputFormat=format,可以忽略;//option B } @ Override void on error(…){…} });codec.configure(format,…);mOutputFormat=编解码器。获取输出格式();//选项b编解码器。start();//等待处理完成编解码器。stop();编解码器。发布();-创建和配置媒体编解码器对象。-到媒体编解码器对象设置回调媒体编解码器.回调-保持输入缓冲可用回调:-读取一段输入,用输入缓冲区填充在系统中进行编码和解码-保持输出缓冲可用回调:-从输出缓冲区进行编码和解码后,处理数据。-处理后,销毁媒体编解码器对象。解码h264视频让我们解码视频中的一个h264(摘自抖音国际版的一段话。/葵h264文件).h265是一回事,只要了解h264.h265的编码方式和原理以及码流结构,都是小菜一碟。为了更好地理解h264的比特流数据,我们演示了一次只读取内存中的文件字节数据。

我们从两个方面来处理,都可以正常播放,只是我们对h264流数据有了更深入的了解。

就是我们做的h264比特流结构,一次一个的纳尔齐克单元(NALU)偷偷给媒体编解码器,包括第一个SPS,PPS。是的,我们只是截取几个k,然后用媒体编解码器填充它首先初始化媒体编解码器

var bytes: ByteArray?=null var媒体编解码器:媒体编解码器初始化{//演示测试,方便一次性访问内存bytes=file util。getbytes(path)//video/AVC即H264,创建解码器媒体编解码器=媒体编解码器。createdecoderbytype(‘ video/AVC ‘)val media format=media format。createvideoformat(‘ video/AVC ‘,宽度,高度)媒体格式。设置整数(媒体格式.KEY_FRAME_RATE,15)媒体编解码器。configure(媒体格式,surface,null,0) }方式一:划分纳尔齐克单元(NALU)方式

私fun decodeSplitNalu(){ if(bytes==null){ return }//数据开始订阅var start frame index=0 val totalSizeIndex=bytes!size – 1 Log.i(TAG,’ totalSize=$ totalSize index ‘)val输入缓冲区=媒体编解码器。输入缓冲区值信息=媒体编解码器.缓冲信息()while(true){//1 ms=1000 us细微索引中的值=媒体编解码器。如果(in index=0){//拆分一帧数据if(totalSizeIndex==0 | | startFrameIndex=totalSizeIndex){ log。e(TAG,’ startIndex=totalSize-1,break ‘)break } val nextframe startIndex 3360 Int=findNextFrame(bytes!startFrameIndex 1,totalSizeIndex)if(nextFrameStartIndex==-1){ log。e(标记,’ nextFrameStartIndex==-1 break ‘)break }//填入数据val byte buffer=输入缓冲区[in index]字节缓冲区。清除()字节缓冲区。放(字节!startFrameIndex、nextFrameStartIndex-startFrameIndex)媒体编解码器。队列输入缓冲区(in index,0,nextFrameStartIndex-startFrameIndex,0,0)startFrameIndex=nextFrameStartIndex } var out index=媒体编解码器。while (outIndex=0) { //这里有一个简单的时间方法可以让视频保持fps,否则视频会播放得很快H264文件的演示是30fps尝试{ sleep(33) }捕捉分割方法

私房钱findNextFrame(bytes : ByteArray,startIndex: Int,totalsizeindex : Int): Int { for(I in startIndex.totalSizeIndex){//00 00 00 01 H264 if的起始码(字节[i]).toInt()==0x00字节[i 1].toInt()==0x00字节[i 2].toInt()==0x00字节[i 3].toInt()==0x01) {//Log.e(TAG,’ bytes[I 4]=0X $ { integer。tohexstring(bytes[I 4]).toInt())}’)//Log.e(TAG,’ bytes[i 4]=${(bytes[i 4]).toInt().和(0X1F))} ‘)返回我//00 00 01 H264开始码for } else if (bytes[i]。toInt()==0x00字节[i 1].toInt()==0x00字节[i 2].toInt()==0x01) {//Log.e(TAG,’ bytes[I 3]=0X $ { integer。tohexstring(bytes[I 3]).toInt())}’)//Log.e(TAG,’ bytes[i 3]=${(bytes[i 3]).toInt().and(0X1F))} ‘)return I } } return-1 }方式一:固定字节数据填充

私房钱findNextFrameFix(bytes : ByteArray,startIndex: Int,totalSizeIndex : Int): Int {//每次都要把数据搞大一点,不然就像网络弱,数据流慢导致显卡val len=startIndex 40000返回if(len totalSizeIndex)totalSizeIndex else len }说明:在实际项目中,通常是web/数据流塞进去的方式,只是给大家演示演示媒体编解码器解码h264文件播放。

保存解码h264视频分量数据为图片我们保存在哪里呢,前面说了,解码后一定是h264保存,解码后的数据就是分量数据。也就是说出列输出缓冲区然后取出解码后的数据,然后使用YuvImageClass compressToJpegSave另存为Jpeg只是图片。我们3s保持一个。本地代码:

//3s保存一张图片如果(系统。当前时间millis()-保存图像3000){保存图像=系统。当前时间millis()val字节缓冲区:字节缓冲区=媒体编解码器。输出缓冲器[out index]字节缓冲器。位置(信息。偏移)字节缓冲区。限制(信息。偏移信息。size)val ba=字节数组(字节缓冲区。剩余())字节缓冲区。get(ba)try { val parent=File(environment。getexternal stratered irectory().absolutePath ‘/h264pic/’) if(!父母。exists()){ parent。mkdirs()日志。d(标记,’ parent=$ { parent。绝对路径} ‘)}//拍摄NV21格式图片,质量70压缩成JPEG val path=“$ { parent。绝对路径}/$ { system。当前时间毫秒()}-帧。jpg ‘日志。e(TAG,’ path : $ path ‘)val fos=文件输出流(File(path))val yuvi image=yuvi image(ba,ImageFormat .NV21,width,height,null)yuvi image。compresstojpge(Rect(0,0,yuvImage.getWidth()),yuvImage.getHeight()),80,fos)fos。flush()fos。close()} catch(e : io异常){ e . printstacktrace()} }最后,硬解码速度很快,效率很高,播放视频需要香港警察训练学校(警察训练学校的缩写)时间戳处理。演示最好的办法就是让它渲染慢一点(演示视频文件是30fps,也就是说1000毫秒/30=33毫秒一帧分量数据),所以在媒体编解码器。释放输出缓冲器(输出索引,真)休眠前(33毫秒)达到正常播放速度。

剪辑教程

sony黑砖新品(索尼nw-wm1a评测)

2022-6-25 2:00:13

剪辑教程

详细的mp4转换成mp3格式的方法(mp3音频怎么转换成mp4音频)

2022-6-25 2:02:18

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索