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 "rtc_base/checks.h"
14 #include "rtc_base/logging.h"
15
16 namespace webrtc {
17
VCMDecoderMapItem(VideoCodec * settings,int number_of_cores,bool require_key_frame)18 VCMDecoderMapItem::VCMDecoderMapItem(VideoCodec* settings,
19 int number_of_cores,
20 bool require_key_frame)
21 : settings(settings),
22 number_of_cores(number_of_cores),
23 require_key_frame(require_key_frame) {
24 RTC_DCHECK_GE(number_of_cores, 0);
25 }
26
VCMExtDecoderMapItem(VideoDecoder * external_decoder_instance,uint8_t payload_type)27 VCMExtDecoderMapItem::VCMExtDecoderMapItem(
28 VideoDecoder* external_decoder_instance,
29 uint8_t payload_type)
30 : payload_type(payload_type),
31 external_decoder_instance(external_decoder_instance) {}
32
~VCMDecoderMapItem()33 VCMDecoderMapItem::~VCMDecoderMapItem() {}
34
VCMDecoderDataBase()35 VCMDecoderDataBase::VCMDecoderDataBase()
36 : receive_codec_(), dec_map_(), dec_external_map_() {}
37
~VCMDecoderDataBase()38 VCMDecoderDataBase::~VCMDecoderDataBase() {
39 ptr_decoder_.reset();
40 for (auto& kv : dec_map_)
41 delete kv.second;
42 for (auto& kv : dec_external_map_)
43 delete kv.second;
44 }
45
DeregisterExternalDecoder(uint8_t payload_type)46 bool VCMDecoderDataBase::DeregisterExternalDecoder(uint8_t payload_type) {
47 ExternalDecoderMap::iterator it = dec_external_map_.find(payload_type);
48 if (it == dec_external_map_.end()) {
49 // Not found.
50 return false;
51 }
52 // We can't use payload_type to check if the decoder is currently in use,
53 // because payload type may be out of date (e.g. before we decode the first
54 // frame after RegisterReceiveCodec).
55 if (ptr_decoder_ &&
56 ptr_decoder_->IsSameDecoder((*it).second->external_decoder_instance)) {
57 // Release it if it was registered and in use.
58 ptr_decoder_.reset();
59 }
60 DeregisterReceiveCodec(payload_type);
61 delete it->second;
62 dec_external_map_.erase(it);
63 return true;
64 }
65
66 // Add the external decoder object to the list of external decoders.
67 // Won't be registered as a receive codec until RegisterReceiveCodec is called.
RegisterExternalDecoder(VideoDecoder * external_decoder,uint8_t payload_type)68 void VCMDecoderDataBase::RegisterExternalDecoder(VideoDecoder* external_decoder,
69 uint8_t payload_type) {
70 // If payload value already exists, erase old and insert new.
71 VCMExtDecoderMapItem* ext_decoder =
72 new VCMExtDecoderMapItem(external_decoder, payload_type);
73 DeregisterExternalDecoder(payload_type);
74 dec_external_map_[payload_type] = ext_decoder;
75 }
76
RegisterReceiveCodec(const VideoCodec * receive_codec,int number_of_cores,bool require_key_frame)77 bool VCMDecoderDataBase::RegisterReceiveCodec(const VideoCodec* receive_codec,
78 int number_of_cores,
79 bool require_key_frame) {
80 if (number_of_cores < 0) {
81 return false;
82 }
83 // If payload value already exists, erase old and insert new.
84 DeregisterReceiveCodec(receive_codec->plType);
85 VideoCodec* new_receive_codec = new VideoCodec(*receive_codec);
86 dec_map_[receive_codec->plType] = new VCMDecoderMapItem(
87 new_receive_codec, number_of_cores, require_key_frame);
88 return true;
89 }
90
DeregisterReceiveCodec(uint8_t payload_type)91 bool VCMDecoderDataBase::DeregisterReceiveCodec(uint8_t payload_type) {
92 DecoderMap::iterator it = dec_map_.find(payload_type);
93 if (it == dec_map_.end()) {
94 return false;
95 }
96 delete it->second;
97 dec_map_.erase(it);
98 if (receive_codec_.plType == payload_type) {
99 // This codec is currently in use.
100 memset(&receive_codec_, 0, sizeof(VideoCodec));
101 }
102 return true;
103 }
104
GetDecoder(const VCMEncodedFrame & frame,VCMDecodedFrameCallback * decoded_frame_callback)105 VCMGenericDecoder* VCMDecoderDataBase::GetDecoder(
106 const VCMEncodedFrame& frame,
107 VCMDecodedFrameCallback* decoded_frame_callback) {
108 RTC_DCHECK(decoded_frame_callback->UserReceiveCallback());
109 uint8_t payload_type = frame.PayloadType();
110 if (payload_type == receive_codec_.plType || payload_type == 0) {
111 return ptr_decoder_.get();
112 }
113 // If decoder exists - delete.
114 if (ptr_decoder_) {
115 ptr_decoder_.reset();
116 memset(&receive_codec_, 0, sizeof(VideoCodec));
117 }
118 ptr_decoder_ = CreateAndInitDecoder(frame, &receive_codec_);
119 if (!ptr_decoder_) {
120 return nullptr;
121 }
122 VCMReceiveCallback* callback = decoded_frame_callback->UserReceiveCallback();
123 callback->OnIncomingPayloadType(receive_codec_.plType);
124 if (ptr_decoder_->RegisterDecodeCompleteCallback(decoded_frame_callback) <
125 0) {
126 ptr_decoder_.reset();
127 memset(&receive_codec_, 0, sizeof(VideoCodec));
128 return nullptr;
129 }
130 return ptr_decoder_.get();
131 }
132
PrefersLateDecoding() const133 bool VCMDecoderDataBase::PrefersLateDecoding() const {
134 return ptr_decoder_ ? ptr_decoder_->PrefersLateDecoding() : true;
135 }
136
CreateAndInitDecoder(const VCMEncodedFrame & frame,VideoCodec * new_codec) const137 std::unique_ptr<VCMGenericDecoder> VCMDecoderDataBase::CreateAndInitDecoder(
138 const VCMEncodedFrame& frame,
139 VideoCodec* new_codec) const {
140 uint8_t payload_type = frame.PayloadType();
141 RTC_LOG(LS_INFO) << "Initializing decoder with payload type '"
142 << static_cast<int>(payload_type) << "'.";
143 RTC_DCHECK(new_codec);
144 const VCMDecoderMapItem* decoder_item = FindDecoderItem(payload_type);
145 if (!decoder_item) {
146 RTC_LOG(LS_ERROR) << "Can't find a decoder associated with payload type: "
147 << static_cast<int>(payload_type);
148 return nullptr;
149 }
150 std::unique_ptr<VCMGenericDecoder> ptr_decoder;
151 const VCMExtDecoderMapItem* external_dec_item =
152 FindExternalDecoderItem(payload_type);
153 if (external_dec_item) {
154 // External codec.
155 ptr_decoder.reset(new VCMGenericDecoder(
156 external_dec_item->external_decoder_instance, true));
157 } else {
158 RTC_LOG(LS_ERROR) << "No decoder of this type exists.";
159 }
160 if (!ptr_decoder)
161 return nullptr;
162
163 // Copy over input resolutions to prevent codec reinitialization due to
164 // the first frame being of a different resolution than the database values.
165 // This is best effort, since there's no guarantee that width/height have been
166 // parsed yet (and may be zero).
167 if (frame.EncodedImage()._encodedWidth > 0 &&
168 frame.EncodedImage()._encodedHeight > 0) {
169 decoder_item->settings->width = frame.EncodedImage()._encodedWidth;
170 decoder_item->settings->height = frame.EncodedImage()._encodedHeight;
171 }
172 int err = ptr_decoder->InitDecode(decoder_item->settings.get(),
173 decoder_item->number_of_cores);
174 if (err < 0) {
175 RTC_LOG(LS_ERROR) << "Failed to initialize decoder. Error code: " << err;
176 return nullptr;
177 }
178 memcpy(new_codec, decoder_item->settings.get(), sizeof(VideoCodec));
179 return ptr_decoder;
180 }
181
FindDecoderItem(uint8_t payload_type) const182 const VCMDecoderMapItem* VCMDecoderDataBase::FindDecoderItem(
183 uint8_t payload_type) const {
184 DecoderMap::const_iterator it = dec_map_.find(payload_type);
185 if (it != dec_map_.end()) {
186 return (*it).second;
187 }
188 return nullptr;
189 }
190
FindExternalDecoderItem(uint8_t payload_type) const191 const VCMExtDecoderMapItem* VCMDecoderDataBase::FindExternalDecoderItem(
192 uint8_t payload_type) const {
193 ExternalDecoderMap::const_iterator it = dec_external_map_.find(payload_type);
194 if (it != dec_external_map_.end()) {
195 return (*it).second;
196 }
197 return nullptr;
198 }
199
200 } // namespace webrtc
201