diff options
author | Mark Thompson <sw@jkqxz.net> | 2017-05-04 23:03:03 +0100 |
---|---|---|
committer | Mark Thompson <sw@jkqxz.net> | 2017-10-17 20:56:29 +0100 |
commit | 686e388bbb6aeef077095a83f84b53d143d44d63 (patch) | |
tree | cfcd19745c52c01c4ecba66863e818d349f5ab59 /libavcodec | |
parent | 9b0c7aa0e446eceec96ba8f4009e004fad29fba3 (diff) | |
download | ffmpeg-686e388bbb6aeef077095a83f84b53d143d44d63.tar.gz |
lavc: Add coded bitstream read/write support for MPEG-2
(cherry picked from commit 2bc9ba8d3c41f3a8e56484bd67b05040c7909a01)
(cherry picked from commit a41b69b5eb950c10d8ede472bcc4e88ce4246db9)
Diffstat (limited to 'libavcodec')
-rw-r--r-- | libavcodec/Makefile | 1 | ||||
-rw-r--r-- | libavcodec/cbs.c | 3 | ||||
-rw-r--r-- | libavcodec/cbs.h | 1 | ||||
-rw-r--r-- | libavcodec/cbs_internal.h | 1 | ||||
-rw-r--r-- | libavcodec/cbs_mpeg2.c | 414 | ||||
-rw-r--r-- | libavcodec/cbs_mpeg2.h | 224 | ||||
-rw-r--r-- | libavcodec/cbs_mpeg2_syntax_template.c | 384 |
7 files changed, 1028 insertions, 0 deletions
diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 39b7dd1e2f..0265c92130 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -62,6 +62,7 @@ OBJS-$(CONFIG_CABAC) += cabac.o OBJS-$(CONFIG_CBS) += cbs.o OBJS-$(CONFIG_CBS_H264) += cbs_h2645.o h2645_parse.o OBJS-$(CONFIG_CBS_H265) += cbs_h2645.o h2645_parse.o +OBJS-$(CONFIG_CBS_MPEG2) += cbs_mpeg2.o OBJS-$(CONFIG_CRYSTALHD) += crystalhd.o OBJS-$(CONFIG_DCT) += dct.o dct32_fixed.o dct32_float.o OBJS-$(CONFIG_ERROR_RESILIENCE) += error_resilience.o diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c index d7eb3033c4..97ab520c22 100644 --- a/libavcodec/cbs.c +++ b/libavcodec/cbs.c @@ -34,6 +34,9 @@ static const CodedBitstreamType *cbs_type_table[] = { #if CONFIG_CBS_H265 &ff_cbs_type_h265, #endif +#if CONFIG_CBS_MPEG2 + &ff_cbs_type_mpeg2, +#endif }; int ff_cbs_init(CodedBitstreamContext **ctx_ptr, diff --git a/libavcodec/cbs.h b/libavcodec/cbs.h index a367fd0bf6..ff97880610 100644 --- a/libavcodec/cbs.h +++ b/libavcodec/cbs.h @@ -45,6 +45,7 @@ struct CodedBitstreamType; * * H.264 / AVC: nal_unit_type * H.265 / HEVC: nal_unit_type + * MPEG-2: start code value (without prefix) */ typedef uint32_t CodedBitstreamUnitType; diff --git a/libavcodec/cbs_internal.h b/libavcodec/cbs_internal.h index f8263bef0a..ae0b417b43 100644 --- a/libavcodec/cbs_internal.h +++ b/libavcodec/cbs_internal.h @@ -85,6 +85,7 @@ int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, extern const CodedBitstreamType ff_cbs_type_h264; extern const CodedBitstreamType ff_cbs_type_h265; +extern const CodedBitstreamType ff_cbs_type_mpeg2; #endif /* AVCODEC_CBS_INTERNAL_H */ diff --git a/libavcodec/cbs_mpeg2.c b/libavcodec/cbs_mpeg2.c new file mode 100644 index 0000000000..d137762227 --- /dev/null +++ b/libavcodec/cbs_mpeg2.c @@ -0,0 +1,414 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" + +#include "cbs.h" +#include "cbs_internal.h" +#include "cbs_mpeg2.h" +#include "internal.h" + + +#define HEADER(name) do { \ + ff_cbs_trace_header(ctx, name); \ + } while (0) + +#define CHECK(call) do { \ + err = (call); \ + if (err < 0) \ + return err; \ + } while (0) + +#define FUNC_NAME(rw, codec, name) cbs_ ## codec ## _ ## rw ## _ ## name +#define FUNC_MPEG2(rw, name) FUNC_NAME(rw, mpeg2, name) +#define FUNC(name) FUNC_MPEG2(READWRITE, name) + + +#define READ +#define READWRITE read +#define RWContext GetBitContext + +#define xui(width, name, var) do { \ + uint32_t value = 0; \ + CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \ + &value, 0, (1 << width) - 1)); \ + var = value; \ + } while (0) + +#define ui(width, name) \ + xui(width, name, current->name) + +#define marker_bit() do { \ + av_unused int one = 1; \ + CHECK(ff_cbs_read_unsigned(ctx, rw, 1, "marker_bit", &one, 1, 1)); \ + } while (0) + +#define nextbits(width, compare, var) \ + (get_bits_left(rw) >= width && \ + (var = show_bits(rw, width)) == (compare)) + +#include "cbs_mpeg2_syntax_template.c" + +#undef READ +#undef READWRITE +#undef RWContext +#undef xui +#undef ui +#undef marker_bit +#undef nextbits + + +#define WRITE +#define READWRITE write +#define RWContext PutBitContext + +#define xui(width, name, var) do { \ + CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ + var, 0, (1 << width) - 1)); \ + } while (0) + +#define ui(width, name) \ + xui(width, name, current->name) + +#define marker_bit() do { \ + CHECK(ff_cbs_write_unsigned(ctx, rw, 1, "marker_bit", 1, 1, 1)); \ + } while (0) + +#define nextbits(width, compare, var) (var) + +#include "cbs_mpeg2_syntax_template.c" + +#undef READ +#undef READWRITE +#undef RWContext +#undef xui +#undef ui +#undef marker_bit +#undef nextbits + + +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; + size_t unit_size; + int err, i, unit_type; + + 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); + + 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 { + // 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_data = av_malloc(unit_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!unit_data) + return AVERROR(ENOMEM); + memcpy(unit_data, start - 1, unit_size); + memset(unit_data + unit_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + err = ff_cbs_insert_unit_data(ctx, frag, i, unit_type, + unit_data, unit_size); + if (err < 0) { + av_freep(&unit_data); + return err; + } + + if (end == frag->data + frag->data_size) + break; + + start_code = next_start_code; + start = end; + } + + return 0; +} + +static int cbs_mpeg2_read_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + GetBitContext gbc; + int err; + + err = init_get_bits(&gbc, unit->data, 8 * unit->data_size); + if (err < 0) + return err; + + if (MPEG2_START_IS_SLICE(unit->type)) { + MPEG2RawSlice *slice; + int pos, len; + + slice = av_mallocz(sizeof(*slice)); + if (!slice) + return AVERROR(ENOMEM); + err = cbs_mpeg2_read_slice_header(ctx, &gbc, &slice->header); + if (err < 0) { + av_free(slice); + return err; + } + + pos = get_bits_count(&gbc); + len = unit->data_size; + + slice->data_size = len - pos / 8; + slice->data = av_malloc(slice->data_size + + AV_INPUT_BUFFER_PADDING_SIZE); + if (!slice->data) { + av_free(slice); + return AVERROR(ENOMEM); + } + + memcpy(slice->data, + unit->data + pos / 8, slice->data_size); + memset(slice->data + slice->data_size, 0, + AV_INPUT_BUFFER_PADDING_SIZE); + slice->data_bit_start = pos % 8; + + unit->content = slice; + + } else { + switch (unit->type) { +#define START(start_code, type, func) \ + case start_code: \ + { \ + type *header; \ + header = av_mallocz(sizeof(*header)); \ + if (!header) \ + return AVERROR(ENOMEM); \ + err = cbs_mpeg2_read_ ## func(ctx, &gbc, header); \ + if (err < 0) { \ + av_free(header); \ + return err; \ + } \ + unit->content = header; \ + } \ + 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); +#undef START + default: + av_log(ctx->log_ctx, AV_LOG_ERROR, "Unknown start code %02x.\n", + unit->type); + return AVERROR_INVALIDDATA; + } + } + + return 0; +} + +static int cbs_mpeg2_write_header(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) +{ + int err; + + switch (unit->type) { +#define START(start_code, type, func) \ + 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); +#undef START + default: + av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for start " + "code %02"PRIu32".\n", unit->type); + return AVERROR_PATCHWELCOME; + } + + return err; +} + +static int cbs_mpeg2_write_slice(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) +{ + MPEG2RawSlice *slice = unit->content; + GetBitContext gbc; + size_t bits_left; + int err; + + err = cbs_mpeg2_write_slice_header(ctx, pbc, &slice->header); + if (err < 0) + return err; + + if (slice->data) { + if (slice->data_size * 8 + 8 > put_bits_left(pbc)) + return AVERROR(ENOSPC); + + init_get_bits(&gbc, slice->data, slice->data_size * 8); + skip_bits_long(&gbc, slice->data_bit_start); + + while (get_bits_left(&gbc) > 15) + put_bits(pbc, 16, get_bits(&gbc, 16)); + + bits_left = get_bits_left(&gbc); + put_bits(pbc, bits_left, get_bits(&gbc, bits_left)); + + // Align with zeroes. + while (put_bits_count(pbc) % 8 != 0) + put_bits(pbc, 1, 0); + } + + return 0; +} + +static int cbs_mpeg2_write_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + 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 " + "%zu 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; + else + unit->data_bit_padding = 0; + + unit->data_size = (put_bits_count(&pbc) + 7) / 8; + flush_put_bits(&pbc); + + err = av_reallocp(&unit->data, unit->data_size); + if (err < 0) + return err; + + memcpy(unit->data, priv->write_buffer, unit->data_size); + + return 0; +} + +static int cbs_mpeg2_assemble_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) +{ + uint8_t *data; + size_t size, dp, sp; + int i; + + size = 0; + for (i = 0; i < frag->nb_units; i++) + size += 3 + frag->units[i].data_size; + + data = av_malloc(size); + if (!data) + return AVERROR(ENOMEM); + + dp = 0; + for (i = 0; i < frag->nb_units; i++) { + CodedBitstreamUnit *unit = &frag->units[i]; + + data[dp++] = 0; + data[dp++] = 0; + data[dp++] = 1; + + for (sp = 0; sp < unit->data_size; sp++) + data[dp++] = unit->data[sp]; + } + + av_assert0(dp == size); + + frag->data = data; + frag->data_size = size; + + return 0; +} + +static void cbs_mpeg2_free_unit(CodedBitstreamUnit *unit) +{ + if (MPEG2_START_IS_SLICE(unit->type)) { + MPEG2RawSlice *slice = unit->content; + av_freep(&slice->data); + av_freep(&slice->header.extra_information); + } else if (unit->type == MPEG2_START_USER_DATA) { + MPEG2RawUserData *user = unit->content; + av_freep(&user->user_data); + } + av_freep(&unit->content); +} + +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, + + .priv_data_size = sizeof(CodedBitstreamMPEG2Context), + + .split_fragment = &cbs_mpeg2_split_fragment, + .read_unit = &cbs_mpeg2_read_unit, + .write_unit = &cbs_mpeg2_write_unit, + .assemble_fragment = &cbs_mpeg2_assemble_fragment, + + .free_unit = &cbs_mpeg2_free_unit, + .close = &cbs_mpeg2_close, +}; diff --git a/libavcodec/cbs_mpeg2.h b/libavcodec/cbs_mpeg2.h new file mode 100644 index 0000000000..a8f12b2e75 --- /dev/null +++ b/libavcodec/cbs_mpeg2.h @@ -0,0 +1,224 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_CBS_MPEG2_H +#define AVCODEC_CBS_MPEG2_H + +#include <stddef.h> +#include <stdint.h> + + +enum { + MPEG2_START_PICTURE = 0x00, + MPEG2_START_SLICE_MIN = 0x01, + MPEG2_START_SLICE_MAX = 0xaf, + MPEG2_START_USER_DATA = 0xb2, + MPEG2_START_SEQUENCE_HEADER = 0xb3, + MPEG2_START_SEQUENCE_ERROR = 0xb4, + MPEG2_START_EXTENSION = 0xb5, + MPEG2_START_SEQUENCE_END = 0xb7, + MPEG2_START_GROUP = 0xb8, +}; + +#define MPEG2_START_IS_SLICE(type) \ + ((type) >= MPEG2_START_SLICE_MIN && \ + (type) <= MPEG2_START_SLICE_MAX) + +enum { + MPEG2_EXTENSION_SEQUENCE = 0x1, + MPEG2_EXTENSION_SEQUENCE_DISPLAY = 0x2, + MPEG2_EXTENSION_QUANT_MATRIX = 0x3, + MPEG2_EXTENSION_COPYRIGHT = 0x4, + MPEG2_EXTENSION_SEQUENCE_SCALABLE = 0x5, + MPEG2_EXTENSION_PICTURE_DISPLAY = 0x7, + MPEG2_EXTENSION_PICTURE_CODING = 0x8, + MPEG2_EXTENSION_PICTURE_SPATIAL_SCALABLE = 0x9, + MPEG2_EXTENSION_PICTURE_TEMPORAL_SCALABLE = 0xa, + MPEG2_EXTENSION_CAMAERA_PARAMETERS = 0xb, + MPEG2_EXTENSION_ITU_T = 0xc, +}; + + +typedef struct MPEG2RawSequenceHeader { + uint8_t sequence_header_code; + + uint16_t horizontal_size_value; + uint16_t vertical_size_value; + uint8_t aspect_ratio_information; + uint8_t frame_rate_code; + uint32_t bit_rate_value; + uint16_t vbv_buffer_size_value; + uint8_t constrained_parameters_flag; + + uint8_t load_intra_quantiser_matrix; + uint8_t intra_quantiser_matrix[64]; + uint8_t load_non_intra_quantiser_matrix; + uint8_t non_intra_quantiser_matrix[64]; +} MPEG2RawSequenceHeader; + +typedef struct MPEG2RawUserData { + uint8_t user_data_start_code; + + uint8_t *user_data; + size_t user_data_length; +} MPEG2RawUserData; + +typedef struct MPEG2RawSequenceExtension { + uint8_t profile_and_level_indication; + uint8_t progressive_sequence; + uint8_t chroma_format; + uint8_t horizontal_size_extension; + uint8_t vertical_size_extension; + uint16_t bit_rate_extension; + uint8_t vbv_buffer_size_extension; + uint8_t low_delay; + uint8_t frame_rate_extension_n; + uint8_t frame_rate_extension_d; +} MPEG2RawSequenceExtension; + +typedef struct MPEG2RawSequenceDisplayExtension { + uint8_t video_format; + + uint8_t colour_description; + uint8_t colour_primaries; + uint8_t transfer_characteristics; + uint8_t matrix_coefficients; + + uint16_t display_horizontal_size; + uint16_t display_vertical_size; +} MPEG2RawSequenceDisplayExtension; + +typedef struct MPEG2RawGroupOfPicturesHeader { + uint8_t group_start_code; + + uint32_t time_code; + uint8_t closed_gop; + uint8_t broken_link; +} MPEG2RawGroupOfPicturesHeader; + +typedef struct MPEG2RawPictureHeader { + uint8_t picture_start_code; + + uint16_t temporal_reference; + uint8_t picture_coding_type; + uint16_t vbv_delay; + + uint8_t full_pel_forward_vector; + uint8_t forward_f_code; + uint8_t full_pel_backward_vector; + uint8_t backward_f_code; + + uint8_t extra_bit_picture; +} MPEG2RawPictureHeader; + +typedef struct MPEG2RawPictureCodingExtension { + uint8_t f_code[2][2]; + + uint8_t intra_dc_precision; + uint8_t picture_structure; + uint8_t top_field_first; + uint8_t frame_pred_frame_dct; + uint8_t concealment_motion_vectors; + uint8_t q_scale_type; + uint8_t intra_vlc_format; + uint8_t alternate_scan; + uint8_t repeat_first_field; + uint8_t chroma_420_type; + uint8_t progressive_frame; + + uint8_t composite_display_flag; + uint8_t v_axis; + uint8_t field_sequence; + uint8_t sub_carrier; + uint8_t burst_amplitude; + uint8_t sub_carrier_phase; +} MPEG2RawPictureCodingExtension; + +typedef struct MPEG2RawQuantMatrixExtension { + uint8_t load_intra_quantiser_matrix; + uint8_t intra_quantiser_matrix[64]; + uint8_t load_non_intra_quantiser_matrix; + uint8_t non_intra_quantiser_matrix[64]; + uint8_t load_chroma_intra_quantiser_matrix; + uint8_t chroma_intra_quantiser_matrix[64]; + uint8_t load_chroma_non_intra_quantiser_matrix; + uint8_t chroma_non_intra_quantiser_matrix[64]; +} MPEG2RawQuantMatrixExtension; + +typedef struct MPEG2RawPictureDisplayExtension { + uint16_t frame_centre_horizontal_offset[3]; + uint16_t frame_centre_vertical_offset[3]; +} MPEG2RawPictureDisplayExtension; + +typedef struct MPEG2RawExtensionData { + uint8_t extension_start_code; + uint8_t extension_start_code_identifier; + + union { + MPEG2RawSequenceExtension sequence; + MPEG2RawSequenceDisplayExtension sequence_display; + MPEG2RawQuantMatrixExtension quant_matrix; + MPEG2RawPictureCodingExtension picture_coding; + MPEG2RawPictureDisplayExtension picture_display; + } data; +} MPEG2RawExtensionData; + +typedef struct MPEG2RawSliceHeader { + uint8_t slice_vertical_position; + + uint8_t slice_vertical_position_extension; + uint8_t priority_breakpoint; + + uint8_t quantiser_scale_code; + + uint8_t slice_extension_flag; + uint8_t intra_slice; + uint8_t slice_picture_id_enable; + uint8_t slice_picture_id; + + uint8_t extra_bit_slice; + + size_t extra_information_length; + uint8_t *extra_information; +} MPEG2RawSliceHeader; + +typedef struct MPEG2RawSlice { + MPEG2RawSliceHeader header; + + uint8_t *data; + size_t data_size; + int data_bit_start; +} MPEG2RawSlice; + + +typedef struct CodedBitstreamMPEG2Context { + // Elements stored in headers which are required for other decoding. + uint16_t horizontal_size; + uint16_t vertical_size; + uint8_t scalable; + uint8_t scalable_mode; + uint8_t progressive_sequence; + uint8_t number_of_frame_centre_offsets; + + // Write buffer. + uint8_t *write_buffer; + size_t write_buffer_size; +} CodedBitstreamMPEG2Context; + + +#endif /* AVCODEC_CBS_MPEG2_H */ diff --git a/libavcodec/cbs_mpeg2_syntax_template.c b/libavcodec/cbs_mpeg2_syntax_template.c new file mode 100644 index 0000000000..90dde26aed --- /dev/null +++ b/libavcodec/cbs_mpeg2_syntax_template.c @@ -0,0 +1,384 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +static int FUNC(sequence_header)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawSequenceHeader *current) +{ + CodedBitstreamMPEG2Context *mpeg2 = ctx->priv_data; + int err, i; + + HEADER("Sequence Header"); + + ui(8, sequence_header_code); + + ui(12, horizontal_size_value); + ui(12, vertical_size_value); + + mpeg2->horizontal_size = current->horizontal_size_value; + mpeg2->vertical_size = current->vertical_size_value; + + ui(4, aspect_ratio_information); + ui(4, frame_rate_code); + ui(18, bit_rate_value); + + marker_bit(); + + ui(10, vbv_buffer_size_value); + ui(1, constrained_parameters_flag); + + ui(1, load_intra_quantiser_matrix); + if (current->load_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) + ui(8, intra_quantiser_matrix[i]); + } + + ui(1, load_non_intra_quantiser_matrix); + if (current->load_non_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) + ui(8, non_intra_quantiser_matrix[i]); + } + + return 0; +} + +static int FUNC(user_data)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawUserData *current) +{ + size_t k; + int err; + + HEADER("User Data"); + + ui(8, user_data_start_code); + +#ifdef READ + k = get_bits_left(rw); + av_assert0(k % 8 == 0); + current->user_data_length = k /= 8; + if (k > 0) { + current->user_data = av_malloc(k); + if (!current->user_data) + return AVERROR(ENOMEM); + } +#endif + + for (k = 0; k < current->user_data_length; k++) + xui(8, user_data, current->user_data[k]); + + return 0; +} + +static int FUNC(sequence_extension)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawSequenceExtension *current) +{ + CodedBitstreamMPEG2Context *mpeg2 = ctx->priv_data; + int err; + + HEADER("Sequence Extension"); + + ui(8, profile_and_level_indication); + ui(1, progressive_sequence); + ui(2, chroma_format); + ui(2, horizontal_size_extension); + ui(2, vertical_size_extension); + + mpeg2->horizontal_size = (mpeg2->horizontal_size & 0xfff) | + current->horizontal_size_extension << 12; + mpeg2->vertical_size = (mpeg2->vertical_size & 0xfff) | + current->vertical_size_extension << 12; + mpeg2->progressive_sequence = current->progressive_sequence; + + ui(12, bit_rate_extension); + marker_bit(); + ui(8, vbv_buffer_size_extension); + ui(1, low_delay); + ui(2, frame_rate_extension_n); + ui(5, frame_rate_extension_d); + + return 0; +} + +static int FUNC(sequence_display_extension)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawSequenceDisplayExtension *current) +{ + int err; + + HEADER("Sequence Display Extension"); + + ui(3, video_format); + + ui(1, colour_description); + if (current->colour_description) { + ui(8, colour_primaries); + ui(8, transfer_characteristics); + ui(8, matrix_coefficients); + } + + ui(14, display_horizontal_size); + marker_bit(); + ui(14, display_vertical_size); + + return 0; +} + +static int FUNC(group_of_pictures_header)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawGroupOfPicturesHeader *current) +{ + int err; + + HEADER("Group of Pictures Header"); + + ui(8, group_start_code); + + ui(25, time_code); + ui(1, closed_gop); + ui(1, broken_link); + + return 0; +} + +static int FUNC(picture_header)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawPictureHeader *current) +{ + int err; + + HEADER("Picture Header"); + + ui(8, picture_start_code); + + ui(10, temporal_reference); + ui(3, picture_coding_type); + ui(16, vbv_delay); + + if (current->picture_coding_type == 2 || + current->picture_coding_type == 3) { + ui(1, full_pel_forward_vector); + ui(3, forward_f_code); + } + + if (current->picture_coding_type == 3) { + ui(1, full_pel_backward_vector); + ui(3, backward_f_code); + } + + ui(1, extra_bit_picture); + + return 0; +} + +static int FUNC(picture_coding_extension)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawPictureCodingExtension *current) +{ + CodedBitstreamMPEG2Context *mpeg2 = ctx->priv_data; + int err; + + HEADER("Picture Coding Extension"); + + ui(4, f_code[0][0]); + ui(4, f_code[0][1]); + ui(4, f_code[1][0]); + ui(4, f_code[1][1]); + + ui(2, intra_dc_precision); + ui(2, picture_structure); + ui(1, top_field_first); + ui(1, frame_pred_frame_dct); + ui(1, concealment_motion_vectors); + ui(1, q_scale_type); + ui(1, intra_vlc_format); + ui(1, alternate_scan); + ui(1, repeat_first_field); + ui(1, chroma_420_type); + ui(1, progressive_frame); + + if (mpeg2->progressive_sequence) { + if (current->repeat_first_field) { + if (current->top_field_first) + mpeg2->number_of_frame_centre_offsets = 3; + else + mpeg2->number_of_frame_centre_offsets = 2; + } else { + mpeg2->number_of_frame_centre_offsets = 1; + } + } else { + if (current->picture_structure == 1 || // Top field. + current->picture_structure == 2) { // Bottom field. + mpeg2->number_of_frame_centre_offsets = 1; + } else { + if (current->repeat_first_field) + mpeg2->number_of_frame_centre_offsets = 3; + else + mpeg2->number_of_frame_centre_offsets = 2; + } + } + + ui(1, composite_display_flag); + if (current->composite_display_flag) { + ui(1, v_axis); + ui(3, field_sequence); + ui(1, sub_carrier); + ui(7, burst_amplitude); + ui(8, sub_carrier_phase); + } + + return 0; +} + +static int FUNC(quant_matrix_extension)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawQuantMatrixExtension *current) +{ + int err, i; + + HEADER("Quant Matrix Extension"); + + ui(1, load_intra_quantiser_matrix); + if (current->load_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) + ui(8, intra_quantiser_matrix[i]); + } + + ui(1, load_non_intra_quantiser_matrix); + if (current->load_non_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) + ui(8, non_intra_quantiser_matrix[i]); + } + + ui(1, load_chroma_intra_quantiser_matrix); + if (current->load_chroma_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) + ui(8, intra_quantiser_matrix[i]); + } + + ui(1, load_chroma_non_intra_quantiser_matrix); + if (current->load_chroma_non_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) + ui(8, chroma_non_intra_quantiser_matrix[i]); + } + + return 0; +} + +static int FUNC(picture_display_extension)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawPictureDisplayExtension *current) +{ + CodedBitstreamMPEG2Context *mpeg2 = ctx->priv_data; + int err, i; + + HEADER("Picture Display Extension"); + + for (i = 0; i < mpeg2->number_of_frame_centre_offsets; i++) { + ui(16, frame_centre_horizontal_offset[i]); + marker_bit(); + ui(16, frame_centre_vertical_offset[i]); + marker_bit(); + } + + return 0; +} + +static int FUNC(extension_data)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawExtensionData *current) +{ + int err; + + HEADER("Extension Data"); + + ui(8, extension_start_code); + ui(4, extension_start_code_identifier); + + switch (current->extension_start_code_identifier) { + case 1: + return FUNC(sequence_extension) + (ctx, rw, ¤t->data.sequence); + case 2: + return FUNC(sequence_display_extension) + (ctx, rw, ¤t->data.sequence_display); + case 3: + return FUNC(quant_matrix_extension) + (ctx, rw, ¤t->data.quant_matrix); + case 7: + return FUNC(picture_display_extension) + (ctx, rw, ¤t->data.picture_display); + case 8: + return FUNC(picture_coding_extension) + (ctx, rw, ¤t->data.picture_coding); + default: + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid extension ID %d.\n", + current->extension_start_code_identifier); + return AVERROR_INVALIDDATA; + } +} + +static int FUNC(slice_header)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawSliceHeader *current) +{ + CodedBitstreamMPEG2Context *mpeg2 = ctx->priv_data; + int err; + + HEADER("Slice Header"); + + ui(8, slice_vertical_position); + + if (mpeg2->vertical_size > 2800) + ui(3, slice_vertical_position_extension); + if (mpeg2->scalable) { + if (mpeg2->scalable_mode == 0) + ui(7, priority_breakpoint); + } + + ui(5, quantiser_scale_code); + + if (nextbits(1, 1, current->slice_extension_flag)) { + ui(1, slice_extension_flag); + ui(1, intra_slice); + ui(1, slice_picture_id_enable); + ui(6, slice_picture_id); + + { + size_t k; +#ifdef READ + GetBitContext start; + uint8_t bit; + start = *rw; + for (k = 0; nextbits(1, 1, bit); k++) + skip_bits(rw, 8); + current->extra_information_length = k; + if (k > 0) { + *rw = start; + current->extra_information = + av_malloc(current->extra_information_length); + if (!current->extra_information) + return AVERROR(ENOMEM); + for (k = 0; k < current->extra_information_length; k++) { + xui(1, extra_bit_slice, bit); + xui(8, extra_information_slice, + current->extra_information[k]); + } + } +#else + for (k = 0; k < current->extra_information_length; k++) { + xui(1, extra_bit_slice, 1); + xui(8, extra_information_slice, current->extra_information[k]); + } +#endif + } + } + ui(1, extra_bit_slice); + + return 0; +} |