視音頻數據處理入門:H.264視頻碼流解析(java)

參考文獻 : 視音頻數據處理入門: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();
		}
	}

}

結果: 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章