1 #include <stdio.h>
2 #include <time.h>
3 #include <stdlib.h>
4 
5 #include <gpac/isomedia.h>
6 #include "lib_ccx.h"
7 #include "utility.h"
8 #include "ccx_encoders_common.h"
9 #include "ccx_common_option.h"
10 #include "ccx_mp4.h"
11 #include "activity.h"
12 #include "ccx_dtvcc.h"
13 
bswap16(short v)14 static short bswap16(short v)
15 {
16 	return ((v >> 8) & 0x00FF) | ((v << 8) & 0xFF00);
17 }
18 
bswap32(long v)19 static long bswap32(long v)
20 {
21 	// For 0x12345678 returns 78563412
22 	long swapped=((v&0xFF)<<24) | ((v&0xFF00)<<8) | ((v&0xFF0000) >>8) | ((v&0xFF000000) >>24);
23 	return swapped;
24 }
25 static struct {
26 	unsigned total;
27 	unsigned type[32];
28 }s_nalu_stats;
29 
process_avc_sample(struct lib_ccx_ctx * ctx,u32 timescale,GF_AVCConfig * c,GF_ISOSample * s,struct cc_subtitle * sub)30 static int process_avc_sample(struct lib_ccx_ctx *ctx, u32 timescale, GF_AVCConfig* c, GF_ISOSample* s, struct cc_subtitle *sub)
31 {
32 	int status = 0;
33 	u32 i;
34 	s32 signed_cts=(s32) s->CTS_Offset; // Convert from unsigned to signed. GPAC uses u32 but unsigned values are legal.
35 	struct lib_cc_decode *dec_ctx = NULL;
36 
37 	dec_ctx = update_decoder_list(ctx);
38 
39 	set_current_pts(dec_ctx->timing, (s->DTS + signed_cts)*MPEG_CLOCK_FREQ/timescale);
40 	set_fts(dec_ctx->timing);
41 
42 	for(i = 0; i < s->dataLength; )
43 	{
44 		u32 nal_length;
45 
46 		switch(c->nal_unit_size)
47 		{
48 			case 1:
49 				nal_length = s->data[i];
50 				break;
51 			case 2:
52 				nal_length = bswap16(*(short* )&s->data[i]);
53 				break;
54 			case 4:
55 				nal_length = bswap32(*(long* )&s->data[i]);
56 				break;
57 		}
58 		i += c->nal_unit_size;
59 
60 		s_nalu_stats.total += 1;
61 		s_nalu_stats.type[s->data[i] & 0x1F] += 1;
62 
63 		temp_debug=0;
64 
65 		if (nal_length>0)
66 			do_NAL (dec_ctx, (unsigned char *) &(s->data[i]) ,nal_length, sub);
67 		i += nal_length;
68 	} // outer for
69 	assert(i == s->dataLength);
70 
71 	return status;
72 }
process_xdvb_track(struct lib_ccx_ctx * ctx,const char * basename,GF_ISOFile * f,u32 track,struct cc_subtitle * sub)73 static int process_xdvb_track(struct lib_ccx_ctx *ctx, const char* basename, GF_ISOFile* f, u32 track, struct cc_subtitle *sub)
74 {
75 	u32 timescale, i, sample_count;
76 	int status;
77 
78 	struct lib_cc_decode *dec_ctx = NULL;
79 
80 	dec_ctx = update_decoder_list(ctx);
81 	if((sample_count = gf_isom_get_sample_count(f, track)) < 1)
82 	{
83 		return 0;
84 	}
85 
86 	timescale = gf_isom_get_media_timescale(f, track);
87 
88 	status = 0;
89 
90 	for(i = 0; i < sample_count; i++)
91 	{
92 		u32 sdi;
93 
94 		GF_ISOSample* s = gf_isom_get_sample(f, track, i + 1, &sdi);
95 		if (s!=NULL)
96 		{
97 			s32 signed_cts=(s32) s->CTS_Offset; // Convert from unsigned to signed. GPAC uses u32 but unsigned values are legal.
98 			set_current_pts(dec_ctx->timing, (s->DTS + signed_cts)*MPEG_CLOCK_FREQ/timescale);
99 			set_fts(dec_ctx->timing);
100 
101 			process_m2v (dec_ctx, (unsigned char *) s->data,s->dataLength, sub);
102 			gf_isom_sample_del(&s);
103 		}
104 
105 		int progress = (int) ((i*100) / sample_count);
106 		if (ctx->last_reported_progress != progress)
107 		{
108 			int cur_sec = (int) (get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000);
109 			activity_progress(progress, cur_sec/60, cur_sec%60);
110 			ctx->last_reported_progress = progress;
111 		}
112 	}
113 	int cur_sec = (int) (get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000);
114 	activity_progress(100, cur_sec/60, cur_sec%60);
115 
116 	return status;
117 }
118 
process_avc_track(struct lib_ccx_ctx * ctx,const char * basename,GF_ISOFile * f,u32 track,struct cc_subtitle * sub)119 static int process_avc_track(struct lib_ccx_ctx *ctx, const char* basename, GF_ISOFile* f, u32 track, struct cc_subtitle *sub)
120 {
121 	u32 timescale, i, sample_count, last_sdi = 0;
122 	int status;
123 	GF_AVCConfig* c = NULL;
124 	struct lib_cc_decode *dec_ctx = NULL;
125 
126 	dec_ctx = update_decoder_list(ctx);
127 
128 	if((sample_count = gf_isom_get_sample_count(f, track)) < 1)
129 	{
130 		return 0;
131 	}
132 
133 	timescale = gf_isom_get_media_timescale(f, track);
134 
135 	status = 0;
136 
137 	for(i = 0; i < sample_count; i++)
138 	{
139 		u32 sdi;
140 
141 		GF_ISOSample* s = gf_isom_get_sample(f, track, i + 1, &sdi);
142 
143 		if(s != NULL)
144 		{
145 			if(sdi != last_sdi)
146 			{
147 				if(c != NULL)
148 				{
149 					gf_odf_avc_cfg_del(c);
150 					c = NULL;
151 				}
152 
153 				if((c = gf_isom_avc_config_get(f, track, sdi)) == NULL)
154 				{
155 					gf_isom_sample_del(&s);
156 					status = -1;
157 					break;
158 				}
159 
160 				last_sdi = sdi;
161 			}
162 
163 			status = process_avc_sample(ctx, timescale, c, s, sub);
164 
165 			gf_isom_sample_del(&s);
166 
167 			if(status != 0)
168 			{
169 				break;
170 			}
171 		}
172 
173 		int progress = (int) ((i*100) / sample_count);
174 		if (ctx->last_reported_progress != progress)
175 		{
176 			int cur_sec = (int) (get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000);
177 			activity_progress(progress, cur_sec/60, cur_sec%60);
178 			ctx->last_reported_progress = progress;
179 		}
180 	}
181 	int cur_sec = (int) (get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000);
182 	activity_progress(100, cur_sec/60, cur_sec%60);
183 
184 	if(c != NULL)
185 	{
186 		gf_odf_avc_cfg_del(c);
187 		c = NULL;
188 	}
189 
190 	return status;
191 }
192 
ccdp_find_data(unsigned char * ccdp_atom_content,unsigned int len,unsigned int * cc_count)193 unsigned char * ccdp_find_data(unsigned char * ccdp_atom_content, unsigned int len, unsigned int *cc_count)
194 {
195 	unsigned char *data = ccdp_atom_content;
196 
197 	if (len < 4)
198 	{
199 		dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: unexpected size of cdp\n");
200 		return NULL;
201 	}
202 
203 	unsigned int cdp_id = (data[0] << 8) | data[1];
204 	if (cdp_id != 0x9669)
205 	{
206 		dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: unexpected header %hhX %hhX\n", data[0], data[1]);
207 		return NULL;
208 	}
209 
210 	data += 2;
211 	len -= 2;
212 
213 	unsigned int cdp_data_count = data[0];
214 	unsigned int cdp_frame_rate = data[1] >> 4; //frequency could be calculated
215 	if (cdp_data_count != len + 2)
216 	{
217 		dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: unexpected data length %u %u\n", cdp_data_count, len + 2);
218 		return NULL;
219 	}
220 
221 	data += 2;
222 	len -= 2;
223 
224 	unsigned int cdp_flags = data[0];
225 	unsigned int cdp_counter = (data[1] << 8) | data[2];
226 
227 	data += 3;
228 	len -= 3;
229 
230 	unsigned int cdp_timecode_added = (cdp_flags & 0x80) >> 7;
231 	unsigned int cdp_data_added = (cdp_flags & 0x40) >> 6;
232 
233 	if (!cdp_data_added)
234 	{
235 		dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: packet without data\n");
236 		return NULL;
237 	}
238 
239 	if (cdp_timecode_added)
240 	{
241 		data += 4;
242 		len -= 4;
243 	}
244 
245 	if (data[0] != CDP_SECTION_DATA)
246 	{
247 		dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: cdp_data_section byte not found\n");
248 		return NULL;
249 	}
250 
251 	*cc_count = (unsigned int) (data[1] & 0x1F);
252 
253 	if (*cc_count != 10 && *cc_count != 20 && *cc_count != 25 && *cc_count != 30)
254 	{
255 		dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: unexpected cc_count %u\n", *cc_count);
256 		return NULL;
257 	}
258 
259 	data += 2;
260 	len -= 2;
261 
262 	if ((*cc_count) * 3 > len)
263 	{
264 		dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: not enough bytes left (%u) to carry %u*3 bytes\n", len, *cc_count);
265 		return NULL;
266 	}
267 
268 	(void)(cdp_counter);
269 	(void)(cdp_frame_rate);
270 
271 	return data;
272 }
273 
274 /*
275 	Here is application algorithm described in some C-like pseudo code:
276 		main(){
277 			media = open()
278 			for each track in media
279 				if track is AVC track
280 					for each sample in track
281 						for each NALU in sample
282 							send to avc.c for processing
283 			close(media)
284 		}
285 
286 */
processmp4(struct lib_ccx_ctx * ctx,struct ccx_s_mp4Cfg * cfg,char * file)287 int processmp4 (struct lib_ccx_ctx *ctx,struct ccx_s_mp4Cfg *cfg, char *file)
288 {
289 	int caps = 0;
290 	GF_ISOFile* f;
291 	u32 i, j, track_count, avc_track_count, cc_track_count;
292 	struct cc_subtitle dec_sub;
293 	struct lib_cc_decode *dec_ctx = NULL;
294 	struct encoder_ctx *enc_ctx = update_encoder_list(ctx);
295 
296 	dec_ctx = update_decoder_list(ctx);
297 
298 	memset(&dec_sub,0,sizeof(dec_sub));
299 	mprint("opening \'%s\': ", file);
300 #ifdef MP4_DEBUG
301 	gf_log_set_tool_level(GF_LOG_CONTAINER,GF_LOG_DEBUG);
302 #endif
303 
304 	if((f = gf_isom_open(file, GF_ISOM_OPEN_READ, NULL)) == NULL)
305 	{
306 		mprint("failed to open\n");
307 		free(dec_ctx->xds_ctx);
308 		return -2;
309 	}
310 
311 	mprint("ok\n");
312 
313 	track_count = gf_isom_get_track_count(f);
314 
315 	avc_track_count = 0;
316 	cc_track_count = 0;
317 
318 	for(i = 0; i < track_count; i++)
319 	{
320 		const u32 type = gf_isom_get_media_type(f, i + 1);
321 		const u32 subtype = gf_isom_get_media_subtype(f, i + 1, 1);
322 		mprint ("Track %d, type=%c%c%c%c subtype=%c%c%c%c\n", i+1, (unsigned char) (type>>24%0x100),
323 			(unsigned char) ((type>>16)%0x100),(unsigned char) ((type>>8)%0x100),(unsigned char) (type%0x100),
324 			(unsigned char) (subtype>>24%0x100),
325 			(unsigned char) ((subtype>>16)%0x100),(unsigned char) ((subtype>>8)%0x100),(unsigned char) (subtype%0x100));
326 		if ((type == GF_ISOM_MEDIA_CAPTIONS && subtype == GF_ISOM_SUBTYPE_C608) ||
327 			(type == GF_ISOM_MEDIA_CAPTIONS && subtype == GF_ISOM_SUBTYPE_C708))
328 			cc_track_count++;
329 		if (type == GF_ISOM_MEDIA_VISUAL && subtype == GF_ISOM_SUBTYPE_AVC_H264)
330 			avc_track_count++;
331 	}
332 
333 	mprint("mp4: found %u tracks: %u avc and %u cc\n", track_count, avc_track_count, cc_track_count);
334 
335 	for(i = 0; i < track_count; i++)
336 	{
337 		const u32 type = gf_isom_get_media_type(f, i + 1);
338 		const u32 subtype = gf_isom_get_media_subtype(f, i + 1, 1);
339 
340 		if ( type == GF_ISOM_MEDIA_VISUAL && subtype == GF_ISOM_SUBTYPE_XDVB)
341 		{
342 			if (cc_track_count && !cfg->mp4vidtrack)
343 				continue;
344 			if(process_xdvb_track(ctx, file, f, i + 1, &dec_sub) != 0)
345 			{
346 				mprint("error\n");
347 				free(dec_ctx->xds_ctx);
348 				return -3;
349 			}
350 			if(dec_sub.got_output)
351 			{
352 				caps = 1;
353 				encode_sub(enc_ctx, &dec_sub);
354 				dec_sub.got_output = 0;
355 			}
356 		}
357 
358 		if( type == GF_ISOM_MEDIA_VISUAL && subtype == GF_ISOM_SUBTYPE_AVC_H264)
359 		{
360 			if (cc_track_count && !cfg->mp4vidtrack)
361 				continue;
362 			GF_AVCConfig *cnf = gf_isom_avc_config_get(f,i+1,1);
363 			if (cnf!=NULL)
364 			{
365 				for (j=0; j<gf_list_count(cnf->sequenceParameterSets);j++)
366 				{
367 					GF_AVCConfigSlot* seqcnf=(GF_AVCConfigSlot* )gf_list_get(cnf->sequenceParameterSets,j);
368 					do_NAL (dec_ctx, (unsigned char *) seqcnf->data, seqcnf->size, &dec_sub);
369 				}
370 			}
371 
372 			if(process_avc_track(ctx, file, f, i + 1, &dec_sub) != 0)
373 			{
374 				mprint("error\n");
375 				free(dec_ctx->xds_ctx);
376 				return -3;
377 			}
378 			if(dec_sub.got_output)
379 			{
380 				caps = 1;
381 				encode_sub(enc_ctx, &dec_sub);
382 				dec_sub.got_output = 0;
383 			}
384 		}
385 		if (type == GF_ISOM_MEDIA_CAPTIONS &&
386 				(subtype == GF_ISOM_SUBTYPE_C608 || subtype == GF_ISOM_SUBTYPE_C708))
387 		{
388 			if (avc_track_count && cfg->mp4vidtrack)
389 				continue;
390 
391 #ifdef MP4_DEBUG
392 			unsigned num_streams = gf_isom_get_sample_description_count (f,i+1);
393 #endif
394 			unsigned num_samples = gf_isom_get_sample_count (f,i+1);
395 
396 			u32 ProcessingStreamDescriptionIndex = 0; // Current track we are processing, 0 = we don't know yet
397 			u32 timescale = gf_isom_get_media_timescale(f,i+1);
398 #ifdef MP4_DEBUG
399 			u64 duration = gf_isom_get_media_duration(f,i+1);
400 			mprint ("%u streams\n",num_streams);
401 			mprint ("%u sample counts\n",num_samples);
402 			mprint ("%u timescale\n",(unsigned) timescale);
403 			mprint ("%u duration\n",(unsigned) duration);
404 #endif
405 			for (unsigned k = 0; k <num_samples; k++)
406 			{
407 				u32 StreamDescriptionIndex;
408 				GF_ISOSample *sample= gf_isom_get_sample(f, i+1, k+1, &StreamDescriptionIndex);
409 				if (ProcessingStreamDescriptionIndex && ProcessingStreamDescriptionIndex!=StreamDescriptionIndex)
410 				{
411 					mprint ("This sample seems to have more than one track. This isn't supported yet.\n");
412 					mprint ("Submitting this video file will help add support to this case.\n");
413 					break;
414 				}
415 				if (!ProcessingStreamDescriptionIndex)
416 						ProcessingStreamDescriptionIndex=StreamDescriptionIndex;
417 				if (sample==NULL)
418 					continue;
419 #ifdef DEBUG
420 				 mprint ("Data length: %lu\n",sample->dataLength);
421 				const LLONG timestamp = (LLONG )((sample->DTS + sample->CTS_Offset) * 1000) / timescale;
422 #endif
423 				set_current_pts(dec_ctx->timing, (sample->DTS + sample->CTS_Offset)*MPEG_CLOCK_FREQ/timescale);
424 				set_fts(dec_ctx->timing);
425 
426 				int atomStart = 0;
427 				// process Atom by Atom
428 				while (atomStart < sample->dataLength)
429 				{
430 					char *data = sample->data + atomStart;
431 					unsigned int atomLength = RB32(data);
432 					if (atomLength < 8 || atomLength > sample->dataLength)
433 					{
434 						mprint ("Invalid atom length. Atom length: %u,  should be: %u\n", atomLength, sample->dataLength);
435 						break;
436 					}
437 #ifdef MP4_DEBUG
438 					dump(256, (unsigned char *)data, atomLength - 8, 0, 1);
439 #endif
440 					data += 4;
441 					int is_ccdp = !strncmp(data, "ccdp", 4);
442 
443 					if (!strncmp(data, "cdat", 4) || !strncmp(data, "cdt2", 4) || is_ccdp)
444 					{
445 						if (subtype == GF_ISOM_SUBTYPE_C708)
446 						{
447 							if (!is_ccdp)
448 							{
449 								mprint("Your video file seems to be an interesting sample for us\n");
450 								mprint("We haven't met c708 subtitle not in a \'ccdp\' atom before\n");
451 								mprint("Please, report\n");
452 								break;
453 							}
454 
455 							unsigned int cc_count;
456 							data += 4;
457 							unsigned char *cc_data = ccdp_find_data((unsigned char *) data, sample->dataLength - 8, &cc_count);
458 
459 							if (!cc_data)
460 							{
461 								dbg_print(CCX_DMT_PARSE, "mp4-708: no cc data found in ccdp\n");
462 								break;
463 							}
464 
465 							ctx->dec_global_setting->settings_dtvcc->enabled = 1;
466 							unsigned char temp[4];
467 							for (int cc_i = 0; cc_i < cc_count; cc_i++, cc_data += 3)
468 							{
469 								unsigned char cc_info = cc_data[0];
470 								unsigned char cc_valid = (unsigned char) ((cc_info & 4) >> 2);
471 								unsigned char cc_type = (unsigned char) (cc_info & 3);
472 
473 								if (cc_info == CDP_SECTION_SVC_INFO || cc_info == CDP_SECTION_FOOTER)
474 								{
475 									dbg_print(CCX_DMT_PARSE, "mp4-708: premature end of sample (0x73 or 0x74)\n");
476 									break;
477 								}
478 
479 								if ((cc_info == 0xFA || cc_info == 0xFC || cc_info == 0xFD)
480 									&& (cc_data[1] & 0x7F) == 0 && (cc_data[2] & 0x7F) == 0)
481 								{
482 									dbg_print(CCX_DMT_PARSE, "mp4-708: skipped (zero cc data)\n");
483 									continue;
484 								}
485 
486 								temp[0] = cc_valid;
487 								temp[1] = cc_type;
488 								temp[2] = cc_data[1];
489 								temp[3] = cc_data[2];
490 
491 								if (cc_type < 2)
492 								{
493 									dbg_print(CCX_DMT_PARSE, "mp4-708: atom skipped (cc_type < 2)\n");
494 									continue;
495 								}
496 								dec_ctx->dtvcc->encoder = (void *)enc_ctx; //WARN: otherwise cea-708 will not work
497 								//TODO is it really always 4-bytes long?
498 								ccx_dtvcc_process_data(dec_ctx, (unsigned char *) temp, 4);
499 								cb_708++;
500 							}
501 							atomStart = sample->dataLength;
502 						}
503 						else //subtype == GF_ISOM_SUBTYPE_C608
504 						{
505 							if (is_ccdp)
506 							{
507 								mprint("Your video file seems to be an interesting sample for us\n");
508 								mprint("We haven't met c608 subtitle in a \'ccdp\' atom before\n");
509 								mprint("Please, report\n");
510 								break;
511 							}
512 
513 							int ret = 0;
514 							int len = atomLength - 8;
515 							data += 4;
516 							char *tdata = data;
517 							do {
518 								// Process each pair independently so we can adjust timing
519 								ret = process608((unsigned char *) tdata, len>2?2:len, dec_ctx,
520 												 &dec_sub);
521 								len -= ret;
522 								tdata += ret;
523 								cb_field1++;
524 								if (dec_sub.got_output) {
525 									caps = 1;
526 									encode_sub(enc_ctx, &dec_sub);
527 									dec_sub.got_output = 0;
528 								}
529 							} while (len > 0);
530 						}
531 					}
532 					atomStart += atomLength;
533 				}
534 				free(sample->data);
535 				free(sample);
536 
537 				// End of change
538 				int progress = (int) ((k*100) / num_samples);
539 				if (ctx->last_reported_progress != progress)
540 				{
541 					int cur_sec = (int) (get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000);
542 					activity_progress(progress, cur_sec/60, cur_sec%60);
543 					ctx->last_reported_progress = progress;
544 				}
545 			}
546 			int cur_sec = (int) (get_fts(dec_ctx->timing, dec_ctx->current_field) / 1000);
547 			activity_progress(100, cur_sec/60, cur_sec%60);
548 		}
549 	}
550 
551 	free(dec_ctx->xds_ctx);
552 
553 	mprint("\nclosing media: ");
554 
555 	gf_isom_close(f);
556 	f = NULL;
557 	mprint ("ok\n");
558 
559 	if(avc_track_count == 0)
560 	{
561 		mprint("Found no AVC track(s). ", file);
562 	}
563 	else
564 	{
565 		mprint("Found %d AVC track(s). ", avc_track_count);
566 	}
567 	if (cc_track_count)
568 		mprint ("Found %d CC track(s).\n", cc_track_count);
569 	else
570 		mprint ("found no dedicated CC track(s).\n");
571 
572 	ctx->freport.mp4_cc_track_cnt = cc_track_count;
573 
574 	return caps;
575 }
576