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(>ime);
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