--- libavcodec/cbs.c | 1 + libavcodec/cbs_internal.h | 1 + libavcodec/cbs_mpeg2.c | 212 ++++++++++++++++++++++++++++ libavcodec/cbs_mpeg2.h | 165 ++++++++++++++++++++++ libavcodec/cbs_mpeg2_syntax.c | 318 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 697 insertions(+) create mode 100644 libavcodec/cbs_mpeg2.c create mode 100644 libavcodec/cbs_mpeg2.h create mode 100644 libavcodec/cbs_mpeg2_syntax.c
diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c index 998990996..81483fbb4 100644 --- a/libavcodec/cbs.c +++ b/libavcodec/cbs.c @@ -29,6 +29,7 @@ static const CodedBitstreamType *cbs_type_table[] = { &ff_cbs_type_h264, &ff_cbs_type_h265, + &ff_cbs_type_mpeg2, }; int ff_cbs_init(CodedBitstreamContext *ctx, diff --git a/libavcodec/cbs_internal.h b/libavcodec/cbs_internal.h index 337cc60da..c6c649a36 100644 --- a/libavcodec/cbs_internal.h +++ b/libavcodec/cbs_internal.h @@ -84,6 +84,7 @@ int ff_cbs_write_se(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 000000000..5a02858f9 --- /dev/null +++ b/libavcodec/cbs_mpeg2.c @@ -0,0 +1,212 @@ +/* + * This file is part of Libav. + * + * Libav 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. + * + * Libav 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 Libav; 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 && ctx->fatal_errors) \ + return err; \ + } while (0) + +#define FUNC3(rw, name) cbs_mpeg2_ ## rw ## _ ## name +#define FUNC2(rw, name) FUNC3(rw, name) +#define FUNC(name) FUNC2(READWRITE, name) + + +#define READ +#define READWRITE read +#define RWContext BitstreamContext + +#define ui(width, name) do { \ + uint32_t value = 0; \ + CHECK(ff_cbs_read_u(ctx, rw, width, #name, \ + &value, 0, (1 << width) - 1)); \ + current->name = value; \ + } while (0) + +#define marker_bit() do { \ + av_unused int one = 1; \ + CHECK(ff_cbs_read_u(ctx, rw, 1, "marker_bit", &one, 1, 1)); \ + } while (0) + +#define nextbits(width, compare, var) (var = bitstream_peek(rw, width), \ + var == (compare)) + +#include "cbs_mpeg2_syntax.c" + + +static int cbs_mpeg2_split_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int header) +{ + const uint8_t *start, *end; + uint32_t start_code = -1, next_start_code = -1; + int err, i; + + if (frag->nb_units != 0) + return AVERROR(EINVAL); + + 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); + + err = ff_cbs_insert_unit(ctx, frag, i, start_code & 0xff, NULL); + if (err < 0) + return err; + + if (end == frag->data + frag->data_size) + frag->units[i].data_size = end - (start - 1); + else + frag->units[i].data_size = (end - 4) - (start - 1); + + frag->units[i].data = av_malloc(frag->units[i].data_size); + if (!frag->units[i].data) + return AVERROR(ENOMEM); + memcpy(frag->units[i].data, start - 1, frag->units[i].data_size); + + 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) +{ + BitstreamContext bc; + int err; + + err = bitstream_init(&bc, unit->data, 8 * unit->data_size); + if (err < 0) + return err; + + if (unit->type >= 0x01 && unit->type <= 0xaf) { + MPEG2RawSlice *slice; + int pos, len; + + slice = av_mallocz(sizeof(*slice)); + if (!slice) + return AVERROR(ENOMEM); + err = cbs_mpeg2_read_slice_header(ctx, &bc, &slice->header); + if (err < 0) { + av_free(slice); + return err; + } + + return 0; + } + + 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, &bc, 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); + default: + av_log(ctx, AV_LOG_ERROR, "Unknown start code %02x.\n", + unit->type); + return AVERROR_INVALIDDATA; + } + + 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) +{ +} + +const CodedBitstreamType ff_cbs_type_mpeg2 = { + .codec_id = AV_CODEC_ID_MPEG2VIDEO, + + .priv_data_size = 1, //sizeof(CodedBitstreamMPEG2Context), + + .split_fragment = &cbs_mpeg2_split_fragment, + .read_unit = &cbs_mpeg2_read_unit, + .write_unit = NULL, //&cbs_mpeg2_write_unit, + .assemble_fragment = &cbs_mpeg2_assemble_fragment, + + .free_unit = &cbs_mpeg2_free_unit, +}; diff --git a/libavcodec/cbs_mpeg2.h b/libavcodec/cbs_mpeg2.h new file mode 100644 index 000000000..14376ffd2 --- /dev/null +++ b/libavcodec/cbs_mpeg2.h @@ -0,0 +1,165 @@ +/* + * This file is part of Libav. + * + * Libav 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. + * + * Libav 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 Libav; 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 <stdint.h> + + +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; +} 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 MPEG2RawExtensionData { + uint8_t extension_start_code; + uint8_t extension_start_code_identifier; + + union { + MPEG2RawSequenceExtension sequence; + MPEG2RawSequenceDisplayExtension sequence_display; + MPEG2RawPictureCodingExtension picture_coding; + MPEG2RawQuantMatrixExtension quant_matrix; + }; +} 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; +} MPEG2RawSliceHeader; + +typedef struct MPEG2RawSlice { + MPEG2RawSliceHeader header; + + uint8_t *data; + size_t data_size; + int data_bit_start; +} MPEG2RawSlice; + + +#endif /* AVCODEC_CBS_MPEG2_H */ diff --git a/libavcodec/cbs_mpeg2_syntax.c b/libavcodec/cbs_mpeg2_syntax.c new file mode 100644 index 000000000..7727fb45c --- /dev/null +++ b/libavcodec/cbs_mpeg2_syntax.c @@ -0,0 +1,318 @@ +/* + * This file is part of Libav. + * + * Libav 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. + * + * Libav 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 Libav; 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) +{ + int err, i; + + HEADER("Sequence Header"); + + ui(8, sequence_header_code); + + ui(12, horizontal_size_value); + ui(12, 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) +{ + int err; + + HEADER("User Data"); + + ui(8, user_data_start_code); + + return 0; +} + +static int FUNC(sequence_extension)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawSequenceExtension *current) +{ + 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); + 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) +{ + 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); + + 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(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->sequence); + case 2: + return FUNC(sequence_display_extension) + (ctx, rw, ¤t->sequence_display); + case 3: + return FUNC(quant_matrix_extension) + (ctx, rw, ¤t->quant_matrix); + /* + case 4: + return FUNC(copyright_extension) + (ctx, rw, ¤t->copyright); + case 5: + return FUNC(sequence_scalable_extension) + (ctx, rw, ¤t->sequence_scalable); + + case 7: + return FUNC(picture_display_extension) + (ctx, rw, ¤t->picture_display); + */ + case 8: + return FUNC(picture_coding_extension) + (ctx, rw, ¤t->picture_coding); + /* + case 9: + return FUNC(picture_spatial_scalable_extension) + (ctx, rw, ¤t->picture_spatial_scalable); + case 10: + return FUNC(picture_temporal_scalable_extension) + (ctx, rw, ¤t->picture_temporal_scalable); + case 11: + return FUNC(camera_parameters_extension) + (ctx, rw, ¤t->camera_parameters); + case 12: + return FUNC(itu_t_extension) + (ctx, rw, ¤t->itu_t); + */ + + default: + av_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; + int err; + + HEADER("Slice Header"); + + ui(8, slice_vertical_position); + + if (0 /*mpeg2->vertical_size > 2800*/) + ui(3, slice_vertical_position_extension); + if (0 /*mpeg2->scalable*/) { + if (0 /*mpeg2->scalable_mode == "data partitioning"*/) + 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); + + /* + for (i = 0; nextbits(1, 1, tmp); i++) { + ui(1, extra_bit_slice); + ui(8, extra_information_slice); + } + */ + } + ui(1, extra_bit_slice); + + return 0; +} -- 2.11.0 _______________________________________________ libav-devel mailing list libav-devel@libav.org https://lists.libav.org/mailman/listinfo/libav-devel