static char* PrintCntlInfo( MP4FileHandle mp4File, MP4TrackId trackId) { const char *media_data_name = MP4GetTrackMediaDataName(mp4File, trackId); const char *typeName = "Unknown"; if (media_data_name == NULL) { typeName = "Unknown - no media data name"; } else if (strcasecmp(media_data_name, "href") == 0) { typeName = "ISMA Href"; } else { typeName = media_data_name; } MP4Duration trackDuration = MP4GetTrackDuration(mp4File, trackId); double msDuration = UINT64_TO_DOUBLE(MP4ConvertFromTrackDuration(mp4File, trackId, trackDuration, MP4_MSECS_TIME_SCALE)); char *sInfo = (char *)MP4Malloc(256); snprintf(sInfo, 256, "%u\tcontrol\t%s, %.3f secs\n", trackId, typeName, msDuration / 1000.0); return sInfo; }
void MP4BytesProperty::SetValue(const u_int8_t* pValue, u_int32_t valueSize, u_int32_t index) { if (m_readOnly) { throw new MP4Error(EACCES, "property is read-only", m_name); } if (m_fixedValueSize) { if (valueSize > m_fixedValueSize) { throw new MP4Error("value size exceeds fixed value size", "MP4BytesProperty::SetValue"); } if (m_values[index] == NULL) { m_values[index] = (u_int8_t*)MP4Calloc(m_fixedValueSize); m_valueSizes[index] = m_fixedValueSize; } if (pValue) { memcpy(m_values[index], pValue, valueSize); } } else { MP4Free(m_values[index]); if (pValue) { m_values[index] = (u_int8_t*)MP4Malloc(valueSize); memcpy(m_values[index], pValue, valueSize); m_valueSizes[index] = valueSize; } else { m_values[index] = NULL; m_valueSizes[index] = 0; } } }
void MP4BytesProperty::Read(MP4File* pFile, u_int32_t index) { if (m_implicit) { return; } MP4Free(m_values[index]); m_values[index] = (u_int8_t*)MP4Malloc(m_valueSizes[index]); pFile->ReadBytes(m_values[index], m_valueSizes[index]); }
void MP4File::CreateIsmaSceneCommand( bool hasAudio, bool hasVideo, u_int8_t** ppBytes, u_int64_t* pNumBytes) { // from ISMA 1.0 Tech Spec Appendix E static u_int8_t bifsAudioOnly[] = { 0xC0, 0x10, 0x12, 0x81, 0x30, 0x2A, 0x05, 0x6D, 0xC0 }; static u_int8_t bifsVideoOnly[] = { 0xC0, 0x10, 0x12, 0x61, 0x04, 0x1F, 0xC0, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00, 0x44, 0x28, 0x22, 0x82, 0x9F, 0x80 }; static u_int8_t bifsAudioVideo[] = { 0xC0, 0x10, 0x12, 0x81, 0x30, 0x2A, 0x05, 0x6D, 0x26, 0x10, 0x41, 0xFC, 0x00, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x04, 0x42, 0x82, 0x28, 0x29, 0xF8 }; if (hasAudio && hasVideo) { *pNumBytes = sizeof(bifsAudioVideo); *ppBytes = (u_int8_t*)MP4Malloc(*pNumBytes); memcpy(*ppBytes, bifsAudioVideo, sizeof(bifsAudioVideo)); } else if (hasAudio) { *pNumBytes = sizeof(bifsAudioOnly); *ppBytes = (u_int8_t*)MP4Malloc(*pNumBytes); memcpy(*ppBytes, bifsAudioOnly, sizeof(bifsAudioOnly)); } else if (hasVideo) { *pNumBytes = sizeof(bifsVideoOnly); *ppBytes = (u_int8_t*)MP4Malloc(*pNumBytes); memcpy(*ppBytes, bifsVideoOnly, sizeof(bifsVideoOnly)); } else { *pNumBytes = 0; *ppBytes = NULL; } }
void MP4SdpAtom::Read() { // read sdp string, length is implicit in size of atom u_int64_t size = GetEnd() - m_pFile->GetPosition(); char* data = (char*)MP4Malloc(size + 1); ASSERT(data != NULL); m_pFile->ReadBytes((u_int8_t*)data, size); data[size] = '\0'; ((MP4StringProperty*)m_pProperties[0])->SetValue(data); MP4Free(data); }
static char* PrintHintInfo( MP4FileHandle mp4File, MP4TrackId trackId) { MP4TrackId referenceTrackId = MP4GetHintTrackReferenceTrackId(mp4File, trackId); char* payloadName = NULL; if (!MP4GetHintTrackRtpPayload(mp4File, trackId, &payloadName)) return NULL; char *sInfo = (char*)MP4Malloc(256); snprintf(sInfo, 256, "%u\thint\tPayload %s for track %u\n", trackId, payloadName, referenceTrackId); free(payloadName); return sInfo; }
static char* PrintTrackInfo( MP4FileHandle mp4File, MP4TrackId trackId) { char* trackInfo = NULL; const char* trackType = MP4GetTrackType(mp4File, trackId); if (trackType == NULL) return NULL; if (!strcmp(trackType, MP4_AUDIO_TRACK_TYPE)) { trackInfo = PrintAudioInfo(mp4File, trackId); } else if (!strcmp(trackType, MP4_VIDEO_TRACK_TYPE)) { trackInfo = PrintVideoInfo(mp4File, trackId); } else if (!strcmp(trackType, MP4_HINT_TRACK_TYPE)) { trackInfo = PrintHintInfo(mp4File, trackId); } else if (strcmp(trackType, MP4_CNTL_TRACK_TYPE) == 0) { trackInfo = PrintCntlInfo(mp4File, trackId); } else { trackInfo = (char*)MP4Malloc(256); if (!strcmp(trackType, MP4_OD_TRACK_TYPE)) { snprintf(trackInfo, 256, "%u\tod\tObject Descriptors\n", trackId); } else if (!strcmp(trackType, MP4_SCENE_TRACK_TYPE)) { snprintf(trackInfo, 256, "%u\tscene\tBIFS\n", trackId); } else { snprintf(trackInfo, 256, "%u\t%s\n", trackId, trackType); } } return trackInfo; }
void MP4Track::ReadChunk(MP4ChunkId chunkId, u_int8_t** ppChunk, u_int32_t* pChunkSize) { ASSERT(chunkId); ASSERT(ppChunk); ASSERT(pChunkSize); u_int64_t chunkOffset = m_pChunkOffsetProperty->GetValue(chunkId - 1); *pChunkSize = GetChunkSize(chunkId); *ppChunk = (u_int8_t*)MP4Malloc(*pChunkSize); VERBOSE_READ_SAMPLE(m_pFile->GetVerbosity(), printf("ReadChunk: track %u id %u offset 0x"LLX" size %u (0x%x)\n", m_trackId, chunkId, chunkOffset, *pChunkSize, *pChunkSize)); u_int64_t oldPos = m_pFile->GetPosition(); // only used in mode == 'w' try { m_pFile->SetPosition(chunkOffset); m_pFile->ReadBytes(*ppChunk, *pChunkSize); } catch (MP4Error* e) { // let's not leak memory MP4Free(*ppChunk); *ppChunk = NULL; if (m_pFile->GetMode() == 'w') { m_pFile->SetPosition(oldPos); } throw e; } if (m_pFile->GetMode() == 'w') { m_pFile->SetPosition(oldPos); } }
// // Clone - clone my properties to destination atom // // this method simplifies duplicating avcC atom properties from // source to destination file using a single API rather than // having to copy each property. This API encapsulates the object // so the application layer need not concern with each property // thereby isolating any future changes to atom properties. // // ---------------------------------------- // property description // ---------------------------------------- // // 0 configurationVersion // 1 AVCProfileIndication // 2 profile_compatibility // 3 AVCLevelIndication // 4 reserved // 5 lengthSizeMinusOne // 6 reserved // 7 number of SPS // 8 SPS entries // 9 number of PPS // 10 PPS entries // // void MP4HvcCAtom::Clone(MP4HvcCAtom *dstAtom) { #if 1 //cwm MP4Property *dstProperty; MP4TableProperty *pTable; uint16_t i16; uint64_t i32; uint64_t i64; uint8_t *tmp; // source pointer Property I16 MP4Integer16Property *spPI16; // source pointer Property Bytes MP4BytesProperty *spPB; // dest pointer Property I16 MP4Integer16Property *dpPI16; // dest pointer Property Bytes MP4BytesProperty *dpPB; // start with defaults and reserved fields dstAtom->Generate(); // 0, 4, 6 are now generated from defaults // leaving 1, 2, 3, 5, 7, 8, 9, 10 to export dstProperty=dstAtom->GetProperty(1); ((MP4Integer8Property *)dstProperty)->SetValue( 0x12);//((MP4Integer8Property *)m_pProperties[1])->GetValue() dstProperty=dstAtom->GetProperty(2); ((MP4Integer8Property *)dstProperty)->SetValue( 0x34);//((MP4Integer8Property *)m_pProperties[2])->GetValue() dstProperty=dstAtom->GetProperty(3); ((MP4Integer8Property *)dstProperty)->SetValue( ((MP4Integer8Property *)m_pProperties[3])->GetValue()); dstProperty=dstAtom->GetProperty(5); ((MP4BitfieldProperty *)dstProperty)->SetValue( ((MP4BitfieldProperty *)m_pProperties[5])->GetValue()); // // 7 and 8 are related SPS (one set of sequence parameters) // // first the count bitfield // dstProperty=dstAtom->GetProperty(7); dstProperty->SetReadOnly(false); ((MP4BitfieldProperty *)dstProperty)->SetValue( ((MP4BitfieldProperty *)m_pProperties[7])->GetValue()); dstProperty->SetReadOnly(true); // next export SPS Length and NAL bytes */ // first source pointers pTable = (MP4TableProperty *) m_pProperties[8]; spPI16 = (MP4Integer16Property *)pTable->GetProperty(0); spPB = (MP4BytesProperty *)pTable->GetProperty(1); // now dest pointers dstProperty=dstAtom->GetProperty(8); pTable = (MP4TableProperty *) dstProperty; dpPI16 = (MP4Integer16Property *)pTable->GetProperty(0); dpPB = (MP4BytesProperty *)pTable->GetProperty(1); // sps length i16 = spPI16->GetValue(); i64 = i16; // FIXME - this leaves m_maxNumElements =2 // but src atom m_maxNumElements is 1 dpPI16->InsertValue(i64, 0); // export byte array i32 = i16; // copy bytes to local buffer tmp = (uint8_t *)MP4Malloc(i32); ASSERT(tmp != NULL); spPB->CopyValue(tmp, 0); // set element count dpPB->SetCount(1); // copy bytes dpPB->SetValue(tmp, i32, 0); MP4Free((void *)tmp); // // 9 and 10 are related PPS (one set of picture parameters) // // first the integer8 count // dstProperty=dstAtom->GetProperty(9); dstProperty->SetReadOnly(false); ((MP4Integer8Property *)dstProperty)->SetValue( ((MP4Integer8Property *)m_pProperties[9])->GetValue()); dstProperty->SetReadOnly(true); // next export PPS Length and NAL bytes */ // first source pointers pTable = (MP4TableProperty *) m_pProperties[10]; spPI16 = (MP4Integer16Property *)pTable->GetProperty(0); spPB = (MP4BytesProperty *)pTable->GetProperty(1); // now dest pointers dstProperty=dstAtom->GetProperty(10); pTable = (MP4TableProperty *) dstProperty; dpPI16 = (MP4Integer16Property *)pTable->GetProperty(0); dpPB = (MP4BytesProperty *)pTable->GetProperty(1); #if 1//cwm 500 // pps length i16 = spPI16->GetValue(); i64 = i16; dpPI16->InsertValue(i64, 0); // export byte array i32 = i16; // copy bytes to local buffer tmp = (uint8_t *)MP4Malloc(i32); ASSERT(tmp != NULL); spPB->CopyValue(tmp, 0); // set element count dpPB->SetCount(1); // copy bytes dpPB->SetValue(tmp, i32, 0); MP4Free((void *)tmp); #endif //cwm 500 #endif //cwm }
void MP4RtpHintTrack::ReadPacket( u_int16_t packetIndex, u_int8_t** ppBytes, u_int32_t* pNumBytes, u_int32_t ssrc, bool addHeader, bool addPayload) { if (m_pReadHint == NULL) { throw new MP4Error("no hint has been read", "MP4ReadRtpPacket"); } if (!addHeader && !addPayload) { throw new MP4Error("no data requested", "MP4ReadRtpPacket"); } MP4RtpPacket* pPacket = m_pReadHint->GetPacket(packetIndex); *pNumBytes = 0; if (addHeader) { *pNumBytes += 12; } if (addPayload) { *pNumBytes += pPacket->GetDataSize(); } // if needed, allocate the packet memory bool buffer_malloc = false; if (*ppBytes == NULL) { *ppBytes = (u_int8_t*)MP4Malloc(*pNumBytes); buffer_malloc = true; } try { u_int8_t* pDest = *ppBytes; if (addHeader) { *pDest++ = 0x80 | (pPacket->GetPBit() << 5) | (pPacket->GetXBit() << 4); *pDest++ = (pPacket->GetMBit() << 7) | pPacket->GetPayload(); *((u_int16_t*)pDest) = htons(m_rtpSequenceStart + pPacket->GetSequenceNumber()); pDest += 2; *((u_int32_t*)pDest) = htonl(m_rtpTimestampStart + (u_int32_t)m_readHintTimestamp); pDest += 4; *((u_int32_t*)pDest) = htonl(ssrc); pDest += 4; } if (addPayload) { pPacket->GetData(pDest); } } catch (MP4Error* e) { if (buffer_malloc) { MP4Free(*ppBytes); *ppBytes = NULL; } throw e; } VERBOSE_READ_HINT(m_pFile->GetVerbosity(), printf("ReadPacket: %u ", packetIndex); MP4HexDump(*ppBytes, *pNumBytes););
static char* PrintAudioInfo( MP4FileHandle mp4File, MP4TrackId trackId) { static const char* mpeg4AudioNames[] = { "MPEG-4 AAC main", "MPEG-4 AAC LC", "MPEG-4 AAC SSR", "MPEG-4 AAC LTP", "MPEG-4 AAC HE", "MPEG-4 AAC Scalable", "MPEG-4 TwinVQ", "MPEG-4 CELP", "MPEG-4 HVXC", NULL, NULL, "MPEG-4 TTSI", "MPEG-4 Main Synthetic", "MPEG-4 Wavetable Syn", "MPEG-4 General MIDI", "MPEG-4 Algo Syn and Audio FX", "MPEG-4 ER AAC LC", NULL, "MPEG-4 ER AAC LTP", "MPEG-4 ER AAC Scalable", "MPEG-4 ER TwinVQ", "MPEG-4 ER BSAC", "MPEG-4 ER ACC LD", "MPEG-4 ER CELP", "MPEG-4 ER HVXC", "MPEG-4 ER HILN", "MPEG-4 ER Parametric", "MPEG-4 SSC", "MPEG-4 PS", "MPEG-4 MPEG Surround", NULL, "MPEG-4 Layer-1", "MPEG-4 Layer-2", "MPEG-4 Layer-3", "MPEG-4 DST", "MPEG-4 Audio Lossless", "MPEG-4 SLS", "MPEG-4 SLS non-core", }; static const u_int8_t mpegAudioTypes[] = { MP4_MPEG2_AAC_MAIN_AUDIO_TYPE, // 0x66 MP4_MPEG2_AAC_LC_AUDIO_TYPE, // 0x67 MP4_MPEG2_AAC_SSR_AUDIO_TYPE, // 0x68 MP4_MPEG2_AUDIO_TYPE, // 0x69 MP4_MPEG1_AUDIO_TYPE, // 0x6B // private types MP4_PCM16_LITTLE_ENDIAN_AUDIO_TYPE, MP4_VORBIS_AUDIO_TYPE, MP4_ALAW_AUDIO_TYPE, MP4_ULAW_AUDIO_TYPE, MP4_G723_AUDIO_TYPE, MP4_PCM16_BIG_ENDIAN_AUDIO_TYPE, }; static const char* mpegAudioNames[] = { "MPEG-2 AAC Main", "MPEG-2 AAC LC", "MPEG-2 AAC SSR", "MPEG-2 Audio (13818-3)", "MPEG-1 Audio (11172-3)", // private types "PCM16 (little endian)", "Vorbis", "G.711 aLaw", "G.711 uLaw", "G.723.1", "PCM16 (big endian)", }; u_int8_t numMpegAudioTypes = sizeof(mpegAudioTypes) / sizeof(u_int8_t); const char* typeName = "Unknown"; bool foundType = false; u_int8_t type = 0; const char *media_data_name; media_data_name = MP4GetTrackMediaDataName(mp4File, trackId); if (media_data_name == NULL) { typeName = "Unknown - no media data name"; } else if (strcasecmp(media_data_name, "samr") == 0) { typeName = "AMR"; foundType = true; } else if (strcasecmp(media_data_name, "sawb") == 0) { typeName = "AMR-WB"; foundType = true; } else if (strcasecmp(media_data_name, "mp4a") == 0) { type = MP4GetTrackEsdsObjectTypeId(mp4File, trackId); switch (type) { case MP4_INVALID_AUDIO_TYPE: typeName = "AAC from .mov"; foundType = true; break; case MP4_MPEG4_AUDIO_TYPE: { type = MP4GetTrackAudioMpeg4Type(mp4File, trackId); if (type == MP4_MPEG4_INVALID_AUDIO_TYPE || type > NUM_ELEMENTS_IN_ARRAY(mpeg4AudioNames) || mpeg4AudioNames[type - 1] == NULL) { typeName = "MPEG-4 Unknown Profile"; } else { typeName = mpeg4AudioNames[type - 1]; foundType = true; } break; } // fall through default: for (u_int8_t i = 0; i < numMpegAudioTypes; i++) { if (type == mpegAudioTypes[i]) { typeName = mpegAudioNames[i]; foundType = true; break; } } } } else { typeName = media_data_name; foundType = true; } u_int32_t timeScale = MP4GetTrackTimeScale(mp4File, trackId); MP4Duration trackDuration = MP4GetTrackDuration(mp4File, trackId); double msDuration = UINT64_TO_DOUBLE(MP4ConvertFromTrackDuration(mp4File, trackId, trackDuration, MP4_MSECS_TIME_SCALE)); u_int32_t avgBitRate = MP4GetTrackBitRate(mp4File, trackId); char *sInfo = (char*)MP4Malloc(256); // type duration avgBitrate samplingFrequency if (foundType) snprintf(sInfo, 256, "%u\taudio\t%s%s, %.3f secs, %u kbps, %u Hz\n", trackId, MP4IsIsmaCrypMediaTrack(mp4File, trackId) ? "enca - " : "", typeName, msDuration / 1000.0, (avgBitRate + 500) / 1000, timeScale); else snprintf(sInfo, 256, "%u\taudio\t%s%s(%u), %.3f secs, %u kbps, %u Hz\n", trackId, MP4IsIsmaCrypMediaTrack(mp4File, trackId) ? "enca - " : "", typeName, type, msDuration / 1000.0, (avgBitRate + 500) / 1000, timeScale); return sInfo; }
static char* PrintVideoInfo( MP4FileHandle mp4File, MP4TrackId trackId) { static const u_int8_t mpegVideoTypes[] = { MP4_MPEG2_SIMPLE_VIDEO_TYPE, // 0x60 MP4_MPEG2_MAIN_VIDEO_TYPE, // 0x61 MP4_MPEG2_SNR_VIDEO_TYPE, // 0x62 MP4_MPEG2_SPATIAL_VIDEO_TYPE, // 0x63 MP4_MPEG2_HIGH_VIDEO_TYPE, // 0x64 MP4_MPEG2_442_VIDEO_TYPE, // 0x65 MP4_MPEG1_VIDEO_TYPE, // 0x6A MP4_JPEG_VIDEO_TYPE, // 0x6C MP4_YUV12_VIDEO_TYPE, MP4_H263_VIDEO_TYPE, MP4_H261_VIDEO_TYPE, }; static const char* mpegVideoNames[] = { "MPEG-2 Simple", "MPEG-2 Main", "MPEG-2 SNR", "MPEG-2 Spatial", "MPEG-2 High", "MPEG-2 4:2:2", "MPEG-1", "JPEG", "YUV12", "H.263", "H.261", }; u_int8_t numMpegVideoTypes = sizeof(mpegVideoTypes) / sizeof(u_int8_t); bool foundTypeName = false; const char* typeName = "Unknown"; const char *media_data_name; char originalFormat[8]; char oformatbuffer[32]; originalFormat[0] = 0; *oformatbuffer = 0; uint8_t type = 0; media_data_name = MP4GetTrackMediaDataName(mp4File, trackId); // encv 264b if (strcasecmp(media_data_name, "encv") == 0) { if (MP4GetTrackMediaDataOriginalFormat(mp4File, trackId, originalFormat, sizeof(originalFormat)) == false) media_data_name = NULL; } char typebuffer[80]; if (media_data_name == NULL) { typeName = "Unknown - no media data name"; foundTypeName = true; } else if ((strcasecmp(media_data_name, "avc1") == 0) || (strcasecmp(originalFormat, "264b") == 0)) { // avc uint8_t profile, level; char profileb[20], levelb[20]; if (MP4GetTrackH264ProfileLevel(mp4File, trackId, &profile, &level)) { if (profile == 66) { strcpy(profileb, "Baseline"); } else if (profile == 77) { strcpy(profileb, "Main"); } else if (profile == 88) { strcpy(profileb, "Extended"); } else if (profile == 100) { strcpy(profileb, "High"); } else if (profile == 110) { strcpy(profileb, "High 10"); } else if (profile == 122) { strcpy(profileb, "High 4:2:2"); } else if (profile == 144) { strcpy(profileb, "High 4:4:4"); } else { snprintf(profileb, 20, "Unknown Profile %x", profile); } switch (level) { case 10: case 20: case 30: case 40: case 50: snprintf(levelb, 20, "%u", level / 10); break; case 11: case 12: case 13: case 21: case 22: case 31: case 32: case 41: case 42: case 51: snprintf(levelb, 20, "%u.%u", level / 10, level % 10); break; default: snprintf(levelb, 20, "unknown level %x", level); break; } if (originalFormat != NULL && originalFormat[0] != '\0') snprintf(oformatbuffer, 32, "(%s) ", originalFormat); snprintf(typebuffer, sizeof(typebuffer), "H264 %s%s@%s", oformatbuffer, profileb, levelb); typeName = typebuffer; } else { typeName = "H.264 - profile/level error"; } foundTypeName = true; } else if (strcasecmp(media_data_name, "s263") == 0) { // 3gp h.263 typeName = "H.263"; foundTypeName = true; } else if ((strcasecmp(media_data_name, "mp4v") == 0) || (strcasecmp(media_data_name, "encv") == 0)) { // note encv might needs it's own field eventually. type = MP4GetTrackEsdsObjectTypeId(mp4File, trackId); if (type == MP4_MPEG4_VIDEO_TYPE) { type = MP4GetVideoProfileLevel(mp4File, trackId); typeName = Mpeg4VisualProfileName(type); if (typeName == NULL) { typeName = "MPEG-4 Unknown Profile"; } else { foundTypeName = true; } } else { for (u_int8_t i = 0; i < numMpegVideoTypes; i++) { if (type == mpegVideoTypes[i]) { typeName = mpegVideoNames[i]; foundTypeName = true; break; } } } } else { typeName = media_data_name; foundTypeName = true; // we don't have a type value to display } MP4Duration trackDuration = MP4GetTrackDuration(mp4File, trackId); double msDuration = UINT64_TO_DOUBLE(MP4ConvertFromTrackDuration(mp4File, trackId, trackDuration, MP4_MSECS_TIME_SCALE)); u_int32_t avgBitRate = MP4GetTrackBitRate(mp4File, trackId); // Note not all mp4 implementations set width and height correctly // The real answer can be buried inside the ES configuration info u_int16_t width = MP4GetTrackVideoWidth(mp4File, trackId); u_int16_t height = MP4GetTrackVideoHeight(mp4File, trackId); double fps = MP4GetTrackVideoFrameRate(mp4File, trackId); char *sInfo = (char*)MP4Malloc(256); // type duration avgBitrate frameSize frameRate if (foundTypeName) { sprintf(sInfo, "%u\tvideo\t%s%s, %.3f secs, %u kbps, %ux%u @ %f fps\n", trackId, MP4IsIsmaCrypMediaTrack(mp4File, trackId) ? "encv - " : "", typeName, msDuration / 1000.0, (avgBitRate + 500) / 1000, width, height, fps ); } else { sprintf(sInfo, "%u\tvideo\t%s(%u), %.3f secs, %u kbps, %ux%u @ %f fps\n", trackId, typeName, type, msDuration / 1000.0, (avgBitRate + 500) / 1000, width, height, fps ); } return sInfo; }
void MP4Track::ReadSample( MP4SampleId sampleId, u_int8_t** ppBytes, u_int32_t* pNumBytes, MP4Timestamp* pStartTime, MP4Duration* pDuration, MP4Duration* pRenderingOffset, bool* pIsSyncSample) { if (sampleId == MP4_INVALID_SAMPLE_ID) { throw new MP4Error("sample id can't be zero", "MP4Track::ReadSample"); } // handle unusual case of wanting to read a sample // that is still sitting in the write chunk buffer if (m_pChunkBuffer && sampleId >= m_writeSampleId - m_chunkSamples) { WriteChunkBuffer(); } FILE* pFile = GetSampleFile(sampleId); if (pFile == (FILE*)-1) { throw new MP4Error("sample is located in an inaccessible file", "MP4Track::ReadSample"); } u_int64_t fileOffset = GetSampleFileOffset(sampleId); u_int32_t sampleSize = GetSampleSize(sampleId); if (*ppBytes != NULL && *pNumBytes < sampleSize) { throw new MP4Error("sample buffer is too small", "MP4Track::ReadSample"); } *pNumBytes = sampleSize; VERBOSE_READ_SAMPLE(m_pFile->GetVerbosity(), printf("ReadSample: track %u id %u offset 0x"LLX" size %u (0x%x)\n", m_trackId, sampleId, fileOffset, *pNumBytes, *pNumBytes)); bool bufferMalloc = false; if (*ppBytes == NULL) { *ppBytes = (u_int8_t*)MP4Malloc(*pNumBytes); bufferMalloc = true; } u_int64_t oldPos = m_pFile->GetPosition(pFile); // only used in mode == 'w' try { m_pFile->SetPosition(fileOffset, pFile); m_pFile->ReadBytes(*ppBytes, *pNumBytes, pFile); if (pStartTime || pDuration) { GetSampleTimes(sampleId, pStartTime, pDuration); VERBOSE_READ_SAMPLE(m_pFile->GetVerbosity(), printf("ReadSample: start "LLU" duration "LLD"\n", (pStartTime ? *pStartTime : 0), (pDuration ? *pDuration : 0))); } if (pRenderingOffset) { *pRenderingOffset = GetSampleRenderingOffset(sampleId); VERBOSE_READ_SAMPLE(m_pFile->GetVerbosity(), printf("ReadSample: renderingOffset "LLD"\n", *pRenderingOffset)); } if (pIsSyncSample) { *pIsSyncSample = IsSyncSample(sampleId); VERBOSE_READ_SAMPLE(m_pFile->GetVerbosity(), printf("ReadSample: isSyncSample %u\n", *pIsSyncSample)); } } catch (MP4Error* e) { if (bufferMalloc) { // let's not leak memory MP4Free(*ppBytes); *ppBytes = NULL; } if (m_pFile->GetMode() == 'w') { m_pFile->SetPosition(oldPos, pFile); } throw e; } if (m_pFile->GetMode() == 'w') { m_pFile->SetPosition(oldPos, pFile); } }
void MP4File::CreateIsmaIodFromParams( u_int8_t videoProfile, u_int32_t videoBitrate, u_int8_t* videoConfig, u_int32_t videoConfigLength, u_int8_t audioProfile, u_int32_t audioBitrate, u_int8_t* audioConfig, u_int32_t audioConfigLength, u_int8_t** ppIodBytes, u_int64_t* pIodNumBytes) { MP4IntegerProperty* pInt; u_int8_t* pBytes = NULL; u_int64_t numBytes; // Create the IOD MP4Descriptor* pIod = new MP4IODescriptor(); pIod->SetTag(MP4IODescrTag); pIod->Generate(); // Set audio and video profileLevels pIod->FindProperty("audioProfileLevelId", (MP4Property**)&pInt); pInt->SetValue(audioProfile); pIod->FindProperty("visualProfileLevelId", (MP4Property**)&pInt); pInt->SetValue(videoProfile); // Mutate esIds from MP4ESIDIncDescrTag to MP4ESDescrTag MP4DescriptorProperty* pEsProperty; pIod->FindProperty("esIds", (MP4Property**)&pEsProperty); pEsProperty->SetTags(MP4ESDescrTag); // Add ES Descriptors // Scene CreateIsmaSceneCommand( (audioProfile != 0xFF), (videoProfile != 0xFF), &pBytes, &numBytes); VERBOSE_ISMA(GetVerbosity(), printf("Scene data =\n"); MP4HexDump(pBytes, numBytes)); char* sceneCmdBase64 = MP4ToBase64(pBytes, numBytes); char* urlBuf = (char*)MP4Malloc(strlen(sceneCmdBase64) + 64); sprintf(urlBuf, "data:application/mpeg4-bifs-au;base64,%s", sceneCmdBase64); VERBOSE_ISMA(GetVerbosity(), printf("Scene data URL = \042%s\042\n", urlBuf)); /* MP4Descriptor* pSceneEsd = */ CreateESD( pEsProperty, 201, // esid MP4SystemsV2ObjectType, MP4SceneDescriptionStreamType, numBytes, // bufferSize numBytes * 8, // bitrate BifsV2Config, sizeof(BifsV2Config), urlBuf); MP4Free(sceneCmdBase64); sceneCmdBase64 = NULL; MP4Free(urlBuf); urlBuf = NULL; MP4Free(pBytes); pBytes = NULL; // OD // Video MP4DescriptorProperty* pVideoEsdProperty = new MP4DescriptorProperty(); pVideoEsdProperty->SetTags(MP4ESDescrTag); /* MP4Descriptor* pVideoEsd = */ CreateESD( pVideoEsdProperty, 20, // esid MP4_MPEG4_VIDEO_TYPE, MP4VisualStreamType, videoBitrate / 8, // bufferSize videoBitrate, videoConfig, videoConfigLength, NULL); // Audio MP4DescriptorProperty* pAudioEsdProperty = new MP4DescriptorProperty(); pAudioEsdProperty->SetTags(MP4ESDescrTag); /* MP4Descriptor* pAudioEsd = */ CreateESD( pAudioEsdProperty, 10, // esid MP4_MPEG4_AUDIO_TYPE, MP4AudioStreamType, audioBitrate / 8, // bufferSize audioBitrate, audioConfig, audioConfigLength, NULL); CreateIsmaODUpdateCommandForStream( pAudioEsdProperty, pVideoEsdProperty, &pBytes, &numBytes); // cleanup temporary descriptor properties delete pAudioEsdProperty; delete pVideoEsdProperty; VERBOSE_ISMA(GetVerbosity(), printf("OD data = %llu bytes\n", numBytes); MP4HexDump(pBytes, numBytes)); char* odCmdBase64 = MP4ToBase64(pBytes, numBytes); urlBuf = (char*)MP4Malloc(strlen(odCmdBase64) + 64); sprintf(urlBuf, "data:application/mpeg4-od-au;base64,%s", odCmdBase64); VERBOSE_ISMA(GetVerbosity(), printf("OD data URL = \042%s\042\n", urlBuf)); /* MP4Descriptor* pOdEsd = */ CreateESD( pEsProperty, 101, MP4SystemsV1ObjectType, MP4ObjectDescriptionStreamType, numBytes, // bufferSize numBytes * 8, // bitrate NULL, // config 0, // configLength urlBuf); MP4Free(odCmdBase64); odCmdBase64 = NULL; MP4Free(pBytes); pBytes = NULL; MP4Free(urlBuf); urlBuf = NULL; // finally get the whole thing written to a memory pIod->WriteToMemory(this, ppIodBytes, pIodNumBytes); delete pIod; VERBOSE_ISMA(GetVerbosity(), printf("IOD data =\n"); MP4HexDump(*ppIodBytes, *pIodNumBytes)); }
void MP4File::CreateIsmaIodFromFile( MP4TrackId odTrackId, MP4TrackId sceneTrackId, MP4TrackId audioTrackId, MP4TrackId videoTrackId, u_int8_t** ppBytes, u_int64_t* pNumBytes) { MP4Descriptor* pIod = new MP4IODescriptor(); pIod->SetTag(MP4IODescrTag); pIod->Generate(); MP4Atom* pIodsAtom = FindAtom("moov.iods"); ASSERT(pIodsAtom); MP4DescriptorProperty* pSrcIod = (MP4DescriptorProperty*)pIodsAtom->GetProperty(2); CloneIntegerProperty(pIod, pSrcIod, "objectDescriptorId"); CloneIntegerProperty(pIod, pSrcIod, "ODProfileLevelId"); CloneIntegerProperty(pIod, pSrcIod, "sceneProfileLevelId"); CloneIntegerProperty(pIod, pSrcIod, "audioProfileLevelId"); CloneIntegerProperty(pIod, pSrcIod, "visualProfileLevelId"); CloneIntegerProperty(pIod, pSrcIod, "graphicsProfileLevelId"); // mutate esIds from MP4ESIDIncDescrTag to MP4ESDescrTag MP4DescriptorProperty* pEsProperty; pIod->FindProperty("esIds", (MP4Property**)&pEsProperty); pEsProperty->SetTags(MP4ESDescrTag); MP4IntegerProperty* pSetProperty; MP4IntegerProperty* pSceneESID; MP4IntegerProperty* pOdESID; // OD MP4Descriptor* pOdEsd = pEsProperty->AddDescriptor(MP4ESDescrTag); pOdEsd->Generate(); pOdEsd->FindProperty("ESID", (MP4Property**)&pOdESID); // we set the OD ESID to a non-zero unique value pOdESID->SetValue(m_odTrackId); pOdEsd->FindProperty("URLFlag", (MP4Property**)&pSetProperty); pSetProperty->SetValue(1); u_int8_t* pBytes; u_int64_t numBytes; CreateIsmaODUpdateCommandFromFileForStream( audioTrackId, videoTrackId, &pBytes, &numBytes); VERBOSE_ISMA(GetVerbosity(), printf("OD data =\n"); MP4HexDump(pBytes, numBytes)); char* odCmdBase64 = MP4ToBase64(pBytes, numBytes); char* urlBuf = (char*)MP4Malloc(strlen(odCmdBase64) + 64); sprintf(urlBuf, "data:application/mpeg4-od-au;base64,%s", odCmdBase64); MP4StringProperty* pUrlProperty; pOdEsd->FindProperty("URL", (MP4Property**)&pUrlProperty); pUrlProperty->SetValue(urlBuf); VERBOSE_ISMA(GetVerbosity(), printf("OD data URL = \042%s\042\n", urlBuf)); MP4Free(odCmdBase64); odCmdBase64 = NULL; MP4Free(pBytes); pBytes = NULL; MP4Free(urlBuf); urlBuf = NULL; MP4DescriptorProperty* pSrcDcd = NULL; // HACK temporarily point to scene decoder config FindProperty(MakeTrackName(odTrackId, "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr"), (MP4Property**)&pSrcDcd); ASSERT(pSrcDcd); MP4Property* pOrgOdEsdProperty = pOdEsd->GetProperty(8); pOdEsd->SetProperty(8, pSrcDcd); // bufferSizeDB needs to be set appropriately MP4BitfieldProperty* pBufferSizeProperty = NULL; pOdEsd->FindProperty("decConfigDescr.bufferSizeDB", (MP4Property**)&pBufferSizeProperty); ASSERT(pBufferSizeProperty); pBufferSizeProperty->SetValue(numBytes); // SL config needs to change from 2 (file) to 1 (null) pOdEsd->FindProperty("slConfigDescr.predefined", (MP4Property**)&pSetProperty); pSetProperty->SetValue(1); // Scene MP4Descriptor* pSceneEsd = pEsProperty->AddDescriptor(MP4ESDescrTag); pSceneEsd->Generate(); pSceneEsd->FindProperty("ESID", (MP4Property**)&pSceneESID); // we set the Scene ESID to a non-zero unique value pSceneESID->SetValue(sceneTrackId); pSceneEsd->FindProperty("URLFlag", (MP4Property**)&pSetProperty); pSetProperty->SetValue(1); CreateIsmaSceneCommand( MP4_IS_VALID_TRACK_ID(audioTrackId), MP4_IS_VALID_TRACK_ID(videoTrackId), &pBytes, &numBytes); VERBOSE_ISMA(GetVerbosity(), printf("Scene data =\n"); MP4HexDump(pBytes, numBytes)); char *sceneCmdBase64 = MP4ToBase64(pBytes, numBytes); urlBuf = (char*)MP4Malloc(strlen(sceneCmdBase64) + 64); sprintf(urlBuf, "data:application/mpeg4-bifs-au;base64,%s", sceneCmdBase64); pSceneEsd->FindProperty("URL", (MP4Property**)&pUrlProperty); pUrlProperty->SetValue(urlBuf); VERBOSE_ISMA(GetVerbosity(), printf("Scene data URL = \042%s\042\n", urlBuf)); MP4Free(sceneCmdBase64); sceneCmdBase64 = NULL; MP4Free(urlBuf); urlBuf = NULL; MP4Free(pBytes); pBytes = NULL; // HACK temporarily point to scene decoder config FindProperty(MakeTrackName(sceneTrackId, "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr"), (MP4Property**)&pSrcDcd); ASSERT(pSrcDcd); MP4Property* pOrgSceneEsdProperty = pSceneEsd->GetProperty(8); pSceneEsd->SetProperty(8, pSrcDcd); // bufferSizeDB needs to be set pBufferSizeProperty = NULL; pSceneEsd->FindProperty("decConfigDescr.bufferSizeDB", (MP4Property**)&pBufferSizeProperty); ASSERT(pBufferSizeProperty); pBufferSizeProperty->SetValue(numBytes); // SL config needs to change from 2 (file) to 1 (null) pSceneEsd->FindProperty("slConfigDescr.predefined", (MP4Property**)&pSetProperty); pSetProperty->SetValue(1); // finally get the whole thing written to a memory pIod->WriteToMemory(this, ppBytes, pNumBytes); // now carefully replace esd properties before destroying pOdEsd->SetProperty(8, pOrgOdEsdProperty); pSceneEsd->SetProperty(8, pOrgSceneEsdProperty); pSceneESID->SetValue(0); // restore 0 value pOdESID->SetValue(0); delete pIod; VERBOSE_ISMA(GetVerbosity(), printf("IOD data =\n"); MP4HexDump(*ppBytes, *pNumBytes)); }