[FFmpeg-devel] [PATCH] Add A53 Closed Captions to MPEG header if they are available.
John Poet
jppoet at gmail.com
Wed Jun 7 00:06:20 EEST 2017
ff_mpeg1_encode_picture_header: Add support for AV_FRAME_DATA_A53_CC
frame: Add av_frame_get_side_data_at() to allow retrival of multiple side
data of the same type.
---
libavcodec/mpeg12enc.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++
libavutil/frame.c | 8 ++++++++
libavutil/frame.h | 38 +++++++++++++++++++++++++++++++++++-
3 files changed, 97 insertions(+), 1 deletion(-)
diff --git a/libavcodec/mpeg12enc.c b/libavcodec/mpeg12enc.c
index f45598a..01fda83 100644
--- a/libavcodec/mpeg12enc.c
+++ b/libavcodec/mpeg12enc.c
@@ -543,6 +543,58 @@ void ff_mpeg1_encode_picture_header(MpegEncContext *s, int picture_number)
}
}
+ /* MPEG closed caption user data is limited to 31 3-byte "closed
+ * caption constructs" per user data block. There can be serveral
+ * such user data blocks per frame.
+ */
+ for (int i = 0;; ++i) {
+ side_data = av_frame_get_side_data_at(s->current_picture_ptr->f, i);
+ if (!side_data)
+ break;
+
+ if (side_data->type == AV_FRAME_DATA_A53_CC) {
+ avpriv_align_put_bits(&s->pb);
+ put_header(s, USER_START_CODE);
+
+ /* ATSC user data identifier for CC or BAR data */
+ put_bits(&s->pb, 8, 'G');
+ put_bits(&s->pb, 8, 'A');
+ put_bits(&s->pb, 8, '9');
+ put_bits(&s->pb, 8, '4');
+
+ /* MPEG CC data type code */
+ put_bits(&s->pb, 8, 0x03);
+
+ /* cc_data() {
+ * reserved (1 bits) ’1’
+ * process_cc_data_flag (1 bits) bslbf
+ * additional_data_flag (1 bits) bslbf
+ * cc_count (5 bits) uimsbf
+ * reserved (8 bits) ‘1111 1111’
+ * for (i=0 ; i < cc_count ; ++i) {
+ * marker_bits (5 bits) ‘1111 1’
+ * cc_valid (1 bits) bslbf
+ * cc_type (2 bits) bslbf
+ * cc_data_1 (8 bits) bslbf
+ * cc_data_2 (8 bits) bslbf
+ * }
+ * marker_bits (8 bits) ‘1111 1111’
+ * if (additional_data_flag) {
+ * while (nextbits() != ‘0000 0000 0000 0000 0000 0001’) {
+ * additional_cc_data
+ * }
+ * }
+ * }
+ */
+ for(int j = 0; j < side_data->size; ++j) {
+ put_bits(&s->pb, 8, side_data->data[j]);
+ }
+
+ /* Marker bits */
+ put_bits(&s->pb, 8, 0xFF);
+ }
+ }
+
s->mb_y = 0;
ff_mpeg1_encode_slice_header(s);
}
diff --git a/libavutil/frame.c b/libavutil/frame.c
index 24d5d5f..8912f52 100644
--- a/libavutil/frame.c
+++ b/libavutil/frame.c
@@ -688,6 +688,14 @@ AVFrameSideData *av_frame_get_side_data(const AVFrame *frame,
return NULL;
}
+AVFrameSideData *av_frame_get_side_data_at(const AVFrame *frame, int idx)
+{
+ if (idx < frame->nb_side_data)
+ return frame->side_data[idx];
+
+ return NULL;
+}
+
static int frame_copy_video(AVFrame *dst, const AVFrame *src)
{
const uint8_t *src_data[4];
diff --git a/libavutil/frame.h b/libavutil/frame.h
index 26261d7..5503106 100644
--- a/libavutil/frame.h
+++ b/libavutil/frame.h
@@ -52,8 +52,39 @@ enum AVFrameSideDataType {
AV_FRAME_DATA_PANSCAN,
/**
* ATSC A53 Part 4 Closed Captions.
- * A53 CC bitstream is stored as uint8_t in AVFrameSideData.data.
+ * A53 CC bitstream (cc_data) is stored as uint8_t in AVFrameSideData.data.
* The number of bytes of CC data is AVFrameSideData.size.
+ *
+ * Data format:
+ *
+ * bslbf -- Bit string, left bit first, where “left” is the order in
+ * which bit strings are written in the Standard. Bit strings are
+ * written as a string of 1s and 0s within single quote marks,
+ * e.g. ‘1000 0001’. Blanks within a bit string are for ease of
+ * reading and have no significance
+ *
+ * uimsbf -- Unsigned integer, most significant bit first.
+ *
+ * cc_data() {
+ * reserved (1 bits) ’1’
+ * process_cc_data_flag (1 bits) bslbf
+ * additional_data_flag (1 bits) bslbf
+ * cc_count (5 bits) uimsbf
+ * reserved (8 bits) ‘1111 1111’
+ * for (i=0 ; i < cc_count ; ++i) {
+ * marker_bits (5 bits) ‘1111 1’
+ * cc_valid (1 bits) bslbf
+ * cc_type (2 bits) bslbf
+ * cc_data_1 (8 bits) bslbf
+ * cc_data_2 (8 bits) bslbf
+ * }
+ * marker_bits (8 bits) ‘1111 1111’
+ * if (additional_data_flag) {
+ * while (nextbits() != ‘0000 0000 0000 0000 0000 0001’) {
+ * additional_cc_data
+ * }
+ * }
+ * }
*/
AV_FRAME_DATA_A53_CC,
/**
@@ -759,6 +790,11 @@ AVFrameSideData *av_frame_new_side_data(AVFrame *frame,
*/
AVFrameSideData *av_frame_get_side_data(const AVFrame *frame,
enum AVFrameSideDataType type);
+/**
+ * @return a pointer to the side data at the given index on success,
+ * NULL if the index is out-of-bounds.
+ */
+AVFrameSideData *av_frame_get_side_data_at(const AVFrame *frame, int idx);
/**
* If side data of the supplied type exists in the frame, free it and remove it
--
2.1.4
More information about the ffmpeg-devel
mailing list