1 | /********** |
2 | This library is free software; you can redistribute it and/or modify it under |
3 | the terms of the GNU Lesser General Public License as published by the |
4 | Free Software Foundation; either version 3 of the License, or (at your |
5 | option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.) |
6 | |
7 | This library is distributed in the hope that it will be useful, but WITHOUT |
8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
9 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for |
10 | more details. |
11 | |
12 | You should have received a copy of the GNU Lesser General Public License |
13 | along with this library; if not, write to the Free Software Foundation, Inc., |
14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
15 | **********/ |
16 | // "liveMedia" |
17 | // Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved. |
18 | // A parser for an Ogg file. |
19 | // Implementation |
20 | |
21 | #include "OggFileParser.hh" |
22 | #include "OggDemuxedTrack.hh" |
23 | #include <GroupsockHelper.hh> // for "gettimeofday() |
24 | |
25 | PacketSizeTable::PacketSizeTable(unsigned number_page_segments) |
26 | : numCompletedPackets(0), totSizes(0), nextPacketNumToDeliver(0), |
27 | lastPacketIsIncomplete(False) { |
28 | size = new unsigned[number_page_segments]; |
29 | for (unsigned i = 0; i < number_page_segments; ++i) size[i] = 0; |
30 | } |
31 | |
32 | PacketSizeTable::~PacketSizeTable() { |
33 | delete[] size; |
34 | } |
35 | |
36 | OggFileParser::OggFileParser(OggFile& ourFile, FramedSource* inputSource, |
37 | FramedSource::onCloseFunc* onEndFunc, void* onEndClientData, |
38 | OggDemux* ourDemux) |
39 | : StreamParser(inputSource, onEndFunc, onEndClientData, continueParsing, this), |
40 | fOurFile(ourFile), fInputSource(inputSource), |
41 | fOnEndFunc(onEndFunc), fOnEndClientData(onEndClientData), |
42 | fOurDemux(ourDemux), fNumUnfulfilledTracks(0), |
43 | fPacketSizeTable(NULL), fCurrentTrackNumber(0), fSavedPacket(NULL) { |
44 | if (ourDemux == NULL) { |
45 | // Initialization |
46 | fCurrentParseState = PARSING_START_OF_FILE; |
47 | continueParsing(); |
48 | } else { |
49 | fCurrentParseState = PARSING_AND_DELIVERING_PAGES; |
50 | // In this case, parsing (of page data) doesn't start until a client starts reading from a track. |
51 | } |
52 | } |
53 | |
54 | OggFileParser::~OggFileParser() { |
55 | delete[] fSavedPacket; |
56 | delete fPacketSizeTable; |
57 | Medium::close(fInputSource); |
58 | } |
59 | |
60 | void OggFileParser::continueParsing(void* clientData, unsigned char* ptr, unsigned size, struct timeval presentationTime) { |
61 | ((OggFileParser*)clientData)->continueParsing(); |
62 | } |
63 | |
64 | void OggFileParser::continueParsing() { |
65 | if (fInputSource != NULL) { |
66 | if (fInputSource->isCurrentlyAwaitingData()) return; |
67 | // Our input source is currently being read. Wait until that read completes |
68 | |
69 | if (!parse()) { |
70 | // We didn't complete the parsing, because we had to read more data from the source, |
71 | // or because we're waiting for another read from downstream. |
72 | // Once that happens, we'll get called again. |
73 | return; |
74 | } |
75 | } |
76 | |
77 | // We successfully parsed the file. Call our 'done' function now: |
78 | if (fOnEndFunc != NULL) (*fOnEndFunc)(fOnEndClientData); |
79 | } |
80 | |
81 | Boolean OggFileParser::parse() { |
82 | try { |
83 | while (1) { |
84 | switch (fCurrentParseState) { |
85 | case PARSING_START_OF_FILE: { |
86 | if (parseStartOfFile()) return True; |
87 | } |
88 | case PARSING_AND_DELIVERING_PAGES: { |
89 | parseAndDeliverPages(); |
90 | } |
91 | case DELIVERING_PACKET_WITHIN_PAGE: { |
92 | if (deliverPacketWithinPage()) return False; |
93 | } |
94 | } |
95 | } |
96 | } catch (int /*e*/) { |
97 | #ifdef DEBUG |
98 | fprintf(stderr, "OggFileParser::parse() EXCEPTION (This is normal behavior - *not* an error)\n" ); |
99 | #endif |
100 | return False; // the parsing got interrupted |
101 | } |
102 | } |
103 | |
104 | Boolean OggFileParser::parseStartOfFile() { |
105 | #ifdef DEBUG |
106 | fprintf(stderr, "parsing start of file\n" ); |
107 | #endif |
108 | // Read and parse each 'page', until we see the first non-BOS page, or until we have |
109 | // collected all required headers for Vorbis, Theora, or Opus track(s) (if any). |
110 | u_int8_t ; |
111 | do { |
112 | header_type_flag = parseInitialPage(); |
113 | } while ((header_type_flag&0x02) != 0 || needHeaders()); |
114 | |
115 | #ifdef DEBUG |
116 | fprintf(stderr, "Finished parsing start of file\n" ); |
117 | #endif |
118 | return True; |
119 | } |
120 | |
121 | static u_int32_t byteSwap(u_int32_t x) { |
122 | return (x<<24)|((x<<8)&0x00FF0000)|((x>>8)&0x0000FF00)|(x>>24); |
123 | } |
124 | |
125 | u_int8_t OggFileParser::parseInitialPage() { |
126 | u_int8_t ; |
127 | u_int32_t bitstream_serial_number; |
128 | parseStartOfPage(header_type_flag, bitstream_serial_number); |
129 | |
130 | // If this is a BOS page, examine the first 8 bytes of the first 'packet', to see whether |
131 | // the track data type is one that we know how to stream: |
132 | OggTrack* track; |
133 | if ((header_type_flag&0x02) != 0) { // BOS |
134 | char const* mimeType = NULL; // if unknown |
135 | if (fPacketSizeTable != NULL && fPacketSizeTable->size[0] >= 8) { // sanity check |
136 | char buf[8]; |
137 | testBytes((u_int8_t*)buf, 8); |
138 | |
139 | if (strncmp(&buf[1], "vorbis" , 6) == 0) { |
140 | mimeType = "audio/VORBIS" ; |
141 | ++fNumUnfulfilledTracks; |
142 | } else if (strncmp(buf, "OpusHead" , 8) == 0) { |
143 | mimeType = "audio/OPUS" ; |
144 | ++fNumUnfulfilledTracks; |
145 | } else if (strncmp(&buf[1], "theora" , 6) == 0) { |
146 | mimeType = "video/THEORA" ; |
147 | ++fNumUnfulfilledTracks; |
148 | } |
149 | } |
150 | |
151 | // Add a new track descriptor for this track: |
152 | track = new OggTrack; |
153 | track->trackNumber = bitstream_serial_number; |
154 | track->mimeType = mimeType; |
155 | fOurFile.addTrack(track); |
156 | } else { // not a BOS page |
157 | // Because this is not a BOS page, the specified track should already have been seen: |
158 | track = fOurFile.lookup(bitstream_serial_number); |
159 | } |
160 | |
161 | if (track != NULL) { // sanity check |
162 | #ifdef DEBUG |
163 | fprintf(stderr, "This track's MIME type: %s\n" , |
164 | track->mimeType == NULL ? "(unknown)" : track->mimeType); |
165 | #endif |
166 | if (track->mimeType != NULL && |
167 | (strcmp(track->mimeType, "audio/VORBIS" ) == 0 || |
168 | strcmp(track->mimeType, "video/THEORA" ) == 0 || |
169 | strcmp(track->mimeType, "audio/OPUS" ) == 0)) { |
170 | // Special-case handling of Vorbis, Theora, or Opus tracks: |
171 | // Make a copy of each packet, until we get the three special headers that we need: |
172 | Boolean isVorbis = strcmp(track->mimeType, "audio/VORBIS" ) == 0; |
173 | Boolean isTheora = strcmp(track->mimeType, "video/THEORA" ) == 0; |
174 | |
175 | for (unsigned j = 0; j < fPacketSizeTable->numCompletedPackets && track->weNeedHeaders(); ++j) { |
176 | unsigned const packetSize = fPacketSizeTable->size[j]; |
177 | if (packetSize == 0) continue; // sanity check |
178 | |
179 | delete[] fSavedPacket/*if any*/; fSavedPacket = new u_int8_t[packetSize]; |
180 | getBytes(fSavedPacket, packetSize); |
181 | fPacketSizeTable->totSizes -= packetSize; |
182 | |
183 | // The start of the packet tells us whether its a header that we know about: |
184 | Boolean = False; |
185 | unsigned index = 0; |
186 | if (isVorbis) { |
187 | u_int8_t const firstByte = fSavedPacket[0]; |
188 | |
189 | headerIsKnown = firstByte == 1 || firstByte == 3 || firstByte == 5; |
190 | index = (firstByte-1)/2; // 1, 3, or 5 => 0, 1, or 2 |
191 | } else if (isTheora) { |
192 | u_int8_t const firstByte = fSavedPacket[0]; |
193 | |
194 | headerIsKnown = firstByte == 0x80 || firstByte == 0x81 || firstByte == 0x82; |
195 | index = firstByte &~0x80; // 0x80, 0x81, or 0x82 => 0, 1, or 2 |
196 | } else { // Opus |
197 | if (strncmp((char const*)fSavedPacket, "OpusHead" , 8) == 0) { |
198 | headerIsKnown = True; |
199 | index = 0; // "identification" header |
200 | } else if (strncmp((char const*)fSavedPacket, "OpusTags" , 8) == 0) { |
201 | headerIsKnown = True; |
202 | index = 1; // "comment" header |
203 | } |
204 | } |
205 | if (headerIsKnown) { |
206 | #ifdef DEBUG |
207 | char const* headerName[3] = { "identification" , "comment" , "setup" }; |
208 | fprintf(stderr, "Saved %d-byte %s \"%s\" header\n" , packetSize, track->mimeType, |
209 | headerName[index]); |
210 | #endif |
211 | // This is a header, but first check it for validity: |
212 | if (!validateHeader(track, fSavedPacket, packetSize)) continue; |
213 | |
214 | // Save this header (deleting any old header of the same type that we'd saved before) |
215 | delete[] track->vtoHdrs.header[index]; |
216 | track->vtoHdrs.header[index] = fSavedPacket; |
217 | fSavedPacket = NULL; |
218 | track->vtoHdrs.headerSize[index] = packetSize; |
219 | |
220 | if (!track->weNeedHeaders()) { |
221 | // We now have all of the needed Vorbis, Theora, or Opus headers for this track: |
222 | --fNumUnfulfilledTracks; |
223 | } |
224 | // Note: The above code won't work if a required header is fragmented over |
225 | // more than one 'page'. We assume that that won't ever happen... |
226 | } |
227 | } |
228 | } |
229 | } |
230 | |
231 | // Skip over any remaining packet data bytes: |
232 | if (fPacketSizeTable->totSizes > 0) { |
233 | #ifdef DEBUG |
234 | fprintf(stderr, "Skipping %d remaining packet data bytes\n" , fPacketSizeTable->totSizes); |
235 | #endif |
236 | skipBytes(fPacketSizeTable->totSizes); |
237 | } |
238 | |
239 | return header_type_flag; |
240 | } |
241 | |
242 | // A simple bit vector class for reading bits in little-endian order. |
243 | // (We can't use our usual "BitVector" class, because that's big-endian.) |
244 | class LEBitVector { |
245 | public: |
246 | LEBitVector(u_int8_t const* p, unsigned numBytes) |
247 | : fPtr(p), fEnd(&p[numBytes]), fNumBitsRemainingInCurrentByte(8) { |
248 | } |
249 | |
250 | u_int32_t getBits(unsigned numBits/*<=32*/) { |
251 | if (noMoreBits()) { |
252 | return 0; |
253 | } else if (numBits == fNumBitsRemainingInCurrentByte) { |
254 | u_int32_t result = (*fPtr++)>>(8-fNumBitsRemainingInCurrentByte); |
255 | fNumBitsRemainingInCurrentByte = 8; |
256 | |
257 | return result; |
258 | } else if (numBits < fNumBitsRemainingInCurrentByte) { |
259 | u_int8_t mask = 0xFF>>(8-numBits); |
260 | u_int32_t result = ((*fPtr)>>(8-fNumBitsRemainingInCurrentByte)) & mask; |
261 | fNumBitsRemainingInCurrentByte -= numBits; |
262 | |
263 | return result; |
264 | } else { // numBits > fNumBitsRemainingInCurrentByte |
265 | // Do two recursive calls to get the result: |
266 | unsigned nbr = fNumBitsRemainingInCurrentByte; |
267 | u_int32_t firstBits = getBits(nbr); |
268 | u_int32_t nextBits = getBits(numBits - nbr); |
269 | |
270 | return (nextBits<<nbr) | firstBits; |
271 | } |
272 | } |
273 | |
274 | void skipBits(unsigned numBits) { |
275 | while (numBits > 32) { |
276 | (void)getBits(32); |
277 | numBits -= 32; |
278 | } |
279 | (void)getBits(numBits); |
280 | } |
281 | |
282 | unsigned numBitsRemaining() { return (fEnd-fPtr-1)*8 + fNumBitsRemainingInCurrentByte; } |
283 | Boolean noMoreBits() const { return fPtr >= fEnd; } |
284 | |
285 | private: |
286 | u_int8_t const* fPtr; |
287 | u_int8_t const* fEnd; |
288 | unsigned fNumBitsRemainingInCurrentByte; // 1..8 |
289 | }; |
290 | |
291 | static unsigned ilog(int n) { |
292 | if (n < 0) return 0; |
293 | |
294 | unsigned x = (unsigned)n; |
295 | unsigned result = 0; |
296 | |
297 | while (x > 0) { |
298 | ++result; |
299 | x >>= 1; |
300 | } |
301 | |
302 | return result; |
303 | } |
304 | |
305 | static unsigned lookup1_values(unsigned codebook_entries, unsigned codebook_dimensions) { |
306 | // "the greatest integer value for which [return_value] to the power of [codebook_dimensions] |
307 | // is less than or equal to [codebook_entries]" |
308 | unsigned return_value = 0; |
309 | unsigned powerValue; |
310 | |
311 | do { |
312 | ++return_value; |
313 | // Compute powerValue = return_value ** codebook_dimensions |
314 | if (return_value == 1) powerValue = 1; // optimization |
315 | else { |
316 | powerValue = 1; |
317 | for (unsigned i = 0; i < codebook_dimensions; ++i) { |
318 | powerValue *= return_value; |
319 | } |
320 | } |
321 | } while (powerValue <= codebook_entries); |
322 | return_value -= 1; |
323 | |
324 | return return_value; |
325 | } |
326 | |
327 | static Boolean parseVorbisSetup_codebook(LEBitVector& bv) { |
328 | if (bv.noMoreBits()) return False; |
329 | |
330 | unsigned sync = bv.getBits(24); |
331 | if (sync != 0x564342) return False; |
332 | unsigned codebook_dimensions = bv.getBits(16); |
333 | unsigned codebook_entries = bv.getBits(24); |
334 | unsigned ordered = bv.getBits(1); |
335 | #ifdef DEBUG_SETUP_HEADER |
336 | fprintf(stderr, "\t\t\tcodebook_dimensions: %d; codebook_entries: %d, ordered: %d\n" , |
337 | codebook_dimensions, codebook_entries, ordered); |
338 | #endif |
339 | if (!ordered) { |
340 | unsigned sparse = bv.getBits(1); |
341 | #ifdef DEBUG_SETUP_HEADER |
342 | fprintf(stderr, "\t\t\t!ordered: sparse %d\n" , sparse); |
343 | #endif |
344 | for (unsigned i = 0; i < codebook_entries; ++i) { |
345 | unsigned codewordLength; |
346 | |
347 | if (sparse) { |
348 | unsigned flag = bv.getBits(1); |
349 | if (flag) { |
350 | codewordLength = bv.getBits(5) + 1; |
351 | } else { |
352 | codewordLength = 0; |
353 | } |
354 | } else { |
355 | codewordLength = bv.getBits(5) + 1; |
356 | } |
357 | #ifdef DEBUG_SETUP_HEADER |
358 | fprintf(stderr, "\t\t\t\tcodeword length[%d]:\t%d\n" , i, codewordLength); |
359 | #else |
360 | codewordLength = codewordLength; // to prevent compiler warning |
361 | #endif |
362 | } |
363 | } else { // ordered |
364 | #ifdef DEBUG_SETUP_HEADER |
365 | fprintf(stderr, "\t\t\tordered:\n" ); |
366 | #endif |
367 | unsigned current_entry = 0; |
368 | unsigned current_length = bv.getBits(5) + 1; |
369 | do { |
370 | unsigned number = bv.getBits(ilog(codebook_entries - current_entry)); |
371 | #ifdef DEBUG_SETUP_HEADER |
372 | fprintf(stderr, "\t\t\t\tcodeword length[%d..%d]:\t%d\n" , |
373 | current_entry, current_entry + number - 1, current_length); |
374 | #endif |
375 | current_entry += number; |
376 | if (current_entry > codebook_entries) { |
377 | fprintf(stderr, "Vorbis codebook parsing error: current_entry %d > codebook_entries %d!\n" , current_entry, codebook_entries); |
378 | return False; |
379 | } |
380 | ++current_length; |
381 | } while (current_entry < codebook_entries); |
382 | } |
383 | |
384 | unsigned codebook_lookup_type = bv.getBits(4); |
385 | #ifdef DEBUG_SETUP_HEADER |
386 | fprintf(stderr, "\t\t\tcodebook_lookup_type: %d\n" , codebook_lookup_type); |
387 | #endif |
388 | if (codebook_lookup_type > 2) { |
389 | fprintf(stderr, "Vorbis codebook parsing error: codebook_lookup_type %d!\n" , codebook_lookup_type); |
390 | return False; |
391 | } else if (codebook_lookup_type > 0) { // 1 or 2 |
392 | bv.skipBits(32+32); // "codebook_minimum_value" and "codebook_delta_value" |
393 | unsigned codebook_value_bits = bv.getBits(4) + 1; |
394 | bv.skipBits(1); // "codebook_lookup_p" |
395 | unsigned codebook_lookup_values; |
396 | if (codebook_lookup_type == 1) { |
397 | codebook_lookup_values = lookup1_values(codebook_entries, codebook_dimensions); |
398 | } else { // 2 |
399 | codebook_lookup_values = codebook_entries*codebook_dimensions; |
400 | } |
401 | |
402 | bv.skipBits(codebook_lookup_values*codebook_value_bits); // "codebook_multiplicands" |
403 | } |
404 | |
405 | return True; |
406 | } |
407 | |
408 | static Boolean parseVorbisSetup_codebooks(LEBitVector& bv) { |
409 | if (bv.noMoreBits()) return False; |
410 | |
411 | unsigned vorbis_codebook_count = bv.getBits(8) + 1; |
412 | #ifdef DEBUG_SETUP_HEADER |
413 | fprintf(stderr, "\tCodebooks: vorbis_codebook_count: %d\n" , vorbis_codebook_count); |
414 | #endif |
415 | for (unsigned i = 0; i < vorbis_codebook_count; ++i) { |
416 | #ifdef DEBUG_SETUP_HEADER |
417 | fprintf(stderr, "\t\tCodebook %d:\n" , i); |
418 | #endif |
419 | if (!parseVorbisSetup_codebook(bv)) return False; |
420 | } |
421 | |
422 | return True; |
423 | } |
424 | |
425 | static Boolean parseVorbisSetup_timeDomainTransforms(LEBitVector& bv) { |
426 | if (bv.noMoreBits()) return False; |
427 | |
428 | unsigned vorbis_time_count = bv.getBits(6) + 1; |
429 | #ifdef DEBUG_SETUP_HEADER |
430 | fprintf(stderr, "\tTime domain transforms: vorbis_time_count: %d\n" , vorbis_time_count); |
431 | #endif |
432 | for (unsigned i = 0; i < vorbis_time_count; ++i) { |
433 | unsigned val = bv.getBits(16); |
434 | if (val != 0) { |
435 | fprintf(stderr, "Vorbis Time domain transforms, read non-zero value %d\n" , val); |
436 | return False; |
437 | } |
438 | } |
439 | |
440 | return True; |
441 | } |
442 | |
443 | static Boolean parseVorbisSetup_floors(LEBitVector& bv) { |
444 | if (bv.noMoreBits()) return False; |
445 | |
446 | unsigned vorbis_floor_count = bv.getBits(6) + 1; |
447 | #ifdef DEBUG_SETUP_HEADER |
448 | fprintf(stderr, "\tFloors: vorbis_floor_count: %d\n" , vorbis_floor_count); |
449 | #endif |
450 | for (unsigned i = 0; i < vorbis_floor_count; ++i) { |
451 | unsigned floorType = bv.getBits(16); |
452 | if (floorType == 0) { |
453 | bv.skipBits(8+16+16+6+8); |
454 | unsigned floor0_number_of_books = bv.getBits(4) + 1; |
455 | bv.skipBits(floor0_number_of_books*8); |
456 | } else if (floorType == 1) { |
457 | unsigned floor1_partitions = bv.getBits(5); |
458 | |
459 | unsigned* floor1_partition_class_list = new unsigned[floor1_partitions]; |
460 | unsigned maximum_class = 0, j; |
461 | for (j = 0; j < floor1_partitions; ++j) { |
462 | floor1_partition_class_list[j] = bv.getBits(4); |
463 | if (floor1_partition_class_list[j] > maximum_class) maximum_class = floor1_partition_class_list[j]; |
464 | } |
465 | |
466 | unsigned* floor1_class_dimensions = new unsigned[maximum_class + 1]; |
467 | for (j = 0; j <= maximum_class; ++j) { |
468 | floor1_class_dimensions[j] = bv.getBits(3) + 1; |
469 | unsigned floor1_class_subclasses = bv.getBits(2); |
470 | if (floor1_class_subclasses != 0) { |
471 | bv.skipBits(8); // "floor1_class_masterbooks[j]" |
472 | } |
473 | |
474 | unsigned twoExp_floor1_class_subclasses = 1 << floor1_class_subclasses; |
475 | bv.skipBits(twoExp_floor1_class_subclasses*8); // "floor1_subclass_books[j][*]" |
476 | } |
477 | |
478 | bv.skipBits(2); // "floor1_multiplier" |
479 | unsigned rangebits = bv.getBits(4); |
480 | for (j = 0; j < floor1_partitions; ++j) { |
481 | unsigned current_class_number = floor1_partition_class_list[j]; |
482 | bv.skipBits(floor1_class_dimensions[current_class_number] * rangebits); |
483 | } |
484 | |
485 | delete[] floor1_partition_class_list; |
486 | delete[] floor1_class_dimensions; |
487 | } else { // floorType > 1 |
488 | fprintf(stderr, "Vorbis Floors, read bad floor type %d\n" , floorType); |
489 | return False; |
490 | } |
491 | } |
492 | |
493 | return True; |
494 | } |
495 | |
496 | static Boolean parseVorbisSetup_residues(LEBitVector& bv) { |
497 | if (bv.noMoreBits()) return False; |
498 | |
499 | unsigned vorbis_residue_count = bv.getBits(6) + 1; |
500 | #ifdef DEBUG_SETUP_HEADER |
501 | fprintf(stderr, "\tResidues: vorbis_residue_count: %d\n" , vorbis_residue_count); |
502 | #endif |
503 | for (unsigned i = 0; i < vorbis_residue_count; ++i) { |
504 | unsigned vorbis_residue_type = bv.getBits(16); |
505 | if (vorbis_residue_type > 2) { |
506 | fprintf(stderr, "Vorbis Residues, read bad vorbis_residue_type: %d\n" , vorbis_residue_type); |
507 | return False; |
508 | } else { |
509 | bv.skipBits(24+24+24); // "residue_begin", "residue_end", "residue_partition_size" |
510 | unsigned residue_classifications = bv.getBits(6) + 1; |
511 | bv.skipBits(8); // "residue_classbook" |
512 | |
513 | u_int8_t* residue_cascade = new u_int8_t[residue_classifications]; |
514 | unsigned j; |
515 | for (j = 0; j < residue_classifications; ++j) { |
516 | u_int8_t high_bits = 0; |
517 | u_int8_t low_bits = bv.getBits(3); |
518 | unsigned bitflag = bv.getBits(1); |
519 | if (bitflag) { |
520 | high_bits = bv.getBits(5); |
521 | } |
522 | |
523 | residue_cascade[j] = (high_bits<<3) | low_bits; |
524 | } |
525 | |
526 | for (j = 0; j < residue_classifications; ++j) { |
527 | u_int8_t const cascade = residue_cascade[j]; |
528 | u_int8_t mask = 0x80; |
529 | while (mask != 0) { |
530 | if ((cascade&mask) != 0) bv.skipBits(8); // "residue_books[j][*]" |
531 | mask >>= 1; |
532 | } |
533 | } |
534 | |
535 | delete[] residue_cascade; |
536 | } |
537 | } |
538 | |
539 | return True; |
540 | } |
541 | |
542 | static Boolean parseVorbisSetup_mappings(LEBitVector& bv, unsigned audio_channels) { |
543 | if (bv.noMoreBits()) return False; |
544 | |
545 | unsigned vorbis_mapping_count = bv.getBits(6) + 1; |
546 | #ifdef DEBUG_SETUP_HEADER |
547 | fprintf(stderr, "\tMappings: vorbis_mapping_count: %d\n" , vorbis_mapping_count); |
548 | #endif |
549 | for (unsigned i = 0; i < vorbis_mapping_count; ++i) { |
550 | unsigned vorbis_mapping_type = bv.getBits(16); |
551 | if (vorbis_mapping_type != 0) { |
552 | fprintf(stderr, "Vorbis Mappings, read bad vorbis_mapping_type: %d\n" , vorbis_mapping_type); |
553 | return False; |
554 | } |
555 | |
556 | unsigned vorbis_mapping_submaps = 1; |
557 | if (bv.getBits(1)) vorbis_mapping_submaps = bv.getBits(4) + 1; |
558 | |
559 | if (bv.getBits(1)) { // "square polar channel mapping is in use" |
560 | unsigned vorbis_mapping_coupling_steps = bv.getBits(8) + 1; |
561 | |
562 | for (unsigned j = 0; j < vorbis_mapping_coupling_steps; ++j) { |
563 | unsigned ilog_audio_channels_minus_1 = ilog(audio_channels - 1); |
564 | bv.skipBits(2*ilog_audio_channels_minus_1); // "vorbis_mapping_magnitude", "vorbis_mapping_angle" |
565 | } |
566 | } |
567 | |
568 | unsigned reserved = bv.getBits(2); |
569 | if (reserved != 0) { |
570 | fprintf(stderr, "Vorbis Mappings, read bad 'reserved' field\n" ); |
571 | return False; |
572 | } |
573 | |
574 | if (vorbis_mapping_submaps > 1) { |
575 | for (unsigned j = 0; j < audio_channels; ++j) { |
576 | unsigned vorbis_mapping_mux = bv.getBits(4); |
577 | |
578 | fprintf(stderr, "\t\t\t\tvorbis_mapping_mux[%d]: %d\n" , j, vorbis_mapping_mux); |
579 | if (vorbis_mapping_mux >= vorbis_mapping_submaps) { |
580 | fprintf(stderr, "Vorbis Mappings, read bad \"vorbis_mapping_mux\" %d (>= \"vorbis_mapping_submaps\" %d)\n" , vorbis_mapping_mux, vorbis_mapping_submaps); |
581 | return False; |
582 | } |
583 | } |
584 | } |
585 | |
586 | bv.skipBits(vorbis_mapping_submaps*(8+8+8)); // "the floor and residue numbers" |
587 | } |
588 | |
589 | return True; |
590 | } |
591 | |
592 | static Boolean parseVorbisSetup_modes(LEBitVector& bv, OggTrack* track) { |
593 | if (bv.noMoreBits()) return False; |
594 | |
595 | unsigned vorbis_mode_count = bv.getBits(6) + 1; |
596 | unsigned ilog_vorbis_mode_count_minus_1 = ilog(vorbis_mode_count - 1); |
597 | #ifdef DEBUG_SETUP_HEADER |
598 | fprintf(stderr, "\tModes: vorbis_mode_count: %d (ilog(%d-1):%d)\n" , |
599 | vorbis_mode_count, vorbis_mode_count, ilog_vorbis_mode_count_minus_1); |
600 | #endif |
601 | track->vtoHdrs.vorbis_mode_count = vorbis_mode_count; |
602 | track->vtoHdrs.ilog_vorbis_mode_count_minus_1 = ilog_vorbis_mode_count_minus_1; |
603 | track->vtoHdrs.vorbis_mode_blockflag = new u_int8_t[vorbis_mode_count]; |
604 | |
605 | for (unsigned i = 0; i < vorbis_mode_count; ++i) { |
606 | track->vtoHdrs.vorbis_mode_blockflag[i] = (u_int8_t)bv.getBits(1); |
607 | #ifdef DEBUG_SETUP_HEADER |
608 | fprintf(stderr, "\t\tMode %d: vorbis_mode_blockflag: %d\n" , i, track->vtoHdrs.vorbis_mode_blockflag[i]); |
609 | #endif |
610 | bv.skipBits(16+16+8); // "vorbis_mode_windowtype", "vorbis_mode_transformtype", "vorbis_mode_mapping" |
611 | } |
612 | |
613 | return True; |
614 | } |
615 | |
616 | static Boolean (OggTrack* track, u_int8_t const* p, unsigned ) { |
617 | LEBitVector bv(p, headerSize); |
618 | do { |
619 | if (!parseVorbisSetup_codebooks(bv)) break; |
620 | if (!parseVorbisSetup_timeDomainTransforms(bv)) break; |
621 | if (!parseVorbisSetup_floors(bv)) break; |
622 | if (!parseVorbisSetup_residues(bv)) break; |
623 | if (!parseVorbisSetup_mappings(bv, track->numChannels)) break; |
624 | if (!parseVorbisSetup_modes(bv, track)) break; |
625 | unsigned framingFlag = bv.getBits(1); |
626 | if (framingFlag == 0) { |
627 | fprintf(stderr, "Vorbis \"setup\" header did not end with a 'framing flag'!\n" ); |
628 | break; |
629 | } |
630 | |
631 | return True; |
632 | } while (0); |
633 | |
634 | // An error occurred: |
635 | return False; |
636 | } |
637 | |
638 | #ifdef DEBUG |
639 | #define CHECK_PTR if (p >= pEnd) return False |
640 | #define printComment(p, len) do { for (unsigned k = 0; k < len; ++k) { CHECK_PTR; fprintf(stderr, "%c", *p++); } } while (0) |
641 | #endif |
642 | |
643 | static Boolean (u_int8_t const *p, unsigned , |
644 | unsigned isOpus = 0) { |
645 | if (headerSize < 15+isOpus) { // need 7+isOpus + 4(vendor_length) + 4(user_comment_list_length) |
646 | fprintf(stderr, "\"comment\" header is too short (%d bytes)\n" , headerSize); |
647 | return False; |
648 | } |
649 | |
650 | #ifdef DEBUG |
651 | u_int8_t const* pEnd = &p[headerSize]; |
652 | p += 7+isOpus; |
653 | |
654 | u_int32_t vendor_length = (p[3]<<24)|(p[2]<<16)|(p[1]<<8)|p[0]; p += 4; |
655 | fprintf(stderr, "\tvendor_string:" ); |
656 | printComment(p, vendor_length); |
657 | fprintf(stderr, "\n" ); |
658 | |
659 | u_int32_t user_comment_list_length = (p[3]<<24)|(p[2]<<16)|(p[1]<<8)|p[0]; p += 4; |
660 | for (unsigned i = 0; i < user_comment_list_length; ++i) { |
661 | CHECK_PTR; u_int32_t length = (p[3]<<24)|(p[2]<<16)|(p[1]<<8)|p[0]; p += 4; |
662 | fprintf(stderr, "\tuser_comment[%d]:" , i); |
663 | printComment(p, length); |
664 | fprintf(stderr, "\n" ); |
665 | } |
666 | #endif |
667 | |
668 | return True; |
669 | } |
670 | |
671 | static unsigned blocksizeFromExponent(unsigned exponent) { |
672 | unsigned result = 1; |
673 | for (unsigned i = 0; i < exponent; ++i) result = 2*result; |
674 | return result; |
675 | } |
676 | |
677 | Boolean OggFileParser::(OggTrack* track, u_int8_t const* p, unsigned ) { |
678 | // Assert: headerSize >= 7 (because we've already checked "<packet_type>XXXXXX" or "OpusXXXX") |
679 | if (strcmp(track->mimeType, "audio/VORBIS" ) == 0) { |
680 | u_int8_t const firstByte = p[0]; |
681 | |
682 | if (firstByte == 1) { // "identification" header |
683 | if (headerSize < 30) { |
684 | fprintf(stderr, "Vorbis \"identification\" header is too short (%d bytes)\n" , headerSize); |
685 | return False; |
686 | } else if ((p[29]&0x1) != 1) { |
687 | fprintf(stderr, "Vorbis \"identification\" header: 'framing_flag' is not set\n" ); |
688 | return False; |
689 | } |
690 | |
691 | p += 7; |
692 | u_int32_t vorbis_version = (p[3]<<24)|(p[2]<<16)|(p[1]<<8)|p[0]; p += 4; |
693 | if (vorbis_version != 0) { |
694 | fprintf(stderr, "Vorbis \"identification\" header has a bad 'vorbis_version': 0x%08x\n" , vorbis_version); |
695 | return False; |
696 | } |
697 | |
698 | u_int8_t audio_channels = *p++; |
699 | if (audio_channels == 0) { |
700 | fprintf(stderr, "Vorbis \"identification\" header: 'audio_channels' is 0!\n" ); |
701 | return False; |
702 | } |
703 | track->numChannels = audio_channels; |
704 | |
705 | u_int32_t audio_sample_rate = (p[3]<<24)|(p[2]<<16)|(p[1]<<8)|p[0]; p += 4; |
706 | if (audio_sample_rate == 0) { |
707 | fprintf(stderr, "Vorbis \"identification\" header: 'audio_sample_rate' is 0!\n" ); |
708 | return False; |
709 | } |
710 | track->samplingFrequency = audio_sample_rate; |
711 | |
712 | p += 4; // skip over 'bitrate_maximum' |
713 | u_int32_t bitrate_nominal = (p[3]<<24)|(p[2]<<16)|(p[1]<<8)|p[0]; p += 4; |
714 | if (bitrate_nominal > 0) track->estBitrate = (bitrate_nominal+500)/1000; // round |
715 | |
716 | p += 4; // skip over 'bitrate_maximum' |
717 | |
718 | // Note the two 'block sizes' (samples per packet), and their durations in microseconds: |
719 | u_int8_t blocksizeBits = *p++; |
720 | unsigned& blocksize_0 = track->vtoHdrs.blocksize[0]; // alias |
721 | unsigned& blocksize_1 = track->vtoHdrs.blocksize[1]; // alias |
722 | blocksize_0 = blocksizeFromExponent(blocksizeBits&0x0F); |
723 | blocksize_1 = blocksizeFromExponent(blocksizeBits>>4); |
724 | |
725 | double uSecsPerSample = 1000000.0/(track->samplingFrequency*2); |
726 | // Why the "2"? I don't know, but it seems to be necessary |
727 | track->vtoHdrs.uSecsPerPacket[0] = (unsigned)(uSecsPerSample*blocksize_0); |
728 | track->vtoHdrs.uSecsPerPacket[1] = (unsigned)(uSecsPerSample*blocksize_1); |
729 | #ifdef DEBUG |
730 | fprintf(stderr, "\t%u Hz, %u-channel, %u kbps (est), block sizes: %u,%u (%u,%u us)\n" , |
731 | track->samplingFrequency, track->numChannels, track->estBitrate, |
732 | blocksize_0, blocksize_1, |
733 | track->vtoHdrs.uSecsPerPacket[0], track->vtoHdrs.uSecsPerPacket[1]); |
734 | #endif |
735 | // To be valid, "blocksize_0" must be <= "blocksize_1", and both must be in [64,8192]: |
736 | if (!(blocksize_0 <= blocksize_1 && blocksize_0 >= 64 && blocksize_1 <= 8192)) { |
737 | fprintf(stderr, "Invalid Vorbis \"blocksize_0\" (%d) and/or \"blocksize_1\" (%d)!\n" , |
738 | blocksize_0, blocksize_1); |
739 | return False; |
740 | } |
741 | } else if (firstByte == 3) { // "comment" header |
742 | if (!validateCommentHeader(p, headerSize)) return False; |
743 | } else if (firstByte == 5) { // "setup" header |
744 | // Parse the "setup" header to get the values that we want: |
745 | // "vorbis_mode_count", and "vorbis_mode_blockflag" for each mode. Unfortunately these come |
746 | // near the end of the header, so we have to parse lots of other crap first. |
747 | p += 7; |
748 | if (!parseVorbisSetupHeader(track, p, headerSize)) { |
749 | fprintf(stderr, "Failed to parse Vorbis \"setup\" header!\n" ); |
750 | return False; |
751 | } |
752 | } |
753 | } else if (strcmp(track->mimeType, "video/THEORA" ) == 0) { |
754 | u_int8_t const firstByte = p[0]; |
755 | |
756 | if (firstByte == 0x80) { // "identification" header |
757 | if (headerSize < 42) { |
758 | fprintf(stderr, "Theora \"identification\" header is too short (%d bytes)\n" , headerSize); |
759 | return False; |
760 | } else if ((p[41]&0x7) != 0) { |
761 | fprintf(stderr, "Theora \"identification\" header: 'res' bits are non-zero\n" ); |
762 | return False; |
763 | } |
764 | |
765 | track->vtoHdrs.KFGSHIFT = ((p[40]&3)<<3) | (p[41]>>5); |
766 | u_int32_t FRN = (p[22]<<24) | (p[23]<<16) | (p[24]<<8) | p[25]; // Frame rate numerator |
767 | u_int32_t FRD = (p[26]<<24) | (p[27]<<16) | (p[28]<<8) | p[29]; // Frame rate numerator |
768 | #ifdef DEBUG |
769 | fprintf(stderr, "\tKFGSHIFT %d, Frame rate numerator %d, Frame rate denominator %d\n" , track->vtoHdrs.KFGSHIFT, FRN, FRD); |
770 | #endif |
771 | if (FRN == 0 || FRD == 0) { |
772 | fprintf(stderr, "Theora \"identification\" header: Bad FRN and/or FRD values: %d, %d\n" , FRN, FRD); |
773 | return False; |
774 | } |
775 | track->vtoHdrs.uSecsPerFrame = (unsigned)((1000000.0*FRD)/FRN); |
776 | #ifdef DEBUG |
777 | fprintf(stderr, "\t\t=> %u microseconds per frame\n" , track->vtoHdrs.uSecsPerFrame); |
778 | #endif |
779 | } else if (firstByte == 0x81) { // "comment" header |
780 | if (!validateCommentHeader(p, headerSize)) return False; |
781 | } else if (firstByte == 0x82) { // "setup" header |
782 | // We don't care about the contents of the Theora "setup" header; just assume it's valid |
783 | } |
784 | } else { // Opus audio |
785 | if (strncmp((char const*)p, "OpusHead" , 8) == 0) { // "identification" header |
786 | // Just check the size, and the 'major' number of the version byte: |
787 | if (headerSize < 19 || (p[8]&0xF0) != 0) return False; |
788 | } else { // comment header |
789 | if (!validateCommentHeader(p, headerSize, 1/*isOpus*/)) return False; |
790 | } |
791 | } |
792 | |
793 | return True; |
794 | } |
795 | |
796 | void OggFileParser::parseAndDeliverPages() { |
797 | #ifdef DEBUG |
798 | fprintf(stderr, "parsing and delivering data\n" ); |
799 | #endif |
800 | while (parseAndDeliverPage()) {} |
801 | } |
802 | |
803 | Boolean OggFileParser::parseAndDeliverPage() { |
804 | u_int8_t ; |
805 | u_int32_t bitstream_serial_number; |
806 | parseStartOfPage(header_type_flag, bitstream_serial_number); |
807 | |
808 | OggDemuxedTrack* demuxedTrack = fOurDemux->lookupDemuxedTrack(bitstream_serial_number); |
809 | if (demuxedTrack == NULL) { // this track is not being read |
810 | #ifdef DEBUG |
811 | fprintf(stderr, "\tIgnoring page from unread track; skipping %d remaining packet data bytes\n" , |
812 | fPacketSizeTable->totSizes); |
813 | #endif |
814 | skipBytes(fPacketSizeTable->totSizes); |
815 | return True; |
816 | } else if (fPacketSizeTable->totSizes == 0) { |
817 | // This page is empty (has no packets). Skip it and continue |
818 | #ifdef DEBUG |
819 | fprintf(stderr, "\t[track: %s] Skipping empty page\n" , demuxedTrack->MIMEtype()); |
820 | #endif |
821 | return True; |
822 | } |
823 | |
824 | // Start delivering packets next: |
825 | demuxedTrack->fCurrentPageIsContinuation = (header_type_flag&0x01) != 0; |
826 | fCurrentTrackNumber = bitstream_serial_number; |
827 | fCurrentParseState = DELIVERING_PACKET_WITHIN_PAGE; |
828 | saveParserState(); |
829 | return False; |
830 | } |
831 | |
832 | Boolean OggFileParser::deliverPacketWithinPage() { |
833 | OggDemuxedTrack* demuxedTrack = fOurDemux->lookupDemuxedTrack(fCurrentTrackNumber); |
834 | if (demuxedTrack == NULL) return False; // should not happen |
835 | |
836 | unsigned packetNum = fPacketSizeTable->nextPacketNumToDeliver; |
837 | unsigned packetSize = fPacketSizeTable->size[packetNum]; |
838 | |
839 | if (!demuxedTrack->isCurrentlyAwaitingData()) { |
840 | // Someone has been reading this stream, but isn't right now. |
841 | // We can't deliver this frame until he asks for it, so punt for now. |
842 | // The next time he asks for a frame, he'll get it. |
843 | #ifdef DEBUG |
844 | fprintf(stderr, "\t[track: %s] Deferring delivery of packet %d (%d bytes%s)\n" , |
845 | demuxedTrack->MIMEtype(), packetNum, packetSize, |
846 | packetNum == fPacketSizeTable->numCompletedPackets ? " (incomplete)" : "" ); |
847 | #endif |
848 | return True; |
849 | } |
850 | |
851 | // Deliver the next packet: |
852 | #ifdef DEBUG |
853 | fprintf(stderr, "\t[track: %s] Delivering packet %d (%d bytes%s)\n" , demuxedTrack->MIMEtype(), |
854 | packetNum, packetSize, |
855 | packetNum == fPacketSizeTable->numCompletedPackets ? " (incomplete)" : "" ); |
856 | #endif |
857 | unsigned numBytesDelivered |
858 | = packetSize < demuxedTrack->maxSize() ? packetSize : demuxedTrack->maxSize(); |
859 | getBytes(demuxedTrack->to(), numBytesDelivered); |
860 | u_int8_t firstByte = numBytesDelivered > 0 ? demuxedTrack->to()[0] : 0x00; |
861 | u_int8_t secondByte = numBytesDelivered > 1 ? demuxedTrack->to()[1] : 0x00; |
862 | demuxedTrack->to() += numBytesDelivered; |
863 | |
864 | if (demuxedTrack->fCurrentPageIsContinuation) { // the previous page's read was incomplete |
865 | demuxedTrack->frameSize() += numBytesDelivered; |
866 | } else { |
867 | // This is the first delivery for this "doGetNextFrame()" call. |
868 | demuxedTrack->frameSize() = numBytesDelivered; |
869 | } |
870 | if (packetSize > demuxedTrack->maxSize()) { |
871 | demuxedTrack->numTruncatedBytes() += packetSize - demuxedTrack->maxSize(); |
872 | } |
873 | demuxedTrack->maxSize() -= numBytesDelivered; |
874 | |
875 | // Figure out the duration and presentation time of this frame. |
876 | unsigned durationInMicroseconds; |
877 | OggTrack* track = fOurFile.lookup(demuxedTrack->fOurTrackNumber); |
878 | |
879 | if (strcmp(track->mimeType, "audio/VORBIS" ) == 0) { |
880 | if ((firstByte&0x01) != 0) { // This is a header packet |
881 | durationInMicroseconds = 0; |
882 | } else { // This is a data packet. |
883 | // Parse the first byte to figure out its duration. |
884 | // Extract the next "track->vtoHdrs.ilog_vorbis_mode_count_minus_1" bits of the first byte: |
885 | u_int8_t const mask = 0xFE<<(track->vtoHdrs.ilog_vorbis_mode_count_minus_1); |
886 | u_int8_t const modeNumber = (firstByte&~mask)>>1; |
887 | if (modeNumber >= track->vtoHdrs.vorbis_mode_count) { |
888 | fprintf(stderr, "Error: Bad mode number %d (>= vorbis_mode_count %d) in Vorbis packet!\n" , |
889 | modeNumber, track->vtoHdrs.vorbis_mode_count); |
890 | durationInMicroseconds = 0; |
891 | } else { |
892 | unsigned blockNumber = track->vtoHdrs.vorbis_mode_blockflag[modeNumber]; |
893 | durationInMicroseconds = track->vtoHdrs.uSecsPerPacket[blockNumber]; |
894 | } |
895 | } |
896 | } else if (strcmp(track->mimeType, "video/THEORA" ) == 0) { |
897 | if ((firstByte&0x80) != 0) { // This is a header packet |
898 | durationInMicroseconds = 0; |
899 | } else { // This is a data packet. |
900 | durationInMicroseconds = track->vtoHdrs.uSecsPerFrame; |
901 | } |
902 | } else { // "audio/OPUS" |
903 | if (firstByte == 0x4F/*'O'*/ && secondByte == 0x70/*'p*/) { // This is a header packet |
904 | durationInMicroseconds = 0; |
905 | } else { // This is a data packet. |
906 | // Parse the first byte to figure out the duration of each frame, and then (if necessary) |
907 | // parse the second byte to figure out how many frames are in this packet: |
908 | u_int8_t config = firstByte >> 3; |
909 | u_int8_t c = firstByte & 0x03; |
910 | unsigned const configDuration[32] = { // in microseconds |
911 | 10000, 20000, 40000, 60000, // config 0..3 |
912 | 10000, 20000, 40000, 60000, // config 4..7 |
913 | 10000, 20000, 40000, 60000, // config 8..11 |
914 | 10000, 20000, // config 12..13 |
915 | 10000, 20000, // config 14..15 |
916 | 2500, 5000, 10000, 20000, // config 16..19 |
917 | 2500, 5000, 10000, 20000, // config 20..23 |
918 | 2500, 5000, 10000, 20000, // config 24..27 |
919 | 2500, 5000, 10000, 20000 // config 28..31 |
920 | }; |
921 | unsigned const numFramesInPacket = c == 0 ? 1 : c == 3 ? (secondByte&0x3F) : 2; |
922 | durationInMicroseconds = numFramesInPacket*configDuration[config]; |
923 | } |
924 | } |
925 | |
926 | if (demuxedTrack->nextPresentationTime().tv_sec == 0 && demuxedTrack->nextPresentationTime().tv_usec == 0) { |
927 | // This is the first delivery. Initialize "demuxedTrack->nextPresentationTime()": |
928 | gettimeofday(&demuxedTrack->nextPresentationTime(), NULL); |
929 | } |
930 | demuxedTrack->presentationTime() = demuxedTrack->nextPresentationTime(); |
931 | demuxedTrack->durationInMicroseconds() = durationInMicroseconds; |
932 | |
933 | demuxedTrack->nextPresentationTime().tv_usec += durationInMicroseconds; |
934 | while (demuxedTrack->nextPresentationTime().tv_usec >= 1000000) { |
935 | ++demuxedTrack->nextPresentationTime().tv_sec; |
936 | demuxedTrack->nextPresentationTime().tv_usec -= 1000000; |
937 | } |
938 | saveParserState(); |
939 | |
940 | // And check whether there's a next packet in this page: |
941 | if (packetNum == fPacketSizeTable->numCompletedPackets) { |
942 | // This delivery was for an incomplete packet, at the end of the page. |
943 | // Return without completing delivery: |
944 | fCurrentParseState = PARSING_AND_DELIVERING_PAGES; |
945 | return False; |
946 | } |
947 | |
948 | if (packetNum < fPacketSizeTable->numCompletedPackets-1 |
949 | || fPacketSizeTable->lastPacketIsIncomplete) { |
950 | // There is at least one more packet (possibly incomplete) left in this packet. |
951 | // Deliver it next: |
952 | ++fPacketSizeTable->nextPacketNumToDeliver; |
953 | } else { |
954 | // Start parsing a new page next: |
955 | fCurrentParseState = PARSING_AND_DELIVERING_PAGES; |
956 | } |
957 | |
958 | FramedSource::afterGetting(demuxedTrack); // completes delivery |
959 | return True; |
960 | } |
961 | |
962 | void OggFileParser::parseStartOfPage(u_int8_t& , |
963 | u_int32_t& bitstream_serial_number) { |
964 | saveParserState(); |
965 | // First, make sure we start with the 'capture_pattern': 0x4F676753 ('OggS'): |
966 | while (test4Bytes() != 0x4F676753) { |
967 | skipBytes(1); |
968 | saveParserState(); // ensures forward progress through the file |
969 | } |
970 | skipBytes(4); |
971 | #ifdef DEBUG |
972 | fprintf(stderr, "\nSaw Ogg page header:\n" ); |
973 | #endif |
974 | |
975 | u_int8_t stream_structure_version = get1Byte(); |
976 | if (stream_structure_version != 0) { |
977 | fprintf(stderr, "Saw page with unknown Ogg file version number: 0x%02x\n" , stream_structure_version); |
978 | } |
979 | |
980 | header_type_flag = get1Byte(); |
981 | #ifdef DEBUG |
982 | fprintf(stderr, "\theader_type_flag: 0x%02x (" , header_type_flag); |
983 | if (header_type_flag&0x01) fprintf(stderr, "continuation " ); |
984 | if (header_type_flag&0x02) fprintf(stderr, "bos " ); |
985 | if (header_type_flag&0x04) fprintf(stderr, "eos " ); |
986 | fprintf(stderr, ")\n" ); |
987 | #endif |
988 | |
989 | u_int32_t granule_position1 = byteSwap(get4Bytes()); |
990 | u_int32_t granule_position2 = byteSwap(get4Bytes()); |
991 | bitstream_serial_number = byteSwap(get4Bytes()); |
992 | u_int32_t page_sequence_number = byteSwap(get4Bytes()); |
993 | u_int32_t CRC_checksum = byteSwap(get4Bytes()); |
994 | u_int8_t number_page_segments = get1Byte(); |
995 | #ifdef DEBUG |
996 | fprintf(stderr, "\tgranule_position 0x%08x%08x, bitstream_serial_number 0x%08x, page_sequence_number 0x%08x, CRC_checksum 0x%08x, number_page_segments %d\n" , granule_position2, granule_position1, bitstream_serial_number, page_sequence_number, CRC_checksum, number_page_segments); |
997 | #else |
998 | // Dummy statements to prevent 'unused variable' compiler warnings: |
999 | #define DUMMY_STATEMENT(x) do {x = x;} while (0) |
1000 | DUMMY_STATEMENT(granule_position1); |
1001 | DUMMY_STATEMENT(granule_position2); |
1002 | DUMMY_STATEMENT(page_sequence_number); |
1003 | DUMMY_STATEMENT(CRC_checksum); |
1004 | #endif |
1005 | |
1006 | // Look at the "segment_table" to count the sizes of the packets in this page: |
1007 | delete fPacketSizeTable/*if any*/; fPacketSizeTable = new PacketSizeTable(number_page_segments); |
1008 | u_int8_t lacing_value = 0; |
1009 | #ifdef DEBUG |
1010 | fprintf(stderr, "\tsegment_table\n" ); |
1011 | #endif |
1012 | for (unsigned i = 0; i < number_page_segments; ++i) { |
1013 | lacing_value = get1Byte(); |
1014 | #ifdef DEBUG |
1015 | fprintf(stderr, "\t\t%d:\t%d" , i, lacing_value); |
1016 | #endif |
1017 | fPacketSizeTable->totSizes += lacing_value; |
1018 | fPacketSizeTable->size[fPacketSizeTable->numCompletedPackets] += lacing_value; |
1019 | if (lacing_value < 255) { |
1020 | // This completes a packet: |
1021 | #ifdef DEBUG |
1022 | fprintf(stderr, " (->%d)" , fPacketSizeTable->size[fPacketSizeTable->numCompletedPackets]); |
1023 | #endif |
1024 | ++fPacketSizeTable->numCompletedPackets; |
1025 | } |
1026 | #ifdef DEBUG |
1027 | fprintf(stderr, "\n" ); |
1028 | #endif |
1029 | } |
1030 | |
1031 | fPacketSizeTable->lastPacketIsIncomplete = lacing_value == 255; |
1032 | } |
1033 | |