static int close_file( hnd_t handle, int64_t largest_pts, int64_t second_largest_pts ) { mp4_hnd_t *p_mp4 = handle; if( !p_mp4 ) return 0; if( p_mp4->p_config ) gf_odf_avc_cfg_del( p_mp4->p_config ); if( p_mp4->p_sample ) { if( p_mp4->p_sample->data ) free( p_mp4->p_sample->data ); p_mp4->p_sample->dataLength = 0; gf_isom_sample_del( &p_mp4->p_sample ); } if( p_mp4->p_file ) { if( p_mp4->i_track ) { /* The mdhd duration is defined as CTS[final] - CTS[0] + duration of last frame. * The mdhd duration (in seconds) should be able to be longer than the tkhd duration since the track is managed by edts. * So, if mdhd duration is equal to the last DTS or less, we give the last composition time delta to the last sample duration. * And then, the mdhd duration is updated, but it time-wise doesn't give the actual duration. * The tkhd duration is the actual track duration. */ uint64_t mdhd_duration = (2 * largest_pts - second_largest_pts) * p_mp4->i_time_inc; if( mdhd_duration != gf_isom_get_media_duration( p_mp4->p_file, p_mp4->i_track ) ) { uint64_t last_dts = gf_isom_get_sample_dts( p_mp4->p_file, p_mp4->i_track, p_mp4->i_numframe ); uint32_t last_duration = (uint32_t)( mdhd_duration > last_dts ? mdhd_duration - last_dts : (largest_pts - second_largest_pts) * p_mp4->i_time_inc ); gf_isom_set_last_sample_duration( p_mp4->p_file, p_mp4->i_track, last_duration ); } /* Write an Edit Box if the first CTS offset is positive. * A media_time is given by not the mvhd timescale but rather the mdhd timescale. * The reason is that an Edit Box maps the presentation time-line to the media time-line. * Any demuxers should follow the Edit Box if it exists. */ GF_ISOSample *sample = gf_isom_get_sample_info( p_mp4->p_file, p_mp4->i_track, 1, NULL, NULL ); if( sample && sample->CTS_Offset > 0 ) { uint32_t mvhd_timescale = gf_isom_get_timescale( p_mp4->p_file ); uint64_t tkhd_duration = (uint64_t)( mdhd_duration * ( (double)mvhd_timescale / p_mp4->i_time_res ) ); gf_isom_append_edit_segment( p_mp4->p_file, p_mp4->i_track, tkhd_duration, sample->CTS_Offset, GF_ISOM_EDIT_NORMAL ); } gf_isom_sample_del( &sample ); recompute_bitrate_mp4( p_mp4->p_file, p_mp4->i_track ); } gf_isom_set_pl_indication( p_mp4->p_file, GF_ISOM_PL_VISUAL, 0x15 ); gf_isom_set_storage_mode( p_mp4->p_file, GF_ISOM_STORE_FLAT ); gf_isom_close( p_mp4->p_file ); } free( p_mp4 ); return 0; }
int dc_gpac_audio_moov_create(AudioOutputFile *audio_output_file, char *filename) { GF_Err ret; u32 di, track; u8 bpsample; GF_ESD *esd; #ifndef GPAC_DISABLE_AV_PARSERS GF_M4ADecSpecInfo acfg; #endif AVCodecContext *audio_codec_ctx = audio_output_file->codec_ctx; audio_output_file->isof = gf_isom_open(filename, GF_ISOM_OPEN_WRITE, NULL); if (!audio_output_file->isof) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open iso file %s\n", filename)); return -1; } esd = gf_odf_desc_esd_new(2); if (!esd) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot create GF_ESD\n")); return -1; } esd->decoderConfig = (GF_DecoderConfig *) gf_odf_desc_new(GF_ODF_DCD_TAG); esd->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG); esd->decoderConfig->streamType = GF_STREAM_AUDIO; if (!strcmp(audio_output_file->codec_ctx->codec->name, "aac")) { //TODO: find an automatic table esd->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_AAC_MPEG4; esd->decoderConfig->bufferSizeDB = 20; esd->slConfig->timestampResolution = audio_codec_ctx->sample_rate; esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG); esd->ESID = 1; #ifndef GPAC_DISABLE_AV_PARSERS memset(&acfg, 0, sizeof(GF_M4ADecSpecInfo)); acfg.base_object_type = GF_M4A_AAC_LC; acfg.base_sr = audio_codec_ctx->sample_rate; acfg.nb_chan = audio_codec_ctx->channels; acfg.sbr_object_type = 0; acfg.audioPL = gf_m4a_get_profile(&acfg); ret = gf_m4a_write_config(&acfg, &esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength); assert(ret == GF_OK); #endif } else { if (strcmp(audio_output_file->codec_ctx->codec->name, "mp2")) { GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("Unlisted codec, setting GPAC_OTI_AUDIO_MPEG1 descriptor.\n")); } esd->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_MPEG1; esd->decoderConfig->bufferSizeDB = 20; esd->slConfig->timestampResolution = audio_codec_ctx->sample_rate; esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG); esd->ESID = 1; #ifndef GPAC_DISABLE_AV_PARSERS memset(&acfg, 0, sizeof(GF_M4ADecSpecInfo)); acfg.base_object_type = GF_M4A_LAYER2; acfg.base_sr = audio_codec_ctx->sample_rate; acfg.nb_chan = audio_codec_ctx->channels; acfg.sbr_object_type = 0; acfg.audioPL = gf_m4a_get_profile(&acfg); ret = gf_m4a_write_config(&acfg, &esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength); assert(ret == GF_OK); #endif } //gf_isom_store_movie_config(video_output_file->isof, 0); track = gf_isom_new_track(audio_output_file->isof, esd->ESID, GF_ISOM_MEDIA_AUDIO, audio_codec_ctx->sample_rate); GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("TimeScale: %d \n", audio_codec_ctx->time_base.den)); if (!track) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot create new track\n")); return -1; } ret = gf_isom_set_track_enabled(audio_output_file->isof, track, 1); if (ret != GF_OK) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_set_track_enabled\n", gf_error_to_string(ret))); return -1; } // if (!esd->ESID) esd->ESID = gf_isom_get_track_id(audio_output_file->isof, track); ret = gf_isom_new_mpeg4_description(audio_output_file->isof, track, esd, NULL, NULL, &di); if (ret != GF_OK) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_new_mpeg4_description\n", gf_error_to_string(ret))); return -1; } gf_odf_desc_del((GF_Descriptor *) esd); esd = NULL; bpsample = av_get_bytes_per_sample(audio_output_file->codec_ctx->sample_fmt) * 8; ret = gf_isom_set_audio_info(audio_output_file->isof, track, di, audio_codec_ctx->sample_rate, audio_output_file->codec_ctx->channels, bpsample); if (ret != GF_OK) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_set_audio_info\n", gf_error_to_string(ret))); return -1; } #ifndef GPAC_DISABLE_AV_PARSERS ret = gf_isom_set_pl_indication(audio_output_file->isof, GF_ISOM_PL_AUDIO, acfg.audioPL); if (ret != GF_OK) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_set_pl_indication\n", gf_error_to_string(ret))); return -1; } #endif GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("time scale: %d sample dur: %d \n", audio_codec_ctx->time_base.den, audio_output_file->codec_ctx->frame_size)); ret = gf_isom_setup_track_fragment(audio_output_file->isof, track, 1, audio_output_file->codec_ctx->frame_size, 0, 0, 0, 0); if (ret != GF_OK) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_setup_track_fragment\n", gf_error_to_string(ret))); return -1; } //gf_isom_add_track_to_root_od(video_output_file->isof,1); ret = gf_isom_finalize_for_fragment(audio_output_file->isof, 1); if (ret != GF_OK) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_finalize_for_fragment\n", gf_error_to_string(ret))); return -1; } ret = gf_media_get_rfc_6381_codec_name(audio_output_file->isof, track, audio_output_file->audio_data_conf->codec6381, GF_FALSE, GF_FALSE); if (ret != GF_OK) return -1; return 0; }
int dc_gpac_audio_moov_create(AudioOutputFile * p_aoutf, char * psz_name) { GF_Err ret; AVCodecContext * p_audio_codec_ctx = p_aoutf->p_codec_ctx; u32 di; u32 track; GF_M4ADecSpecInfo acfg; p_aoutf->p_isof = gf_isom_open(psz_name, GF_ISOM_OPEN_WRITE, NULL); if (!p_aoutf->p_isof) { fprintf(stderr, "Cannot open iso file %s\n", psz_name); return -1; } memset(&acfg, 0, sizeof(GF_M4ADecSpecInfo)); acfg.base_object_type = GF_M4A_AAC_LC; acfg.base_sr = p_audio_codec_ctx->sample_rate; acfg.nb_chan = p_audio_codec_ctx->channels; acfg.sbr_object_type = 0; acfg.audioPL = gf_m4a_get_profile(&acfg); GF_ESD * p_esd = gf_odf_desc_esd_new(2); if (!p_esd) { fprintf(stderr, "Cannot create GF_ESD\n"); return -1; } p_esd->decoderConfig = (GF_DecoderConfig *) gf_odf_desc_new(GF_ODF_DCD_TAG); p_esd->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG); p_esd->decoderConfig->streamType = GF_STREAM_AUDIO; p_esd->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_AAC_MPEG4; p_esd->decoderConfig->bufferSizeDB = 20; p_esd->slConfig->timestampResolution = p_audio_codec_ctx->sample_rate; p_esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG); p_esd->ESID = 1; ret = gf_m4a_write_config(&acfg, &p_esd->decoderConfig->decoderSpecificInfo->data, &p_esd->decoderConfig->decoderSpecificInfo->dataLength); //gf_isom_store_movie_config(p_voutf->p_isof, 0); track = gf_isom_new_track(p_aoutf->p_isof, p_esd->ESID, GF_ISOM_MEDIA_AUDIO, p_audio_codec_ctx->sample_rate); //printf("TimeScale: %d \n", p_video_codec_ctx->time_base.den); if (!track) { fprintf(stderr, "Cannot create new track\n"); return -1; } ret = gf_isom_set_track_enabled(p_aoutf->p_isof, track, 1); if (ret != GF_OK) { fprintf(stderr, "%s: gf_isom_set_track_enabled\n", gf_error_to_string(ret)); return -1; } // if (!p_esd->ESID) p_esd->ESID = gf_isom_get_track_id(p_aoutf->p_isof, track); ret = gf_isom_new_mpeg4_description(p_aoutf->p_isof, track, p_esd, NULL, NULL, &di); if (ret != GF_OK) { fprintf(stderr, "%s: gf_isom_new_mpeg4_description\n", gf_error_to_string(ret)); return -1; } gf_odf_desc_del((GF_Descriptor *) p_esd); p_esd = NULL; u8 bpsample = av_get_bytes_per_sample(p_aoutf->p_codec_ctx->sample_fmt) * 8; ret = gf_isom_set_audio_info(p_aoutf->p_isof, track, di, p_audio_codec_ctx->sample_rate, p_aoutf->p_codec_ctx->channels, bpsample); if (ret != GF_OK) { fprintf(stderr, "%s: gf_isom_set_audio_info\n", gf_error_to_string(ret)); return -1; } ret = gf_isom_set_pl_indication(p_aoutf->p_isof, GF_ISOM_PL_AUDIO, acfg.audioPL); if (ret != GF_OK) { fprintf(stderr, "%s: gf_isom_set_pl_indication\n", gf_error_to_string(ret)); return -1; } //printf("time scale: %d sample dur: %d \n", // p_video_codec_ctx->time_base.den, p_aoutf->p_codec_ctx->frame_size); ret = gf_isom_setup_track_fragment(p_aoutf->p_isof, track, 1, p_aoutf->p_codec_ctx->frame_size, 0, 0, 0, 0); if (ret != GF_OK) { fprintf(stderr, "%s: gf_isom_setup_track_fragment\n", gf_error_to_string(ret)); return -1; } //gf_isom_add_track_to_root_od(p_voutf->p_isof,1); ret = gf_isom_finalize_for_fragment(p_aoutf->p_isof, 1); if (ret != GF_OK) { fprintf(stderr, "%s: gf_isom_finalize_for_fragment\n", gf_error_to_string(ret)); return -1; } return 0; }