decoder_database.cc (5563B)
1 /* 2 * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "modules/video_coding/decoder_database.h" 12 13 #include <cstdint> 14 #include <memory> 15 #include <optional> 16 #include <utility> 17 18 #include "api/sequence_checker.h" 19 #include "api/video/encoded_frame.h" 20 #include "api/video/render_resolution.h" 21 #include "api/video_codecs/video_decoder.h" 22 #include "modules/video_coding/generic_decoder.h" 23 #include "modules/video_coding/include/video_coding_defines.h" 24 #include "rtc_base/checks.h" 25 #include "rtc_base/logging.h" 26 27 namespace webrtc { 28 29 VCMDecoderDatabase::VCMDecoderDatabase() { 30 decoder_sequence_checker_.Detach(); 31 } 32 33 void VCMDecoderDatabase::DeregisterExternalDecoder(uint8_t payload_type) { 34 RTC_DCHECK_RUN_ON(&decoder_sequence_checker_); 35 auto it = decoders_.find(payload_type); 36 if (it == decoders_.end()) { 37 return; 38 } 39 40 // We can't use payload_type to check if the decoder is currently in use, 41 // because payload type may be out of date (e.g. before we decode the first 42 // frame after RegisterReceiveCodec). 43 if (current_decoder_ && current_decoder_->IsSameDecoder(it->second.get())) { 44 // Release it if it was registered and in use. 45 current_decoder_ = std::nullopt; 46 } 47 decoders_.erase(it); 48 } 49 50 // Add the external decoder object to the list of external decoders. 51 // Won't be registered as a receive codec until RegisterReceiveCodec is called. 52 void VCMDecoderDatabase::RegisterExternalDecoder( 53 uint8_t payload_type, 54 std::unique_ptr<VideoDecoder> external_decoder) { 55 RTC_DCHECK_RUN_ON(&decoder_sequence_checker_); 56 // If payload value already exists, erase old and insert new. 57 DeregisterExternalDecoder(payload_type); 58 if (external_decoder) { 59 decoders_.emplace( 60 std::make_pair(payload_type, std::move(external_decoder))); 61 } 62 } 63 64 bool VCMDecoderDatabase::IsExternalDecoderRegistered( 65 uint8_t payload_type) const { 66 RTC_DCHECK_RUN_ON(&decoder_sequence_checker_); 67 return decoders_.find(payload_type) != decoders_.end(); 68 } 69 70 void VCMDecoderDatabase::RegisterReceiveCodec( 71 uint8_t payload_type, 72 const VideoDecoder::Settings& settings) { 73 // If payload value already exists, erase old and insert new. 74 if (payload_type == current_payload_type_) { 75 current_payload_type_ = std::nullopt; 76 } 77 decoder_settings_[payload_type] = settings; 78 } 79 80 bool VCMDecoderDatabase::DeregisterReceiveCodec(uint8_t payload_type) { 81 if (decoder_settings_.erase(payload_type) == 0) { 82 return false; 83 } 84 if (payload_type == current_payload_type_) { 85 // This codec is currently in use. 86 current_payload_type_ = std::nullopt; 87 } 88 return true; 89 } 90 91 void VCMDecoderDatabase::DeregisterReceiveCodecs() { 92 current_payload_type_ = std::nullopt; 93 decoder_settings_.clear(); 94 } 95 96 VCMGenericDecoder* VCMDecoderDatabase::GetDecoder( 97 const EncodedFrame& frame, 98 VCMDecodedFrameCallback* decoded_frame_callback) { 99 RTC_DCHECK_RUN_ON(&decoder_sequence_checker_); 100 RTC_DCHECK(decoded_frame_callback->UserReceiveCallback()); 101 uint8_t payload_type = frame.PayloadType(); 102 if (payload_type == current_payload_type_ || payload_type == 0) { 103 return current_decoder_.has_value() ? &*current_decoder_ : nullptr; 104 } 105 // If decoder exists - delete. 106 if (current_decoder_.has_value()) { 107 current_decoder_ = std::nullopt; 108 current_payload_type_ = std::nullopt; 109 } 110 111 CreateAndInitDecoder(frame); 112 if (current_decoder_ == std::nullopt) { 113 return nullptr; 114 } 115 116 VCMReceiveCallback* callback = decoded_frame_callback->UserReceiveCallback(); 117 callback->OnIncomingPayloadType(payload_type); 118 if (current_decoder_->RegisterDecodeCompleteCallback(decoded_frame_callback) < 119 0) { 120 current_decoder_ = std::nullopt; 121 return nullptr; 122 } 123 124 current_payload_type_ = payload_type; 125 return &*current_decoder_; 126 } 127 128 void VCMDecoderDatabase::CreateAndInitDecoder(const EncodedFrame& frame) { 129 uint8_t payload_type = frame.PayloadType(); 130 RTC_DLOG(LS_INFO) << "Initializing decoder with payload type '" 131 << int{payload_type} << "'."; 132 auto decoder_item = decoder_settings_.find(payload_type); 133 if (decoder_item == decoder_settings_.end()) { 134 RTC_LOG(LS_ERROR) << "Can't find a decoder associated with payload type: " 135 << int{payload_type}; 136 return; 137 } 138 auto external_dec_item = decoders_.find(payload_type); 139 if (external_dec_item == decoders_.end()) { 140 RTC_LOG(LS_ERROR) << "No decoder of this type exists."; 141 return; 142 } 143 current_decoder_.emplace(external_dec_item->second.get()); 144 145 // Copy over input resolutions to prevent codec reinitialization due to 146 // the first frame being of a different resolution than the database values. 147 // This is best effort, since there's no guarantee that width/height have been 148 // parsed yet (and may be zero). 149 RenderResolution frame_resolution(frame.EncodedImage()._encodedWidth, 150 frame.EncodedImage()._encodedHeight); 151 if (frame_resolution.Valid()) { 152 decoder_item->second.set_max_render_resolution(frame_resolution); 153 } 154 if (!current_decoder_->Configure(decoder_item->second)) { 155 current_decoder_ = std::nullopt; 156 RTC_LOG(LS_ERROR) << "Failed to initialize decoder."; 157 } 158 } 159 160 } // namespace webrtc