From 1eaac1d6f7bb8e52d82e1a114c88a59a9a8e5025 Mon Sep 17 00:00:00 2001 From: John Stebbins Date: Mon, 25 Nov 2013 15:57:28 -0800 Subject: [PATCH] mpeg12dec: Extract CC user data into frame side data Signed-off-by: Anton Khirnov --- doc/APIchanges | 4 +++ libavcodec/mpeg12dec.c | 67 ++++++++++++++++++++++++++++++++++++++++++ libavutil/frame.h | 6 ++++ libavutil/version.h | 2 +- 4 files changed, 78 insertions(+), 1 deletion(-) diff --git a/doc/APIchanges b/doc/APIchanges index 1882fb87fd..1e380e9f23 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -13,6 +13,10 @@ libavutil: 2012-10-22 API changes, most recent first: +2013-11-xx - xxxxxxx- - lavu 52.19.0 - frame.h + Add AV_FRAME_DATA_A53_CC value to the AVFrameSideDataType enum, which + identifies ATSC A53 Part 4 Closed Captions data. + 2013-11-xx - xxxxxxx - lavu 52.18.0 - mem.h Move av_fast_malloc() and av_fast_realloc() for libavcodec to libavutil. diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c index 0e11dda3e6..9d0c3be36a 100644 --- a/libavcodec/mpeg12dec.c +++ b/libavcodec/mpeg12dec.c @@ -44,6 +44,8 @@ typedef struct Mpeg1Context { int mpeg_enc_ctx_allocated; /* true if decoding context allocated */ int repeat_field; /* true if we must repeat the field */ AVPanScan pan_scan; /**< some temporary storage for the panscan */ + uint8_t *a53_caption; + int a53_caption_size; int slice_count; int save_aspect_info; int save_width, save_height, save_progressive_seq; @@ -1529,6 +1531,14 @@ static int mpeg_field_start(MpegEncContext *s, const uint8_t *buf, int buf_size) return AVERROR(ENOMEM); memcpy(pan_scan->data, &s1->pan_scan, sizeof(s1->pan_scan)); + if (s1->a53_caption) { + AVFrameSideData *sd = av_frame_new_side_data( + &s->current_picture_ptr->f, AV_FRAME_DATA_A53_CC, + s1->a53_caption_size); + if (sd) + memcpy(sd->data, s1->a53_caption, s1->a53_caption_size); + av_freep(&s1->a53_caption); + } if (HAVE_THREADS && (avctx->active_thread_type & FF_THREAD_FRAME)) ff_thread_finish_setup(avctx); } else { // second field @@ -2038,6 +2048,60 @@ static int vcr2_init_sequence(AVCodecContext *avctx) } +static int mpeg_decode_a53_cc(AVCodecContext *avctx, + const uint8_t *p, int buf_size) +{ + Mpeg1Context *s1 = avctx->priv_data; + + if (buf_size >= 6 && + p[0] == 'G' && p[1] == 'A' && p[2] == '9' && p[3] == '4' && + p[4] == 3 && (p[5] & 0x40)) { + /* extract A53 Part 4 CC data */ + int cc_count = p[5] & 0x1f; + if (cc_count > 0 && buf_size >= 7 + cc_count * 3) { + av_freep(&s1->a53_caption); + s1->a53_caption_size = cc_count * 3; + s1->a53_caption = av_malloc(s1->a53_caption_size); + if (s1->a53_caption) { + memcpy(s1->a53_caption, p + 7, s1->a53_caption_size); + } + } + return 1; + } else if (buf_size >= 11 && + p[0] == 'C' && p[1] == 'C' && p[2] == 0x01 && p[3] == 0xf8) { + /* extract DVD CC data */ + int cc_count = 0; + int i; + // There is a caption count field in the data, but it is often + // incorect. So count the number of captions present. + for (i = 5; i + 6 <= buf_size && ((p[i] & 0xfe) == 0xfe); i += 6) + cc_count++; + // Transform the DVD format into A53 Part 4 format + if (cc_count > 0) { + av_freep(&s1->a53_caption); + s1->a53_caption_size = cc_count * 6; + s1->a53_caption = av_malloc(s1->a53_caption_size); + if (s1->a53_caption) { + uint8_t field1 = !!(p[4] & 0x80); + uint8_t *cap = s1->a53_caption; + p += 5; + for (i = 0; i < cc_count; i++) { + cap[0] = (p[0] == 0xff && field1) ? 0xfc : 0xfd; + cap[1] = p[1]; + cap[2] = p[2]; + cap[3] = (p[3] == 0xff && !field1) ? 0xfc : 0xfd; + cap[4] = p[4]; + cap[5] = p[5]; + cap += 6; + p += 6; + } + } + } + return 1; + } + return 0; +} + static void mpeg_decode_user_data(AVCodecContext *avctx, const uint8_t *p, int buf_size) { @@ -2057,6 +2121,8 @@ static void mpeg_decode_user_data(AVCodecContext *avctx, return; avctx->dtg_active_format = p[0] & 0x0f; } + } else if (mpeg_decode_a53_cc(avctx, p, buf_size)) { + return; } } @@ -2402,6 +2468,7 @@ static av_cold int mpeg_decode_end(AVCodecContext *avctx) if (s->mpeg_enc_ctx_allocated) ff_MPV_common_end(&s->mpeg_enc_ctx); + av_freep(&s->a53_caption); return 0; } diff --git a/libavutil/frame.h b/libavutil/frame.h index 449a6b799b..d869d83902 100644 --- a/libavutil/frame.h +++ b/libavutil/frame.h @@ -35,6 +35,12 @@ enum AVFrameSideDataType { * The data is the AVPanScan struct defined in libavcodec. */ AV_FRAME_DATA_PANSCAN, + /** + * ATSC A53 Part 4 Closed Captions. + * A53 CC bitstream is stored as uint8_t in AVFrameSideData.data. + * The number of bytes of CC data is AVFrameSideData.size. + */ + AV_FRAME_DATA_A53_CC, }; typedef struct AVFrameSideData { diff --git a/libavutil/version.h b/libavutil/version.h index 4f0f469c62..fa1f53b66b 100644 --- a/libavutil/version.h +++ b/libavutil/version.h @@ -37,7 +37,7 @@ */ #define LIBAVUTIL_VERSION_MAJOR 52 -#define LIBAVUTIL_VERSION_MINOR 18 +#define LIBAVUTIL_VERSION_MINOR 19 #define LIBAVUTIL_VERSION_MICRO 0 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \