This source file includes following definitions.
- CanAccessMovie
- unpack_track
- FlushCaptureMode
- CheckNoData
- AddMovieIOD
- gf_isom_add_track_to_root_od
- gf_isom_remove_root_od
- gf_isom_remove_track_from_root_od
- gf_isom_set_creation_time
- gf_isom_set_track_creation_time
- gf_isom_set_track_enabled
- gf_isom_set_media_language
- gf_isom_set_root_iod
- gf_isom_add_desc_to_root_od
- gf_isom_set_timescale
- gf_isom_set_pl_indication
- gf_isom_set_root_od_id
- gf_isom_set_root_od_url
- gf_isom_new_track
- gf_isom_new_mpeg4_description
- gf_isom_add_sample
- gf_isom_add_sample_shadow
- gf_isom_set_sample_rap
- gf_isom_append_sample_data
- gf_isom_add_sample_reference
- gf_isom_set_last_sample_duration
- gf_isom_update_sample
- gf_isom_update_sample_reference
- gf_isom_remove_sample
- gf_isom_set_final_name
- gf_isom_add_desc_to_description
- gf_isom_change_mpeg4_description
- gf_isom_set_visual_info
- gf_isom_set_pixel_aspect_ratio
- gf_isom_set_clean_apperture
- gf_isom_set_audio_info
- gf_isom_set_storage_mode
- gf_isom_force_64bit_chunk_offset
- gf_isom_set_edit_segment
- gf_isom_remove_edit_segments
- gf_isom_remove_edit_segment
- gf_isom_append_edit_segment
- gf_isom_modify_edit_segment
- gf_isom_remove_track
- gf_isom_set_copyright
- gf_isom_add_track_kind
- gf_isom_remove_track_kind
- gf_isom_add_chapter
- gf_isom_remove_chapter
- gf_isom_remove_copyright
- gf_isom_set_watermark
- gf_isom_set_interleave_time
- gf_isom_get_interleave_time
- gf_isom_get_storage_mode
- gf_isom_use_compact_size
- gf_isom_set_brand_info
- gf_isom_modify_alternate_brand
- gf_isom_reset_alt_brands
- gf_isom_set_sample_padding_bits
- gf_isom_remove_user_data_item
- gf_isom_remove_user_data
- gf_isom_add_user_data
- gf_isom_add_user_data_boxes
- gf_isom_add_sample_fragment
- gf_isom_remove_sample_fragment
- gf_isom_remove_sample_fragments
- gf_isom_clone_pl_indications
- gf_isom_clone_box
- gf_isom_clone_movie
- gf_isom_clone_track
- gf_isom_clone_sample_descriptions
- gf_isom_clone_sample_description
- gf_isom_new_generic_sample_description
- gf_isom_change_generic_sample_description
- gf_isom_remove_sample_description
- gf_isom_set_track_reference
- gf_isom_remove_track_reference
- gf_isom_set_track_id
- gf_isom_rewrite_track_dependencies
- gf_isom_modify_cts_offset
- gf_isom_remove_cts_info
- gf_isom_set_cts_packing
- gf_isom_set_track_matrix
- gf_isom_set_track_layout_info
- gf_isom_set_track_name
- gf_isom_get_track_name
- gf_isom_store_movie_config
- gf_isom_load_movie_config
- gf_isom_set_media_timescale
- gf_isom_box_equal
- gf_isom_is_same_sample_description
- gf_isom_estimate_size
- gf_isom_remove_sync_shadows
- gf_isom_set_sync_shadow
- gf_isom_set_track_interleaving_group
- gf_isom_set_track_priority_in_group
- gf_isom_set_max_samples_per_chunk
- gf_isom_set_extraction_slc
- gf_isom_get_extraction_slc
- gf_isom_get_track_group
- gf_isom_get_track_priority_in_group
- gf_isom_make_interleave
- gf_isom_set_handler_name
- gf_isom_clone_root_od
- gf_isom_set_media_type
- gf_isom_set_media_subtype
- gf_isom_set_JPEG2000
- gf_isom_remove_uuid
- gf_isom_add_uuid
- gf_isom_apple_set_tag
- gf_isom_set_alternate_group_id
- gf_isom_set_track_switch_parameter
- reset_tsel_box
- gf_isom_reset_track_switch_parameter
- gf_isom_reset_switch_parameters
- gf_isom_add_subsample
- gf_isom_set_rvc_config
- gf_isom_add_sample_group_entry
- get_sgdp
- gf_isom_set_sample_group_info_ex
- gf_isom_set_sample_group_info
- gf_isom_add_sample_group_info
- gf_isom_remove_sample_group
- gf_isom_add_sample_info
- sg_rap_create_entry
- sg_rap_compare_entry
- gf_isom_set_sample_rap_group
- sg_roll_create_entry
- sg_roll_compare_entry
- gf_isom_set_sample_roll_group
- sg_encryption_create_entry
- sg_encryption_compare_entry
- gf_isom_copy_sample_group_entry_to_traf
- gf_isom_set_sample_cenc_group
- gf_isom_set_ctts_v1
- gf_isom_set_ctts_v0
- gf_isom_set_composition_offset_mode
- gf_isom_set_sync_table
- gf_isom_is_identical_sgpd
- gf_isom_copy_sample_info
- gf_isom_text_set_display_flags
- gf_isom_update_duration
- gf_isom_update_edit_list_duration
- gf_isom_clone_pssh
- gf_isom_set_track_group
#include <gpac/internal/isomedia_dev.h>
#include <gpac/iso639.h>
#if !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_WRITE)
GF_Err CanAccessMovie(GF_ISOFile *movie, u32 Mode)
{
if (!movie) return GF_BAD_PARAM;
if (movie->openMode < Mode) return GF_ISOM_INVALID_MODE;
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
if (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY) return GF_ISOM_INVALID_MODE;
#endif
return GF_OK;
}
static GF_Err unpack_track(GF_TrackBox *trak)
{
GF_Err e = GF_OK;
if (!trak->is_unpacked) {
e = stbl_UnpackOffsets(trak->Media->information->sampleTable);
if (e) return e;
e = stbl_unpackCTS(trak->Media->information->sampleTable);
trak->is_unpacked = GF_TRUE;
}
return e;
}
GF_Err FlushCaptureMode(GF_ISOFile *movie)
{
GF_Err e;
if (movie->openMode != GF_ISOM_OPEN_WRITE) return GF_OK;
if (gf_bs_get_position(movie->editFileMap->bs)) return GF_OK;
if (movie->brand) {
e = gf_isom_box_size((GF_Box *)movie->brand);
if (e) return e;
e = gf_isom_box_write((GF_Box *)movie->brand, movie->editFileMap->bs);
if (e) return e;
}
if (movie->pdin) {
e = gf_isom_box_size((GF_Box *)movie->pdin);
if (e) return e;
e = gf_isom_box_write((GF_Box *)movie->pdin, movie->editFileMap->bs);
if (e) return e;
}
gf_bs_write_int(movie->editFileMap->bs, 0, 128);
return GF_OK;
}
static GF_Err CheckNoData(GF_ISOFile *movie)
{
if (movie->openMode != GF_ISOM_OPEN_WRITE) return GF_OK;
if (gf_bs_get_position(movie->editFileMap->bs)) return GF_BAD_PARAM;
return GF_OK;
}
GF_Err AddMovieIOD(GF_MovieBox *moov, u8 isIOD)
{
GF_Descriptor *od;
GF_ObjectDescriptorBox *iods;
if (moov->iods) return GF_OK;
if (isIOD) {
od = gf_odf_desc_new(GF_ODF_ISOM_IOD_TAG);
} else {
od = gf_odf_desc_new(GF_ODF_ISOM_OD_TAG);
}
if (!od) return GF_OUT_OF_MEM;
((GF_IsomObjectDescriptor *)od)->objectDescriptorID = 1;
iods = (GF_ObjectDescriptorBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_IODS);
iods->descriptor = od;
return moov_AddBox((GF_Box*)moov, (GF_Box *)iods);
}
GF_EXPORT
GF_Err gf_isom_add_track_to_root_od(GF_ISOFile *movie, u32 trackNumber)
{
GF_Err e;
GF_ES_ID_Inc *inc;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
gf_isom_insert_moov(movie);
if (!movie->moov->iods) AddMovieIOD(movie->moov, 0);
if (gf_isom_is_track_in_root_od(movie, trackNumber) == 1) return GF_OK;
inc = (GF_ES_ID_Inc *) gf_odf_desc_new(GF_ODF_ESD_INC_TAG);
inc->trackID = gf_isom_get_track_id(movie, trackNumber);
if (!inc->trackID) {
gf_odf_desc_del((GF_Descriptor *)inc);
return movie->LastError;
}
if ( (movie->LastError = gf_isom_add_desc_to_root_od(movie, (GF_Descriptor *)inc) ) ) {
return movie->LastError;
}
gf_odf_desc_del((GF_Descriptor *)inc);
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_remove_root_od(GF_ISOFile *movie)
{
GF_Err e;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
if (!movie->moov || !movie->moov->iods) return GF_OK;
gf_isom_box_del((GF_Box *)movie->moov->iods);
movie->moov->iods = NULL;
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_remove_track_from_root_od(GF_ISOFile *movie, u32 trackNumber)
{
GF_List *esds;
GF_ES_ID_Inc *inc;
u32 i;
GF_Err e;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
if (!movie->moov) return GF_OK;
if (!gf_isom_is_track_in_root_od(movie, trackNumber)) return GF_OK;
if (!movie->moov->iods) AddMovieIOD(movie->moov, 0);
if (!movie->moov->iods) return GF_OUT_OF_MEM;
switch (movie->moov->iods->descriptor->tag) {
case GF_ODF_ISOM_IOD_TAG:
esds = ((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->ES_ID_IncDescriptors;
break;
case GF_ODF_ISOM_OD_TAG:
esds = ((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->ES_ID_IncDescriptors;
break;
default:
return GF_ISOM_INVALID_FILE;
}
i=0;
while ((inc = (GF_ES_ID_Inc*)gf_list_enum(esds, &i))) {
if (inc->trackID == gf_isom_get_track_id(movie, trackNumber)) {
gf_odf_desc_del((GF_Descriptor *)inc);
gf_list_rem(esds, i-1);
break;
}
}
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_set_creation_time(GF_ISOFile *movie, u64 time)
{
if (!movie || !movie->moov) return GF_BAD_PARAM;
movie->moov->mvhd->creationTime = time;
movie->moov->mvhd->modificationTime = time;
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_set_track_creation_time(GF_ISOFile *movie,u32 trackNumber, u64 time)
{
GF_TrackBox *trak;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
trak->Header->creationTime = time;
trak->Header->modificationTime = time;
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_set_track_enabled(GF_ISOFile *movie, u32 trackNumber, u8 enableTrack)
{
GF_Err e;
GF_TrackBox *trak;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
if (enableTrack) {
trak->Header->flags |= 1;
} else {
trak->Header->flags &= ~1;
}
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_set_media_language(GF_ISOFile *movie, u32 trackNumber, char *code)
{
GF_Err e;
GF_TrackBox *trak;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
if (strlen(code) == 3) {
memcpy(trak->Media->mediaHeader->packedLanguage, code, sizeof(char)*3);
} else {
s32 lang_idx;
const char *code_3cc;
lang_idx = gf_lang_find(code);
if (lang_idx == -1) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("The given code is not a valid one: %s, using 'und' as 3-letter code\n", code));
code_3cc = "und";
} else {
code_3cc = gf_lang_get_3cc(lang_idx);
}
memcpy(trak->Media->mediaHeader->packedLanguage, code_3cc, sizeof(char)*3);
}
{
u32 i, count;
GF_ExtendedLanguageBox *elng;
elng = NULL;
count = gf_list_count(trak->Media->other_boxes);
for (i = 0; i < count; i++) {
GF_Box *box = (GF_Box *)gf_list_get(trak->Media->other_boxes, i);
if (box->type == GF_ISOM_BOX_TYPE_ELNG) {
elng = (GF_ExtendedLanguageBox *)box;
break;
}
}
if (!elng && (strlen(code) != 3)) {
elng = (GF_ExtendedLanguageBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_ELNG);
if (!count) {
trak->Media->other_boxes = gf_list_new();
}
gf_list_add(trak->Media->other_boxes, elng);
}
if (elng) {
if (elng->extended_language) {
gf_free(elng->extended_language);
}
elng->extended_language = gf_strdup(code);
}
}
if (!movie->keep_utc)
trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
return GF_OK;
}
static void gf_isom_set_root_iod(GF_ISOFile *movie)
{
GF_IsomInitialObjectDescriptor *iod;
GF_IsomObjectDescriptor *od;
gf_isom_insert_moov(movie);
if (!movie->moov->iods) {
AddMovieIOD(movie->moov, 1);
return;
}
if (movie->moov->iods->descriptor->tag == GF_ODF_ISOM_IOD_TAG) return;
od = (GF_IsomObjectDescriptor *) movie->moov->iods->descriptor;
iod = (GF_IsomInitialObjectDescriptor*)gf_malloc(sizeof(GF_IsomInitialObjectDescriptor));
memset(iod, 0, sizeof(GF_IsomInitialObjectDescriptor));
iod->ES_ID_IncDescriptors = od->ES_ID_IncDescriptors;
od->ES_ID_IncDescriptors = NULL;
iod->ES_ID_RefDescriptors = NULL;
iod->extensionDescriptors = od->extensionDescriptors;
od->extensionDescriptors = NULL;
iod->IPMP_Descriptors = od->IPMP_Descriptors;
od->IPMP_Descriptors = NULL;
iod->objectDescriptorID = od->objectDescriptorID;
iod->OCIDescriptors = od->OCIDescriptors;
od->OCIDescriptors = NULL;
iod->tag = GF_ODF_ISOM_IOD_TAG;
iod->URLString = od->URLString;
od->URLString = NULL;
gf_odf_desc_del((GF_Descriptor *) od);
movie->moov->iods->descriptor = (GF_Descriptor *)iod;
}
GF_Err gf_isom_add_desc_to_root_od(GF_ISOFile *movie, GF_Descriptor *theDesc)
{
GF_Err e;
GF_Descriptor *desc, *dupDesc;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
gf_isom_insert_moov(movie);
if (!movie->moov->iods) AddMovieIOD(movie->moov, 0);
if (!movie->moov->iods) return GF_OUT_OF_MEM;
if (theDesc->tag==GF_ODF_IPMP_TL_TAG) gf_isom_set_root_iod(movie);
desc = movie->moov->iods->descriptor;
switch (desc->tag) {
case GF_ODF_ISOM_IOD_TAG:
case GF_ODF_ISOM_OD_TAG:
e = gf_odf_desc_copy(theDesc, &dupDesc);
if (e) return e;
movie->LastError = gf_odf_desc_add_desc(desc, dupDesc);
if (movie->LastError) gf_odf_desc_del((GF_Descriptor *)dupDesc);
break;
default:
movie->LastError = GF_ISOM_INVALID_FILE;
break;
}
return movie->LastError;
}
GF_EXPORT
GF_Err gf_isom_set_timescale(GF_ISOFile *movie, u32 timeScale)
{
Double ts_scale;
GF_TrackBox *trak;
u32 i;
GF_Err e;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
gf_isom_insert_moov(movie);
if (movie->moov->mvhd->timeScale == timeScale) return GF_OK;
ts_scale = timeScale;
ts_scale /= movie->moov->mvhd->timeScale;
movie->moov->mvhd->timeScale = timeScale;
movie->interleavingTime = timeScale;
movie->moov->mvhd->duration = (u64) (s64) ((s64) movie->moov->mvhd->duration * ts_scale);
i=0;
while ((trak = (GF_TrackBox*)gf_list_enum(movie->moov->trackList, &i))) {
trak->Header->duration = (u64) (s64) ((s64) trak->Header->duration * ts_scale);
if (trak->editBox && trak->editBox->editList) {
u32 j, count = gf_list_count(trak->editBox->editList->entryList);
for (j=0; j<count; j++) {
GF_EdtsEntry *ent = (GF_EdtsEntry *)gf_list_get(trak->editBox->editList->entryList, j);
ent->segmentDuration = (u64) (s64) ((s64) ent->segmentDuration * ts_scale);
}
}
}
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_set_pl_indication(GF_ISOFile *movie, u8 PL_Code, u8 ProfileLevel)
{
GF_IsomInitialObjectDescriptor *iod;
GF_Err e;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
gf_isom_set_root_iod(movie);
iod = (GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor;
switch (PL_Code) {
case GF_ISOM_PL_AUDIO:
iod->audio_profileAndLevel = ProfileLevel;
break;
case GF_ISOM_PL_GRAPHICS:
iod->graphics_profileAndLevel = ProfileLevel;
break;
case GF_ISOM_PL_OD:
iod->OD_profileAndLevel = ProfileLevel;
break;
case GF_ISOM_PL_SCENE:
iod->scene_profileAndLevel = ProfileLevel;
break;
case GF_ISOM_PL_VISUAL:
iod->visual_profileAndLevel = ProfileLevel;
break;
case GF_ISOM_PL_INLINE:
iod->inlineProfileFlag = ProfileLevel ? 1 : 0;
break;
}
return GF_OK;
}
GF_Err gf_isom_set_root_od_id(GF_ISOFile *movie, u32 OD_ID)
{
GF_Err e;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
gf_isom_insert_moov(movie);
if (!movie->moov->iods) AddMovieIOD(movie->moov, 0);
if (!movie->moov->iods) return GF_OUT_OF_MEM;
switch (movie->moov->iods->descriptor->tag) {
case GF_ODF_ISOM_OD_TAG:
((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->objectDescriptorID = OD_ID;
break;
case GF_ODF_ISOM_IOD_TAG:
((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->objectDescriptorID = OD_ID;
break;
default:
return GF_ISOM_INVALID_FILE;
}
return GF_OK;
}
GF_Err gf_isom_set_root_od_url(GF_ISOFile *movie, char *url_string)
{
GF_Err e;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
gf_isom_insert_moov(movie);
if (!movie->moov->iods) AddMovieIOD(movie->moov, 0);
if (!movie->moov->iods) return GF_OUT_OF_MEM;
switch (movie->moov->iods->descriptor->tag) {
case GF_ODF_ISOM_OD_TAG:
if (((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->URLString) gf_free(((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->URLString);
((GF_IsomObjectDescriptor *)movie->moov->iods->descriptor)->URLString = url_string ? gf_strdup(url_string) : NULL;
break;
case GF_ODF_ISOM_IOD_TAG:
if (((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->URLString) gf_free(((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->URLString);
((GF_IsomInitialObjectDescriptor *)movie->moov->iods->descriptor)->URLString = url_string ? gf_strdup(url_string) : NULL;
break;
default:
return GF_ISOM_INVALID_FILE;
}
return GF_OK;
}
GF_EXPORT
u32 gf_isom_new_track(GF_ISOFile *movie, u32 trakID, u32 MediaType, u32 TimeScale)
{
GF_Err e;
u64 now;
u8 isHint;
GF_TrackBox *trak;
GF_TrackHeaderBox *tkhd;
GF_MediaBox *mdia;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) {
gf_isom_set_last_error(movie, e);
return 0;
}
gf_isom_insert_moov(movie);
isHint = 0;
if (MediaType == GF_ISOM_MEDIA_HINT) {
isHint = 1;
}
mdia = NULL;
tkhd = NULL;
trak = NULL;
if (trakID) {
if (!isHint && (trakID > 0xFFFF)) {
gf_isom_set_last_error(movie, GF_BAD_PARAM);
return 0;
}
if (!RequestTrack(movie->moov, trakID)) return 0;
} else {
trakID = movie->moov->mvhd->nextTrackID;
if (!trakID) trakID = 1;
if (! isHint && (trakID > 0xFFFF)) trakID = 1;
while (1) {
if (RequestTrack(movie->moov, trakID)) break;
trakID += 1;
if (trakID == 0xFFFFFFFF) break;
}
if (trakID == 0xFFFFFFFF) {
gf_isom_set_last_error(movie, GF_BAD_PARAM);
return 0;
}
if (! isHint && (trakID > 0xFFFF)) {
gf_isom_set_last_error(movie, GF_BAD_PARAM);
return 0;
}
}
trak = (GF_TrackBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_TRAK);
if (!trak) {
gf_isom_set_last_error(movie, GF_OUT_OF_MEM);
return 0;
}
tkhd = (GF_TrackHeaderBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_TKHD);
if (!tkhd) {
gf_isom_set_last_error(movie, GF_OUT_OF_MEM);
gf_isom_box_del((GF_Box *)trak);
return 0;
}
now = gf_isom_get_mp4time();
tkhd->creationTime = now;
if (!movie->keep_utc)
tkhd->modificationTime = now;
e = NewMedia(&mdia, MediaType, TimeScale);
if (e) {
gf_isom_box_del((GF_Box *)mdia);
gf_isom_box_del((GF_Box *)trak);
gf_isom_box_del((GF_Box *)tkhd);
return 0;
}
mdia->mediaTrack = trak;
e = trak_AddBox((GF_Box*)trak, (GF_Box *) tkhd);
if (e) goto err_exit;
e = trak_AddBox((GF_Box*)trak, (GF_Box *) mdia);
if (e) goto err_exit;
tkhd->trackID = trakID;
switch (MediaType) {
case GF_ISOM_MEDIA_VISUAL:
case GF_ISOM_MEDIA_SCENE:
case GF_ISOM_MEDIA_TEXT:
case GF_ISOM_MEDIA_SUBT:
tkhd->width = 0x01400000;
tkhd->height = 0x00F00000;
break;
case GF_ISOM_MEDIA_AUDIO:
tkhd->volume = 0x0100;
break;
}
mdia->mediaHeader->creationTime = mdia->mediaHeader->modificationTime = now;
trak->Header->creationTime = trak->Header->modificationTime = now;
e = moov_AddBox((GF_Box*)movie->moov, (GF_Box *)trak);
if (e) goto err_exit;
if (trakID+1> movie->moov->mvhd->nextTrackID)
movie->moov->mvhd->nextTrackID = trakID+1;
return gf_isom_get_track_by_id(movie, trakID);
err_exit:
if (tkhd) gf_isom_box_del((GF_Box *)tkhd);
if (trak) gf_isom_box_del((GF_Box *)trak);
if (mdia) gf_isom_box_del((GF_Box *)mdia);
return 0;
}
GF_EXPORT
GF_Err gf_isom_new_mpeg4_description(GF_ISOFile *movie,
u32 trackNumber,
GF_ESD *esd,
char *URLname,
char *URNname,
u32 *outDescriptionIndex)
{
GF_TrackBox *trak;
GF_Err e;
u32 dataRefIndex;
GF_ESD *new_esd;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak || !trak->Media ||
!esd || !esd->decoderConfig ||
!esd->slConfig) return GF_BAD_PARAM;
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;
}
e = gf_odf_desc_copy((GF_Descriptor *)esd, (GF_Descriptor **)&new_esd);
if (e) return e;
if (!movie->keep_utc)
trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
e = Track_SetStreamDescriptor(trak, 0, dataRefIndex, new_esd, outDescriptionIndex);
if (e) {
gf_odf_desc_del((GF_Descriptor *)new_esd);
return e;
}
if (new_esd->URLString) {
}
return e;
}
GF_EXPORT
GF_Err gf_isom_add_sample(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, const GF_ISOSample *sample)
{
GF_Err e;
GF_TrackBox *trak;
GF_SampleEntryBox *entry;
u32 dataRefIndex;
u64 data_offset;
u32 descIndex;
GF_DataEntryURLBox *Dentry;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
e = FlushCaptureMode(movie);
if (e) return e;
e = unpack_track(trak);
if (e) return e;
descIndex = StreamDescriptionIndex;
if (!StreamDescriptionIndex) {
descIndex = trak->Media->information->sampleTable->currentEntryIndex;
}
e = Media_GetSampleDesc(trak->Media, descIndex, &entry, &dataRefIndex);
if (e) return e;
if (!entry || !dataRefIndex) return GF_BAD_PARAM;
trak->Media->information->sampleTable->currentEntryIndex = descIndex;
Dentry = (GF_DataEntryURLBox*)gf_list_get(trak->Media->information->dataInformation->dref->other_boxes, dataRefIndex - 1);
if (!Dentry || Dentry->flags != 1) return GF_BAD_PARAM;
e = gf_isom_datamap_open(trak->Media, dataRefIndex, 1);
if (e) return e;
data_offset = gf_isom_datamap_get_offset(trak->Media->information->dataHandler);
if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
GF_ISOSample *od_sample = NULL;
e = Media_ParseODFrame(trak->Media, sample, &od_sample);
if (e) return e;
e = Media_AddSample(trak->Media, data_offset, od_sample, descIndex, 0);
if (e) return e;
e = gf_isom_datamap_add_data(trak->Media->information->dataHandler, od_sample->data, od_sample->dataLength);
if (e) return e;
if (od_sample) gf_isom_sample_del(&od_sample);
} else {
e = Media_AddSample(trak->Media, data_offset, sample, descIndex, 0);
if (e) return e;
if (sample->dataLength) {
e = gf_isom_datamap_add_data(trak->Media->information->dataHandler, sample->data, sample->dataLength);
if (e) return e;
}
}
if (!movie->keep_utc)
trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
return SetTrackDuration(trak);
}
GF_Err gf_isom_add_sample_shadow(GF_ISOFile *movie, u32 trackNumber, GF_ISOSample *sample)
{
GF_Err e;
GF_TrackBox *trak;
GF_ISOSample *prev;
GF_SampleEntryBox *entry;
u32 dataRefIndex;
u64 data_offset;
u32 descIndex;
u32 sampleNum, prevSampleNum;
GF_DataEntryURLBox *Dentry;
Bool offset_times = GF_FALSE;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak || !sample) return GF_BAD_PARAM;
e = FlushCaptureMode(movie);
if (e) return e;
e = unpack_track(trak);
if (e) return e;
e = stbl_findEntryForTime(trak->Media->information->sampleTable, sample->DTS, 0, &sampleNum, &prevSampleNum);
if (e) return e;
if (!sampleNum) return GF_BAD_PARAM;
prev = gf_isom_get_sample_info(movie, trackNumber, sampleNum, &descIndex, NULL);
if (!prev) return gf_isom_last_error(movie);
if (sample->DTS==prev->DTS) offset_times = GF_TRUE;
gf_isom_sample_del(&prev);
e = Media_GetSampleDesc(trak->Media, descIndex, &entry, &dataRefIndex);
if (e) return e;
if (!entry || !dataRefIndex) return GF_BAD_PARAM;
trak->Media->information->sampleTable->currentEntryIndex = descIndex;
Dentry = (GF_DataEntryURLBox*)gf_list_get(trak->Media->information->dataInformation->dref->other_boxes, dataRefIndex - 1);
if (!Dentry || Dentry->flags != 1) return GF_BAD_PARAM;
e = gf_isom_datamap_open(trak->Media, dataRefIndex, 1);
if (e) return e;
data_offset = gf_isom_datamap_get_offset(trak->Media->information->dataHandler);
if (offset_times) sample->DTS += 1;
if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
GF_ISOSample *od_sample = NULL;
e = Media_ParseODFrame(trak->Media, sample, &od_sample);
if (!e) e = Media_AddSample(trak->Media, data_offset, od_sample, descIndex, sampleNum);
if (!e) e = gf_isom_datamap_add_data(trak->Media->information->dataHandler, od_sample->data, od_sample->dataLength);
if (od_sample) gf_isom_sample_del(&od_sample);
} else {
e = Media_AddSample(trak->Media, data_offset, sample, descIndex, sampleNum);
if (!e) e = gf_isom_datamap_add_data(trak->Media->information->dataHandler, sample->data, sample->dataLength);
}
if (e) return e;
if (offset_times) sample->DTS -= 1;
e = Media_SetDuration(trak);
if (e) return e;
if (!movie->keep_utc)
trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
return SetTrackDuration(trak);
}
GF_Err gf_isom_set_sample_rap(GF_ISOFile *movie, u32 trackNumber)
{
GF_SampleTableBox *stbl;
GF_Err e;
GF_TrackBox *trak;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
stbl = trak->Media->information->sampleTable;
if (!stbl->SyncSample) stbl->SyncSample = (GF_SyncSampleBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STSS);
return stbl_AddRAP(stbl->SyncSample, stbl->SampleSize->sampleCount);
}
GF_Err gf_isom_append_sample_data(GF_ISOFile *movie, u32 trackNumber, char *data, u32 data_size)
{
GF_Err e;
GF_TrackBox *trak;
GF_SampleEntryBox *entry;
u32 dataRefIndex;
u32 descIndex;
GF_DataEntryURLBox *Dentry;
if (!data_size) return GF_OK;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) return GF_BAD_PARAM;
descIndex = trak->Media->information->sampleTable->currentEntryIndex;
e = Media_GetSampleDesc(trak->Media, descIndex, &entry, &dataRefIndex);
if (e) return e;
if (!entry || !dataRefIndex) return GF_BAD_PARAM;
Dentry = (GF_DataEntryURLBox*)gf_list_get(trak->Media->information->dataInformation->dref->other_boxes, dataRefIndex - 1);
if (!Dentry || Dentry->flags != 1) return GF_BAD_PARAM;
e = gf_isom_datamap_open(trak->Media, dataRefIndex, 1);
if (e) return e;
e = gf_isom_datamap_add_data(trak->Media->information->dataHandler, data, data_size);
if (e) return e;
return stbl_SampleSizeAppend(trak->Media->information->sampleTable->SampleSize, data_size);
}
GF_EXPORT
GF_Err gf_isom_add_sample_reference(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_ISOSample *sample, u64 dataOffset)
{
GF_TrackBox *trak;
GF_SampleEntryBox *entry;
u32 dataRefIndex;
u32 descIndex;
GF_DataEntryURLBox *Dentry;
GF_Err e;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
e = unpack_track(trak);
if (e) return e;
if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
return GF_BAD_PARAM;
}
descIndex = StreamDescriptionIndex;
if (!StreamDescriptionIndex) {
descIndex = trak->Media->information->sampleTable->currentEntryIndex;
}
e = Media_GetSampleDesc(trak->Media, descIndex, &entry, &dataRefIndex);
if (e) return e;
if (!entry || !dataRefIndex) return GF_BAD_PARAM;
trak->Media->information->sampleTable->currentEntryIndex = descIndex;
Dentry =(GF_DataEntryURLBox*) gf_list_get(trak->Media->information->dataInformation->dref->other_boxes, dataRefIndex - 1);
if (Dentry->flags == 1) return GF_BAD_PARAM;
e = Media_AddSample(trak->Media, dataOffset, sample, descIndex, 0);
if (e) return e;
if (!movie->keep_utc)
trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
e = Media_SetDuration(trak);
if (e) return e;
return SetTrackDuration(trak);
}
GF_EXPORT
GF_Err gf_isom_set_last_sample_duration(GF_ISOFile *movie, u32 trackNumber, u32 duration)
{
GF_TrackBox *trak;
GF_SttsEntry *ent;
GF_TimeToSampleBox *stts;
u64 mdur;
GF_Err e;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
mdur = trak->Media->mediaHeader->duration;
stts = trak->Media->information->sampleTable->TimeToSample;
if (!stts->nb_entries) return GF_BAD_PARAM;
ent = (GF_SttsEntry*) &stts->entries[stts->nb_entries-1];
mdur -= ent->sampleDelta;
mdur += duration;
if (ent->sampleCount == 1) {
ent->sampleDelta = duration;
} else {
if (ent->sampleDelta == duration) return GF_OK;
ent->sampleCount -= 1;
if (stts->nb_entries==stts->alloc_size) {
stts->alloc_size++;
stts->entries = (GF_SttsEntry*)gf_realloc(stts->entries, sizeof(GF_SttsEntry)*stts->alloc_size);
if (!stts->entries) return GF_OUT_OF_MEM;
}
stts->entries[stts->nb_entries].sampleCount = 1;
stts->entries[stts->nb_entries].sampleDelta = duration;
stts->nb_entries++;
stts->w_currentSampleNum = trak->Media->information->sampleTable->SampleSize->sampleCount;
}
if (!movie->keep_utc)
trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
trak->Media->mediaHeader->duration = mdur;
return SetTrackDuration(trak);
}
GF_EXPORT
GF_Err gf_isom_update_sample(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber, GF_ISOSample *sample, Bool data_only)
{
GF_Err e;
GF_TrackBox *trak;
e = CanAccessMovie(movie, GF_ISOM_OPEN_EDIT);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
e = unpack_track(trak);
if (e) return e;
if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_HINT) return GF_BAD_PARAM;
if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
GF_ISOSample *od_sample = NULL;
e = Media_ParseODFrame(trak->Media, sample, &od_sample);
if (!e) e = Media_UpdateSample(trak->Media, sampleNumber, od_sample, data_only);
if (od_sample) gf_isom_sample_del(&od_sample);
} else {
e = Media_UpdateSample(trak->Media, sampleNumber, sample, data_only);
}
if (e) return e;
if (!movie->keep_utc)
trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_update_sample_reference(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber, GF_ISOSample *sample, u64 data_offset)
{
GF_Err e;
GF_TrackBox *trak;
e = CanAccessMovie(movie, GF_ISOM_OPEN_EDIT);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_HINT) return GF_BAD_PARAM;
if (!sampleNumber || !sample) return GF_BAD_PARAM;
e = unpack_track(trak);
if (e) return e;
if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_OD) {
return GF_BAD_PARAM;
}
e = Media_UpdateSampleReference(trak->Media, sampleNumber, sample, data_offset);
if (e) return e;
if (!movie->keep_utc)
trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_remove_sample(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber)
{
GF_Err e;
GF_TrackBox *trak;
e = CanAccessMovie(movie, GF_ISOM_OPEN_EDIT);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak || !sampleNumber || (sampleNumber > trak->Media->information->sampleTable->SampleSize->sampleCount) )
return GF_BAD_PARAM;
if (trak->Media->handler->handlerType == GF_ISOM_MEDIA_HINT) return GF_BAD_PARAM;
e = unpack_track(trak);
if (e) return e;
e = stbl_RemoveDTS(trak->Media->information->sampleTable, sampleNumber, trak->Media->mediaHeader->timeScale);
if (e) return e;
if (trak->Media->information->sampleTable->CompositionOffset) {
e = stbl_RemoveCTS(trak->Media->information->sampleTable, sampleNumber);
if (e) return e;
}
e = stbl_RemoveSize(trak->Media->information->sampleTable->SampleSize, sampleNumber);
if (e) return e;
e = stbl_RemoveChunk(trak->Media->information->sampleTable, sampleNumber);
if (e) return e;
if (trak->Media->information->sampleTable->SyncSample) {
e = stbl_RemoveRAP(trak->Media->information->sampleTable, sampleNumber);
if (e) return e;
}
if (trak->Media->information->sampleTable->SampleDep) {
e = stbl_RemoveRedundant(trak->Media->information->sampleTable, sampleNumber);
if (e) return e;
}
if (trak->Media->information->sampleTable->ShadowSync) {
e = stbl_RemoveShadow(trak->Media->information->sampleTable->ShadowSync, sampleNumber);
if (e) return e;
}
e = stbl_RemovePaddingBits(trak->Media->information->sampleTable, sampleNumber);
if (e) return e;
e = stbl_RemoveSubSample(trak->Media->information->sampleTable, sampleNumber);
if (e) return e;
e = stbl_RemoveSampleGroup(trak->Media->information->sampleTable, sampleNumber);
if (e) return e;
return SetTrackDuration(trak);
}
GF_EXPORT
GF_Err gf_isom_set_final_name(GF_ISOFile *movie, char *filename)
{
GF_Err e;
if (!movie ) return GF_BAD_PARAM;
e = CanAccessMovie(movie, GF_ISOM_OPEN_EDIT);
if (e) return e;
if (filename) {
if ( (movie->openMode == GF_ISOM_OPEN_EDIT)
&& movie->fileName && !strcmp(filename, movie->fileName))
return GF_BAD_PARAM;
if (movie->finalName) gf_free(movie->finalName);
movie->finalName = gf_strdup(filename);
if (!movie->finalName) return GF_OUT_OF_MEM;
}
return GF_OK;
}
GF_Err gf_isom_add_desc_to_description(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_Descriptor *theDesc)
{
GF_IPIPtr *ipiD;
GF_Err e;
u16 tmpRef;
GF_TrackBox *trak;
GF_Descriptor *desc;
GF_ESD *esd;
GF_TrackReferenceBox *tref;
GF_TrackReferenceTypeBox *dpnd;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
e = Media_GetESD(trak->Media, StreamDescriptionIndex, &esd, GF_TRUE);
if (e) return e;
e = gf_odf_desc_copy(theDesc, &desc);
if (e) return e;
if (!movie->keep_utc)
trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
switch (desc->tag) {
case GF_ODF_IPI_PTR_TAG:
goto insertIPI;
default:
return gf_odf_desc_add_desc((GF_Descriptor *)esd, desc);
}
insertIPI:
if (esd->ipiPtr) {
gf_odf_desc_del((GF_Descriptor *) esd->ipiPtr);
esd->ipiPtr = NULL;
}
ipiD = (GF_IPIPtr *) desc;
if (!trak->References) {
tref = (GF_TrackReferenceBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_TREF);
e = trak_AddBox((GF_Box*)trak, (GF_Box *)tref);
if (e) return e;
}
tref = trak->References;
e = Track_FindRef(trak, GF_ISOM_REF_IPI, &dpnd);
if (e) return e;
if (!dpnd) {
tmpRef = 0;
dpnd = (GF_TrackReferenceTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_REFT);
dpnd->reference_type = GF_ISOM_BOX_TYPE_IPIR;
e = tref_AddBox((GF_Box*)tref, (GF_Box *) dpnd);
if (e) return e;
e = reftype_AddRefTrack(dpnd, ipiD->IPI_ES_Id, &tmpRef);
if (e) return e;
ipiD->IPI_ES_Id = tmpRef;
ipiD->tag = GF_ODF_ISOM_IPI_PTR_TAG;
} else {
dpnd->trackIDCount = 1;
dpnd->trackIDs[0] = ipiD->IPI_ES_Id;
ipiD->IPI_ES_Id = 1;
ipiD->tag = GF_ODF_ISOM_IPI_PTR_TAG;
}
return gf_odf_desc_add_desc((GF_Descriptor *)esd, desc);
}
GF_EXPORT
GF_Err gf_isom_change_mpeg4_description(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_ESD *newESD)
{
GF_Err e;
GF_ESD *esd;
GF_TrackBox *trak;
GF_SampleEntryBox *entry;
GF_SampleDescriptionBox *stsd;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
stsd = trak->Media->information->sampleTable->SampleDescription;
if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->other_boxes)) {
return movie->LastError = GF_BAD_PARAM;
}
entry = (GF_SampleEntryBox *)gf_list_get(stsd->other_boxes, StreamDescriptionIndex - 1);
if (entry == NULL) return GF_BAD_PARAM;
if (!movie->keep_utc)
trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
e = gf_odf_desc_copy((GF_Descriptor *)newESD, (GF_Descriptor **)&esd);
if (e) return e;
e = Track_SetStreamDescriptor(trak, StreamDescriptionIndex, entry->dataReferenceIndex, esd, NULL);
if (e != GF_OK) {
gf_odf_desc_del((GF_Descriptor *) esd);
}
return e;
}
GF_EXPORT
GF_Err gf_isom_set_visual_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 Width, u32 Height)
{
GF_Err e;
GF_TrackBox *trak;
GF_SampleEntryBox *entry;
GF_SampleDescriptionBox *stsd;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
stsd = trak->Media->information->sampleTable->SampleDescription;
if (!stsd) {
return movie->LastError = GF_ISOM_INVALID_FILE;
}
if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->other_boxes)) {
return movie->LastError = GF_BAD_PARAM;
}
entry = (GF_SampleEntryBox *)gf_list_get(stsd->other_boxes, StreamDescriptionIndex - 1);
if (entry == NULL) return GF_BAD_PARAM;
if (!movie->keep_utc)
trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
if (entry->internal_type == GF_ISOM_SAMPLE_ENTRY_VIDEO) {
((GF_VisualSampleEntryBox*)entry)->Width = Width;
((GF_VisualSampleEntryBox*)entry)->Height = Height;
trak->Header->width = Width<<16;
trak->Header->height = Height<<16;
return GF_OK;
} else if (trak->Media->handler->handlerType==GF_ISOM_MEDIA_SCENE) {
trak->Header->width = Width<<16;
trak->Header->height = Height<<16;
return GF_OK;
} else {
return GF_BAD_PARAM;
}
}
GF_EXPORT
GF_Err gf_isom_set_pixel_aspect_ratio(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 hSpacing, u32 vSpacing)
{
GF_Err e;
GF_TrackBox *trak;
GF_SampleEntryBox *entry;
GF_VisualSampleEntryBox*vent;
GF_SampleDescriptionBox *stsd;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
stsd = trak->Media->information->sampleTable->SampleDescription;
if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->other_boxes)) {
return movie->LastError = GF_BAD_PARAM;
}
entry = (GF_SampleEntryBox *)gf_list_get(stsd->other_boxes, StreamDescriptionIndex - 1);
if (entry == NULL) return GF_BAD_PARAM;
if (!movie->keep_utc)
trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_BAD_PARAM;
vent = (GF_VisualSampleEntryBox*)entry;
if (!hSpacing || !vSpacing) {
if (vent->pasp) gf_isom_box_del((GF_Box*)vent->pasp);
vent->pasp = NULL;
return GF_OK;
}
if (!vent->pasp) vent->pasp = (GF_PixelAspectRatioBox*)gf_isom_box_new(GF_ISOM_BOX_TYPE_PASP);
vent->pasp->hSpacing = hSpacing;
vent->pasp->vSpacing = vSpacing;
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_set_clean_apperture(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 cleanApertureWidthN, u32 cleanApertureWidthD, u32 cleanApertureHeightN, u32 cleanApertureHeightD, u32 horizOffN, u32 horizOffD, u32 vertOffN, u32 vertOffD)
{
GF_Err e;
GF_TrackBox *trak;
GF_SampleEntryBox *entry;
GF_VisualSampleEntryBox*vent;
GF_SampleDescriptionBox *stsd;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
stsd = trak->Media->information->sampleTable->SampleDescription;
if (!stsd) return movie->LastError = GF_ISOM_INVALID_FILE;
if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->other_boxes)) {
return movie->LastError = GF_BAD_PARAM;
}
entry = (GF_SampleEntryBox *)gf_list_get(stsd->other_boxes, StreamDescriptionIndex - 1);
if (entry == NULL) return GF_BAD_PARAM;
if (!movie->keep_utc)
trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_BAD_PARAM;
vent = (GF_VisualSampleEntryBox*)entry;
if (!cleanApertureHeightD || !cleanApertureWidthD || !horizOffD || !vertOffD) {
if (vent->clap) gf_isom_box_del((GF_Box*)vent->clap);
vent->clap = NULL;
return GF_OK;
}
if (!vent->clap) vent->clap = (GF_CleanAppertureBox*)gf_isom_box_new(GF_ISOM_BOX_TYPE_CLAP);
vent->clap->cleanApertureWidthN = cleanApertureWidthN;
vent->clap->cleanApertureWidthD = cleanApertureWidthD;
vent->clap->cleanApertureHeightN = cleanApertureHeightN;
vent->clap->cleanApertureHeightD = cleanApertureHeightD;
vent->clap->horizOffN = horizOffN;
vent->clap->horizOffD = horizOffD;
vent->clap->vertOffN = vertOffN;
vent->clap->vertOffD = vertOffD;
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_set_audio_info(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, u32 sampleRate, u32 nbChannels, u8 bitsPerSample)
{
GF_Err e;
GF_TrackBox *trak;
GF_SampleEntryBox *entry;
GF_SampleDescriptionBox *stsd;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
stsd = trak->Media->information->sampleTable->SampleDescription;
if (!stsd) {
return movie->LastError = GF_ISOM_INVALID_FILE;
}
if (!StreamDescriptionIndex || StreamDescriptionIndex > gf_list_count(stsd->other_boxes)) {
return movie->LastError = GF_BAD_PARAM;
}
entry = (GF_SampleEntryBox *)gf_list_get(stsd->other_boxes, StreamDescriptionIndex - 1);
if (entry == NULL) return GF_BAD_PARAM;
if (!movie->keep_utc)
trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_AUDIO) return GF_BAD_PARAM;
((GF_AudioSampleEntryBox*)entry)->samplerate_hi = sampleRate;
((GF_AudioSampleEntryBox*)entry)->samplerate_lo = 0;
((GF_AudioSampleEntryBox*)entry)->channel_count = nbChannels;
((GF_AudioSampleEntryBox*)entry)->bitspersample = bitsPerSample;
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_set_storage_mode(GF_ISOFile *movie, u8 storageMode)
{
GF_Err e;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
switch (storageMode) {
case GF_ISOM_STORE_FLAT:
case GF_ISOM_STORE_STREAMABLE:
case GF_ISOM_STORE_INTERLEAVED:
case GF_ISOM_STORE_DRIFT_INTERLEAVED:
case GF_ISOM_STORE_TIGHT:
movie->storageMode = storageMode;
return GF_OK;
default:
return GF_BAD_PARAM;
}
}
GF_EXPORT
void gf_isom_force_64bit_chunk_offset(GF_ISOFile *file, Bool set_on)
{
file->force_co64 = set_on;
}
GF_EXPORT
GF_Err gf_isom_set_edit_segment(GF_ISOFile *movie, u32 trackNumber, u64 EditTime, u64 EditDuration, u64 MediaTime, u8 EditMode)
{
GF_TrackBox *trak;
GF_EditBox *edts;
GF_EditListBox *elst;
GF_EdtsEntry *ent, *newEnt;
u32 i;
GF_Err e;
u64 startTime;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
edts = trak->editBox;
if (! edts) {
edts = (GF_EditBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_EDTS);
if (!edts) return GF_OUT_OF_MEM;
trak_AddBox((GF_Box*)trak, (GF_Box *)edts);
}
elst = edts->editList;
if (!elst) {
elst = (GF_EditListBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_ELST);
if (!elst) return GF_OUT_OF_MEM;
edts_AddBox((GF_Box*)edts, (GF_Box *)elst);
}
startTime = 0;
ent = NULL;
i=0;
while ((ent = (GF_EdtsEntry *)gf_list_enum(elst->entryList, &i))) {
if ( (startTime <= EditTime) && (startTime + ent->segmentDuration > EditTime) )
goto found;
startTime += ent->segmentDuration;
}
if (!ent) {
newEnt = CreateEditEntry(EditDuration, MediaTime, EditMode);
if (!newEnt) return GF_OUT_OF_MEM;
gf_list_add(elst->entryList, newEnt);
return SetTrackDuration(trak);
}
startTime -= ent->segmentDuration;
found:
if (startTime == EditTime) {
ent->segmentDuration = EditDuration;
switch (EditMode) {
case GF_ISOM_EDIT_EMPTY:
ent->mediaRate = 1;
ent->mediaTime = -1;
break;
case GF_ISOM_EDIT_DWELL:
ent->mediaRate = 0;
ent->mediaTime = MediaTime;
break;
default:
ent->mediaRate = 1;
ent->mediaTime = MediaTime;
break;
}
return SetTrackDuration(trak);
}
ent->segmentDuration = EditTime - startTime;
newEnt = CreateEditEntry(EditDuration, MediaTime, EditMode);
if (!newEnt) return GF_OUT_OF_MEM;
if (i >= gf_list_count(elst->entryList) - 1) {
gf_list_add(elst->entryList, newEnt);
return SetTrackDuration(trak);
} else {
gf_list_insert(elst->entryList, newEnt, i+1);
return SetTrackDuration(trak);
}
}
GF_EXPORT
GF_Err gf_isom_remove_edit_segments(GF_ISOFile *movie, u32 trackNumber)
{
GF_Err e;
GF_TrackBox *trak;
GF_EdtsEntry *ent;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
if (!trak->editBox || !trak->editBox->editList) return GF_OK;
while (gf_list_count(trak->editBox->editList->entryList)) {
ent = (GF_EdtsEntry*)gf_list_get(trak->editBox->editList->entryList, 0);
gf_free(ent);
e = gf_list_rem(trak->editBox->editList->entryList, 0);
if (e) return e;
}
gf_isom_box_del((GF_Box *)trak->editBox);
trak->editBox = NULL;
return SetTrackDuration(trak);
}
GF_Err gf_isom_remove_edit_segment(GF_ISOFile *movie, u32 trackNumber, u32 seg_index)
{
GF_Err e;
GF_TrackBox *trak;
GF_EdtsEntry *ent, *next_ent;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak || !seg_index) return GF_BAD_PARAM;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
if (!trak->editBox || !trak->editBox->editList) return GF_OK;
if (gf_list_count(trak->editBox->editList->entryList)<=1) return gf_isom_remove_edit_segments(movie, trackNumber);
ent = (GF_EdtsEntry*) gf_list_get(trak->editBox->editList->entryList, seg_index-1);
gf_list_rem(trak->editBox->editList->entryList, seg_index-1);
next_ent = (GF_EdtsEntry *)gf_list_get(trak->editBox->editList->entryList, seg_index-1);
if (next_ent) next_ent->segmentDuration += ent->segmentDuration;
gf_free(ent);
return SetTrackDuration(trak);
}
GF_EXPORT
GF_Err gf_isom_append_edit_segment(GF_ISOFile *movie, u32 trackNumber, u64 EditDuration, u64 MediaTime, u8 EditMode)
{
GF_Err e;
GF_TrackBox *trak;
GF_EdtsEntry *ent;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
if (!trak->editBox) {
GF_EditBox *edts = (GF_EditBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_EDTS);
if (!edts) return GF_OUT_OF_MEM;
trak_AddBox((GF_Box*)trak, (GF_Box *)edts);
}
if (!trak->editBox->editList) {
GF_EditListBox *elst = (GF_EditListBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_ELST);
if (!elst) return GF_OUT_OF_MEM;
edts_AddBox((GF_Box*)trak->editBox, (GF_Box *)elst);
}
ent = (GF_EdtsEntry *)gf_malloc(sizeof(GF_EdtsEntry));
if (!ent) return GF_OUT_OF_MEM;
ent->segmentDuration = EditDuration;
switch (EditMode) {
case GF_ISOM_EDIT_EMPTY:
ent->mediaRate = 1;
ent->mediaTime = -1;
break;
case GF_ISOM_EDIT_DWELL:
ent->mediaRate = 0;
ent->mediaTime = MediaTime;
break;
default:
ent->mediaRate = 1;
ent->mediaTime = MediaTime;
break;
}
gf_list_add(trak->editBox->editList->entryList, ent);
return SetTrackDuration(trak);
}
GF_EXPORT
GF_Err gf_isom_modify_edit_segment(GF_ISOFile *movie, u32 trackNumber, u32 seg_index, u64 EditDuration, u64 MediaTime, u8 EditMode)
{
GF_Err e;
GF_TrackBox *trak;
GF_EdtsEntry *ent;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak || !seg_index) return GF_BAD_PARAM;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
if (!trak->editBox || !trak->editBox->editList) return GF_OK;
if (gf_list_count(trak->editBox->editList->entryList)<seg_index) return GF_BAD_PARAM;
ent = (GF_EdtsEntry*) gf_list_get(trak->editBox->editList->entryList, seg_index-1);
ent->segmentDuration = EditDuration;
switch (EditMode) {
case GF_ISOM_EDIT_EMPTY:
ent->mediaRate = 1;
ent->mediaTime = -1;
break;
case GF_ISOM_EDIT_DWELL:
ent->mediaRate = 0;
ent->mediaTime = MediaTime;
break;
default:
ent->mediaRate = 1;
ent->mediaTime = MediaTime;
break;
}
return SetTrackDuration(trak);
}
GF_EXPORT
GF_Err gf_isom_remove_track(GF_ISOFile *movie, u32 trackNumber)
{
GF_Err e;
GF_TrackBox *the_trak, *trak;
GF_TrackReferenceTypeBox *tref;
u32 i, j, k, *newRefs, descIndex;
u8 found;
GF_ISOSample *samp;
the_trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!the_trak) return GF_BAD_PARAM;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
if (movie->moov->iods && movie->moov->iods->descriptor) {
GF_Descriptor *desc;
GF_ES_ID_Inc *inc;
GF_List *ESDs;
desc = movie->moov->iods->descriptor;
if (desc->tag == GF_ODF_ISOM_IOD_TAG) {
ESDs = ((GF_IsomInitialObjectDescriptor *)desc)->ES_ID_IncDescriptors;
} else if (desc->tag == GF_ODF_ISOM_OD_TAG) {
ESDs = ((GF_IsomObjectDescriptor *)desc)->ES_ID_IncDescriptors;
} else {
return GF_ISOM_INVALID_FILE;
}
i=0;
while ((inc = (GF_ES_ID_Inc *)gf_list_enum(ESDs, &i))) {
if (inc->trackID == the_trak->Header->trackID) {
gf_odf_desc_del((GF_Descriptor *)inc);
i--;
gf_list_rem(ESDs, i);
}
}
}
gf_list_del_item(movie->moov->trackList, the_trak);
i=0;
while ((trak = (GF_TrackBox *)gf_list_enum(movie->moov->trackList, &i))) {
if (trak->Media->handler->handlerType != GF_ISOM_MEDIA_OD) continue;
j = gf_isom_get_sample_count(movie, i);
for (k=0; k < j; k++) {
samp = gf_isom_get_sample(movie, i, k+1, &descIndex);
if (!samp) break;
if (!samp->dataLength) {
e = gf_isom_remove_sample(movie, i, k+1);
if (e) return e;
} else {
e = gf_isom_update_sample(movie, i, k+1, samp, GF_TRUE);
if (e) return e;
}
gf_isom_sample_del(&samp);
}
}
i=0;
while ((trak = (GF_TrackBox *)gf_list_enum(movie->moov->trackList, &i))) {
if (trak == the_trak) continue;
if (! trak->References || ! gf_list_count(trak->References->other_boxes)) continue;
j=0;
while ((tref = (GF_TrackReferenceTypeBox *)gf_list_enum(trak->References->other_boxes, &j))) {
if (tref->reference_type==GF_4CC('s','c','a','l'))
continue;
found = 0;
for (k=0; k<tref->trackIDCount; k++) {
if (tref->trackIDs[k] == the_trak->Header->trackID) found++;
}
if (!found) continue;
if (found == tref->trackIDCount) {
gf_isom_box_del((GF_Box *)tref);
j--;
gf_list_rem(trak->References->other_boxes, j);
} else {
newRefs = (u32*)gf_malloc(sizeof(u32) * (tref->trackIDCount - found));
found = 0;
for (k = 0; k < tref->trackIDCount; k++) {
if (tref->trackIDs[k] != the_trak->Header->trackID) {
newRefs[k-found] = tref->trackIDs[k];
} else {
found++;
}
}
gf_free(tref->trackIDs);
tref->trackIDs = newRefs;
tref->trackIDCount -= found;
}
}
if (! gf_list_count(trak->References->other_boxes)) {
gf_isom_box_del((GF_Box *)trak->References);
trak->References = NULL;
}
}
gf_isom_box_del((GF_Box *)the_trak);
movie->moov->mvhd->nextTrackID = 0;
i=0;
while ((trak = (GF_TrackBox *)gf_list_enum(movie->moov->trackList, &i))) {
if (trak->Header->trackID>movie->moov->mvhd->nextTrackID)
movie->moov->mvhd->nextTrackID = trak->Header->trackID;
}
if (!gf_list_count(movie->moov->trackList)) {
gf_list_del_item(movie->TopBoxes, movie->moov);
gf_isom_box_del((GF_Box *)movie->moov);
movie->moov = NULL;
}
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_set_copyright(GF_ISOFile *movie, const char *threeCharCode, char *notice)
{
GF_Err e;
GF_CopyrightBox *ptr;
GF_UserDataMap *map;
u32 count, i;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
if (!notice || !threeCharCode) return GF_BAD_PARAM;
gf_isom_insert_moov(movie);
if (!movie->moov->udta) {
e = moov_AddBox((GF_Box*)movie->moov, gf_isom_box_new(GF_ISOM_BOX_TYPE_UDTA));
if (e) return e;
}
map = udta_getEntry(movie->moov->udta, GF_ISOM_BOX_TYPE_CPRT, NULL);
if (map) {
count = gf_list_count(map->other_boxes);
for (i=0; i<count; i++) {
ptr = (GF_CopyrightBox*)gf_list_get(map->other_boxes, i);
if (!strcmp(threeCharCode, (const char *) ptr->packedLanguageCode)) {
gf_free(ptr->notice);
ptr->notice = (char*)gf_malloc(sizeof(char) * (strlen(notice) + 1));
strcpy(ptr->notice, notice);
return GF_OK;
}
}
}
ptr = (GF_CopyrightBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_CPRT);
memcpy(ptr->packedLanguageCode, threeCharCode, 4);
ptr->notice = (char*)gf_malloc(sizeof(char) * (strlen(notice)+1));
strcpy(ptr->notice, notice);
return udta_AddBox((GF_Box *)movie->moov->udta, (GF_Box *) ptr);
}
GF_EXPORT
GF_Err gf_isom_add_track_kind(GF_ISOFile *movie, u32 trackNumber, const char *schemeURI, const char *value)
{
GF_Err e;
GF_KindBox *ptr;
GF_UserDataBox *udta;
GF_UserDataMap *map;
u32 i, count;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
gf_isom_insert_moov(movie);
if (trackNumber) {
GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
if (!trak->udta) {
e = trak_AddBox((GF_Box*)trak, gf_isom_box_new(GF_ISOM_BOX_TYPE_UDTA));
if (e) return e;
}
udta = trak->udta;
} else {
return GF_BAD_PARAM;
}
map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_KIND, NULL);
if (map) {
count = gf_list_count(map->other_boxes);
for (i=0; i<count; i++) {
GF_Box *b = (GF_Box *)gf_list_get(map->other_boxes, i);
if (b->type == GF_ISOM_BOX_TYPE_KIND) {
GF_KindBox *kb = (GF_KindBox *)b;
if (!strcmp(kb->schemeURI, schemeURI) &&
((value && kb->value && !strcmp(value, kb->value)) || (!value && !kb->value))) {
return GF_OK;
}
}
}
}
ptr = (GF_KindBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_KIND);
if (e) return e;
ptr->schemeURI = gf_strdup(schemeURI);
if (value) ptr->value = gf_strdup(value);
return udta_AddBox((GF_Box *)udta, (GF_Box *) ptr);
}
GF_EXPORT
GF_Err gf_isom_remove_track_kind(GF_ISOFile *movie, u32 trackNumber, const char *schemeURI, const char *value)
{
GF_Err e;
GF_UserDataBox *udta;
GF_UserDataMap *map;
u32 i;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
gf_isom_insert_moov(movie);
if (trackNumber) {
GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
if (!trak->udta) {
e = trak_AddBox((GF_Box*)trak, gf_isom_box_new(GF_ISOM_BOX_TYPE_UDTA));
if (e) return e;
}
udta = trak->udta;
} else {
return GF_OK;
}
map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_KIND, NULL);
if (map) {
for (i=0; i<gf_list_count(map->other_boxes); i++) {
GF_Box *b = (GF_Box *)gf_list_get(map->other_boxes, i);
if (b->type == GF_ISOM_BOX_TYPE_KIND) {
GF_KindBox *kb = (GF_KindBox *)b;
if (!schemeURI ||
(!strcmp(kb->schemeURI, schemeURI) &&
((value && kb->value && !strcmp(value, kb->value)) || (!value && !kb->value)))) {
gf_isom_box_del(b);
gf_list_rem(map->other_boxes, i);
i--;
}
}
}
}
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_add_chapter(GF_ISOFile *movie, u32 trackNumber, u64 timestamp, char *name)
{
GF_Err e;
GF_ChapterListBox *ptr;
u32 i, count;
GF_ChapterEntry *ce;
GF_UserDataBox *udta;
GF_UserDataMap *map;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
gf_isom_insert_moov(movie);
if (trackNumber) {
GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
if (!trak->udta) {
e = trak_AddBox((GF_Box*)trak, gf_isom_box_new(GF_ISOM_BOX_TYPE_UDTA));
if (e) return e;
}
udta = trak->udta;
} else {
if (!movie->moov->udta) {
e = moov_AddBox((GF_Box*)movie->moov, gf_isom_box_new(GF_ISOM_BOX_TYPE_UDTA));
if (e) return e;
}
udta = movie->moov->udta;
}
ptr = NULL;
map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_CHPL, NULL);
if (!map) {
ptr = (GF_ChapterListBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_CHPL);
e = udta_AddBox((GF_Box *)udta, (GF_Box *) ptr);
if (e) return e;
map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_CHPL, NULL);
} else {
ptr = (GF_ChapterListBox*)gf_list_get(map->other_boxes, 0);
}
if (!map) return GF_OUT_OF_MEM;
if (!ptr) {
ptr = (GF_ChapterListBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_CHPL);
if (!ptr) return GF_OUT_OF_MEM;
gf_list_add(map->other_boxes, ptr);
}
GF_SAFEALLOC(ce, GF_ChapterEntry);
if (!ce) return GF_OUT_OF_MEM;
ce->start_time = timestamp * 10000L;
ce->name = name ? gf_strdup(name) : NULL;
count = gf_list_count(ptr->list);
for (i=0; i<count; i++) {
GF_ChapterEntry *ace = (GF_ChapterEntry *)gf_list_get(ptr->list, i);
if (ace->start_time == ce->start_time) {
if (ace->name) gf_free(ace->name);
ace->name = ce->name;
gf_free(ce);
return GF_OK;
}
if (ace->start_time >= ce->start_time)
return gf_list_insert(ptr->list, ce, i);
}
return gf_list_add(ptr->list, ce);
}
GF_Err gf_isom_remove_chapter(GF_ISOFile *movie, u32 trackNumber, u32 index)
{
GF_Err e;
GF_ChapterListBox *ptr;
GF_ChapterEntry *ce;
GF_UserDataBox *udta;
GF_UserDataMap *map;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
gf_isom_insert_moov(movie);
if (trackNumber) {
GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
if (!trak->udta) {
e = trak_AddBox((GF_Box*)trak, gf_isom_box_new(GF_ISOM_BOX_TYPE_UDTA));
if (e) return e;
}
udta = trak->udta;
} else {
if (!movie->moov->udta) {
e = moov_AddBox((GF_Box*)movie->moov, gf_isom_box_new(GF_ISOM_BOX_TYPE_UDTA));
if (e) return e;
}
udta = movie->moov->udta;
}
map = udta_getEntry(udta, GF_ISOM_BOX_TYPE_CHPL, NULL);
if (!map) return GF_OK;
ptr = (GF_ChapterListBox*)gf_list_get(map->other_boxes, 0);
if (!ptr) return GF_OK;
if (index) {
ce = (GF_ChapterEntry *)gf_list_get(ptr->list, index-1);
if (!ce) return GF_BAD_PARAM;
if (ce->name) gf_free(ce->name);
gf_free(ce);
gf_list_rem(ptr->list, index-1);
} else {
while (gf_list_count(ptr->list)) {
ce = (GF_ChapterEntry *)gf_list_get(ptr->list, 0);
if (ce->name) gf_free(ce->name);
gf_free(ce);
gf_list_rem(ptr->list, 0);
}
}
if (!gf_list_count(ptr->list)) {
gf_list_del_item(udta->recordList, map);
gf_isom_box_array_del(map->other_boxes);
gf_free(map);
}
return GF_OK;
}
GF_Err gf_isom_remove_copyright(GF_ISOFile *movie, u32 index)
{
GF_Err e;
GF_CopyrightBox *ptr;
GF_UserDataMap *map;
u32 count;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
gf_isom_insert_moov(movie);
if (!index) return GF_BAD_PARAM;
if (!movie->moov->udta) return GF_OK;
map = udta_getEntry(movie->moov->udta, GF_ISOM_BOX_TYPE_CPRT, NULL);
if (!map) return GF_OK;
count = gf_list_count(map->other_boxes);
if (index>count) return GF_BAD_PARAM;
ptr = (GF_CopyrightBox*)gf_list_get(map->other_boxes, index-1);
if (ptr) {
gf_list_rem(map->other_boxes, index-1);
if (ptr->notice) gf_free(ptr->notice);
gf_free(ptr);
}
if (!gf_list_count(map->other_boxes)) {
gf_list_del_item(movie->moov->udta->recordList, map);
gf_list_del(map->other_boxes);
gf_free(map);
}
return GF_OK;
}
GF_Err gf_isom_set_watermark(GF_ISOFile *movie, bin128 UUID, u8* data, u32 length)
{
GF_Err e;
GF_UnknownUUIDBox *ptr;
GF_UserDataMap *map;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
gf_isom_insert_moov(movie);
if (!movie->moov->udta) {
e = moov_AddBox((GF_Box*)movie->moov, gf_isom_box_new(GF_ISOM_BOX_TYPE_UDTA));
if (e) return e;
}
map = udta_getEntry(movie->moov->udta, GF_ISOM_BOX_TYPE_UUID, (bin128 *) & UUID);
if (map) {
ptr = (GF_UnknownUUIDBox *)gf_list_get(map->other_boxes, 0);
if (ptr) {
gf_free(ptr->data);
ptr->data = (char*)gf_malloc(length);
memcpy(ptr->data, data, length);
ptr->dataSize = length;
return GF_OK;
}
}
ptr = (GF_UnknownUUIDBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_UUID);
memcpy(ptr->uuid, UUID, 16);
ptr->data = (char*)gf_malloc(length);
memcpy(ptr->data, data, length);
ptr->dataSize = length;
return udta_AddBox((GF_Box *)movie->moov->udta, (GF_Box *) ptr);
}
GF_Err gf_isom_set_interleave_time(GF_ISOFile *movie, u32 InterleaveTime)
{
GF_Err e;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
if (!InterleaveTime || !movie->moov) return GF_OK;
movie->interleavingTime = InterleaveTime;
return GF_OK;
}
u32 gf_isom_get_interleave_time(GF_ISOFile *movie)
{
return movie ? movie->interleavingTime : 0;
}
u8 gf_isom_get_storage_mode(GF_ISOFile *movie)
{
return movie ? movie->storageMode : 0;
}
GF_Err gf_isom_use_compact_size(GF_ISOFile *movie, u32 trackNumber, u8 CompactionOn)
{
GF_TrackBox *trak;
u32 i, size;
GF_SampleSizeBox *stsz;
GF_Err e;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
if (!trak->Media || !trak->Media->information
|| !trak->Media->information->sampleTable || !trak->Media->information->sampleTable->SampleSize)
return GF_ISOM_INVALID_FILE;
stsz = trak->Media->information->sampleTable->SampleSize;
if (!CompactionOn) {
if (stsz->type == GF_ISOM_BOX_TYPE_STSZ) return GF_OK;
stsz->type = GF_ISOM_BOX_TYPE_STSZ;
stsz->sampleSize = 0;
if (!stsz->sampleCount) return GF_OK;
if (!stsz->sizes) return GF_OK;
size = stsz->sizes[0];
for (i=1; i<stsz->sampleCount; i++) {
if (size != stsz->sizes[i]) {
size = 0;
break;
}
}
if (size) {
gf_free(stsz->sizes);
stsz->sizes = NULL;
stsz->sampleSize = size;
}
return GF_OK;
}
if (stsz->type == GF_ISOM_BOX_TYPE_STZ2) return GF_OK;
if (stsz->sampleSize) {
if (stsz->sizes) gf_free(stsz->sizes);
stsz->sizes = (u32*) gf_malloc(sizeof(u32)*stsz->sampleCount);
memset(stsz->sizes, stsz->sampleSize, sizeof(u32));
}
stsz->sampleSize = 0;
stsz->type = GF_ISOM_BOX_TYPE_STZ2;
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_set_brand_info(GF_ISOFile *movie, u32 MajorBrand, u32 MinorVersion)
{
u32 i, *p;
if (!MajorBrand) return GF_BAD_PARAM;
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
if (! (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY)) {
GF_Err e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
e = CheckNoData(movie);
if (e) return e;
}
#endif
if (!movie->brand) {
movie->brand = (GF_FileTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_FTYP);
gf_list_add(movie->TopBoxes, movie->brand);
}
movie->brand->majorBrand = MajorBrand;
movie->brand->minorVersion = MinorVersion;
if (!movie->brand->altBrand) {
movie->brand->altBrand = (u32*)gf_malloc(sizeof(u32));
movie->brand->altBrand[0] = MajorBrand;
movie->brand->altCount = 1;
return GF_OK;
}
for (i=0; i<movie->brand->altCount; i++) {
if (movie->brand->altBrand[i] == MajorBrand) return GF_OK;
}
p = (u32*)gf_malloc(sizeof(u32)*(movie->brand->altCount + 1));
if (!p) return GF_OUT_OF_MEM;
memcpy(p, movie->brand->altBrand, sizeof(u32)*movie->brand->altCount);
p[movie->brand->altCount] = MajorBrand;
movie->brand->altCount += 1;
gf_free(movie->brand->altBrand);
movie->brand->altBrand = p;
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_modify_alternate_brand(GF_ISOFile *movie, u32 Brand, u8 AddIt)
{
u32 i, k, *p;
if (!Brand) return GF_BAD_PARAM;
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
if (! (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY)) {
GF_Err e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
e = CheckNoData(movie);
if (e) return e;
}
#endif
if (!movie->brand && AddIt) {
movie->brand = (GF_FileTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_FTYP);
if (!movie->brand) return GF_OUT_OF_MEM;
gf_list_add(movie->TopBoxes, movie->brand);
}
if (!AddIt && !movie->brand) return GF_OK;
if (!AddIt && movie->brand->majorBrand == Brand) return GF_OK;
if (!AddIt && movie->brand->altCount == 1) {
movie->brand->altBrand[0] = movie->brand->majorBrand;
return GF_OK;
}
for (i=0; i<movie->brand->altCount; i++) {
if (movie->brand->altBrand[i] == Brand) goto found;
}
if (!AddIt) return GF_OK;
p = (u32*)gf_malloc(sizeof(u32)*(movie->brand->altCount + 1));
if (!p) return GF_OUT_OF_MEM;
memcpy(p, movie->brand->altBrand, sizeof(u32)*movie->brand->altCount);
p[movie->brand->altCount] = Brand;
movie->brand->altCount += 1;
gf_free(movie->brand->altBrand);
movie->brand->altBrand = p;
return GF_OK;
found:
if (AddIt) return GF_OK;
assert(movie->brand->altCount>1);
p = (u32*)gf_malloc(sizeof(u32)*(movie->brand->altCount - 1));
if (!p) return GF_OUT_OF_MEM;
k = 0;
for (i=0; i<movie->brand->altCount; i++) {
if (movie->brand->altBrand[i] == Brand) continue;
else {
p[k] = movie->brand->altBrand[i];
k++;
}
}
movie->brand->altCount -= 1;
gf_free(movie->brand->altBrand);
movie->brand->altBrand = p;
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_reset_alt_brands(GF_ISOFile *movie)
{
u32 *p;
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
if (! (movie->FragmentsFlags & GF_ISOM_FRAG_WRITE_READY)) {
GF_Err e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
e = CheckNoData(movie);
if (e) return e;
}
#endif
if (!movie->brand) {
movie->brand = (GF_FileTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_FTYP);
gf_list_add(movie->TopBoxes, movie->brand);
}
p = (u32*)gf_malloc(sizeof(u32));
if (!p) return GF_OUT_OF_MEM;
p[0] = movie->brand->majorBrand;
movie->brand->altCount = 1;
gf_free(movie->brand->altBrand);
movie->brand->altBrand = p;
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_set_sample_padding_bits(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber, u8 NbBits)
{
GF_TrackBox *trak;
GF_Err e;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak || NbBits > 7) return GF_BAD_PARAM;
return stbl_SetPaddingBits(trak->Media->information->sampleTable, sampleNumber, NbBits);
}
GF_EXPORT
GF_Err gf_isom_remove_user_data_item(GF_ISOFile *movie, u32 trackNumber, u32 UserDataType, bin128 UUID, u32 UserDataIndex)
{
GF_UserDataMap *map;
GF_Box *a;
u32 i;
bin128 t;
GF_Err e;
GF_TrackBox *trak;
GF_UserDataBox *udta;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
if (UserDataType == GF_ISOM_BOX_TYPE_UUID) UserDataType = 0;
memset(t, 1, 16);
if (trackNumber) {
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
udta = trak->udta;
} else {
udta = movie->moov->udta;
}
if (!udta) return GF_BAD_PARAM;
if (!UserDataIndex) return GF_BAD_PARAM;
i=0;
while ((map = (GF_UserDataMap*)gf_list_enum(udta->recordList, &i))) {
if ((map->boxType == GF_ISOM_BOX_TYPE_UUID) && !memcmp(map->uuid, UUID, 16)) goto found;
else if (map->boxType == UserDataType) goto found;
}
return GF_OK;
found:
if (UserDataIndex > gf_list_count(map->other_boxes) ) return GF_BAD_PARAM;
a = (GF_Box*)gf_list_get(map->other_boxes, UserDataIndex-1);
gf_list_rem(map->other_boxes, UserDataIndex-1);
gf_isom_box_del(a);
if (!gf_list_count(map->other_boxes)) {
gf_list_rem(udta->recordList, i-1);
gf_isom_box_array_del(map->other_boxes);
gf_free(map);
}
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_remove_user_data(GF_ISOFile *movie, u32 trackNumber, u32 UserDataType, bin128 UUID)
{
GF_UserDataMap *map;
u32 i;
GF_Err e;
bin128 t;
GF_TrackBox *trak;
GF_UserDataBox *udta;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
if (UserDataType == GF_ISOM_BOX_TYPE_UUID) UserDataType = 0;
memset(t, 1, 16);
if (trackNumber) {
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
udta = trak->udta;
} else {
udta = movie->moov->udta;
}
if (!udta) return GF_BAD_PARAM;
i=0;
while ((map = (GF_UserDataMap*)gf_list_enum(udta->recordList, &i))) {
if ((map->boxType == GF_ISOM_BOX_TYPE_UUID) && !memcmp(map->uuid, UUID, 16)) goto found;
else if (map->boxType == UserDataType) goto found;
}
return GF_OK;
found:
gf_list_rem(udta->recordList, i-1);
gf_isom_box_array_del(map->other_boxes);
gf_free(map);
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_add_user_data(GF_ISOFile *movie, u32 trackNumber, u32 UserDataType, bin128 UUID, char *data, u32 DataLength)
{
GF_Err e;
GF_TrackBox *trak;
GF_UserDataBox *udta;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
if (UserDataType == GF_ISOM_BOX_TYPE_UUID) UserDataType = 0;
if (trackNumber) {
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
if (!trak->udta) trak_AddBox((GF_Box*)trak, gf_isom_box_new(GF_ISOM_BOX_TYPE_UDTA));
udta = trak->udta;
} else {
if (!movie->moov->udta) moov_AddBox((GF_Box*)movie->moov, gf_isom_box_new(GF_ISOM_BOX_TYPE_UDTA));
udta = movie->moov->udta;
}
if (!udta) return GF_OUT_OF_MEM;
if (UserDataType) {
GF_UnknownBox *a = (GF_UnknownBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_UNKNOWN);
a->original_4cc = UserDataType;
if (DataLength) {
a->data = (char*)gf_malloc(sizeof(char)*DataLength);
memcpy(a->data, data, DataLength);
a->dataSize = DataLength;
}
return udta_AddBox((GF_Box *)udta, (GF_Box *) a);
} else {
GF_UnknownUUIDBox *a = (GF_UnknownUUIDBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_UUID);
memcpy(a->uuid, UUID, 16);
if (DataLength) {
a->data = (char*)gf_malloc(sizeof(char)*DataLength);
memcpy(a->data, data, DataLength);
a->dataSize = DataLength;
}
return udta_AddBox((GF_Box *)udta, (GF_Box *) a);
}
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_add_user_data_boxes(GF_ISOFile *movie, u32 trackNumber, char *data, u32 DataLength)
{
GF_Err e;
GF_TrackBox *trak;
GF_UserDataBox *udta;
GF_BitStream *bs;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
if (trackNumber) {
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
if (!trak->udta) trak_AddBox((GF_Box*)trak, gf_isom_box_new(GF_ISOM_BOX_TYPE_UDTA));
udta = trak->udta;
} else {
if (!movie->moov) return GF_BAD_PARAM;
if (!movie->moov->udta) moov_AddBox((GF_Box*)movie->moov, gf_isom_box_new(GF_ISOM_BOX_TYPE_UDTA));
udta = movie->moov->udta;
}
if (!udta) return GF_OUT_OF_MEM;
bs = gf_bs_new(data, DataLength, GF_BITSTREAM_READ);
while (gf_bs_available(bs)) {
GF_Box *a;
e = gf_isom_box_parse(&a, bs);
if (e) break;
e = udta_AddBox((GF_Box *)udta, a);
if (e) break;
}
gf_bs_del(bs);
return e;
}
GF_Err gf_isom_add_sample_fragment(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber, u16 FragmentSize)
{
GF_Err e;
GF_TrackBox *trak;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak || !sampleNumber || !FragmentSize) return GF_BAD_PARAM;
return stbl_AddSampleFragment(trak->Media->information->sampleTable, sampleNumber, FragmentSize);
}
GF_EXPORT
GF_Err gf_isom_remove_sample_fragment(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber)
{
GF_TrackBox *trak;
GF_Err e;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
return stbl_RemoveSampleFragments(trak->Media->information->sampleTable, sampleNumber);
}
GF_Err gf_isom_remove_sample_fragments(GF_ISOFile *movie, u32 trackNumber)
{
GF_TrackBox *trak;
GF_Err e;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
if (trak->Media->information->sampleTable->Fragments) {
gf_isom_box_del((GF_Box *)trak->Media->information->sampleTable->Fragments);
trak->Media->information->sampleTable->Fragments = NULL;
}
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_clone_pl_indications(GF_ISOFile *orig, GF_ISOFile *dest)
{
GF_IsomInitialObjectDescriptor *iod_d;
if (!orig || !dest) return GF_BAD_PARAM;
if (!orig->moov->iods || !orig->moov->iods->descriptor) return GF_OK;
if (orig->moov->iods->descriptor->tag != GF_ODF_ISOM_IOD_TAG) return GF_OK;
AddMovieIOD(dest->moov, 1);
gf_odf_desc_del((GF_Descriptor *)dest->moov->iods->descriptor);
gf_odf_desc_copy((GF_Descriptor *)orig->moov->iods->descriptor, (GF_Descriptor **)&dest->moov->iods->descriptor);
iod_d = (GF_IsomInitialObjectDescriptor *) dest->moov->iods->descriptor;
while (gf_list_count(iod_d->ES_ID_IncDescriptors)) {
GF_Descriptor *d = (GF_Descriptor *)gf_list_get(iod_d->ES_ID_IncDescriptors, 0);
gf_list_rem(iod_d->ES_ID_IncDescriptors, 0);
gf_odf_desc_del(d);
}
while (gf_list_count(iod_d->ES_ID_RefDescriptors)) {
GF_Descriptor *d = (GF_Descriptor *)gf_list_get(iod_d->ES_ID_RefDescriptors, 0);
gf_list_rem(iod_d->ES_ID_RefDescriptors, 0);
gf_odf_desc_del(d);
}
return GF_OK;
}
GF_Err gf_isom_clone_box(GF_Box *src, GF_Box **dst)
{
GF_Err e;
char *data;
u32 data_size;
GF_BitStream *bs;
if (*dst) {
gf_isom_box_del(*dst);
*dst=NULL;
}
bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
if (!bs) return GF_OUT_OF_MEM;
e = gf_isom_box_size( (GF_Box *) src);
if (!e) e = gf_isom_box_write((GF_Box *) src, bs);
gf_bs_get_content(bs, &data, &data_size);
gf_bs_del(bs);
if (e) return e;
bs = gf_bs_new(data, data_size, GF_BITSTREAM_READ);
if (!bs) return GF_OUT_OF_MEM;
e = gf_isom_box_parse(dst, bs);
gf_bs_del(bs);
gf_free(data);
return e;
}
GF_Err gf_isom_clone_movie(GF_ISOFile *orig_file, GF_ISOFile *dest_file, Bool clone_tracks, Bool keep_hint_tracks, Bool keep_pssh)
{
GF_Err e;
u32 i;
GF_Box *box;
e = CanAccessMovie(dest_file, GF_ISOM_OPEN_WRITE);
if (e) return e;
if (orig_file->brand) {
gf_list_del_item(dest_file->TopBoxes, dest_file->brand);
gf_isom_box_del((GF_Box *)dest_file->brand);
dest_file->brand = NULL;
gf_isom_clone_box((GF_Box *)orig_file->brand, (GF_Box **)&dest_file->brand);
if (dest_file->brand) gf_list_add(dest_file->TopBoxes, dest_file->brand);
}
if (orig_file->meta) {
gf_list_del_item(dest_file->TopBoxes, dest_file->meta);
gf_isom_box_del((GF_Box *)dest_file->meta);
dest_file->meta = NULL;
gf_isom_clone_box((GF_Box *)orig_file->meta, (GF_Box **)&dest_file->meta);
if (dest_file->meta) gf_list_add(dest_file->TopBoxes, dest_file->meta);
}
if (orig_file->moov) {
u32 i, dstTrack;
GF_Box *iods;
GF_List *tracks = gf_list_new();
GF_List *old_tracks = orig_file->moov->trackList;
orig_file->moov->trackList = tracks;
iods = (GF_Box*)orig_file->moov->iods;
orig_file->moov->iods = NULL;
e = gf_isom_clone_box((GF_Box *)orig_file->moov, (GF_Box **)&dest_file->moov);
if (e) {
gf_list_del(tracks);
orig_file->moov->trackList = old_tracks;
return e;
}
orig_file->moov->trackList = old_tracks;
gf_list_del(tracks);
orig_file->moov->iods = (GF_ObjectDescriptorBox*)iods;
gf_list_add(dest_file->TopBoxes, dest_file->moov);
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
if (dest_file->moov->mvex) {
gf_isom_box_del((GF_Box *)dest_file->moov->mvex);
dest_file->moov->mvex = NULL;
}
#endif
if (clone_tracks) {
for (i=0; i<gf_list_count(orig_file->moov->trackList); i++) {
GF_TrackBox *trak = (GF_TrackBox*)gf_list_get( orig_file->moov->trackList, i);
if (!trak) continue;
if (keep_hint_tracks || (trak->Media->handler->handlerType != GF_ISOM_MEDIA_HINT)) {
e = gf_isom_clone_track(orig_file, i+1, dest_file, GF_FALSE, &dstTrack);
if (e) return e;
}
}
if (iods)
gf_isom_clone_box((GF_Box *)orig_file->moov->iods, (GF_Box **)dest_file->moov->iods);
} else {
dest_file->moov->mvhd->nextTrackID = 1;
gf_isom_clone_pl_indications(orig_file, dest_file);
}
dest_file->moov->mov = dest_file;
}
if (!keep_pssh) {
i=0;
while ((box = (GF_Box*)gf_list_get(dest_file->moov->other_boxes, i++))) {
if (box->type == GF_ISOM_BOX_TYPE_PSSH) {
i--;
gf_list_rem(dest_file->moov->other_boxes, i);
gf_isom_box_del(box);
}
}
}
i=0;
while ((box = (GF_Box*)gf_list_get(orig_file->TopBoxes, i++))) {
switch(box->type) {
case GF_ISOM_BOX_TYPE_MOOV:
case GF_ISOM_BOX_TYPE_META:
case GF_ISOM_BOX_TYPE_MDAT:
case GF_ISOM_BOX_TYPE_FTYP:
case GF_ISOM_BOX_TYPE_PDIN:
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
case GF_ISOM_BOX_TYPE_STYP:
case GF_ISOM_BOX_TYPE_SIDX:
case GF_ISOM_BOX_TYPE_SSIX:
case GF_ISOM_BOX_TYPE_MOOF:
#endif
case GF_4CC('j','P',' ',' '):
break;
case GF_ISOM_BOX_TYPE_PSSH:
if (!keep_pssh)
break;
default:
{
GF_Box *box2 = NULL;
gf_isom_clone_box(box, &box2);
gf_list_add(dest_file->TopBoxes, box2);
}
break;
}
}
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_clone_track(GF_ISOFile *orig_file, u32 orig_track, GF_ISOFile *dest_file, Bool keep_data_ref, u32 *dest_track)
{
GF_TrackBox *trak, *new_tk;
GF_BitStream *bs;
char *data;
const char *buffer;
u32 data_size;
Double ts_scale;
GF_Err e;
GF_SampleEntryBox *entry;
GF_SampleTableBox *stbl, *stbl_temp;
e = CanAccessMovie(dest_file, GF_ISOM_OPEN_WRITE);
if (e) return e;
gf_isom_insert_moov(dest_file);
trak = gf_isom_get_track_from_file(orig_file, orig_track);
if (!trak || !trak->Media) return GF_BAD_PARAM;
stbl = trak->Media->information->sampleTable;
stbl_temp = (GF_SampleTableBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STBL);
stbl_temp->SampleDescription = stbl->SampleDescription;
stbl_temp->sampleGroupsDescription = stbl->sampleGroupsDescription;
trak->Media->information->sampleTable = stbl_temp;
stbl_temp->CompositionToDecode = stbl->CompositionToDecode;
bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
gf_isom_box_size( (GF_Box *) trak);
gf_isom_box_write((GF_Box *) trak, bs);
gf_bs_get_content(bs, &data, &data_size);
gf_bs_del(bs);
bs = gf_bs_new(data, data_size, GF_BITSTREAM_READ);
e = gf_isom_box_parse((GF_Box **) &new_tk, bs);
gf_bs_del(bs);
gf_free(data);
trak->Media->information->sampleTable = stbl;
stbl_temp->SampleDescription = NULL;
stbl_temp->sampleGroupsDescription = NULL;
stbl_temp->CompositionToDecode = NULL;
gf_isom_box_del((GF_Box *)stbl_temp);
if (e) return e;
stbl = new_tk->Media->information->sampleTable;
stbl->ChunkOffset = gf_isom_box_new(GF_ISOM_BOX_TYPE_STCO);
stbl->SampleSize = (GF_SampleSizeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STSZ);
stbl->SampleToChunk = (GF_SampleToChunkBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STSC);
stbl->TimeToSample = (GF_TimeToSampleBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STTS);
if (gf_isom_get_track_by_id(dest_file, new_tk->Header->trackID)) {
u32 ID = 1;
while (1) {
if (RequestTrack(dest_file->moov, ID)) break;
ID += 1;
if (ID == 0xFFFFFFFF) break;
}
new_tk->Header->trackID = ID;
}
moov_AddBox((GF_Box*)dest_file->moov, (GF_Box *)new_tk);
new_tk->originalID = trak->Header->trackID;
buffer = gf_isom_get_filename(orig_file);
new_tk->originalFile = gf_crc_32(buffer, sizeof(buffer));
ts_scale = dest_file->moov->mvhd->timeScale;
ts_scale /= orig_file->moov->mvhd->timeScale;
new_tk->Header->duration = (u64) (s64) ((s64) new_tk->Header->duration * ts_scale);
if (new_tk->editBox && new_tk->editBox->editList) {
u32 i, count = gf_list_count(new_tk->editBox->editList->entryList);
for (i=0; i<count; i++) {
GF_EdtsEntry *ent = (GF_EdtsEntry *)gf_list_get(new_tk->editBox->editList->entryList, i);
ent->segmentDuration = (u64) (s64) ((s64) ent->segmentDuration * ts_scale);
}
}
if (!keep_data_ref) {
gf_isom_box_array_del(new_tk->Media->information->dataInformation->dref->other_boxes);
new_tk->Media->information->dataInformation->dref->other_boxes = gf_list_new();
entry = (GF_SampleEntryBox*)gf_list_get(new_tk->Media->information->sampleTable->SampleDescription->other_boxes, 0);
if (entry) {
u32 dref;
Media_CreateDataRef(new_tk->Media->information->dataInformation->dref, NULL, NULL, &dref);
entry->dataReferenceIndex = dref;
}
} else {
u32 i;
for (i=0; i<gf_list_count(new_tk->Media->information->dataInformation->dref->other_boxes); i++) {
GF_DataEntryBox *dref_entry = (GF_DataEntryBox *)gf_list_get(new_tk->Media->information->dataInformation->dref->other_boxes, i);
if (dref_entry->flags & 1) {
dref_entry->flags &= ~1;
dref_entry->location = gf_strdup(orig_file->fileName);
}
}
}
*dest_track = gf_list_count(dest_file->moov->trackList);
if (dest_file->moov->mvhd->nextTrackID<= new_tk->Header->trackID)
dest_file->moov->mvhd->nextTrackID = new_tk->Header->trackID+1;
return GF_OK;
}
GF_Err gf_isom_clone_sample_descriptions(GF_ISOFile *the_file, u32 trackNumber, GF_ISOFile *orig_file, u32 orig_track, Bool reset_existing)
{
u32 i;
GF_TrackBox *dst_trak, *src_trak;
GF_Err e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE);
if (e) return e;
dst_trak = gf_isom_get_track_from_file(the_file, trackNumber);
if (!dst_trak || !dst_trak->Media) return GF_BAD_PARAM;
src_trak = gf_isom_get_track_from_file(orig_file, orig_track);
if (!src_trak || !src_trak->Media) return GF_BAD_PARAM;
if (reset_existing) {
gf_isom_box_array_del(dst_trak->Media->information->sampleTable->SampleDescription->other_boxes);
dst_trak->Media->information->sampleTable->SampleDescription->other_boxes = gf_list_new();
}
for (i=0; i<gf_list_count(src_trak->Media->information->sampleTable->SampleDescription->other_boxes); i++) {
u32 outDesc;
e = gf_isom_clone_sample_description(the_file, trackNumber, orig_file, orig_track, i+1, NULL, NULL, &outDesc);
if (e) break;
}
return e;
}
GF_EXPORT
GF_Err gf_isom_clone_sample_description(GF_ISOFile *the_file, u32 trackNumber, GF_ISOFile *orig_file, u32 orig_track, u32 orig_desc_index, char *URLname, char *URNname, u32 *outDescriptionIndex)
{
GF_TrackBox *trak;
GF_BitStream *bs;
char *data;
u32 data_size;
GF_Box *entry;
GF_Err e;
u32 dataRefIndex;
e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(orig_file, orig_track);
if (!trak || !trak->Media) return GF_BAD_PARAM;
entry = (GF_Box*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, orig_desc_index-1);
if (!entry) return GF_BAD_PARAM;
bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
gf_isom_box_size(entry);
gf_isom_box_write(entry, bs);
gf_bs_get_content(bs, &data, &data_size);
gf_bs_del(bs);
bs = gf_bs_new(data, data_size, GF_BITSTREAM_READ);
e = gf_isom_box_parse(&entry, bs);
gf_bs_del(bs);
gf_free(data);
if (e) return e;
trak = gf_isom_get_track_from_file(the_file, trackNumber);
if (!trak || !trak->Media) goto exit;
e = Media_FindDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex);
if (e) goto exit;
if (!dataRefIndex) {
e = Media_CreateDataRef(trak->Media->information->dataInformation->dref, URLname, URNname, &dataRefIndex);
if (e) goto exit;
}
if (!the_file->keep_utc)
trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
((GF_SampleEntryBox *)entry)->dataReferenceIndex = dataRefIndex;
e = gf_list_add(trak->Media->information->sampleTable->SampleDescription->other_boxes, entry);
*outDescriptionIndex = gf_list_count(trak->Media->information->sampleTable->SampleDescription->other_boxes);
if (gf_isom_get_media_type(the_file, trackNumber) == GF_ISOM_MEDIA_VISUAL) {
gf_isom_set_visual_info(the_file, trackNumber, (*outDescriptionIndex), ((GF_VisualSampleEntryBox*)entry)->Width, ((GF_VisualSampleEntryBox*)entry)->Height);
}
return e;
exit:
gf_isom_box_del(entry);
return e;
}
GF_Err gf_isom_new_generic_sample_description(GF_ISOFile *movie, u32 trackNumber, char *URLname, char *URNname, GF_GenericSampleDescription *udesc, u32 *outDescriptionIndex)
{
GF_TrackBox *trak;
GF_Err e;
u32 dataRefIndex;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak || !trak->Media || !udesc) return GF_BAD_PARAM;
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;
}
if (!movie->keep_utc)
trak->Media->mediaHeader->modificationTime = gf_isom_get_mp4time();
if (trak->Media->handler->handlerType==GF_ISOM_MEDIA_VISUAL) {
GF_GenericVisualSampleEntryBox *entry;
entry = (GF_GenericVisualSampleEntryBox*) gf_isom_box_new(GF_ISOM_BOX_TYPE_GNRV);
if (!entry) return GF_OUT_OF_MEM;
if (!udesc->codec_tag) {
entry->EntryType = GF_ISOM_BOX_TYPE_UUID;
memcpy(entry->uuid, udesc->UUID, sizeof(bin128));
} else {
entry->EntryType = udesc->codec_tag;
}
entry->dataReferenceIndex = dataRefIndex;
entry->vendor = udesc->vendor_code;
entry->version = udesc->version;
entry->revision = udesc->revision;
entry->temporal_quality = udesc->temporal_quality;
entry->spatial_quality = udesc->spatial_quality;
entry->Width = udesc->width;
entry->Height = udesc->height;
strcpy(entry->compressor_name, udesc->compressor_name);
entry->color_table_index = -1;
entry->frames_per_sample = 1;
entry->horiz_res = udesc->h_res ? udesc->h_res : 0x00480000;
entry->vert_res = udesc->v_res ? udesc->v_res : 0x00480000;
entry->bit_depth = udesc->depth ? udesc->depth : 0x18;
if (udesc->extension_buf && udesc->extension_buf_size) {
entry->data = (char*)gf_malloc(sizeof(char) * udesc->extension_buf_size);
if (!entry->data) {
gf_isom_box_del((GF_Box *) entry);
return GF_OUT_OF_MEM;
}
memcpy(entry->data, udesc->extension_buf, udesc->extension_buf_size);
entry->data_size = udesc->extension_buf_size;
}
e = gf_list_add(trak->Media->information->sampleTable->SampleDescription->other_boxes, entry);
}
else if (trak->Media->handler->handlerType==GF_ISOM_MEDIA_AUDIO) {
GF_GenericAudioSampleEntryBox *gena;
gena = (GF_GenericAudioSampleEntryBox*) gf_isom_box_new(GF_ISOM_BOX_TYPE_GNRA);
if (!gena) return GF_OUT_OF_MEM;
if (!udesc->codec_tag) {
gena->EntryType = GF_ISOM_BOX_TYPE_UUID;
memcpy(gena->uuid, udesc->UUID, sizeof(bin128));
} else {
gena->EntryType = udesc->codec_tag;
}
gena->dataReferenceIndex = dataRefIndex;
gena->vendor = udesc->vendor_code;
gena->version = udesc->version;
gena->revision = udesc->revision;
gena->bitspersample = udesc->bits_per_sample ? udesc->bits_per_sample : 16;
gena->channel_count = udesc->nb_channels ? udesc->nb_channels : 2;
gena->samplerate_hi = udesc->samplerate;
gena->samplerate_lo = 0;
if (udesc->extension_buf && udesc->extension_buf_size) {
gena->data = (char*)gf_malloc(sizeof(char) * udesc->extension_buf_size);
if (!gena->data) {
gf_isom_box_del((GF_Box *) gena);
return GF_OUT_OF_MEM;
}
memcpy(gena->data, udesc->extension_buf, udesc->extension_buf_size);
gena->data_size = udesc->extension_buf_size;
}
e = gf_list_add(trak->Media->information->sampleTable->SampleDescription->other_boxes, gena);
}
else {
GF_GenericSampleEntryBox *genm;
genm = (GF_GenericSampleEntryBox*) gf_isom_box_new(GF_ISOM_BOX_TYPE_GNRM);
if (!genm) return GF_OUT_OF_MEM;
if (!udesc->codec_tag) {
genm->EntryType = GF_ISOM_BOX_TYPE_UUID;
memcpy(genm->uuid, udesc->UUID, sizeof(bin128));
} else {
genm->EntryType = udesc->codec_tag;
}
genm->dataReferenceIndex = dataRefIndex;
if (udesc->extension_buf && udesc->extension_buf_size) {
genm->data = (char*)gf_malloc(sizeof(char) * udesc->extension_buf_size);
if (!genm->data) {
gf_isom_box_del((GF_Box *) genm);
return GF_OUT_OF_MEM;
}
memcpy(genm->data, udesc->extension_buf, udesc->extension_buf_size);
genm->data_size = udesc->extension_buf_size;
}
e = gf_list_add(trak->Media->information->sampleTable->SampleDescription->other_boxes, genm);
}
*outDescriptionIndex = gf_list_count(trak->Media->information->sampleTable->SampleDescription->other_boxes);
return e;
}
GF_Err gf_isom_change_generic_sample_description(GF_ISOFile *movie, u32 trackNumber, u32 StreamDescriptionIndex, GF_GenericSampleDescription *udesc)
{
GF_TrackBox *trak;
GF_Err e;
GF_GenericVisualSampleEntryBox *entry;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak || !trak->Media || !StreamDescriptionIndex) return GF_BAD_PARAM;
entry = (GF_GenericVisualSampleEntryBox *)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, StreamDescriptionIndex-1);
if (!entry) return GF_BAD_PARAM;
if (entry->type == GF_ISOM_BOX_TYPE_GNRV) {
entry->vendor = udesc->vendor_code;
entry->version = udesc->version;
entry->revision = udesc->revision;
entry->temporal_quality = udesc->temporal_quality;
entry->spatial_quality = udesc->spatial_quality;
entry->Width = udesc->width;
entry->Height = udesc->height;
strcpy(entry->compressor_name, udesc->compressor_name);
entry->color_table_index = -1;
entry->frames_per_sample = 1;
entry->horiz_res = udesc->h_res ? udesc->h_res : 0x00480000;
entry->vert_res = udesc->v_res ? udesc->v_res : 0x00480000;
entry->bit_depth = udesc->depth ? udesc->depth : 0x18;
if (entry->data) gf_free(entry->data);
entry->data = NULL;
entry->data_size = 0;
if (udesc->extension_buf && udesc->extension_buf_size) {
entry->data = (char*)gf_malloc(sizeof(char) * udesc->extension_buf_size);
if (!entry->data) {
gf_isom_box_del((GF_Box *) entry);
return GF_OUT_OF_MEM;
}
memcpy(entry->data, udesc->extension_buf, udesc->extension_buf_size);
entry->data_size = udesc->extension_buf_size;
}
return GF_OK;
} else if (entry->type == GF_ISOM_BOX_TYPE_GNRA) {
GF_GenericAudioSampleEntryBox *gena = (GF_GenericAudioSampleEntryBox *)entry;
gena->vendor = udesc->vendor_code;
gena->version = udesc->version;
gena->revision = udesc->revision;
gena->bitspersample = udesc->bits_per_sample ? udesc->bits_per_sample : 16;
gena->channel_count = udesc->nb_channels ? udesc->nb_channels : 2;
gena->samplerate_hi = udesc->samplerate;
gena->samplerate_lo = 0;
if (gena->data) gf_free(gena->data);
gena->data = NULL;
gena->data_size = 0;
if (udesc->extension_buf && udesc->extension_buf_size) {
gena->data = (char*)gf_malloc(sizeof(char) * udesc->extension_buf_size);
if (!gena->data) {
gf_isom_box_del((GF_Box *) gena);
return GF_OUT_OF_MEM;
}
memcpy(gena->data, udesc->extension_buf, udesc->extension_buf_size);
gena->data_size = udesc->extension_buf_size;
}
return GF_OK;
} else if (entry->type == GF_ISOM_BOX_TYPE_GNRM) {
GF_GenericSampleEntryBox *genm = (GF_GenericSampleEntryBox *)entry;
if (genm->data) gf_free(genm->data);
genm->data = NULL;
genm->data_size = 0;
if (udesc->extension_buf && udesc->extension_buf_size) {
genm->data = (char*)gf_malloc(sizeof(char) * udesc->extension_buf_size);
if (!genm->data) {
gf_isom_box_del((GF_Box *) genm);
return GF_OUT_OF_MEM;
}
memcpy(genm->data, udesc->extension_buf, udesc->extension_buf_size);
genm->data_size = udesc->extension_buf_size;
}
return GF_OK;
}
return GF_BAD_PARAM;
}
GF_Err gf_isom_remove_sample_description(GF_ISOFile *movie, u32 trackNumber, u32 streamDescIndex)
{
GF_TrackBox *trak;
GF_Err e;
GF_Box *entry;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak || !trak->Media || !streamDescIndex) return GF_BAD_PARAM;
entry = (GF_Box*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, streamDescIndex-1);
if (!entry) return GF_BAD_PARAM;
gf_list_rem(trak->Media->information->sampleTable->SampleDescription->other_boxes, streamDescIndex-1);
gf_isom_box_del(entry);
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_set_track_reference(GF_ISOFile *the_file, u32 trackNumber, u32 referenceType, u32 ReferencedTrackID)
{
GF_Err e;
GF_TrackBox *trak;
GF_TrackReferenceBox *tref;
GF_TrackReferenceTypeBox *dpnd;
trak = gf_isom_get_track_from_file(the_file, trackNumber);
if (!trak) return GF_BAD_PARAM;
tref = trak->References;
if (!tref) {
tref = (GF_TrackReferenceBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_TREF);
e = trak_AddBox((GF_Box*)trak, (GF_Box *) tref);
if (e) return e;
}
e = Track_FindRef(trak, referenceType, &dpnd);
if (e) return e;
if (!dpnd) {
dpnd = (GF_TrackReferenceTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_REFT);
dpnd->reference_type = referenceType;
e = tref_AddBox((GF_Box*)tref, (GF_Box *)dpnd);
if (e) return e;
}
return reftype_AddRefTrack(dpnd, ReferencedTrackID, NULL);
}
GF_EXPORT
GF_Err gf_isom_remove_track_reference(GF_ISOFile *the_file, u32 trackNumber, u32 referenceType, u32 ReferenceIndex)
{
GF_Err e;
GF_TrackBox *trak;
GF_TrackReferenceBox *tref;
GF_TrackReferenceTypeBox *dpnd, *tmp;
u32 i, k, *newIDs;
trak = gf_isom_get_track_from_file(the_file, trackNumber);
if (!trak || !ReferenceIndex) return GF_BAD_PARAM;
tref = trak->References;
if (!tref) return GF_OK;
e = Track_FindRef(trak, referenceType, &dpnd);
if (e || !dpnd) return GF_OK;
if (ReferenceIndex > dpnd->trackIDCount) return GF_BAD_PARAM;
if (dpnd->trackIDCount==1) {
i=0;
while ((tmp = (GF_TrackReferenceTypeBox *)gf_list_enum(tref->other_boxes, &i))) {
if (tmp==dpnd) {
gf_list_rem(tref->other_boxes, i-1);
gf_isom_box_del((GF_Box *) dpnd);
return GF_OK;
}
}
}
k = 0;
newIDs = (u32*)gf_malloc(sizeof(u32)*(dpnd->trackIDCount-1));
for (i=0; i<dpnd->trackIDCount; i++) {
if (i+1 != ReferenceIndex) {
newIDs[k] = dpnd->trackIDs[i];
k++;
}
}
gf_free(dpnd->trackIDs);
dpnd->trackIDCount -= 1;
dpnd->trackIDs = newIDs;
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_set_track_id(GF_ISOFile *movie, u32 trackNumber, u32 trackID)
{
GF_TrackReferenceTypeBox *ref;
GF_TrackBox *trak, *a_trak;
u32 i, j, k;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (trak && (trak->Header->trackID==trackID)) return GF_OK;
a_trak = gf_isom_get_track_from_id(movie->moov, trackID);
if (!movie || !trak || a_trak) return GF_BAD_PARAM;
if (movie->moov->mvhd->nextTrackID<=trackID)
movie->moov->mvhd->nextTrackID = trackID;
i=0;
while ((a_trak = (GF_TrackBox*)gf_list_enum(movie->moov->trackList, &i))) {
if (!a_trak->References) continue;
j=0;
while ((ref = (GF_TrackReferenceTypeBox *)gf_list_enum(a_trak->References->other_boxes, &j))) {
for (k=0; k<ref->trackIDCount; k++) {
if (ref->trackIDs[k]==trak->Header->trackID) {
ref->trackIDs[k] = trackID;
break;
}
}
}
}
if (movie->moov->iods && movie->moov->iods->descriptor) {
GF_ES_ID_Inc *inc;
GF_IsomObjectDescriptor *od = (GF_IsomObjectDescriptor *)movie->moov->iods->descriptor;
u32 i = 0;
while ((inc = (GF_ES_ID_Inc*)gf_list_enum(od->ES_ID_IncDescriptors, &i))) {
if (inc->trackID==trak->Header->trackID) inc->trackID = trackID;
}
}
trak->Header->trackID = trackID;
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_rewrite_track_dependencies(GF_ISOFile *movie, u32 trackNumber)
{
GF_TrackReferenceTypeBox *ref;
GF_TrackBox *trak, *a_trak;
u32 i, k;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak)
return GF_BAD_PARAM;
if (!trak->References)
return GF_OK;
i=0;
while ((ref = (GF_TrackReferenceTypeBox *)gf_list_enum(trak->References->other_boxes, &i))) {
for (k=0; k < ref->trackIDCount; k++) {
a_trak = gf_isom_get_track_from_original_id(movie->moov, ref->trackIDs[k], trak->originalFile);
if (a_trak) {
ref->trackIDs[k] = a_trak->Header->trackID;
} else {
a_trak = gf_isom_get_track_from_id(movie->moov, ref->trackIDs[k]);
if (! a_trak || a_trak->originalID) return GF_BAD_PARAM;
}
}
}
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_modify_cts_offset(GF_ISOFile *the_file, u32 trackNumber, u32 sample_number, u32 offset)
{
GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
if (!trak) return GF_BAD_PARAM;
if (!trak->Media->information->sampleTable->CompositionOffset) return GF_BAD_PARAM;
if (!trak->Media->information->sampleTable->CompositionOffset->unpack_mode) return GF_BAD_PARAM;
trak->Media->information->sampleTable->CompositionOffset->entries[sample_number - 1].decodingOffset = offset;
return GF_OK;
}
GF_Err gf_isom_remove_cts_info(GF_ISOFile *the_file, u32 trackNumber)
{
GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
if (!trak) return GF_BAD_PARAM;
if (!trak->Media->information->sampleTable->CompositionOffset) return GF_OK;
gf_isom_box_del((GF_Box *)trak->Media->information->sampleTable->CompositionOffset);
trak->Media->information->sampleTable->CompositionOffset = NULL;
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_set_cts_packing(GF_ISOFile *the_file, u32 trackNumber, Bool unpack)
{
GF_Err e;
GF_Err stbl_repackCTS(GF_CompositionOffsetBox *ctts);
GF_Err stbl_unpackCTS(GF_SampleTableBox *stbl);
GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
if (!trak) return GF_BAD_PARAM;
if (unpack) {
if (!trak->Media->information->sampleTable->CompositionOffset) trak->Media->information->sampleTable->CompositionOffset = (GF_CompositionOffsetBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_CTTS);
e = stbl_unpackCTS(trak->Media->information->sampleTable);
} else {
if (!trak->Media->information->sampleTable->CompositionOffset) return GF_OK;
e = stbl_repackCTS(trak->Media->information->sampleTable->CompositionOffset);
}
if (e) return e;
return SetTrackDuration(trak);
}
GF_EXPORT
GF_Err gf_isom_set_track_matrix(GF_ISOFile *the_file, u32 trackNumber, u32 matrix[9])
{
GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
if (!trak || !trak->Header) return GF_BAD_PARAM;
memcpy(trak->Header->matrix, matrix, sizeof(trak->Header->matrix));
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_set_track_layout_info(GF_ISOFile *the_file, u32 trackNumber, u32 width, u32 height, s32 translation_x, s32 translation_y, s16 layer)
{
GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
if (!trak || !trak->Header) return GF_BAD_PARAM;
trak->Header->width = width;
trak->Header->height = height;
trak->Header->matrix[6] = translation_x;
trak->Header->matrix[7] = translation_y;
trak->Header->layer = layer;
return GF_OK;
}
GF_Err gf_isom_set_track_name(GF_ISOFile *the_file, u32 trackNumber, char *name)
{
GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
if (!trak) return GF_BAD_PARAM;
if (trak->name) gf_free(trak->name);
trak->name = NULL;
if (name) trak->name = gf_strdup(name);
return GF_OK;
}
const char *gf_isom_get_track_name(GF_ISOFile *the_file, u32 trackNumber)
{
GF_TrackBox *trak = gf_isom_get_track_from_file(the_file, trackNumber);
if (!trak) return NULL;
return trak->name;
}
GF_Err gf_isom_store_movie_config(GF_ISOFile *movie, Bool remove_all)
{
u32 i, count, len;
char *data;
GF_BitStream *bs;
bin128 binID;
if (movie == NULL) return GF_BAD_PARAM;
gf_isom_remove_user_data(movie, 0, GF_4CC('G','P','A','C'), binID);
count = gf_isom_get_track_count(movie);
for (i=0; i<count; i++) gf_isom_remove_user_data(movie, i+1, GF_4CC('G','P','A','C'), binID);
if (remove_all) return GF_OK;
bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
gf_bs_write_u8(bs, 0xFE);
gf_bs_write_u8(bs, movie->storageMode);
gf_bs_write_u32(bs, movie->interleavingTime);
gf_bs_get_content(bs, &data, &len);
gf_bs_del(bs);
gf_isom_add_user_data(movie, 0, GF_4CC('G','P','A','C'), binID, data, len);
gf_free(data);
for (i=0; i<count; i++) {
u32 j;
GF_TrackBox *trak = gf_isom_get_track_from_file(movie, i+1);
bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
gf_bs_write_u8(bs, 0xFE);
gf_bs_write_u32(bs, trak->Media->information->sampleTable->groupID);
gf_bs_write_u32(bs, trak->Media->information->sampleTable->trackPriority);
len = trak->name ? (u32) strlen(trak->name) : 0;
gf_bs_write_u32(bs, len);
for (j=0; j<len; j++) gf_bs_write_u8(bs, trak->name[j]);
gf_bs_get_content(bs, &data, &len);
gf_bs_del(bs);
gf_isom_add_user_data(movie, i+1, GF_4CC('G','P','A','C'), binID, data, len);
gf_free(data);
}
return GF_OK;
}
GF_Err gf_isom_load_movie_config(GF_ISOFile *movie)
{
u32 i, count, len;
char *data;
GF_BitStream *bs;
Bool found_cfg;
bin128 binID;
if (movie == NULL) return GF_BAD_PARAM;
found_cfg = GF_FALSE;
count = gf_isom_get_user_data_count(movie, 0, GF_4CC('G','P','A','C'), binID);
for (i=0; i<count; i++) {
data = NULL;
gf_isom_get_user_data(movie, 0, GF_4CC('G','P','A','C'), binID, i+1, &data, &len);
if (!data) continue;
if ((unsigned char) data[0] != 0xFE) {
gf_free(data);
continue;
}
bs = gf_bs_new(data, len, GF_BITSTREAM_READ);
gf_bs_read_u8(bs);
movie->storageMode = gf_bs_read_u8(bs);
movie->interleavingTime = gf_bs_read_u32(bs);
gf_bs_del(bs);
gf_free(data);
found_cfg = GF_TRUE;
break;
}
for (i=0; i<gf_isom_get_track_count(movie); i++) {
u32 j;
GF_TrackBox *trak = gf_isom_get_track_from_file(movie, i+1);
count = gf_isom_get_user_data_count(movie, i+1, GF_4CC('G','P','A','C'), binID);
for (j=0; j<count; j++) {
data = NULL;
gf_isom_get_user_data(movie, i+1, GF_4CC('G','P','A','C'), binID, j+1, &data, &len);
if (!data) continue;
if ((unsigned char) data[0] != 0xFE) {
gf_free(data);
continue;
}
bs = gf_bs_new(data, len, GF_BITSTREAM_READ);
gf_bs_read_u8(bs);
trak->Media->information->sampleTable->groupID = gf_bs_read_u32(bs);
trak->Media->information->sampleTable->trackPriority = gf_bs_read_u32(bs);
len = gf_bs_read_u32(bs);
if (len) {
u32 k;
trak->name = (char*)gf_malloc(sizeof(char)*(len+1));
for (k=0; k<len; k++) trak->name[k] = gf_bs_read_u8(bs);
trak->name[k] = 0;
}
gf_bs_del(bs);
gf_free(data);
found_cfg = GF_TRUE;
break;
}
}
return found_cfg ? GF_OK : GF_NOT_SUPPORTED;
}
GF_EXPORT
GF_Err gf_isom_set_media_timescale(GF_ISOFile *the_file, u32 trackNumber, u32 newTS, Bool force_rescale)
{
Double scale;
GF_TrackBox *trak;
trak = gf_isom_get_track_from_file(the_file, trackNumber);
if (!trak || !trak->Media | !trak->Media->mediaHeader) return GF_BAD_PARAM;
if (trak->Media->mediaHeader->timeScale==newTS) return GF_OK;
scale = newTS;
scale /= trak->Media->mediaHeader->timeScale;
trak->Media->mediaHeader->timeScale = newTS;
if (!force_rescale) {
u32 i, k, idx;
GF_SampleTableBox *stbl = trak->Media->information->sampleTable;
u64 cur_dts;
u64*DTSs = NULL;
s64*CTSs = NULL;
if (trak->editBox) {
GF_EdtsEntry *ent;
u32 i=0;
while ((ent = (GF_EdtsEntry*)gf_list_enum(trak->editBox->editList->entryList, &i))) {
ent->mediaTime = (u32) (scale*ent->mediaTime);
}
}
if (! stbl || !stbl->TimeToSample) {
return SetTrackDuration(trak);
}
idx = 0;
cur_dts = 0;
DTSs = (u64*)gf_malloc(sizeof(u64) * (stbl->SampleSize->sampleCount) );
CTSs = NULL;
if (!DTSs) return GF_OUT_OF_MEM;
if (stbl->CompositionOffset) {
CTSs = (s64*)gf_malloc(sizeof(u64) * (stbl->SampleSize->sampleCount) );
}
for (i=0; i<stbl->TimeToSample->nb_entries; i++) {
for (k=0; k<stbl->TimeToSample->entries[i].sampleCount; k++) {
cur_dts += stbl->TimeToSample->entries[i].sampleDelta;
DTSs[idx] = (u64) (cur_dts * scale);
if (stbl->CompositionOffset) {
s32 cts_o;
stbl_GetSampleCTS(stbl->CompositionOffset, idx+1, &cts_o);
CTSs[idx] = (s64) ( ((s64) cur_dts + cts_o) * scale);
}
idx++;
}
}
if (stbl->SampleSize->sampleCount) {
stbl->TimeToSample->entries = gf_realloc(stbl->TimeToSample->entries, sizeof(GF_SttsEntry)*stbl->SampleSize->sampleCount);
memset(stbl->TimeToSample->entries, 0, sizeof(GF_SttsEntry)*stbl->SampleSize->sampleCount);
stbl->TimeToSample->nb_entries = 1;
stbl->TimeToSample->entries[0].sampleDelta = (u32) DTSs[0];
stbl->TimeToSample->entries[0].sampleCount = 1;
idx=0;
for (i=1; i< stbl->SampleSize->sampleCount - 1; i++) {
if (DTSs[i+1] - DTSs[i] == stbl->TimeToSample->entries[idx].sampleDelta) {
stbl->TimeToSample->entries[idx].sampleCount++;
} else {
idx++;
stbl->TimeToSample->entries[idx].sampleDelta = (u32) ( DTSs[i+1] - DTSs[i] );
stbl->TimeToSample->entries[idx].sampleCount=1;
}
}
stbl->TimeToSample->nb_entries = idx+1;
stbl->TimeToSample->entries = gf_realloc(stbl->TimeToSample->entries, sizeof(GF_SttsEntry)*stbl->TimeToSample->nb_entries);
}
if (CTSs && stbl->SampleSize->sampleCount>0) {
stbl->CompositionOffset->entries = gf_realloc(stbl->CompositionOffset->entries, sizeof(GF_DttsEntry)*stbl->SampleSize->sampleCount);
memset(stbl->CompositionOffset->entries, 0, sizeof(GF_DttsEntry)*stbl->SampleSize->sampleCount);
stbl->CompositionOffset->nb_entries = 1;
stbl->CompositionOffset->entries[0].decodingOffset = (s32) (CTSs[0] - DTSs[0]);
stbl->CompositionOffset->entries[0].sampleCount = 1;
idx=0;
for (i=1; i< stbl->SampleSize->sampleCount; i++) {
s32 cts_o = (s32) (CTSs[i] - DTSs[i]);
if (cts_o == stbl->CompositionOffset->entries[idx].decodingOffset) {
stbl->CompositionOffset->entries[idx].sampleCount++;
} else {
idx++;
stbl->CompositionOffset->entries[idx].decodingOffset = cts_o;
stbl->CompositionOffset->entries[idx].sampleCount=1;
}
}
stbl->CompositionOffset->nb_entries = idx+1;
stbl->CompositionOffset->entries = gf_realloc(stbl->CompositionOffset->entries, sizeof(GF_DttsEntry)*stbl->CompositionOffset->nb_entries);
gf_free(CTSs);
}
gf_free(DTSs);
if (stbl->CompositionToDecode) {
stbl->CompositionToDecode->compositionEndTime = (s32) (stbl->CompositionToDecode->compositionEndTime * scale);
stbl->CompositionToDecode->compositionStartTime = (s32)(stbl->CompositionToDecode->compositionStartTime * scale);
stbl->CompositionToDecode->compositionToDTSShift = (s32)(stbl->CompositionToDecode->compositionToDTSShift * scale);
stbl->CompositionToDecode->greatestDecodeToDisplayDelta = (s32)(stbl->CompositionToDecode->greatestDecodeToDisplayDelta * scale);
stbl->CompositionToDecode->leastDecodeToDisplayDelta = (s32)(stbl->CompositionToDecode->leastDecodeToDisplayDelta * scale);
}
}
return SetTrackDuration(trak);
}
GF_EXPORT
Bool gf_isom_box_equal(GF_Box *a, GF_Box *b)
{
Bool ret;
char *data1, *data2;
u32 data1_size, data2_size;
GF_BitStream *bs;
if (a == b) return GF_TRUE;
if (!a || !b) return GF_FALSE;
data1 = data2 = NULL;
bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
gf_isom_box_size(a);
gf_isom_box_write(a, bs);
gf_bs_get_content(bs, &data1, &data1_size);
gf_bs_del(bs);
bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
gf_isom_box_size(b);
gf_isom_box_write(b, bs);
gf_bs_get_content(bs, &data2, &data2_size);
gf_bs_del(bs);
ret = GF_FALSE;
if (data1_size == data2_size) {
ret = (memcmp(data1, data2, sizeof(char)*data1_size) == 0) ? GF_TRUE : GF_FALSE;
}
gf_free(data1);
gf_free(data2);
return ret;
}
GF_EXPORT
Bool gf_isom_is_same_sample_description(GF_ISOFile *f1, u32 tk1, u32 sdesc_index1, GF_ISOFile *f2, u32 tk2, u32 sdesc_index2)
{
u32 i, count;
GF_TrackBox *trak1, *trak2;
GF_ESD *esd1, *esd2;
Bool need_memcmp;
GF_Box *a, *b;
trak1 = gf_isom_get_track_from_file(f1, tk1);
if (!trak1 || !trak1->Media) return GF_FALSE;
trak2 = gf_isom_get_track_from_file(f2, tk2);
if (!trak2 || !trak2->Media) return GF_FALSE;
if (trak1->Media->handler->handlerType != trak2->Media->handler->handlerType) return GF_FALSE;
count = gf_list_count(trak1->Media->information->sampleTable->SampleDescription->other_boxes);
if (count != gf_list_count(trak2->Media->information->sampleTable->SampleDescription->other_boxes)) {
if (!sdesc_index1 && !sdesc_index2) return GF_FALSE;
}
need_memcmp = GF_TRUE;
for (i=0; i<count; i++) {
GF_Box *ent1 = (GF_Box *)gf_list_get(trak1->Media->information->sampleTable->SampleDescription->other_boxes, i);
GF_Box *ent2 = (GF_Box *)gf_list_get(trak2->Media->information->sampleTable->SampleDescription->other_boxes, i);
if (sdesc_index1) ent1 = (GF_Box *)gf_list_get(trak1->Media->information->sampleTable->SampleDescription->other_boxes, sdesc_index1 - 1);
if (sdesc_index2) ent2 = (GF_Box *)gf_list_get(trak2->Media->information->sampleTable->SampleDescription->other_boxes, sdesc_index2 - 1);
if (!ent1 || !ent2) return GF_FALSE;
if (ent1->type != ent2->type) return GF_FALSE;
switch (ent1->type) {
case GF_ISOM_BOX_TYPE_MP4S:
case GF_ISOM_BOX_TYPE_MP4A:
case GF_ISOM_BOX_TYPE_MP4V:
case GF_ISOM_BOX_TYPE_ENCA:
case GF_ISOM_BOX_TYPE_ENCV:
case GF_ISOM_BOX_TYPE_RESV:
case GF_ISOM_BOX_TYPE_ENCS:
Media_GetESD(trak1->Media, sdesc_index1 ? sdesc_index1 : i+1, &esd1, GF_TRUE);
Media_GetESD(trak2->Media, sdesc_index2 ? sdesc_index2 : i+1, &esd2, GF_TRUE);
if (!esd1 || !esd2) continue;
need_memcmp = GF_FALSE;
if (esd1->decoderConfig->streamType != esd2->decoderConfig->streamType) return GF_FALSE;
if (esd1->decoderConfig->objectTypeIndication != esd2->decoderConfig->objectTypeIndication) return GF_FALSE;
if (!esd1->decoderConfig->decoderSpecificInfo && esd2->decoderConfig->decoderSpecificInfo) return GF_FALSE;
if (esd1->decoderConfig->decoderSpecificInfo && !esd2->decoderConfig->decoderSpecificInfo) return GF_FALSE;
if (!esd1->decoderConfig->decoderSpecificInfo || !esd2->decoderConfig->decoderSpecificInfo) continue;
if (memcmp(esd1->decoderConfig->decoderSpecificInfo->data, esd2->decoderConfig->decoderSpecificInfo->data, sizeof(char)*esd1->decoderConfig->decoderSpecificInfo->dataLength)!=0) return GF_FALSE;
break;
case GF_ISOM_BOX_TYPE_HVT1:
return GF_TRUE;
case GF_ISOM_BOX_TYPE_AVC1:
case GF_ISOM_BOX_TYPE_AVC2:
case GF_ISOM_BOX_TYPE_AVC3:
case GF_ISOM_BOX_TYPE_AVC4:
case GF_ISOM_BOX_TYPE_SVC1:
case GF_ISOM_BOX_TYPE_MVC1:
case GF_ISOM_BOX_TYPE_HVC1:
case GF_ISOM_BOX_TYPE_HEV1:
case GF_ISOM_BOX_TYPE_HVC2:
case GF_ISOM_BOX_TYPE_HEV2:
case GF_ISOM_BOX_TYPE_LHE1:
case GF_ISOM_BOX_TYPE_LHV1:
{
GF_MPEGVisualSampleEntryBox *avc1 = (GF_MPEGVisualSampleEntryBox *)ent1;
GF_MPEGVisualSampleEntryBox *avc2 = (GF_MPEGVisualSampleEntryBox *)ent2;
if (avc1->hevc_config)
a = (GF_Box *) avc1->hevc_config;
else if (avc1->lhvc_config)
a = (GF_Box *) avc1->lhvc_config;
else if (avc1->svc_config)
a = (GF_Box *) avc1->svc_config;
else if (avc1->mvc_config)
a = (GF_Box *) avc1->mvc_config;
else
a = (GF_Box *) avc1->avc_config;
if (avc2->hevc_config)
b = (GF_Box *) avc2->hevc_config;
else if (avc2->lhvc_config)
b = (GF_Box *) avc2->lhvc_config;
else if (avc2->svc_config)
b = (GF_Box *) avc2->svc_config;
else if (avc2->mvc_config)
b = (GF_Box *) avc2->mvc_config;
else
b = (GF_Box *) avc2->avc_config;
return gf_isom_box_equal(a,b);
}
break;
case GF_ISOM_BOX_TYPE_LSR1:
{
GF_LASeRSampleEntryBox *lsr1 = (GF_LASeRSampleEntryBox *)ent1;
GF_LASeRSampleEntryBox *lsr2 = (GF_LASeRSampleEntryBox *)ent2;
if (lsr1->lsr_config && lsr2->lsr_config
&& lsr1->lsr_config->hdr && lsr2->lsr_config->hdr
&& (lsr1->lsr_config->hdr_size==lsr2->lsr_config->hdr_size)
&& !memcmp(lsr1->lsr_config->hdr, lsr2->lsr_config->hdr, lsr2->lsr_config->hdr_size)
) {
return GF_TRUE;
}
return GF_FALSE;
}
break;
#ifndef GPAC_DISABLE_VTT
case GF_ISOM_BOX_TYPE_WVTT:
{
GF_WebVTTSampleEntryBox *wvtt1 = (GF_WebVTTSampleEntryBox *)ent1;
GF_WebVTTSampleEntryBox *wvtt2 = (GF_WebVTTSampleEntryBox *)ent2;
if (wvtt1->config && wvtt2->config &&
(wvtt1->config->string && wvtt1->config->string && !strcmp(wvtt1->config->string, wvtt2->config->string))) {
return GF_TRUE;
}
return GF_FALSE;
}
break;
#endif
case GF_ISOM_BOX_TYPE_STPP:
{
GF_MetaDataSampleEntryBox *stpp1 = (GF_MetaDataSampleEntryBox *)ent1;
GF_MetaDataSampleEntryBox *stpp2 = (GF_MetaDataSampleEntryBox *)ent2;
if (stpp1->xml_namespace && stpp2->xml_namespace && !strcmp(stpp1->xml_namespace, stpp2->xml_namespace)) {
return GF_TRUE;
}
return GF_FALSE;
}
break;
case GF_ISOM_BOX_TYPE_SBTT:
{
return GF_FALSE;
}
break;
case GF_ISOM_BOX_TYPE_STXT:
{
GF_MetaDataSampleEntryBox *stxt1 = (GF_MetaDataSampleEntryBox *)ent1;
GF_MetaDataSampleEntryBox *stxt2 = (GF_MetaDataSampleEntryBox *)ent2;
if (stxt1->mime_type && stxt2->mime_type &&
( (!stxt1->config && !stxt2->config) ||
(stxt1->config && stxt2->config && stxt1->config->config && stxt2->config->config &&
!strcmp(stxt1->config->config, stxt2->config->config)))) {
return GF_TRUE;
}
return GF_FALSE;
}
break;
}
if (sdesc_index1 && sdesc_index2) break;
}
if (!need_memcmp) return GF_TRUE;
a = (GF_Box *)trak1->Media->information->sampleTable->SampleDescription;
b = (GF_Box *)trak2->Media->information->sampleTable->SampleDescription;
return gf_isom_box_equal(a,b);
}
GF_EXPORT
u64 gf_isom_estimate_size(GF_ISOFile *movie)
{
GF_Err e;
GF_Box *a;
u32 i, count;
u64 mdat_size;
if (!movie || !movie->moov) return 0;
mdat_size = 0;
count = gf_list_count(movie->moov->trackList);
for (i=0; i<count; i++) {
mdat_size += gf_isom_get_media_data_size(movie, i+1);
}
if (mdat_size) {
mdat_size += 8;
if (mdat_size > 0xFFFFFFFF) mdat_size += 8;
}
i=0;
while ((a = (GF_Box*)gf_list_enum(movie->TopBoxes, &i))) {
e = gf_isom_box_size(a);
if (e == GF_OK)
mdat_size += a->size;
}
return mdat_size;
}
GF_Err gf_isom_remove_sync_shadows(GF_ISOFile *movie, u32 trackNumber)
{
GF_TrackBox *trak;
GF_SampleTableBox *stbl;
if (movie->openMode == GF_ISOM_OPEN_READ) return GF_ISOM_INVALID_MODE;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
stbl = trak->Media->information->sampleTable;
if (stbl->ShadowSync) {
gf_isom_box_del((GF_Box *) stbl->ShadowSync);
stbl->ShadowSync = NULL;
}
return GF_OK;
}
GF_Err gf_isom_set_sync_shadow(GF_ISOFile *movie, u32 trackNumber, u32 sampleNumber, u32 syncSample)
{
GF_TrackBox *trak;
GF_SampleTableBox *stbl;
SAPType isRAP;
GF_Err e;
if (movie->openMode == GF_ISOM_OPEN_READ) return GF_ISOM_INVALID_MODE;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak || !sampleNumber || !syncSample) return GF_BAD_PARAM;
stbl = trak->Media->information->sampleTable;
if (!stbl->ShadowSync) stbl->ShadowSync = (GF_ShadowSyncBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STSH);
if (!stbl->SyncSample) return GF_OK;
e = stbl_GetSampleRAP(stbl->SyncSample, sampleNumber, &isRAP, NULL, NULL);
if (e) return e;
if (isRAP) return GF_OK;
e = stbl_GetSampleRAP(stbl->SyncSample, syncSample, &isRAP, NULL, NULL);
if (e) return e;
if (!isRAP) return GF_BAD_PARAM;
return stbl_SetSyncShadow(stbl->ShadowSync, sampleNumber, syncSample);
}
GF_Err gf_isom_set_track_interleaving_group(GF_ISOFile *movie, u32 trackNumber, u32 GroupID)
{
GF_TrackBox *trak;
if (movie->openMode != GF_ISOM_OPEN_EDIT) return GF_ISOM_INVALID_MODE;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak || !GroupID) return GF_BAD_PARAM;
trak->Media->information->sampleTable->groupID = GroupID;
return GF_OK;
}
GF_Err gf_isom_set_track_priority_in_group(GF_ISOFile *movie, u32 trackNumber, u32 Priority)
{
GF_TrackBox *trak;
if (movie->openMode != GF_ISOM_OPEN_EDIT) return GF_ISOM_INVALID_MODE;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak || !Priority) return GF_BAD_PARAM;
trak->Media->information->sampleTable->trackPriority = Priority > 255 ? 255 : Priority;
return GF_OK;
}
GF_Err gf_isom_set_max_samples_per_chunk(GF_ISOFile *movie, u32 trackNumber, u32 maxSamplesPerChunk)
{
GF_TrackBox *trak;
if (movie->openMode == GF_ISOM_OPEN_READ) return GF_ISOM_INVALID_MODE;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak || !maxSamplesPerChunk) return GF_BAD_PARAM;
trak->Media->information->sampleTable->MaxSamplePerChunk = maxSamplesPerChunk;
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_set_extraction_slc(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex, GF_SLConfig *slConfig)
{
GF_TrackBox *trak;
GF_SampleEntryBox *entry;
GF_Err e;
GF_SLConfig **slc;
trak = gf_isom_get_track_from_file(the_file, trackNumber);
if (!trak) return GF_BAD_PARAM;
e = Media_GetSampleDesc(trak->Media, StreamDescriptionIndex, &entry, NULL);
if (e) return e;
switch (entry->type) {
case GF_ISOM_BOX_TYPE_MP4S:
if (((GF_MPEGSampleEntryBox *)entry)->esd->desc->slConfig->predefined != SLPredef_MP4) return GF_BAD_PARAM;
slc = & ((GF_MPEGSampleEntryBox *)entry)->slc;
break;
case GF_ISOM_BOX_TYPE_MP4A:
if (((GF_MPEGAudioSampleEntryBox *)entry)->esd->desc->slConfig->predefined != SLPredef_MP4) return GF_BAD_PARAM;
slc = & ((GF_MPEGAudioSampleEntryBox *)entry)->slc;
break;
case GF_ISOM_BOX_TYPE_MP4V:
if (((GF_MPEGVisualSampleEntryBox *)entry)->esd->desc->slConfig->predefined != SLPredef_MP4) return GF_BAD_PARAM;
slc = & ((GF_MPEGVisualSampleEntryBox *)entry)->slc;
break;
default:
return GF_BAD_PARAM;
}
if (*slc) {
gf_odf_desc_del((GF_Descriptor *)*slc);
*slc = NULL;
}
if (!slConfig) return GF_OK;
return gf_odf_desc_copy((GF_Descriptor *) slConfig, (GF_Descriptor **) slc);
}
GF_Err gf_isom_get_extraction_slc(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex, GF_SLConfig **slConfig)
{
GF_TrackBox *trak;
GF_SampleEntryBox *entry;
GF_Err e;
GF_SLConfig *slc;
trak = gf_isom_get_track_from_file(the_file, trackNumber);
if (!trak) return GF_BAD_PARAM;
e = Media_GetSampleDesc(trak->Media, StreamDescriptionIndex, &entry, NULL);
if (e) return e;
slc = NULL;
*slConfig = NULL;
switch (entry->type) {
case GF_ISOM_BOX_TYPE_MP4S:
if (((GF_MPEGSampleEntryBox *)entry)->esd->desc->slConfig->predefined != SLPredef_MP4) return GF_BAD_PARAM;
slc = ((GF_MPEGSampleEntryBox *)entry)->slc;
break;
case GF_ISOM_BOX_TYPE_MP4A:
if (((GF_MPEGAudioSampleEntryBox *)entry)->esd->desc->slConfig->predefined != SLPredef_MP4) return GF_BAD_PARAM;
slc = ((GF_MPEGAudioSampleEntryBox *)entry)->slc;
break;
case GF_ISOM_BOX_TYPE_MP4V:
if (((GF_MPEGVisualSampleEntryBox *)entry)->esd->desc->slConfig->predefined != SLPredef_MP4) return GF_BAD_PARAM;
slc = ((GF_MPEGVisualSampleEntryBox *)entry)->slc;
break;
default:
return GF_BAD_PARAM;
}
if (!slc) return GF_OK;
return gf_odf_desc_copy((GF_Descriptor *) slc, (GF_Descriptor **) slConfig);
}
u32 gf_isom_get_track_group(GF_ISOFile *the_file, u32 trackNumber)
{
GF_TrackBox *trak;
trak = gf_isom_get_track_from_file(the_file, trackNumber);
if (!trak) return 0;
return trak->Media->information->sampleTable->groupID;
}
u32 gf_isom_get_track_priority_in_group(GF_ISOFile *the_file, u32 trackNumber)
{
GF_TrackBox *trak;
trak = gf_isom_get_track_from_file(the_file, trackNumber);
if (!trak) return 0;
return trak->Media->information->sampleTable->trackPriority;
}
GF_EXPORT
GF_Err gf_isom_make_interleave(GF_ISOFile *file, Double TimeInSec)
{
GF_Err e;
if (gf_isom_get_mode(file) < GF_ISOM_OPEN_EDIT) return GF_BAD_PARAM;
e = gf_isom_set_storage_mode(file, GF_ISOM_STORE_DRIFT_INTERLEAVED);
if (e) return e;
return gf_isom_set_interleave_time(file, (u32) (TimeInSec * gf_isom_get_timescale(file)));
}
GF_EXPORT
GF_Err gf_isom_set_handler_name(GF_ISOFile *the_file, u32 trackNumber, const char *nameUTF8)
{
GF_TrackBox *trak;
trak = gf_isom_get_track_from_file(the_file, trackNumber);
if (!trak) return GF_BAD_PARAM;
if (trak->Media->handler->nameUTF8) gf_free(trak->Media->handler->nameUTF8);
trak->Media->handler->nameUTF8 = NULL;
if (!nameUTF8) return GF_OK;
if (!strnicmp(nameUTF8, "file://", 7)) {
u8 BOM[4];
FILE *f = gf_fopen(nameUTF8+7, "rb");
u64 size;
if (!f) return GF_URL_ERROR;
gf_fseek(f, 0, SEEK_END);
size = gf_ftell(f);
gf_fseek(f, 0, SEEK_SET);
if (3!=fread(BOM, sizeof(char), 3, f)) {
gf_fclose(f);
return GF_CORRUPTED_DATA;
}
if ((BOM[0]==0xEF) && (BOM[1]==0xBB) && (BOM[2]==0xBF)) size -= 3;
else if ((BOM[0]==0xEF) || (BOM[0]==0xFF)) {
gf_fclose(f);
return GF_BAD_PARAM;
}
else gf_fseek(f, 0, SEEK_SET);
trak->Media->handler->nameUTF8 = (char*)gf_malloc(sizeof(char)*(size_t)(size+1));
size = fread(trak->Media->handler->nameUTF8, sizeof(char), (size_t)size, f);
trak->Media->handler->nameUTF8[size] = 0;
gf_fclose(f);
} else {
u32 i, j, len;
char szOrig[1024], szLine[1024];
strcpy(szOrig, nameUTF8);
j=0;
len = (u32) strlen(szOrig);
for (i=0; i<len; i++) {
if (szOrig[i] & 0x80) {
if ( (szOrig[i+1] & 0xc0) != 0x80) {
szLine[j] = 0xc0 | ( (szOrig[i] >> 6) & 0x3 );
j++;
szOrig[i] &= 0xbf;
}
else if ( (szOrig[i] & 0xe0) == 0xc0) {
szLine[j] = szOrig[i];
i++;
j++;
}
else if ( (szOrig[i] & 0xf0) == 0xe0) {
szLine[j] = szOrig[i];
i++;
j++;
szLine[j] = szOrig[i];
i++;
j++;
}
else if ( (szOrig[i] & 0xf8) == 0xf0) {
szLine[j] = szOrig[i];
i++;
j++;
szLine[j] = szOrig[i];
i++;
j++;
szLine[j] = szOrig[i];
i++;
j++;
}
}
szLine[j] = szOrig[i];
j++;
}
szLine[j] = 0;
trak->Media->handler->nameUTF8 = gf_strdup(szLine);
}
return GF_OK;
}
GF_Err gf_isom_clone_root_od(GF_ISOFile *input, GF_ISOFile *output)
{
GF_List *esds;
GF_Err e;
u32 i;
GF_Descriptor *desc;
e = gf_isom_remove_root_od(output);
if (e) return e;
if (!input->moov || !input->moov->iods || !input->moov->iods->descriptor) return GF_OK;
gf_isom_insert_moov(output);
e = AddMovieIOD(output->moov, 0);
if (e) return e;
if (output->moov->iods->descriptor) gf_odf_desc_del(output->moov->iods->descriptor);
output->moov->iods->descriptor = NULL;
gf_odf_desc_copy(input->moov->iods->descriptor, &output->moov->iods->descriptor);
switch (output->moov->iods->descriptor->tag) {
case GF_ODF_ISOM_IOD_TAG:
esds = ((GF_IsomInitialObjectDescriptor *)output->moov->iods->descriptor)->ES_ID_IncDescriptors;
break;
case GF_ODF_ISOM_OD_TAG:
esds = ((GF_IsomObjectDescriptor *)output->moov->iods->descriptor)->ES_ID_IncDescriptors;
break;
default:
return GF_ISOM_INVALID_FILE;
}
i=0;
while ((desc = (GF_Descriptor*)gf_list_enum(esds, &i))) {
gf_odf_desc_del(desc);
gf_list_rem(esds, i-1);
}
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_set_media_type(GF_ISOFile *movie, u32 trackNumber, u32 new_type)
{
GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak || !new_type) return GF_BAD_PARAM;
trak->Media->handler->handlerType = new_type;
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_set_media_subtype(GF_ISOFile *movie, u32 trackNumber, u32 sampleDescriptionIndex, u32 new_type)
{
GF_SampleEntryBox*entry;
GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak || !sampleDescriptionIndex || !new_type) return GF_BAD_PARAM;
entry = (GF_SampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, sampleDescriptionIndex - 1);
if (!entry) return GF_BAD_PARAM;
entry->type = new_type;
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_set_JPEG2000(GF_ISOFile *mov, Bool set_on)
{
if (!mov) return GF_BAD_PARAM;
mov->is_jp2 = set_on;
return GF_OK;
}
GF_Err gf_isom_remove_uuid(GF_ISOFile *movie, u32 trackNumber, bin128 UUID)
{
u32 i, count;
GF_List *list;
if (trackNumber==(u32) -1) {
if (!movie) return GF_BAD_PARAM;
list = movie->TopBoxes;
} else if (trackNumber) {
GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
list = trak->other_boxes;
} else {
if (!movie) return GF_BAD_PARAM;
list = movie->moov->other_boxes;
}
count = list ? gf_list_count(list) : 0;
for (i=0; i<count; i++) {
GF_UnknownUUIDBox *uuid = (GF_UnknownUUIDBox *)gf_list_get(list, i);
if (uuid->type != GF_ISOM_BOX_TYPE_UUID) continue;
if (memcmp(UUID, uuid->uuid, sizeof(bin128))) continue;
gf_list_rem(list, i);
i--;
count--;
gf_isom_box_del((GF_Box*)uuid);
}
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_add_uuid(GF_ISOFile *movie, u32 trackNumber, bin128 UUID, const char *data, u32 data_size)
{
GF_List *list;
GF_Box *box;
GF_UnknownUUIDBox *uuid;
if (!data_size || !data) return GF_OK;
if (trackNumber==(u32) -1) {
if (!movie) return GF_BAD_PARAM;
list = movie->TopBoxes;
} else if (trackNumber) {
GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
if (!trak->other_boxes) trak->other_boxes = gf_list_new();
list = trak->other_boxes;
} else {
if (!movie) return GF_BAD_PARAM;
if (!movie->moov->other_boxes) movie->moov->other_boxes = gf_list_new();
list = movie->moov->other_boxes;
}
box = gf_isom_box_new(gf_isom_solve_uuid_box((char *) UUID));
uuid = (GF_UnknownUUIDBox*)box;
uuid->internal_4cc = gf_isom_solve_uuid_box((char *) UUID);
memcpy(uuid->uuid, UUID, sizeof(bin128));
uuid->dataSize = data_size;
uuid->data = (char*)gf_malloc(sizeof(char)*data_size);
memcpy(uuid->data, data, sizeof(char)*data_size);
gf_list_add(list, uuid);
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_apple_set_tag(GF_ISOFile *mov, u32 tag, const char *data, u32 data_len)
{
GF_BitStream *bs;
GF_Err e;
GF_ItemListBox *ilst;
GF_MetaBox *meta;
GF_ListItemBox *info;
u32 btype, i;
e = CanAccessMovie(mov, GF_ISOM_OPEN_WRITE);
if (e) return e;
meta = gf_isom_apple_create_meta_extensions(mov);
if (!meta) return GF_BAD_PARAM;
ilst = gf_ismo_locate_box(meta->other_boxes, GF_ISOM_BOX_TYPE_ILST, NULL);
if (!ilst) {
ilst = (GF_ItemListBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_ILST);
if (!meta->other_boxes) meta->other_boxes = gf_list_new();
gf_list_add(meta->other_boxes, ilst);
}
if (tag==GF_ISOM_ITUNE_GENRE) {
btype = data ? GF_ISOM_BOX_TYPE_0xA9GEN : GF_ISOM_BOX_TYPE_GNRE;
} else {
btype = tag;
}
i = 0;
while ((info = (GF_ListItemBox*)gf_list_enum(ilst->other_boxes, &i))) {
if (info->type==btype) {
gf_list_rem(ilst->other_boxes, i-1);
gf_isom_box_del((GF_Box *) info);
info = NULL;
break;
}
}
if (data != NULL) {
info = (GF_ListItemBox *)gf_isom_box_new(btype);
if (info == NULL) return GF_OUT_OF_MEM;
switch (btype) {
case GF_ISOM_BOX_TYPE_TRKN:
case GF_ISOM_BOX_TYPE_DISK:
case GF_ISOM_BOX_TYPE_GNRE:
info->data->flags = 0x0;
break;
case GF_ISOM_BOX_TYPE_PGAP:
case GF_ISOM_BOX_TYPE_CPIL:
info->data->flags = 0x15;
break;
default:
info->data->flags = 0x1;
break;
}
if (tag==GF_ISOM_ITUNE_COVER_ART) {
if (data_len & 0x80000000) {
data_len = (data_len & 0x7FFFFFFF);
info->data->flags = 14;
} else {
info->data->flags = 13;
}
}
info->data->dataSize = data_len;
info->data->data = (char*)gf_malloc(sizeof(char)*data_len);
memcpy(info->data->data , data, sizeof(char)*data_len);
}
else if (data_len && (tag==GF_ISOM_ITUNE_GENRE)) {
info = (GF_ListItemBox *)gf_isom_box_new(btype);
if (info == NULL) return GF_OUT_OF_MEM;
bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
gf_bs_write_u16(bs, data_len);
gf_bs_get_content(bs, & info->data->data, &info->data->dataSize);
info->data->flags = 0x0;
gf_bs_del(bs);
} else if (data_len && (tag==GF_ISOM_ITUNE_COMPILATION)) {
info = (GF_ListItemBox *)gf_isom_box_new(btype);
if (info == NULL) return GF_OUT_OF_MEM;
info->data->data = (char*)gf_malloc(sizeof(char));
info->data->data[0] = 1;
info->data->dataSize = 1;
info->data->flags = 21;
} else if (data_len && (tag==GF_ISOM_ITUNE_TEMPO)) {
info = (GF_ListItemBox *)gf_isom_box_new(btype);
if (info == NULL) return GF_OUT_OF_MEM;
bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
gf_bs_write_u16(bs, data_len);
gf_bs_get_content(bs, &info->data->data, &info->data->dataSize);
info->data->flags = 0x15;
gf_bs_del(bs);
}
if (!info || (tag==GF_ISOM_ITUNE_ALL) ) {
if (!gf_list_count(ilst->other_boxes) || (tag==GF_ISOM_ITUNE_ALL) ) {
gf_list_del_item(meta->other_boxes, ilst);
gf_isom_box_del((GF_Box *) ilst);
}
return GF_OK;
}
return gf_list_add(ilst->other_boxes, info);
}
GF_EXPORT
GF_Err gf_isom_set_alternate_group_id(GF_ISOFile *movie, u32 trackNumber, u32 groupId)
{
GF_TrackBox *trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
trak->Header->alternate_group = groupId;
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_set_track_switch_parameter(GF_ISOFile *movie, u32 trackNumber, u32 trackRefGroup, Bool is_switch_group, u32 *switchGroupID, u32 *criteriaList, u32 criteriaListCount)
{
GF_TrackSelectionBox *tsel;
GF_TrackBox *trak;
GF_UserDataMap *map;
GF_Err e;
u32 alternateGroupID = 0;
u32 next_switch_group_id = 0;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak || !switchGroupID) return GF_BAD_PARAM;
if (trackRefGroup) {
GF_TrackBox *trak_ref = gf_isom_get_track_from_file(movie, trackRefGroup);
if (trak_ref != trak) {
if (!trak_ref || !trak_ref->Header->alternate_group) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("Track %d has not an alternate group - skipping\n", trak_ref->Header->trackID));
return GF_BAD_PARAM;
}
alternateGroupID = trak_ref->Header->alternate_group;
} else {
alternateGroupID = trak->Header->alternate_group;
}
}
if (!alternateGroupID) {
if (trak->Header->alternate_group) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("Track %d has already an alternate group - skipping\n", trak->Header->trackID));
return GF_BAD_PARAM;
}
alternateGroupID = gf_isom_get_next_alternate_group_id(movie);
}
if (is_switch_group) {
u32 i=0;
while (i< gf_isom_get_track_count(movie) ) {
GF_TrackBox *a_trak = gf_isom_get_track_from_file(movie, i+1);
if (a_trak->udta) {
u32 j, count;
map = udta_getEntry(a_trak->udta, GF_ISOM_BOX_TYPE_TSEL, NULL);
if (map) {
count = gf_list_count(map->other_boxes);
for (j=0; j<count; j++) {
tsel = (GF_TrackSelectionBox*)gf_list_get(map->other_boxes, j);
if (*switchGroupID) {
if (tsel->switchGroup==next_switch_group_id) {
if (a_trak->Header->alternate_group != alternateGroupID) return GF_BAD_PARAM;
}
} else {
if (tsel->switchGroup && (tsel->switchGroup>=next_switch_group_id) )
next_switch_group_id = tsel->switchGroup;
}
}
}
}
i++;
}
if (! *switchGroupID) *switchGroupID = next_switch_group_id+1;
}
trak->Header->alternate_group = alternateGroupID;
tsel = NULL;
if (*switchGroupID) {
if (!trak->udta) {
e = trak_AddBox((GF_Box*)trak, gf_isom_box_new(GF_ISOM_BOX_TYPE_UDTA));
if (e) return e;
}
map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_TSEL, NULL);
if (map) {
u32 j, count = gf_list_count(map->other_boxes);
for (j=0; j<count; j++) {
tsel = (GF_TrackSelectionBox*)gf_list_get(map->other_boxes, j);
if (tsel->switchGroup == *switchGroupID) break;
tsel = NULL;
}
}
if (!tsel) {
tsel = (GF_TrackSelectionBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_TSEL);
e = udta_AddBox((GF_Box *)trak->udta, (GF_Box *) tsel);
if (e) return e;
}
tsel->switchGroup = *switchGroupID;
tsel->attributeListCount = criteriaListCount;
if (tsel->attributeList) gf_free(tsel->attributeList);
tsel->attributeList = (u32*)gf_malloc(sizeof(u32)*criteriaListCount);
memcpy(tsel->attributeList, criteriaList, sizeof(u32)*criteriaListCount);
}
return GF_OK;
}
void reset_tsel_box(GF_TrackBox *trak)
{
GF_UserDataMap *map;
trak->Header->alternate_group = 0;
map = udta_getEntry(trak->udta, GF_ISOM_BOX_TYPE_TSEL, NULL);
if (map) {
gf_list_del_item(trak->udta->recordList, map);
gf_isom_box_array_del(map->other_boxes);
gf_free(map);
}
}
GF_EXPORT
GF_Err gf_isom_reset_track_switch_parameter(GF_ISOFile *movie, u32 trackNumber, Bool reset_all_group)
{
GF_TrackBox *trak;
u32 alternateGroupID = 0;
trak = gf_isom_get_track_from_file(movie, trackNumber);
if (!trak) return GF_BAD_PARAM;
if (!trak->Header->alternate_group) return GF_OK;
alternateGroupID = trak->Header->alternate_group;
if (reset_all_group) {
u32 i=0;
while (i< gf_isom_get_track_count(movie) ) {
GF_TrackBox *a_trak = gf_isom_get_track_from_file(movie, i+1);
if (a_trak->Header->alternate_group == alternateGroupID) reset_tsel_box(a_trak);
i++;
}
} else {
reset_tsel_box(trak);
}
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_reset_switch_parameters(GF_ISOFile *movie)
{
u32 i=0;
while (i< gf_isom_get_track_count(movie) ) {
GF_TrackBox *a_trak = gf_isom_get_track_from_file(movie, i+1);
reset_tsel_box(a_trak);
i++;
}
return GF_OK;
}
GF_Err gf_isom_add_subsample(GF_ISOFile *movie, u32 track, u32 sampleNumber, u32 flags, u32 subSampleSize, u8 priority, u32 reserved, Bool discardable)
{
u32 i, count;
GF_SubSampleInformationBox *sub_samples;
GF_TrackBox *trak;
GF_Err e;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, track);
if (!trak || !trak->Media || !trak->Media->information->sampleTable)
return GF_BAD_PARAM;
if (!trak->Media->information->sampleTable->sub_samples) {
trak->Media->information->sampleTable->sub_samples=gf_list_new();
}
sub_samples = NULL;
count = gf_list_count(trak->Media->information->sampleTable->sub_samples);
for (i=0; i<count; i++) {
sub_samples = gf_list_get(trak->Media->information->sampleTable->sub_samples, i);
if (sub_samples->flags==flags) break;
sub_samples = NULL;
}
if (!sub_samples) {
sub_samples = (GF_SubSampleInformationBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_SUBS);
gf_list_add(trak->Media->information->sampleTable->sub_samples, sub_samples);
sub_samples->version = (subSampleSize>0xFFFF) ? 1 : 0;
sub_samples->flags = flags;
}
return gf_isom_add_subsample_info(sub_samples, sampleNumber, subSampleSize, priority, reserved, discardable);
}
GF_EXPORT
GF_Err gf_isom_set_rvc_config(GF_ISOFile *movie, u32 track, u32 sampleDescriptionIndex, u16 rvc_predefined, char *mime, char *data, u32 size)
{
GF_MPEGVisualSampleEntryBox *entry;
GF_Err e;
GF_TrackBox *trak;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, track);
if (!trak) return GF_BAD_PARAM;
entry = (GF_MPEGVisualSampleEntryBox *) gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, sampleDescriptionIndex-1);
if (!entry ) return GF_BAD_PARAM;
if (entry->internal_type != GF_ISOM_SAMPLE_ENTRY_VIDEO) return GF_BAD_PARAM;
if (entry->rvcc && entry->rvcc->rvc_meta_idx) {
gf_isom_remove_meta_item(movie, GF_FALSE, track, entry->rvcc->rvc_meta_idx);
entry->rvcc->rvc_meta_idx = 0;
}
if (!entry->rvcc) {
entry->rvcc = (GF_RVCConfigurationBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_RVCC);
}
entry->rvcc->predefined_rvc_config = rvc_predefined;
if (!rvc_predefined) {
e = gf_isom_set_meta_type(movie, GF_FALSE, track, GF_4CC('r','v','c','i'));
if (e) return e;
gf_isom_modify_alternate_brand(movie, GF_ISOM_BRAND_ISO2, 1);
e = gf_isom_add_meta_item_memory(movie, GF_FALSE, track, "rvcconfig.xml", 0, GF_4CC('m', 'i', 'm', 'e'), mime, NULL, NULL, data, size, NULL);
if (e) return e;
entry->rvcc->rvc_meta_idx = gf_isom_get_meta_item_count(movie, GF_FALSE, track);
}
return GF_OK;
}
static GF_Err gf_isom_add_sample_group_entry(GF_List *sampleGroups, u32 sample_number, u32 grouping_type, u32 grouping_type_parameter, u32 sampleGroupDescriptionIndex)
{
GF_SampleGroupBox *sgroup = NULL;
u32 i, count, last_sample_in_entry;
count = gf_list_count(sampleGroups);
for (i=0; i<count; i++) {
sgroup = (GF_SampleGroupBox*)gf_list_get(sampleGroups, i);
if (sgroup->grouping_type==grouping_type) break;
sgroup = NULL;
}
if (!sgroup) {
sgroup = (GF_SampleGroupBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_SBGP);
sgroup->grouping_type = grouping_type;
sgroup->grouping_type_parameter = grouping_type_parameter;
gf_list_add(sampleGroups, sgroup);
}
if (!sample_number) {
sample_number = 1;
if (sgroup->entry_count) {
for (i=0; i<sgroup->entry_count; i++) {
sample_number += sgroup->sample_entries[i].sample_count;
}
}
}
if (!sgroup->entry_count) {
u32 idx = 0;
sgroup->entry_count = (sample_number>1) ? 2 : 1;
sgroup->sample_entries = (GF_SampleGroupEntry*)gf_malloc(sizeof(GF_SampleGroupEntry) * sgroup->entry_count );
if (sample_number>1) {
sgroup->sample_entries[0].sample_count = sample_number-1;
sgroup->sample_entries[0].group_description_index = 0;
idx = 1;
}
sgroup->sample_entries[idx].sample_count = 1;
sgroup->sample_entries[idx].group_description_index = sampleGroupDescriptionIndex;
return GF_OK;
}
last_sample_in_entry = 0;
for (i=0; i<sgroup->entry_count; i++) {
if (last_sample_in_entry + sgroup->sample_entries[i].sample_count > sample_number) return GF_NOT_SUPPORTED;
last_sample_in_entry += sgroup->sample_entries[i].sample_count;
}
if (last_sample_in_entry == sample_number) {
if (sgroup->sample_entries[sgroup->entry_count-1].group_description_index==sampleGroupDescriptionIndex)
return GF_OK;
else
return GF_NOT_SUPPORTED;
}
if ((sgroup->sample_entries[sgroup->entry_count-1].group_description_index==sampleGroupDescriptionIndex) && (last_sample_in_entry+1==sample_number)) {
sgroup->sample_entries[sgroup->entry_count-1].sample_count++;
return GF_OK;
}
if (! sgroup->sample_entries[sgroup->entry_count-1].group_description_index) {
sgroup->sample_entries[sgroup->entry_count-1].sample_count += sample_number - 1 - last_sample_in_entry;
sgroup->sample_entries = (GF_SampleGroupEntry*)gf_realloc(sgroup->sample_entries, sizeof(GF_SampleGroupEntry) * (sgroup->entry_count + 1) );
sgroup->sample_entries[sgroup->entry_count].sample_count = 1;
sgroup->sample_entries[sgroup->entry_count].group_description_index = sampleGroupDescriptionIndex;
sgroup->entry_count++;
return GF_OK;
}
if (!sampleGroupDescriptionIndex || (sample_number - 1 - last_sample_in_entry==0) ) {
sgroup->sample_entries = (GF_SampleGroupEntry*)gf_realloc(sgroup->sample_entries, sizeof(GF_SampleGroupEntry) * (sgroup->entry_count + 1) );
sgroup->sample_entries[sgroup->entry_count].sample_count = 1;
sgroup->sample_entries[sgroup->entry_count].group_description_index = sampleGroupDescriptionIndex;
sgroup->entry_count++;
return GF_OK;
}
sgroup->sample_entries = (GF_SampleGroupEntry*)gf_realloc(sgroup->sample_entries, sizeof(GF_SampleGroupEntry) * (sgroup->entry_count + 2) );
sgroup->sample_entries[sgroup->entry_count].sample_count = sample_number - 1 - last_sample_in_entry;
sgroup->sample_entries[sgroup->entry_count].group_description_index = 0;
sgroup->sample_entries[sgroup->entry_count+1].sample_count = 1;
sgroup->sample_entries[sgroup->entry_count+1].group_description_index = sampleGroupDescriptionIndex;
sgroup->entry_count+=2;
return GF_OK;
}
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
static GF_SampleGroupDescriptionBox *get_sgdp(GF_SampleTableBox *stbl, GF_TrackFragmentBox *traf, u32 grouping_type)
#else
static GF_SampleGroupDescriptionBox *get_sgdp(GF_SampleTableBox *stbl, void *traf, u32 grouping_type)
#endif
{
GF_List *groupList;
GF_SampleGroupDescriptionBox *sgdesc=NULL;
u32 count, i;
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
if (traf) {
if (!traf->sampleGroupsDescription)
traf->sampleGroupsDescription = gf_list_new();
groupList = traf->sampleGroupsDescription;
} else
#endif
{
if (!stbl->sampleGroupsDescription)
stbl->sampleGroupsDescription = gf_list_new();
groupList = stbl->sampleGroupsDescription;
}
count = gf_list_count(groupList);
for (i=0; i<count; i++) {
sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(groupList, i);
if (sgdesc->grouping_type==grouping_type) break;
sgdesc = NULL;
}
if (!sgdesc) {
sgdesc = (GF_SampleGroupDescriptionBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_SGPD);
sgdesc->grouping_type = grouping_type;
gf_list_add(groupList, sgdesc);
}
return sgdesc;
}
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
static GF_Err gf_isom_set_sample_group_info_ex(GF_SampleTableBox *stbl, GF_TrackFragmentBox *traf, u32 sample_number, u32 grouping_type, u32 grouping_type_parameter, void *udta, void *(*sg_create_entry)(void *udta), Bool (*sg_compare_entry)(void *udta, void *entry))
#else
static GF_Err gf_isom_set_sample_group_info_ex(GF_SampleTableBox *stbl, void *traf, u32 sample_number, u32 grouping_type, u32 grouping_type_parameter, void *udta, void *(*sg_create_entry)(void *udta), Bool (*sg_compare_entry)(void *udta, void *entry))
#endif
{
GF_List *groupList;
void *entry;
GF_SampleGroupDescriptionBox *sgdesc = NULL;
u32 i, entry_idx;
if (!stbl && !traf) return GF_BAD_PARAM;
sgdesc = get_sgdp(stbl, traf, grouping_type);
if (!sgdesc) return GF_OUT_OF_MEM;
entry = NULL;
for (i=0; i<gf_list_count(sgdesc->group_descriptions); i++) {
entry = gf_list_get(sgdesc->group_descriptions, i);
if (sg_compare_entry(udta, entry)) break;
entry = NULL;
}
if (!entry) {
entry = sg_create_entry(udta);
if (!entry) return GF_IO_ERR;
gf_list_add(sgdesc->group_descriptions, entry);
}
entry_idx = 1 + gf_list_find(sgdesc->group_descriptions, entry);
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
if (traf) {
if (!traf->sampleGroups)
traf->sampleGroups = gf_list_new();
groupList = traf->sampleGroups;
entry_idx |= 0x10000;
} else
#endif
{
if (!stbl->sampleGroups)
stbl->sampleGroups = gf_list_new();
groupList = stbl->sampleGroups;
}
return gf_isom_add_sample_group_entry(groupList, sample_number, grouping_type, grouping_type_parameter, entry_idx);
}
static GF_Err gf_isom_set_sample_group_info(GF_ISOFile *movie, u32 track, u32 sample_number, u32 grouping_type, u32 grouping_type_parameter, void *udta, void *(*sg_create_entry)(void *udta), Bool (*sg_compare_entry)(void *udta, void *entry))
{
GF_Err e;
GF_TrackBox *trak;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, track);
if (!trak) return GF_BAD_PARAM;
return gf_isom_set_sample_group_info_ex(trak->Media->information->sampleTable, NULL, sample_number, grouping_type, grouping_type_parameter, udta, sg_create_entry, sg_compare_entry);
}
GF_EXPORT
GF_Err gf_isom_add_sample_group_info(GF_ISOFile *movie, u32 track, u32 grouping_type, void *data, u32 data_size, Bool is_default, u32 *sampleGroupDescriptionIndex)
{
GF_Err e;
GF_TrackBox *trak;
GF_DefaultSampleGroupDescriptionEntry *entry=NULL;
GF_SampleGroupDescriptionBox *sgdesc = NULL;
if (sampleGroupDescriptionIndex) *sampleGroupDescriptionIndex = 0;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, track);
if (!trak) return GF_BAD_PARAM;
sgdesc = get_sgdp(trak->Media->information->sampleTable, NULL, grouping_type);
if (!sgdesc) return GF_OUT_OF_MEM;
if (grouping_type==GF_4CC('o','i','n','f')) {
GF_OperatingPointsInformation *ptr = gf_isom_oinf_new_entry();
GF_BitStream *bs=gf_bs_new(data, data_size, GF_BITSTREAM_READ);
e = gf_isom_oinf_read_entry(ptr, bs);
gf_bs_del(bs);
if (e) {
gf_isom_oinf_del_entry(ptr);
return e;
}
e = gf_list_add(sgdesc->group_descriptions, ptr);
if (e) return e;
entry = (GF_DefaultSampleGroupDescriptionEntry *) ptr;
} else if (grouping_type==GF_4CC('l','i','n','f')) {
GF_LHVCLayerInformation *ptr = gf_isom_linf_new_entry();
GF_BitStream *bs=gf_bs_new(data, data_size, GF_BITSTREAM_READ);
e = gf_isom_linf_read_entry(ptr, bs);
gf_bs_del(bs);
if (e) {
gf_isom_linf_del_entry(ptr);
return e;
}
e = gf_list_add(sgdesc->group_descriptions, ptr);
if (e) return e;
entry = (GF_DefaultSampleGroupDescriptionEntry *) ptr;
} else {
u32 i, count=gf_list_count(sgdesc->group_descriptions);
for (i=0; i<count; i++) {
GF_DefaultSampleGroupDescriptionEntry *ent = gf_list_get(sgdesc->group_descriptions, i);
if ((ent->length == data_size) && !memcmp(ent->data, data, data_size)) {
entry = ent;
break;
}
entry=NULL;
}
if (!entry) {
GF_SAFEALLOC(entry, GF_DefaultSampleGroupDescriptionEntry);
if (!entry) return GF_OUT_OF_MEM;
entry->data = (u8*)gf_malloc(sizeof(char) * data_size);
if (!entry->data) {
gf_free(entry);
return GF_OUT_OF_MEM;
}
entry->length = data_size;
memcpy(entry->data, data, sizeof(char) * data_size);
e = gf_list_add(sgdesc->group_descriptions, entry);
if (e) {
gf_free(entry->data);
gf_free(entry);
return e;
}
}
}
if (is_default) {
sgdesc->default_description_index = 1 + gf_list_find(sgdesc->group_descriptions, entry);
sgdesc->version = 2;
}
if (sampleGroupDescriptionIndex) *sampleGroupDescriptionIndex = 1 + gf_list_find(sgdesc->group_descriptions, entry);
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_remove_sample_group(GF_ISOFile *movie, u32 track, u32 grouping_type)
{
GF_Err e;
GF_TrackBox *trak;
GF_SampleGroupDescriptionBox *sgdesc = NULL;
u32 count, i;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, track);
if (!trak) return GF_BAD_PARAM;
if (!trak->Media->information->sampleTable->sampleGroupsDescription)
return GF_OK;
count = gf_list_count(trak->Media->information->sampleTable->sampleGroupsDescription);
for (i=0; i<count; i++) {
sgdesc = (GF_SampleGroupDescriptionBox*)gf_list_get(trak->Media->information->sampleTable->sampleGroupsDescription, i);
if (sgdesc->grouping_type==grouping_type) {
gf_isom_box_del((GF_Box*)sgdesc);
gf_list_rem(trak->Media->information->sampleTable->sampleGroupsDescription, i);
i--;
count--;
}
sgdesc = NULL;
}
return GF_OK;
}
GF_Err gf_isom_add_sample_info(GF_ISOFile *movie, u32 track, u32 sample_number, u32 grouping_type, u32 sampleGroupDescriptionIndex, u32 grouping_type_parameter)
{
GF_Err e;
GF_TrackBox *trak;
GF_List *groupList;
e = CanAccessMovie(movie, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(movie, track);
if (!trak) return GF_BAD_PARAM;
if (!trak->Media->information->sampleTable->sampleGroups)
trak->Media->information->sampleTable->sampleGroups = gf_list_new();
groupList = trak->Media->information->sampleTable->sampleGroups;
return gf_isom_add_sample_group_entry(groupList, sample_number, grouping_type, grouping_type_parameter, sampleGroupDescriptionIndex);
}
void *sg_rap_create_entry(void *udta)
{
GF_VisualRandomAccessEntry *entry;
u32 *num_leading_samples = (u32 *) udta;
assert(udta);
GF_SAFEALLOC(entry, GF_VisualRandomAccessEntry);
if (!entry) return NULL;
entry->num_leading_samples = *num_leading_samples;
entry->num_leading_samples_known = entry->num_leading_samples ? 1 : 0;
return entry;
}
Bool sg_rap_compare_entry(void *udta, void *entry)
{
u32 *num_leading_samples = (u32 *) udta;
if (*num_leading_samples == ((GF_VisualRandomAccessEntry *)entry)->num_leading_samples) return GF_TRUE;
return GF_FALSE;
}
GF_Err gf_isom_set_sample_rap_group(GF_ISOFile *movie, u32 track, u32 sample_number, u32 num_leading_samples)
{
return gf_isom_set_sample_group_info(movie, track, sample_number, GF_4CC( 'r', 'a', 'p', ' ' ), 0, &num_leading_samples, sg_rap_create_entry, sg_rap_compare_entry);
}
void *sg_roll_create_entry(void *udta)
{
GF_RollRecoveryEntry *entry;
s16 *roll_distance = (s16 *) udta;
GF_SAFEALLOC(entry, GF_RollRecoveryEntry);
if (!entry) return NULL;
entry->roll_distance = *roll_distance;
return entry;
}
Bool sg_roll_compare_entry(void *udta, void *entry)
{
s16 *roll_distance = (s16 *) udta;
if (*roll_distance == ((GF_RollRecoveryEntry *)entry)->roll_distance) return GF_TRUE;
return GF_FALSE;
}
GF_Err gf_isom_set_sample_roll_group(GF_ISOFile *movie, u32 track, u32 sample_number, s16 roll_distance)
{
return gf_isom_set_sample_group_info(movie, track, sample_number, GF_4CC( 'r', 'o', 'l', 'l' ), 0, &roll_distance, sg_roll_create_entry, sg_roll_compare_entry);
}
void *sg_encryption_create_entry(void *udta)
{
GF_CENCSampleEncryptionGroupEntry *entry;
GF_BitStream *bs;
GF_SAFEALLOC(entry, GF_CENCSampleEncryptionGroupEntry);
if (!entry) return NULL;
bs = gf_bs_new((char *) udta, sizeof(GF_CENCSampleEncryptionGroupEntry), GF_BITSTREAM_READ);
gf_bs_read_u8(bs);
entry->crypt_byte_block = gf_bs_read_int(bs, 4);
entry->skip_byte_block = gf_bs_read_int(bs, 4);
entry->IsProtected = gf_bs_read_u8(bs);
entry->Per_Sample_IV_size = gf_bs_read_u8(bs);
gf_bs_read_data(bs, (char *)entry->KID, 16);
if ((entry->IsProtected == 1) && !entry->Per_Sample_IV_size) {
entry->constant_IV_size = gf_bs_read_u8(bs);
assert((entry->constant_IV_size == 8) || (entry->constant_IV_size == 16));
gf_bs_read_data(bs, (char *)entry->constant_IV, entry->constant_IV_size);
}
gf_bs_del(bs);
return entry;
}
Bool sg_encryption_compare_entry(void *udta, void *entry)
{
u8 isEncrypted;
u8 IV_size;
bin128 KID;
u8 constant_IV_size=0;
bin128 constant_IV;
u8 crypt_byte_block, skip_byte_block;
GF_BitStream *bs;
GF_CENCSampleEncryptionGroupEntry *seig = (GF_CENCSampleEncryptionGroupEntry *)entry;
Bool is_identical;
bs = gf_bs_new((char *) udta, sizeof(GF_CENCSampleEncryptionGroupEntry), GF_BITSTREAM_READ);
gf_bs_read_u8(bs);
crypt_byte_block = gf_bs_read_int(bs, 4);
skip_byte_block = gf_bs_read_int(bs, 4);
isEncrypted = gf_bs_read_u8(bs);
IV_size = gf_bs_read_u8(bs);
gf_bs_read_data(bs, (char *)KID, 16);
if (isEncrypted && !IV_size) {
constant_IV_size = gf_bs_read_u8(bs);
gf_bs_read_data(bs, (char *)constant_IV, 16);
}
gf_bs_del(bs);
is_identical = GF_TRUE;
if ((isEncrypted != seig->IsProtected) || (IV_size != seig->Per_Sample_IV_size) || (strncmp((const char *)KID, (const char *)seig->KID, 16)))
is_identical = GF_FALSE;
if ((crypt_byte_block != seig->crypt_byte_block) || (skip_byte_block != seig->skip_byte_block))
is_identical = GF_FALSE;
if ((isEncrypted == 1) && !IV_size) {
if ((constant_IV_size != seig->constant_IV_size) || (strncmp((const char *)constant_IV, (const char *)seig->constant_IV, constant_IV_size)))
is_identical = GF_FALSE;
}
return is_identical;
}
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
GF_Err gf_isom_copy_sample_group_entry_to_traf(GF_TrackFragmentBox *traf, GF_SampleTableBox *stbl, u32 grouping_type, u32 grouping_type_parameter, u32 sampleGroupDescriptionIndex, Bool sgpd_in_traf)
{
if (sgpd_in_traf) {
void *entry = NULL;
u32 i, count;
GF_SampleGroupDescriptionBox *sgdesc = NULL;
GF_BitStream *bs;
count = gf_list_count(stbl->sampleGroupsDescription);
for (i = 0; i < count; i++) {
sgdesc = (GF_SampleGroupDescriptionBox *)gf_list_get(stbl->sampleGroupsDescription, i);
if (sgdesc->grouping_type == grouping_type)
break;
sgdesc = NULL;
}
if (!sgdesc)
return GF_BAD_PARAM;
entry = gf_list_get(sgdesc->group_descriptions, sampleGroupDescriptionIndex-1);
if (!entry)
return GF_BAD_PARAM;
switch (grouping_type) {
case GF_4CC( 'r', 'a', 'p', ' ' ):
{
char udta[2];
bs = gf_bs_new(udta, 2*sizeof(char), GF_BITSTREAM_WRITE);
gf_bs_write_u8(bs, ((GF_VisualRandomAccessEntry *)entry)->num_leading_samples_known);
gf_bs_write_u8(bs, ((GF_VisualRandomAccessEntry *)entry)->num_leading_samples);
gf_bs_del(bs);
return gf_isom_set_sample_group_info_ex(NULL, traf, 0, grouping_type, 0, udta, sg_rap_create_entry, sg_rap_compare_entry);
}
case GF_4CC( 'r', 'o', 'l', 'l' ):
{
char udta[2];
bs = gf_bs_new(udta, 2*sizeof(char), GF_BITSTREAM_WRITE);
gf_bs_write_u16(bs, ((GF_RollRecoveryEntry *)entry)->roll_distance);
return gf_isom_set_sample_group_info_ex(NULL, traf, 0, grouping_type, 0, udta, sg_roll_create_entry, sg_roll_compare_entry);
}
case GF_4CC( 's', 'e', 'i', 'g' ):
{
char *udta;
u32 size;
GF_BitStream *bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
GF_Err e = GF_OK;
gf_bs_write_u8(bs, 0x0);
gf_bs_write_int(bs, ((GF_CENCSampleEncryptionGroupEntry *)entry)->crypt_byte_block, 4);
gf_bs_write_int(bs, ((GF_CENCSampleEncryptionGroupEntry *)entry)->skip_byte_block, 4);
gf_bs_write_u8(bs, ((GF_CENCSampleEncryptionGroupEntry *)entry)->IsProtected);
gf_bs_write_u8(bs, ((GF_CENCSampleEncryptionGroupEntry *)entry)->Per_Sample_IV_size);
gf_bs_write_data(bs, (char *) ((GF_CENCSampleEncryptionGroupEntry *)entry)->KID, 16);
if ((((GF_CENCSampleEncryptionGroupEntry *)entry)->IsProtected == 1) && !((GF_CENCSampleEncryptionGroupEntry *)entry)->Per_Sample_IV_size) {
gf_bs_write_u8(bs, ((GF_CENCSampleEncryptionGroupEntry *)entry)->constant_IV_size);
gf_bs_write_data(bs,(char *) ((GF_CENCSampleEncryptionGroupEntry *)entry)->constant_IV, ((GF_CENCSampleEncryptionGroupEntry *)entry)->constant_IV_size);
}
gf_bs_get_content(bs, &udta, &size);
gf_bs_del(bs);
e = gf_isom_set_sample_group_info_ex(NULL, traf, 0, grouping_type, 0, udta, sg_encryption_create_entry, sg_encryption_compare_entry);
gf_free(udta);
return e;
}
default:
return GF_BAD_PARAM;
}
}
return gf_isom_add_sample_group_entry(traf->sampleGroups, 0, grouping_type, grouping_type_parameter, sampleGroupDescriptionIndex);
}
#endif
GF_EXPORT
GF_Err gf_isom_set_sample_cenc_group(GF_ISOFile *movie, u32 track, u32 sample_number, u8 isEncrypted, u8 IV_size, bin128 KeyID,
u8 crypt_byte_block, u8 skip_byte_block, u8 constant_IV_size, bin128 constant_IV)
{
char *udta;
u32 size;
GF_BitStream *bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
GF_Err e = GF_OK;
if ((IV_size!=0) && (IV_size!=8) && (IV_size!=16)) return GF_BAD_PARAM;
gf_bs_write_u8(bs, 0x0);
gf_bs_write_int(bs, crypt_byte_block, 4);
gf_bs_write_int(bs, skip_byte_block, 4);
gf_bs_write_u8(bs, isEncrypted);
gf_bs_write_u8(bs, IV_size);
gf_bs_write_data(bs, (char *) KeyID, 16);
if ((isEncrypted == 1) && !IV_size) {
gf_bs_write_u8(bs, constant_IV_size);
gf_bs_write_data(bs,(char *) constant_IV, constant_IV_size);
}
gf_bs_get_content(bs, &udta, &size);
gf_bs_del(bs);
e = gf_isom_set_sample_group_info(movie, track, sample_number, GF_4CC( 's', 'e', 'i', 'g' ), 0, udta, sg_encryption_create_entry, sg_encryption_compare_entry);
gf_free(udta);
return e;
}
static GF_Err gf_isom_set_ctts_v1(GF_ISOFile *file, u32 track, GF_TrackBox *trak)
{
u32 i, shift;
u64 duration;
GF_CompositionOffsetBox *ctts;
GF_CompositionToDecodeBox *cslg;
s32 leastCTTS, greatestCTTS;
ctts = trak->Media->information->sampleTable->CompositionOffset;
shift = ctts->entries[0].decodingOffset;
leastCTTS = GF_INT_MAX;
greatestCTTS = 0;
for (i=0; i<ctts->nb_entries; i++) {
ctts->entries[i].decodingOffset -= shift;
if ((s32)ctts->entries[i].decodingOffset < leastCTTS)
leastCTTS = ctts->entries[i].decodingOffset;
if ((s32)ctts->entries[i].decodingOffset > greatestCTTS)
greatestCTTS = ctts->entries[i].decodingOffset;
}
ctts->version = 1;
gf_isom_remove_edit_segments(file, track);
if (!trak->Media->information->sampleTable->CompositionToDecode)
trak->Media->information->sampleTable->CompositionToDecode = (GF_CompositionToDecodeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_CSLG);
cslg = trak->Media->information->sampleTable->CompositionToDecode;
cslg->compositionToDTSShift = shift;
cslg->leastDecodeToDisplayDelta = leastCTTS;
cslg->greatestDecodeToDisplayDelta = greatestCTTS;
cslg->compositionStartTime = 0;
duration = gf_isom_get_media_duration(file, track);
cslg->compositionEndTime = (duration<0x7FFFFFFF) ? (s32) duration : 0;
gf_isom_modify_alternate_brand(file, GF_ISOM_BRAND_ISO4, GF_TRUE);
return GF_OK;
}
static GF_Err gf_isom_set_ctts_v0(GF_ISOFile *file, GF_TrackBox *trak)
{
u32 i;
s32 shift;
GF_CompositionOffsetBox *ctts;
GF_CompositionToDecodeBox *cslg;
ctts = trak->Media->information->sampleTable->CompositionOffset;
if (!trak->Media->information->sampleTable->CompositionToDecode)
{
shift = 0;
for (i=0; i<ctts->nb_entries; i++) {
if (-ctts->entries[i].decodingOffset > shift)
shift = -ctts->entries[i].decodingOffset;
}
if (shift > 0)
{
for (i=0; i<ctts->nb_entries; i++) {
ctts->entries[i].decodingOffset += shift;
}
}
}
else
{
cslg = trak->Media->information->sampleTable->CompositionToDecode;
shift = cslg->compositionToDTSShift;
for (i=0; i<ctts->nb_entries; i++) {
ctts->entries[i].decodingOffset += shift;
}
gf_isom_box_del((GF_Box *)cslg);
trak->Media->information->sampleTable->CompositionToDecode = NULL;
}
if (! trak->editBox && shift>0) {
u64 dur = trak->Media->mediaHeader->duration;
dur *= file->moov->mvhd->timeScale;
dur /= trak->Media->mediaHeader->timeScale;
gf_isom_set_edit_segment(file, gf_list_find(file->moov->trackList, trak)+1, 0, dur, shift, GF_ISOM_EDIT_NORMAL);
}
ctts->version = 0;
gf_isom_modify_alternate_brand(file, GF_ISOM_BRAND_ISO4, GF_FALSE);
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_set_composition_offset_mode(GF_ISOFile *file, u32 track, Bool use_negative_offsets)
{
GF_Err e;
GF_TrackBox *trak;
GF_CompositionOffsetBox *ctts;
e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(file, track);
if (!trak) return GF_BAD_PARAM;
ctts = trak->Media->information->sampleTable->CompositionOffset;
if (!ctts) return GF_OK;
if (use_negative_offsets) {
if (ctts->version==1) return GF_OK;
return gf_isom_set_ctts_v1(file, track, trak);
} else {
if (ctts->version==0) return GF_OK;
return gf_isom_set_ctts_v0(file, trak);
}
}
GF_EXPORT
GF_Err gf_isom_set_sync_table(GF_ISOFile *file, u32 track)
{
GF_Err e;
GF_TrackBox *trak;
e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(file, track);
if (!trak) return GF_BAD_PARAM;
trak->Media->information->sampleTable->SyncSample = (GF_SyncSampleBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_STSS);
return GF_OK;
}
Bool gf_isom_is_identical_sgpd(void *ptr1, void *ptr2, u32 grouping_type)
{
Bool res = GF_FALSE;
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_BitStream *bs1, *bs2;
char *buf1, *buf2;
u32 len1, len2;
if (!ptr1 || !ptr2)
return GF_FALSE;
bs1 = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
if (grouping_type) {
sgpd_write_entry(grouping_type, ptr1, bs1);
} else {
gf_isom_box_write((GF_Box *)ptr1, bs1);
}
gf_bs_get_content(bs1, &buf1, &len1);
gf_bs_del(bs1);
bs2 = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
if (grouping_type) {
sgpd_write_entry(grouping_type, ptr2, bs2);
} else {
gf_isom_box_write((GF_Box *)ptr2, bs2);
}
gf_bs_get_content(bs2, &buf2, &len2);
gf_bs_del(bs2);
if ((len1==len2) && !memcmp(buf1, buf2, len1))
res = GF_TRUE;
gf_free(buf1);
gf_free(buf2);
#endif
return res;
}
GF_EXPORT
GF_Err gf_isom_copy_sample_info(GF_ISOFile *dst, u32 dst_track, GF_ISOFile *src, u32 src_track, u32 sampleNumber)
{
u32 i, count, idx, dst_sample_num, subs_flags;
GF_SubSampleInfoEntry *sub_sample;
GF_Err e;
GF_TrackBox *src_trak, *dst_trak;
src_trak = gf_isom_get_track_from_file(src, src_track);
if (!src_trak) return GF_BAD_PARAM;
dst_trak = gf_isom_get_track_from_file(dst, dst_track);
if (!dst_trak) return GF_BAD_PARAM;
dst_sample_num = dst_trak->Media->information->sampleTable->SampleSize->sampleCount;
if (src_trak->Media->information->sampleTable->SampleDep) {
u32 isLeading, dependsOn, dependedOn, redundant;
isLeading = dependsOn = dependedOn = redundant = 0;
e = stbl_GetSampleDepType(src_trak->Media->information->sampleTable->SampleDep, sampleNumber, &isLeading, &dependsOn, &dependedOn, &redundant);
if (e) return e;
e = stbl_AppendDependencyType(dst_trak->Media->information->sampleTable, isLeading, dependsOn, dependedOn, redundant);
if (e) return e;
}
idx=1;
while (gf_isom_get_subsample_types(src, src_track, idx, &subs_flags)) {
GF_SubSampleInformationBox *dst_subs=NULL;
idx++;
if ( ! gf_isom_sample_get_subsample_entry(src, src_track, sampleNumber, subs_flags, &sub_sample))
continue;
if (!dst_trak->Media->information->sampleTable->sub_samples) {
dst_trak->Media->information->sampleTable->sub_samples = gf_list_new();
}
count = gf_list_count(dst_trak->Media->information->sampleTable->sub_samples);
for (i=0; i<count; i++) {
dst_subs = gf_list_get(dst_trak->Media->information->sampleTable->sub_samples, i);
if (dst_subs->flags==subs_flags) break;
dst_subs=NULL;
}
if (!dst_subs) {
dst_subs = (GF_SubSampleInformationBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_SUBS);
dst_subs->version=0;
dst_subs->flags = subs_flags;
gf_list_add(dst_trak->Media->information->sampleTable->sub_samples, dst_subs);
}
count = gf_list_count(sub_sample->SubSamples);
for (i=0; i<count; i++) {
GF_SubSampleEntry *entry = (GF_SubSampleEntry*)gf_list_get(sub_sample->SubSamples, i);
e = gf_isom_add_subsample_info(dst_subs, dst_sample_num, entry->subsample_size, entry->subsample_priority, entry->reserved, entry->discardable);
if (e) return e;
}
}
if (src_trak->Media->information->sampleTable->sampleGroups) {
count = gf_list_count(src_trak->Media->information->sampleTable->sampleGroups);
for (i=0; i<count; i++) {
GF_SampleGroupBox *sg;
u32 j, k, default_index;
u32 first_sample_in_entry, last_sample_in_entry, group_desc_index_src, group_desc_index_dst;
first_sample_in_entry = 1;
sg = (GF_SampleGroupBox*)gf_list_get(src_trak->Media->information->sampleTable->sampleGroups, i);
for (j=0; j<sg->entry_count; j++) {
last_sample_in_entry = first_sample_in_entry + sg->sample_entries[j].sample_count - 1;
if ((sampleNumber<first_sample_in_entry) || (sampleNumber>last_sample_in_entry)) {
first_sample_in_entry = last_sample_in_entry+1;
continue;
}
if (!dst_trak->Media->information->sampleTable->sampleGroups)
dst_trak->Media->information->sampleTable->sampleGroups = gf_list_new();
group_desc_index_src = group_desc_index_dst = sg->sample_entries[j].group_description_index;
if (group_desc_index_src) {
GF_SampleGroupDescriptionBox *sgd_src, *sgd_dst;
GF_DefaultSampleGroupDescriptionEntry *sgde_src, *sgde_dst;
group_desc_index_dst = 0;
sgde_src = gf_isom_get_sample_group_info_entry(src, src_trak, sg->grouping_type, sg->sample_entries[j].group_description_index, &default_index, &sgd_src);
if (!sgde_src) break;
if (!dst_trak->Media->information->sampleTable->sampleGroupsDescription)
dst_trak->Media->information->sampleTable->sampleGroupsDescription = gf_list_new();
sgd_dst = NULL;
for (k=0; k< gf_list_count(dst_trak->Media->information->sampleTable->sampleGroupsDescription); k++) {
sgd_dst = gf_list_get(dst_trak->Media->information->sampleTable->sampleGroupsDescription, k);
if (sgd_dst->grouping_type==sgd_src->grouping_type) break;
sgd_dst = NULL;
}
if (!sgd_dst) {
gf_isom_clone_box( (GF_Box *) sgd_src, (GF_Box **) &sgd_dst);
if (!sgd_dst) return GF_OUT_OF_MEM;
gf_list_add(dst_trak->Media->information->sampleTable->sampleGroupsDescription, sgd_dst);
}
for (k=0; k<gf_list_count(sgd_dst->group_descriptions); k++) {
sgde_dst = gf_list_get(sgd_dst->group_descriptions, i);
if (gf_isom_is_identical_sgpd(sgde_src, sgde_dst, sgd_src->grouping_type)) {
group_desc_index_dst = k+1;
break;
}
}
if (!group_desc_index_dst) {
GF_SampleGroupDescriptionBox *cloned=NULL;
gf_isom_clone_box( (GF_Box *) sgd_src, (GF_Box **) &cloned);
if (!cloned) return GF_OUT_OF_MEM;
sgde_dst = gf_list_get(cloned->group_descriptions, group_desc_index_dst);
gf_list_rem(cloned->group_descriptions, group_desc_index_dst);
gf_isom_box_del( (GF_Box *) cloned);
gf_list_add(sgd_dst->group_descriptions, sgde_dst);
group_desc_index_dst = gf_list_count(sgd_dst->group_descriptions);
}
}
e = gf_isom_add_sample_group_entry(dst_trak->Media->information->sampleTable->sampleGroups, dst_sample_num, sg->grouping_type, sg->grouping_type_parameter, group_desc_index_dst);
if (e) return e;
break;
}
}
}
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_text_set_display_flags(GF_ISOFile *file, u32 track, u32 desc_index, u32 flags, GF_TextFlagsMode op_type)
{
u32 i;
GF_Err e;
GF_TrackBox *trak;
e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(file, track);
if (!trak) return GF_BAD_PARAM;
for (i=0; i < gf_list_count(trak->Media->information->sampleTable->SampleDescription->other_boxes); i++) {
GF_Tx3gSampleEntryBox *txt;
if (desc_index && (i+1 != desc_index)) continue;
txt = (GF_Tx3gSampleEntryBox*)gf_list_get(trak->Media->information->sampleTable->SampleDescription->other_boxes, i);
if (txt->type != GF_ISOM_BOX_TYPE_TX3G) continue;
switch (op_type) {
case GF_ISOM_TEXT_FLAGS_TOGGLE:
txt->displayFlags |= flags;
break;
case GF_ISOM_TEXT_FLAGS_UNTOGGLE:
txt->displayFlags &= ~flags;
break;
default:
txt->displayFlags = flags;
break;
}
}
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_update_duration(GF_ISOFile *movie)
{
u32 i;
u64 maxDur;
GF_TrackBox *trak;
if (!movie || !movie->moov) return GF_BAD_PARAM;
maxDur = 0;
i=0;
while ((trak = (GF_TrackBox *)gf_list_enum(movie->moov->trackList, &i))) {
if( (movie->LastError = SetTrackDuration(trak)) ) return movie->LastError;
if (trak->Header->duration > maxDur)
maxDur = trak->Header->duration;
}
movie->moov->mvhd->duration = maxDur;
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_update_edit_list_duration(GF_ISOFile *file, u32 track)
{
u32 i;
u64 trackDuration;
GF_EdtsEntry *ent;
GF_EditListBox *elst;
GF_Err e;
GF_TrackBox *trak;
e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(file, track);
if (!trak) return GF_BAD_PARAM;
e = Media_SetDuration(trak);
if (e) return e;
if (!trak->moov->mvhd->timeScale || !trak->Media->mediaHeader->timeScale) return GF_ISOM_INVALID_FILE;
trackDuration = (trak->Media->mediaHeader->duration * trak->moov->mvhd->timeScale) / trak->Media->mediaHeader->timeScale;
if (trak->editBox && trak->editBox->editList) {
u64 editListDuration = 0;
elst = trak->editBox->editList;
i=0;
while ((ent = (GF_EdtsEntry*)gf_list_enum(elst->entryList, &i))) {
if (ent->segmentDuration > trackDuration)
ent->segmentDuration = trackDuration;
if ((ent->mediaTime>=0) && ((u64) ent->mediaTime>=trak->Media->mediaHeader->duration)) {
ent->mediaTime = trak->Media->mediaHeader->duration;
}
editListDuration += ent->segmentDuration;
}
trackDuration = editListDuration;
}
if (!trackDuration) {
trackDuration = (trak->Media->mediaHeader->duration * trak->moov->mvhd->timeScale) / trak->Media->mediaHeader->timeScale;
}
trak->Header->duration = trackDuration;
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_clone_pssh(GF_ISOFile *output, GF_ISOFile *input, Bool in_moof) {
GF_Box *a;
u32 i;
i = 0;
while ((a = (GF_Box *)gf_list_enum(input->moov->other_boxes, &i))) {
if (a->type == GF_ISOM_BOX_TYPE_PSSH) {
GF_ProtectionSystemHeaderBox *pssh = (GF_ProtectionSystemHeaderBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_PSSH);
memmove(pssh->SystemID, ((GF_ProtectionSystemHeaderBox *)a)->SystemID, 16);
pssh->KID_count = ((GF_ProtectionSystemHeaderBox *)a)->KID_count;
pssh->KIDs = (bin128 *)gf_malloc(pssh->KID_count*sizeof(bin128));
memmove(pssh->KIDs, ((GF_ProtectionSystemHeaderBox *)a)->KIDs, pssh->KID_count*sizeof(bin128));
pssh->private_data_size = ((GF_ProtectionSystemHeaderBox *)a)->private_data_size;
pssh->private_data = (u8 *)gf_malloc(pssh->private_data_size*sizeof(char));
memmove(pssh->private_data, ((GF_ProtectionSystemHeaderBox *)a)->private_data, pssh->private_data_size);
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
gf_isom_box_add_default(in_moof ? (GF_Box*)output->moof : (GF_Box*)output->moov, (GF_Box*)pssh);
#else
gf_isom_box_add_default((GF_Box*)output->moov, (GF_Box*)pssh);
#endif
}
}
return GF_OK;
}
GF_EXPORT
GF_Err gf_isom_set_track_group(GF_ISOFile *file, u32 track_number, u32 track_group_id, u32 group_type, Bool do_add)
{
u32 i, j;
GF_TrackGroupTypeBox *trgt;
GF_Err e;
GF_TrackBox *trak;
e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
if (e) return e;
trak = gf_isom_get_track_from_file(file, track_number);
if (!trak) return GF_BAD_PARAM;
if (!trak->groups) trak->groups = (GF_TrackGroupBox*) gf_isom_box_new(GF_ISOM_BOX_TYPE_TRGR);
for (j=0; j<gf_list_count(file->moov->trackList); j++) {
GF_TrackBox *a_trak = gf_list_get(file->moov->trackList, j);
if (!a_trak->groups) continue;
for (i=0; i<gf_list_count(a_trak->groups->groups); i++) {
trgt = gf_list_get(a_trak->groups->groups, i);
if (trgt->track_group_id==track_group_id) {
if (trgt->group_type != group_type) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("A track with same group ID is already defined for different group type %s\n", gf_4cc_to_str(trgt->group_type) ));
return GF_BAD_PARAM;
}
if (a_trak==trak) {
if (!do_add) {
gf_list_rem(trak->groups->groups, i);
gf_isom_box_del((GF_Box *)trgt);
}
return GF_OK;
}
}
}
}
trgt = (GF_TrackGroupTypeBox*) gf_isom_box_new(GF_ISOM_BOX_TYPE_TRGT);
trgt->track_group_id = track_group_id;
trgt->group_type = group_type;
return gf_list_add(trak->groups->groups, trgt);
}
#endif