static int open_file( char *psz_filename, hnd_t *p_handle, cli_output_opt_t *opt ) { mp4_hnd_t *p_mp4; *p_handle = NULL; FILE *fh = fopen( psz_filename, "w" ); if( !fh ) return -1; FAIL_IF_ERR( !x264_is_regular_file( fh ), "mp4", "MP4 output is incompatible with non-regular file `%s'\n", psz_filename ) fclose( fh ); if( !(p_mp4 = malloc( sizeof(mp4_hnd_t) )) ) return -1; memset( p_mp4, 0, sizeof(mp4_hnd_t) ); p_mp4->p_file = gf_isom_open( psz_filename, GF_ISOM_OPEN_WRITE, NULL ); p_mp4->b_dts_compress = opt->use_dts_compress; if( !(p_mp4->p_sample = gf_isom_sample_new()) ) { close_file( p_mp4, 0, 0 ); return -1; } gf_isom_set_brand_info( p_mp4->p_file, GF_ISOM_BRAND_AVC1, 0 ); *p_handle = p_mp4; return 0; }
//写入AAC信息 bool EasyMP4Writer::WriteAACInfo(unsigned char*info,int len, int nSampleRate, int nChannel, int nBitsPerSample) { p_audiosample=gf_isom_sample_new(); p_audiosample->data=(char*)malloc(1024*10); GF_ESD*esd= gf_odf_desc_esd_new(0); esd->ESID=gf_isom_get_track_id(p_file,m_audiotrackid); esd->OCRESID=gf_isom_get_track_id(p_file,m_audiotrackid); esd->decoderConfig->streamType=0x05; esd->decoderConfig->objectTypeIndication=0x40;//0x40; esd->slConfig->timestampResolution=1000;//1000;//时间单元 esd->decoderConfig->decoderSpecificInfo=(GF_DefaultDescriptor*)gf_odf_desc_new(GF_ODF_DSI_TAG); esd->decoderConfig->decoderSpecificInfo->data=(char*)malloc(len); memcpy(esd->decoderConfig->decoderSpecificInfo->data,info,len); esd->decoderConfig->decoderSpecificInfo->dataLength=len; GF_Err gferr=gf_isom_new_mpeg4_description(p_file, m_audiotrackid, esd, NULL, NULL, &i_audiodescidx); if (gferr!=0) { // TRACE("mpeg4_description:%d\n",gferr); } gferr=gf_isom_set_audio_info(p_file,m_audiotrackid,i_audiodescidx, nSampleRate,nChannel, nBitsPerSample);//44100 2 16 if (gferr!=0) { // TRACE("gf_isom_set_audio:%d\n",gferr); } free(esd->decoderConfig->decoderSpecificInfo->data); return true; }
int dc_audio_muxer_init(AudioOutputFile * p_aoutf, AudioData * p_adata, AudioMuxerType muxer_type, int frame_per_seg, int frame_per_frag) { char name[256]; sprintf(name, "audio encoder %s", p_adata->psz_name); dc_consumer_init(&p_aoutf->acon, AUDIO_CB_SIZE, name); p_aoutf->p_sample = gf_isom_sample_new(); p_aoutf->p_isof = NULL; p_aoutf->muxer_type = muxer_type; p_aoutf->i_frame_per_seg = frame_per_seg; p_aoutf->i_frame_per_frag = frame_per_frag; return 0; }
int dc_audio_muxer_init(AudioOutputFile *audio_output_file, AudioDataConf *audio_data_conf, AudioMuxerType muxer_type, int frame_per_seg, int frame_per_frag, u32 seg_marker) { char name[GF_MAX_PATH]; snprintf(name, sizeof(name), "audio encoder %s", audio_data_conf->filename); dc_consumer_init(&audio_output_file->consumer, AUDIO_CB_SIZE, name); #ifndef GPAC_DISABLE_ISOM audio_output_file->sample = gf_isom_sample_new(); audio_output_file->isof = NULL; #endif audio_output_file->muxer_type = muxer_type; audio_output_file->frame_per_seg = frame_per_seg; audio_output_file->frame_per_frag = frame_per_frag; audio_output_file->seg_marker = seg_marker; return 0; }
//stores the hint sample in the file //set IsRandomAccessPoint if you want to indicate that this is a random access point //in the stream GF_Err gf_isom_end_hint_sample(GF_ISOFile *the_file, u32 trackNumber, u8 IsRandomAccessPoint) { GF_TrackBox *trak; GF_HintSampleEntryBox *entry; u32 dataRefIndex; GF_Err e; GF_BitStream *bs; GF_ISOSample *samp; trak = gf_isom_get_track_from_file(the_file, trackNumber); if (!trak || !IsHintTrack(trak)) return GF_BAD_PARAM; e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &dataRefIndex); if (e) return e; if (!entry->hint_sample) return GF_BAD_PARAM; //first of all, we need to adjust the offset for data referenced IN THIS hint sample //and get some PckSize e = AdjustHintInfo(entry, trak->Media->information->sampleTable->SampleSize->sampleCount + 1); if (e) return e; //ok, let's write the sample bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); e = gf_isom_hint_sample_write(entry->hint_sample, bs); if (e) { gf_bs_del(bs); return e; } samp = gf_isom_sample_new(); samp->CTS_Offset = 0; samp->IsRAP = IsRandomAccessPoint; samp->DTS = entry->hint_sample->TransmissionTime; //get the sample gf_bs_get_content(bs, &samp->data, &samp->dataLength); gf_bs_del(bs); //finally add the sample e = gf_isom_add_sample(the_file, trackNumber, trak->Media->information->sampleTable->currentEntryIndex, samp); gf_isom_sample_del(&samp); //and delete the sample in our entry ... gf_isom_hint_sample_del(entry->hint_sample); entry->hint_sample = NULL; return e; }
GF_ISOSample *gf_isom_webvtt_to_sample(void *s) { GF_Err e = GF_OK; GF_ISOSample *res; GF_BitStream *bs; u32 i; GF_WebVTTCue *cue; GF_WebVTTSample *samp = (GF_WebVTTSample *)s; if (!samp) return NULL; bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); if (gf_list_count(samp->cues)) { i=0; while ((cue = (GF_WebVTTCue *)gf_list_enum(samp->cues, &i))) { e = webvtt_write_cue(bs, cue); if (e) break; } if (e) { gf_bs_del(bs); return NULL; } } else { GF_Box *cuebox = (GF_Box *)vtte_New(); e = gf_isom_box_size((GF_Box *)cuebox); if (!e) e = gf_isom_box_write((GF_Box *)cuebox, bs); gf_isom_box_del((GF_Box *)cuebox); if (e) { gf_bs_del(bs); return NULL; } } res = gf_isom_sample_new(); if (!res) { gf_bs_del(bs); return NULL; } gf_bs_get_content(bs, &res->data, &res->dataLength); gf_bs_del(bs); res->IsRAP = RAP; return res; }
GF_ISOSample *gf_isom_text_to_sample(GF_TextSample *samp) { GF_Err e; GF_ISOSample *res; GF_BitStream *bs; u32 i; if (!samp) return NULL; bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); gf_bs_write_u16(bs, samp->len); if (samp->len) gf_bs_write_data(bs, samp->text, samp->len); e = gpp_write_modifier(bs, (GF_Box *)samp->styles); if (!e) e = gpp_write_modifier(bs, (GF_Box *)samp->highlight_color); if (!e) e = gpp_write_modifier(bs, (GF_Box *)samp->scroll_delay); if (!e) e = gpp_write_modifier(bs, (GF_Box *)samp->box); if (!e) e = gpp_write_modifier(bs, (GF_Box *)samp->wrap); if (!e) { GF_Box *a; i=0; while ((a = (GF_Box*)gf_list_enum(samp->others, &i))) { e = gpp_write_modifier(bs, a); if (e) break; } } if (e) { gf_bs_del(bs); return NULL; } res = gf_isom_sample_new(); if (!res) { gf_bs_del(bs); return NULL; } gf_bs_get_content(bs, &res->data, &res->dataLength); gf_bs_del(bs); res->IsRAP = 1; return res; }
static int open_file( char *psz_filename, hnd_t *p_handle, cli_output_opt_t *opt ) { mp4_hnd_t *p_mp4; *p_handle = NULL; FILE *fh = x264_fopen( psz_filename, "w" ); if( !fh ) return -1; FAIL_IF_ERR( !x264_is_regular_file( fh ), "mp4", "MP4 output is incompatible with non-regular file `%s'\n", psz_filename ) fclose( fh ); if( !(p_mp4 = malloc( sizeof(mp4_hnd_t) )) ) return -1; memset( p_mp4, 0, sizeof(mp4_hnd_t) ); #ifdef _WIN32 /* GPAC doesn't support Unicode filenames. */ char ansi_filename[MAX_PATH]; FAIL_IF_ERR( !x264_ansi_filename( psz_filename, ansi_filename, MAX_PATH, 1 ), "mp4", "invalid ansi filename\n" ) p_mp4->p_file = gf_isom_open( ansi_filename, GF_ISOM_OPEN_WRITE, NULL ); #else p_mp4->p_file = gf_isom_open( psz_filename, GF_ISOM_OPEN_WRITE, NULL ); #endif p_mp4->b_dts_compress = opt->use_dts_compress; if( !(p_mp4->p_sample = gf_isom_sample_new()) ) { close_file( p_mp4, 0, 0 ); return -1; } gf_isom_set_brand_info( p_mp4->p_file, GF_ISOM_BRAND_AVC1, 0 ); *p_handle = p_mp4; return 0; }
/* * Writing the generic sample structure into a sample buffer * 2 options: * - putting the text or XML in the sample directly * - or using a meta box to structure the sample data */ GF_ISOSample *gf_isom_generic_subtitle_to_sample(GF_GenericSubtitleSample *samp) { GF_ISOSample *res; GF_BitStream *bs; if (!samp) return NULL; bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); //gf_bs_write_u16(bs, samp->len); if (samp->len) gf_bs_write_data(bs, samp->text, samp->len); else gf_bs_write_data(bs, "", 1); res = gf_isom_sample_new(); if (!res) { gf_bs_del(bs); return NULL; } gf_bs_get_content(bs, &res->data, &res->dataLength); gf_bs_del(bs); res->IsRAP = 1; return res; }
static GF_ISOSample *gf_isom_get_data_sample(GF_HintSample *hsamp, GF_TrackBox *trak, u32 sample_num) { GF_ISOSample *samp; GF_HintDataCache *hdc; u32 i, count; count = gf_list_count(hsamp->sample_cache); for (i=0; i<count; i++) { hdc = (GF_HintDataCache *)gf_list_get(hsamp->sample_cache, i); if ((hdc->sample_num==sample_num) && (hdc->trak==trak)) return hdc->samp; } samp = gf_isom_sample_new(); Media_GetSample(trak->Media, sample_num, &samp, &i, 0, NULL); if (!samp) return NULL; GF_SAFEALLOC(hdc, GF_HintDataCache); hdc->samp = samp; hdc->sample_num = sample_num; hdc->trak = trak; /*we insert all new samples, since they're more likely to be fetched next (except for audio interleaving and other multiplex)*/ gf_list_insert(hsamp->sample_cache, hdc, 0); return samp; }
//sps,pps第一个字节为0x67或68, bool EasyMP4Writer::WriteH264SPSandPPS(unsigned char*sps,int spslen,unsigned char*pps,int ppslen,int width,int height) { p_videosample=gf_isom_sample_new(); p_videosample->data=(char*)malloc(1024*1024); p_config=gf_odf_avc_cfg_new(); gf_isom_avc_config_new(p_file,m_videtrackid,p_config,NULL,NULL,&i_videodescidx); gf_isom_set_visual_info(p_file,m_videtrackid,i_videodescidx,width,height); GF_AVCConfigSlot m_slotsps={0}; GF_AVCConfigSlot m_slotpps={0}; p_config->configurationVersion = 1; p_config->AVCProfileIndication = sps[1]; p_config->profile_compatibility = sps[2]; p_config->AVCLevelIndication = sps[3]; m_slotsps.size=spslen; m_slotsps.data=(char*)malloc(spslen); memcpy(m_slotsps.data,sps,spslen); gf_list_add(p_config->sequenceParameterSets,&m_slotsps); m_slotpps.size=ppslen; m_slotpps.data=(char*)malloc(ppslen); memcpy(m_slotpps.data,pps,ppslen); gf_list_add(p_config->pictureParameterSets,&m_slotpps); gf_isom_avc_config_update(p_file,m_videtrackid,1,p_config); free(m_slotsps.data); free(m_slotpps.data); return true; }
int dc_video_muxer_init(VideoOutputFile *video_output_file, VideoDataConf *video_data_conf, VideoMuxerType muxer_type, int frame_per_segment, int frame_per_fragment, u32 seg_marker, int gdr, int seg_dur, int frag_dur, int frame_dur, int gop_size, int video_cb_size) { char name[GF_MAX_PATH]; memset(video_output_file, 0, sizeof(VideoOutputFile)); snprintf(name, sizeof(name), "video encoder %s", video_data_conf->filename); dc_consumer_init(&video_output_file->consumer, video_cb_size, name); video_output_file->sample = gf_isom_sample_new(); video_output_file->isof = NULL; video_output_file->muxer_type = muxer_type; video_output_file->frame_per_segment = frame_per_segment; video_output_file->frame_per_fragment = frame_per_fragment; video_output_file->seg_dur = seg_dur; video_output_file->frag_dur = frag_dur; video_output_file->seg_marker = seg_marker; video_output_file->gdr = gdr; video_output_file->gop_size = gop_size; video_output_file->frame_dur = frame_dur; return 0; }
static GF_Err ISOW_Write(GF_StreamingCache *mc, LPNETCHANNEL ch, char *data, u32 data_size, GF_SLHeader *sl_hdr) { ISOMChannel *mch; GF_ESD *esd; u32 di, mtype; u64 DTS, CTS; ISOMReader *cache = (ISOMReader *)mc->priv; if (!cache->mov || !cache->service) return GF_BAD_PARAM; mch = isor_get_channel(cache, ch); if (!mch) { Bool mapped; GF_NetworkCommand com; com.base.on_channel = ch; com.base.command_type = GF_NET_CHAN_GET_ESD; gf_service_command(cache->service, &com, GF_OK); if (!com.cache_esd.esd) return GF_SERVICE_ERROR; esd = (GF_ESD *)com.cache_esd.esd; switch (esd->decoderConfig->streamType) { case GF_STREAM_OD: mtype = GF_ISOM_MEDIA_OD; break; case GF_STREAM_SCENE: mtype = GF_ISOM_MEDIA_SCENE; break; case GF_STREAM_VISUAL: mtype = GF_ISOM_MEDIA_VISUAL; break; case GF_STREAM_AUDIO: mtype = GF_ISOM_MEDIA_AUDIO; break; case GF_STREAM_MPEG7: mtype = GF_ISOM_MEDIA_MPEG7; break; case GF_STREAM_OCI: mtype = GF_ISOM_MEDIA_OCI; break; case GF_STREAM_IPMP: mtype = GF_ISOM_MEDIA_IPMP; break; case GF_STREAM_MPEGJ: mtype = GF_ISOM_MEDIA_MPEGJ; break; case GF_STREAM_TEXT: mtype = GF_ISOM_MEDIA_TEXT; break; default: return GF_NOT_SUPPORTED; } GF_SAFEALLOC(mch, ISOMChannel); if (!mch) { return GF_OUT_OF_MEM; } mch->time_scale = esd->slConfig->timestampResolution; mch->streamType = esd->decoderConfig->streamType; mch->track = gf_isom_new_track(cache->mov, com.cache_esd.esd->ESID, mtype, mch->time_scale); mch->is_playing = GF_TRUE; mch->channel = ch; mch->owner = cache; gf_isom_set_track_enabled(cache->mov, mch->track, 1); /*translate 3GP streams to MP4*/ mapped = GF_FALSE; if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_MEDIA_GENERIC) { char szCode[5]; strncpy(szCode, esd->decoderConfig->decoderSpecificInfo->data, 4); szCode[4]=0; if (!stricmp(szCode, "samr") || !stricmp(szCode, "amr ") || !stricmp(szCode, "sawb")) { GF_3GPConfig amrc; mapped = GF_TRUE; memset(&amrc, 0, sizeof(GF_3GPConfig)); amrc.frames_per_sample = (u32) esd->decoderConfig->decoderSpecificInfo->data[13]; amrc.type = (!stricmp(szCode, "sawb")) ? GF_ISOM_SUBTYPE_3GP_AMR_WB : GF_ISOM_SUBTYPE_3GP_AMR; amrc.vendor = GF_VENDOR_GPAC; gf_isom_3gp_config_new(cache->mov, mch->track, &amrc, NULL, NULL, &di); } else if (!stricmp(szCode, "h263")) { GF_3GPConfig h263c; memset(&h263c, 0, sizeof(GF_3GPConfig)); h263c.type = GF_ISOM_SUBTYPE_3GP_H263; h263c.vendor = GF_VENDOR_GPAC; gf_isom_3gp_config_new(cache->mov, mch->track, &h263c, NULL, NULL, &di); mapped = GF_TRUE; } } if (!mapped) gf_isom_new_mpeg4_description(cache->mov, mch->track, esd, NULL, NULL, &di); if (com.cache_esd.is_iod_stream) gf_isom_add_track_to_root_od(cache->mov, mch->track); gf_list_add(cache->channels, mch); } /*first sample, cache it*/ if (!mch->cache_sample) { mch->cache_seed_ts = sl_hdr->decodingTimeStamp; mch->cache_sample = gf_isom_sample_new(); mch->cache_sample->IsRAP = sl_hdr->randomAccessPointFlag; mch->cache_sample->dataLength = data_size; mch->cache_sample->data = (char*)gf_malloc(sizeof(char)*data_size); memcpy(mch->cache_sample->data, data, sizeof(char)*data_size); return GF_OK; } /*adjust DTS/CTS*/ DTS = sl_hdr->decodingTimeStamp - mch->cache_seed_ts; if ((mch->streamType==GF_STREAM_VISUAL) && (DTS<=mch->cache_sample->DTS)) { assert(DTS>mch->prev_dts); CTS = mch->cache_sample->DTS + mch->cache_sample->CTS_Offset; mch->cache_sample->CTS_Offset = 0; /*first time, shift all CTS*/ if (!mch->frame_cts_offset) { u32 i, count = gf_isom_get_sample_count(cache->mov, mch->track); mch->frame_cts_offset = (u32) (DTS-mch->prev_dts); for (i=0; i<count; i++) { gf_isom_modify_cts_offset(cache->mov, mch->track, i+1, mch->frame_cts_offset); } mch->cache_sample->CTS_Offset += mch->frame_cts_offset; } mch->cache_sample->DTS = mch->prev_dts + mch->frame_cts_offset; mch->cache_sample->CTS_Offset += (u32) (CTS-mch->cache_sample->DTS); } /*deal with reference picture insertion: if no CTS offset and biggest CTS until now, this is a reference insertion - we must check that in order to make sure we have strictly increasing DTSs*/ if (mch->max_cts && !mch->cache_sample->CTS_Offset && (mch->cache_sample->DTS+mch->cache_sample->CTS_Offset > mch->max_cts)) { assert(mch->cache_sample->DTS > mch->prev_dts + mch->frame_cts_offset); CTS = mch->cache_sample->DTS + mch->cache_sample->CTS_Offset; mch->cache_sample->DTS = mch->prev_dts + mch->frame_cts_offset; mch->cache_sample->CTS_Offset = (u32) (CTS-mch->cache_sample->DTS); } if (mch->cache_sample->CTS_Offset) mch->max_cts = mch->cache_sample->DTS+mch->cache_sample->CTS_Offset; /*add cache*/ gf_isom_add_sample(cache->mov, mch->track, 1, mch->cache_sample); assert(!mch->prev_dts || (mch->prev_dts < mch->cache_sample->DTS)); mch->prev_dts = mch->cache_sample->DTS; mch->duration = MAX(mch->max_cts, mch->prev_dts); gf_isom_sample_del(&mch->cache_sample); /*store sample*/ mch->cache_sample = gf_isom_sample_new(); mch->cache_sample->IsRAP = sl_hdr->randomAccessPointFlag; mch->cache_sample->DTS = DTS + mch->frame_cts_offset; mch->cache_sample->CTS_Offset = (u32) (sl_hdr->compositionTimeStamp - mch->cache_seed_ts - DTS); mch->cache_sample->dataLength = data_size; mch->cache_sample->data = (char*)gf_malloc(sizeof(char)*data_size); memcpy(mch->cache_sample->data, data, sizeof(char)*data_size); return GF_OK; }
// Update the dependancies when an OD AU is inserted in the file GF_Err Media_ParseODFrame(GF_MediaBox *mdia, GF_ISOSample *sample, GF_ISOSample **od_samp) { GF_TrackReferenceBox *tref; GF_TrackReferenceTypeBox *mpod; GF_Err e; GF_ODCom *com; GF_ODCodec *ODencode; GF_ODCodec *ODdecode; u32 i, j; //the commands we proceed GF_ESDUpdate *esdU, *esdU2; GF_ESDRemove *esdR, *esdR2; GF_ODUpdate *odU, *odU2; //the desc they contain GF_ObjectDescriptor *od; GF_IsomObjectDescriptor *isom_od; GF_ESD *esd; GF_ES_ID_Ref *ref; GF_Descriptor *desc; *od_samp = NULL; if (!mdia || !sample || !sample->data || !sample->dataLength) return GF_BAD_PARAM; //First find the references, and create them if none tref = mdia->mediaTrack->References; if (!tref) { tref = (GF_TrackReferenceBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_TREF); e = trak_AddBox((GF_Box*)mdia->mediaTrack, (GF_Box *) tref); if (e) return e; } //then find the OD reference, and create it if none e = Track_FindRef(mdia->mediaTrack, GF_ISOM_BOX_TYPE_MPOD, &mpod); if (e) return e; if (!mpod) { mpod = (GF_TrackReferenceTypeBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_REFT); mpod->reference_type = GF_ISOM_BOX_TYPE_MPOD; e = tref_AddBox((GF_Box*)tref, (GF_Box *)mpod); if (e) return e; } //OK, create our codecs ODencode = gf_odf_codec_new(); if (!ODencode) return GF_OUT_OF_MEM; ODdecode = gf_odf_codec_new(); if (!ODdecode) return GF_OUT_OF_MEM; e = gf_odf_codec_set_au(ODdecode, sample->data, sample->dataLength); if (e) goto err_exit; e = gf_odf_codec_decode(ODdecode); if (e) goto err_exit; while (1) { com = gf_odf_codec_get_com(ODdecode); if (!com) break; //check our commands switch (com->tag) { //Rewrite OD Update case GF_ODF_OD_UPDATE_TAG: //duplicate our command odU = (GF_ODUpdate *) com; odU2 = (GF_ODUpdate *) gf_odf_com_new(GF_ODF_OD_UPDATE_TAG); i=0; while ((desc = (GF_Descriptor*)gf_list_enum(odU->objectDescriptors, &i))) { //both OD and IODs are accepted switch (desc->tag) { case GF_ODF_OD_TAG: case GF_ODF_IOD_TAG: break; default: e = GF_ODF_INVALID_DESCRIPTOR; goto err_exit; } //get the esd e = gf_odf_desc_copy(desc, (GF_Descriptor **)&od); if (e) goto err_exit; if (desc->tag == GF_ODF_OD_TAG) { isom_od = (GF_IsomObjectDescriptor *) gf_malloc(sizeof(GF_IsomObjectDescriptor)); isom_od->tag = GF_ODF_ISOM_OD_TAG; } else { isom_od = (GF_IsomObjectDescriptor *) gf_malloc(sizeof(GF_IsomInitialObjectDescriptor)); isom_od->tag = GF_ODF_ISOM_IOD_TAG; //copy PL ((GF_IsomInitialObjectDescriptor *)isom_od)->inlineProfileFlag = ((GF_InitialObjectDescriptor *)od)->inlineProfileFlag; ((GF_IsomInitialObjectDescriptor *)isom_od)->graphics_profileAndLevel = ((GF_InitialObjectDescriptor *)od)->graphics_profileAndLevel; ((GF_IsomInitialObjectDescriptor *)isom_od)->audio_profileAndLevel = ((GF_InitialObjectDescriptor *)od)->audio_profileAndLevel; ((GF_IsomInitialObjectDescriptor *)isom_od)->OD_profileAndLevel = ((GF_InitialObjectDescriptor *)od)->OD_profileAndLevel; ((GF_IsomInitialObjectDescriptor *)isom_od)->scene_profileAndLevel = ((GF_InitialObjectDescriptor *)od)->scene_profileAndLevel; ((GF_IsomInitialObjectDescriptor *)isom_od)->visual_profileAndLevel = ((GF_InitialObjectDescriptor *)od)->visual_profileAndLevel; ((GF_IsomInitialObjectDescriptor *)isom_od)->IPMPToolList = ((GF_InitialObjectDescriptor *)od)->IPMPToolList; ((GF_InitialObjectDescriptor *)od)->IPMPToolList = NULL; } //in OD stream only ref desc are accepted isom_od->ES_ID_RefDescriptors = gf_list_new(); isom_od->ES_ID_IncDescriptors = NULL; //TO DO: check that a given sampleDescription exists isom_od->extensionDescriptors = od->extensionDescriptors; od->extensionDescriptors = NULL; isom_od->IPMP_Descriptors = od->IPMP_Descriptors; od->IPMP_Descriptors = NULL; isom_od->OCIDescriptors = od->OCIDescriptors; od->OCIDescriptors = NULL; isom_od->URLString = od->URLString; od->URLString = NULL; isom_od->objectDescriptorID = od->objectDescriptorID; j=0; while ((esd = (GF_ESD*)gf_list_enum(od->ESDescriptors, &j))) { ref = (GF_ES_ID_Ref *) gf_odf_desc_new(GF_ODF_ESD_REF_TAG); //1 to 1 mapping trackID and ESID. Add this track to MPOD //if track does not exist, this will be remove while reading the OD stream e = reftype_AddRefTrack(mpod, esd->ESID, &ref->trackRef); e = gf_odf_desc_add_desc((GF_Descriptor *)isom_od, (GF_Descriptor *)ref); if (e) goto err_exit; } //delete our desc gf_odf_desc_del((GF_Descriptor *)od); //and add the new one to our command gf_list_add(odU2->objectDescriptors, isom_od); } //delete the command gf_odf_com_del((GF_ODCom **)&odU); //and add the new one to the codec gf_odf_codec_add_com(ODencode, (GF_ODCom *)odU2); break; //Rewrite ESD Update case GF_ODF_ESD_UPDATE_TAG: esdU = (GF_ESDUpdate *) com; esdU2 = (GF_ESDUpdate *) gf_odf_com_new(GF_ODF_ESD_UPDATE_TAG); esdU2->ODID = esdU->ODID; i=0; while ((esd = (GF_ESD*)gf_list_enum(esdU->ESDescriptors, &i))) { ref = (GF_ES_ID_Ref *) gf_odf_desc_new(GF_ODF_ESD_REF_TAG); //1 to 1 mapping trackID and ESID e = reftype_AddRefTrack(mpod, esd->ESID, &ref->trackRef); e = gf_list_add(esdU2->ESDescriptors, ref); if (e) goto err_exit; } gf_odf_com_del((GF_ODCom **)&esdU); gf_odf_codec_add_com(ODencode, (GF_ODCom *)esdU2); break; //Brand new case: the ESRemove has to be rewritten too according to the specs... case GF_ODF_ESD_REMOVE_TAG: esdR = (GF_ESDRemove *) com; esdR2 = (GF_ESDRemove *) gf_odf_com_new(GF_ODF_ESD_REMOVE_TAG); //change the tag for the file format esdR2->tag = GF_ODF_ESD_REMOVE_REF_TAG; esdR2->ODID = esdR->ODID; esdR2->NbESDs = esdR->NbESDs; if (esdR->NbESDs) { //alloc our stuff esdR2->ES_ID = (unsigned short*)gf_malloc(sizeof(u32) * esdR->NbESDs); if (!esdR2->ES_ID) { e = GF_OUT_OF_MEM; goto err_exit; } for (i = 0; i < esdR->NbESDs; i++) { //1 to 1 mapping trackID and ESID e = reftype_AddRefTrack(mpod, esdR->ES_ID[i], &esdR2->ES_ID[i]); if (e) goto err_exit; } } gf_odf_com_del(&com); gf_odf_codec_add_com(ODencode, (GF_ODCom *)esdR2); break; //Add the command as is default: e = gf_odf_codec_add_com(ODencode, com); if (e) goto err_exit; } } //encode our new AU e = gf_odf_codec_encode(ODencode, 1); if (e) goto err_exit; //and set the buffer in the sample *od_samp = gf_isom_sample_new(); (*od_samp)->CTS_Offset = sample->CTS_Offset; (*od_samp)->DTS = sample->DTS; (*od_samp)->IsRAP = sample->IsRAP; e = gf_odf_codec_get_au(ODencode, & (*od_samp)->data, & (*od_samp)->dataLength); if (e) { gf_isom_sample_del(od_samp); *od_samp = NULL; } err_exit: gf_odf_codec_del(ODencode); gf_odf_codec_del(ODdecode); return e; }
int main(int argc, char **argv) { GF_ISOFile *movie; GF_ESD *esd; GF_Err e; Double gb_size = 5.0; u8 store_mode; u32 track, di, i, nb_samp; GF_ISOSample *samp; store_mode = GF_ISOM_OPEN_WRITE; for (i=1; i<argc; i++) { if (!strcmp(argv[i], "-flat")) store_mode = GF_ISOM_OPEN_WRITE; else if (!strcmp(argv[i], "-inter")) store_mode = GF_ISOM_WRITE_EDIT; else if (!strcmp(argv[i], "-size") && (i+1<argc)) { gb_size = atof(argv[i+1]); i++; } else if (!strcmp(argv[i], "-h")) { PrintUsage(); return 0; } } nb_samp = (u32) (gb_size*1024); fprintf(stdout, "Creating test file %s - %g GBytes - %d samples - %s mode\n", TEST_FILE_NAME, gb_size, nb_samp, (store_mode == GF_ISOM_OPEN_WRITE) ? "Flat" : "Interleaved"); movie = gf_isom_open(TEST_FILE_NAME, store_mode, NULL); if (!movie) { fprintf(stdout, "Error creating file: %s\n", gf_error_to_string(gf_isom_last_error(NULL))); return 1; } track = gf_isom_new_track(movie, 1, GF_ISOM_MEDIA_VISUAL, 25); esd = gf_odf_desc_esd_new(2); esd->decoderConfig->streamType = 4; gf_isom_new_mpeg4_description(movie, track, esd, NULL, NULL, &di); samp = gf_isom_sample_new(); samp->dataLength = 1024*1024; samp->data = gf_malloc(sizeof(char)*samp->dataLength); memset(samp->data, 0, sizeof(char)*samp->dataLength); for (i=0; i<nb_samp; i++) { if (samp->DTS % 25) samp->IsRAP = 0; else samp->IsRAP = 1; e = gf_isom_add_sample(movie, track, di, samp); samp->DTS += 1; fprintf(stdout, "Writing sample %d / %d \r", i+1, nb_samp); if (e) break; } gf_isom_sample_del(&samp); if (e) { fprintf(stdout, "\nError writing sample %d\n", i); gf_isom_delete(movie); return 1; } fprintf(stdout, "\nDone writing samples\n"); e = gf_isom_close(movie); if (e) { fprintf(stdout, "Error writing file\n"); return 1; } return 0; }