Mercurial > hg > enc-imaf
view IM_AF Decoder/IM_AF_Decoder.c @ 0:138a3cea9792
Different files related to my project, including the encoder (I made it) and decoder. Also I added the mp4atoms as an example.
MP4atoms belong to the IMAF player library.
| author | Eugenio Oñate Hospital <eo301@eecs.qmul.ac.uk> |
|---|---|
| date | Wed, 04 Jul 2012 22:16:23 +0100 |
| parents | |
| children |
line wrap: on
line source
#include "MP4Movies.h" #include "MP4LinkedList.h" #include "MP4InputStream.h" #include "IM_AF_Decoder.h" #ifndef BAILWITHERROR #define BAILWITHERROR(v) \ { \ err = (v); \ goto bail; \ } #endif typedef struct IMAFDecoder { u8 *InputMafFilename; FILE *InputFp; u32 TrackCount; // u32 CompletedTrackCount; u32 HasTimedTextTrack; MP4Movie moov; MP4Track trak; MP4Media media; u32 MovieTimescale; u32 MovieDuration; // Multi audio track MP4LinkedList TrackReaderList; // for all Track MP4LinkedList TrackSampleList; // for all Track Sample MP4TrackReader TimedTextTrackReader; MP4Handle TimedTextSampleH; MP4Handle TextH; u32 TimedTextTrackIndex; TextSampleStyleParam *TextParam; unsigned int HasSaocTrack; }IMAFDecoder; void InitTextSampleStyleParam(TextSampleStyleParam *TextParam) { if(TextParam) { if(TextParam->styl_text_styles) free(TextParam->styl_text_styles); if(TextParam->krok_highlight_end_time) free(TextParam->krok_highlight_end_time); if(TextParam->krok_startcharoffset) free(TextParam->krok_startcharoffset); if(TextParam->krok_endcharoffset) free(TextParam->krok_endcharoffset); if(TextParam->font) free(TextParam->font); memset(TextParam, 0, sizeof(TextSampleStyleParam)); } } IMAF_DECODER_API IMAF_Err IMAF_Decoder_Create(IMAF_DecoderH *IMafDecoder, IMAF_Decoder_Param *param) { IMAFDecoder *decoder = NULL; MP4Err err; u32 i; u32 sample_desc_type; MP4TrackReader reader; MP4Handle sampleH; u32 minorVersion; decoder = calloc(1, sizeof(IMAFDecoder)); if(param == NULL || param->InputMafFilename == NULL) { err = MP4BadParamErr; goto bail; } else decoder->InputMafFilename = _strdup(param->InputMafFilename); err = MP4OpenMovieFile( &decoder->moov, decoder->InputMafFilename, MP4OpenMovieInPlace ); if (err) goto bail; err = MP4GetMovieTrackCount( decoder->moov, &decoder->TrackCount); if(err) goto bail; //Timed Text for(i=0; i<decoder->TrackCount; i++) { err = MP4GetMovieIndTrack( decoder->moov, i+1, &decoder->trak ); if (err) goto bail; err = MP4GetTrackMedia( decoder->trak, &decoder->media ); if (err) goto bail; err = MP4GetMediaSampleDescriptionType(decoder->media, &sample_desc_type); if(err) goto bail; if(sample_desc_type == 'tx3g') { decoder->HasTimedTextTrack = 1; decoder->TimedTextTrackIndex = i; break; } } param->HasTimedTextTrack = decoder->HasTimedTextTrack; param->NumberOfAudioTrack = decoder->TrackCount - decoder->HasTimedTextTrack; err = MP4GetMovieTimeScale(decoder->moov, &decoder->MovieTimescale); if(err) goto bail; param->MovieTimescale = decoder->MovieTimescale; err = MP4GetMovieDuration(decoder->moov, (u64*)&decoder->MovieDuration); if(err) goto bail; param->MovieDuration = decoder->MovieDuration; // Create TrackReader for all Track err = MP4MakeLinkedList( &decoder->TrackReaderList); if(err) goto bail; err = MP4MakeLinkedList( &decoder->TrackSampleList); if(err) goto bail; for(i=0; i<decoder->TrackCount; i++) { err = MP4GetMovieIndTrack( decoder->moov, i+1, &decoder->trak ); if (err) goto bail; if(decoder->HasTimedTextTrack && decoder->TimedTextTrackIndex == i) { err = MP4CreateTrackReader( decoder->trak, &reader ); if (err) goto bail; decoder->TimedTextTrackReader = reader; } else { err = MP4CreateTrackReader( decoder->trak, &reader ); if (err) goto bail; err = MP4AddListEntry( reader, decoder->TrackReaderList); if (err) goto bail; err = MP4NewHandle(0, &sampleH); if(err) goto bail; err = MP4AddListEntry( sampleH, decoder->TrackSampleList); if (err) goto bail; } } err = MP4NewHandle(0, &decoder->TimedTextSampleH); if(err) goto bail; err = MP4NewHandle(0, &decoder->TextH); if(err) goto bail; decoder->TextParam = calloc(1, sizeof(TextSampleStyleParam)); err = ISOGetMovieBrand(decoder->moov, ¶m->MajorBrand, &minorVersion); if(err) goto bail; err = ISOGetNbCompatableBrands(decoder->moov, ¶m->NumberOfCompatibleBrands); if(err) goto bail; if(param->NumberOfCompatibleBrands) { param->CompatibleBrands = calloc(param->NumberOfCompatibleBrands, sizeof(u32)); err = ISOGetCompatableBrands(decoder->moov, param->CompatibleBrands); if(err) goto bail; } else param->CompatibleBrands = NULL; *IMafDecoder = decoder; bail: TEST_RETURN( err ); return err; } IMAF_DECODER_API IMAF_Err IMAF_Decoder_GetAudioTrackInfos(IMAF_DecoderH IMafDecoder, unsigned int *AudioTrackObjectTypeArray ,unsigned int *AudioTrackIdArray, IMAF_AudioParam *AudioParamArray) { IMAFDecoder *decoder = (IMAFDecoder*) IMafDecoder; IMAF_Err err; u32 i; u32 outObjectType, sample_desc_type; u32 hasTimedText = 0; u32 trackID; unsigned int nBitsPerSample; unsigned int nChannels; unsigned int nSamplingFrequency; for(i=0; i<decoder->TrackCount - decoder->HasTimedTextTrack; i++) { err = MP4GetMovieIndTrack( decoder->moov, i+1, &decoder->trak ); if (err) goto bail; err = MP4GetTrackMedia( decoder->trak, &decoder->media ); if (err) goto bail; err = MP4GetMediaSampleDescriptionType(decoder->media, &sample_desc_type); if(err) goto bail; if(sample_desc_type == 'mp4a') { err = MP4GetTrackID(decoder->trak, &trackID); if(err) goto bail; AudioTrackIdArray[i - hasTimedText] = trackID; err = MP4GetMediaDecoderType( decoder->media, 1, &outObjectType, NULL, NULL, NULL ); if(err) goto bail; if(outObjectType == AUDIO_OBJECT_TYPE_INDICATION_MP3 || outObjectType == AUDIO_OBJECT_TYPE_INDICATION_AAC || outObjectType == AUDIO_OBJECT_TYPE_INDICATION_SAOC|| outObjectType == AUDIO_OBJECT_TYPE_INDICATION_PCM) { AudioTrackObjectTypeArray[i - hasTimedText] = outObjectType; if(outObjectType = AUDIO_OBJECT_TYPE_INDICATION_SAOC) decoder->HasSaocTrack = 1; } else BAILWITHERROR(MP4BadDataErr) err = MP4GetSampleRateChannelBitsPerSample(decoder->media, &nSamplingFrequency, &nChannels, &nBitsPerSample); if(err) goto bail; AudioParamArray[i].nSamplingFrequency = nSamplingFrequency; AudioParamArray[i].nChannels = nChannels; AudioParamArray[i].nBitsPerSample = nBitsPerSample; } else { hasTimedText = 1; } } bail: TEST_RETURN( err ); return err; } IMAF_DECODER_API IMAF_Err IMAF_Decoder_GetGroupContainerInfo(IMAF_DecoderH IMafDecoder, unsigned int *GroupCount) { IMAFDecoder *decoder = (IMAFDecoder*) IMafDecoder; IMAF_Err err; err = MP4GetGroupContainerInfo(decoder->moov, GroupCount); if(err) goto bail; bail: TEST_RETURN( err ); return err; } IMAF_DECODER_API IMAF_Err IMAF_Decoder_GetGroupByIndex(IMAF_DecoderH IMafDecoder, unsigned int i, IMAF_Group *grup) { IMAFDecoder *decoder = (IMAFDecoder*) IMafDecoder; IMAF_Err err; unsigned int *element_ID; char *group_name; char *group_description; err = MP4GetGroupByIndex(decoder->moov, i, &grup->group_ID, &grup->num_elements, &element_ID, &grup->group_activation_mode, &grup->group_activation_elements_number, &grup->group_reference_volume, &group_name, &group_description); if(err) goto bail; grup->element_ID =(u32*) calloc( grup->num_elements, sizeof(u32) ); memcpy(grup->element_ID, element_ID, sizeof(u32)*grup->num_elements); if(group_name) grup->group_name = _strdup(group_name); else grup->group_name = NULL; if(group_description) grup->group_description = _strdup(group_description); else grup->group_description = NULL; bail: TEST_RETURN( err ); return err; } IMAF_DECODER_API IMAF_Err IMAF_Decoder_GetPresetContainerInfo(IMAF_DecoderH IMafDecoder, unsigned int *num_preset, unsigned int *default_preset_ID) { IMAFDecoder *decoder = (IMAFDecoder*) IMafDecoder; IMAF_Err err; err = MP4GetPresetContainerInfo(decoder->moov, num_preset, default_preset_ID); if(err) goto bail; bail: TEST_RETURN( err ); return err; } IMAF_DECODER_API IMAF_Err IMAF_Decoder_GetPresetByIndex(IMAF_DecoderH IMafDecoder, unsigned int i, IMAF_Preset *prst) { IMAFDecoder *decoder = (IMAFDecoder*) IMafDecoder; IMAF_Err err; u32 *preset_element_ID; u32 *preset_volume_element; u32 *num_input_channel; u32 *updated_sample_number; char *preset_name; u32 ii; u32 element_count; err = MP4GetPresetByIndex(decoder->moov, i, &prst->preset_ID, &prst->num_preset_elements, &preset_element_ID, &prst->preset_type, &prst->preset_global_volume, &preset_volume_element, &num_input_channel , &prst->output_channel_type , &prst->num_output_channel , &prst->num_updates , &updated_sample_number, &preset_name); if(err) goto bail; prst->preset_element_ID =(u32*) calloc( prst->num_preset_elements, sizeof(u32) ); memcpy(prst->preset_element_ID, preset_element_ID, sizeof(u32)*prst->num_preset_elements); if(prst->preset_type == 0) { element_count = prst->num_preset_elements; prst->preset_volume_element =(u32*) calloc( element_count, sizeof(u32) ); for(ii=0; ii<element_count; ii++) prst->preset_volume_element[ii] = preset_volume_element[ii]*2; } else if(prst->preset_type == 1) { element_count = prst->num_preset_elements*num_input_channel[0]*prst->num_output_channel; prst->preset_volume_element =(u32*) calloc( element_count, sizeof(u32) ); for(ii=0; ii<element_count; ii++) prst->preset_volume_element[ii] = preset_volume_element[ii]*2; } else if(prst->preset_type == 2) { element_count = prst->num_preset_elements * prst->num_updates; prst->preset_volume_element =(u32*) calloc( element_count, sizeof(u32) ); for(ii=0; ii<element_count; ii++) prst->preset_volume_element[ii] = preset_volume_element[ii]*2; } else if(prst->preset_type == 3) { element_count = prst->num_updates*prst->num_preset_elements*num_input_channel[0]*prst->num_output_channel; prst->preset_volume_element =(u32*) calloc( element_count, sizeof(u32) ); for(ii=0; ii<element_count; ii++) prst->preset_volume_element[ii] = preset_volume_element[ii]*2; } if(num_input_channel) { prst->num_input_channel =(u32*) calloc( prst->num_preset_elements, sizeof(u32) ); memcpy(prst->num_input_channel, num_input_channel, sizeof(u32)*prst->num_preset_elements); } else prst->num_input_channel = NULL; if(updated_sample_number) { prst->updated_sample_number =(u32*) calloc( prst->num_updates, sizeof(u32) ); memcpy(prst->updated_sample_number, updated_sample_number, sizeof(u32)*prst->num_updates); } else prst->updated_sample_number = NULL; if(preset_name) prst->preset_name = _strdup(preset_name); else prst->preset_name = NULL; bail: TEST_RETURN( err ); return err; } IMAF_DECODER_API IMAF_Err IMAF_Decoder_GetRuleContainerInfo(IMAF_DecoderH IMafDecoder, unsigned int *num_selection_rules, unsigned int *num_mixing_rules) { IMAFDecoder *decoder = (IMAFDecoder*) IMafDecoder; IMAF_Err err; err = MP4GetRuleContainerInfo(decoder->moov, num_selection_rules, num_mixing_rules); if(err) goto bail; bail: TEST_RETURN( err ); return err; } IMAF_DECODER_API IMAF_Err IMAF_Decoder_GetSelectionRuleByIndex(IMAF_DecoderH IMafDecoder, unsigned int i, IMAF_SelectionRule *rusc) { IMAFDecoder *decoder = (IMAFDecoder*) IMafDecoder; IMAF_Err err; char *selection_rule_description; err = MP4GetSelectionRuleByIndex(decoder->moov, i, &rusc->selection_rule_ID, &rusc->selection_rule_type, &rusc->element_ID, &rusc->min_num_elements, &rusc->max_num_elements, &rusc->key_element_ID, &selection_rule_description); if(err) goto bail; if(selection_rule_description) rusc->selection_rule_description = _strdup(selection_rule_description); else rusc->selection_rule_description = NULL; bail: TEST_RETURN( err ); return err; } IMAF_DECODER_API IMAF_Err IMAF_Decoder_GetMixingRuleByIndex(IMAF_DecoderH IMafDecoder, unsigned int i, IMAF_MixingRule *rumx) { IMAFDecoder *decoder = (IMAFDecoder*) IMafDecoder; IMAF_Err err; char *mixing_rule_description; err = MP4GetMixingRuleByIndex(decoder->moov, i, &rumx->mixing_rule_ID, &rumx->mixing_rule_type, &rumx->element_ID, &rumx->min_volume, &rumx->max_volume, &rumx->key_element_ID, &mixing_rule_description); if(err) goto bail; if(mixing_rule_description) rumx->mixing_rule_description = _strdup(mixing_rule_description); else rumx->mixing_rule_description = NULL; bail: TEST_RETURN( err ); return err; } IMAF_DECODER_API IMAF_Err IMAFDecoder_SeekSample(IMAF_DecoderH IMafDecoder, unsigned int mediaTime) { IMAFDecoder *decoder = (IMAFDecoder*) IMafDecoder; IMAF_Err err; u32 timescale, i; MP4TrackReader reader; err = MP4GetMediaTimeScale(decoder->media, ×cale); if(err) goto bail; mediaTime /= 1000; //in miliseconds mediaTime *= timescale; for(i=0; i<decoder->TrackCount - decoder->HasTimedTextTrack; i++) { err = MP4GetListEntry(decoder->TrackReaderList, i, (char**)&reader); if(err) goto bail; err = MP4TrackReaderSeekToSyncSample( reader, mediaTime); if(err) goto bail; } if(decoder->TimedTextTrackReader) { err = MP4TrackReaderSeekToSyncSample( decoder->TimedTextTrackReader, mediaTime); if(err) goto bail; } bail: TEST_RETURN( err ); return err; } IMAF_DECODER_API IMAF_Err IMAFDecoder_GetNextAudioSampleByIndex(IMAF_DecoderH IMafDecoder, unsigned int i, unsigned char **SampleData, unsigned int *SampleDataSize, unsigned int *CurrentTime, unsigned int *sampleNumber) { IMAFDecoder *decoder = (IMAFDecoder*) IMafDecoder; IMAF_Err err; MP4TrackReader reader; MP4Handle sampleH; u32 unitSize; u32 sampleFlags; u32 cts; u32 dts; if(i >= decoder->TrackCount - decoder->HasTimedTextTrack) BAILWITHERROR(MP4BadParamErr) err = MP4GetListEntry(decoder->TrackReaderList, i, (char**)&reader); if(err) goto bail; err = MP4GetListEntry(decoder->TrackSampleList, i, (char**)&sampleH); if(err) goto bail; err = MP4TrackReaderGetNextAccessUnitWithSampleNumber( reader, sampleH, &unitSize,&sampleFlags, &cts, &dts, sampleNumber); if ( err ) { if ( err == MP4EOF ) { *SampleData = NULL; *SampleDataSize = 0; *CurrentTime = 0; err = MP4NoErr; } else goto bail; } *CurrentTime = dts; *SampleData = *sampleH; *SampleDataSize = unitSize; bail: TEST_RETURN( err ); return err; } IMAF_DECODER_API IMAF_Err IMAFDecoder_GetNextTextSample(IMAF_DecoderH IMafDecoder, unsigned char **SampleData, unsigned int *SampleDataSize, unsigned int *CurrentTime, TextSampleStyleParam **param) { IMAFDecoder *decoder = (IMAFDecoder*) IMafDecoder; IMAF_Err err; u32 unitSize; u32 sampleFlags; u32 cts; u32 dts; u32 i; u8 *TextSample; MP4InputStreamPtr is; u32 TextModifiersSize, TotalAtomSize; MP4AtomPtr entry; TextStyleAtomPtr styl; TextHighlightAtomPtr hlit; TextHighlightColorAtomPtr hclr; TextKaraokeAtomPtr krok; TextSampleEntryValue tx3g_value; err = MP4TrackReaderGetNextAccessUnit(decoder->TimedTextTrackReader, decoder->TimedTextSampleH, &unitSize, &sampleFlags, &cts, &dts); if ( err ) { if ( err == MP4EOF ) { *SampleData = NULL; *SampleDataSize = 0; *CurrentTime = 0; return MP4EOF; } else goto bail; } err = MP4TrackReaderGetTextSampleEntryValues(decoder->TimedTextTrackReader, &tx3g_value); if(err) goto bail; #if 0 //only text *CurrentTime = dts; *SampleData = *decoder->TimedTextSampleH; *SampleDataSize = unitSize; #else *CurrentTime = dts; TextSample = *decoder->TimedTextSampleH; *SampleDataSize = TextSample[0]<<8 | TextSample[1]; TextSample+=2; MP4SetHandleSize(decoder->TextH, *SampleDataSize+1); memcpy(*decoder->TextH, TextSample, *SampleDataSize); TextSample += *SampleDataSize; (*decoder->TextH)[*SampleDataSize] = '\0'; *SampleData = *decoder->TextH; //Extract Text Style InitTextSampleStyleParam(decoder->TextParam); decoder->TextParam->displayFlags= tx3g_value.displayFlags; decoder->TextParam->horizontal_justification= tx3g_value.horizontal_justification; decoder->TextParam->vertical_justification= tx3g_value.vertical_justification; decoder->TextParam->background_color_r= tx3g_value.background_color_r; decoder->TextParam->background_color_g= tx3g_value.background_color_g; decoder->TextParam->background_color_b= tx3g_value.background_color_b; decoder->TextParam->background_color_a= tx3g_value.background_color_a; decoder->TextParam->default_text_box_top= tx3g_value.default_text_box_top; decoder->TextParam->default_text_box_left= tx3g_value.default_text_box_left; decoder->TextParam->default_text_box_bottom= tx3g_value.default_text_box_bottom; decoder->TextParam->default_text_box_right= tx3g_value.default_text_box_right; decoder->TextParam->default_style_startChar= tx3g_value.default_style_startChar; decoder->TextParam->default_style_endChar= tx3g_value.default_style_endChar; decoder->TextParam->default_style_font_ID= tx3g_value.default_style_font_ID; decoder->TextParam->default_style_face_style_flags= tx3g_value.default_style_face_style_flags; decoder->TextParam->default_style_font_size= tx3g_value.default_style_font_size; decoder->TextParam->default_style_text_color_r= tx3g_value.default_style_text_color_r; decoder->TextParam->default_style_text_color_g= tx3g_value.default_style_text_color_g; decoder->TextParam->default_style_text_color_b= tx3g_value.default_style_text_color_b; decoder->TextParam->default_style_text_color_a= tx3g_value.default_style_text_color_a; decoder->TextParam->font_ID= tx3g_value.font_ID; decoder->TextParam->font_name_length= tx3g_value.font_name_length; decoder->TextParam->font= _strdup(tx3g_value.font); free(tx3g_value.font); TotalAtomSize= 0; TextModifiersSize = unitSize - 2 - *SampleDataSize; err = MP4CreateMemoryInputStream(TextSample, TextModifiersSize, &is ); if (err) goto bail; is->debugging = 0; while(TextModifiersSize>TotalAtomSize) { err = MP4ParseAtom( is, &entry ); if (err) goto bail; TotalAtomSize += entry->size; if(entry->type == 'styl') { StyleRecordStructPtr styleRecord; styl = (TextStyleAtomPtr)entry; decoder->TextParam->styl_entry_count = styl->entry_count; decoder->TextParam->styl_text_styles = (StyleRecord*)calloc(styl->entry_count, sizeof(styleRecord)); for(i=0; i<styl->entry_count; i++) { err = MP4GetListEntry(styl->styleRecordList, i, (char**)&styleRecord); if(err) goto bail; memcpy(&decoder->TextParam->styl_text_styles[i], styleRecord, sizeof(StyleRecord)); } } else if(entry->type == 'hlit') { hlit = (TextHighlightAtomPtr)entry; decoder->TextParam->hlit_startcharoffset = hlit->startcharoffset; decoder->TextParam->hlit_endcharoffset = hlit->endcharoffset; } else if(entry->type == 'hclr') { hclr = (TextHighlightColorAtomPtr)entry; decoder->TextParam->hclr_highlight_color_r = hclr->highlight_color_r; decoder->TextParam->hclr_highlight_color_g = hclr->highlight_color_g; decoder->TextParam->hclr_highlight_color_b = hclr->highlight_color_b; decoder->TextParam->hclr_highlight_color_a = hclr->highlight_color_a; } else if(entry->type == 'krok') { krok = (TextKaraokeAtomPtr)entry; decoder->TextParam->krok_highlight_start_time = krok->highlight_start_time; decoder->TextParam->krok_entry_count = krok->entry_count; decoder->TextParam->krok_highlight_end_time = calloc(krok->entry_count, sizeof(u32)); decoder->TextParam->krok_startcharoffset= calloc(krok->entry_count, sizeof(u32)); decoder->TextParam->krok_endcharoffset = calloc(krok->entry_count, sizeof(u32)); for(i=0; i<krok->entry_count; i++) { decoder->TextParam->krok_highlight_end_time[i] =krok->highlight_end_time[i]; decoder->TextParam->krok_startcharoffset[i] = krok->startcharoffset[i]; decoder->TextParam->krok_endcharoffset[i] = krok->endcharoffset[i]; } } else { BAILWITHERROR(MP4NotImplementedErr) } entry->destroy(entry); } if (is) { is->destroy( is ); is = NULL; } *param = decoder->TextParam; #endif bail: TEST_RETURN( err ); return err; } IMAF_DECODER_API IMAF_Err IMAFDecoder_GetDsiByIndex(IMAF_DecoderH IMafDecoder, unsigned int i, char** dsi, unsigned int *dsiSize) { IMAFDecoder *decoder = (IMAFDecoder*) IMafDecoder; IMAF_Err err; MP4TrackReader reader; MP4Handle specificInfoH; err = MP4GetListEntry(decoder->TrackReaderList, i, (char**)&reader); if(err) goto bail; err = MP4NewHandle(0, &specificInfoH); if(err) goto bail; err = MP4TrackReaderGetCurrentDecoderSpecificInfo(reader, specificInfoH); if(err) goto bail; err = MP4GetHandleSize(specificInfoH, dsiSize); *dsi = (u8*)malloc(*dsiSize); memcpy(*dsi, *specificInfoH, *dsiSize); err = MP4DisposeHandle(specificInfoH); if(err) goto bail; bail: TEST_RETURN( err ); return err; } IMAF_DECODER_API IMAF_Err IMAFDecoder_GetSongImage(IMAF_DecoderH IMafDecoder, unsigned char **image, unsigned int *imageSize) { IMAFDecoder *decoder = (IMAFDecoder*) IMafDecoder; IMAF_Err err; u8 *content_type; err = MP4GetMovieIndTrack( decoder->moov, 1, &decoder->trak ); if (err) goto bail; err = MP4GetTrackMedia( decoder->trak, &decoder->media ); if (err) goto bail; err = MP4_GetImageByItemId(decoder->moov, decoder->media, image, imageSize, &content_type, 1); if(err) goto bail; bail: TEST_RETURN( err ); return err; } IMAF_DECODER_API IMAF_Err IMAFDecoder_GetMetadata(IMAF_DecoderH IMafDecoder, unsigned char **Meta, unsigned int *MetaSize) { IMAFDecoder *decoder = (IMAFDecoder*) IMafDecoder; IMAF_Err err; err = MP4GetMetaXml(decoder->moov, Meta, MetaSize); if(err) goto bail; bail: TEST_RETURN( err ); return err; } IMAF_DECODER_API IMAF_Err IMAF_Decoder_Destroy(IMAF_DecoderH IMafDecoder) { IMAFDecoder *decoder = (IMAFDecoder*) IMafDecoder; IMAF_Err err; if(decoder) { if(decoder->InputMafFilename) { free(decoder->InputMafFilename); decoder->InputMafFilename = NULL; } if(decoder->TrackReaderList) { u32 i; MP4TrackReader reader; MP4Handle sampleH; for(i=0; i<decoder->TrackCount - decoder->HasTimedTextTrack; i++) { err = MP4GetListEntry(decoder->TrackReaderList, i, (char**)&reader); if(err) goto bail; err = MP4DisposeTrackReader(reader); if(err) goto bail; err = MP4GetListEntry(decoder->TrackSampleList, i, (char**)&sampleH); if(err) goto bail; err = MP4DisposeHandle(sampleH); if(err) goto bail; } err = MP4DeleteLinkedList(decoder->TrackReaderList); if(err) goto bail; err = MP4DeleteLinkedList(decoder->TrackSampleList); if(err) goto bail; decoder->TrackReaderList = NULL; decoder->TrackSampleList = NULL; } if(decoder->TimedTextSampleH) MP4DisposeHandle(decoder->TimedTextSampleH); if(decoder->TextH) MP4DisposeHandle(decoder->TextH); if(decoder->TimedTextTrackReader) MP4DisposeTrackReader(decoder->TimedTextTrackReader); if(decoder->TextParam) { InitTextSampleStyleParam(decoder->TextParam); free(decoder->TextParam); } if(decoder->moov) { err = MP4DisposeMovie( decoder->moov ); if(err) goto bail; } free(decoder); } bail: return err; } IMAF_DECODER_API char* IMAF_Decoder_GetLastError(IMAF_Err err) { return MP4GetLastError(err); }
