diff 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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IM_AF Decoder/IM_AF_Decoder.c	Wed Jul 04 22:16:23 2012 +0100
@@ -0,0 +1,718 @@
+#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, &param->MajorBrand, &minorVersion); if(err) goto bail;
+	 err = ISOGetNbCompatableBrands(decoder->moov, &param->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, &timescale); 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);
+}
\ No newline at end of file