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 "controler.h"
27 
28 
29 #if (!defined(__DARWIN__) && !defined(__APPLE__))
30 # include <malloc.h>
31 #endif
32 
33 #include <time.h>
34 
35 #if defined(__GNUC__)
36 # include <unistd.h>
37 # include <sys/time.h>
38 #elif defined(WIN32)
39 # include <Winsock.h>
40 # include <sys/timeb.h>
41 # define suseconds_t long
42 #else
43 # error
44 #endif
45 
46 #include <gpac/network.h>
47 
48 typedef struct {
49 	int segnum;
50 	u64 utc_time, ntpts;
51 } segtime;
52 
53 
54 //#define MAX_SOURCE_NUMBER 20
55 #define FRAGMENTER 0
56 //#define DEBUG 1
57 
58 //#define VIDEO_MUXER FFMPEG_VIDEO_MUXER
59 //#define VIDEO_MUXER RAW_VIDEO_H264
60 //#define VIDEO_MUXER GPAC_VIDEO_MUXER
61 #define VIDEO_MUXER GPAC_INIT_VIDEO_MUXER_AVC1
62 //#define VIDEO_MUXER GPAC_INIT_VIDEO_MUXER_AVC3
63 
64 //#define AUDIO_MUXER FFMPEG_AUDIO_MUXER
65 //#define AUDIO_MUXER GPAC_AUDIO_MUXER
66 #define AUDIO_MUXER GPAC_INIT_AUDIO_MUXER
67 
68 #define AUDIO_FRAME_SIZE 1024
69 
70 
optimize_seg_frag_dur(int * seg,int * frag)71 void optimize_seg_frag_dur(int *seg, int *frag)
72 {
73 	int min_rem;
74 	int seg_nb = *seg;
75 	int frag_nb = *frag;
76 	if (!frag_nb) frag_nb = 1;
77 
78 	min_rem = seg_nb % frag_nb;
79 
80 	if (seg_nb % (frag_nb + 1) < min_rem) {
81 		min_rem = seg_nb % (frag_nb + 1);
82 		*seg = seg_nb;
83 		*frag = frag_nb + 1;
84 	}
85 
86 	if ((seg_nb + 1) % frag_nb < min_rem) {
87 		min_rem = (seg_nb + 1) % frag_nb;
88 		*seg = seg_nb + 1;
89 		*frag = frag_nb;
90 	}
91 
92 	if ((seg_nb + 1) % (frag_nb + 1) < min_rem) {
93 		min_rem = (seg_nb + 1) % (frag_nb + 1);
94 		*seg = seg_nb + 1;
95 		*frag = frag_nb + 1;
96 	}
97 
98 	*seg -= min_rem;
99 }
100 
change_source_thread(void * params)101 Bool change_source_thread(void *params)
102 {
103 	Bool ret = GF_FALSE;
104 	return ret;
105 }
106 
send_frag_event(void * params)107 u32 send_frag_event(void *params)
108 {
109 	int ret;
110 	//int status;
111 	char buff[GF_MAX_PATH];
112 	ThreadParam *th_param = (ThreadParam*)params;
113 	CmdData *cmd_data = th_param->in_data;
114 	MessageQueue *mq = th_param->mq;
115 
116 	while (1) {
117 		if (cmd_data->exit_signal) {
118 			break;
119 		}
120 
121 		ret = dc_message_queue_get(mq, (void*) buff);
122 		if (ret > 0) {
123 			fprintf(stdout, "Message received: %s\n", buff);
124 		}
125 	}
126 
127 	return 0;
128 }
129 
dc_write_mpd(CmdData * cmddata,const AudioDataConf * audio_data_conf,const VideoDataConf * video_data_conf,const char * presentation_duration,const char * availability_start_time,const char * time_shift,const int segnum,const int ast_offset)130 static void dc_write_mpd(CmdData *cmddata, const AudioDataConf *audio_data_conf, const VideoDataConf *video_data_conf, const char *presentation_duration, const char *availability_start_time, const char *time_shift, const int segnum, const int ast_offset)
131 {
132 	u32 i = 0, sec;
133 	int audio_seg_dur = 0, video_seg_dur = 0, audio_frag_dur = 0,	video_frag_dur = 0;
134 	int audio_frame_size = AUDIO_FRAME_SIZE;
135 	time_t gtime;
136 	struct tm *t;
137 	FILE *f;
138 
139 	char name[GF_MAX_PATH];
140 
141 	snprintf(name, sizeof(name), "%s/%s", cmddata->out_dir, cmddata->mpd_filename);
142 
143 	GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Write MPD at UTC "LLU" ms - %s : %s\n", gf_net_get_utc(), (cmddata->mode == ON_DEMAND) ? "mediaPresentationDuration" : "availabilityStartTime", (cmddata->mode == ON_DEMAND) ? presentation_duration : availability_start_time));
144 
145 	if (strcmp(cmddata->audio_data_conf.filename, "") != 0) {
146 		audio_data_conf = (const AudioDataConf*)gf_list_get(cmddata->audio_lst, 0);
147 		if (audio_data_conf) {
148 			audio_seg_dur = (int)((audio_data_conf->samplerate / (double) audio_frame_size) * (cmddata->seg_dur / 1000.0));
149 			audio_frag_dur = (int)((audio_data_conf->samplerate / (double) audio_frame_size) * (cmddata->frag_dur / 1000.0));
150 			optimize_seg_frag_dur(&audio_seg_dur, &audio_frag_dur);
151 		}
152 	}
153 
154 	if (strcmp(cmddata->video_data_conf.filename, "") != 0) {
155 		video_data_conf = (VideoDataConf*)gf_list_get(cmddata->video_lst, 0);
156 		if (video_data_conf) {
157 			video_seg_dur = (int)(video_data_conf->framerate * (cmddata->seg_dur / 1000.0));
158 			video_frag_dur = (int)(video_data_conf->framerate * (cmddata->frag_dur / 1000.0));
159 			optimize_seg_frag_dur(&video_seg_dur, &video_frag_dur);
160 		}
161 	}
162 
163 	f = gf_fopen(name, "w");
164 	//TODO: if (!f) ...
165 
166 	//	time_t t = time(NULL);
167 	//	time_t t2 = t + 2;
168 	//	t += (2 * (cmddata->seg_dur / 1000.0));
169 	//	tm = *gmtime(&t2);
170 	//	snprintf(availability_start_time, "%d-%d-%dT%d:%d:%dZ", tm.tm_year + 1900,
171 	//			tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
172 	//	fprintf(stdout, "%s \n", availability_start_time);
173 
174 	fprintf(f, "<?xml version=\"1.0\"?>\n");
175 	fprintf(f, "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\" profiles=\"urn:mpeg:dash:profile:full:2011\" minBufferTime=\"PT%fS\"", cmddata->min_buffer_time);
176 
177 	if (cmddata->mode == ON_DEMAND) {
178 		fprintf(f, " type=\"static\" mediaPresentationDuration=\"%s\"", presentation_duration);
179 	} else {
180 		fprintf(f, " type=\"dynamic\" availabilityStartTime=\"%s\"", availability_start_time);
181 		if (time_shift) fprintf(f, " timeShiftBufferDepth=\"%s\"", time_shift);
182 
183 		if (cmddata->minimum_update_period > 0)
184 			fprintf(f, " minimumUpdatePeriod=\"PT%dS\"", cmddata->minimum_update_period);
185 
186 		gf_net_get_ntp(&sec, NULL);
187 		gtime = sec - GF_NTP_SEC_1900_TO_1970;
188 		t = gmtime(&gtime);
189 		fprintf(f, " publishTime=\"%d-%02d-%02dT%02d:%02d:%02dZ\"", 1900+t->tm_year, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
190 
191 	}
192 
193 	fprintf(f, ">\n");
194 
195 	fprintf(f,
196 	        " <ProgramInformation moreInformationURL=\"http://gpac.io\">\n"
197 	        "  <Title>%s</Title>\n"
198 	        " </ProgramInformation>\n", cmddata->mpd_filename);
199 
200 	if (strcmp(cmddata->base_url, "") != 0) {
201 		fprintf(f, " <BaseURL>%s</BaseURL>\n", cmddata->base_url);
202 	}
203 
204 	fprintf(f, " <Period start=\"PT0H0M0.000S\" id=\"P1\">\n");
205 
206 	if (strcmp(cmddata->audio_data_conf.filename, "") != 0) {
207 		fprintf(f, "  <AdaptationSet segmentAlignment=\"true\" bitstreamSwitching=\"false\">\n");
208 
209 		fprintf(f,
210 		        "   <AudioChannelConfiguration schemeIdUri=\"urn:mpeg:dash:23003:3:audio_channel_configuration:2011\" "
211 		        "value=\"2\"/>\n");
212 
213 		fprintf(f,
214 		        "   <SegmentTemplate timescale=\"%d\" duration=\"%d\" media=\"$RepresentationID$_$Number$_gpac.m4s\""
215 		        " startNumber=\"%d\" initialization=\"$RepresentationID$_init_gpac.mp4\"",
216 		        audio_data_conf->samplerate, audio_seg_dur * audio_frame_size, segnum);
217 
218 		if (ast_offset<0) {
219 			fprintf(f, " availabilityTimeOffset=\"%g\"", -ast_offset/1000.0);
220 		}
221 		fprintf(f, "/>\n");
222 
223 
224 
225 		for (i = 0; i < gf_list_count(cmddata->audio_lst); i++) {
226 			audio_data_conf = (const AudioDataConf*)gf_list_get(cmddata->audio_lst, i);
227 			fprintf(f,
228 			        "   <Representation id=\"%s\" mimeType=\"audio/mp4\" codecs=\"%s\" "
229 			        "audioSamplingRate=\"%d\" startWithSAP=\"1\" bandwidth=\"%d\">\n"
230 			        "   </Representation>\n", audio_data_conf->filename, audio_data_conf->codec6381, audio_data_conf->samplerate, audio_data_conf->bitrate);
231 		}
232 
233 		fprintf(f, "  </AdaptationSet>\n");
234 	}
235 
236 	if (strcmp(cmddata->video_data_conf.filename, "") != 0) {
237 		fprintf(f, "  <AdaptationSet segmentAlignment=\"true\" bitstreamSwitching=\"false\">\n");
238 
239 		fprintf(f,
240 		        "   <SegmentTemplate timescale=\"%d\" duration=\"%d\" media=\"$RepresentationID$_$Number$_gpac.m4s\""
241 		        " startNumber=\"%d\" initialization=\"$RepresentationID$_init_gpac.mp4\"",
242 		        video_data_conf->framerate, video_seg_dur, segnum);
243 
244 
245 		if (ast_offset<0) {
246 			fprintf(f, " availabilityTimeOffset=\"%g\"", -ast_offset/1000.0);
247 		}
248 		fprintf(f, "/>\n");
249 
250 		for (i = 0; i < gf_list_count(cmddata->video_lst); i++) {
251 			video_data_conf = (VideoDataConf*)gf_list_get(cmddata->video_lst, i);
252 			fprintf(f, "   <Representation id=\"%s\" mimeType=\"video/mp4\" codecs=\"%s\" "
253 			        "width=\"%d\" height=\"%d\" frameRate=\"%d\" sar=\"1:1\" startWithSAP=\"1\" bandwidth=\"%d\">\n"
254 			        "   </Representation>\n", video_data_conf->filename,
255 			        VIDEO_MUXER == GPAC_INIT_VIDEO_MUXER_AVC1 ? video_data_conf->codec6381 : "avc3",
256 			        video_data_conf->width, video_data_conf->height, video_data_conf->framerate,
257 			        video_data_conf->bitrate);
258 		}
259 
260 		fprintf(f, "  </AdaptationSet>\n");
261 	}
262 
263 	fprintf(f, " </Period>\n");
264 
265 	fprintf(f, "</MPD>\n");
266 
267 	gf_fclose(f);
268 }
269 
mpd_thread(void * params)270 static u32 mpd_thread(void *params)
271 {
272 	ThreadParam *th_param = (ThreadParam*)params;
273 	CmdData *cmddata = th_param->in_data;
274 	MessageQueue *mq = th_param->mq;
275 	char availability_start_time[GF_MAX_PATH];
276 	char presentation_duration[GF_MAX_PATH];
277 	char time_shift[GF_MAX_PATH] = "";
278 	AudioDataConf *audio_data_conf = NULL;
279 	VideoDataConf *video_data_conf = NULL;
280 	struct tm ast_time;
281 	int dur = 0;
282 	int h, m, s, ms;
283 	segtime last_seg_time;
284 	segtime main_seg_time;
285 	Bool first = GF_TRUE;
286 	main_seg_time.segnum = 0;
287 	main_seg_time.utc_time = 0;
288 	main_seg_time.ntpts = 0;
289 	last_seg_time = main_seg_time;
290 
291 	if (cmddata->mode == LIVE_CAMERA || cmddata->mode == LIVE_MEDIA) {
292 		while (1) {
293 			u32 msecs;
294 			time_t t;
295 			segtime seg_time;
296 			seg_time.segnum = 0;
297 			seg_time.utc_time = 0;
298 			seg_time.ntpts = 0;
299 
300 			if (cmddata->exit_signal) {
301 				break;
302 			}
303 
304 			if (strcmp(cmddata->video_data_conf.filename, "") != 0) {
305 				if (dc_message_queue_get(mq, &seg_time) < 0) {
306 					continue;
307 				}
308 			}
309 
310 			if (strcmp(cmddata->audio_data_conf.filename, "") != 0) {
311 				if (dc_message_queue_get(mq, &seg_time) < 0) {
312 					continue;
313 				}
314 			}
315 			assert(seg_time.ntpts);
316 
317 			if (cmddata->use_dynamic_ast) {
318 				main_seg_time = seg_time;
319 			} else {
320 				//get the last notification of AST
321 				if (first) {
322 					main_seg_time = seg_time;
323 					first = GF_FALSE;
324 				}
325 				assert(main_seg_time.ntpts);
326 			}
327 
328 			last_seg_time = seg_time;
329 			assert(main_seg_time.ntpts <= seg_time.ntpts);
330 
331 			t = (seg_time.ntpts >> 32)  - GF_NTP_SEC_1900_TO_1970;
332 			msecs = (u32) ( (seg_time.ntpts & 0xFFFFFFFF) * (1000.0/0xFFFFFFFF) );
333 			ast_time = *gmtime(&t);
334 			fprintf(stdout, "Generating MPD at %d-%02d-%02dT%02d:%02d:%02d.%03dZ\n", 1900 + ast_time.tm_year, ast_time.tm_mon+1, ast_time.tm_mday, ast_time.tm_hour, ast_time.tm_min, ast_time.tm_sec, msecs);
335 			GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Generating MPD at %d-%02d-%02dT%02d:%02d:%02d.%03dZ - UTC "LLU" ms - AST UTC "LLU" ms\n", 1900 + ast_time.tm_year, ast_time.tm_mon+1, ast_time.tm_mday, ast_time.tm_hour, ast_time.tm_min, ast_time.tm_sec, msecs, seg_time.utc_time, main_seg_time.utc_time));
336 
337 			t = (main_seg_time.ntpts >> 32)  - GF_NTP_SEC_1900_TO_1970;
338 			if (cmddata->ast_offset>0) {
339 				t += cmddata->ast_offset/1000;
340 			}
341 			msecs = (u32) ( (main_seg_time.ntpts & 0xFFFFFFFF) * (1000.0/0xFFFFFFFF) );
342 			ast_time = *gmtime(&t);
343 			assert(ast_time.tm_year);
344 
345 			sprintf(availability_start_time, "%d-%02d-%02dT%02d:%02d:%02d.%03dZ", 1900 + ast_time.tm_year, ast_time.tm_mon+1, ast_time.tm_mday, ast_time.tm_hour, ast_time.tm_min, ast_time.tm_sec, msecs);
346 			fprintf(stdout, "StartTime: %s - startNumber %d - last number %d\n", availability_start_time, main_seg_time.segnum+1, seg_time.segnum+1);
347 
348 			if (cmddata->time_shift != -1) {
349 				int ts, h, m, s;
350 				ts = cmddata->time_shift;
351 				h = ts / 3600;
352 				ts = ts % 3600;
353 				m = ts / 60;
354 				s = ts % 60;
355 				snprintf(time_shift, sizeof(time_shift), "PT%02dH%02dM%02dS", h, m, s);
356 			}
357 
358 			dc_write_mpd(cmddata, audio_data_conf, video_data_conf, presentation_duration, availability_start_time, time_shift, main_seg_time.segnum+1, cmddata->ast_offset);
359 		}
360 
361 		if (cmddata->no_mpd_rewrite) return 0;
362 
363 		//finally rewrite the MPD to static
364 		dur = cmddata->seg_dur * (last_seg_time.segnum - main_seg_time.segnum);
365 		if (cmddata->time_shift) {
366 			if (dur > cmddata->time_shift * 1000) {
367 				u32 nb_seg = cmddata->time_shift*1000 / cmddata->seg_dur;
368 				main_seg_time.segnum = last_seg_time.segnum - nb_seg;
369 				//dur = cmddata->time_shift;
370 			}
371 			dur = cmddata->seg_dur * (last_seg_time.segnum - main_seg_time.segnum);
372 		}
373 		cmddata->mode = ON_DEMAND;
374 
375 	} else {
376 		int a_dur = 0;
377 		int v_dur = 0;
378 
379 		if (strcmp(cmddata->audio_data_conf.filename, "") != 0) {
380 			dc_message_queue_get(mq, &a_dur);
381 		}
382 
383 		if (strcmp(cmddata->video_data_conf.filename, "") != 0) {
384 			dc_message_queue_get(mq, &v_dur);
385 		}
386 
387 		dur =  v_dur > a_dur ? v_dur : a_dur;
388 	}
389 
390 
391 	h = dur / 3600000;
392 	dur = dur % 3600000;
393 	m = dur / 60000;
394 	dur = dur % 60000;
395 	s = dur / 1000;
396 	ms = dur % 1000;
397 	snprintf(presentation_duration, sizeof(presentation_duration), "PT%02dH%02dM%02d.%03dS", h, m, s, ms);
398 	fprintf(stdout, "Duration: %s\n", presentation_duration);
399 
400 
401 	dc_write_mpd(cmddata, audio_data_conf, video_data_conf, presentation_duration, availability_start_time, 0, main_seg_time.segnum+1, 0);
402 
403 	return 0;
404 }
405 
delete_seg_thread(void * params)406 u32 delete_seg_thread(void *params)
407 {
408 	int ret;
409 	ThreadParam *th_param = (ThreadParam*)params;
410 	CmdData *cmd_data = th_param->in_data;
411 	MessageQueue *mq = th_param->mq;
412 
413 	char buff[GF_MAX_PATH];
414 
415 	while (1) {
416 		ret = dc_message_queue_get(mq, (void*) buff);
417 		if (ret > 0) {
418 			int status;
419 			status = unlink(buff);
420 			if (status != 0) {
421 				GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("Unable to delete the file %s\n", buff));
422 			}
423 		}
424 
425 		if (cmd_data->exit_signal) {
426 			break;
427 		}
428 	}
429 
430 	return 0;
431 }
432 
fragmenter_thread(void * params)433 Bool fragmenter_thread(void *params)
434 {
435 //	int ret;
436 	ThreadParam *th_param = (ThreadParam*)params;
437 	CmdData *cmd_data = th_param->in_data;
438 	MessageQueue *mq = th_param->mq;
439 
440 	char buff[GF_MAX_PATH];
441 
442 	while (1) {
443 		/*ret = */dc_message_queue_get(mq, (void*) buff);
444 		if (cmd_data->exit_signal) {
445 			break;
446 		}
447 	}
448 
449 	return GF_FALSE;
450 }
451 
keyboard_thread(void * params)452 static u32 keyboard_thread(void *params)
453 {
454 
455 	ThreadParam *th_param = (ThreadParam*)params;
456 	CmdData *in_data = th_param->in_data;
457 	char c;
458 
459 	while (1) {
460 		if (gf_prompt_has_input()) {
461 			c = gf_prompt_get_char();
462 			if (c == 'q' || c == 'Q') {
463 				in_data->exit_signal = 1;
464 				break;
465 			}
466 		}
467 
468 		if (in_data->exit_signal) {
469 			break;
470 		}
471 
472 		gf_sleep(100);
473 	}
474 	GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Keyboard thread exit\n"));
475 	return 0;
476 }
477 
video_decoder_thread(void * params)478 u32 video_decoder_thread(void *params)
479 {
480 #ifdef DASHCAST_PRINT
481 	int i = 0;
482 #endif
483 	int ret;
484 	int source_number = 0;
485 
486 	//int first_time = 1;
487 	struct timeval time_start, time_end, time_wait;
488 	VideoThreadParam *thread_params = (VideoThreadParam *) params;
489 
490 	CmdData *in_data = thread_params->in_data;
491 	VideoInputData *video_input_data = thread_params->video_input_data;
492 	VideoInputFile **video_input_file = thread_params->video_input_file;
493 
494 	suseconds_t total_wait_time = (int) (1000000.0 / (double) in_data->video_data_conf.framerate);
495 	suseconds_t pick_packet_delay, select_delay = 0, real_wait, other_delays = 2;
496 
497 	Task t;
498 	//fprintf(stdout, "wait time : %f\n", total_wait_time);
499 
500 	if (!gf_list_count(in_data->video_lst))
501 		return 0;
502 
503 	while (1) {
504 		dc_task_get_current(&in_data->task_list, &t);
505 		source_number = t.source_number;
506 
507 		//fprintf(stdout, "sourcenumber: %d\n", source_number);
508 
509 //		if (video_input_file[source_number]->mode == LIVE_MEDIA) {
510 			gf_gettimeofday(&time_start, NULL);
511 //		}
512 
513 		ret = dc_video_decoder_read(video_input_file[source_number], video_input_data, source_number, in_data->use_source_timing, (in_data->mode == LIVE_CAMERA) ? 1 : 0, (const int *) &in_data->exit_signal);
514 #ifdef DASHCAST_PRINT
515 		fprintf(stdout, "Read video frame %d\r", i++);
516 		fflush(stdout);
517 #endif
518 		if (ret == -2) {
519 			GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Video reader has no more frame to read.\n"));
520 			break;
521 		}
522 		if (ret == -1) {
523 			GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("An error occurred while reading video frame.\n"));
524 			break;
525 		}
526 
527 		if (in_data->exit_signal) {
528 			dc_video_input_data_end_signal(video_input_data);
529 			break;
530 		}
531 
532 		if (video_input_file[source_number]->mode == LIVE_MEDIA) {
533 			gf_gettimeofday(&time_end, NULL);
534 			pick_packet_delay = ((time_end.tv_sec - time_start.tv_sec) * 1000000) + time_end.tv_usec - time_start.tv_usec;
535 			time_wait.tv_sec = 0;
536 			real_wait = total_wait_time - pick_packet_delay - select_delay - other_delays;
537 			time_wait.tv_usec = real_wait;
538 			GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("delay: %ld = %ld - %ld\n", time_wait.tv_usec, total_wait_time, pick_packet_delay));
539 
540 			gf_gettimeofday(&time_start, NULL);
541 			select(0, NULL, NULL, NULL, &time_wait);
542 			gf_gettimeofday(&time_end, NULL);
543 
544 			select_delay = (((time_end.tv_sec - time_start.tv_sec) * 1000000) + time_end.tv_usec - time_start.tv_usec) - real_wait;
545 		}
546 	}
547 
548 	GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("Video decoder is exiting...\n"));
549 	GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("video decoder thread exit\n"));
550 	return 0;
551 }
552 
audio_decoder_thread(void * params)553 u32 audio_decoder_thread(void *params)
554 {
555 	int ret;
556 	struct timeval time_start, time_end, time_wait;
557 	AudioThreadParam *thread_params = (AudioThreadParam*)params;
558 
559 	CmdData *in_data = thread_params->in_data;
560 	AudioInputData *audio_input_data = thread_params->audio_input_data;
561 	AudioInputFile *audio_input_file = thread_params->audio_input_file;
562 
563 	suseconds_t pick_packet_delay, select_delay = 0, real_wait, other_delays = 1;
564 	suseconds_t total_wait_time;
565 	if (in_data->audio_data_conf.samplerate < 1024) {
566 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error: invalid audio sample rate: %d\n", in_data->audio_data_conf.samplerate));
567 		dc_audio_inout_data_end_signal(audio_input_data);
568 		//FIXME: deadlock on the mpd thread. Reproduce with big_buck_bunny.mp4.
569 		return 1;
570 	}
571 	total_wait_time = (int) (1000000.0 / (in_data->audio_data_conf.samplerate / (double) AUDIO_FRAME_SIZE));
572 	GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("wait time : %ld\n", total_wait_time));
573 	GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("sample-rate : %ld\n", in_data->audio_data_conf.samplerate));
574 
575 	if (!gf_list_count(in_data->audio_lst))
576 		return 0;
577 
578 	while (1) {
579 //		if (audio_input_file->mode == LIVE_MEDIA) {
580 			gf_gettimeofday(&time_start, NULL);
581 //		}
582 
583 		ret = dc_audio_decoder_read(audio_input_file, audio_input_data);
584 		if (ret == -2) {
585 			GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Audio decoder has no more frame to read.\n"));
586 			break;
587 		}
588 		if (ret == -1) {
589 			GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("An error occurred while reading audio frame.\n"));
590 			break;
591 		}
592 
593 		if (in_data->exit_signal) {
594 			dc_audio_inout_data_end_signal(audio_input_data);
595 			break;
596 		}
597 
598 		if (audio_input_file->mode == LIVE_MEDIA) {
599 			gf_gettimeofday(&time_end, NULL);
600 			pick_packet_delay = ((time_end.tv_sec - time_start.tv_sec) * 1000000) + time_end.tv_usec - time_start.tv_usec;
601 			time_wait.tv_sec = 0;
602 			real_wait = total_wait_time - pick_packet_delay - select_delay - other_delays;
603 			time_wait.tv_usec = real_wait;
604 
605 			gf_gettimeofday(&time_start, NULL);
606 			select(0, NULL, NULL, NULL, &time_wait);
607 			gf_gettimeofday(&time_end, NULL);
608 
609 			select_delay = (((time_end.tv_sec - time_start.tv_sec) * 1000000) + time_end.tv_usec - time_start.tv_usec) - real_wait;
610 		}
611 	}
612 
613 	GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Audio decoder is exiting...\n"));
614 	return 0;
615 }
616 
video_scaler_thread(void * params)617 u32 video_scaler_thread(void *params)
618 {
619 	int ret;
620 	VideoThreadParam *thread_params = (VideoThreadParam *) params;
621 	CmdData *in_data = thread_params->in_data;
622 	VideoInputData *video_input_data = thread_params->video_input_data;
623 	VideoScaledData *video_scaled_data = thread_params->video_scaled_data;
624 
625 	if (!gf_list_count(in_data->video_lst))
626 		return 0;
627 
628 	while (1) {
629 		ret = dc_video_scaler_scale(video_input_data, video_scaled_data);
630 		if (ret == -2) {
631 			GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Video scaler has no more frame to read.\n"));
632 			break;
633 		}
634 	}
635 
636 	dc_video_scaler_end_signal(video_scaled_data);
637 
638 	GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("video scaler thread exit\n"));
639 	return 0;
640 }
641 
video_encoder_thread(void * params)642 u32 video_encoder_thread(void *params)
643 {
644 	int ret, shift, frame_nb, seg_frame_max, frag_frame_max, seg_nb = 0, loss_state = 0, quit = 0, real_video_seg_dur;
645 	char name_to_delete[GF_MAX_PATH], name_to_send[GF_MAX_PATH];
646 	u64 start_utc, seg_utc;
647 	segtime time_at_segment_start;
648 	VideoMuxerType muxer_type = VIDEO_MUXER;
649 	VideoThreadParam *thread_params = (VideoThreadParam*)params;
650 	u32 sec, frac;
651 	Bool init_mpd = GF_FALSE;
652 	CmdData *in_data = thread_params->in_data;
653 	int video_conf_idx = thread_params->video_conf_idx;
654 	VideoDataConf *video_data_conf = (VideoDataConf*)gf_list_get(in_data->video_lst, video_conf_idx);
655 
656 	VideoScaledData *video_scaled_data = thread_params->video_scaled_data;
657 	int video_cb_size = (in_data->mode == LIVE_MEDIA || in_data->mode == LIVE_CAMERA) ? 1 : VIDEO_CB_DEFAULT_SIZE;
658 	VideoOutputFile out_file;
659 
660 	MessageQueue *mq = thread_params->mq;
661 	MessageQueue *delete_seg_mq = thread_params->delete_seg_mq;
662 	MessageQueue *send_seg_mq = thread_params->send_seg_mq;
663 
664 	if (!gf_list_count(in_data->video_lst))
665 		return 0;
666 
667 	seg_frame_max = (int)(video_data_conf->framerate * (float) (in_data->seg_dur / 1000.0));
668 	frag_frame_max = (int)(video_data_conf->framerate * (float) (in_data->frag_dur / 1000.0));
669 	optimize_seg_frag_dur(&seg_frame_max, &frag_frame_max);
670 
671 	real_video_seg_dur = (int) (seg_frame_max * 1000.0 / (float) video_data_conf->framerate);
672 	GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[video_encoder] seg_frame_max=%d, frag_frame_max=%d, real_video_seg_dur=%d ms\n", seg_frame_max, frag_frame_max, real_video_seg_dur));
673 
674 
675 	if (seg_frame_max <= 0)
676 		seg_frame_max = -1;
677 
678 	if (dc_video_muxer_init(&out_file, video_data_conf, muxer_type, seg_frame_max, frag_frame_max, in_data->seg_marker, in_data->gdr, in_data->seg_dur, in_data->frag_dur, (u32) video_scaled_data->vsprop->video_input_data->frame_duration, in_data->gop_size, video_cb_size) < 0) {
679 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot init output video file.\n"));
680 		in_data->exit_signal = 1;
681 		return -1;
682 	}
683 
684 	if (dc_video_encoder_open(&out_file, video_data_conf, in_data->use_source_timing, video_scaled_data->sar) < 0) {
685 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output video stream.\n"));
686 		in_data->exit_signal = 1;
687 		return -1;
688 	}
689 
690 	if (in_data->mode == LIVE_MEDIA || in_data->mode == LIVE_CAMERA) {
691 		init_mpd = GF_TRUE;
692 	}
693 
694 
695 	time_at_segment_start.ntpts = 0;
696 	start_utc = gf_net_get_utc();
697 
698 	while (1) {
699 		frame_nb = 0;
700 		//log time at segment start, because segment availabilityStartTime is computed from AST anchor + segment duration
701 		//logging at the end of the segment production will induce one segment delay
702 		time_at_segment_start.segnum = seg_nb;
703 		time_at_segment_start.utc_time = gf_net_get_utc();
704 		gf_net_get_ntp(&sec, &frac);
705 
706 #ifndef GPAC_DISABLE_LOG
707 		if (gf_log_tool_level_on(GF_LOG_DASH, GF_LOG_INFO)) {
708 			if (time_at_segment_start.ntpts) {
709 				u32 ref_sec, ref_frac;
710 				Double tr, t;
711 				ref_sec = (time_at_segment_start.ntpts>>32) & 0xFFFFFFFFULL;
712 				ref_frac = (u32) (time_at_segment_start.ntpts & 0xFFFFFFFFULL);
713 				tr = ref_sec * 1000.0;
714 				tr += ref_frac*1000.0 /0xFFFFFFFF;
715 				t = sec * 1000.0;
716 				t += frac*1000.0 /0xFFFFFFFF;
717 				GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[DashCast] NTP diff since last segment start in msec is %f\n", t - tr));
718 
719 			}
720 		}
721 #endif
722 
723 		time_at_segment_start.ntpts = sec;
724 		time_at_segment_start.ntpts <<= 32;
725 		time_at_segment_start.ntpts |= frac;
726 
727 		//force writing MPD before any encoding happens (eg don't wait for the end of the first segment)
728 		if (init_mpd) {
729 			init_mpd = GF_FALSE;
730 			GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Initial MPD publish at UTC "LLU" ms\n", time_at_segment_start.utc_time));
731 			dc_message_queue_put(mq, &time_at_segment_start, sizeof(time_at_segment_start));
732 		}
733 
734 		assert(! out_file.segment_started);
735 
736 		if (dc_video_muxer_open(&out_file, in_data->out_dir, video_data_conf->filename, seg_nb+1) < 0) {
737 			GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output video file.\n"));
738 			in_data->exit_signal = 1;
739 			return -1;
740 		}
741 //		fprintf(stdout, "Header size: %d\n", ret);
742 		while (1) {
743 			//we have the RAP already encoded, skip coder
744 			if (loss_state == 2) {
745 				ret = 1;
746 				loss_state = 0;
747 			} else {
748 				ret = dc_video_encoder_encode(&out_file, video_scaled_data);
749 			}
750 
751 			if (ret == -2) {
752 				GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Video encoder has no more data to encode.\n"));
753 				quit = 1;
754 				break;
755 			}
756 			if (ret == -1) {
757 				GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("An error occured while writing video frame.\n"));
758 				quit = 1;
759 				break;
760 			}
761 
762 			if (ret > 0) {
763 				int r;
764 
765 				/*resync at first RAP: flush current broken segment and restart next one on rap*/
766 				if ((loss_state==1) && out_file.codec_ctx->coded_frame->key_frame) {
767 					loss_state = 2;
768 					break;
769 				}
770 
771 				r = dc_video_muxer_write(&out_file, frame_nb, in_data->insert_utc ? GF_TRUE : GF_FALSE);
772 				if (r < 0) {
773 					quit = 1;
774 					in_data->exit_signal = 1;
775 					break;
776 				} else if (r == 1) {
777 					GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("fragment is written!\n"));
778 					if (in_data->send_message == 1) {
779 						snprintf(name_to_send, sizeof(name_to_send), "%s/%s_%d_gpac.m4s", in_data->out_dir, video_data_conf->filename, seg_nb);
780 						dc_message_queue_put(send_seg_mq, name_to_send, sizeof(name_to_send));
781 					}
782 
783 					break;
784 				}
785 
786 				frame_nb++;
787 			}
788 		}
789 
790 		dc_video_muxer_close(&out_file);
791 
792 		// If system is live,
793 		// Send the time that a segment is available to MPD generator thread.
794 		if (in_data->mode == LIVE_MEDIA || in_data->mode == LIVE_CAMERA) {
795 			//check we don't loose sync
796 			int diff;
797 			int seg_diff;
798 			seg_utc = gf_net_get_utc();
799 			diff = (int) (seg_utc - start_utc);
800 
801 			//if seg UTC is after next segment UTC (current ends at seg_nb+1, next at seg_nb+2), adjust numbers
802 			if (diff > (seg_nb+2) * real_video_seg_dur) {
803 				GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[video_encoder] Rep %s UTC diff %d bigger than segment duration %d - some frame where probably lost. Adjusting\n", out_file.rep_id, diff, seg_nb));
804 
805 				while (diff > (seg_nb+2) * real_video_seg_dur) {
806 					seg_nb++;
807 
808 					//do a rough estimate of losses to adjust timing...
809 					if (! in_data->use_source_timing) {
810 						out_file.first_dts_in_fragment += out_file.codec_ctx->time_base.den;
811 					}
812 				}
813 				//wait for RAP to cut next segment
814 				loss_state = 1;
815 			} else {
816 #define SYNC_SAFE	800
817 
818 				seg_diff = diff;
819 				seg_diff -= (seg_nb+1) * real_video_seg_dur;
820 				if (seg_diff > SYNC_SAFE) {
821 					GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[video_encoder] Rep %s UTC diff at segment close: %d is higher than cumulated segment duration %d (diff %d) - frame rate is probably not correct!\n", out_file.rep_id, diff, (seg_nb+1) * in_data->seg_dur, seg_diff));
822 				}
823 				else if (seg_diff < -SYNC_SAFE) {
824 					GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[video_encoder] Rep %s UTC diff at segment close: %d is lower than cumulated segment duration %d (diff %d) - frame rate is probably not correct or frames were lost!\n", out_file.rep_id, diff, (seg_nb+1) * in_data->seg_dur, seg_diff));
825 				} else {
826 					GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[video_encoder] Rep %s UTC diff at segment close: %d - cumulated segment duration %d (diff %d)\n", out_file.rep_id, diff, (seg_nb+1) * in_data->seg_dur, seg_diff));
827 				}
828 			}
829 
830 			//time_t t = time(NULL);
831 			dc_message_queue_put(mq, &time_at_segment_start, sizeof(time_at_segment_start));
832 		}
833 
834 		if ((in_data->time_shift != -1)) {
835 			shift = 1000 * in_data->time_shift / in_data->seg_dur;
836 			if (seg_nb > shift) {
837 				snprintf(name_to_delete, sizeof(name_to_delete), "%s/%s_%d_gpac.m4s", in_data->out_dir, video_data_conf->filename, (seg_nb - shift));
838 				dc_message_queue_put(delete_seg_mq, name_to_delete, sizeof(name_to_delete));
839 			}
840 		}
841 
842 		seg_nb++;
843 
844 		if (quit)
845 			break;
846 	}
847 
848 	// If system is not live,
849 	// Send the duration of the video
850 	if (in_data->mode == ON_DEMAND) {
851 		if (thread_params->video_conf_idx == 0) {
852 			int dur = (seg_nb * seg_frame_max * 1000) / video_data_conf->framerate;
853 			int dur_tot = (out_file.codec_ctx->frame_number * 1000)
854 			              / video_data_conf->framerate;
855 			if (dur > dur_tot)
856 				dur = dur_tot;
857 			GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("Duration: %d \n", dur));
858 			dc_message_queue_put(mq, &dur, sizeof(dur));
859 		}
860 	}
861 
862 	/* Close output video file */
863 	dc_video_encoder_close(&out_file);
864 
865 	dc_video_muxer_free(&out_file);
866 
867 	GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("video encoder thread exit\n"));
868 	return 0;
869 }
870 
audio_encoder_thread(void * params)871 u32 audio_encoder_thread(void *params)
872 {
873 	int ret, exit_loop = 0, quit = 0, seg_nb = 0, frame_per_seg, frame_per_frag, frame_nb, shift, real_audio_seg_dur;
874 	//int seg_frame_max;
875 	//int frag_frame_max;
876 	//int audio_frame_size = AUDIO_FRAME_SIZE;
877 	char name_to_delete[GF_MAX_PATH];
878 	u64 start_utc, seg_utc;
879 	segtime time_at_segment_start;
880 	Bool check_first_seg_utc = GF_TRUE;
881 
882 	AudioMuxerType muxer_type = AUDIO_MUXER;
883 	AudioThreadParam *thread_params = (AudioThreadParam *) params;
884 
885 	CmdData *in_data = thread_params->in_data;
886 	int audio_conf_idx = thread_params->audio_conf_idx;
887 	AudioDataConf *audio_data_conf = (AudioDataConf*)gf_list_get(in_data->audio_lst, audio_conf_idx);
888 
889 	AudioInputData *audio_input_data = thread_params->audio_input_data;
890 	AudioOutputFile audio_output_file;
891 
892 	MessageQueue *mq = thread_params->mq;
893 	MessageQueue *delete_seg_mq = thread_params->delete_seg_mq;
894 
895 	if (!gf_list_count(in_data->audio_lst))
896 		return 0;
897 
898 	//seg_frame_max = audio_data_conf->samplerate
899 	//		* (float) (in_data->seg_dur / 1000.0);
900 
901 	//frag_frame_max = audio_data_conf->samplerate * (float) (in_data->frag_dur / 1000.0);
902 	//if (seg_frame_max <= 0)
903 	//	seg_frame_max = -1;
904 
905 	if (dc_audio_encoder_open(&audio_output_file, audio_data_conf) < 0) {
906 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output audio stream.\n"));
907 		in_data->exit_signal = 1;
908 		return -1;
909 	}
910 
911 	frame_per_seg  = (int)((audio_data_conf->samplerate / (double) audio_output_file.codec_ctx->frame_size) * (in_data->seg_dur  / 1000.0));
912 	frame_per_frag = (int)((audio_data_conf->samplerate / (double) audio_output_file.codec_ctx->frame_size) * (in_data->frag_dur / 1000.0));
913 	optimize_seg_frag_dur(&frame_per_seg, &frame_per_frag);
914 
915 	real_audio_seg_dur = (int) (frame_per_seg * (double) audio_output_file.codec_ctx->frame_size * 1000.0 / (double) audio_data_conf->samplerate);
916 	GF_LOG(GF_LOG_INFO, GF_LOG_DASH,("[audio_encoder] frame_per_seg=%d, frame_per_frag=%d, real_audio_seg_dur=%d ms\n", frame_per_seg, frame_per_frag, real_audio_seg_dur) );
917 
918 	if (dc_audio_muxer_init(&audio_output_file, audio_data_conf, muxer_type, frame_per_seg, frame_per_frag, in_data->seg_marker) < 0) {
919 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot init output audio.\n"));
920 		in_data->exit_signal = 1;
921 		return -1;
922 	}
923 
924 	start_utc = gf_net_get_utc();
925 	GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[audio_encoder] start_utc="LLU"\n", start_utc));
926 
927 	while (1) {
928 		//logging at the end of the segment production will induce one segment delay
929 		time_at_segment_start.utc_time = gf_net_get_utc();
930 		time_at_segment_start.ntpts = gf_net_get_ntp_ts();
931 
932 		frame_nb = 0;
933 		quit = 0;
934 
935 		if (dc_audio_muxer_open(&audio_output_file, in_data->out_dir, audio_data_conf->filename, seg_nb+1) < 0) {
936 			GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open output audio.\n"));
937 			in_data->exit_signal = 1;
938 			return -1;
939 		}
940 
941 		while (1) {
942 			exit_loop = 0;
943 //			if (frame_per_seg > 0) {
944 //				if (frame_nb == frame_per_seg) {
945 //
946 //					//if (dc_audio_encoder_flush(&audio_output_file, audio_input_data) == 0) {
947 //					//	dc_audio_muxer_write(&audio_output_file);
948 //					//	frame_nb++;//= audio_output_file.codec_ctx->frame_size; //audio_output_file.acc_samples;
949 //					//}
950 //
951 //					exit_loop = 1;
952 //					break;
953 //				}
954 //			}
955 
956 			audio_output_file.frame_ntp = gf_net_get_ntp_ts();
957 			ret = dc_audio_encoder_read(&audio_output_file, audio_input_data);
958 			if (ret == -2) {
959 				GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Audio encoder has no more data to encode.\n"));
960 				//if (dc_audio_encoder_flush(&audio_output_file, audio_input_data) == 0) {
961 				//	dc_audio_muxer_write(&audio_output_file);
962 				//	frame_nb++;//= audio_output_file.codec_ctx->frame_size; //audio_output_file.acc_samples;
963 				//}
964 				quit = 1;
965 				break;
966 			}
967 
968 			while (1) {
969 				ret = dc_audio_encoder_encode(&audio_output_file, audio_input_data);
970 				if (ret == 1) {
971 					break;
972 				}
973 				if (ret == -1) {
974 					GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("An error occured while encoding audio frame.\n"));
975 					quit = 1;
976 					break;
977 				}
978 
979 				ret = dc_audio_muxer_write(&audio_output_file, frame_nb, in_data->insert_utc);
980 				if (ret == -1) {
981 					GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("An error occured while writing audio frame.\n"));
982 					quit = 1;
983 					break;
984 				}
985 
986 				if (ret == 1) {
987 					exit_loop = 1;
988 					break;
989 				}
990 
991 				frame_nb++; //= audio_output_file.codec_ctx->frame_size; //audio_output_file.acc_samples;
992 			}
993 
994 			if (exit_loop || quit)
995 				break;
996 		}
997 
998 		dc_audio_muxer_close(&audio_output_file);
999 
1000 		// Send the time that a segment is available to MPD generator thread.
1001 		if (in_data->mode == LIVE_CAMERA || in_data->mode == LIVE_MEDIA) {
1002 			int diff;
1003 			if (check_first_seg_utc) {
1004 				u64 now = gf_net_get_utc();
1005 				check_first_seg_utc = GF_FALSE;
1006 
1007 				diff = (int) (now - time_at_segment_start.utc_time);
1008 				if (diff  < real_audio_seg_dur / 2) {
1009 					u32 sec, frac, ms;
1010 					s32 left, nb_s;
1011 					gf_net_get_ntp(&sec, &frac);
1012 					nb_s = real_audio_seg_dur/1000;
1013 					sec -= nb_s;
1014 					ms = (u32) ((u64) 1000 * frac / 0xFFFFFFFF);
1015 					left = ms;
1016 					left -= (s32) (real_audio_seg_dur - 1000*nb_s);
1017 					while (left<0) {
1018 						left += 1000;
1019 						sec-=1;
1020 					}
1021 					time_at_segment_start.ntpts = sec;
1022 					time_at_segment_start.ntpts <<= 32;
1023 					time_at_segment_start.ntpts |= (u32) ((0xFFFFFFFF*left)/1000);
1024 
1025 					start_utc = time_at_segment_start.utc_time = now - real_audio_seg_dur;
1026 					GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[audio_encoder] First segment produced faster (%d ms) than duration (%d ms) probably due to HW buffers - adjusting ast\n", diff, real_audio_seg_dur));
1027 				}
1028 			}
1029 			if (thread_params->audio_conf_idx == 0) {
1030 
1031 				//check we don't loose sync
1032 				seg_utc = gf_net_get_utc();
1033 				diff = (int) (seg_utc - start_utc);
1034 				//if seg UTC is after next segment UTC (current ends at seg_nb+1, next at seg_nb+2), adjust numbers
1035 				if (diff > (seg_nb+2) * real_audio_seg_dur) {
1036 					GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[audio_encoder] UTC dur %d bigger than segment duration %d - some frame where probably lost. Adjusting\n", diff, seg_nb));
1037 					while (diff > (seg_nb+2) * real_audio_seg_dur) {
1038 						seg_nb++;
1039 					}
1040 				}
1041 				GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("[audio_encoder] UTC dur %d - cumulated segment duration %d (diff %d ms)\n", diff, (seg_nb+1) * real_audio_seg_dur, diff - (seg_nb+1) * real_audio_seg_dur));
1042 
1043 
1044 				time_at_segment_start.segnum = seg_nb;
1045 				dc_message_queue_put(mq, &time_at_segment_start, sizeof(time_at_segment_start));
1046 			}
1047 		}
1048 
1049 		if (in_data->time_shift != -1) {
1050 			shift = 1000 * in_data->time_shift / in_data->seg_dur;
1051 			if (seg_nb > shift) {
1052 				snprintf(name_to_delete, sizeof(name_to_delete), "%s/%s_%d_gpac.m4s", in_data->out_dir, audio_data_conf->filename, (seg_nb - shift));
1053 				dc_message_queue_put(delete_seg_mq, name_to_delete, sizeof(name_to_delete));
1054 			}
1055 		}
1056 
1057 		seg_nb++;
1058 
1059 		if (quit)
1060 			break;
1061 	}
1062 
1063 	// If system is not live,
1064 	// Send the duration of the video
1065 	if (in_data->mode == ON_DEMAND) {
1066 		if (thread_params->audio_conf_idx == 0) {
1067 			int dur = (seg_nb * audio_output_file.codec_ctx->frame_size * frame_per_seg * 1000) / audio_data_conf->samplerate;
1068 			int dur_tot = (audio_output_file.codec_ctx->frame_number * audio_output_file.codec_ctx->frame_size * 1000) / audio_data_conf->samplerate;
1069 			if (dur > dur_tot)
1070 				dur = dur_tot;
1071 			GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("Duration: %d \n", dur));
1072 			dc_message_queue_put(mq, &dur, sizeof(dur));
1073 		}
1074 	}
1075 
1076 	dc_audio_muxer_free(&audio_output_file);
1077 
1078 	/* Close output audio file */
1079 	dc_audio_encoder_close(&audio_output_file);
1080 
1081 	GF_LOG(GF_LOG_INFO, GF_LOG_DASH, ("Audio encoder is exiting...\n"));
1082 	return 0;
1083 }
1084 
dc_run_controler(CmdData * in_data)1085 int dc_run_controler(CmdData *in_data)
1086 {
1087 	int ret = 0;
1088 	u32 video_cb_size = VIDEO_CB_DEFAULT_SIZE;
1089 	u32 i, j;
1090 
1091 	ThreadParam keyboard_th_params;
1092 	ThreadParam mpd_th_params;
1093 	ThreadParam delete_seg_th_params;
1094 	ThreadParam send_frag_th_params;
1095 
1096 	//Video parameters
1097 	VideoThreadParam vdecoder_th_params;
1098 	VideoThreadParam *vencoder_th_params = (VideoThreadParam*)alloca(gf_list_count(in_data->video_lst) * sizeof(VideoThreadParam));
1099 	VideoInputData video_input_data;
1100 	VideoInputFile *video_input_file[MAX_SOURCE_NUMBER];
1101 	VideoScaledDataList video_scaled_data_list;
1102 	VideoThreadParam *vscaler_th_params = NULL;
1103 
1104 	//Audio parameters
1105 	AudioThreadParam adecoder_th_params;
1106 	AudioThreadParam *aencoder_th_params = (AudioThreadParam*)alloca(gf_list_count(in_data->audio_lst) * sizeof(AudioThreadParam));
1107 	AudioInputData audio_input_data;
1108 	AudioInputFile audio_input_file;
1109 
1110 	MessageQueue mq;
1111 	MessageQueue delete_seg_mq;
1112 	MessageQueue send_frag_mq;
1113 
1114 	GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Controler init at UTC "LLU"\n", gf_net_get_utc() ));
1115 	dc_register_libav();
1116 
1117 	for (i = 0; i < MAX_SOURCE_NUMBER; i++)
1118 		video_input_file[i] = (VideoInputFile*)gf_malloc(sizeof(VideoInputFile));
1119 
1120 	dc_message_queue_init(&mq);
1121 	dc_message_queue_init(&delete_seg_mq);
1122 	dc_message_queue_init(&send_frag_mq);
1123 
1124 	memset(&audio_input_data, 0, sizeof(AudioInputData));
1125 	memset(&audio_input_file, 0, sizeof(AudioInputFile));
1126 	memset(&video_input_data, 0, sizeof(VideoInputData));
1127 
1128 
1129 	if (in_data->mode == LIVE_CAMERA || in_data->mode == LIVE_MEDIA)
1130 		video_cb_size  = 1;
1131 
1132 	if (strcmp(in_data->video_data_conf.filename, "") != 0) {
1133 		dc_video_scaler_list_init(&video_scaled_data_list, in_data->video_lst);
1134 		vscaler_th_params = (VideoThreadParam*)gf_malloc(video_scaled_data_list.size * sizeof(VideoThreadParam));
1135 
1136 		/* Open input video */
1137 		if (dc_video_decoder_open(video_input_file[0], &in_data->video_data_conf, in_data->mode, in_data->no_loop, video_scaled_data_list.size) < 0) {
1138 			GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open input video.\n"));
1139 			ret = -1;
1140 			goto exit;
1141 		}
1142 
1143 		if (dc_video_input_data_init(&video_input_data, /*video_input_file[0]->width, video_input_file[0]->height,
1144 		  video_input_file[0]->pix_fmt,*/video_scaled_data_list.size, in_data->mode, MAX_SOURCE_NUMBER, video_cb_size) < 0) {
1145 			GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot initialize audio data.\n"));
1146 			ret = -1;
1147 			goto exit;
1148 		}
1149 
1150 		/* open other input videos for source switching */
1151 		for (i = 0; i < gf_list_count(in_data->vsrc); i++) {
1152 			VideoDataConf *video_data_conf = (VideoDataConf*)gf_list_get(in_data->vsrc, i);
1153 			if (dc_video_decoder_open(video_input_file[i + 1], video_data_conf, LIVE_MEDIA, 1, video_scaled_data_list.size) < 0) {
1154 				GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open input video.\n"));
1155 				ret = -1;
1156 				goto exit;
1157 			}
1158 		}
1159 
1160 		for (i=0; i<gf_list_count(in_data->vsrc) + 1; i++) {
1161 			dc_video_input_data_set_prop(&video_input_data, i, video_input_file[i]->width, video_input_file[i]->height, in_data->video_data_conf.crop_x, in_data->video_data_conf.crop_y, video_input_file[i]->pix_fmt, video_input_file[i]->sar);
1162 		}
1163 
1164 		for (i=0; i<video_scaled_data_list.size; i++) {
1165 			dc_video_scaler_data_init(&video_input_data, video_scaled_data_list.video_scaled_data[i], MAX_SOURCE_NUMBER, video_cb_size);
1166 
1167 			for (j=0; j<gf_list_count(in_data->vsrc) + 1; j++) {
1168 				dc_video_scaler_data_set_prop(&video_input_data, video_scaled_data_list.video_scaled_data[i], j);
1169 			}
1170 		}
1171 
1172 		/* Initialize video decoder thread */
1173 		vdecoder_th_params.thread = gf_th_new("video_decoder_thread");
1174 
1175 		for (i=0; i<video_scaled_data_list.size; i++) {
1176 			vscaler_th_params[i].thread = gf_th_new("video_scaler_thread");
1177 		}
1178 
1179 		/* Initialize video encoder threads */
1180 		for (i=0; i<gf_list_count(in_data->video_lst); i++)
1181 			vencoder_th_params[i].thread = gf_th_new("video_encoder_thread");
1182 	}
1183 
1184 	/* When video and audio share the same source, open it once. This allow to read from unicast streams */
1185 	if (!strcmp(in_data->video_data_conf.filename, in_data->audio_data_conf.filename)) {
1186 		audio_input_file.av_fmt_ctx = video_input_file[0]->av_fmt_ctx;
1187 		video_input_file[0]->av_fmt_ctx_ref_cnt++;
1188 		audio_input_file.av_pkt_list = video_input_file[0]->av_pkt_list = gf_list_new();
1189 		audio_input_file.av_pkt_list_mutex = video_input_file[0]->av_pkt_list_mutex = gf_mx_new("Demux AVPackets List");
1190 	}
1191 
1192 	if (strcmp(in_data->audio_data_conf.filename, "") != 0) {
1193 		/* Open input audio */
1194 		if (dc_audio_decoder_open(&audio_input_file, &in_data->audio_data_conf, in_data->mode, in_data->no_loop, in_data->video_data_conf.framerate) < 0) {
1195 			GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open input audio.\n"));
1196 			ret = -1;
1197 			goto exit;
1198 		}
1199 
1200 		if (dc_audio_input_data_init(&audio_input_data, in_data->audio_data_conf.channels, in_data->audio_data_conf.samplerate, gf_list_count(in_data->audio_lst), in_data->mode) < 0) {
1201 			GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot initialize audio data.\n"));
1202 			ret = -1;
1203 			goto exit;
1204 		}
1205 
1206 		/* Initialize audio decoder thread */
1207 		adecoder_th_params.thread = gf_th_new("audio_decoder_thread");
1208 
1209 		/* Initialize audio encoder threads */
1210 		for (i = 0; i < gf_list_count(in_data->audio_lst); i++)
1211 			aencoder_th_params[i].thread = gf_th_new("video_encoder_thread");
1212 	}
1213 
1214 	/******** Keyboard controler Thread ********/
1215 
1216 	/* Initialize keyboard controller thread */
1217 	keyboard_th_params.thread = gf_th_new("keyboard_thread");
1218 
1219 	/* Create keyboard controller thread */
1220 	keyboard_th_params.in_data = in_data;
1221 	if (gf_th_run(keyboard_th_params.thread, keyboard_thread, (void *)&keyboard_th_params) != GF_OK) {
1222 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for keyboard_thread.\n"));
1223 	}
1224 
1225 	/********************************************/
1226 
1227 	//Communication between decoder and audio encoder
1228 	for (i = 0; i < gf_list_count(in_data->audio_lst); i++) {
1229 		AudioDataConf *tmadata = (AudioDataConf*)gf_list_get(in_data->audio_lst, i);
1230 		tmadata->channels = in_data->audio_data_conf.channels;
1231 		tmadata->samplerate = in_data->audio_data_conf.samplerate;
1232 	}
1233 
1234 	//Communication between decoder and video encoder
1235 	for (i = 0; i < gf_list_count(in_data->video_lst); i++) {
1236 		VideoDataConf *tmvdata = (VideoDataConf*)gf_list_get(in_data->video_lst, i);
1237 		tmvdata->framerate = in_data->video_data_conf.framerate;
1238 		if (in_data->use_source_timing) {
1239 			tmvdata->time_base = in_data->video_data_conf.time_base;
1240 		}
1241 	}
1242 
1243 	/******** MPD Thread ********/
1244 
1245 	/* Initialize MPD generator thread */
1246 	mpd_th_params.thread = gf_th_new("mpd_thread");
1247 
1248 	/* Create MPD generator thread */
1249 	mpd_th_params.in_data = in_data;
1250 	mpd_th_params.mq = &mq;
1251 	if (gf_th_run(mpd_th_params.thread, mpd_thread, (void *)&mpd_th_params) != GF_OK) {
1252 		GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for mpd_thread.\n"));
1253 	}
1254 
1255 
1256 	if (strcmp(in_data->video_data_conf.filename, "") != 0) {
1257 		/* Create video decoder thread */
1258 		vdecoder_th_params.in_data = in_data;
1259 		vdecoder_th_params.video_input_data = &video_input_data;
1260 		vdecoder_th_params.video_input_file = video_input_file;
1261 		if (gf_th_run(vdecoder_th_params.thread, video_decoder_thread, (void *) &vdecoder_th_params) != GF_OK) {
1262 			GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for video_decoder_thread.\n"));
1263 		}
1264 
1265 		while ((in_data->mode == LIVE_CAMERA) && !video_input_data.frame_duration) {
1266 			gf_sleep(0);
1267 		}
1268 	}
1269 
1270 	if (strcmp(in_data->audio_data_conf.filename, "") != 0) {
1271 		/* Create audio decoder thread */
1272 		adecoder_th_params.in_data = in_data;
1273 		adecoder_th_params.audio_input_data = &audio_input_data;
1274 		adecoder_th_params.audio_input_file = &audio_input_file;
1275 		if (gf_th_run(adecoder_th_params.thread, audio_decoder_thread, (void *) &adecoder_th_params) != GF_OK) {
1276 			GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for audio_decoder_thread.\n"));
1277 		}
1278 	}
1279 
1280 	/****************************/
1281 
1282 	if (strcmp(in_data->video_data_conf.filename, "") != 0) {
1283 		/* Create video encoder threads */
1284 		for (i=0; i<gf_list_count(in_data->video_lst); i++) {
1285 			VideoDataConf * video_data_conf = (VideoDataConf*)gf_list_get(in_data->video_lst, i);
1286 
1287 			vencoder_th_params[i].in_data = in_data;
1288 			vencoder_th_params[i].video_conf_idx = i;
1289 			vencoder_th_params[i].video_scaled_data = dc_video_scaler_get_data(&video_scaled_data_list, video_data_conf->width, video_data_conf->height);
1290 
1291 			vencoder_th_params[i].mq = &mq;
1292 			vencoder_th_params[i].delete_seg_mq = &delete_seg_mq;
1293 			vencoder_th_params[i].send_seg_mq = &send_frag_mq;
1294 
1295 			if (gf_th_run(vencoder_th_params[i].thread, video_encoder_thread, (void*)&vencoder_th_params[i]) != GF_OK) {
1296 				GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for video_encoder_thread.\n"));
1297 			}
1298 		}
1299 
1300 		/* Create video scaler threads */
1301 		for (i=0; i<video_scaled_data_list.size; i++) {
1302 			vscaler_th_params[i].in_data = in_data;
1303 			vscaler_th_params[i].video_scaled_data = video_scaled_data_list.video_scaled_data[i];
1304 			vscaler_th_params[i].video_input_data = &video_input_data;
1305 
1306 			if (gf_th_run(vscaler_th_params[i].thread, video_scaler_thread, (void*)&vscaler_th_params[i]) != GF_OK) {
1307 				GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for video_scaler_thread.\n"));
1308 			}
1309 		}
1310 	}
1311 
1312 	if (strcmp(in_data->audio_data_conf.filename, "") != 0) {
1313 		/* Create audio encoder threads */
1314 		for (i = 0; i < gf_list_count(in_data->audio_lst); i++) {
1315 			aencoder_th_params[i].in_data = in_data;
1316 			aencoder_th_params[i].audio_conf_idx = i;
1317 			aencoder_th_params[i].audio_input_data = &audio_input_data;
1318 
1319 			aencoder_th_params[i].mq = &mq;
1320 			aencoder_th_params[i].delete_seg_mq = &delete_seg_mq;
1321 			aencoder_th_params[i].send_seg_mq = &send_frag_mq;
1322 
1323 			if (gf_th_run(aencoder_th_params[i].thread, audio_encoder_thread, (void *) &aencoder_th_params[i]) != GF_OK) {
1324 				GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for audio_encoder_thread.\n"));
1325 			}
1326 		}
1327 	}
1328 
1329 	if (in_data->time_shift != -1) {
1330 		/* Initialize delete segment thread */
1331 		delete_seg_th_params.thread = gf_th_new("delete_seg_thread");
1332 		delete_seg_th_params.in_data = in_data;
1333 		delete_seg_th_params.mq = &delete_seg_mq;
1334 		if (gf_th_run(delete_seg_th_params.thread, delete_seg_thread, (void *) &delete_seg_th_params) != GF_OK) {
1335 			GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for delete_seg_thread.\n"));
1336 		}
1337 	}
1338 
1339 	if (in_data->send_message == 1) {
1340 		/* Initialize delete segment thread */
1341 		send_frag_th_params.thread = gf_th_new("send_frag_event_thread");
1342 		send_frag_th_params.in_data = in_data;
1343 		send_frag_th_params.mq = &send_frag_mq;
1344 		if (gf_th_run(send_frag_th_params.thread, send_frag_event, (void *) &send_frag_th_params) != GF_OK) {
1345 			GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while doing pthread_create for send_frag_event_thread.\n"));
1346 		}
1347 	}
1348 
1349 	fprintf(stdout, "Press q or Q to exit...\n");
1350 
1351 	if (strcmp(in_data->audio_data_conf.filename, "") != 0) {
1352 		/* Wait for and destroy audio decoder threads */
1353 		gf_th_stop(adecoder_th_params.thread);
1354 		gf_th_del(adecoder_th_params.thread);
1355 	}
1356 
1357 	if (strcmp(in_data->video_data_conf.filename, "") != 0) {
1358 		/* Wait for and destroy video decoder threads */
1359 		gf_th_stop(vdecoder_th_params.thread);
1360 		gf_th_del(vdecoder_th_params.thread);
1361 	}
1362 
1363 	if (strcmp(in_data->audio_data_conf.filename, "") != 0) {
1364 		/* Wait for and destroy audio encoder threads */
1365 		for (i = 0; i < gf_list_count(in_data->audio_lst); i++) {
1366 			gf_th_stop(aencoder_th_params[i].thread);
1367 			gf_th_del(aencoder_th_params[i].thread);
1368 		}
1369 	}
1370 
1371 	if (strcmp(in_data->video_data_conf.filename, "") != 0) {
1372 		/* Wait for and destroy video encoder threads */
1373 		for (i=0; i<gf_list_count(in_data->video_lst); i++) {
1374 			gf_th_stop(vencoder_th_params[i].thread);
1375 			gf_th_del(vencoder_th_params[i].thread);
1376 		}
1377 
1378 		/* Wait for and destroy video scaler threads */
1379 		for (i=0; i<video_scaled_data_list.size; i++) {
1380 			gf_th_stop(vscaler_th_params[i].thread);
1381 			gf_th_del(vscaler_th_params[i].thread);
1382 		}
1383 	}
1384 
1385 	keyboard_th_params.in_data->exit_signal = 1;
1386 
1387 	/********** Keyboard thread ***********/
1388 
1389 	/* Wait for and destroy keyboard controler thread */
1390 	gf_th_stop(keyboard_th_params.thread);
1391 	gf_th_del(keyboard_th_params.thread);
1392 
1393 	/**************************************/
1394 
1395 	/********** MPD generator thread ***********/
1396 
1397 	/* Wait for and destroy MPD generator thread */
1398 	gf_th_stop(mpd_th_params.thread);
1399 	gf_th_del(mpd_th_params.thread);
1400 
1401 	/**************************************/
1402 
1403 	if (in_data->time_shift != -1) {
1404 		//	dc_message_queue_flush(&delete_seg_mq);
1405 		/* Wait for and destroy delete segment thread */
1406 		gf_th_stop(delete_seg_th_params.thread);
1407 		gf_th_del(delete_seg_th_params.thread);
1408 	}
1409 
1410 	if (in_data->send_message == 1) {
1411 		/* Wait for and destroy delete segment thread */
1412 		gf_th_stop(send_frag_th_params.thread);
1413 		gf_th_del(send_frag_th_params.thread);
1414 	}
1415 
1416 exit:
1417 	if (strcmp(in_data->audio_data_conf.filename, "") != 0) {
1418 		/* Destroy audio input data */
1419 		dc_audio_input_data_destroy(&audio_input_data);
1420 		/* Close input audio */
1421 		dc_audio_decoder_close(&audio_input_file);
1422 	}
1423 
1424 	if (strcmp(in_data->video_data_conf.filename, "") != 0) {
1425 		/* Destroy video input data */
1426 		dc_video_input_data_destroy(&video_input_data);
1427 
1428 		for (i = 0; i < gf_list_count(in_data->vsrc); i++) {
1429 			/* Close input video */
1430 			dc_video_decoder_close(video_input_file[i]);
1431 		}
1432 
1433 		for (i=0; i<video_scaled_data_list.size; i++) {
1434 			dc_video_scaler_data_destroy(video_scaled_data_list.video_scaled_data[i]);
1435 		}
1436 
1437 		/* Destroy video scaled data */
1438 		dc_video_scaler_list_destroy(&video_scaled_data_list);
1439 	}
1440 
1441 	if (vscaler_th_params)
1442 		gf_free(vscaler_th_params);
1443 
1444 	for (i = 0; i < MAX_SOURCE_NUMBER; i++)
1445 		gf_free(video_input_file[i]);
1446 
1447 	dc_message_queue_free(&mq);
1448 	dc_message_queue_free(&delete_seg_mq);
1449 	dc_message_queue_free(&send_frag_mq);
1450 
1451 	dc_unregister_libav();
1452 
1453 	return ret;
1454 }
1455