]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/cbs_mpeg2.c
avcodec: Constify all the AVCodecParsers
[ffmpeg] / libavcodec / cbs_mpeg2.c
index 8b8b2665631edbeaa2c5f81cc9fefab1db49749e..26400f279f5c35973be19bb31b16cdcd452a4c8a 100644 (file)
 #define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL)
 
 #define ui(width, name) \
-        xui(width, name, current->name, 0)
+        xui(width, name, current->name, 0, MAX_UINT_BITS(width), 0, )
+#define uir(width, name) \
+        xui(width, name, current->name, 1, MAX_UINT_BITS(width), 0, )
 #define uis(width, name, subs, ...) \
-        xui(width, name, current->name, subs, __VA_ARGS__)
+        xui(width, name, current->name, 0, MAX_UINT_BITS(width), subs, __VA_ARGS__)
+#define uirs(width, name, subs, ...) \
+        xui(width, name, current->name, 1, MAX_UINT_BITS(width), subs, __VA_ARGS__)
+#define xui(width, name, var, range_min, range_max, subs, ...) \
+        xuia(width, #name, var, range_min, range_max, subs, __VA_ARGS__)
+#define sis(width, name, subs, ...) \
+        xsi(width, name, current->name, subs, __VA_ARGS__)
+
+#define marker_bit() \
+        bit("marker_bit", 1)
+#define bit(string, value) do { \
+        av_unused uint32_t bit = value; \
+        xuia(1, string, bit, value, value, 0, ); \
+    } while (0)
 
 
 #define READ
 #define READWRITE read
 #define RWContext GetBitContext
 
-#define xui(width, name, var, subs, ...) do { \
-        uint32_t value = 0; \
-        CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \
+#define xuia(width, string, var, range_min, range_max, subs, ...) do { \
+        uint32_t value; \
+        CHECK(ff_cbs_read_unsigned(ctx, rw, width, string, \
                                    SUBSCRIPTS(subs, __VA_ARGS__), \
-                                   &value, 0, (1 << width) - 1)); \
+                                   &value, range_min, range_max)); \
         var = value; \
     } while (0)
 
-#define marker_bit() do { \
-        av_unused uint32_t one; \
-        CHECK(ff_cbs_read_unsigned(ctx, rw, 1, "marker_bit", NULL, &one, 1, 1)); \
+#define xsi(width, name, var, subs, ...) do { \
+        int32_t value; \
+        CHECK(ff_cbs_read_signed(ctx, rw, width, #name, \
+                                 SUBSCRIPTS(subs, __VA_ARGS__), &value, \
+                                 MIN_INT_BITS(width), \
+                                 MAX_INT_BITS(width))); \
+        var = value; \
     } while (0)
 
 #define nextbits(width, compare, var) \
     (get_bits_left(rw) >= width && \
      (var = show_bits(rw, width)) == (compare))
 
+#define infer(name, value) do { \
+        current->name = value; \
+    } while (0)
+
 #include "cbs_mpeg2_syntax_template.c"
 
 #undef READ
 #undef READWRITE
 #undef RWContext
-#undef xui
-#undef marker_bit
+#undef xuia
+#undef xsi
 #undef nextbits
+#undef infer
 
 
 #define WRITE
 #define READWRITE write
 #define RWContext PutBitContext
 
-#define xui(width, name, var, subs, ...) do { \
-        CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \
+#define xuia(width, string, var, range_min, range_max, subs, ...) do { \
+        CHECK(ff_cbs_write_unsigned(ctx, rw, width, string, \
                                     SUBSCRIPTS(subs, __VA_ARGS__), \
-                                    var, 0, (1 << width) - 1)); \
+                                    var, range_min, range_max)); \
     } while (0)
 
-#define marker_bit() do { \
-        CHECK(ff_cbs_write_unsigned(ctx, rw, 1, "marker_bit", NULL, 1, 1, 1)); \
+#define xsi(width, name, var, subs, ...) do { \
+        CHECK(ff_cbs_write_signed(ctx, rw, width, #name, \
+                                  SUBSCRIPTS(subs, __VA_ARGS__), var, \
+                                  MIN_INT_BITS(width), \
+                                  MAX_INT_BITS(width))); \
     } while (0)
 
 #define nextbits(width, compare, var) (var)
 
+#define infer(name, value) do { \
+        if (current->name != (value)) { \
+            av_log(ctx->log_ctx, AV_LOG_WARNING, "Warning: " \
+                   "%s does not match inferred value: " \
+                   "%"PRId64", but should be %"PRId64".\n", \
+                   #name, (int64_t)current->name, (int64_t)(value)); \
+        } \
+    } while (0)
+
 #include "cbs_mpeg2_syntax_template.c"
 
