/* * Copyright (c) 2019, Alliance for Open Media. All rights reserved. * * This source code is subject to the terms of the BSD 2 Clause License and * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License * was not distributed with this source code in the LICENSE file, you can * obtain it at www.aomedia.org/license/software. If the Alliance for Open * Media Patent License 1.0 was not distributed with this source code in the * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
staticconstchar *level_fail_messages[TARGET_LEVEL_FAIL_IDS] = { "The picture size is too large.", "The picture width is too large.", "The picture height is too large.", "The picture width is too small.", "The picture height is too small.", "Too many tile columns are used.", "Too many tiles are used.", "The tile rate is too high.", "The tile size is too large.", "The superres tile width is too large.", "The cropped tile width is less than 8.", "The cropped tile height is less than 8.", "The tile width is invalid.", "The frame header rate is too high.", "The display luma sample rate is too high.", "The decoded luma sample rate is too high.", "The compression ratio is too small.", "The product of max tile size and header rate is too high.", "The bitrate is too high.", "The decoder model fails.",
};
// We assume time t to be valid if and only if t >= 0.0. // So INVALID_TIME can be defined as anything less than 0. #define INVALID_TIME (-1.0)
// This corresponds to "free_buffer" in the spec. staticvoid release_buffer(DECODER_MODEL *const decoder_model, int idx) {
assert(idx >= 0 && idx < BUFFER_POOL_MAX_SIZE);
FRAME_BUFFER *const this_buffer = &decoder_model->frame_buffer_pool[idx];
this_buffer->decoder_ref_count = 0;
this_buffer->player_ref_count = 0;
this_buffer->display_index = -1;
this_buffer->presentation_time = INVALID_TIME;
}
staticvoid initialize_buffer_pool(DECODER_MODEL *const decoder_model) { for (int i = 0; i < BUFFER_POOL_MAX_SIZE; ++i) {
release_buffer(decoder_model, i);
} for (int i = 0; i < REF_FRAMES; ++i) {
decoder_model->vbi[i] = -1;
}
}
staticint get_free_buffer(DECODER_MODEL *const decoder_model) { for (int i = 0; i < BUFFER_POOL_MAX_SIZE; ++i) { const FRAME_BUFFER *const this_buffer =
&decoder_model->frame_buffer_pool[i]; if (this_buffer->decoder_ref_count == 0 &&
this_buffer->player_ref_count == 0) return i;
} return -1;
}
staticvoid update_ref_buffers(DECODER_MODEL *const decoder_model, int idx, int refresh_frame_flags) {
FRAME_BUFFER *const this_buffer = &decoder_model->frame_buffer_pool[idx]; for (int i = 0; i < REF_FRAMES; ++i) { if (refresh_frame_flags & (1 << i)) { constint pre_idx = decoder_model->vbi[i]; if (pre_idx != -1) {
--decoder_model->frame_buffer_pool[pre_idx].decoder_ref_count;
}
decoder_model->vbi[i] = idx;
++this_buffer->decoder_ref_count;
}
}
}
// The time (in seconds) required to decode a frame. staticdouble time_to_decode_frame(const AV1_COMMON *const cm,
int64_t max_decode_rate) { if (cm->show_existing_frame) return 0.0;
// Release frame buffers that are no longer needed for decode or display. // It corresponds to "start_decode_at_removal_time" in the spec. staticvoid release_processed_frames(DECODER_MODEL *const decoder_model, double removal_time) { for (int i = 0; i < BUFFER_POOL_MAX_SIZE; ++i) {
FRAME_BUFFER *const this_buffer = &decoder_model->frame_buffer_pool[i]; if (this_buffer->player_ref_count > 0) { if (this_buffer->presentation_time >= 0.0 &&
this_buffer->presentation_time <= removal_time) {
this_buffer->player_ref_count = 0; if (this_buffer->decoder_ref_count == 0) {
release_buffer(decoder_model, i);
}
}
}
}
}
staticint frames_in_buffer_pool(const DECODER_MODEL *const decoder_model) { int frames_in_pool = 0; for (int i = 0; i < BUFFER_POOL_MAX_SIZE; ++i) { const FRAME_BUFFER *const this_buffer =
&decoder_model->frame_buffer_pool[i]; if (this_buffer->decoder_ref_count > 0 ||
this_buffer->player_ref_count > 0) {
++frames_in_pool;
}
} return frames_in_pool;
}
staticdouble get_presentation_time(const DECODER_MODEL *const decoder_model, int display_index) { if (decoder_model->mode == SCHEDULE_MODE) {
assert(0 && "SCHEDULE_MODE NOT SUPPORTED"); return INVALID_TIME;
} else { constdouble initial_presentation_delay =
decoder_model->initial_presentation_delay; // Can't decide presentation time until the initial presentation delay is // known. if (initial_presentation_delay < 0.0) return INVALID_TIME;
if (!decoder_model || decoder_model->status != DECODER_MODEL_OK) { return status;
}
const AV1_COMMON *const cm = &cpi->common; constint show_existing_frame = cm->show_existing_frame;
size_t cur_coded_bits = decoder_model->coded_bits + coded_bits; int num_decoded_frame = decoder_model->num_decoded_frame; if (!show_existing_frame) ++num_decoded_frame;
if (show_existing_frame) { return status;
} else { constdouble removal_time = get_removal_time(
decoder_model->mode, num_decoded_frame,
decoder_model->decoder_buffer_delay, decoder_model->frame_buffer_pool,
decoder_model->current_time); if (removal_time < 0.0) {
status = DECODE_FRAME_BUF_UNAVAILABLE; return status;
}
// A frame with show_existing_frame being false indicates the end of a DFG. // Update the bits arrival time of this DFG. constdouble buffer_delay = (decoder_model->encoder_buffer_delay +
decoder_model->decoder_buffer_delay) /
90000.0; constdouble latest_arrival_time = removal_time - buffer_delay; constdouble first_bit_arrival_time =
AOMMAX(decoder_model->last_bit_arrival_time, latest_arrival_time); constdouble last_bit_arrival_time =
first_bit_arrival_time +
(double)cur_coded_bits / decoder_model->bit_rate; // Smoothing buffer underflows if the last bit arrives after the removal // time. if (last_bit_arrival_time > removal_time &&
!decoder_model->is_low_delay_mode) {
status = SMOOTHING_BUFFER_UNDERFLOW; return status;
}
// Check if the smoothing buffer overflows. const DFG_INTERVAL_QUEUE *const queue = &decoder_model->dfg_interval_queue; if (queue->size >= DFG_INTERVAL_QUEUE_SIZE) {
assert(0);
}
double total_interval = queue->total_interval; int qhead = queue->head; int qsize = queue->size; // Remove the DFGs with removal time earlier than last_bit_arrival_time. while (queue->buf[qhead].removal_time <= last_bit_arrival_time &&
qsize > 0) { if (queue->buf[qhead].removal_time - first_bit_arrival_time +
total_interval >
1.0) {
status = SMOOTHING_BUFFER_OVERFLOW; return status;
}
total_interval -= queue->buf[qhead].last_bit_arrival_time -
queue->buf[qhead].first_bit_arrival_time;
qhead = (qhead + 1) % DFG_INTERVAL_QUEUE_SIZE;
--qsize;
}
total_interval += last_bit_arrival_time - first_bit_arrival_time; // The smoothing buffer can hold at most "bit_rate" bits, which is // equivalent to 1 second of total interval. if (total_interval > 1.0) {
status = SMOOTHING_BUFFER_OVERFLOW; return status;
}
// A frame with show_existing_frame being false indicates the end of a DFG. // Update the bits arrival time of this DFG. constdouble buffer_delay = (decoder_model->encoder_buffer_delay +
decoder_model->decoder_buffer_delay) /
90000.0; constdouble latest_arrival_time = removal_time - buffer_delay;
decoder_model->first_bit_arrival_time =
AOMMAX(decoder_model->last_bit_arrival_time, latest_arrival_time);
decoder_model->last_bit_arrival_time =
decoder_model->first_bit_arrival_time +
(double)decoder_model->coded_bits / decoder_model->bit_rate; // Smoothing buffer underflows if the last bit arrives after the removal // time. if (decoder_model->last_bit_arrival_time > removal_time &&
!decoder_model->is_low_delay_mode) {
decoder_model->status = SMOOTHING_BUFFER_UNDERFLOW; return;
} // Reset the coded bits for the next DFG.
decoder_model->coded_bits = 0;
// Check if the smoothing buffer overflows.
DFG_INTERVAL_QUEUE *const queue = &decoder_model->dfg_interval_queue; if (queue->size >= DFG_INTERVAL_QUEUE_SIZE) {
assert(0);
} constdouble first_bit_arrival_time = decoder_model->first_bit_arrival_time; constdouble last_bit_arrival_time = decoder_model->last_bit_arrival_time; // Remove the DFGs with removal time earlier than last_bit_arrival_time. while (queue->buf[queue->head].removal_time <= last_bit_arrival_time &&
queue->size > 0) { if (queue->buf[queue->head].removal_time - first_bit_arrival_time +
queue->total_interval >
1.0) {
decoder_model->status = SMOOTHING_BUFFER_OVERFLOW; return;
}
queue->total_interval -= queue->buf[queue->head].last_bit_arrival_time -
queue->buf[queue->head].first_bit_arrival_time;
queue->head = (queue->head + 1) % DFG_INTERVAL_QUEUE_SIZE;
--queue->size;
} // Push current DFG into the queue. constint queue_index =
(queue->head + queue->size++) % DFG_INTERVAL_QUEUE_SIZE;
queue->buf[queue_index].first_bit_arrival_time = first_bit_arrival_time;
queue->buf[queue_index].last_bit_arrival_time = last_bit_arrival_time;
queue->buf[queue_index].removal_time = removal_time;
queue->total_interval += last_bit_arrival_time - first_bit_arrival_time; // The smoothing buffer can hold at most "bit_rate" bits, which is // equivalent to 1 second of total interval. if (queue->total_interval > 1.0) {
decoder_model->status = SMOOTHING_BUFFER_OVERFLOW; return;
}
if (decoder_model->initial_presentation_delay < 0.0) { // Display can begin after required number of frames have been buffered. if (frames_in_buffer_pool(decoder_model) >=
decoder_model->initial_display_delay - 1) {
decoder_model->initial_presentation_delay = decoder_model->current_time; // Update presentation time for each shown frame in the frame buffer. for (int i = 0; i < BUFFER_POOL_MAX_SIZE; ++i) {
FRAME_BUFFER *const this_buffer =
&decoder_model->frame_buffer_pool[i]; if (this_buffer->player_ref_count == 0) continue;
assert(this_buffer->display_index >= 0);
this_buffer->presentation_time =
get_presentation_time(decoder_model, this_buffer->display_index);
}
}
}
}
if (level_spec->max_h_size > target_level_spec->max_h_size) {
fail_id = LUMA_PIC_H_SIZE_TOO_LARGE; break;
}
if (level_spec->max_v_size > target_level_spec->max_v_size) {
fail_id = LUMA_PIC_V_SIZE_TOO_LARGE; break;
}
if (level_spec->max_tile_cols > target_level_spec->max_tile_cols) {
fail_id = TOO_MANY_TILE_COLUMNS; break;
}
if (level_spec->max_tiles > target_level_spec->max_tiles) {
fail_id = TOO_MANY_TILES; break;
}
if (level_spec->max_header_rate > target_level_spec->max_header_rate) {
fail_id = FRAME_HEADER_RATE_TOO_HIGH; break;
}
if (decoder_model->max_display_rate >
(double)target_level_spec->max_display_rate) {
fail_id = DISPLAY_RATE_TOO_HIGH; break;
}
// TODO(huisu): we are not using max decode rate calculated by the decoder // model because the model in resource availability mode always returns // MaxDecodeRate(as in the level definitions) as the max decode rate. if (level_spec->max_decode_rate > target_level_spec->max_decode_rate) {
fail_id = DECODE_RATE_TOO_HIGH; break;
}
// Count the number of frames encoded in the last "duration" ticks, in display // time. staticint count_frames(const FrameWindowBuffer *const buffer,
int64_t duration) { constint current_idx = (buffer->start + buffer->num - 1) % FRAME_WINDOW_SIZE; // Assume current frame is shown frame.
assert(buffer->buf[current_idx].show_frame);
const int64_t current_time = buffer->buf[current_idx].ts_end; const int64_t time_limit = AOMMAX(current_time - duration, 0); int num_frames = 1; int index = current_idx - 1; for (int i = buffer->num - 2; i >= 0; --i, --index, ++num_frames) { if (index < 0) index = FRAME_WINDOW_SIZE - 1; const FrameRecord *const record = &buffer->buf[index]; if (!record->show_frame) continue; const int64_t ts_start = record->ts_start; if (ts_start < time_limit) break;
}
return num_frames;
}
// Scan previously encoded frames and update level metrics accordingly. staticvoid scan_past_frames(const FrameWindowBuffer *const buffer, int num_frames_to_scan,
AV1LevelSpec *const level_spec,
AV1LevelStats *const level_stats) { constint num_frames_in_buffer = buffer->num; int index = (buffer->start + num_frames_in_buffer - 1) % FRAME_WINDOW_SIZE; int frame_headers = 0; int tiles = 0;
int64_t display_samples = 0;
int64_t decoded_samples = 0;
size_t encoded_size_in_bytes = 0; for (int i = 0; i < AOMMIN(num_frames_in_buffer, num_frames_to_scan); ++i) { const FrameRecord *const record = &buffer->buf[index]; if (!record->show_existing_frame) {
frame_headers += record->frame_header_count;
decoded_samples += record->pic_size;
} if (record->show_frame) {
display_samples += record->pic_size;
}
tiles += record->tiles;
encoded_size_in_bytes += record->encoded_size_in_bytes;
--index; if (index < 0) index = FRAME_WINDOW_SIZE - 1;
}
level_spec->max_header_rate =
AOMMAX(level_spec->max_header_rate, frame_headers); // TODO(huisu): we can now compute max display rate with the decoder model, so // these couple of lines can be removed. Keep them here for a while for // debugging purpose.
level_spec->max_display_rate =
AOMMAX(level_spec->max_display_rate, display_samples);
level_spec->max_decode_rate =
AOMMAX(level_spec->max_decode_rate, decoded_samples);
level_spec->max_tile_rate = AOMMAX(level_spec->max_tile_rate, tiles);
level_stats->max_bitrate =
AOMMAX(level_stats->max_bitrate,
(int)AOMMIN(encoded_size_in_bytes * 8, (size_t)INT_MAX));
}
int max_tile_size; int min_cropped_tile_width; int min_cropped_tile_height; int max_superres_tile_width; int tile_width_is_valid;
get_tile_stats(cm, cpi->tile_data, &max_tile_size, &max_superres_tile_width,
&min_cropped_tile_width, &min_cropped_tile_height,
&tile_width_is_valid);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.