[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