/* * Copyright (c) 2019 The WebM project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree.
*/
staticint get_plane_height(vpx_img_fmt_t img_fmt, int frame_height, int plane) {
assert(plane < 3); if (plane == 0) { return frame_height;
} switch (img_fmt) { case VPX_IMG_FMT_I420: case VPX_IMG_FMT_I440: case VPX_IMG_FMT_YV12: case VPX_IMG_FMT_I42016: case VPX_IMG_FMT_I44016: return (frame_height + 1) >> 1; default: return frame_height;
}
}
staticint get_plane_width(vpx_img_fmt_t img_fmt, int frame_width, int plane) {
assert(plane < 3); if (plane == 0) { return frame_width;
} switch (img_fmt) { case VPX_IMG_FMT_I420: case VPX_IMG_FMT_YV12: case VPX_IMG_FMT_I422: case VPX_IMG_FMT_I42016: case VPX_IMG_FMT_I42216: return (frame_width + 1) >> 1; default: return frame_width;
}
}
// TODO(angiebird): Merge this function with vpx_img_plane_width() staticint img_plane_width(const vpx_image_t *img, int plane) { if (plane > 0 && img->x_chroma_shift > 0) return (img->d_w + 1) >> img->x_chroma_shift; else return img->d_w;
}
// TODO(angiebird): Merge this function with vpx_img_plane_height() staticint img_plane_height(const vpx_image_t *img, int plane) { if (plane > 0 && img->y_chroma_shift > 0) return (img->d_h + 1) >> img->y_chroma_shift; else return img->d_h;
}
// TODO(angiebird): Merge this function with vpx_img_read() staticint img_read(vpx_image_t *img, FILE *file) { int plane;
for (plane = 0; plane < 3; ++plane) { unsignedchar *buf = img->planes[plane]; constint stride = img->stride[plane]; constint w = img_plane_width(img, plane) *
((img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1); constint h = img_plane_height(img, plane); int y;
for (y = 0; y < h; ++y) { if (fread(buf, 1, w, file) != (size_t)w) return 0;
buf += stride;
}
}
return 1;
}
// Assume every config in VP9EncoderConfig is less than 100 characters. #define ENCODE_CONFIG_BUF_SIZE 100 struct EncodeConfig { char name[ENCODE_CONFIG_BUF_SIZE]; char value[ENCODE_CONFIG_BUF_SIZE];
};
staticvoid free_encoder(VP9_COMP *cpi) {
BufferPool *buffer_pool = cpi->common.buffer_pool;
vp9_remove_compressor(cpi); // buffer_pool needs to be free after cpi because buffer_pool contains // allocated buffers that will be free in vp9_remove_compressor()
vpx_free(buffer_pool);
}
staticvoid update_frame_counts(const FRAME_COUNTS *input_counts,
FrameCounts *output_counts) { // Init array sizes.
output_counts->y_mode.resize(BLOCK_SIZE_GROUPS); for (int i = 0; i < BLOCK_SIZE_GROUPS; ++i) {
output_counts->y_mode[i].resize(INTRA_MODES);
}
output_counts->uv_mode.resize(INTRA_MODES); for (int i = 0; i < INTRA_MODES; ++i) {
output_counts->uv_mode[i].resize(INTRA_MODES);
}
output_counts->partition.resize(PARTITION_CONTEXTS); for (int i = 0; i < PARTITION_CONTEXTS; ++i) {
output_counts->partition[i].resize(PARTITION_TYPES);
}
output_counts->coef.resize(TX_SIZES);
output_counts->eob_branch.resize(TX_SIZES); for (int i = 0; i < TX_SIZES; ++i) {
output_counts->coef[i].resize(PLANE_TYPES);
output_counts->eob_branch[i].resize(PLANE_TYPES); for (int j = 0; j < PLANE_TYPES; ++j) {
output_counts->coef[i][j].resize(REF_TYPES);
output_counts->eob_branch[i][j].resize(REF_TYPES); for (int k = 0; k < REF_TYPES; ++k) {
output_counts->coef[i][j][k].resize(COEF_BANDS);
output_counts->eob_branch[i][j][k].resize(COEF_BANDS); for (int l = 0; l < COEF_BANDS; ++l) {
output_counts->coef[i][j][k][l].resize(COEFF_CONTEXTS);
output_counts->eob_branch[i][j][k][l].resize(COEFF_CONTEXTS); for (int m = 0; m < COEFF_CONTEXTS; ++m) {
output_counts->coef[i][j][k][l][m].resize(UNCONSTRAINED_NODES + 1);
}
}
}
}
}
output_counts->switchable_interp.resize(SWITCHABLE_FILTER_CONTEXTS); for (int i = 0; i < SWITCHABLE_FILTER_CONTEXTS; ++i) {
output_counts->switchable_interp[i].resize(SWITCHABLE_FILTERS);
}
output_counts->inter_mode.resize(INTER_MODE_CONTEXTS); for (int i = 0; i < INTER_MODE_CONTEXTS; ++i) {
output_counts->inter_mode[i].resize(INTER_MODES);
}
output_counts->intra_inter.resize(INTRA_INTER_CONTEXTS); for (int i = 0; i < INTRA_INTER_CONTEXTS; ++i) {
output_counts->intra_inter[i].resize(2);
}
output_counts->comp_inter.resize(COMP_INTER_CONTEXTS); for (int i = 0; i < COMP_INTER_CONTEXTS; ++i) {
output_counts->comp_inter[i].resize(2);
}
output_counts->single_ref.resize(REF_CONTEXTS); for (int i = 0; i < REF_CONTEXTS; ++i) {
output_counts->single_ref[i].resize(2); for (int j = 0; j < 2; ++j) {
output_counts->single_ref[i][j].resize(2);
}
}
output_counts->comp_ref.resize(REF_CONTEXTS); for (int i = 0; i < REF_CONTEXTS; ++i) {
output_counts->comp_ref[i].resize(2);
}
output_counts->skip.resize(SKIP_CONTEXTS); for (int i = 0; i < SKIP_CONTEXTS; ++i) {
output_counts->skip[i].resize(2);
}
output_counts->tx.p32x32.resize(TX_SIZE_CONTEXTS);
output_counts->tx.p16x16.resize(TX_SIZE_CONTEXTS);
output_counts->tx.p8x8.resize(TX_SIZE_CONTEXTS); for (int i = 0; i < TX_SIZE_CONTEXTS; i++) {
output_counts->tx.p32x32[i].resize(TX_SIZES);
output_counts->tx.p16x16[i].resize(TX_SIZES - 1);
output_counts->tx.p8x8[i].resize(TX_SIZES - 2);
}
output_counts->tx.tx_totals.resize(TX_SIZES);
output_counts->mv.joints.resize(MV_JOINTS);
output_counts->mv.comps.resize(2); for (int i = 0; i < 2; ++i) {
output_counts->mv.comps[i].sign.resize(2);
output_counts->mv.comps[i].classes.resize(MV_CLASSES);
output_counts->mv.comps[i].class0.resize(CLASS0_SIZE);
output_counts->mv.comps[i].bits.resize(MV_OFFSET_BITS); for (int j = 0; j < MV_OFFSET_BITS; ++j) {
output_counts->mv.comps[i].bits[j].resize(2);
}
output_counts->mv.comps[i].class0_fp.resize(CLASS0_SIZE); for (int j = 0; j < CLASS0_SIZE; ++j) {
output_counts->mv.comps[i].class0_fp[j].resize(MV_FP_SIZE);
}
output_counts->mv.comps[i].fp.resize(MV_FP_SIZE);
output_counts->mv.comps[i].class0_hp.resize(2);
output_counts->mv.comps[i].hp.resize(2);
}
// Populate counts. for (int i = 0; i < BLOCK_SIZE_GROUPS; ++i) { for (int j = 0; j < INTRA_MODES; ++j) {
output_counts->y_mode[i][j] = input_counts->y_mode[i][j];
}
} for (int i = 0; i < INTRA_MODES; ++i) { for (int j = 0; j < INTRA_MODES; ++j) {
output_counts->uv_mode[i][j] = input_counts->uv_mode[i][j];
}
} for (int i = 0; i < PARTITION_CONTEXTS; ++i) { for (int j = 0; j < PARTITION_TYPES; ++j) {
output_counts->partition[i][j] = input_counts->partition[i][j];
}
} for (int i = 0; i < TX_SIZES; ++i) { for (int j = 0; j < PLANE_TYPES; ++j) { for (int k = 0; k < REF_TYPES; ++k) { for (int l = 0; l < COEF_BANDS; ++l) { for (int m = 0; m < COEFF_CONTEXTS; ++m) {
output_counts->eob_branch[i][j][k][l][m] =
input_counts->eob_branch[i][j][k][l][m]; for (int n = 0; n < UNCONSTRAINED_NODES + 1; n++) {
output_counts->coef[i][j][k][l][m][n] =
input_counts->coef[i][j][k][l][m][n];
}
}
}
}
}
} for (int i = 0; i < SWITCHABLE_FILTER_CONTEXTS; ++i) { for (int j = 0; j < SWITCHABLE_FILTERS; ++j) {
output_counts->switchable_interp[i][j] =
input_counts->switchable_interp[i][j];
}
} for (int i = 0; i < INTER_MODE_CONTEXTS; ++i) { for (int j = 0; j < INTER_MODES; ++j) {
output_counts->inter_mode[i][j] = input_counts->inter_mode[i][j];
}
} for (int i = 0; i < INTRA_INTER_CONTEXTS; ++i) { for (int j = 0; j < 2; ++j) {
output_counts->intra_inter[i][j] = input_counts->intra_inter[i][j];
}
} for (int i = 0; i < COMP_INTER_CONTEXTS; ++i) { for (int j = 0; j < 2; ++j) {
output_counts->comp_inter[i][j] = input_counts->comp_inter[i][j];
}
} for (int i = 0; i < REF_CONTEXTS; ++i) { for (int j = 0; j < 2; ++j) { for (int k = 0; k < 2; ++k) {
output_counts->single_ref[i][j][k] = input_counts->single_ref[i][j][k];
}
}
} for (int i = 0; i < REF_CONTEXTS; ++i) { for (int j = 0; j < 2; ++j) {
output_counts->comp_ref[i][j] = input_counts->comp_ref[i][j];
}
} for (int i = 0; i < SKIP_CONTEXTS; ++i) { for (int j = 0; j < 2; ++j) {
output_counts->skip[i][j] = input_counts->skip[i][j];
}
} for (int i = 0; i < TX_SIZE_CONTEXTS; i++) { for (int j = 0; j < TX_SIZES; j++) {
output_counts->tx.p32x32[i][j] = input_counts->tx.p32x32[i][j];
} for (int j = 0; j < TX_SIZES - 1; j++) {
output_counts->tx.p16x16[i][j] = input_counts->tx.p16x16[i][j];
} for (int j = 0; j < TX_SIZES - 2; j++) {
output_counts->tx.p8x8[i][j] = input_counts->tx.p8x8[i][j];
}
} for (int i = 0; i < TX_SIZES; i++) {
output_counts->tx.tx_totals[i] = input_counts->tx.tx_totals[i];
} for (int i = 0; i < MV_JOINTS; i++) {
output_counts->mv.joints[i] = input_counts->mv.joints[i];
} for (int k = 0; k < 2; k++) { const nmv_component_counts *const comps_t = &input_counts->mv.comps[k]; for (int i = 0; i < 2; i++) {
output_counts->mv.comps[k].sign[i] = comps_t->sign[i];
output_counts->mv.comps[k].class0_hp[i] = comps_t->class0_hp[i];
output_counts->mv.comps[k].hp[i] = comps_t->hp[i];
} for (int i = 0; i < MV_CLASSES; i++) {
output_counts->mv.comps[k].classes[i] = comps_t->classes[i];
} for (int i = 0; i < CLASS0_SIZE; i++) {
output_counts->mv.comps[k].class0[i] = comps_t->class0[i]; for (int j = 0; j < MV_FP_SIZE; j++) {
output_counts->mv.comps[k].class0_fp[i][j] = comps_t->class0_fp[i][j];
}
} for (int i = 0; i < MV_OFFSET_BITS; i++) { for (int j = 0; j < 2; j++) {
output_counts->mv.comps[k].bits[i][j] = comps_t->bits[i][j];
}
} for (int i = 0; i < MV_FP_SIZE; i++) {
output_counts->mv.comps[k].fp[i] = comps_t->fp[i];
}
}
}
void output_image_buffer(const ImageBuffer &image_buffer, std::FILE *out_file) { for (int plane = 0; plane < 3; ++plane) { constint w = image_buffer.plane_width[plane]; constint h = image_buffer.plane_height[plane]; const uint8_t *buf = image_buffer.plane_buffer[plane].get();
fprintf(out_file, "%d %d\n", h, w); for (int i = 0; i < w * h; ++i) {
fprintf(out_file, "%d ", (int)buf[i]);
}
fprintf(out_file, "\n");
}
}
staticbool init_image_buffer(ImageBuffer *image_buffer, int frame_width, int frame_height, vpx_img_fmt_t img_fmt) { for (int plane = 0; plane < 3; ++plane) { constint w = get_plane_width(img_fmt, frame_width, plane); constint h = get_plane_height(img_fmt, frame_height, plane);
image_buffer->plane_width[plane] = w;
image_buffer->plane_height[plane] = h;
image_buffer->plane_buffer[plane].reset(new (std::nothrow) uint8_t[w * h]); if (image_buffer->plane_buffer[plane].get() == nullptr) { returnfalse;
}
} returntrue;
}
booloperator==(const RefFrameInfo &a, const RefFrameInfo &b) { bool match = true; for (int i = 0; i < kRefFrameTypeMax; ++i) {
match &= a.coding_indexes[i] == b.coding_indexes[i];
match &= a.valid_list[i] == b.valid_list[i];
} return match;
}
staticvoid InitRefFrameInfo(RefFrameInfo *ref_frame_info) { for (int i = 0; i < kRefFrameTypeMax; ++i) {
ref_frame_info->coding_indexes[i] = -1;
ref_frame_info->valid_list[i] = 0;
}
}
// After finishing coding a frame, this function will update the coded frame // into the ref_frame_info based on the frame_type and the coding_index. staticvoid PostUpdateRefFrameInfo(FrameType frame_type, int frame_coding_index,
RefFrameInfo *ref_frame_info) { // This part is written based on the logics in vp9_configure_buffer_updates() // and update_ref_frames() int *ref_frame_coding_indexes = ref_frame_info->coding_indexes; switch (frame_type) { case kFrameTypeKey:
ref_frame_coding_indexes[kRefFrameTypeLast] = frame_coding_index;
ref_frame_coding_indexes[kRefFrameTypePast] = frame_coding_index;
ref_frame_coding_indexes[kRefFrameTypeFuture] = frame_coding_index; break; case kFrameTypeInter:
ref_frame_coding_indexes[kRefFrameTypeLast] = frame_coding_index; break; case kFrameTypeAltRef:
ref_frame_coding_indexes[kRefFrameTypeFuture] = frame_coding_index; break; case kFrameTypeOverlay: // Reserve the past coding_index in the future slot. This logic is from // update_ref_frames() with condition vp9_preserve_existing_gf() == 1 // TODO(angiebird): Invetegate why we need this.
ref_frame_coding_indexes[kRefFrameTypeFuture] =
ref_frame_coding_indexes[kRefFrameTypePast];
ref_frame_coding_indexes[kRefFrameTypePast] = frame_coding_index; break; case kFrameTypeGolden:
ref_frame_coding_indexes[kRefFrameTypePast] = frame_coding_index;
ref_frame_coding_indexes[kRefFrameTypeLast] = frame_coding_index; break;
}
// This part is written based on the logics in get_ref_frame_flags() but we // rename the flags alt, golden to future, past respectively. Mark // non-duplicated reference frames as valid. The priorities are // kRefFrameTypeLast > kRefFrameTypePast > kRefFrameTypeFuture. constint last_index = ref_frame_coding_indexes[kRefFrameTypeLast]; constint past_index = ref_frame_coding_indexes[kRefFrameTypePast]; constint future_index = ref_frame_coding_indexes[kRefFrameTypeFuture];
int *ref_frame_valid_list = ref_frame_info->valid_list; for (int ref_frame_idx = 0; ref_frame_idx < kRefFrameTypeMax;
++ref_frame_idx) {
ref_frame_valid_list[ref_frame_idx] = 1;
}
if (past_index == last_index) {
ref_frame_valid_list[kRefFrameTypePast] = 0;
}
if (future_index == last_index) {
ref_frame_valid_list[kRefFrameTypeFuture] = 0;
}
if (future_index == past_index) {
ref_frame_valid_list[kRefFrameTypeFuture] = 0;
}
}
staticvoid SetGroupOfPicture(int first_is_key_frame, int use_alt_ref, int coding_frame_count, int first_show_idx, int last_gop_use_alt_ref, int start_coding_index, const RefFrameInfo &start_ref_frame_info,
GroupOfPicture *group_of_picture) { // Clean up the state of previous group of picture.
group_of_picture->encode_frame_list.clear();
group_of_picture->next_encode_frame_index = 0;
group_of_picture->show_frame_count = coding_frame_count - use_alt_ref;
group_of_picture->start_show_index = first_show_idx;
group_of_picture->start_coding_index = start_coding_index;
group_of_picture->first_is_key_frame = first_is_key_frame;
group_of_picture->use_alt_ref = use_alt_ref;
group_of_picture->last_gop_use_alt_ref = last_gop_use_alt_ref;
// We need to make a copy of start reference frame info because we // use it to simulate the ref frame update.
RefFrameInfo ref_frame_info = start_ref_frame_info;
{ // First frame in the group of pictures. It's either key frame or show inter // frame.
EncodeFrameInfo encode_frame_info; // Set frame_type if (first_is_key_frame) {
encode_frame_info.frame_type = kFrameTypeKey;
} else { if (last_gop_use_alt_ref) {
encode_frame_info.frame_type = kFrameTypeOverlay;
} else {
encode_frame_info.frame_type = kFrameTypeGolden;
}
}
constint show_frame_count = coding_frame_count - use_alt_ref; if (use_alt_ref) { // If there is alternate reference, it is always coded at the second place. // Its show index (or timestamp) is at the last of this group
EncodeFrameInfo encode_frame_info;
encode_frame_info.frame_type = kFrameTypeAltRef;
encode_frame_info.show_idx = first_show_idx + show_frame_count;
encode_frame_info.coding_index = start_coding_index + 1;
// Gets group of picture information from VP9's decision, and update // |group_of_picture| accordingly. // This is called at the starting of encoding of each group of picture. staticvoid UpdateGroupOfPicture(const VP9_COMP *cpi, int start_coding_index, const RefFrameInfo &start_ref_frame_info,
GroupOfPicture *group_of_picture) { int first_is_key_frame; int use_alt_ref; int coding_frame_count; int first_show_idx; int last_gop_use_alt_ref;
vp9_get_next_group_of_picture(cpi, &first_is_key_frame, &use_alt_ref,
&coding_frame_count, &first_show_idx,
&last_gop_use_alt_ref);
SetGroupOfPicture(first_is_key_frame, use_alt_ref, coding_frame_count,
first_show_idx, last_gop_use_alt_ref, start_coding_index,
start_ref_frame_info, group_of_picture);
}
#define SET_STRUCT_VALUE(config, structure, ret, field) \ do { \ if (strcmp(config.name, #field) == 0) { \
structure->field = atoi(config.value); \
ret = 1; \
} \
} while (false)
std::vector<std::vector<double>> SimpleEncode::ObserveFirstPassStats() {
std::vector<std::vector<double>> output_stats; // TODO(angiebird): This function make several assumptions of // FIRSTPASS_STATS. 1) All elements in FIRSTPASS_STATS are double except the // last one. 2) The last entry of first_pass_stats is the total_stats. // Change the code structure, so that we don't have to make these assumptions
// Note the last entry of first_pass_stats is the total_stats, we don't need // it. for (size_t i = 0; i < impl_ptr_->first_pass_stats.size() - 1; ++i) { double *buf_start = reinterpret_cast<double *>(&impl_ptr_->first_pass_stats[i]); // We use - 2 here because: // (1). The last member in FIRSTPASS_STATS is not double. // (2). We do not need the last - 1 member. double *buf_end =
buf_start + sizeof(impl_ptr_->first_pass_stats[i]) / sizeof(*buf_end) -
2;
std::vector<double> this_stats(buf_start, buf_end);
output_stats.push_back(this_stats);
} return output_stats;
}
void SimpleEncode::SetExternalGroupOfPicturesMap(int *gop_map, int gop_map_size) { for (int i = 0; i < gop_map_size; ++i) {
gop_map_.push_back(gop_map[i]);
} // The following will check and modify gop_map_ to make sure the // gop_map_ satisfies the constraints. // 1) Each key frame position should be at the start of a gop. // 2) The last gop should not use an alt ref.
assert(gop_map_.size() == key_frame_map_.size()); int last_gop_start = 0; for (int i = 0; static_cast<size_t>(i) < gop_map_.size(); ++i) { if (key_frame_map_[i] == 1 && gop_map_[i] == 0) {
fprintf(stderr, "Add an extra gop start at show_idx %d\n", i); // Insert a gop start at key frame location.
gop_map_[i] |= kGopMapFlagStart;
gop_map_[i] |= kGopMapFlagUseAltRef;
} if (gop_map_[i] & kGopMapFlagStart) {
last_gop_start = i;
}
} if (gop_map_[last_gop_start] & kGopMapFlagUseAltRef) {
fprintf(stderr, "Last group of pictures starting at show_idx %d shouldn't use alt " "ref\n",
last_gop_start);
gop_map_[last_gop_start] &= ~kGopMapFlagUseAltRef;
}
}
template <typename T>
T *GetVectorData(const std::vector<T> &v) { if (v.empty()) { return nullptr;
} returnconst_cast<T *>(v.data());
}
static GOP_COMMAND GetGopCommand(const std::vector<int> &gop_map, int start_show_index) {
GOP_COMMAND gop_command; if (static_cast<size_t>(start_show_index) < gop_map.size()) {
assert((gop_map[start_show_index] & kGopMapFlagStart) != 0); int end_show_index = start_show_index + 1; // gop_map[end_show_index] & kGopMapFlagStart == 0 means this is // the start of a gop. while (static_cast<size_t>(end_show_index) < gop_map.size() &&
(gop_map[end_show_index] & kGopMapFlagStart) == 0) {
++end_show_index;
} constint show_frame_count = end_show_index - start_show_index; int use_alt_ref = (gop_map[start_show_index] & kGopMapFlagUseAltRef) != 0; if (static_cast<size_t>(end_show_index) == gop_map.size()) { // This is the last gop group, there must be no altref.
use_alt_ref = 0;
}
gop_command_on(&gop_command, show_frame_count, use_alt_ref);
} else {
gop_command_off(&gop_command);
} return gop_command;
}
if (out_file_ != nullptr) { constchar *fourcc = "VP90"; // In SimpleEncode, we use time_base = 1 / TICKS_PER_SEC. // Based on that, the ivf_timestamp for each image is set to // show_idx * TICKS_PER_SEC / frame_rate // such that each image's actual timestamp in seconds can be computed as // ivf_timestamp * time_base == show_idx / frame_rate // TODO(angiebird): 1) Add unit test for ivf timestamp. // 2) Simplify the frame_rate setting process.
vpx_rational_t time_base = make_vpx_rational(1, TICKS_PER_SEC);
ivf_write_file_header_with_video_info(out_file_, *(const uint32_t *)fourcc,
num_frames_, frame_width_,
frame_height_, time_base);
}
}
void SimpleEncode::PostUpdateState( const EncodeFrameResult &encode_frame_result) { // This function needs to be called before the increament of // frame_coding_index_
PostUpdateRefFrameInfo(encode_frame_result.frame_type, frame_coding_index_,
&ref_frame_info_);
++frame_coding_index_; if (encode_frame_result.frame_type != kFrameTypeAltRef) { // Only kFrameTypeAltRef is not a show frame
++show_frame_count_;
}
PostUpdateKeyFrameGroupIndex(encode_frame_result.frame_type); if (key_frame_group_index_ == key_frame_group_size_) {
UpdateKeyFrameGroup(show_frame_count_);
}
IncreaseGroupOfPictureIndex(&group_of_picture_); if (IsGroupOfPictureFinished(group_of_picture_)) { const GOP_COMMAND gop_command = GetGopCommand(gop_map_, show_frame_count_);
encode_command_set_gop_command(&impl_ptr_->cpi->encode_command,
gop_command); // This function needs to be called after ref_frame_info_ is updated // properly in PostUpdateRefFrameInfo() and UpdateKeyFrameGroup().
UpdateGroupOfPicture(impl_ptr_->cpi, frame_coding_index_, ref_frame_info_,
&group_of_picture_);
}
}
void SimpleEncode::EncodeFrame(EncodeFrameResult *encode_frame_result) {
VP9_COMP *cpi = impl_ptr_->cpi; struct lookahead_ctx *lookahead = cpi->lookahead; int use_highbitdepth = 0; #if CONFIG_VP9_HIGHBITDEPTH
use_highbitdepth = cpi->common.use_highbitdepth; #endif // The lookahead's size is set to oxcf->lag_in_frames. // We want to fill lookahead to it's max capacity if possible so that the // encoder can construct alt ref frame in time. // In the other words, we hope vp9_get_compressed_data to encode a frame // every time in the function while (!vp9_lookahead_full(lookahead)) { // TODO(angiebird): Check whether we can move this file read logics to // lookahead if (img_read(&impl_ptr_->tmp_img, in_file_)) { int next_show_idx = vp9_lookahead_next_show_idx(lookahead);
int64_t ts_start =
timebase_units_to_ticks(&cpi->oxcf.g_timebase_in_ts, next_show_idx);
int64_t ts_end = timebase_units_to_ticks(&cpi->oxcf.g_timebase_in_ts,
next_show_idx + 1);
YV12_BUFFER_CONFIG sd;
image2yuvconfig(&impl_ptr_->tmp_img, &sd);
vp9_lookahead_push(lookahead, &sd, ts_start, ts_end, use_highbitdepth, 0);
} else { break;
}
}
// vp9_get_compressed_data is expected to encode a frame every time, so the // data size should be greater than zero. if (encode_frame_result->coding_data_byte_size <= 0) {
fprintf(stderr, "Coding data size <= 0\n");
abort();
} if (encode_frame_result->coding_data_byte_size >
encode_frame_result->max_coding_data_byte_size) {
fprintf(stderr, "Coding data size exceeds the maximum.\n");
abort();
}
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.