MP3AudioMatroskaFileServerMediaSubsession ::MP3AudioMatroskaFileServerMediaSubsession(MatroskaFileServerDemux& demux, MatroskaTrack* track, Boolean generateADUs, Interleaving* interleaving) : MP3AudioFileServerMediaSubsession(demux.envir(), demux.fileName(), False, generateADUs, interleaving), fOurDemux(demux), fTrackNumber(track->trackNumber) { fFileDuration = fOurDemux.fileDuration(); }
H264VideoMatroskaFileServerMediaSubsession ::H264VideoMatroskaFileServerMediaSubsession(MatroskaFileServerDemux& demux, unsigned trackNumber) : H264VideoFileServerMediaSubsession(demux.envir(), demux.fileName(), False), fOurDemux(demux), fTrackNumber(trackNumber), fSPSSize(0), fSPS(NULL), fPPSSize(0), fPPS(NULL) { // Use our track's 'Codec Private' data: Byte 4 contains the size of NAL unit lengths, // and bytes 5 and beyond contain SPS and PPSs: MatroskaTrack* track = fOurDemux.lookup(fTrackNumber); if (track->codecPrivateSize >= 5) track->subframeSizeSize = (track->codecPrivate[4])&0x3 + 1; unsigned numSPSandPPSBytes; u_int8_t* SPSandPPSBytes; if (track->codecPrivateSize >= 6) { numSPSandPPSBytes = track->codecPrivateSize - 5; track->codecPrivate[5] &=~ 0xE0; // mask out the top 3 (reserved) bits from the 'numSPSs' byte SPSandPPSBytes = &track->codecPrivate[5]; } else { numSPSandPPSBytes = 0; SPSandPPSBytes = NULL; } // Extract, from "SPSandPPSBytes", one SPS NAL unit, and one PPS NAL unit. (I hope one is all we need of each.) do { if (numSPSandPPSBytes == 0 || SPSandPPSBytes == NULL) break; // sanity check u_int8_t* ptr = SPSandPPSBytes; u_int8_t* limit = &SPSandPPSBytes[numSPSandPPSBytes]; unsigned numSPSs = *ptr++; checkPtr; unsigned i; for (i = 0; i < numSPSs; ++i) { unsigned spsSize = (*ptr++)<<8; checkPtr; spsSize |= *ptr++; checkPtr; if (spsSize > numBytesRemaining) return; if (i == 0) { // save the first one fSPSSize = spsSize; fSPS = new u_int8_t[spsSize]; memmove(fSPS, ptr, spsSize); } ptr += spsSize; } unsigned numPPSs = *ptr++; checkPtr; for (i = 0; i < numPPSs; ++i) { unsigned ppsSize = (*ptr++)<<8; checkPtr; ppsSize |= *ptr++; checkPtr; if (ppsSize > numBytesRemaining) return; if (i == 0) { // save the first one fPPSSize = ppsSize; fPPS = new u_int8_t[ppsSize]; memmove(fPPS, ptr, ppsSize); } ptr += ppsSize; } } while (0); }
AACAudioMatroskaFileServerMediaSubsession ::AACAudioMatroskaFileServerMediaSubsession(MatroskaFileServerDemux& demux, unsigned trackNumber) : FileServerMediaSubsession(demux.envir(), demux.fileName(), False), fOurDemux(demux), fTrackNumber(trackNumber) { // The Matroska file's 'Codec Private' data is assumed to be the AAC configuration information. // Use this to generate a 'config string': MatroskaTrack* track = fOurDemux.lookup(fTrackNumber); fConfigStr = new char[2*track->codecPrivateSize + 1]; // 2 hex digits per byte, plus the trailing '\0' for (unsigned i = 0; i < track->codecPrivateSize; ++i) sprintf(&fConfigStr[2*i], "%02X", track->codecPrivate[i]); }
T140TextMatroskaFileServerMediaSubsession ::T140TextMatroskaFileServerMediaSubsession(MatroskaFileServerDemux& demux, unsigned trackNumber) : FileServerMediaSubsession(demux.envir(), demux.fileName(), False), fOurDemux(demux), fTrackNumber(trackNumber) { }
MatroskaFileServerMediaSubsession ::MatroskaFileServerMediaSubsession(MatroskaFileServerDemux& demux, MatroskaTrack* track) : FileServerMediaSubsession(demux.envir(), demux.fileName(), False), fOurDemux(demux), fTrack(track), fNumFiltersInFrontOfTrack(0) { }
VorbisAudioMatroskaFileServerMediaSubsession ::VorbisAudioMatroskaFileServerMediaSubsession(MatroskaFileServerDemux& demux, unsigned trackNumber) : FileServerMediaSubsession(demux.envir(), demux.fileName(), False), fOurDemux(demux), fTrackNumber(trackNumber), fIdentificationHeader(NULL), fIdentificationHeaderSize(0), fCommentHeader(NULL), fCommentHeaderSize(0), fSetupHeader(NULL), fSetupHeaderSize(0), fEstBitrate(96/* kbps, default guess */) { MatroskaTrack* track = fOurDemux.lookup(fTrackNumber); // The Matroska file's 'Codec Private' data is assumed to be the Vorbis configuration information, // containing the "Identification", "Comment", and "Setup" headers. Extract these headers now: do { u_int8_t* p = track->codecPrivate; unsigned n = track->codecPrivateSize; if (n == 0 || p == NULL) break; // we have no 'Codec Private' data u_int8_t numHeaders; getPrivByte(numHeaders); unsigned headerSize[3]; // we don't handle any more than 2+1 headers // Extract the sizes of each of these headers: unsigned sizesSum = 0; Boolean success = True; unsigned i; for (i = 0; i < numHeaders && i < 3; ++i) { unsigned len = 0; u_int8_t c; do { success = False; getPrivByte(c); success = True; len += c; } while (c == 255); if (!success || len == 0) break; headerSize[i] = len; sizesSum += len; } if (!success) break; // Compute the implicit size of the final header: if (numHeaders < 3) { int finalHeaderSize = n - sizesSum; if (finalHeaderSize <= 0) break; // error in data; give up headerSize[numHeaders] = (unsigned)finalHeaderSize; ++numHeaders; // include the final header now } else { numHeaders = 3; // The maximum number of headers that we handle } // Then, extract and classify each header: for (i = 0; i < numHeaders; ++i) { success = False; unsigned newHeaderSize = headerSize[i]; u_int8_t* newHeader = new u_int8_t[newHeaderSize]; if (newHeader == NULL) break; u_int8_t* hdr = newHeader; while (newHeaderSize-- > 0) { success = False; getPrivByte(*hdr++); success = True; } if (!success) { delete[] newHeader; break; } u_int8_t headerType = newHeader[0]; if (headerType == 1) { delete[] fIdentificationHeader; fIdentificationHeader = newHeader; fIdentificationHeaderSize = headerSize[i]; if (fIdentificationHeaderSize >= 28) { // Get the 'bitrate' values from this header, and use them to set "fEstBitrate": u_int32_t val; u_int8_t* p; p = &fIdentificationHeader[16]; val = ((p[3]*256 + p[2])*256 + p[1])*256 + p[0]; // i.e., little-endian int bitrate_maximum = (int)val; if (bitrate_maximum < 0) bitrate_maximum = 0; p = &fIdentificationHeader[20]; val = ((p[3]*256 + p[2])*256 + p[1])*256 + p[0]; // i.e., little-endian int bitrate_nominal = (int)val; if (bitrate_nominal < 0) bitrate_nominal = 0; p = &fIdentificationHeader[24]; val = ((p[3]*256 + p[2])*256 + p[1])*256 + p[0]; // i.e., little-endian int bitrate_minimum = (int)val; if (bitrate_minimum < 0) bitrate_minimum = 0; int bitrate = bitrate_nominal>0 ? bitrate_nominal : bitrate_maximum>0 ? bitrate_maximum : bitrate_minimum>0 ? bitrate_minimum : 0; if (bitrate > 0) fEstBitrate = ((unsigned)bitrate)/1000; } } else if (headerType == 3) { delete[] fCommentHeader; fCommentHeader = newHeader; fCommentHeaderSize = headerSize[i]; } else if (headerType == 5) { delete[] fSetupHeader; fSetupHeader = newHeader; fSetupHeaderSize = headerSize[i]; } else { delete[] newHeader; // because it was a header type that we don't understand } } if (!success) break; } while (0); }