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