Android MediaCodec 解码H264码流播放
视频编解码,编的是什么码?解的又是什么码?有没有想过?现在主流的就是H264码流,Android 采集摄像头原始帧数据
这篇博客讲解的是如何从摄像头从提取YUV画面色值,然后由MediaCodec进行编码压缩,最后生成的就是H264码流,我们先了解下H264码流格式。
可以看到一个个NALU单元组成了H264码流,NALU单元又包含头数据部分和帧数据部分。
每一个头开始都包含0x 00000001或者0x000001.
我选取了上面讲的采集摄像头画面进行编码后的H264文件,打开其字节文件,码流格式数据如下
可以看到手机编码后的码流每个NAL开头起始码为0x00000001
所以我要做的工作就是提取出每一个NAL单元,然后送给MediaCodec进行解码。
提取出NAL 单元的代码函数如下
private byte[] getNALU() {try {int curpos = 0;//一般NAL不超过100000字节byte[] bb = new byte[100000];//先读取4个字节rf.read(bb, 0, 4);//判断是否是0x00000001开头if (findStartCode4(bb, 0)) {curpos = 4;} else {rf.seek(0);rf.read(bb, 0, 3);//判断是否是0x000001开头if (findStartCode3(bb, 0)) {curpos = 3;}}//标志是否找到NAL单元开头boolean findNALStartCode = false;//下一个NAL单元的开始位置int nextNalStartPos = 0;//找到适合标记开头的长度int reWind = 0;while (!findNALStartCode) {int hex = rf.read();if (curpos >= bb.length) {break;}bb[curpos++] = (byte) hex;if (hex == -1) {nextNalStartPos = curpos;}if (findStartCode4(bb, curpos - 4)) {findNALStartCode = true;reWind = 4;nextNalStartPos = curpos - reWind;} else if (findStartCode3(bb, curpos - 3)) {findNALStartCode = true;reWind = 3;nextNalStartPos = curpos - reWind;}}byte[] nal = new byte[nextNalStartPos];System.arraycopy(bb, 0, nal, 0, nextNalStartPos);long pos = rf.getFilePointer();long setPos = pos - reWind;//退回rewind长度字节rf.seek(setPos);return nal;} catch (IOException e) {e.printStackTrace();}return null;}//find match "00 00 00 01"private boolean findStartCode4(byte[] bb, int offSet) {if (offSet < 0) {return false;}if (bb[offSet] == 0 && bb[offSet + 1] == 0 && bb[offSet + 2] == 0 && bb[offSet + 3] == 1) {return true;}return false;}//find match "00 00 01"private boolean findStartCode3(byte[] bb, int offSet) {if (offSet <= 0) {return false;}if (bb[offSet] == 0 && bb[offSet + 1] == 0 && bb[offSet + 2] == 1) {return true;}return false;}
封装其数据,读取每一NAL单元
/*** 读取每一帧数据* @param buffer* @return*/public int readSampleData(ByteBuffer buffer) {byte[] nal = getNALU();buffer.put(nal);return nal.length;}
MediaCodec开启解码线程,和 Android MediaCodec,MediaExtractor解码播放MP4文件中解码一样,将NAL单元数据送给解码器即可。
/*** 解析播放H264码流*/private class DecoderH264Thread extends Thread {long pts = 0;@Overridepublic void run() {super.run();while (!isDecodeFinish) {int inputIndex = mediaCodec.dequeueInputBuffer(-1);if (inputIndex >= 0) {ByteBuffer byteBuffer = mediaCodec.getInputBuffer(inputIndex);int sampSize = DecodeH264File.getInstance().readSampleData(byteBuffer);long time = computePresentationTime();if (sampSize > 0 && time > 0) {mediaCodec.queueInputBuffer(inputIndex, 0, sampSize, time, 0);try {sleep(30);} catch (InterruptedException e) {e.printStackTrace();}}}BufferInfo bufferInfo = new BufferInfo();int outIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);if (outIndex >= 0) {mediaCodec.releaseOutputBuffer(outIndex, true);}}}}
好了,到这里结束了,有什么不明白的,欢迎留言~~
GitHub
https://github.com/zxd1991/AndroidMedia
Android MediaCodec 解码H264码流播放相关推荐
- 从原理到实践:使用Mediacodec编码H265并实现解码H265码流
H265 H265,也称为HEVC(High Efficiency Video Coding),是一种高效视频编码格式.它是H264(AVC)的后继者,也是ITU-T和ISO/IEC联合开发的标准.相 ...
- Ubuntu VLC 播放器播放本机h264码流
1:打开VLC播放器. 2:选择媒体菜单,在下拉菜单栏中,选择打开网络串流(快捷键Ctrl + N),输入:1:打开VLC播放器. 3:点击播放按钮,使得VLC播放器处于等待码流状态. 4:使用udp ...
- 【H.264/AVC视频编解码技术】第二章【H264码流分析】
H264码流分层 NAL层,视频数据网络抽象层,作用是控制二进制数据的传输,主要用于网络传输. VCL层,视频数据编码层. VCL结构关系 NALU NAL Header (1B)+ RBSP H2 ...
- H264码流打包分析(精华)
H264码流打包分析 SODB 数据比特串-->最原始的编码数据 RBSP 原始字节序列载荷-->在SODB的后面填加了结尾比特(RBSP trailing bits 一个bit" ...
- RTP协议全解(H264码流和PS流)
1 视频编码的原理 1.1 一个图像或者一个视频序列进行压缩,产生码流. 对图像的处理即是:帧内预测编码 其预测值P,是由已编码的图像做参考,经运动补偿得到的.预测图像P和当前帧Fn相减,得到两图像的 ...
- 原始 H.264 码流播放
我们平时遇到的视频文件各式各样,五花八门.通常它们会根据格式的不同,而有着不同的扩展名,比如 avi,rmvb,mkv,mp4 等等等.这些格式代表的都是 封装格式. 这些文件通常产生的过程是这样的: ...
- 将H264码流打包成RTP包
分类: 流媒体(25) 版权声明:本文为博主原创文章,未经博主允许不得转载. H264码流打包成RTP包的代码如下: [cpp] view plaincopy #include <stdio.h ...
- H264码流打包成RTP包
http://blog.csdn.net/tanningzhong/article/details/53281986 H264码流打包成RTP包的代码如下: [cpp] view plaincopy ...
- 应用角度理解H264码流
应用角度理解H264码流 前言 1.NAL 2.SPS.PPS 2.1 SPS 2.2 PPS 3.Slice&MB 3.1.Slice 3.2.MB 4.RTP负载 5.AUD 6.文献 前 ...
最新文章
- XamarinSQLite教程添加测试数据
- 前端学python有什么用-对于一个小白,前端和python哪个更适合?
- 时序预测:从两篇高影响力的论文谈起
- Java Jar包的压缩、解压使用指南
- 使用@JsonIdentityInfo的Spring自定义序列化器
- 屏幕取色工具ColorCat
- linux freemind字体,解决 ubuntu 18.04 lts freemind 或freeplane 乱码口口的问题
- tkinter GUI 客户端页面编程 登录注册案例开发
- WPS Excel表格安装宏插件
- 从百草园到三味书屋 鲁迅
- lisp 圆柱螺旋线_Visual LISP开发三维圆柱螺旋线程序
- 变量、函数、类等编程时常用英文命名和缩写
- 网上作业c语言第三章,c语言 第3章 作业 和部分答案.doc
- 评论式软文怎么写?学会这三招,让你轻松营造出客观的感觉
- M1001 4G/5G应急指挥箱
- Phonetic symbol 双元音 -- əʊ
- 退烧方法及退烧药的选择
- GEE 提取长系列NDVI像元值
- 精益生产制造的三要素,了解一下
- Packet_Tracer
热门文章
- 廖雪峰介绍Node.js
- 开启灯光就是近光吗_科目三考前必看!夜间灯光语音模拟+超全项目操作
- 成为百万富翁的25种方法
- 马斯克加入推特董事会引发员工担忧:可能改变审查规则
- iPhone 14 Pro渲染图曝光 网友:冲这个外观就可以买了
- 神州12号航天员确定:住110米“大平层” 有120种美食
- 金山办公:因个人原因 葛珂辞去公司董事长职务
- 天齐锂业高管减持后定增160亿 收到深交所关注函
- 头条搜索“美丽中国”,你为哪处风景胜地打过Call?
- 华为Mate 40系列或采用双处理器方案:国行版仍为麒麟芯