1 /*
2  *			GPAC - Multimedia Framework C SDK
3  *
4  *			Authors: Arash Shafiei
5  *			Copyright (c) Telecom ParisTech 2000-2013
6  *					All rights reserved
7  *
8  *  This file is part of GPAC / dashcast
9  *
10  *  GPAC is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU Lesser General Public License as published by
12  *  the Free Software Foundation; either version 2, or (at your option)
13  *  any later version.
14  *
15  *  GPAC is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU Lesser General Public License for more details.
19  *
20  *  You should have received a copy of the GNU Lesser General Public
21  *  License along with this library; see the file COPYING.  If not, write to
22  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  */
25 
26 #include "audio_muxer.h"
27 #include "libavformat/avio.h"
28 
29 #ifndef GPAC_DISABLE_ISOM
30 
dc_gpac_audio_moov_create(AudioOutputFile * audio_output_file,char * filename)31 int dc_gpac_audio_moov_create(AudioOutputFile *audio_output_file, char *filename)
32 {
33 	GF_Err ret;
34 	u32 di, track;
35 	u8 bpsample;
36 	GF_ESD *esd;
37 #ifndef GPAC_DISABLE_AV_PARSERS
38 	GF_M4ADecSpecInfo acfg;
39 #endif
40 	AVCodecContext *audio_codec_ctx = audio_output_file->codec_ctx;
41 
42 	audio_output_file->isof = gf_isom_open(filename, GF_ISOM_OPEN_WRITE, NULL);
43 	if (!audio_output_file->isof) {
44 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open iso file %s\n", filename));
45 		return -1;
46 	}
47 
48 	esd = gf_odf_desc_esd_new(2);
49 	if (!esd) {
50 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot create GF_ESD\n"));
51 		return -1;
52 	}
53 
54 	esd->decoderConfig = (GF_DecoderConfig *) gf_odf_desc_new(GF_ODF_DCD_TAG);
55 	esd->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG);
56 	esd->decoderConfig->streamType = GF_STREAM_AUDIO;
57 	if (!strcmp(audio_output_file->codec_ctx->codec->name, "aac")) { //TODO: find an automatic table
58 		esd->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_AAC_MPEG4;
59 		esd->decoderConfig->bufferSizeDB = 20;
60 		esd->slConfig->timestampResolution = audio_codec_ctx->sample_rate;
61 		esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG);
62 		esd->ESID = 1;
63 
64 #ifndef GPAC_DISABLE_AV_PARSERS
65 		memset(&acfg, 0, sizeof(GF_M4ADecSpecInfo));
66 		acfg.base_object_type = GF_M4A_AAC_LC;
67 		acfg.base_sr = audio_codec_ctx->sample_rate;
68 		acfg.nb_chan = audio_codec_ctx->channels;
69 		acfg.sbr_object_type = 0;
70 		acfg.audioPL = gf_m4a_get_profile(&acfg);
71 
72 		ret = gf_m4a_write_config(&acfg, &esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength);
73 		assert(ret == GF_OK);
74 #endif
75 	} else {
76 		if (strcmp(audio_output_file->codec_ctx->codec->name, "mp2")) {
77 			GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("Unlisted codec, setting GPAC_OTI_AUDIO_MPEG1 descriptor.\n"));
78 		}
79 		esd->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_MPEG1;
80 		esd->decoderConfig->bufferSizeDB = 20;
81 		esd->slConfig->timestampResolution = audio_codec_ctx->sample_rate;
82 		esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG);
83 		esd->ESID = 1;
84 
85 #ifndef GPAC_DISABLE_AV_PARSERS
86 		memset(&acfg, 0, sizeof(GF_M4ADecSpecInfo));
87 		acfg.base_object_type = GF_M4A_LAYER2;
88 		acfg.base_sr = audio_codec_ctx->sample_rate;
89 		acfg.nb_chan = audio_codec_ctx->channels;
90 		acfg.sbr_object_type = 0;
91 		acfg.audioPL = gf_m4a_get_profile(&acfg);
92 
93 		ret = gf_m4a_write_config(&acfg, &esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength);
94 		assert(ret == GF_OK);
95 #endif
96 	}
97 
98 	//gf_isom_store_movie_config(video_output_file->isof, 0);
99 	track = gf_isom_new_track(audio_output_file->isof, esd->ESID, GF_ISOM_MEDIA_AUDIO, audio_codec_ctx->sample_rate);
100 	GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("TimeScale: %d \n", audio_codec_ctx->time_base.den));
101 	if (!track) {
102 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot create new track\n"));
103 		return -1;
104 	}
105 
106 	ret = gf_isom_set_track_enabled(audio_output_file->isof, track, 1);
107 	if (ret != GF_OK) {
108 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_set_track_enabled\n", gf_error_to_string(ret)));
109 		return -1;
110 	}
111 
112 //	if (!esd->ESID) esd->ESID = gf_isom_get_track_id(audio_output_file->isof, track);
113 
114 	ret = gf_isom_new_mpeg4_description(audio_output_file->isof, track, esd, NULL, NULL, &di);
115 	if (ret != GF_OK) {
116 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_new_mpeg4_description\n", gf_error_to_string(ret)));
117 		return -1;
118 	}
119 
120 	gf_odf_desc_del((GF_Descriptor *) esd);
121 	esd = NULL;
122 
123 	bpsample = av_get_bytes_per_sample(audio_output_file->codec_ctx->sample_fmt) * 8;
124 
125 	ret = gf_isom_set_audio_info(audio_output_file->isof, track, di, audio_codec_ctx->sample_rate, audio_output_file->codec_ctx->channels, bpsample, GF_IMPORT_AUDIO_SAMPLE_ENTRY_v0_BS);
126 	if (ret != GF_OK) {
127 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_set_audio_info\n", gf_error_to_string(ret)));
128 		return -1;
129 	}
130 
131 #ifndef GPAC_DISABLE_AV_PARSERS
132 	ret = gf_isom_set_pl_indication(audio_output_file->isof, GF_ISOM_PL_AUDIO, acfg.audioPL);
133 	if (ret != GF_OK) {
134 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_set_pl_indication\n", gf_error_to_string(ret)));
135 		return -1;
136 	}
137 #endif
138 
139 	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));
140 
141 	ret = gf_isom_setup_track_fragment(audio_output_file->isof, track, 1, audio_output_file->codec_ctx->frame_size, 0, 0, 0, 0, 0);
142 	if (ret != GF_OK) {
143 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_setup_track_fragment\n", gf_error_to_string(ret)));
144 		return -1;
145 	}
146 
147 	//gf_isom_add_track_to_root_od(video_output_file->isof,1);
148 
149 	ret = gf_isom_finalize_for_fragment(audio_output_file->isof, 1);
150 	if (ret != GF_OK) {
151 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_finalize_for_fragment\n", gf_error_to_string(ret)));
152 		return -1;
153 	}
154 
155 	ret = gf_media_get_rfc_6381_codec_name(audio_output_file->isof, track, audio_output_file->audio_data_conf->codec6381, GF_FALSE, GF_FALSE);
156 	if (ret != GF_OK) return -1;
157 	return 0;
158 }
159 
dc_gpac_audio_isom_open_seg(AudioOutputFile * audio_output_file,char * filename)160 int dc_gpac_audio_isom_open_seg(AudioOutputFile *audio_output_file, char *filename)
161 {
162 	GF_Err ret;
163 	ret = gf_isom_start_segment(audio_output_file->isof, filename, GF_TRUE);
164 	if (ret != GF_OK) {
165 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_start_segment\n", gf_error_to_string(ret)));
166 		return -1;
167 	}
168 
169 	GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Audio segment %s started at "LLU"\n", filename, gf_net_get_utc() ));
170 
171 	audio_output_file->dts = 0;
172 
173 	return 0;
174 }
175 
dc_gpac_audio_isom_write(AudioOutputFile * audio_output_file)176 int dc_gpac_audio_isom_write(AudioOutputFile *audio_output_file)
177 {
178 	GF_Err ret;
179 	audio_output_file->sample->data = (char *) audio_output_file->packet.data;
180 	audio_output_file->sample->dataLength = audio_output_file->packet.size;
181 
182 	audio_output_file->sample->DTS = audio_output_file->dts; //audio_output_file->aframe->pts;
183 	audio_output_file->sample->IsRAP = RAP; //audio_output_file->aframe->key_frame;//audio_codec_ctx->coded_frame->key_frame;
184 
185 	ret = gf_isom_fragment_add_sample(audio_output_file->isof, 1, audio_output_file->sample, 1, audio_output_file->codec_ctx->frame_size, 0, 0, 0);
186 	audio_output_file->dts += audio_output_file->codec_ctx->frame_size;
187 	if (ret != GF_OK) {
188 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_fragment_add_sample\n", gf_error_to_string(ret)));
189 		return -1;
190 	}
191 	return 0;
192 }
193 
dc_gpac_audio_isom_close_seg(AudioOutputFile * audio_output_file)194 int dc_gpac_audio_isom_close_seg(AudioOutputFile *audio_output_file)
195 {
196 	u64 seg_size;
197 	GF_Err ret;
198 	ret = gf_isom_close_segment(audio_output_file->isof, 0, 0, 0, 0, 0, 0, 0, GF_TRUE, GF_FALSE, audio_output_file->seg_marker, NULL, NULL, &seg_size);
199 	if (ret != GF_OK) {
200 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_close_segment\n", gf_error_to_string(ret)));
201 		return -1;
202 	}
203 	GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Audio segment %s closed at "LLU" - size "LLU" bytes\n", gf_isom_get_segment_name(audio_output_file->isof), gf_net_get_utc(), seg_size ));
204 
205 	//audio_output_file->acc_samples = 0;
206 
207 	return 0;
208 }
209 
dc_gpac_audio_isom_close(AudioOutputFile * audio_output_file)210 int dc_gpac_audio_isom_close(AudioOutputFile *audio_output_file)
211 {
212 	GF_Err ret;
213 	ret = gf_isom_close(audio_output_file->isof);
214 	if (ret != GF_OK) {
215 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("%s: gf_isom_close\n", gf_error_to_string(ret)));
216 		return -1;
217 	}
218 
219 	//audio_output_file->acc_samples = 0;
220 
221 	return 0;
222 }
223 
224 #endif
225 
226 
227 
dc_ffmpeg_audio_muxer_open(AudioOutputFile * audio_output_file,char * filename)228 int dc_ffmpeg_audio_muxer_open(AudioOutputFile *audio_output_file, char *filename)
229 {
230 	AVStream *audio_stream;
231 	AVOutputFormat *output_fmt;
232 	AVDictionary *opts = NULL;
233 
234 	AVCodecContext *audio_codec_ctx = audio_output_file->codec_ctx;
235 	audio_output_file->av_fmt_ctx = NULL;
236 
237 //	strcpy(audio_output_file->filename, audio_data_conf->filename);
238 //	audio_output_file->abr = audio_data_conf->bitrate;
239 //	audio_output_file->asr = audio_data_conf->samplerate;
240 //	audio_output_file->ach = audio_data_conf->channels;
241 //	strcpy(audio_output_file->codec, audio_data_conf->codec);
242 
243 	/* Find output format */
244 	output_fmt = av_guess_format(NULL, filename, NULL);
245 	if (!output_fmt) {
246 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find suitable output format\n"));
247 		return -1;
248 	}
249 
250 	audio_output_file->av_fmt_ctx = avformat_alloc_context();
251 	if (!audio_output_file->av_fmt_ctx) {
252 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot allocate memory for pOutVideoFormatCtx\n"));
253 		return -1;
254 	}
255 
256 	audio_output_file->av_fmt_ctx->oformat = output_fmt;
257 	strcpy(audio_output_file->av_fmt_ctx->filename, filename);
258 
259 	/* Open the output file */
260 	if (!(output_fmt->flags & AVFMT_NOFILE)) {
261 		if (avio_open(&audio_output_file->av_fmt_ctx->pb, filename, URL_WRONLY) < 0) {
262 			GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot not open '%s'\n", filename));
263 			return -1;
264 		}
265 	}
266 
267 	audio_stream = avformat_new_stream(audio_output_file->av_fmt_ctx, audio_output_file->codec);
268 	if (!audio_stream) {
269 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot create output video stream\n"));
270 		return -1;
271 	}
272 
273 	audio_stream->codec->codec_id = audio_output_file->codec->id;
274 	audio_stream->codec->codec_type = AVMEDIA_TYPE_AUDIO;
275 	audio_stream->codec->bit_rate = audio_codec_ctx->bit_rate;//audio_output_file->audio_data_conf->bitrate;
276 	audio_stream->codec->sample_rate = audio_codec_ctx->sample_rate;//audio_output_file->audio_data_conf->samplerate;
277 	audio_stream->codec->channels = audio_codec_ctx->channels;//audio_output_file->audio_data_conf->channels;
278 	assert(audio_codec_ctx->codec->sample_fmts);
279 	audio_stream->codec->sample_fmt = audio_codec_ctx->codec->sample_fmts[0];
280 
281 //	if (audio_output_file->av_fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
282 //		audio_output_file->codec_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
283 
284 	//video_stream->codec = video_output_file->codec_ctx;
285 
286 	/* open the video codec */
287 	av_dict_set(&opts, "strict", "experimental", 0);
288 	if (avcodec_open2(audio_stream->codec, audio_output_file->codec, &opts) < 0) {
289 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output video codec\n"));
290 		av_dict_free(&opts);
291 		return -1;
292 	}
293 	av_dict_free(&opts);
294 
295 	return avformat_write_header(audio_output_file->av_fmt_ctx, NULL);
296 
297 }
298 
dc_ffmpeg_audio_muxer_write(AudioOutputFile * audio_output_file)299 int dc_ffmpeg_audio_muxer_write(AudioOutputFile *audio_output_file)
300 {
301 	AVStream *audio_stream = audio_output_file->av_fmt_ctx->streams[audio_output_file->astream_idx];
302 	AVCodecContext *audio_codec_ctx = audio_stream->codec;
303 
304 	audio_output_file->packet.stream_index = audio_stream->index;
305 
306 	if (audio_output_file->packet.pts != AV_NOPTS_VALUE)
307 		audio_output_file->packet.pts = av_rescale_q(audio_output_file->packet.pts, audio_codec_ctx->time_base, audio_stream->time_base);
308 
309 	if (audio_output_file->packet.duration > 0)
310 		audio_output_file->packet.duration = (int)av_rescale_q(audio_output_file->packet.duration, audio_codec_ctx->time_base, audio_stream->time_base);
311 	/*
312 	 * if (pkt.pts != AV_NOPTS_VALUE)
313 	 * pkt.pts = av_rescale_q(pkt.pts, audioEncCtx->time_base, audioStream->time_base);
314 	 */
315 
316 	audio_output_file->packet.flags |= AV_PKT_FLAG_KEY;
317 
318 	if (av_interleaved_write_frame(audio_output_file->av_fmt_ctx, &audio_output_file->packet) != 0) {
319 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Writing frame is not successful\n"));
320 		av_free_packet(&audio_output_file->packet);
321 		return -1;
322 	}
323 
324 	av_free_packet(&audio_output_file->packet);
325 
326 	return 0;
327 }
328 
dc_ffmpeg_audio_muxer_close(AudioOutputFile * audio_output_file)329 int dc_ffmpeg_audio_muxer_close(AudioOutputFile *audio_output_file)
330 {
331 	u32 i;
332 
333 	av_write_trailer(audio_output_file->av_fmt_ctx);
334 	avio_close(audio_output_file->av_fmt_ctx->pb);
335 
336 	// free the streams
337 	for (i = 0; i < audio_output_file->av_fmt_ctx->nb_streams; i++) {
338 		avcodec_close(audio_output_file->av_fmt_ctx->streams[i]->codec);
339 		av_freep(&audio_output_file->av_fmt_ctx->streams[i]->info);
340 	}
341 
342 	//video_output_file->av_fmt_ctx->streams[video_output_file->vstream_idx]->codec = NULL;
343 	avformat_free_context(audio_output_file->av_fmt_ctx);
344 
345 	//audio_output_file->acc_samples = 0;
346 
347 	return 0;
348 
349 }
350 
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)351 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)
352 {
353 	char name[GF_MAX_PATH];
354 	snprintf(name, sizeof(name), "audio encoder %s", audio_data_conf->filename);
355 	dc_consumer_init(&audio_output_file->consumer, AUDIO_CB_SIZE, name);
356 
357 #ifndef GPAC_DISABLE_ISOM
358 	audio_output_file->sample = gf_isom_sample_new();
359 	audio_output_file->isof = NULL;
360 #endif
361 
362 	audio_output_file->muxer_type = muxer_type;
363 	audio_output_file->frame_per_seg = frame_per_seg;
364 	audio_output_file->frame_per_frag = frame_per_frag;
365 	audio_output_file->seg_marker = seg_marker;
366 	return 0;
367 }
368 
dc_audio_muxer_free(AudioOutputFile * audio_output_file)369 void dc_audio_muxer_free(AudioOutputFile *audio_output_file)
370 {
371 #ifndef GPAC_DISABLE_ISOM
372 	if (audio_output_file->isof != NULL) {
373 		gf_isom_close(audio_output_file->isof);
374 	}
375 	//gf_isom_sample_del(&audio_output_file->sample);
376 #endif
377 }
378 
dc_audio_muxer_open(AudioOutputFile * audio_output_file,char * directory,char * id_name,int seg)379 GF_Err dc_audio_muxer_open(AudioOutputFile *audio_output_file, char *directory, char *id_name, int seg)
380 {
381 	GF_Err ret = GF_NOT_SUPPORTED;
382 	char name[GF_MAX_PATH];
383 
384 	switch (audio_output_file->muxer_type) {
385 	case FFMPEG_AUDIO_MUXER:
386 		snprintf(name, sizeof(name), "%s/%s_%d_ffmpeg.mp4", directory, id_name, seg);
387 		return dc_ffmpeg_audio_muxer_open(audio_output_file, name);
388 #ifndef GPAC_DISABLE_ISOM
389 	case GPAC_AUDIO_MUXER:
390 		snprintf(name, sizeof(name), "%s/%s_%d_gpac.mp4", directory, id_name, seg);
391 		dc_gpac_audio_moov_create(audio_output_file, name);
392 		return dc_gpac_audio_isom_open_seg(audio_output_file, NULL);
393 	case GPAC_INIT_AUDIO_MUXER:
394 		if (seg == 1) {
395 			snprintf(name, sizeof(name), "%s/%s_init_gpac.mp4", directory, id_name);
396 			dc_gpac_audio_moov_create(audio_output_file, name);
397 			audio_output_file->first_dts = 0;
398 		}
399 		snprintf(name, sizeof(name), "%s/%s_%d_gpac.m4s", directory, id_name, seg);
400 		ret = dc_gpac_audio_isom_open_seg(audio_output_file, name);
401 		return ret;
402 #endif
403 	default:
404 		ret = GF_BAD_PARAM;
405 		break;
406 	}
407 
408 	return ret;
409 }
410 
dc_audio_muxer_write(AudioOutputFile * audio_output_file,int frame_nb,Bool insert_ntp)411 int dc_audio_muxer_write(AudioOutputFile *audio_output_file, int frame_nb, Bool insert_ntp)
412 {
413 	switch (audio_output_file->muxer_type) {
414 	case FFMPEG_AUDIO_MUXER:
415 		return dc_ffmpeg_audio_muxer_write(audio_output_file);
416 #ifndef GPAC_DISABLE_ISOM
417 	case GPAC_AUDIO_MUXER:
418 	case GPAC_INIT_AUDIO_MUXER:
419 		if (frame_nb % audio_output_file->frame_per_frag == 0) {
420 			gf_isom_start_fragment(audio_output_file->isof, 1);
421 
422 			if (insert_ntp) {
423 				gf_isom_set_fragment_reference_time(audio_output_file->isof, 1, audio_output_file->frame_ntp, audio_output_file->first_dts * audio_output_file->codec_ctx->frame_size);
424 			}
425 
426 			gf_isom_set_traf_base_media_decode_time(audio_output_file->isof, 1, audio_output_file->first_dts * audio_output_file->codec_ctx->frame_size);
427 			audio_output_file->first_dts += audio_output_file->frame_per_frag;
428 			GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Audio start fragment first DTS %u at "LLU"\n", audio_output_file->first_dts, gf_net_get_utc() ));
429 		}
430 		dc_gpac_audio_isom_write(audio_output_file);
431 		if (frame_nb % audio_output_file->frame_per_frag == audio_output_file->frame_per_frag - 1) {
432 			gf_isom_flush_fragments(audio_output_file->isof, 1);
433 			GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Audio flush fragment first DTS %u at "LLU"\n", audio_output_file->first_dts, gf_net_get_utc() ));
434 		}
435 		//TODO - do same as video, flush based on time in case of losses
436 		if (frame_nb + 1 == audio_output_file->frame_per_seg) {
437 			return 1;
438 		}
439 
440 		return 0;
441 #endif
442 
443 	default:
444 		return GF_BAD_PARAM;
445 	}
446 	return GF_BAD_PARAM;
447 }
448 
dc_audio_muxer_close(AudioOutputFile * audio_output_file)449 int dc_audio_muxer_close(AudioOutputFile *audio_output_file)
450 {
451 	switch (audio_output_file->muxer_type) {
452 	case FFMPEG_AUDIO_MUXER:
453 		return dc_ffmpeg_audio_muxer_close(audio_output_file);
454 #ifndef GPAC_DISABLE_ISOM
455 	case GPAC_AUDIO_MUXER:
456 		dc_gpac_audio_isom_close_seg(audio_output_file);
457 		return dc_gpac_audio_isom_close(audio_output_file);
458 	case GPAC_INIT_AUDIO_MUXER:
459 		return dc_gpac_audio_isom_close_seg(audio_output_file);
460 #endif
461 	default:
462 		return GF_BAD_PARAM;
463 	}
464 
465 	return GF_BAD_PARAM;
466 }
467