123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688 |
- /*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is MPEG4IP.
- *
- * The Initial Developer of the Original Code is Cisco Systems Inc.
- * Portions created by Cisco Systems Inc. are
- * Copyright (C) Cisco Systems Inc. 2001-2002. All Rights Reserved.
- *
- * Portions created by Ximpo Group Ltd. are
- * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved.
- *
- * Contributor(s):
- * Dave Mackie [email protected]
- * Bill May [email protected]
- * Alix Marchandise-Franquet [email protected]
- * Ximpo Group Ltd. [email protected]
- */
- #include "mp4common.h"
- extern "C" char* MP4PrintAudioInfo(
- 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);
- u_int32_t timeScale = 0;
- 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
- {
- if (type == 2)
- {
- u_int8_t* pAacConfig = NULL;
- u_int32_t aacConfigLength;
- MP4GetTrackESConfiguration(mp4File,
- trackId,
- &pAacConfig,
- &aacConfigLength);
- if (aacConfigLength >= 5 && (pAacConfig[4] >> 7) == 1)
- {
- int samplingRates[]={96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000,-1};
- type = 5;
- int index = (pAacConfig[4] >> 3) & 0x7;
- timeScale = samplingRates[index];
- }
- MP4Free(pAacConfig);
- }
- 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;
- }
- if (!timeScale)
- timeScale = MP4GetTrackTimeScale(mp4File, trackId);
- MP4Duration trackDuration =
- MP4GetTrackDuration(mp4File, trackId);
- double msDuration =
- UINT64_TO_DOUBLE(MP4ConvertFromTrackDuration(mp4File, trackId,
- trackDuration, MP4_MSECS_TIME_SCALE));
- char *sInfo = (char*)MP4Malloc(256);
- // type duration avgBitrate samplingFrequency
- if (foundType)
- snprintf(sInfo, 256,
- "%s",
- typeName);
- else
- snprintf(sInfo, 256,
- "%s(%u)",
- typeName,
- type);
- return sInfo;
- }
- static const struct
- {
- uint8_t profile;
- const char *name;
- }
- VisualProfileToName[] = {
- { MPEG4_SP_L1, "MPEG-4 Simple @ L1"},
- { MPEG4_SP_L2, "MPEG-4 Simple @ L2" },
- { MPEG4_SP_L3, "MPEG-4 Simple @ L3" },
- { MPEG4_SP_L0, "MPEG-4 Simple @ L0" },
- { MPEG4_SSP_L1, "MPEG-4 Simple Scalable @ L1"},
- { MPEG4_SSP_L2, "MPEG-4 Simple Scalable @ L2" },
- { MPEG4_CP_L1, "MPEG-4 Core @ L1"},
- { MPEG4_CP_L2, "MPEG-4 Core @ L2"},
- { MPEG4_MP_L2, "MPEG-4 Main @ L2"},
- { MPEG4_MP_L3, "MPEG-4 Main @ L3"},
- { MPEG4_MP_L4, "MPEG-4 Main @ L4"},
- { MPEG4_NBP_L2, "MPEG-4 N-bit @ L2"},
- { MPEG4_STP_L1, "MPEG-4 Scalable Texture @ L1"},
- { MPEG4_SFAP_L1, "MPEG-4 Simple Face Anim @ L1"},
- { MPEG4_SFAP_L2, "MPEG-4 Simple Face Anim @ L2"},
- { MPEG4_SFBAP_L1, "MPEG-4 Simple FBA @ L1"},
- { MPEG4_SFBAP_L2, "MPEG-4 Simple FBA @ L2"},
- { MPEG4_BATP_L1, "MPEG-4 Basic Anim Text @ L1"},
- { MPEG4_BATP_L2, "MPEG-4 Basic Anim Text @ L2"},
- { MPEG4_HP_L1, "MPEG-4 Hybrid @ L1"},
- { MPEG4_HP_L2, "MPEG-4 Hybrid @ L2"},
- { MPEG4_ARTSP_L1, "MPEG-4 Adv RT Simple @ L1"},
- { MPEG4_ARTSP_L2, "MPEG-4 Adv RT Simple @ L2"},
- { MPEG4_ARTSP_L3, "MPEG-4 Adv RT Simple @ L3"},
- { MPEG4_ARTSP_L4, "MPEG-4 Adv RT Simple @ L4"},
- { MPEG4_CSP_L1, "MPEG-4 Core Scalable @ L1"},
- { MPEG4_CSP_L2, "MPEG-4 Core Scalable @ L2"},
- { MPEG4_CSP_L3, "MPEG-4 Core Scalable @ L3"},
- { MPEG4_ACEP_L1, "MPEG-4 Adv Coding Efficieny @ L1"},
- { MPEG4_ACEP_L2, "MPEG-4 Adv Coding Efficieny @ L2"},
- { MPEG4_ACEP_L3, "MPEG-4 Adv Coding Efficieny @ L3"},
- { MPEG4_ACEP_L4, "MPEG-4 Adv Coding Efficieny @ L4"},
- { MPEG4_ACP_L1, "MPEG-4 Adv Core Profile @ L1"},
- { MPEG4_ACP_L2, "MPEG-4 Adv Core Profile @ L2"},
- { MPEG4_AST_L1, "MPEG-4 Adv Scalable Texture @ L1"},
- { MPEG4_AST_L2, "MPEG-4 Adv Scalable Texture @ L2"},
- { MPEG4_AST_L3, "MPEG-4 Adv Scalable Texture @ L3"},
- { MPEG4_S_STUDIO_P_L1, "MPEG-4 Simple Studio @ L1"},
- { MPEG4_S_STUDIO_P_L2, "MPEG-4 Simple Studio @ L2"},
- { MPEG4_S_STUDIO_P_L3, "MPEG-4 Simple Studio @ L3"},
- { MPEG4_S_STUDIO_P_L4, "MPEG-4 Simple Studio @ L4"},
- { MPEG4_C_STUDIO_P_L1, "MPEG-4 Core Studio @ L1"},
- { MPEG4_C_STUDIO_P_L2, "MPEG-4 Core Studio @ L2"},
- { MPEG4_C_STUDIO_P_L3, "MPEG-4 Core Studio @ L3"},
- { MPEG4_C_STUDIO_P_L4, "MPEG-4 Core Studio @ L4"},
- { MPEG4_ASP_L0, "MPEG-4 Adv Simple@L0"},
- { MPEG4_ASP_L1, "MPEG-4 Adv Simple@L1"},
- { MPEG4_ASP_L2, "MPEG-4 Adv Simple@L2"},
- { MPEG4_ASP_L3, "MPEG-4 Adv Simple@L3"},
- { MPEG4_ASP_L4, "MPEG-4 Adv Simple@L4"},
- { MPEG4_ASP_L5, "MPEG-4 Adv Simple@L5"},
- { MPEG4_ASP_L3B, "MPEG-4 Adv Simple@L3b"},
- { MPEG4_FGSP_L0, "MPEG-4 FGS @ L0" },
- { MPEG4_FGSP_L1, "MPEG-4 FGS @ L1" },
- { MPEG4_FGSP_L2, "MPEG-4 FGS @ L2" },
- { MPEG4_FGSP_L3, "MPEG-4 FGS @ L3" },
- { MPEG4_FGSP_L4, "MPEG-4 FGS @ L4" },
- { MPEG4_FGSP_L5, "MPEG-4 FGS @ L5" }
- };
- static const char *Mpeg4VisualProfileName(uint8_t visual_profile)
- {
- size_t size = sizeof(VisualProfileToName) / sizeof(*VisualProfileToName);
- for (size_t ix = 0; ix < size; ix++)
- {
- if (visual_profile == VisualProfileToName[ix].profile)
- {
- return (VisualProfileToName[ix].name);
- }
- }
- return (NULL);
- }
- extern "C" char* MP4PrintVideoInfo(
- 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 (media_data_name && 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 == 44)
- {
- strcpy(profileb, "CAVLC 4:4:4");
- }
- else 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 || profile == 244)
- {
- 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), "H.264 %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));
- // 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,
- "%s",
- typeName);
- }
- else
- {
- sprintf(sInfo,
- "%s(%u)",
- typeName,
- type);
- }
- return sInfo;
- }
- 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\r\n",
- trackId,
- typeName,
- msDuration / 1000.0);
- return sInfo;
- }
- 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\r\n",
- trackId,
- payloadName,
- referenceTrackId);
- free(payloadName);
- return sInfo;
- }
- #if 0
- 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\r\n",
- trackId);
- }
- else if (!strcmp(trackType, MP4_SCENE_TRACK_TYPE))
- {
- snprintf(trackInfo, 256,
- "%u\tscene\tBIFS\r\n",
- trackId);
- }
- else
- {
- snprintf(trackInfo, 256,
- "%u\t%s\r\n",
- trackId, trackType);
- }
- }
- return trackInfo;
- }
- extern "C" char* MP4Info(
- MP4FileHandle mp4File,
- MP4TrackId trackId)
- {
- char* info = NULL;
- if (MP4_IS_VALID_FILE_HANDLE(mp4File))
- {
- try
- {
- if (trackId == MP4_INVALID_TRACK_ID)
- {
- uint buflen = 4 * 1024;
- info = (char*)MP4Calloc(buflen);
- buflen -= snprintf(info, buflen,
- "Track\tType\tInfo\r\n");
- u_int32_t numTracks = MP4GetNumberOfTracks(mp4File);
- for (u_int32_t i = 0; i < numTracks; i++)
- {
- trackId = MP4FindTrackId(mp4File, i);
- char* trackInfo = PrintTrackInfo(mp4File, trackId);
- strncat(info, trackInfo, buflen);
- uint newlen = strlen(trackInfo);
- if (newlen > buflen) buflen = 0;
- else buflen -= newlen;
- MP4Free(trackInfo);
- }
- }
- else
- {
- info = PrintTrackInfo(mp4File, trackId);
- }
- }
- catch (MP4Error* e)
- {
- delete e;
- }
- }
- return info;
- }
- extern "C" char* MP4FileInfo(
- const MP4_FILENAME_CHAR* fileName,
- MP4TrackId trackId)
- {
- MP4FileHandle mp4File =
- MP4Read(fileName);
- if (!mp4File)
- {
- return NULL;
- }
- char* info = MP4Info(mp4File, trackId);
- MP4Close(mp4File);
- return info; // caller should free this
- }
- #endif
|