视音频数据处理入门:H.264视频码流解析(java)

版权声明:版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_41054313/article/details/88841234

参考文献 : 视音频数据处理入门:H.264视频码流解析

测试文件:H264文件

链接:https://pan.baidu.com/s/1eRTJwTsXTgHf2Ez8Inab1A 
提取码:1c7q 

原理

H.264原始码流(又称为“裸流”)是由一个一个的NALU组成的。他们的结构如下图所示。

其中每个NALU之间通过startcode(起始码)进行分隔,起始码分成两种:0x000001(3Byte)或者0x00000001(4Byte)。如果NALU对应的Slice为一帧的开始就用0x00000001,否则就用0x000001。
H.264码流解析的步骤就是首先从码流中搜索0x000001和0x00000001,分离出NALU;然后再分析NALU的各个字段。本文的程序即实现了上述的两个步骤。
 

代码

import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;

public class Test {
	//NALU结构
	static class NALU
	{
		  int startcodeprefix_len;      //! 4 for parameter sets and first slice in picture, 3 for everything else (suggested)
		  int len;                 		//! Length of the NAL unit (Excluding the start code, which does not belong to the NALU)
		  int max_size;           		//! Nal Unit Buffer size
		  int forbidden_bit;            //! should be always FALSE
		  int nal_reference_idc;        //! NALU_PRIORITY_xxxx
		  int nal_unit_type;            //! NALU_TYPE_xxxx    
		@Override
		public String toString() {
			return "NALU [len=" + len + ", forbidden_bit=" + forbidden_bit + ", nal_reference_idc=" + nal_reference_idc
					+ ", nal_unit_type=" + nal_unit_type + "]";
		}
		  
		  
	}
	
	
	private static RandomAccessFile in;
	private static List<NALU> list = new ArrayList<NALU>();
	private static List<Long> NALUIndexs = new ArrayList<>() ;
	
	public static void main(String[] args) throws Exception {
		String fileName = "F:/testFile/video/vid.h264";
		if(args.length>0) {
			fileName = args[0];
		}
		in = new RandomAccessFile(fileName, "r");
		parseIndexs();
		System.out.println(NALUIndexs);
		getNALU();
		System.out.println(list);
		in.close();
	}
	
	public static int parseNALU() throws IOException {
		int head = in.readInt();
		if(head==1) {//0x00000001?
			return 4;
		}else if(head>>1 == 1) {//0x000001?
			in.seek(in.getFilePointer()-1);
			return 3;
		}
		return -1;
	}
	
	/*
	 * 获取每一帧NALU 并存入集合
	 */
	public static void getNALU() throws IOException, InterruptedException {
		
		for(int i=0;i<NALUIndexs.size();i++) {
			NALU n = new NALU();
			if(i!=NALUIndexs.size()-1) {
				n.len = (int) (NALUIndexs.get(i+1)-NALUIndexs.get(i));
			}else {
				n.len = (int) (in.length() - NALUIndexs.get(i));
			}
			in.seek(NALUIndexs.get(i));
			int head = in.read();
			n.forbidden_bit = head >> 7 & 1;
			n.nal_reference_idc = head >> 5 & 3;
			n.nal_unit_type = head & 0x1f;
			list.add(n);
		}
		
		
	}
	/*
	 * 获取所有NAUL的起始位置
	 */
	public static void parseIndexs() throws IOException {
		while(true) {
			if(parseNALU()>0) {
				NALUIndexs.add(in.getFilePointer());
			}
			if(in.getFilePointer()==in.length()) {
				break;
			}
			in.seek(in.getFilePointer()-4);
			in.readByte();
		}
	}

}

结果: 

猜你喜欢

转载自blog.csdn.net/qq_41054313/article/details/88841234