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