-#undef READ
+#undef WRITE
 #undef READWRITE
 #undef RWContext
-#undef xui
-#undef marker_bit
+#undef xuia
+#undef xsi
 #undef nextbits
+#undef infer
 
 
-static void cbs_mpeg2_free_user_data(void *unit, uint8_t *content)
-{
-    MPEG2RawUserData *user = (MPEG2RawUserData*)content;
-    av_buffer_unref(&user->user_data_ref);
-    av_freep(&content);
-}
-
-static void cbs_mpeg2_free_slice(void *unit, uint8_t *content)
-{
-    MPEG2RawSlice *slice = (MPEG2RawSlice*)content;
-    av_buffer_unref(&slice->header.extra_information_ref);
-    av_buffer_unref(&slice->data_ref);
-    av_freep(&content);
-}
-
 static int cbs_mpeg2_split_fragment(CodedBitstreamContext *ctx,
                                     CodedBitstreamFragment *frag,
                                     int header)
 {
     const uint8_t *start, *end;
-    uint8_t *unit_data;
-    uint32_t start_code = -1, next_start_code = -1;
+    CodedBitstreamUnitType unit_type;
+    uint32_t start_code = -1;
     size_t unit_size;
-    int err, i, unit_type;
+    int err, i, final = 0;
 
     start = avpriv_find_start_code(frag->data, frag->data + frag->data_size,
                                    &start_code);
-    for (i = 0;; i++) {
-        end = avpriv_find_start_code(start, frag->data + frag->data_size,
-                                     &next_start_code);
+    if (start_code >> 8 != 0x000001) {
+        // No start code found.
+        return AVERROR_INVALIDDATA;
+    }
 
+    for (i = 0;; i++) {
         unit_type = start_code & 0xff;
 
-        // The start and end pointers point at to the byte following the
-        // start_code_identifier in the start code that they found.
-        if (end == frag->data + frag->data_size) {
-            // We didn't find a start code, so this is the final unit.
-            unit_size = end - (start - 1);
-        } else {
+        if (start == frag->data + frag->data_size) {
+            // The last four bytes form a start code which constitutes
+            // a unit of its own.  In this situation avpriv_find_start_code
+            // won't modify start_code at all so modify start_code so that
+            // the next unit will be treated as the last unit.
+            start_code = 0;
+        }
+
+        end = avpriv_find_start_code(start--, frag->data + frag->data_size,
+                                     &start_code);
+
+        // start points to the byte containing the start_code_identifier
+        // (may be the last byte of fragment->data); end points to the byte
+        // following the byte containing the start code identifier (or to
+        // the end of fragment->data).
+        if (start_code >> 8 == 0x000001) {
             // Unit runs from start to the beginning of the start code
             // pointed to by end (including any padding zeroes).
-            unit_size = (end - 4) - (start - 1);
+            unit_size = (end - 4) - start;
+        } else {
+           // We didn't find a start code, so this is the final unit.
+           unit_size = end - start;
+           final     = 1;
         }
 
-        unit_data = (uint8_t *)start - 1;
-
-        err = ff_cbs_insert_unit_data(ctx, frag, i, unit_type,
-                                      unit_data, unit_size, frag->data_ref);
+        err = ff_cbs_insert_unit_data(frag, i, unit_type, (uint8_t*)start,
+                                      unit_size, frag->data_ref);
         if (err < 0)
             return err;
 
-        if (end == frag->data + frag->data_size)
+        if (final)
             break;
 
-        start_code = next_start_code;
         start = end;
     }
 
@@ -174,20 +209,21 @@ static int cbs_mpeg2_read_unit(CodedBitstreamContext *ctx,
     if (err < 0)
         return err;
 
+    err = ff_cbs_alloc_unit_content2(ctx, unit);
+    if (err < 0)
+        return err;
+
     if (MPEG2_START_IS_SLICE(unit->type)) {
-        MPEG2RawSlice *slice;
+        MPEG2RawSlice *slice = unit->content;
         int pos, len;
 
-        err = ff_cbs_alloc_unit_content(ctx, unit, sizeof(*slice),
-                                        &cbs_mpeg2_free_slice);
-        if (err < 0)
-            return err;
-        slice = unit->content;
-
         err = cbs_mpeg2_read_slice_header(ctx, &gbc, &slice->header);
         if (err < 0)
             return err;
 
+        if (!get_bits_left(&gbc))
+            return AVERROR_INVALIDDATA;
+
         pos = get_bits_count(&gbc);
         len = unit->data_size;
 
@@ -204,29 +240,27 @@ static int cbs_mpeg2_read_unit(CodedBitstreamContext *ctx,
 #define START(start_code, type, read_func, free_func) \
         case start_code: \
             { \
-                type *header; \
-                err = ff_cbs_alloc_unit_content(ctx, unit, \
-                                                sizeof(*header), free_func); \
-                if (err < 0) \
-                    return err; \
-                header = unit->content; \
+                type *header = unit->content; \
                 err = cbs_mpeg2_read_ ## read_func(ctx, &gbc, header); \
                 if (err < 0) \
                     return err; \
             } \
             break;
-            START(0x00, MPEG2RawPictureHeader,  picture_header,  NULL);
-            START(0xb2, MPEG2RawUserData,       user_data,
-                                            &cbs_mpeg2_free_user_data);
-            START(0xb3, MPEG2RawSequenceHeader, sequence_header, NULL);
-            START(0xb5, MPEG2RawExtensionData,  extension_data,  NULL);
-            START(0xb8, MPEG2RawGroupOfPicturesHeader,
-                                       group_of_pictures_header, NULL);
+            START(MPEG2_START_PICTURE,   MPEG2RawPictureHeader,
+                  picture_header,           &cbs_mpeg2_free_picture_header);
+            START(MPEG2_START_USER_DATA, MPEG2RawUserData,
+                  user_data,                &cbs_mpeg2_free_user_data);
+            START(MPEG2_START_SEQUENCE_HEADER, MPEG2RawSequenceHeader,
+                  sequence_header,          NULL);
+            START(MPEG2_START_EXTENSION, MPEG2RawExtensionData,
+                  extension_data,           NULL);
+            START(MPEG2_START_GROUP,     MPEG2RawGroupOfPicturesHeader,
+                  group_of_pictures_header, NULL);
+            START(MPEG2_START_SEQUENCE_END, MPEG2RawSequenceEnd,
+                  sequence_end,             NULL);
 #undef START
         default:
-            av_log(ctx->log_ctx, AV_LOG_ERROR, "Unknown start code %02"PRIx32".\n",
-                   unit->type);
-            return AVERROR_INVALIDDATA;
+            return AVERROR(ENOSYS);
         }
     }
 
@@ -244,11 +278,13 @@ static int cbs_mpeg2_write_header(CodedBitstreamContext *ctx,
     case start_code: \
         err = cbs_mpeg2_write_ ## func(ctx, pbc, unit->content); \
         break;
-        START(0x00, MPEG2RawPictureHeader,  picture_header);
-        START(0xb2, MPEG2RawUserData,       user_data);
-        START(0xb3, MPEG2RawSequenceHeader, sequence_header);
-        START(0xb5, MPEG2RawExtensionData,  extension_data);
-        START(0xb8, MPEG2RawGroupOfPicturesHeader, group_of_pictures_header);
+        START(MPEG2_START_PICTURE,         MPEG2RawPictureHeader,  picture_header);
+        START(MPEG2_START_USER_DATA,       MPEG2RawUserData,       user_data);
+        START(MPEG2_START_SEQUENCE_HEADER, MPEG2RawSequenceHeader, sequence_header);
+        START(MPEG2_START_EXTENSION,       MPEG2RawExtensionData,  extension_data);
+        START(MPEG2_START_GROUP,           MPEG2RawGroupOfPicturesHeader,
+                                                         group_of_pictures_header);
+        START(MPEG2_START_SEQUENCE_END,    MPEG2RawSequenceEnd,    sequence_end);
 #undef START
     default:
         av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for start "
@@ -275,7 +311,7 @@ static int cbs_mpeg2_write_slice(CodedBitstreamContext *ctx,
         uint8_t *pos = slice->data + slice->data_bit_start / 8;
 
         av_assert0(slice->data_bit_start >= 0 &&
-                   8 * slice->data_size > slice->data_bit_start);
+                   slice->data_size > slice->data_bit_start / 8);
 
         if (slice->data_size * 8 + 8 > put_bits_left(pbc))
             return AVERROR(ENOSPC);
@@ -309,58 +345,13 @@ static int cbs_mpeg2_write_slice(CodedBitstreamContext *ctx,
 }
 
 static int cbs_mpeg2_write_unit(CodedBitstreamContext *ctx,
-                                CodedBitstreamUnit *unit)
+                                CodedBitstreamUnit *unit,
+                                PutBitContext *pbc)
 {
-    CodedBitstreamMPEG2Context *priv = ctx->priv_data;
-    PutBitContext pbc;
-    int err;
-
-    if (!priv->write_buffer) {
-        // Initial write buffer size is 1MB.
-        priv->write_buffer_size = 1024 * 1024;
-
-    reallocate_and_try_again:
-        err = av_reallocp(&priv->write_buffer, priv->write_buffer_size);
-        if (err < 0) {
-            av_log(ctx->log_ctx, AV_LOG_ERROR, "Unable to allocate a "
-                   "sufficiently large write buffer (last attempt "
-                   "%"SIZE_SPECIFIER" bytes).\n", priv->write_buffer_size);
-            return err;
-        }
-    }
-
-    init_put_bits(&pbc, priv->write_buffer, priv->write_buffer_size);
-
-    if (unit->type >= 0x01 && unit->type <= 0xaf)
-        err = cbs_mpeg2_write_slice(ctx, unit, &pbc);
-    else
-        err = cbs_mpeg2_write_header(ctx, unit, &pbc);
-
-    if (err == AVERROR(ENOSPC)) {
-        // Overflow.
-        priv->write_buffer_size *= 2;
-        goto reallocate_and_try_again;
-    }
-    if (err < 0) {
-        // Write failed for some other reason.
-        return err;
-    }
-
-    if (put_bits_count(&pbc) % 8)
-        unit->data_bit_padding = 8 - put_bits_count(&pbc) % 8;
+    if (MPEG2_START_IS_SLICE(unit->type))
+        return cbs_mpeg2_write_slice (ctx, unit, pbc);
     else
-        unit->data_bit_padding = 0;
-
-    unit->data_size = (put_bits_count(&pbc) + 7) / 8;
-    flush_put_bits(&pbc);
-
-    err = ff_cbs_alloc_unit_data(ctx, unit, unit->data_size);
-    if (err < 0)
-        return err;
-
-    memcpy(unit->data, priv->write_buffer, unit->data_size);
-
-    return 0;
+        return cbs_mpeg2_write_header(ctx, unit, pbc);
 }
 
 static int cbs_mpeg2_assemble_fragment(CodedBitstreamContext *ctx,
@@ -400,22 +391,42 @@ static int cbs_mpeg2_assemble_fragment(CodedBitstreamContext *ctx,
     return 0;
 }
 
-static void cbs_mpeg2_close(CodedBitstreamContext *ctx)
-{
-    CodedBitstreamMPEG2Context *priv = ctx->priv_data;
+static const CodedBitstreamUnitTypeDescriptor cbs_mpeg2_unit_types[] = {
+    CBS_UNIT_TYPE_INTERNAL_REF(MPEG2_START_PICTURE, MPEG2RawPictureHeader,
+                               extra_information_picture.extra_information),
 
-    av_freep(&priv->write_buffer);
-}
+    {
+        .nb_unit_types         = CBS_UNIT_TYPE_RANGE,
+        .unit_type_range_start = 0x01,
+        .unit_type_range_end   = 0xaf,
+
+        .content_type   = CBS_CONTENT_TYPE_INTERNAL_REFS,
+        .content_size   = sizeof(MPEG2RawSlice),
+        .nb_ref_offsets = 2,
+        .ref_offsets    = { offsetof(MPEG2RawSlice, header.extra_information_slice.extra_information),
+                            offsetof(MPEG2RawSlice, data) },
+    },
+
+    CBS_UNIT_TYPE_INTERNAL_REF(MPEG2_START_USER_DATA, MPEG2RawUserData,
+                               user_data),
+
+    CBS_UNIT_TYPE_POD(MPEG2_START_SEQUENCE_HEADER, MPEG2RawSequenceHeader),
+    CBS_UNIT_TYPE_POD(MPEG2_START_EXTENSION,       MPEG2RawExtensionData),
+    CBS_UNIT_TYPE_POD(MPEG2_START_SEQUENCE_END,    MPEG2RawSequenceEnd),
+    CBS_UNIT_TYPE_POD(MPEG2_START_GROUP,           MPEG2RawGroupOfPicturesHeader),
+
+    CBS_UNIT_TYPE_END_OF_LIST
+};
 
 const CodedBitstreamType ff_cbs_type_mpeg2 = {
     .codec_id          = AV_CODEC_ID_MPEG2VIDEO,
 
     .priv_data_size    = sizeof(CodedBitstreamMPEG2Context),
 
+    .unit_types        = cbs_mpeg2_unit_types,
+
     .split_fragment    = &cbs_mpeg2_split_fragment,
     .read_unit         = &cbs_mpeg2_read_unit,
     .write_unit        = &cbs_mpeg2_write_unit,
     .assemble_fragment = &cbs_mpeg2_assemble_fragment,
-
-    .close             = &cbs_mpeg2_close,
 };