From bcf1546fc298ff7d5ef34a6fbe11d494ae3dbee5 Mon Sep 17 00:00:00 2001 From: Oleg Kisselef Date: Fri, 24 Apr 2015 15:38:15 +0600 Subject: [PATCH 1/9] added c708 media subtype --- src/gpacmp4/gpac/isomedia.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gpacmp4/gpac/isomedia.h b/src/gpacmp4/gpac/isomedia.h index b7de05400..739d651b9 100644 --- a/src/gpacmp4/gpac/isomedia.h +++ b/src/gpacmp4/gpac/isomedia.h @@ -227,7 +227,8 @@ enum GF_ISOM_SUBTYPE_LSR1 = GF_4CC( 'l', 's', 'r', '1' ), /* CAPTIONS */ - GF_ISOM_SUBTYPE_C608 = GF_4CC ('c', '6', '0', '8' ) + GF_ISOM_SUBTYPE_C608 = GF_4CC ('c', '6', '0', '8' ), + GF_ISOM_SUBTYPE_C708 = GF_4CC ('c', '7', '0', '8' ) }; From e0903a0789a56e0191978673cee21e154cb28b6f Mon Sep 17 00:00:00 2001 From: Oleg Kisselef Date: Fri, 24 Apr 2015 15:39:20 +0600 Subject: [PATCH 2/9] cdp sections enum added --- src/lib_ccx/ccx_common_constants.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib_ccx/ccx_common_constants.h b/src/lib_ccx/ccx_common_constants.h index d63c5a42b..999ef39d3 100644 --- a/src/lib_ccx/ccx_common_constants.h +++ b/src/lib_ccx/ccx_common_constants.h @@ -231,6 +231,14 @@ enum ccx_code_type CCX_CODEC_ISDB_CC, CCX_CODEC_NONE, }; + +enum cdp_section_type +{ + CDP_DATA_SECTION = 0x72, + CDP_SVC_INFO_SECTION = 0x73, + CDP_FOOTER_SECTION = 0x74 +}; + /* * This Macro check whether descriptor tag is valid for teletext * codec or not. From 5daccf4268f16d56cecc306e705703e170cf3597 Mon Sep 17 00:00:00 2001 From: Oleg Kisselef Date: Fri, 24 Apr 2015 15:40:15 +0600 Subject: [PATCH 3/9] gpac size calculation fix merged from gpac repo --- src/gpacmp4/isom_read.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/gpacmp4/isom_read.c b/src/gpacmp4/isom_read.c index 420502ac1..ced0c711d 100644 --- a/src/gpacmp4/isom_read.c +++ b/src/gpacmp4/isom_read.c @@ -1736,15 +1736,15 @@ GF_Err gf_isom_get_chunks_infos(GF_ISOFile *movie, u32 trackNumber, u32 *dur_min chunk_dur += dur; stbl_GetSampleSize(trak->Media->information->sampleTable->SampleSize, k+sample_idx, &size); chunk_size += size; - + } if (dmin>chunk_dur) dmin = chunk_dur; if (dmaxchunk_size) smin = chunk_size; if (smaxentries[i].samplesPerChunk; if (i+1==stsc->nb_entries) break; @@ -1752,8 +1752,10 @@ GF_Err gf_isom_get_chunks_infos(GF_ISOFile *movie, u32 trackNumber, u32 *dur_min if (stsc->entries[i].firstChunk + nb_chunk == stsc->entries[i+1].firstChunk) break; } } - if (tot_chunks) davg /= tot_chunks; - + if (tot_chunks) { + davg /= tot_chunks; + savg /= tot_chunks; + } if (dur_min) *dur_min = dmin; if (dur_avg) *dur_avg = (u32) davg; if (dur_max) *dur_max = dmax; From b92e42e68592f84320f6189a7bb63afd7fc160d7 Mon Sep 17 00:00:00 2001 From: Oleg Kisselef Date: Fri, 24 Apr 2015 15:42:08 +0600 Subject: [PATCH 4/9] yet another gpac fix applied --- src/gpacmp4/media.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gpacmp4/media.c b/src/gpacmp4/media.c index a64ffa554..8c0222a6c 100644 --- a/src/gpacmp4/media.c +++ b/src/gpacmp4/media.c @@ -333,10 +333,12 @@ GF_Err Media_GetSample(GF_MediaBox *mdia, u32 sampleNumber, GF_ISOSample **samp, //divided into the original and the edition files if (mdia->mediaTrack->moov->mov->openMode == GF_ISOM_OPEN_READ) { //same as last call in read mode - if (!mdia->information->dataHandler || (mdia->information->dataEntryIndex != dataRefIndex)) { + if (!mdia->information->dataHandler) { e = gf_isom_datamap_open(mdia, dataRefIndex, isEdited); if (e) return e; } + if (mdia->information->dataEntryIndex != dataRefIndex) + mdia->information->dataEntryIndex = dataRefIndex; } else { e = gf_isom_datamap_open(mdia, dataRefIndex, isEdited); if (e) return e; From fcd250a5576149db60af71831f8f00cd638cfb5c Mon Sep 17 00:00:00 2001 From: Oleg Kisselef Date: Fri, 24 Apr 2015 15:43:59 +0600 Subject: [PATCH 5/9] basic c708 support for mp4 --- src/gpacmp4/mp4.c | 205 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 179 insertions(+), 26 deletions(-) diff --git a/src/gpacmp4/mp4.c b/src/gpacmp4/mp4.c index c9be6273d..121188a5a 100644 --- a/src/gpacmp4/mp4.c +++ b/src/gpacmp4/mp4.c @@ -3,6 +3,7 @@ #include #include +#include #include "lib_ccx.h" #include "utility.h" #include "ccx_encoders_common.h" @@ -185,6 +186,87 @@ static int process_avc_track(struct lib_ccx_ctx *ctx, const char* basename, GF_I return status; } +unsigned char * ccdp_extract_data(unsigned char * ccdp_atom_content, unsigned int len, unsigned int *cc_count) +{ + unsigned char *data = ccdp_atom_content; + + if (len < 4) + { + dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: unexpected size of cdp\n"); + return NULL; + } + + unsigned int cdp_id = (data[0] << 8) | data[1]; + if (cdp_id != 0x9669) + { + dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: unexpected header %hhX %hhX\n", data[0], data[1]); + return NULL; + } + + data += 2; + len -= 2; + + unsigned int cdp_data_count = data[0]; + unsigned int cdp_frame_rate = data[1] >> 4; //frequency could be calculated + if (cdp_data_count != len + 2) + { + dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: unexpected data length %u %u\n", cdp_data_count, len + 2); + return NULL; + } + + data += 2; + len -= 2; + + unsigned int cdp_flags = data[0]; + unsigned int cdp_counter = (data[1] << 8) | data[2]; + + data += 3; + len -= 3; + + unsigned int cdp_timecode_added = (cdp_flags & 0x80) >> 7; + unsigned int cdp_data_added = (cdp_flags & 0x40) >> 6; + + if (!cdp_data_added) + { + dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: packet without data\n"); + return NULL; + } + + if (cdp_timecode_added) + { + data += 4; + len -= 4; + } + + if (data[0] != CDP_DATA_SECTION) + { + dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: cdp_data_section byte not found\n"); + return NULL; + } + + *cc_count = (unsigned int) (data[1] & 0x1F); + + if (*cc_count != 10 && *cc_count != 20 && *cc_count != 25 && *cc_count != 30) + { + dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: unexpected cc_count %u\n", cc_count); + return NULL; + } + + data += 2; + len -= 2; + + if ((*cc_count) * 3 > len) + { + dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: not enough bytes left (%u) to carry %u*3 bytes\n", len, cc_count); + return NULL; + } + + (void)(cdp_counter); + (void)(cdp_frame_rate); + + return data; +} + /* Here is application algorithm described in some C-like pseudo code: main(){ @@ -231,17 +313,20 @@ int processmp4 (struct lib_ccx_ctx *ctx, char *file,void *enc_ctx) (unsigned char) ((type>>16)%0x100),(unsigned char) ((type>>8)%0x100),(unsigned char) (type%0x100), (unsigned char) (subtype>>24%0x100), (unsigned char) ((subtype>>16)%0x100),(unsigned char) ((subtype>>8)%0x100),(unsigned char) (subtype%0x100)); - if (type == GF_ISOM_MEDIA_CAPTIONS && subtype == GF_ISOM_SUBTYPE_C608) - cc_track_count++; - if( type == GF_ISOM_MEDIA_VISUAL && subtype == GF_ISOM_SUBTYPE_AVC_H264) + if ((type == GF_ISOM_MEDIA_CAPTIONS && subtype == GF_ISOM_SUBTYPE_C608) || + (type == GF_ISOM_MEDIA_CAPTIONS && subtype == GF_ISOM_SUBTYPE_C708)) + cc_track_count++; + if (type == GF_ISOM_MEDIA_VISUAL && subtype == GF_ISOM_SUBTYPE_AVC_H264) avc_track_count++; } + mprint("mp4: found %u tracks: %u avc and %u cc\n", track_count, avc_track_count, cc_track_count); + for(i = 0; i < track_count; i++) { const u32 type = gf_isom_get_media_type(f, i + 1); const u32 subtype = gf_isom_get_media_subtype(f, i + 1, 1); - + if ( type == GF_ISOM_MEDIA_VISUAL && subtype == GF_ISOM_SUBTYPE_XDVB) { if (cc_track_count && !ccx_options.mp4vidtrack) @@ -285,7 +370,8 @@ int processmp4 (struct lib_ccx_ctx *ctx, char *file,void *enc_ctx) } - if (type == GF_ISOM_MEDIA_CAPTIONS && subtype == GF_ISOM_SUBTYPE_C608) + if ((type == GF_ISOM_MEDIA_CAPTIONS && subtype == GF_ISOM_SUBTYPE_C608) || + (type == GF_ISOM_MEDIA_CAPTIONS && subtype == GF_ISOM_SUBTYPE_C708)) { if (avc_track_count && ccx_options.mp4vidtrack) continue; @@ -294,7 +380,7 @@ int processmp4 (struct lib_ccx_ctx *ctx, char *file,void *enc_ctx) unsigned num_streams = gf_isom_get_sample_description_count (f,i+1); #endif unsigned num_samples = gf_isom_get_sample_count (f,i+1); - + u32 ProcessingStreamDescriptionIndex = 0; // Current track we are processing, 0 = we don't know yet u32 timescale = gf_isom_get_media_timescale(f,i+1); #ifdef MP$DEBUG @@ -306,7 +392,7 @@ int processmp4 (struct lib_ccx_ctx *ctx, char *file,void *enc_ctx) #endif for (unsigned k = 0; k data + atomStart; unsigned int atomLength = RB32(data); - if(atomLength < 8 || atomLength > sample->dataLength) + if (atomLength < 8 || atomLength > sample->dataLength) { - mprint ("Invalid atom.\n"); + mprint ("Invalid atom length. Atom length: %u, should be: %u\n", atomLength, sample->dataLength); break; } - - data += 4; - if (!strncmp(data, "cdat", 4) || !strncmp(data, "cdt2", 4)) - { - int ret = 0; - int len = atomLength - 8; - data += 4; #ifdef MP4_DEBUG - dump(256, (unsigned char *)data, atomLength - 8, 0, 1); + dump(256, (unsigned char *)data, atomLength - 8, 0, 1); #endif - do + data += 4; + int is_ccdp = !strncmp(data, "ccdp", 4); + + if (!strncmp(data, "cdat", 4) || !strncmp(data, "cdt2", 4) || is_ccdp) + { + if (subtype == GF_ISOM_SUBTYPE_C708) { - ret = process608((unsigned char*)data, len, ctx->dec_ctx->context_cc608_field_1, &dec_sub); - len -= ret; - data += ret; - if(dec_sub.got_output) + if (!is_ccdp) + { + mprint("Your video file seems to be an interesting sample for us\n"); + mprint("We haven't met c708 subtitle not in a \'ccdp\' atom before\n"); + mprint("Please, report\n"); + break; + } + + unsigned int cc_count; + data += 4; + unsigned char *cc_data = ccdp_extract_data((unsigned char *) data, sample->dataLength - 8, &cc_count); + + if (!cc_data) { - encode_sub(enc_ctx, &dec_sub); - dec_sub.got_output = 0; + dbg_print(CCX_DMT_PARSE, "mp4-708: no cc data found in ccdp\n"); + break; } - } while (len > 0); + + do_cea708 = 1; + unsigned char temp[4]; + for (int cc_i = 0; cc_i < cc_count; cc_i++, cc_data += 3) + { + unsigned char cc_info = cc_data[0]; + unsigned char cc_valid = (unsigned char) ((cc_info & 4) >> 2); + unsigned char cc_type = (unsigned char) (cc_info & 3); + + if (cc_info == CDP_SVC_INFO_SECTION || cc_info == CDP_FOOTER_SECTION) + { + dbg_print(CCX_DMT_PARSE, "mp4-708: premature end of sample (0x73 or 0x74)\n"); + break; + } + + if ((cc_info == 0xFA || cc_info == 0xFC || cc_info == 0xFD) + && (cc_data[1] & 0x7F) == 0 && (cc_data[2] & 0x7F) == 0) + { + dbg_print(CCX_DMT_PARSE, "mp4-708: skipped (zero cc data)\n"); + continue; + } + + temp[0] = cc_valid; + temp[1] = cc_type; + temp[2] = cc_data[1]; + temp[3] = cc_data[2]; + + if (cc_type < 2) + { + dbg_print(CCX_DMT_PARSE, "mp4-708: atom skipped (cc_type < 2)\n"); + continue; + } + do_708(ctx->dec_ctx, (unsigned char *) temp, 4); + cb_708++; + } + atomStart = sample->dataLength; + } + else //subtype == GF_ISOM_SUBTYPE_C608 + { + if (is_ccdp) + { + mprint("Your video file seems to be an interesting sample for us\n"); + mprint("We haven't met c608 subtitle in a \'ccdp\' atom before\n"); + mprint("Please, report\n"); + break; + } + + int ret = 0; + int len = atomLength - 8; + data += 4; + + do { + ret = process608((unsigned char *) data, len, ctx->dec_ctx->context_cc608_field_1, + &dec_sub); + len -= ret; + data += ret; + if (dec_sub.got_output) { + encode_sub(enc_ctx, &dec_sub); + dec_sub.got_output = 0; + } + } while (len > 0); + } } atomStart += atomLength; - } // End of change From 4570965af2f990eb5284227d75019bc39cb8fb16 Mon Sep 17 00:00:00 2001 From: Oleg Kisselef Date: Fri, 24 Apr 2015 15:51:07 +0600 Subject: [PATCH 6/9] removed ide auto-added header include --- src/gpacmp4/mp4.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gpacmp4/mp4.c b/src/gpacmp4/mp4.c index 121188a5a..2f3d8b767 100644 --- a/src/gpacmp4/mp4.c +++ b/src/gpacmp4/mp4.c @@ -3,7 +3,6 @@ #include #include -#include #include "lib_ccx.h" #include "utility.h" #include "ccx_encoders_common.h" From 8140bf3e52804d972491834a650849e66b6b00c6 Mon Sep 17 00:00:00 2001 From: Oleg Kisselef Date: Fri, 24 Apr 2015 18:27:28 +0600 Subject: [PATCH 7/9] mp4 708: fixed *cc_count value obtaining --- src/gpacmp4/mp4.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gpacmp4/mp4.c b/src/gpacmp4/mp4.c index 2f3d8b767..c90cccfef 100644 --- a/src/gpacmp4/mp4.c +++ b/src/gpacmp4/mp4.c @@ -247,7 +247,7 @@ unsigned char * ccdp_extract_data(unsigned char * ccdp_atom_content, unsigned in if (*cc_count != 10 && *cc_count != 20 && *cc_count != 25 && *cc_count != 30) { - dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: unexpected cc_count %u\n", cc_count); + dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: unexpected cc_count %u\n", *cc_count); return NULL; } @@ -256,7 +256,7 @@ unsigned char * ccdp_extract_data(unsigned char * ccdp_atom_content, unsigned in if ((*cc_count) * 3 > len) { - dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: not enough bytes left (%u) to carry %u*3 bytes\n", len, cc_count); + dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: not enough bytes left (%u) to carry %u*3 bytes\n", len, *cc_count); return NULL; } From 45974e88bed8d5a163e2dda1da1c1b7e7fb9cd1a Mon Sep 17 00:00:00 2001 From: Oleg Kisselef Date: Sun, 26 Apr 2015 21:40:36 +0600 Subject: [PATCH 8/9] debug constant typo fix --- src/gpacmp4/mp4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gpacmp4/mp4.c b/src/gpacmp4/mp4.c index c90cccfef..7c9d77108 100644 --- a/src/gpacmp4/mp4.c +++ b/src/gpacmp4/mp4.c @@ -382,7 +382,7 @@ int processmp4 (struct lib_ccx_ctx *ctx, char *file,void *enc_ctx) u32 ProcessingStreamDescriptionIndex = 0; // Current track we are processing, 0 = we don't know yet u32 timescale = gf_isom_get_media_timescale(f,i+1); -#ifdef MP$DEBUG +#ifdef MP4_DEBUG u64 duration = gf_isom_get_media_duration(f,i+1); mprint ("%u streams\n",num_streams); mprint ("%u sample counts\n",num_samples); From e572ba8b6e9abd16b2938f24cc7a847e4ea2bc67 Mon Sep 17 00:00:00 2001 From: Oleg Kisselef Date: Sun, 26 Apr 2015 21:47:02 +0600 Subject: [PATCH 9/9] better naming --- src/gpacmp4/mp4.c | 8 ++++---- src/lib_ccx/ccx_common_constants.h | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/gpacmp4/mp4.c b/src/gpacmp4/mp4.c index 7c9d77108..b89ab2c6b 100644 --- a/src/gpacmp4/mp4.c +++ b/src/gpacmp4/mp4.c @@ -185,7 +185,7 @@ static int process_avc_track(struct lib_ccx_ctx *ctx, const char* basename, GF_I return status; } -unsigned char * ccdp_extract_data(unsigned char * ccdp_atom_content, unsigned int len, unsigned int *cc_count) +unsigned char * ccdp_find_data(unsigned char * ccdp_atom_content, unsigned int len, unsigned int *cc_count) { unsigned char *data = ccdp_atom_content; @@ -237,7 +237,7 @@ unsigned char * ccdp_extract_data(unsigned char * ccdp_atom_content, unsigned in len -= 4; } - if (data[0] != CDP_DATA_SECTION) + if (data[0] != CDP_SECTION_DATA) { dbg_print(CCX_DMT_PARSE, "mp4-708-cdp: cdp_data_section byte not found\n"); return NULL; @@ -443,7 +443,7 @@ int processmp4 (struct lib_ccx_ctx *ctx, char *file,void *enc_ctx) unsigned int cc_count; data += 4; - unsigned char *cc_data = ccdp_extract_data((unsigned char *) data, sample->dataLength - 8, &cc_count); + unsigned char *cc_data = ccdp_find_data((unsigned char *) data, sample->dataLength - 8, &cc_count); if (!cc_data) { @@ -459,7 +459,7 @@ int processmp4 (struct lib_ccx_ctx *ctx, char *file,void *enc_ctx) unsigned char cc_valid = (unsigned char) ((cc_info & 4) >> 2); unsigned char cc_type = (unsigned char) (cc_info & 3); - if (cc_info == CDP_SVC_INFO_SECTION || cc_info == CDP_FOOTER_SECTION) + if (cc_info == CDP_SECTION_SVC_INFO || cc_info == CDP_SECTION_FOOTER) { dbg_print(CCX_DMT_PARSE, "mp4-708: premature end of sample (0x73 or 0x74)\n"); break; diff --git a/src/lib_ccx/ccx_common_constants.h b/src/lib_ccx/ccx_common_constants.h index 999ef39d3..11d1752bf 100644 --- a/src/lib_ccx/ccx_common_constants.h +++ b/src/lib_ccx/ccx_common_constants.h @@ -234,9 +234,9 @@ enum ccx_code_type enum cdp_section_type { - CDP_DATA_SECTION = 0x72, - CDP_SVC_INFO_SECTION = 0x73, - CDP_FOOTER_SECTION = 0x74 + CDP_SECTION_DATA = 0x72, + CDP_SECTION_SVC_INFO = 0x73, + CDP_SECTION_FOOTER = 0x74 }; /*