You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-11-23 21:54:53 +02:00
Don't overwrite the bitstream values when updating the top-level loop filter and segmentation state, instead do the update separately at the end of the frame parsing. This also reverts the change to the passthrough tests which made them have output not matching the input.
487 lines
15 KiB
C
487 lines
15 KiB
C
/*
|
|
* 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(frame_sync_code)(CodedBitstreamContext *ctx, RWContext *rw,
|
|
VP9RawFrameHeader *current)
|
|
{
|
|
int err;
|
|
|
|
fixed(8, frame_sync_byte_0, VP9_FRAME_SYNC_0);
|
|
fixed(8, frame_sync_byte_1, VP9_FRAME_SYNC_1);
|
|
fixed(8, frame_sync_byte_2, VP9_FRAME_SYNC_2);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int FUNC(color_config)(CodedBitstreamContext *ctx, RWContext *rw,
|
|
VP9RawFrameHeader *current, int profile)
|
|
{
|
|
CodedBitstreamVP9Context *vp9 = ctx->priv_data;
|
|
int err;
|
|
|
|
if (profile >= 2) {
|
|
f(1, ten_or_twelve_bit);
|
|
vp9->bit_depth = current->ten_or_twelve_bit ? 12 : 10;
|
|
} else
|
|
vp9->bit_depth = 8;
|
|
|
|
f(3, color_space);
|
|
|
|
if (current->color_space != VP9_CS_RGB) {
|
|
f(1, color_range);
|
|
if (profile == 1 || profile == 3) {
|
|
f(1, subsampling_x);
|
|
f(1, subsampling_y);
|
|
fixed(1, reserved_zero, 0);
|
|
} else {
|
|
infer(subsampling_x, 1);
|
|
infer(subsampling_y, 1);
|
|
}
|
|
} else {
|
|
infer(color_range, 1);
|
|
if (profile == 1 || profile == 3) {
|
|
infer(subsampling_x, 0);
|
|
infer(subsampling_y, 0);
|
|
fixed(1, reserved_zero, 0);
|
|
}
|
|
}
|
|
|
|
vp9->subsampling_x = current->subsampling_x;
|
|
vp9->subsampling_y = current->subsampling_y;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int FUNC(frame_size)(CodedBitstreamContext *ctx, RWContext *rw,
|
|
VP9RawFrameHeader *current)
|
|
{
|
|
CodedBitstreamVP9Context *vp9 = ctx->priv_data;
|
|
int err;
|
|
|
|
f(16, frame_width_minus_1);
|
|
f(16, frame_height_minus_1);
|
|
|
|
vp9->frame_width = current->frame_width_minus_1 + 1;
|
|
vp9->frame_height = current->frame_height_minus_1 + 1;
|
|
|
|
vp9->mi_cols = (vp9->frame_width + 7) >> 3;
|
|
vp9->mi_rows = (vp9->frame_height + 7) >> 3;
|
|
vp9->sb64_cols = (vp9->mi_cols + 7) >> 3;
|
|
vp9->sb64_rows = (vp9->mi_rows + 7) >> 3;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int FUNC(render_size)(CodedBitstreamContext *ctx, RWContext *rw,
|
|
VP9RawFrameHeader *current)
|
|
{
|
|
int err;
|
|
|
|
f(1, render_and_frame_size_different);
|
|
|
|
if (current->render_and_frame_size_different) {
|
|
f(16, render_width_minus_1);
|
|
f(16, render_height_minus_1);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int FUNC(frame_size_with_refs)(CodedBitstreamContext *ctx, RWContext *rw,
|
|
VP9RawFrameHeader *current)
|
|
{
|
|
CodedBitstreamVP9Context *vp9 = ctx->priv_data;
|
|
int err, i;
|
|
|
|
for (i = 0; i < VP9_REFS_PER_FRAME; i++) {
|
|
fs(1, found_ref[i], 1, i);
|
|
if (current->found_ref[i]) {
|
|
VP9ReferenceFrameState *ref =
|
|
&vp9->ref[current->ref_frame_idx[i]];
|
|
|
|
vp9->frame_width = ref->frame_width;
|
|
vp9->frame_height = ref->frame_height;
|
|
|
|
vp9->subsampling_x = ref->subsampling_x;
|
|
vp9->subsampling_y = ref->subsampling_y;
|
|
vp9->bit_depth = ref->bit_depth;
|
|
|
|
break;
|
|
}
|
|
}
|
|
if (i >= VP9_REFS_PER_FRAME)
|
|
CHECK(FUNC(frame_size)(ctx, rw, current));
|
|
else {
|
|
vp9->mi_cols = (vp9->frame_width + 7) >> 3;
|
|
vp9->mi_rows = (vp9->frame_height + 7) >> 3;
|
|
vp9->sb64_cols = (vp9->mi_cols + 7) >> 3;
|
|
vp9->sb64_rows = (vp9->mi_rows + 7) >> 3;
|
|
}
|
|
CHECK(FUNC(render_size)(ctx, rw, current));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int FUNC(interpolation_filter)(CodedBitstreamContext *ctx, RWContext *rw,
|
|
VP9RawFrameHeader *current)
|
|
{
|
|
int err;
|
|
|
|
f(1, is_filter_switchable);
|
|
if (!current->is_filter_switchable)
|
|
f(2, raw_interpolation_filter_type);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int FUNC(loop_filter_params)(CodedBitstreamContext *ctx, RWContext *rw,
|
|
VP9RawFrameHeader *current)
|
|
{
|
|
int err, i;
|
|
|
|
f(6, loop_filter_level);
|
|
f(3, loop_filter_sharpness);
|
|
|
|
f(1, loop_filter_delta_enabled);
|
|
if (current->loop_filter_delta_enabled) {
|
|
f(1, loop_filter_delta_update);
|
|
if (current->loop_filter_delta_update) {
|
|
for (i = 0; i < VP9_MAX_REF_FRAMES; i++) {
|
|
fs(1, update_ref_delta[i], 1, i);
|
|
if (current->update_ref_delta[i])
|
|
ss(6, loop_filter_ref_deltas[i], 1, i);
|
|
}
|
|
for (i = 0; i < 2; i++) {
|
|
fs(1, update_mode_delta[i], 1, i);
|
|
if (current->update_mode_delta[i])
|
|
ss(6, loop_filter_mode_deltas[i], 1, i);
|
|
}
|
|
}
|
|
} else {
|
|
infer(loop_filter_delta_update, 0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int FUNC(quantization_params)(CodedBitstreamContext *ctx, RWContext *rw,
|
|
VP9RawFrameHeader *current)
|
|
{
|
|
int err;
|
|
|
|
f(8, base_q_idx);
|
|
|
|
delta_q(delta_q_y_dc);
|
|
delta_q(delta_q_uv_dc);
|
|
delta_q(delta_q_uv_ac);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int FUNC(segmentation_params)(CodedBitstreamContext *ctx, RWContext *rw,
|
|
VP9RawFrameHeader *current)
|
|
{
|
|
static const uint8_t segmentation_feature_bits[VP9_SEG_LVL_MAX] = { 8, 6, 2, 0 };
|
|
static const uint8_t segmentation_feature_signed[VP9_SEG_LVL_MAX] = { 1, 1, 0, 0 };
|
|
int err, i, j;
|
|
|
|
f(1, segmentation_enabled);
|
|
|
|
if (current->segmentation_enabled) {
|
|
f(1, segmentation_update_map);
|
|
if (current->segmentation_update_map) {
|
|
for (i = 0; i < 7; i++)
|
|
prob(segmentation_tree_probs[i], 1, i);
|
|
f(1, segmentation_temporal_update);
|
|
for (i = 0; i < 3; i++) {
|
|
if (current->segmentation_temporal_update)
|
|
prob(segmentation_pred_prob[i], 1, i);
|
|
else
|
|
infer(segmentation_pred_prob[i], 255);
|
|
}
|
|
}
|
|
|
|
f(1, segmentation_update_data);
|
|
if (current->segmentation_update_data) {
|
|
f(1, segmentation_abs_or_delta_update);
|
|
for (i = 0; i < VP9_MAX_SEGMENTS; i++) {
|
|
for (j = 0; j < VP9_SEG_LVL_MAX; j++) {
|
|
fs(1, feature_enabled[i][j], 2, i, j);
|
|
if (current->feature_enabled[i][j] &&
|
|
segmentation_feature_bits[j]) {
|
|
fs(segmentation_feature_bits[j],
|
|
feature_value[i][j], 2, i, j);
|
|
if (segmentation_feature_signed[j])
|
|
fs(1, feature_sign[i][j], 2, i, j);
|
|
else
|
|
infer(feature_sign[i][j], 0);
|
|
} else {
|
|
infer(feature_value[i][j], 0);
|
|
infer(feature_sign[i][j], 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
infer(segmentation_update_data, 0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int FUNC(tile_info)(CodedBitstreamContext *ctx, RWContext *rw,
|
|
VP9RawFrameHeader *current)
|
|
{
|
|
CodedBitstreamVP9Context *vp9 = ctx->priv_data;
|
|
int min_log2_tile_cols, max_log2_tile_cols;
|
|
int err;
|
|
|
|
min_log2_tile_cols = 0;
|
|
while ((VP9_MAX_TILE_WIDTH_B64 << min_log2_tile_cols) < vp9->sb64_cols)
|
|
++min_log2_tile_cols;
|
|
max_log2_tile_cols = 0;
|
|
while ((vp9->sb64_cols >> (max_log2_tile_cols + 1)) >= VP9_MIN_TILE_WIDTH_B64)
|
|
++max_log2_tile_cols;
|
|
|
|
increment(tile_cols_log2, min_log2_tile_cols, max_log2_tile_cols);
|
|
|
|
increment(tile_rows_log2, 0, 2);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int FUNC(uncompressed_header)(CodedBitstreamContext *ctx, RWContext *rw,
|
|
VP9RawFrameHeader *current)
|
|
{
|
|
CodedBitstreamVP9Context *vp9 = ctx->priv_data;
|
|
int err, i;
|
|
|
|
f(2, frame_marker);
|
|
|
|
f(1, profile_low_bit);
|
|
f(1, profile_high_bit);
|
|
vp9->profile = (current->profile_high_bit << 1) + current->profile_low_bit;
|
|
if (vp9->profile == 3)
|
|
fixed(1, reserved_zero, 0);
|
|
|
|
f(1, show_existing_frame);
|
|
if (current->show_existing_frame) {
|
|
f(3, frame_to_show_map_idx);
|
|
infer(header_size_in_bytes, 0);
|
|
infer(refresh_frame_flags, 0x00);
|
|
infer(loop_filter_level, 0);
|
|
return 0;
|
|
}
|
|
|
|
f(1, frame_type);
|
|
f(1, show_frame);
|
|
f(1, error_resilient_mode);
|
|
|
|
if (current->frame_type == VP9_KEY_FRAME) {
|
|
CHECK(FUNC(frame_sync_code)(ctx, rw, current));
|
|
CHECK(FUNC(color_config)(ctx, rw, current, vp9->profile));
|
|
CHECK(FUNC(frame_size)(ctx, rw, current));
|
|
CHECK(FUNC(render_size)(ctx, rw, current));
|
|
|
|
infer(refresh_frame_flags, 0xff);
|
|
|
|
} else {
|
|
if (current->show_frame == 0)
|
|
f(1, intra_only);
|
|
else
|
|
infer(intra_only, 0);
|
|
|
|
if (current->error_resilient_mode == 0)
|
|
f(2, reset_frame_context);
|
|
else
|
|
infer(reset_frame_context, 0);
|
|
|
|
if (current->intra_only == 1) {
|
|
CHECK(FUNC(frame_sync_code)(ctx, rw, current));
|
|
|
|
if (vp9->profile > 0) {
|
|
CHECK(FUNC(color_config)(ctx, rw, current, vp9->profile));
|
|
} else {
|
|
infer(color_space, 1);
|
|
infer(subsampling_x, 1);
|
|
infer(subsampling_y, 1);
|
|
vp9->bit_depth = 8;
|
|
|
|
vp9->subsampling_x = current->subsampling_x;
|
|
vp9->subsampling_y = current->subsampling_y;
|
|
}
|
|
|
|
f(8, refresh_frame_flags);
|
|
|
|
CHECK(FUNC(frame_size)(ctx, rw, current));
|
|
CHECK(FUNC(render_size)(ctx, rw, current));
|
|
} else {
|
|
f(8, refresh_frame_flags);
|
|
|
|
for (i = 0; i < VP9_REFS_PER_FRAME; i++) {
|
|
fs(3, ref_frame_idx[i], 1, i);
|
|
fs(1, ref_frame_sign_bias[VP9_LAST_FRAME + i],
|
|
1, VP9_LAST_FRAME + i);
|
|
}
|
|
|
|
CHECK(FUNC(frame_size_with_refs)(ctx, rw, current));
|
|
f(1, allow_high_precision_mv);
|
|
CHECK(FUNC(interpolation_filter)(ctx, rw, current));
|
|
}
|
|
}
|
|
|
|
if (current->error_resilient_mode == 0) {
|
|
f(1, refresh_frame_context);
|
|
f(1, frame_parallel_decoding_mode);
|
|
} else {
|
|
infer(refresh_frame_context, 0);
|
|
infer(frame_parallel_decoding_mode, 1);
|
|
}
|
|
|
|
f(2, frame_context_idx);
|
|
|
|
CHECK(FUNC(loop_filter_params)(ctx, rw, current));
|
|
CHECK(FUNC(quantization_params)(ctx, rw, current));
|
|
CHECK(FUNC(segmentation_params)(ctx, rw, current));
|
|
CHECK(FUNC(tile_info)(ctx, rw, current));
|
|
|
|
f(16, header_size_in_bytes);
|
|
|
|
for (i = 0; i < VP9_NUM_REF_FRAMES; i++) {
|
|
if (current->refresh_frame_flags & (1 << i)) {
|
|
vp9->ref[i] = (VP9ReferenceFrameState) {
|
|
.frame_width = vp9->frame_width,
|
|
.frame_height = vp9->frame_height,
|
|
.subsampling_x = vp9->subsampling_x,
|
|
.subsampling_y = vp9->subsampling_y,
|
|
.bit_depth = vp9->bit_depth,
|
|
};
|
|
}
|
|
}
|
|
|
|
// Update top-level loop filter and segmentation state with changes
|
|
// from this frame.
|
|
if (current->frame_type == VP9_KEY_FRAME ||
|
|
current->intra_only ||
|
|
current->error_resilient_mode) {
|
|
// setup_past_independence() - fill with the initial values.
|
|
|
|
vp9->loop_filter_ref_deltas[VP9_INTRA_FRAME] = 1;
|
|
vp9->loop_filter_ref_deltas[VP9_LAST_FRAME] = 0;
|
|
vp9->loop_filter_ref_deltas[VP9_GOLDEN_FRAME] = -1;
|
|
vp9->loop_filter_ref_deltas[VP9_ALTREF_FRAME] = -1;
|
|
|
|
vp9->loop_filter_mode_deltas[0] = 0;
|
|
vp9->loop_filter_mode_deltas[1] = 0;
|
|
|
|
memset(vp9->feature_enabled, 0, sizeof(vp9->feature_enabled));
|
|
memset(vp9->feature_value, 0, sizeof(vp9->feature_value));
|
|
memset(vp9->feature_sign, 0, sizeof(vp9->feature_sign));
|
|
|
|
} else {
|
|
// Modify previous state based on updates in this frame.
|
|
|
|
if (current->loop_filter_delta_update) {
|
|
for (i = 0; i < 4; i++) {
|
|
if (current->update_ref_delta[i])
|
|
vp9->loop_filter_ref_deltas[i] =
|
|
current->loop_filter_ref_deltas[i];
|
|
}
|
|
for (i = 0; i < 2; i++) {
|
|
if (current->update_mode_delta[i])
|
|
vp9->loop_filter_mode_deltas[i] =
|
|
current->loop_filter_mode_deltas[i];
|
|
}
|
|
}
|
|
|
|
if (current->segmentation_update_data) {
|
|
memcpy(vp9->feature_enabled, current->feature_enabled,
|
|
sizeof(vp9->feature_enabled));
|
|
memcpy(vp9->feature_value, current->feature_value,
|
|
sizeof(vp9->feature_value));
|
|
memcpy(vp9->feature_sign, current->feature_sign,
|
|
sizeof(vp9->feature_sign));
|
|
|
|
if (current->segmentation_update_map) {
|
|
memcpy(vp9->segmentation_tree_probs,
|
|
current->segmentation_tree_probs,
|
|
sizeof(vp9->segmentation_tree_probs));
|
|
memcpy(vp9->segmentation_pred_prob,
|
|
current->segmentation_pred_prob,
|
|
sizeof(vp9->segmentation_pred_prob));
|
|
}
|
|
}
|
|
}
|
|
|
|
av_log(ctx->log_ctx, AV_LOG_DEBUG, "Frame: size %dx%d "
|
|
"subsample %dx%d bit_depth %d tiles %dx%d.\n",
|
|
vp9->frame_width, vp9->frame_height,
|
|
vp9->subsampling_x, vp9->subsampling_y,
|
|
vp9->bit_depth, 1 << current->tile_cols_log2,
|
|
1 << current->tile_rows_log2);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int FUNC(trailing_bits)(CodedBitstreamContext *ctx, RWContext *rw)
|
|
{
|
|
int err;
|
|
while (byte_alignment(rw) != 0)
|
|
fixed(1, zero_bit, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int FUNC(frame)(CodedBitstreamContext *ctx, RWContext *rw,
|
|
VP9RawFrame *current)
|
|
{
|
|
int err;
|
|
|
|
HEADER("Frame");
|
|
|
|
CHECK(FUNC(uncompressed_header)(ctx, rw, ¤t->header));
|
|
|
|
CHECK(FUNC(trailing_bits)(ctx, rw));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int FUNC(superframe_index)(CodedBitstreamContext *ctx, RWContext *rw,
|
|
VP9RawSuperframeIndex *current)
|
|
{
|
|
int err, i;
|
|
|
|
HEADER("Superframe Index");
|
|
|
|
f(3, superframe_marker);
|
|
f(2, bytes_per_framesize_minus_1);
|
|
f(3, frames_in_superframe_minus_1);
|
|
|
|
for (i = 0; i <= current->frames_in_superframe_minus_1; i++) {
|
|
// Surprise little-endian!
|
|
fle(8 * (current->bytes_per_framesize_minus_1 + 1),
|
|
frame_sizes[i], 1, i);
|
|
}
|
|
|
|
f(3, superframe_marker);
|
|
f(2, bytes_per_framesize_minus_1);
|
|
f(3, frames_in_superframe_minus_1);
|
|
|
|
return 0;
|
|
}
|