功能点
- 从连续的字节块中,解析分割出多个H264帧数据
- 通过MediaCodec解码H264帧
- 通过SurfaceView播放
代码
//H264数据解析
package com.easing.commons.android.MediaCodec.format;
public class H264Format {
//从流数据中查找H264的header
public static int findH264Header(byte[] buffer, int length) {
//两个header之间的字节,即为一帧的数据
//因此我们实际是跳过第一个header,查找第二个header的位置
final int firsetOffset = 512;
for (int index = firsetOffset; index {
//循环播放H264文件
WorkThread.postByLoop(() -> {
final InputStream is = Resources.readAssetStream("abc.h264");
final int maxFrameSize = 1024 * 1024; //大小要足够放下两帧以上的数据
byte[] buffer = new byte[128 * 1024]; //读文件的缓存区
byte[] frameBuffer = new byte[maxFrameSize]; //帧数据的缓存区
int availableDataLength = 0; //FrameBuffer实际帧数据的长度
//读文件,按帧解码
//区分帧数据边界的逻辑是,两个H264.Header之间的字节即为一帧
int length = 0;
while (true) {
//读取文件
length = is.read(buffer);
if (length maxFrameSize)
availableDataLength = 0;
//接着之前的位置,填充数据到缓存区
System.arraycopy(buffer, 0, frameBuffer, availableDataLength, length);
availableDataLength = availableDataLength + length;
//查找第二个H264.Header
int offset = H264Format.findH264Header(frameBuffer, availableDataLength);
//递归查找所有的帧
while (offset > 0) {
//FrameBuffer以H264.Header开头,则表示数据正常,否则表示数据异常
boolean startWithH264Header = H264Format.isH264Header(frameBuffer, 0);
//数据正常
if (startWithH264Header) {
//解码帧数据
boolean decodeResult = h264PlayView1.decodeFrame(frameBuffer, 0, offset);
//解码成功
if (decodeResult) {
//移除第二个Header之前的字节
byte[] temp = frameBuffer;
frameBuffer = new byte[maxFrameSize];
System.arraycopy(temp, offset, frameBuffer, 0, availableDataLength - offset);
availableDataLength = availableDataLength - offset;
//查找下个头
offset = H264Format.findH264Header(frameBuffer, availableDataLength);
}
}
//数据异常
else {
//移除第二个Header之前的字节
byte[] temp = frameBuffer;
frameBuffer = new byte[maxFrameSize];
System.arraycopy(temp, offset, frameBuffer, 0, availableDataLength - offset);
availableDataLength = availableDataLength - offset;
//查找下个头
offset = H264Format.findH264Header(frameBuffer, availableDataLength);
}
}
}
});
});
源码
Android H264数据解帧和播放.zip