/*
 *			GPAC - MPEG-4 Systems C Development Kit
 *
 *			Copyright (c) Jean Le Feuvre 2000-2005 
 *					All rights reserved
 *
 *  This file is part of GPAC / ISO Media File Format sub-project
 *
 *  GPAC is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *   
 *  GPAC is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *   
 *  You should have received a copy of the GNU General Public License
 *  along with GNU Make; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 *
 */

//		NOTE: MPEG-4 OD Framework cannot be used with 3GPP files. Stream Descriptions
//	are not ESDescriptor, just generic config options as specified in this file

#include <gpac/intern/m4_isomedia_dev.h>

GPPMediaConfig *M4_3GP_GetStreamConfig(M4File *the_file, u32 trackNumber, u32 StreamDescriptionIndex)
{
	GPPMediaConfig *config, *res;
	TrackAtom *trak;
	SampleEntryAtom *entry;
	trak = GetTrackFromFile(the_file, trackNumber);
	if (!trak || !StreamDescriptionIndex) return NULL;

	config = NULL;
	entry = ChainGetEntry(trak->Media->information->sampleTable->SampleDescription->atomList, StreamDescriptionIndex-1);
	if (!entry) return NULL;
	switch (entry->type) {
	case M4_3GP_AMR_SubType:
	case M4_3GP_AMR_WB_SubType:
	case M4_3GP_EVRC_SubType:
	case M4_3GP_QCELP_SubType:
	case M4_3GP_SMV_SubType:
		if (! ((GP3AudioSampleEntryAtom*)entry)->info) return NULL;
		config = & ((GP3AudioSampleEntryAtom*)entry)->info->cfg;
		break;
	case M4_3GP_H263_SubType:
		if (! ((GP3VisualSampleEntryAtom*)entry)->info) return NULL;
		config = & ((GP3VisualSampleEntryAtom*)entry)->info->cfg;
		break;
	default:
		return NULL;
	}
	if (!config) return NULL;

	res = malloc(sizeof(GPPMediaConfig));
	memcpy(res, config, sizeof(GPPMediaConfig));
	return res;
}

#ifndef M4_READ_ONLY

M4Err M4_3GP_NewStreamConfig(M4File *the_file, u32 trackNumber, GPPMediaConfig *cfg, char *URLname, char *URNname, u32 *outDescriptionIndex)
{
	TrackAtom *trak;
	M4Err e;
	u32 dataRefIndex;
	TrackReferenceTypeAtom *dpnd;
	TrackReferenceAtom *tref;
	u32 cfg_type;

	e = CanAccessMovie(the_file, M4_OPEN_WRITE);
	if (e) return e;
	
	trak = GetTrackFromFile(the_file, trackNumber);
	if (!trak || !trak->Media || !cfg) return M4BadParam;

	switch (cfg->type) {
	case M4_3GP_AMR_SubType:
	case M4_3GP_AMR_WB_SubType:
		if (trak->Media->handler->handlerType!=M4_AudioMediaType) return M4BadParam;
		cfg_type = AMRConfigAtomType;
		break;
	case M4_3GP_EVRC_SubType: 
		if (trak->Media->handler->handlerType!=M4_AudioMediaType) return M4BadParam;
		cfg_type = EVRCConfigAtomType;
		break;
	case M4_3GP_QCELP_SubType:
		if (trak->Media->handler->handlerType!=M4_AudioMediaType) return M4BadParam;
		cfg_type = QCELPConfigAtomType;
		break;
	case M4_3GP_SMV_SubType:
		if (trak->Media->handler->handlerType!=M4_AudioMediaType) return M4BadParam;
		cfg_type = SMVConfigAtomType;
		break;
	case M4_3GP_H263_SubType:
		if (trak->Media->handler->handlerType!=M4_VisualMediaType) return M4BadParam;
		cfg_type = H263ConfigAtomType;
		break;
	case 0: return M4BadParam;
	default:
		return M4NotSupported;
	}
	dpnd = NULL;
	tref = NULL;


	//get or create the data ref
	e = Media_FindDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex);
	if (e) return e;
	if (!dataRefIndex) {
		e = Media_CreateDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex);
		if (e) return e;
	}
	trak->Media->mediaHeader->modificationTime = GetMP4Time();

	switch (cfg->type) {
	case M4_3GP_AMR_SubType:
	case M4_3GP_AMR_WB_SubType:
	case M4_3GP_EVRC_SubType:
	case M4_3GP_QCELP_SubType:
	case M4_3GP_SMV_SubType:
	{
		GP3AudioSampleEntryAtom *entry = (GP3AudioSampleEntryAtom *) CreateAtom(cfg->type);
		if (!entry) return M4OutOfMem;
		entry->info = (GP3ConfigAtom *) CreateAtom(cfg_type);
		if (!entry->info) {
			DelAtom((Atom *) entry);
			return M4OutOfMem;
		}
		memcpy(&entry->info->cfg, cfg, sizeof(GPPMediaConfig));
		entry->samplerate_hi = trak->Media->mediaHeader->timeScale;
		entry->dataReferenceIndex = dataRefIndex;
		e = ChainAddEntry(trak->Media->information->sampleTable->SampleDescription->atomList, entry);
		*outDescriptionIndex = ChainGetCount(trak->Media->information->sampleTable->SampleDescription->atomList);
	}
		break;
	case M4_3GP_H263_SubType:
	{
		GP3VisualSampleEntryAtom *entry = (GP3VisualSampleEntryAtom *) CreateAtom(cfg->type);
		if (!entry) return M4OutOfMem;
		entry->info = (GP3ConfigAtom *) CreateAtom(cfg_type);
		if (!entry->info) {
			DelAtom((Atom *) entry);
			return M4OutOfMem;
		}
		memcpy(&entry->info->cfg, cfg, sizeof(GPPMediaConfig));
		entry->dataReferenceIndex = dataRefIndex;
		e = ChainAddEntry(trak->Media->information->sampleTable->SampleDescription->atomList, entry);
		*outDescriptionIndex = ChainGetCount(trak->Media->information->sampleTable->SampleDescription->atomList);
	}
		break;
	}
	return e;
}

M4Err M4_3GP_UpdateStreamConfig(M4File *the_file, u32 trackNumber, GPPMediaConfig *param, u32 DescriptionIndex)
{
	TrackAtom *trak;
	M4Err e;
	GPPMediaConfig *cfg;
	GP3AudioSampleEntryAtom *entry;

	e = CanAccessMovie(the_file, M4_OPEN_WRITE);
	if (e) return e;
	
	trak = GetTrackFromFile(the_file, trackNumber);
	if (!trak || !trak->Media || !param || !DescriptionIndex) return M4BadParam;

	cfg = NULL;
	entry = ChainGetEntry(trak->Media->information->sampleTable->SampleDescription->atomList, DescriptionIndex-1);
	if (!entry) return M4BadParam;
	switch (entry->type) {
	case M4_3GP_AMR_SubType:
	case M4_3GP_AMR_WB_SubType:
	case M4_3GP_EVRC_SubType:
	case M4_3GP_QCELP_SubType:
	case M4_3GP_SMV_SubType:
		cfg = &entry->info->cfg;
		break;
	case M4_3GP_H263_SubType:
		cfg = & ((GP3VisualSampleEntryAtom *)entry)->info->cfg;
		break;
	default:
		break;
	}
	if (!cfg || (cfg->type != param->type)) return M4BadParam;
	memcpy(cfg, param, sizeof(GPPMediaConfig));
	return M4OK;
}


#endif	//M4_READ_ONLY

