unsigned H264VideoStreamParser::parse() {
try {
3: //
//首先找到起始符号,并跳过。文件流的最开始必需以0x00000001开始,但后续的NALU充许以0x000001(3 bytes)作为分隔
5: 6: // The stream must start with a 0x00000001:
7: if (!fHaveSeenFirstStartCode) {
8: // Skip over any input bytes that precede the first 0x00000001:
9: u_int32_t first4Bytes;
while ((first4Bytes = test4Bytes()) != 0x00000001) {
11: get1Byte(); setParseState(); // ensures that we progress over bad data
12: }
13: skipBytes(4); // skip this initial code
14:
15: setParseState();
16: fHaveSeenFirstStartCode = True; // from now on
17: }
//将起始标志也保存到目的缓冲区中
if (fOutputStartCodeSize > 0) {
22: // Include a start code in the output:
23: save4Bytes(0x00000001);
24: }
25:
26: 27: //保存所有数据,直至遇到起始标志,或者文件结束符。需要注意NALU中的第一个字节,因为它指示了NALU的类型
28: 29: // Then save everything up until the next 0x00000001 (4 bytes) or 0x000001 (3 bytes),or we hit EOF.
30: // Also make note of the first byte,because it contains the "nal_unit_type":
31: u_int8_t firstByte;
32: if (haveSeenEOF()) {
33: 34: //已经设置了文件结束标志,将剩下的数据保存也来即可
35: 36: // We hit EOF the last time that we tried to parse this data,monospace; font-size:12px"> 37: // so we know that the remaining unparsed data forms a complete NAL unit:
38: unsigned remainingDataSize = totNumValidBytes() - curOffset();
39: if (remainingDataSize == 0) (void)get1Byte(); // forces another read,which will cause EOF to get handled for real this time
40: #ifdef DEBUG
41: fprintf(stderr,"This NAL unit (%d bytes) ends with EOFn",remainingDataSize);
42: #endif
43: if (remainingDataSize == 0) return 0;
44: firstByte = get1Byte(); //将第一个字节保存下来,其指示了NALU的类型
45: saveByte(firstByte);
46:
47: while (--remainingDataSize > 0) {
48: saveByte(get1Byte());
49: }
50: } else {
51: u_int32_t next4Bytes = test4Bytes();
52: firstByte = next4Bytes>>24; //将第一个字节保存下来
53: 54: //将下一个起始符号之前的数据都保存下来
55: 56: while (next4Bytes != 0x00000001 && (next4Bytes&0xFFFFFF00) != 0x00000100) {
57: // We save at least some of "next4Bytes".
58: if ((unsigned)(next4Bytes&0xFF) > 1) { //一次可以保存4个字节,并不需要一个一个字节对比,除非到了结尾
59: // Common case: 0x00000001 or 0x000001 definitely doesn't begin anywhere in "next4Bytes",so we save all of it:
60: save4Bytes(next4Bytes);
61: skipBytes(4);
62: } // Save the first byte,and continue testing the rest:
64: saveByte(next4Bytes>>24);
65: skipBytes(1);
66: }
67: next4Bytes = test4Bytes();
68: }
69: // Assert: next4Bytes starts with 0x00000001 or 0x000001,and we've saved all previous bytes (forming a complete NAL unit).
70: // Skip over these remaining bytes,up until the start of the next NAL unit:
if (next4Bytes == 0x00000001) {
72: skipBytes(4);
73: } 74: skipBytes(3);
75: }
76: }
77:
78: u_int8_t nal_ref_idc = (firstByte&0x60)>>5;
79: u_int8_t nal_unit_type = firstByte&0x1F;
80: #ifdef DEBUG
81: fprintf(stderr,0)">Parsed %d-byte NAL-unit (nal_ref_idc: %d,nal_unit_type: %d ("%s"))n",monospace; font-size:12px"> 82: curFrameSize()-fOutputStartCodeSize,nal_ref_idc,nal_unit_type,nal_unit_type_description[nal_unit_type]);
83: #endif
84:
85:
86: 87: //下面根据NALU的类型来作具体的分析
89: switch (nal_unit_type) {
90: case 6: { // Supplemental enhancement information (SEI)
91: analyze_sei_data();
92: // Later,perhaps adjust "fPresentationTime" if we saw a "pic_timing" SEI payload??? #####
break;
94: }
95: case 7: { // Sequence parameter set (序列参数集)
96: 97: //保存一份SPS的副本到H264VideoStreamFramer中,后面的pps也需要保存,sps中可能还包含了帧率信息
98: 99: // First,save a copy of this NAL unit,in case the downstream object wants to see it:
100: usingSource()->saveCopyOfSPS(fStartOfFrame + fOutputStartCodeSize,fTo - fStartOfFrame - fOutputStartCodeSize);
101:
102:
103: // Parse this NAL unit to check whether frame rate information is present:
104: unsigned num_units_in_tick,time_scale,fixed_frame_rate_flag;
105: analyze_seq_parameter_set_data(num_units_in_tick,fixed_frame_rate_flag);
106: if (time_scale > 0 && num_units_in_tick > 0) {
107: usingSource()->fFrameRate = time_scale/(2.0*num_units_in_tick); //sps中包含了帧率信息
108: #ifdef DEBUG
109: fprintf(stderr,0)">Set frame rate to %f fpsn",usingSource()->fFrameRate);
110: if (fixed_frame_rate_flag == 0) {
111: fprintf(stderr,0)">tWARNING: "fixed_frame_rate_flag" was not setn");
112: }
113: #endif
114: } else { //sps中不包含帧率信息,则使用source中设置的默认帧率
115: #ifdef DEBUG
116: fprintf(stderr,0)">tThis "Sequence Parameter Set" NAL unit contained no frame rate information,so we use a default frame rate of %f fpsn",monospace; font-size:12px">117: #endif
118: }
119: 120: }
121: case 8: { // Picture parameter set (图像参数集PPS)
122: // Save a copy of this NAL unit,monospace; font-size:12px">123: usingSource()->saveCopyOfPPS(fStartOfFrame + fOutputStartCodeSize,monospace; font-size:12px">124: }
125: }
126:
127: usingSource()->setPresentationTime(); //设置当前的时间
128: #ifdef DEBUG
129: unsigned long secs = (long)usingSource()->fPresentationTime.tv_sec;
130: unsigned uSecs = (unsigned)usingSource()->fPresentationTime.tv_usec;
131: fprintf(stderr,0)">tPresentation time: %lu.%06un",secs,uSecs);
132: #endif
133:
134: 135: //如果这个NALU是一个VCL NALU(即包含的是视频数据),我们需要扫描下一个NALU的起始符,
136: //以判断这个NALU是否是当前的"access unit"(这个"access unit"应该可以理解为一帧图像帧吧)。
137: //我们需要根据这个信息去指明何时该增加"fPresentationTime"(RTP 打包时也需要根据这个信息,决定是否设置"M"位)。
138: 139: // If this NAL unit is a VCL NAL unit,we also scan the start of the next NAL unit,to determine whether this NAL unit
140: // ends the current 'access unit'. We need this information to figure out when to increment "fPresentationTime".
141: // (RTP streamers also need to know this in order to figure out whether or not to set the "M" bit.)
142: Boolean thisNALUnitEndsAccessUnit = False; // until we learn otherwise
143: 144: // There is no next NAL unit,so we assume that this one ends the current 'access unit':
145: thisNALUnitEndsAccessUnit = True;
146: } 147: Boolean const isVCL = nal_unit_type <= 5 && nal_unit_type > 0; // Would need to include type 20 for SVC and MVC #####
148: if (isVCL) {
149: u_int32_t first4BytesOfNextNALUnit = test4Bytes();
150: u_int8_t firstByteOfNextNALUnit = first4BytesOfNextNALUnit>>24;
151: u_int8_t next_nal_ref_idc = (firstByteOfNextNALUnit&0x60)>>5;
152: u_int8_t next_nal_unit_type = firstByteOfNextNALUnit&0x1F;
153: if (next_nal_unit_type >= 6) {
154: //下一个NALU不是VCL的,当前的"access unit"结束了
155: // The next NAL unit is not a VCL; therefore,we assume that this NAL unit ends the current 'access unit':
156: #ifdef DEBUG
157: fprintf(stderr,0)">t(The next NAL unit is not a VCL)n");
158: #endif
159: thisNALUnitEndsAccessUnit = True;
160: } 161: //下一个NALU也是VCL的,还需要检查一下它们是不是属于同一个"access unit"
162: // The next NAL unit is also a VLC. We need to examine it a little to figure out if it's a different 'access unit'.
163: // (We use many of the criteria described in section 7.4.1.2.4 of the H.264 specification.)
164: Boolean IdrPicFlag = nal_unit_type == 5;
165: Boolean next_IdrPicFlag = next_nal_unit_type == 5;
166: if (next_IdrPicFlag != IdrPicFlag) {
167: // IdrPicFlag differs in value
168: #ifdef DEBUG
169: fprintf(stderr,0)">t(IdrPicFlag differs in value)n");
170: #endif
171: thisNALUnitEndsAccessUnit = True;
172: } else if (next_nal_ref_idc != nal_ref_idc && next_nal_ref_idc*nal_ref_idc == 0) {
173: // nal_ref_idc differs in value with one of the nal_ref_idc values being equal to 0
174: #ifdef DEBUG
175: fprintf(stderr,0)">t(nal_ref_idc differs in value with one of the nal_ref_idc values being equal to 0)n");
176: #endif
177: thisNALUnitEndsAccessUnit = True;
178: } if ((nal_unit_type == 1 || nal_unit_type == 2 || nal_unit_type == 5)
179: && (next_nal_unit_type == 1 || next_nal_unit_type == 2 || next_nal_unit_type == 5)) {
180: // Both this and the next NAL units begin with a "slice_header".
181: // Parse this (for each),to get parameters that we can compare:
182:
183: // Current NAL unit's "slice_header":
184: unsigned frame_num,pic_parameter_set_id,idr_pic_id;
185: Boolean field_pic_flag,bottom_field_flag;
186: analyze_slice_header(fStartOfFrame + fOutputStartCodeSize,fTo,monospace; font-size:12px">187: frame_num,idr_pic_id,field_pic_flag,bottom_field_flag);
188:
189: // Next NAL unit's "slice_header":
190: #ifdef DEBUG
191: fprintf(stderr,0)"> Next NAL unit's slice_header:n");
192: #endif
193: u_int8_t next_slice_header[NUM_NEXT_SLICE_HEADER_BYTES_TO_ANALYZE];
194: testBytes(next_slice_header,255)">sizeof next_slice_header);
195: unsigned next_frame_num,next_pic_parameter_set_id,next_idr_pic_id;
196: Boolean next_field_pic_flag,next_bottom_field_flag;
197: analyze_slice_header(next_slice_header,&next_slice_header[sizeof next_slice_header],next_nal_unit_type,monospace; font-size:12px">198: next_frame_num,next_idr_pic_id,next_field_pic_flag,next_bottom_field_flag);
199:
200: if (next_frame_num != frame_num) {
201: // frame_num differs in value
202: #ifdef DEBUG
203: fprintf(stderr,0)">t(frame_num differs in value)n");
204: #endif
205: thisNALUnitEndsAccessUnit = True;
206: } if (next_pic_parameter_set_id != pic_parameter_set_id) {
207: // pic_parameter_set_id differs in value
208: #ifdef DEBUG
209: fprintf(stderr,0)">t(pic_parameter_set_id differs in value)n");
210: #endif
211: thisNALUnitEndsAccessUnit = True;
212: } if (next_field_pic_flag != field_pic_flag) {
213: // field_pic_flag differs in value
214: #ifdef DEBUG
215: fprintf(stderr,0)">t(field_pic_flag differs in value)n");
216: #endif
217: thisNALUnitEndsAccessUnit = True;
218: } if (next_bottom_field_flag != bottom_field_flag) {
219: // bottom_field_flag differs in value
220: #ifdef DEBUG
221: fprintf(stderr,0)">t(bottom_field_flag differs in value)n");
222: #endif
223: thisNALUnitEndsAccessUnit = True;
224: } if (next_IdrPicFlag == 1 && next_idr_pic_id != idr_pic_id) {
225: // IdrPicFlag is equal to 1 for both and idr_pic_id differs in value
226: // Note: We already know that IdrPicFlag is the same for both.
227: #ifdef DEBUG
228: fprintf(stderr,0)">t(IdrPicFlag is equal to 1 for both and idr_pic_id differs in value)n");
229: #endif
230: thisNALUnitEndsAccessUnit = True;
231: }
232: }
233: }
234: }
235: }
236:
237: if (thisNALUnitEndsAccessUnit) {
238: #ifdef DEBUG
239: fprintf(stderr,0)">*****This NAL unit ends the current access unit*****n");
240: #endif
241: usingSource()->fPictureEndMarker = True; //这里就是设置RTP打包时用到的M标志了
242: ++usingSource()->fPictureCount;
243:
244:
245: 246: //下一个NALU不再属于当前"access unit""时,才改变时间
247: 248: // Note that the presentation time for the next NAL unit will be different:
249: struct timeval& nextPT = usingSource()->fNextPresentationTime; // alias 这里是引用
250: nextPT = usingSource()->fPresentationTime;
251: double nextFraction = nextPT.tv_usec/1000000.0 + 1/usingSource()->fFrameRate;
252: unsigned nextSecsIncrement = (long)nextFraction;
253: nextPT.tv_sec += (long)nextSecsIncrement;
254: nextPT.tv_usec = (long)((nextFraction - nextSecsIncrement)*1000000);
255: }
256: setParseState();
257:
258:
259: return curFrameSize();
260: } catch (int /*e*/) {
261: #ifdef DEBUG
262: fprintf(stderr,0)">H264VideoStreamParser::parse() EXCEPTION (This is normal behavior - *not* an error)n");
263: #endif
264: return 0; // the parsing got interrupted
265: }
266: }