Skip to content

Commit

Permalink
Refs #9829. Handle duplicate SCTE and ATSC captions with patch from A…
Browse files Browse the repository at this point in the history
…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 d526385
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 21 deletions.
7 changes: 7 additions & 0 deletions mythtv/external/FFmpeg/libavcodec/avcodec.h
Expand Up @@ -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
Expand Down
20 changes: 10 additions & 10 deletions mythtv/external/FFmpeg/libavcodec/mpeg12.c
Expand Up @@ -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);
Expand All @@ -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 &&
Expand Down
3 changes: 3 additions & 0 deletions mythtv/external/FFmpeg/libavcodec/mpegvideo.c
Expand Up @@ -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++;

Expand Down
3 changes: 3 additions & 0 deletions mythtv/external/FFmpeg/libavcodec/mpegvideo.h
Expand Up @@ -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
Expand Down
51 changes: 43 additions & 8 deletions mythtv/libs/libmythtv/avformatdecoder.cpp
Expand Up @@ -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())),
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
5 changes: 4 additions & 1 deletion mythtv/libs/libmythtv/avformatdecoder.h
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
16 changes: 14 additions & 2 deletions mythtv/libs/libmythtv/cc608decoder.cpp
Expand Up @@ -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);

Expand Down Expand Up @@ -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).
Expand Down

0 comments on commit d526385

Please sign in to comment.