X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fcbs_mpeg2.c;h=13d871cc89aabee6937f49b45cb520813e68c807;hb=56c8856966ecc7a016aa0edb5472a902a7fbd49a;hp=8b8b2665631edbeaa2c5f81cc9fefab1db49749e;hpb=47e12966b75490cfa5fb8ed65a48a9a3d84a7bce;p=ffmpeg diff --git a/libavcodec/cbs_mpeg2.c b/libavcodec/cbs_mpeg2.c index 8b8b2665631..13d871cc89a 100644 --- a/libavcodec/cbs_mpeg2.c +++ b/libavcodec/cbs_mpeg2.c @@ -41,79 +41,123 @@ #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_picture_header(void *opaque, uint8_t *content) +{ + MPEG2RawPictureHeader *picture = (MPEG2RawPictureHeader*)content; + av_buffer_unref(&picture->extra_information_picture.extra_information_ref); + av_freep(&content); +} -static void cbs_mpeg2_free_user_data(void *unit, uint8_t *content) +static void cbs_mpeg2_free_user_data(void *opaque, 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) +static void cbs_mpeg2_free_slice(void *opaque, uint8_t *content) { MPEG2RawSlice *slice = (MPEG2RawSlice*)content; - av_buffer_unref(&slice->header.extra_information_ref); + av_buffer_unref(&slice->header.extra_information_slice.extra_information_ref); av_buffer_unref(&slice->data_ref); av_freep(&content); } @@ -123,41 +167,54 @@ static int cbs_mpeg2_split_fragment(CodedBitstreamContext *ctx, 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(ctx, 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; } @@ -215,18 +272,21 @@ static int cbs_mpeg2_read_unit(CodedBitstreamContext *ctx, 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 +304,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 +337,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 +371,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,13 +417,6 @@ static int cbs_mpeg2_assemble_fragment(CodedBitstreamContext *ctx, return 0; } -static void cbs_mpeg2_close(CodedBitstreamContext *ctx) -{ - CodedBitstreamMPEG2Context *priv = ctx->priv_data; - - av_freep(&priv->write_buffer); -} - const CodedBitstreamType ff_cbs_type_mpeg2 = { .codec_id = AV_CODEC_ID_MPEG2VIDEO, @@ -416,6 +426,4 @@ const CodedBitstreamType ff_cbs_type_mpeg2 = { .read_unit = &cbs_mpeg2_read_unit, .write_unit = &cbs_mpeg2_write_unit, .assemble_fragment = &cbs_mpeg2_assemble_fragment, - - .close = &cbs_mpeg2_close, };