Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
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...
commit d526385aa4c1466b064e9544cdb663f357007e35 1 parent d986a92
@daniel-kristjansson daniel-kristjansson authored
View
7 mythtv/external/FFmpeg/libavcodec/avcodec.h
@@ -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
View
20 mythtv/external/FFmpeg/libavcodec/mpeg12.c
@@ -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 &&
View
3  mythtv/external/FFmpeg/libavcodec/mpegvideo.c
@@ -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++;
View
3  mythtv/external/FFmpeg/libavcodec/mpegvideo.h
@@ -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
View
51 mythtv/libs/libmythtv/avformatdecoder.cpp
@@ -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)
View
5 mythtv/libs/libmythtv/avformatdecoder.h
@@ -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;
View
16 mythtv/libs/libmythtv/cc608decoder.cpp
@@ -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).
Please sign in to comment.
Something went wrong with that request. Please try again.