mirror of https://github.com/FFmpeg/FFmpeg.git
(cherry picked from commitpull/272/head2bc9ba8d3c
) (cherry picked from commita41b69b5eb
)
parent
9b0c7aa0e4
commit
686e388bbb
8 changed files with 1030 additions and 0 deletions
@ -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, |
||||
}; |
@ -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 */ |
@ -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; |
||||
} |
Loading…
Reference in new issue