Skip to content
Permalink
Browse files

Refs #9829. Handle duplicate SCTE and ATSC captions with patch from A…

…lex Halovanic.

The primary problem is that some streams have both SCTE and ATSC captions, so we need to capture them seperately and then decide which to use.

A secondary problem is inversion and repeats in 608 captions, esp SCTE.
  • Loading branch information
daniel-kristjansson committed Aug 11, 2011
1 parent d986a92 commit d526385aa4c1466b064e9544cdb663f357007e35
@@ -1060,6 +1060,13 @@ typedef struct AVPanScan{
uint8_t atsc_cc_buf[1024];\
int atsc_cc_len;\
\
/** SCTE CC data CEA-608 \
* - encoding: unused\
* - decoding: Set by libavcodec
*/\
uint8_t scte_cc_buf[1024];\
int scte_cc_len;\
\

#define FF_QSCALE_TYPE_MPEG1 0
#define FF_QSCALE_TYPE_MPEG2 1
@@ -2168,14 +2168,14 @@ static void mpeg_decode_user_data(AVCodecContext *avctx,
unsigned int cc_bytes = (cc_bits + 7 - 3) / 8;
Mpeg1Context *s1 = avctx->priv_data;
MpegEncContext *s = &s1->mpeg_enc_ctx;
if (buf_end - p >= (2+cc_bytes) && (s->tmp_atsc_cc_len + 2 + 3*cc_count) < ATSC_CC_BUF_SIZE) {
int atsc_cnt_loc = s->tmp_atsc_cc_len;
if (buf_end - p >= (2+cc_bytes) && (s->tmp_scte_cc_len + 2 + 3*cc_count) < SCTE_CC_BUF_SIZE) {
int scte_cnt_loc = s->tmp_scte_cc_len;
uint8_t real_count = 0, marker = 1, i;
GetBitContext gb;
init_get_bits(&gb, p+2, (buf_end-p-2) * sizeof(uint8_t));
get_bits(&gb, 5); // swallow cc_count
s->tmp_atsc_cc_buf[s->tmp_atsc_cc_len++] = 0x40 | (0x1f&cc_count);
s->tmp_atsc_cc_buf[s->tmp_atsc_cc_len++] = 0x00; // em_data
s->tmp_scte_cc_buf[s->tmp_scte_cc_len++] = 0x40 | (0x1f&cc_count);
s->tmp_scte_cc_buf[s->tmp_scte_cc_len++] = 0x00; // em_data
for (i = 0; i < cc_count; i++) {
uint8_t valid, cc608_hdr;
uint8_t priority = get_bits(&gb, 2);
@@ -2196,18 +2196,18 @@ static void mpeg_decode_user_data(AVCodecContext *avctx,
continue;
cc608_hdr = 0xf8 | (valid ? 0x04 : 0x00) | type;
real_count++;
s->tmp_atsc_cc_buf[s->tmp_atsc_cc_len++] = cc608_hdr;
s->tmp_atsc_cc_buf[s->tmp_atsc_cc_len++] = cc_data_1;
s->tmp_atsc_cc_buf[s->tmp_atsc_cc_len++] = cc_data_2;
s->tmp_scte_cc_buf[s->tmp_scte_cc_len++] = cc608_hdr;
s->tmp_scte_cc_buf[s->tmp_scte_cc_len++] = cc_data_1;
s->tmp_scte_cc_buf[s->tmp_scte_cc_len++] = cc_data_2;
}
if (!real_count)
{
s->tmp_atsc_cc_len = atsc_cnt_loc;
s->tmp_scte_cc_len = scte_cnt_loc;
}
else
{
s->tmp_atsc_cc_buf[atsc_cnt_loc] = 0x40 | (0x1f&real_count);
s->tmp_atsc_cc_len = atsc_cnt_loc + 2 + 3 * real_count;
s->tmp_scte_cc_buf[scte_cnt_loc] = 0x40 | (0x1f&real_count);
s->tmp_scte_cc_len = scte_cnt_loc + 2 + 3 * real_count;
}
}
} else if (buf_end - p >= 11 &&
@@ -961,6 +961,9 @@ int MPV_frame_start(MpegEncContext *s, AVCodecContext *avctx)
memcpy(pic->atsc_cc_buf, s->tmp_atsc_cc_buf, s->tmp_atsc_cc_len);
pic->atsc_cc_len = s->tmp_atsc_cc_len;
s->tmp_atsc_cc_len = 0;
memcpy(pic->scte_cc_buf, s->tmp_scte_cc_buf, s->tmp_scte_cc_len);
pic->scte_cc_len = s->tmp_scte_cc_len;
s->tmp_scte_cc_len = 0;

pic->coded_picture_number= s->coded_picture_number++;

@@ -656,6 +656,9 @@ typedef struct MpegEncContext {
/// frame for these packets has been created in MPV_frame_start().
uint8_t tmp_atsc_cc_buf[ATSC_CC_BUF_SIZE];
int tmp_atsc_cc_len;
#define SCTE_CC_BUF_SIZE 1024
uint8_t tmp_scte_cc_buf[SCTE_CC_BUF_SIZE];
int tmp_scte_cc_len;

int (*decode_mb)(struct MpegEncContext *s, DCTELEM block[6][64]); // used by some codecs to avoid a switch()
#define SLICE_OK 0
@@ -289,6 +289,9 @@ AvFormatDecoder::AvFormatDecoder(MythPlayer *parent,
special_decode(special_decoding),
maxkeyframedist(-1),
// Closed Caption & Teletext decoders
ignore_scte(false),
invert_scte_field(0),
last_scte_field(0),
ccd608(new CC608Decoder(parent->GetCC608Reader())),
ccd708(new CC708Decoder(parent->GetCC708Reader())),
ttd(new TeletextDecoder(parent->GetTeletextReader())),
@@ -2483,7 +2486,7 @@ int get_avf_buffer_vaapi(struct AVCodecContext *c, AVFrame *pic)
return 0;
}

void AvFormatDecoder::DecodeDTVCC(const uint8_t *buf, uint len)
void AvFormatDecoder::DecodeDTVCC(const uint8_t *buf, uint len, bool scte)
{
if (!len)
return;
@@ -2517,13 +2520,36 @@ void AvFormatDecoder::DecodeDTVCC(const uint8_t *buf, uint len)
uint data2 = buf[4+(cur*3)];
uint data = (data2 << 8) | data1;
uint cc_type = cc_code & 0x03;
uint field;

if (cc_type <= 0x1) // EIA-608 field-1/2
if (scte || cc_type <= 0x1) // EIA-608 field-1/2
{
if (cc_type == 0x2)
{
// SCTE repeated field
field = !last_scte_field;
invert_scte_field = !invert_scte_field;
}
else
{
field = cc_type ^ invert_scte_field;
}

// in film mode, we may start at the wrong field;
// correct if XDS is detected (must be field 2)
if (scte && field == 0 && data1 == 0x01)
{
if (cc_type == 1)
invert_scte_field = 0;
field = 1;
}

last_scte_field = field;

if (cc608_good_parity(cc608_parity_table, data))
{
had_608 = true;
ccd608->FormatCCField(lastccptsu / 1000, cc_type, data);
ccd608->FormatCCField(lastccptsu / 1000, field, data);
}
}
else
@@ -3034,14 +3060,23 @@ bool AvFormatDecoder::ProcessVideoFrame(AVStream *stream, AVFrame *mpa_pic)
{
AVCodecContext *context = stream->codec;

// Decode CEA-608 and CEA-708 captions
for (uint i = 0; i < (uint)mpa_pic->atsc_cc_len;
i += ((mpa_pic->atsc_cc_buf[i] & 0x1f) * 3) + 2)
uint cc_len = (uint) max(mpa_pic->scte_cc_len,0);
uint8_t *cc_buf = mpa_pic->scte_cc_buf;
bool scte = true;

// If both ATSC and SCTE caption data are available, prefer ATSC
if ((mpa_pic->atsc_cc_len > 0) || ignore_scte)
{
DecodeDTVCC(mpa_pic->atsc_cc_buf + i,
mpa_pic->atsc_cc_len - i);
ignore_scte = true;
cc_len = (uint) max(mpa_pic->atsc_cc_len, 0);
cc_buf = mpa_pic->atsc_cc_buf;
scte = false;
}

// Decode CEA-608 and CEA-708 captions
for (uint i = 0; i < cc_len; i += ((cc_buf[i] & 0x1f) * 3) + 2)
DecodeDTVCC(cc_buf + i, cc_len - i, scte);

VideoFrame *picframe = (VideoFrame *)(mpa_pic->opaque);

if (special_decode & kAVSpecialDecode_NoDecode)
@@ -203,7 +203,7 @@ class AvFormatDecoder : public DecoderBase
friend int64_t seek_avf(URLContext *h, int64_t offset, int whence);
friend int close_avf(URLContext *h);

void DecodeDTVCC(const uint8_t *buf, uint buf_size);
void DecodeDTVCC(const uint8_t *buf, uint buf_size, bool scte);
void InitByteContext(void);
void InitVideoCodec(AVStream *stream, AVCodecContext *enc,
bool selectedStream = false);
@@ -311,6 +311,9 @@ class AvFormatDecoder : public DecoderBase
int maxkeyframedist;

// Caption/Subtitle/Teletext decoders
bool ignore_scte;
uint invert_scte_field;
uint last_scte_field;
CC608Decoder *ccd608;
CC708Decoder *ccd708;
TeletextDecoder *ttd;
@@ -176,7 +176,12 @@ void CC608Decoder::FormatCCField(int tc, int field, int data)
}

if (FalseDup(tc, field, data))
goto skip;
{
if (ignore_time_code)
return;
else
goto skip;
}

XDSDecode(field, b1, b2);

@@ -539,12 +544,19 @@ int CC608Decoder::FalseDup(int tc, int field, int data)

if (ignore_time_code)
{
// just suppress duplicate control codes
// most digital streams with encoded VBI
// have duplicate control codes;
// suppress every other repeated control code
if ((data == lastcode[field]) &&
((b1 & 0x70) == 0x10))
{
lastcode[field] = -1;
return 1;
}
else
{
return 0;
}
}

// bttv-0.9 VBI reads are pretty reliable (1 read/33367us).

0 comments on commit d526385

Please sign in to comment.
You can’t perform that action at this time.