| /* |
| * Copyright (c) 2022, 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. |
| */ |
| #include "av1/ratectrl_qmode.h" |
| |
| #include <algorithm> |
| #include <cassert> |
| #include <climits> |
| #include <vector> |
| |
| #include "av1/encoder/pass2_strategy.h" |
| |
| namespace aom { |
| |
| static GopFrame gop_frame_basic(int coding_idx, int order_idx, |
| bool is_key_frame, bool is_arf_frame, |
| bool is_golden_frame, bool is_show_frame) { |
| GopFrame gop_frame; |
| gop_frame.coding_idx = coding_idx; |
| gop_frame.order_idx = order_idx; |
| gop_frame.is_key_frame = is_key_frame; |
| gop_frame.is_arf_frame = is_arf_frame; |
| gop_frame.is_golden_frame = is_golden_frame; |
| gop_frame.is_show_frame = is_show_frame; |
| gop_frame.encode_ref_mode = EncodeRefMode::kRegular; |
| gop_frame.colocated_ref_idx = -1; |
| gop_frame.update_ref_idx = -1; |
| return gop_frame; |
| } |
| |
| // This function create gop frames with indices of display order from |
| // order_start to order_end - 1. The function will recursively introduce |
| // intermediate ARF untill maximum depth is met or the number of regular frames |
| // in between two ARFs are less than 3. Than the regular frames will be added |
| // into the gop_struct. |
| void construct_gop_multi_layer(GopStruct *gop_struct, |
| RefFrameManager *ref_frame_manager, |
| int max_depth, int depth, int order_start, |
| int order_end) { |
| int coding_idx = static_cast<int>(gop_struct->gop_frame_list.size()); |
| GopFrame gop_frame; |
| int num_frames = order_end - order_start; |
| // If there are less than 3 frames, stop introducing ARF |
| if (depth < max_depth && num_frames < 3) { |
| int order_mid = (order_start + order_end) / 2; |
| // intermediate ARF |
| gop_frame = gop_frame_basic(coding_idx, order_mid, 0, 1, 0, 0); |
| ref_frame_manager->UpdateFrame(&gop_frame, RefUpdateType::kForward, |
| EncodeRefMode::kRegular); |
| gop_struct->gop_frame_list.push_back(gop_frame); |
| construct_gop_multi_layer(gop_struct, ref_frame_manager, max_depth, |
| depth + 1, order_start, order_mid); |
| // show existing intermediate ARF |
| gop_frame = gop_frame_basic(coding_idx, order_mid, 0, 0, 0, 1); |
| ref_frame_manager->UpdateFrame(&gop_frame, RefUpdateType::kNone, |
| EncodeRefMode::kShowExisting); |
| gop_struct->gop_frame_list.push_back(gop_frame); |
| construct_gop_multi_layer(gop_struct, ref_frame_manager, max_depth, |
| depth + 1, order_mid + 1, order_end); |
| } else { |
| // regular frame |
| for (int i = order_start; i < order_end; ++i) { |
| coding_idx = static_cast<int>(gop_struct->gop_frame_list.size()); |
| gop_frame = gop_frame_basic(coding_idx, i, 0, 0, 0, 1); |
| ref_frame_manager->UpdateFrame(&gop_frame, RefUpdateType::kLast, |
| EncodeRefMode::kRegular); |
| gop_struct->gop_frame_list.push_back(gop_frame); |
| } |
| } |
| } |
| |
| GopStruct construct_gop(RefFrameManager *ref_frame_manager, |
| int show_frame_count, bool has_key_frame) { |
| GopStruct gop_struct; |
| gop_struct.show_frame_count = show_frame_count; |
| int order_start = 0; |
| int order_arf = show_frame_count - 1; |
| int coding_idx; |
| GopFrame gop_frame; |
| if (has_key_frame) { |
| ref_frame_manager->Reset(); |
| coding_idx = static_cast<int>(gop_struct.gop_frame_list.size()); |
| gop_frame = gop_frame_basic(coding_idx, order_start, 1, 0, 1, 1); |
| ref_frame_manager->UpdateFrame(&gop_frame, RefUpdateType::kBackward, |
| EncodeRefMode::kRegular); |
| gop_struct.gop_frame_list.push_back(gop_frame); |
| order_start++; |
| } |
| // ARF |
| coding_idx = static_cast<int>(gop_struct.gop_frame_list.size()); |
| gop_frame = gop_frame_basic(coding_idx, order_arf, 0, 1, 1, 0); |
| ref_frame_manager->UpdateFrame(&gop_frame, RefUpdateType::kForward, |
| EncodeRefMode::kRegular); |
| gop_struct.gop_frame_list.push_back(gop_frame); |
| construct_gop_multi_layer(&gop_struct, ref_frame_manager, |
| ref_frame_manager->ForwardMaxSize(), 1, order_start, |
| order_arf); |
| // Overlay |
| coding_idx = static_cast<int>(gop_struct.gop_frame_list.size()); |
| gop_frame = gop_frame_basic(coding_idx, order_arf, 0, 0, 0, 1); |
| ref_frame_manager->UpdateFrame(&gop_frame, RefUpdateType::kNone, |
| EncodeRefMode::kOverlay); |
| gop_struct.gop_frame_list.push_back(gop_frame); |
| return gop_struct; |
| } |
| |
| void AV1RateControlQMode::SetRcParam(const RateControlParam &rc_param) { |
| rc_param_ = rc_param; |
| } |
| |
| GopStructList AV1RateControlQMode::DetermineGopInfo( |
| const FirstpassInfo &firstpass_info) { |
| std::vector<REGIONS> regions_list(MAX_FIRSTPASS_ANALYSIS_FRAMES); |
| int total_regions = 0; |
| // TODO(jianj): firstpass_info.size() should eventually be replaced |
| // by the number of frames to the next KF. |
| assert(firstpass_info.size() <= INT_MAX); |
| av1_identify_regions(firstpass_info.data(), |
| std::min(static_cast<int>(firstpass_info.size()), |
| MAX_FIRSTPASS_ANALYSIS_FRAMES), |
| 0, regions_list.data(), &total_regions); |
| |
| // A temporary simple implementation |
| const int max_gop_show_frame_count = 16; |
| int remaining_show_frame_count = static_cast<int>(firstpass_info.size()); |
| GopStructList gop_list; |
| |
| RefFrameManager ref_frame_manager(rc_param_.max_ref_frames); |
| |
| while (remaining_show_frame_count > 0) { |
| int show_frame_count = |
| std::min(remaining_show_frame_count, max_gop_show_frame_count); |
| // TODO(angiebird): determine gop show frame count based on first pass stats |
| // here. |
| bool has_key_frame = gop_list.size() == 0; |
| GopStruct gop = |
| construct_gop(&ref_frame_manager, show_frame_count, has_key_frame); |
| gop_list.push_back(gop); |
| remaining_show_frame_count -= show_frame_count; |
| } |
| return gop_list; |
| } |
| |
| std::vector<FrameEncodeParameters> AV1RateControlQMode::GetGopEncodeInfo( |
| const TplGopStats &tpl_stats_list) { |
| std::vector<FrameEncodeParameters> frame_encoder_param; |
| (void)tpl_stats_list; |
| return frame_encoder_param; |
| } |
| |
| } // namespace aom |