void MP4File::MakeIsmaCompliant(bool addIsmaComplianceSdp) { ProtectWriteOperation("MP4MakeIsmaCompliant"); if (m_useIsma) { // already done return; } // find first audio and/or video tracks MP4TrackId audioTrackId = MP4_INVALID_TRACK_ID; try { audioTrackId = FindTrackId(0, MP4_AUDIO_TRACK_TYPE); } catch (MP4Error* e) { delete e; } MP4TrackId videoTrackId = MP4_INVALID_TRACK_ID; try { videoTrackId = FindTrackId(0, MP4_VIDEO_TRACK_TYPE); } catch (MP4Error* e) { delete e; } const char *audio_media_data_name, *video_media_data_name; audio_media_data_name = MP4GetTrackMediaDataName(this, audioTrackId); if (!(ATOMID(audio_media_data_name) == ATOMID("mp4a") || ATOMID(audio_media_data_name) == ATOMID("enca"))) { VERBOSE_ERROR(m_verbosity, printf("MakeIsmaCompliant:can't make ISMA compliant when file contains an %s track\n", audio_media_data_name); );
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; }
/* * getType: * * Returns a format/sub-format information. Taken from mp4.h/mp4info. */ static void getType(MP4FileHandle file, MP4TrackId trackId, const char **format, const char **subformat ) { unsigned i; const char *media_data_name = MP4GetTrackMediaDataName(file, trackId); *format = _("Audio"); *subformat = _("Unknown"); if (media_data_name == NULL) { ; } else if (strcasecmp(media_data_name, "samr") == 0) { *subformat = "AMR"; } else if (strcasecmp(media_data_name, "sawb") == 0) { *subformat = "AMR-WB"; } else if (strcasecmp(media_data_name, "mp4a") == 0) { u_int8_t type = MP4GetTrackEsdsObjectTypeId(file, trackId); if( type == MP4_MPEG4_AUDIO_TYPE ) { u_int8_t* pAacConfig = NULL; u_int32_t aacConfigLength; MP4GetTrackESConfiguration(file, trackId, &pAacConfig, &aacConfigLength); if (pAacConfig != NULL) { type = aacConfigLength >= 2 ? ((pAacConfig[0] >> 3) & 0x1f) : 0; free(pAacConfig); for (i = 0; i < NUMBER_OF(MP4AudioProfileToName); i++) { if (type == MP4AudioProfileToName[i].profile) { *format = MP4AudioProfileToName[i].format; *subformat = MP4AudioProfileToName[i].subformat; return; } } }
int CMp4File::create_media (CPlayerSession *psptr, int have_audio_driver, control_callback_vft_t *cc_vft) { uint video_count, video_offset; uint text_count, text_offset; uint audio_count, audio_offset; MP4TrackId trackId; video_query_t *vq; audio_query_t *aq; text_query_t *tq; uint ix; codec_plugin_t *plugin; int ret_value = 0; uint8_t *foo; u_int32_t bufsize; uint32_t verb = MP4GetVerbosity(m_mp4file); MP4SetVerbosity(m_mp4file, verb & ~(MP4_DETAILS_ERROR)); video_count = MP4GetNumberOfTracks(m_mp4file, MP4_VIDEO_TRACK_TYPE); audio_count = MP4GetNumberOfTracks(m_mp4file, MP4_AUDIO_TRACK_TYPE); text_count = MP4GetNumberOfTracks(m_mp4file, MP4_CNTL_TRACK_TYPE); mp4f_message(LOG_DEBUG, "cntl tracks %u", text_count); MP4SetVerbosity(m_mp4file, verb); if (video_count == 0 && audio_count == 0 && text_count == 0) { psptr->set_message("No audio, video or control tracks in file"); return -1; } if (video_count > 0) { vq = (video_query_t *)malloc(sizeof(video_query_t) * video_count); memset(vq, 0, sizeof(video_query_t) * video_count); } else { vq = NULL; } if (have_audio_driver && audio_count > 0) { aq = (audio_query_t *)malloc(sizeof(audio_query_t) * audio_count); memset(aq, 0, sizeof(audio_query_t) * audio_count); } else { aq = NULL; } if (text_count > 0) { tq = (text_query_t *)malloc(sizeof(text_query_t) * text_count); memset(tq, 0, sizeof(text_query_t) * text_count); } else { tq = NULL; } for (ix = 0, video_offset = 0; ix < video_count; ix++) { trackId = MP4FindTrackId(m_mp4file, ix, MP4_VIDEO_TRACK_TYPE); const char *media_data_name; media_data_name = MP4GetTrackMediaDataName(m_mp4file, trackId); // for now, treat mp4v and encv the same vq[video_offset].track_id = trackId; vq[video_offset].stream_type = STREAM_TYPE_MP4_FILE; vq[video_offset].compressor = media_data_name; if (strcasecmp(media_data_name, "mp4v") == 0 || strcasecmp(media_data_name, "encv") == 0) { uint8_t video_type = MP4GetTrackEsdsObjectTypeId(m_mp4file, trackId); uint8_t profileID = MP4GetVideoProfileLevel(m_mp4file, trackId); mp4f_message(LOG_DEBUG, "MP4 - got track %x profile ID %d", trackId, profileID); MP4SetVerbosity(m_mp4file, verb & ~(MP4_DETAILS_ERROR)); MP4GetTrackESConfiguration(m_mp4file, trackId, &foo, &bufsize); MP4SetVerbosity(m_mp4file, verb); vq[video_offset].type = video_type; vq[video_offset].profile = profileID; vq[video_offset].fptr = NULL; vq[video_offset].config = foo; vq[video_offset].config_len = bufsize; } else if (strcasecmp(media_data_name, "avc1") == 0) { uint8_t profile, level; uint8_t **seqheader, **pictheader; uint32_t *pictheadersize, *seqheadersize; uint32_t ix; MP4GetTrackH264ProfileLevel(m_mp4file, trackId, &profile, &level); MP4GetTrackH264SeqPictHeaders(m_mp4file, trackId, &seqheader, &seqheadersize, &pictheader, &pictheadersize); bufsize = 0; for (ix = 0; seqheadersize[ix] != 0; ix++) { bufsize += seqheadersize[ix] + 4; } for (ix = 0; pictheadersize[ix] != 0; ix++) { bufsize += pictheadersize[ix] + 4; } foo = (uint8_t *)malloc(bufsize + 4); memset(foo, 0, bufsize + 4); uint32_t copied = 0; // headers do not have the byte stream start code stored in the file for (ix = 0; seqheadersize[ix] != 0; ix++) { foo[copied] = 0; foo[copied + 1] = 0; foo[copied + 2] = 0; foo[copied + 3] = 1; copied += 4; // add header memcpy(foo + copied, seqheader[ix], seqheadersize[ix]); copied += seqheadersize[ix]; free(seqheader[ix]); } free(seqheader); free(seqheadersize); for (ix = 0; pictheadersize[ix] != 0; ix++) { foo[copied] = 0; foo[copied + 1] = 0; foo[copied + 2] = 0; foo[copied + 3] = 1; copied += 4; // add header memcpy(foo + copied, pictheader[ix], pictheadersize[ix]); copied += pictheadersize[ix]; free(pictheader[ix]); } free(pictheader); free(pictheadersize); vq[video_offset].type = level; vq[video_offset].profile = profile; vq[video_offset].fptr = NULL; vq[video_offset].config = foo; vq[video_offset].config_len = bufsize; } else { MP4GetTrackVideoMetadata(m_mp4file, trackId, &foo, &bufsize); vq[video_offset].config = foo; vq[video_offset].config_len = bufsize; } plugin = check_for_video_codec(vq[video_offset].stream_type, vq[video_offset].compressor, NULL, vq[video_offset].type, vq[video_offset].profile, vq[video_offset].config, vq[video_offset].config_len, &config); if (plugin == NULL) { psptr->set_message("Can't find plugin for video %s type %d, profile %d", vq[video_offset].compressor, vq[video_offset].type, vq[video_offset].profile); m_illegal_video_codec++; ret_value = 1; // possibly memleak for foo here } else { vq[video_offset].h = MP4GetTrackVideoHeight(m_mp4file, trackId); vq[video_offset].w = MP4GetTrackVideoWidth(m_mp4file, trackId); vq[video_offset].frame_rate = MP4GetTrackVideoFrameRate(m_mp4file, trackId); vq[video_offset].enabled = 0; vq[video_offset].reference = NULL; video_offset++; } } audio_offset = 0; if (have_audio_driver) { for (ix = 0; ix < audio_count; ix++) { trackId = MP4FindTrackId(m_mp4file, ix, MP4_AUDIO_TRACK_TYPE); const char *media_data_name; media_data_name = MP4GetTrackMediaDataName(m_mp4file, trackId); aq[audio_offset].track_id = trackId; aq[audio_offset].stream_type = STREAM_TYPE_MP4_FILE; aq[audio_offset].compressor = media_data_name; if (strcasecmp(media_data_name, "mp4a") == 0 || strcasecmp(media_data_name, "enca") == 0) { uint8_t *userdata = NULL; u_int32_t userdata_size; aq[audio_offset].type = MP4GetTrackEsdsObjectTypeId(m_mp4file, trackId); MP4SetVerbosity(m_mp4file, verb & ~(MP4_DETAILS_ERROR)); aq[audio_offset].profile = MP4GetAudioProfileLevel(m_mp4file); MP4GetTrackESConfiguration(m_mp4file, trackId, &userdata, &userdata_size); MP4SetVerbosity(m_mp4file, verb); aq[audio_offset].config = userdata; aq[audio_offset].config_len = userdata_size; } plugin = check_for_audio_codec(aq[audio_offset].stream_type, aq[audio_offset].compressor, NULL, aq[audio_offset].type, aq[audio_offset].profile, aq[audio_offset].config, aq[audio_offset].config_len, &config); if (plugin != NULL) { aq[audio_offset].fptr = NULL; aq[audio_offset].sampling_freq = MP4GetTrackTimeScale(m_mp4file, trackId); MP4SetVerbosity(m_mp4file, verb & ~(MP4_DETAILS_ERROR)); aq[audio_offset].chans = MP4GetTrackAudioChannels(m_mp4file, trackId); MP4SetVerbosity(m_mp4file, verb); aq[audio_offset].enabled = 0; aq[audio_offset].reference = NULL; audio_offset++; m_have_audio = true; } else { m_illegal_audio_codec++; ret_value = 1; } } } else { if (audio_count) ret_value = 1; } text_offset = 0; for (ix = 0; ix < text_count; ix++) { trackId = MP4FindTrackId(m_mp4file, ix, MP4_CNTL_TRACK_TYPE); const char *media_data_name; media_data_name = MP4GetTrackMediaDataName(m_mp4file, trackId); tq[text_offset].track_id = trackId; tq[text_offset].stream_type = STREAM_TYPE_MP4_FILE; tq[text_offset].compressor = media_data_name; plugin = check_for_text_codec(tq[text_offset].stream_type, tq[text_offset].compressor, NULL, NULL, 0, &config); if (plugin != NULL) { tq[text_offset].fptr = NULL; tq[text_offset].enabled = 0; tq[text_offset].reference = NULL; text_offset++; } else { m_illegal_text_codec++; ret_value = 1; } } if (video_offset == 0 && audio_offset == 0 && text_offset == 0) { psptr->set_message("No playable codecs in mp4 file"); return -1; } if (cc_vft && cc_vft->media_list_query != NULL) { (cc_vft->media_list_query)(psptr, video_offset, vq, audio_offset, aq, text_offset, tq); } else { if (video_offset > 0) { vq[0].enabled = 1; } if (audio_offset > 0) { aq[0].enabled = 1; } if (text_offset > 0) { tq[0].enabled = 1; } } int vidret, audret, textret; uint start_desc = 1; vidret = create_video(psptr, vq, video_offset, start_desc); free(vq); if (vidret < 0) { free(aq); free(tq); return -1; } audret = create_audio(psptr, aq, audio_offset, start_desc); free(aq); textret = create_text(psptr, tq, text_offset, start_desc); free(tq); if (audret < 0 || textret < 0) ret_value = -1; char *name; verb = MP4GetVerbosity(m_mp4file); MP4SetVerbosity(m_mp4file, verb & ~(MP4_DETAILS_ERROR)); if (MP4GetMetadataName(m_mp4file, &name) && name != NULL) { psptr->set_session_desc(0, name); free(name); } MP4SetVerbosity(m_mp4file, verb); return (ret_value); }
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; }
static void DumpTrack (MP4FileHandle mp4file, MP4TrackId tid, bool dump_off, bool dump_rend) { uint32_t numSamples; MP4SampleId sid; uint8_t *buffer; uint32_t max_frame_size; uint32_t timescale; uint64_t msectime; const char *media_data_name; uint32_t len_size = 0; uint8_t video_type = 0; numSamples = MP4GetTrackNumberOfSamples(mp4file, tid); max_frame_size = MP4GetTrackMaxSampleSize(mp4file, tid) + 4; media_data_name = MP4GetTrackMediaDataName(mp4file, tid); if (strcasecmp(media_data_name, "avc1") == 0) { MP4GetTrackH264LengthSize(mp4file, tid, &len_size); } else if (strcasecmp(media_data_name, "mp4v") == 0) { video_type = MP4GetTrackEsdsObjectTypeId(mp4file, tid); } buffer = (uint8_t *)malloc(max_frame_size); if (buffer == NULL) { printf("couldn't get buffer\n"); return; } timescale = MP4GetTrackTimeScale(mp4file, tid); printf("mp4file %s, track %d, samples %d, timescale %d\n", Mp4FileName, tid, numSamples, timescale); for (sid = 1; sid <= numSamples; sid++) { MP4Timestamp sampleTime; MP4Duration sampleDuration, sampleRenderingOffset; bool isSyncSample = FALSE; bool ret; u_int8_t *temp; uint32_t this_frame_size = max_frame_size; temp = buffer; ret = MP4ReadSample(mp4file, tid, sid, &temp, &this_frame_size, &sampleTime, &sampleDuration, &sampleRenderingOffset, &isSyncSample); msectime = sampleTime; msectime *= TO_U64(1000); msectime /= timescale; printf("sampleId %6d, size %5u time "U64"("U64")", sid, MP4GetSampleSize(mp4file, tid, sid), sampleTime, msectime); if (dump_rend) printf(" %6"U64F, sampleRenderingOffset); if (strcasecmp(media_data_name, "mp4v") == 0) { if (MP4_IS_MPEG4_VIDEO_TYPE(video_type)) ParseMpeg4(temp, this_frame_size, dump_off); } else if (strcasecmp(media_data_name, "avc1") == 0) { ParseH264(temp, this_frame_size, len_size, dump_off); } printf("\n"); } }
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", }; 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: { u_int8_t* pAacConfig = NULL; u_int32_t aacConfigLength; MP4GetTrackESConfiguration(mp4File, trackId, &pAacConfig, &aacConfigLength); if (pAacConfig != NULL && aacConfigLength >= 2) { type = (pAacConfig[0] >> 3) & 0x1f; if (type == 0 || /* type == 5 || */ type == 10 || type == 11 || type == 18 || type >= 28) { typeName = "MPEG-4 Unknown Profile"; } else { typeName = mpeg4AudioNames[type - 1]; foundType = true; } free(pAacConfig); } else { typeName = "MPEG-4 (no GAConfig)"; foundType = true; } break; }