basic c708 support for mp4

This commit is contained in:
Oleg Kisselef 2015-04-24 15:43:59 +06:00
parent b92e42e685
commit fcd250a557

View File

@ -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