-
Notifications
You must be signed in to change notification settings - Fork 37
Creating an MP4 file
Dimitri Podborski edited this page Sep 17, 2020
·
1 revision
This example demonstrates creating an MP4 Movie, adding audio samples to it, and saving the movie to a file.
In a nutshell, there are ten things to do:
- #include ISOMovies.h
- Link with libisomediafile
- Create a new Movie
- Create a Track for each elementary stream
- Create Media for each elementary stream
- Begin Media edits for each Media
- Add samples to each Media
- End Media edits for each Media
- Insert each Media into its track
- Write the Movie to a file
This will now be demonstrated in code listings.
#include "ISOMovies.h"
ISOErr createMyMovie( char *filename )
{
ISOErr err;
ISOMovie moov;
ISOTrack trak;
ISOMedia media;
u32 initialObjectDescriptorID;
u8 OD_profileAndLevel;
u8 scene_profileAndLevel;
u8 audio_profileAndLevel;
u8 visual_profileAndLevel;
u8 graphics_profileAndLevel;
u64 mediaDuration;
err = ISONoErr;
initialObjectDescriptorID = 1;
OD_profileAndLevel = 0xff; /* none required */
scene_profileAndLevel = 0xff; /* none required */
audio_profileAndLevel = 0x01; /* main profile L1 */
visual_profileAndLevel = 0xff; /* none required */
graphics_profileAndLevel = 0xff; /* none required */
err = MP4NewMovie( &moov,
initialObjectDescriptorID,
OD_profileAndLevel,
scene_profileAndLevel,
audio_profileAndLevel,
visual_profileAndLevel,
graphics_profileAndLevel );
err = ISONewMovieTrack( moov, ISONewTrackIsAudio, &trak);
err = MP4AddTrackToMovieIOD( trak );
err = ISONewTrackMedia( trak, &media,
ISOAudioHandlerType, 48000, NULL);
err = ISOBeginMediaEdits( media );
err = addMySamples( trak, media ); /* see next listing */
err = ISOGetMediaDuration( media, &mediaDuration );
err = ISOEndMediaEdits( media );
err = ISOInsertMediaIntoTrack( trak, 0, 0, mediaDuration, 1 );
err = ISOWriteMovieToFile( moov, filename );
err = ISODisposeMovie( moov );
return err;
}
Important things to note from above listing:
- You specify profiles and levels when you create the movie. The constants used are those from the Systems part of MPEG-4.
- When you create Media for a Track, you must specify the media time scale and the location of the samples. In this case we set the time scale to the audio sampling rate (48000) and set the media data reference to NULL, which indicates that the media samples will be placed in the movie file.
- You must also specify a handler type for the Media. In this case we choose ISOAudioHandlerType. This is an enumeration from ISOMovies.h and is not to be confused with stream type, which you will set in Listing 2.
- We add the track into the IOD. Normally this would be done only for BIFS and OD tracks, in full MPEG-4 presentations.
#include "ISOMovies.h"
ISOErr addMySamples( ISOTrack trak, ISOMedia media )
{
ISOErr err;
ISOHandle sampleEntryH;
ISOHandle sampleDataH;
ISOHandle sampleDurationH;
ISOHandle sampleSizeH;
ISOHandle decoderSpecificInfoH;
err = ISOSetMediaLanguage( media, "und" );
/* undetermined */
decoderSpecificInfoH = NULL; /* put stuff here */
err = ISONewHandle( 0, &sampleEntryH );
err = MP4NewSampleDescription( trak, sampleEntryH, 1,
0x40, /* mpeg-4 audio */
0x05, /* audio stream */
8192, /* dec buf size */
64000, 64000, /* bitrates */
decoderSpecificInfoH );
err = ISONewHandle( sizeof(u32), &sampleDurationH );
*((u32*) *sampleDurationH) = 1024;
err = ISONewHandle( 0, &sampleDataH );
err = ISONewHandle( sizeof(u32), &sampleSizeH );
for ( ;; )
{
err = getNextAudioFrame( sampleDataH );
if ( err )
{
if ( err == ISOEOF ) err = 0;
break;
}
err = ISOGetHandleSize( sampleDataH,
(u32*) *sampleSizeH );
// Adding 1 sample at a time means 1-sample chunks
// which is VERY INEFFICIENT with file space
// Don’t just copy this code!
err = ISOAddMediaSamples( media, sampleDataH, 1,
sampleDurationH,
sampleSizeH,
sampleEntryH, NULL, NULL );
// NOTE adding 1 sample at a time like this is a BAD IDEA
if ( sampleEntryH )
{
err = ISODisposeHandle( sampleEntryH );
sampleEntryH = NULL;
}
}
err = ISODisposeHandle(sampleDataH);
err = ISODisposeHandle(sampleSizeH);
err = ISODisposeHandle(sampleDurationH);
return err;
}
Items of interest from above listing:
- All Media tracks have an associated language, set using the ISO 639-2/T three-letter code. In this case we use "und" to indicate that the language is undetermined.
- You must make a Handle and fill it with your decoder specific info. Make sure that you properly encode this, and it is truly a decoderSpecificInfo descriptor (including tag and length fields) as defined in the Systems specification. If your decoder doesn’t use specific info you can set this handle to NULL.
- There is a function provided that helps you make SampleDescriptions. This prevents you from having to understand Elementary Stream descriptors and a few other of the descriptors from the Systems spec. Make sure that you set the object and stream types appropriately. This is the only way the MPEG-4 terminal can determine which decoder to send your stream to.
- Samples are added using ISOAddMediaSamples. This function has several parameters that allow for all the flexibility that MPEG-4 needs, including setting different decoding and composition time stamps. It is typical to supply NULL for some of these parameters. You can add as many samples as you like with one call to this function. Unless you are changing decoders or configuration you can ordinarily associate a single sample description with all samples. To do this we set the sample description handle to NULL for all calls after the initial one.
- Warning: with the current implementation what you create for each call to add media samples is a ’chunk,’ which probably works best when it contains about 1/2 second of data. Each call adds some metadata to the file, so grouping samples helps reduce file size. This advice is not heeded in this listing 2: this simple example adds one sample per chunk, which results in very poorly optimized files (but an easy to read example). In your actual program, you should interleave your calls to add samples to the various tracks, so that (a) each call adds a reasonable amount of data – perhaps half a second and (b) you add data for all the tracks at the same time instant roughly in parallel – this ensures that the media data is roughly in time-order in the file.
How to use
API documentation single page
- Data Types
- Movie related functions
- Track related functions
- Media related functions
- MPEG sample auxiliary information functions
- MPEG sync-layer functions
- MPEG SLConfig functions
- General Sample Description functions
- AVC Sample Description functions
- MetaData Sample Description functions
- Meta data functions
- Track reader functions
- MPEG-4 IPMPX related functions
- ISMACrypt Support
- Utility functions