mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2024-12-25 00:32:31 +00:00
avformat/av1: update ff_isom_write_av1c() to the latest revision of the spec
This will get ISOBMFF and Matroska up to date with the revised AV1 Codec Configuration Box spec. For now keep propagating raw OBUs as extradata until all libavcodec modules are adapted to handle AV1CodecConfigurationRecord formatted extradata. Tested-by: Thomas Daede <bztdlinux@gmail.com> Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
parent
96a7099f3e
commit
8d5604a69a
@ -22,6 +22,8 @@
|
||||
#include "libavutil/mem.h"
|
||||
#include "libavcodec/av1.h"
|
||||
#include "libavcodec/av1_parse.h"
|
||||
#include "libavcodec/profiles.h"
|
||||
#include "libavcodec/put_bits.h"
|
||||
#include "av1.h"
|
||||
#include "avio.h"
|
||||
|
||||
@ -73,9 +75,233 @@ int ff_av1_filter_obus_buf(const uint8_t *buf, uint8_t **out, int *size)
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef struct AV1SequenceParameters {
|
||||
uint8_t seq_profile;
|
||||
uint8_t seq_level_idx_0;
|
||||
uint8_t seq_tier_0;
|
||||
uint8_t high_bitdepth;
|
||||
uint8_t twelve_bit;
|
||||
uint8_t monochrome;
|
||||
uint8_t chroma_subsampling_x;
|
||||
uint8_t chroma_subsampling_y;
|
||||
uint8_t chroma_sample_position;
|
||||
} AV1SequenceParameters;
|
||||
|
||||
static inline void uvlc(GetBitContext *gb)
|
||||
{
|
||||
int leading_zeros = 0;
|
||||
|
||||
while (get_bits_left(gb)) {
|
||||
if (get_bits1(gb))
|
||||
break;
|
||||
leading_zeros++;
|
||||
}
|
||||
|
||||
if (leading_zeros >= 32)
|
||||
return;
|
||||
|
||||
skip_bits_long(gb, leading_zeros);
|
||||
}
|
||||
|
||||
static int parse_color_config(AV1SequenceParameters *seq_params, GetBitContext *gb)
|
||||
{
|
||||
int color_primaries, transfer_characteristics, matrix_coefficients;
|
||||
|
||||
seq_params->high_bitdepth = get_bits1(gb);
|
||||
if (seq_params->seq_profile == FF_PROFILE_AV1_PROFESSIONAL && seq_params->high_bitdepth)
|
||||
seq_params->twelve_bit = get_bits1(gb);
|
||||
else
|
||||
seq_params->twelve_bit = 0;
|
||||
|
||||
if (seq_params->seq_profile == FF_PROFILE_AV1_HIGH)
|
||||
seq_params->monochrome = 0;
|
||||
else
|
||||
seq_params->monochrome = get_bits1(gb);
|
||||
|
||||
if (get_bits1(gb)) { // color_description_present_flag
|
||||
color_primaries = get_bits(gb, 8);
|
||||
transfer_characteristics = get_bits(gb, 8);
|
||||
matrix_coefficients = get_bits(gb, 8);
|
||||
} else {
|
||||
color_primaries = AVCOL_PRI_UNSPECIFIED;
|
||||
transfer_characteristics = AVCOL_TRC_UNSPECIFIED;
|
||||
matrix_coefficients = AVCOL_SPC_UNSPECIFIED;
|
||||
}
|
||||
|
||||
if (seq_params->monochrome) {
|
||||
skip_bits1(gb); // color_range
|
||||
seq_params->chroma_subsampling_x = 1;
|
||||
seq_params->chroma_subsampling_y = 1;
|
||||
seq_params->chroma_sample_position = 0;
|
||||
return 0;
|
||||
} else if (color_primaries == AVCOL_PRI_BT709 &&
|
||||
transfer_characteristics == AVCOL_TRC_IEC61966_2_1 &&
|
||||
matrix_coefficients == AVCOL_SPC_RGB) {
|
||||
seq_params->chroma_subsampling_x = 0;
|
||||
seq_params->chroma_subsampling_y = 0;
|
||||
} else {
|
||||
skip_bits1(gb); // color_range
|
||||
|
||||
if (seq_params->seq_profile == FF_PROFILE_AV1_MAIN) {
|
||||
seq_params->chroma_subsampling_x = 1;
|
||||
seq_params->chroma_subsampling_y = 1;
|
||||
} else if (seq_params->seq_profile == FF_PROFILE_AV1_HIGH) {
|
||||
seq_params->chroma_subsampling_x = 0;
|
||||
seq_params->chroma_subsampling_y = 0;
|
||||
} else {
|
||||
if (seq_params->twelve_bit) {
|
||||
seq_params->chroma_subsampling_x = get_bits1(gb);
|
||||
if (seq_params->chroma_subsampling_x)
|
||||
seq_params->chroma_subsampling_y = get_bits1(gb);
|
||||
else
|
||||
seq_params->chroma_subsampling_y = 0;
|
||||
} else {
|
||||
seq_params->chroma_subsampling_x = 1;
|
||||
seq_params->chroma_subsampling_y = 0;
|
||||
}
|
||||
}
|
||||
if (seq_params->chroma_subsampling_x && seq_params->chroma_subsampling_y)
|
||||
seq_params->chroma_sample_position = get_bits(gb, 2);
|
||||
}
|
||||
|
||||
skip_bits1(gb); // separate_uv_delta_q
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_sequence_header(AV1SequenceParameters *seq_params, const uint8_t *buf, int size)
|
||||
{
|
||||
GetBitContext gb;
|
||||
int reduced_still_picture_header;
|
||||
int frame_width_bits_minus_1, frame_height_bits_minus_1;
|
||||
int size_bits, ret;
|
||||
|
||||
size_bits = get_obu_bit_length(buf, size, AV1_OBU_SEQUENCE_HEADER);
|
||||
if (size_bits < 0)
|
||||
return size_bits;
|
||||
|
||||
ret = init_get_bits(&gb, buf, size_bits);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
seq_params->seq_profile = get_bits(&gb, 3);
|
||||
|
||||
skip_bits1(&gb); // still_picture
|
||||
reduced_still_picture_header = get_bits1(&gb);
|
||||
|
||||
if (reduced_still_picture_header) {
|
||||
seq_params->seq_level_idx_0 = get_bits(&gb, 5);
|
||||
seq_params->seq_tier_0 = 0;
|
||||
} else {
|
||||
int initial_display_delay_present_flag, operating_points_cnt_minus_1;
|
||||
int decoder_model_info_present_flag, buffer_delay_length_minus_1;
|
||||
|
||||
if (get_bits1(&gb)) { // timing_info_present_flag
|
||||
skip_bits_long(&gb, 32); // num_units_in_display_tick
|
||||
skip_bits_long(&gb, 32); // time_scale
|
||||
|
||||
if (get_bits1(&gb)) // equal_picture_interval
|
||||
uvlc(&gb); // num_ticks_per_picture_minus_1
|
||||
|
||||
decoder_model_info_present_flag = get_bits1(&gb);
|
||||
if (decoder_model_info_present_flag) {
|
||||
buffer_delay_length_minus_1 = get_bits(&gb, 5);
|
||||
skip_bits_long(&gb, 32); // num_units_in_decoding_tick
|
||||
skip_bits(&gb, 10); // buffer_removal_time_length_minus_1 (5)
|
||||
// frame_presentation_time_length_minus_1 (5)
|
||||
}
|
||||
} else
|
||||
decoder_model_info_present_flag = 0;
|
||||
|
||||
initial_display_delay_present_flag = get_bits1(&gb);
|
||||
|
||||
operating_points_cnt_minus_1 = get_bits(&gb, 5);
|
||||
for (int i = 0; i <= operating_points_cnt_minus_1; i++) {
|
||||
int seq_level_idx, seq_tier;
|
||||
|
||||
skip_bits(&gb, 12); // operating_point_idc
|
||||
seq_level_idx = get_bits(&gb, 5);
|
||||
|
||||
if (seq_level_idx > 7)
|
||||
seq_tier = get_bits1(&gb);
|
||||
else
|
||||
seq_tier = 0;
|
||||
|
||||
if (decoder_model_info_present_flag) {
|
||||
if (get_bits1(&gb)) { // decoder_model_present_for_this_op
|
||||
skip_bits_long(&gb, buffer_delay_length_minus_1 + 1); // decoder_buffer_delay
|
||||
skip_bits_long(&gb, buffer_delay_length_minus_1 + 1); // encoder_buffer_delay
|
||||
skip_bits1(&gb); // low_delay_mode_flag
|
||||
}
|
||||
}
|
||||
|
||||
if (initial_display_delay_present_flag) {
|
||||
if (get_bits1(&gb)) // initial_display_delay_present_for_this_op
|
||||
skip_bits(&gb, 4); // initial_display_delay_minus_1
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
seq_params->seq_level_idx_0 = seq_level_idx;
|
||||
seq_params->seq_tier_0 = seq_tier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
frame_width_bits_minus_1 = get_bits(&gb, 4);
|
||||
frame_height_bits_minus_1 = get_bits(&gb, 4);
|
||||
|
||||
skip_bits(&gb, frame_width_bits_minus_1 + 1); // max_frame_width_minus_1
|
||||
skip_bits(&gb, frame_height_bits_minus_1 + 1); // max_frame_height_minus_1
|
||||
|
||||
if (!reduced_still_picture_header) {
|
||||
if (get_bits1(&gb)) // frame_id_numbers_present_flag
|
||||
skip_bits(&gb, 7); // delta_frame_id_length_minus_2 (4), additional_frame_id_length_minus_1 (3)
|
||||
}
|
||||
|
||||
skip_bits(&gb, 3); // use_128x128_superblock (1), enable_filter_intra (1), enable_intra_edge_filter (1)
|
||||
|
||||
if (!reduced_still_picture_header) {
|
||||
int enable_order_hint, seq_force_screen_content_tools;
|
||||
|
||||
skip_bits(&gb, 4); // enable_intraintra_compound (1), enable_masked_compound (1)
|
||||
// enable_warped_motion (1), enable_dual_filter (1)
|
||||
|
||||
enable_order_hint = get_bits1(&gb);
|
||||
if (enable_order_hint)
|
||||
skip_bits(&gb, 2); // enable_jnt_comp (1), enable_ref_frame_mvs (1)
|
||||
|
||||
if (get_bits1(&gb)) // seq_choose_screen_content_tools
|
||||
seq_force_screen_content_tools = 2;
|
||||
else
|
||||
seq_force_screen_content_tools = get_bits1(&gb);
|
||||
|
||||
if (seq_force_screen_content_tools) {
|
||||
if (!get_bits1(&gb)) // seq_choose_integer_mv
|
||||
skip_bits1(&gb); // seq_force_integer_mv
|
||||
}
|
||||
|
||||
if (enable_order_hint)
|
||||
skip_bits(&gb, 3); // order_hint_bits_minus_1
|
||||
}
|
||||
|
||||
skip_bits(&gb, 3); // enable_superres (1), enable_cdef (1), enable_restoration (1)
|
||||
|
||||
parse_color_config(seq_params, &gb);
|
||||
|
||||
skip_bits1(&gb); // film_grain_params_present
|
||||
|
||||
if (get_bits_left(&gb))
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size)
|
||||
{
|
||||
AVIOContext *seq_pb = NULL, *meta_pb = NULL;
|
||||
AV1SequenceParameters seq_params;
|
||||
PutBitContext pbc;
|
||||
uint8_t header[4];
|
||||
uint8_t *seq = NULL, *meta = NULL;
|
||||
int64_t obu_size;
|
||||
int start_pos, type, temporal_id, spatial_id;
|
||||
@ -106,6 +332,10 @@ int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size)
|
||||
ret = AVERROR_INVALIDDATA;
|
||||
goto fail;
|
||||
}
|
||||
ret = parse_sequence_header(&seq_params, buf + start_pos, obu_size);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
avio_write(seq_pb, buf, len);
|
||||
break;
|
||||
case AV1_OBU_METADATA:
|
||||
@ -127,6 +357,23 @@ int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size)
|
||||
ret = AVERROR_INVALIDDATA;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
init_put_bits(&pbc, header, sizeof(header));
|
||||
|
||||
put_bits(&pbc, 1, 1); // marker
|
||||
put_bits(&pbc, 7, 1); // version
|
||||
put_bits(&pbc, 3, seq_params.seq_profile);
|
||||
put_bits(&pbc, 5, seq_params.seq_level_idx_0);
|
||||
put_bits(&pbc, 1, seq_params.seq_tier_0);
|
||||
put_bits(&pbc, 1, seq_params.high_bitdepth);
|
||||
put_bits(&pbc, 1, seq_params.twelve_bit);
|
||||
put_bits(&pbc, 1, seq_params.monochrome);
|
||||
put_bits(&pbc, 1, seq_params.chroma_subsampling_x);
|
||||
put_bits(&pbc, 1, seq_params.chroma_subsampling_y);
|
||||
put_bits(&pbc, 2, seq_params.chroma_sample_position);
|
||||
flush_put_bits(&pbc);
|
||||
|
||||
avio_write(pb, header, sizeof(header));
|
||||
avio_write(pb, seq, seq_size);
|
||||
|
||||
meta_size = avio_close_dyn_buf(meta_pb, &meta);
|
||||
|
@ -2421,6 +2421,10 @@ static int matroska_parse_tracks(AVFormatContext *s)
|
||||
/* we don't need any value stored in CodecPrivate.
|
||||
make sure that it's not exported as extradata. */
|
||||
track->codec_priv.size = 0;
|
||||
} else if (codec_id == AV_CODEC_ID_AV1 && track->codec_priv.size) {
|
||||
/* For now, propagate only the OBUs, if any. Once libavcodec is
|
||||
updated to handle isobmff style extradata this can be removed. */
|
||||
extradata_offset = 4;
|
||||
}
|
||||
track->codec_priv.size -= extradata_offset;
|
||||
|
||||
|
@ -5190,27 +5190,25 @@ static int mov_read_tmcd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
|
||||
static int mov_read_av1c(MOVContext *c, AVIOContext *pb, MOVAtom atom)
|
||||
{
|
||||
AVStream *st;
|
||||
int ret, version;
|
||||
int ret;
|
||||
|
||||
if (c->fc->nb_streams < 1)
|
||||
return 0;
|
||||
st = c->fc->streams[c->fc->nb_streams - 1];
|
||||
|
||||
if (atom.size < 5) {
|
||||
if (atom.size < 4) {
|
||||
av_log(c->fc, AV_LOG_ERROR, "Empty AV1 Codec Configuration Box\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
|
||||
version = avio_r8(pb);
|
||||
if (version != 0) {
|
||||
av_log(c->fc, AV_LOG_WARNING, "Unknown AV1 Codec Configuration Box version %d\n", version);
|
||||
/* For now, propagate only the OBUs, if any. Once libavcodec is
|
||||
updated to handle isobmff style extradata this can be removed. */
|
||||
avio_skip(pb, 4);
|
||||
|
||||
if (atom.size == 4)
|
||||
return 0;
|
||||
}
|
||||
avio_skip(pb, 3); /* flags */
|
||||
|
||||
avio_skip(pb, 1); /* reserved, initial_presentation_delay_present, initial_presentation_delay_minus_one */
|
||||
|
||||
ret = ff_get_extradata(c->fc, st->codecpar, pb, atom.size - 5);
|
||||
ret = ff_get_extradata(c->fc, st->codecpar, pb, atom.size - 4);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -1170,9 +1170,6 @@ static int mov_write_av1c_tag(AVIOContext *pb, MOVTrack *track)
|
||||
|
||||
avio_wb32(pb, 0);
|
||||
ffio_wfourcc(pb, "av1C");
|
||||
avio_w8(pb, 0); /* version */
|
||||
avio_wb24(pb, 0); /* flags */
|
||||
avio_w8(pb, 0); /* reserved (3), initial_presentation_delay_present (1), initial_presentation_delay_minus_one/reserved (4) */
|
||||
ff_isom_write_av1c(pb, track->vos_data, track->vos_len);
|
||||
return update_size(pb, pos);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user