mirror of
https://github.com/CCExtractor/ccextractor.git
synced 2024-12-24 11:53:25 +00:00
basic c708 support for mp4
This commit is contained in:
parent
b92e42e685
commit
fcd250a557
@ -3,6 +3,7 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <gpac/isomedia.h>
|
||||
#include <gpacmp4/gpac/isomedia.h>
|
||||
#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 <num_samples; k++)
|
||||
{
|
||||
u32 StreamDescriptionIndex;
|
||||
u32 StreamDescriptionIndex;
|
||||
GF_ISOSample *sample= gf_isom_get_sample(f, i+1, k+1, &StreamDescriptionIndex);
|
||||
if (ProcessingStreamDescriptionIndex && ProcessingStreamDescriptionIndex!=StreamDescriptionIndex)
|
||||
{
|
||||
@ -333,35 +419,102 @@ int processmp4 (struct lib_ccx_ctx *ctx, char *file,void *enc_ctx)
|
||||
{
|
||||
char *data = sample->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)
|
||||
{
|
||||
encode_sub(enc_ctx, &dec_sub);
|
||||
dec_sub.got_output = 0;
|
||||
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;
|
||||
}
|
||||
} while (len > 0);
|
||||
|
||||
unsigned int cc_count;
|
||||
data += 4;
|
||||
unsigned char *cc_data = ccdp_extract_data((unsigned char *) data, sample->dataLength - 8, &cc_count);
|
||||
|
||||
if (!cc_data)
|
||||
{
|
||||
dbg_print(CCX_DMT_PARSE, "mp4-708: no cc data found in ccdp\n");
|
||||
break;
|
||||
}
|
||||
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user