blob: 029ae45600f6bd778a14114e09917962cd12de3c [file] [log] [blame]
Niels Möllerf9063782018-02-20 16:09:48 +01001/*
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"
Jonas Olssona4d87372019-07-05 19:08:33 +020012
Niels Möllerf9063782018-02-20 16:09:48 +010013#include "rtc_base/checks.h"
14#include "rtc_base/logging.h"
15
16namespace webrtc {
17
Niels Möller18c83d32020-08-07 14:14:49 +020018VCMDecoderMapItem::VCMDecoderMapItem(VideoCodec* settings, int number_of_cores)
19 : settings(settings), number_of_cores(number_of_cores) {
Niels Möllerf9063782018-02-20 16:09:48 +010020 RTC_DCHECK_GE(number_of_cores, 0);
21}
22
23VCMExtDecoderMapItem::VCMExtDecoderMapItem(
24 VideoDecoder* external_decoder_instance,
25 uint8_t payload_type)
26 : payload_type(payload_type),
27 external_decoder_instance(external_decoder_instance) {}
28
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020029VCMDecoderMapItem::~VCMDecoderMapItem() {}
30
Niels Möllerf9063782018-02-20 16:09:48 +010031VCMDecoderDataBase::VCMDecoderDataBase()
32 : receive_codec_(), dec_map_(), dec_external_map_() {}
33
34VCMDecoderDataBase::~VCMDecoderDataBase() {
35 ptr_decoder_.reset();
36 for (auto& kv : dec_map_)
37 delete kv.second;
38 for (auto& kv : dec_external_map_)
39 delete kv.second;
40}
41
42bool VCMDecoderDataBase::DeregisterExternalDecoder(uint8_t payload_type) {
43 ExternalDecoderMap::iterator it = dec_external_map_.find(payload_type);
44 if (it == dec_external_map_.end()) {
Åsa Persson6cb74fd2018-06-01 15:13:42 +020045 // Not found.
Niels Möllerf9063782018-02-20 16:09:48 +010046 return false;
47 }
48 // We can't use payload_type to check if the decoder is currently in use,
49 // because payload type may be out of date (e.g. before we decode the first
Åsa Persson6cb74fd2018-06-01 15:13:42 +020050 // frame after RegisterReceiveCodec).
Niels Möllerf9063782018-02-20 16:09:48 +010051 if (ptr_decoder_ &&
52 ptr_decoder_->IsSameDecoder((*it).second->external_decoder_instance)) {
53 // Release it if it was registered and in use.
54 ptr_decoder_.reset();
55 }
56 DeregisterReceiveCodec(payload_type);
57 delete it->second;
58 dec_external_map_.erase(it);
59 return true;
60}
61
Åsa Persson6cb74fd2018-06-01 15:13:42 +020062// Add the external decoder object to the list of external decoders.
Niels Möllerf9063782018-02-20 16:09:48 +010063// Won't be registered as a receive codec until RegisterReceiveCodec is called.
64void VCMDecoderDataBase::RegisterExternalDecoder(VideoDecoder* external_decoder,
65 uint8_t payload_type) {
Åsa Persson6cb74fd2018-06-01 15:13:42 +020066 // If payload value already exists, erase old and insert new.
Niels Möllerf9063782018-02-20 16:09:48 +010067 VCMExtDecoderMapItem* ext_decoder =
68 new VCMExtDecoderMapItem(external_decoder, payload_type);
69 DeregisterExternalDecoder(payload_type);
70 dec_external_map_[payload_type] = ext_decoder;
71}
72
Niels Möller582102c2020-08-07 16:19:56 +020073bool VCMDecoderDataBase::RegisterReceiveCodec(uint8_t payload_type,
74 const VideoCodec* receive_codec,
Niels Möller18c83d32020-08-07 14:14:49 +020075 int number_of_cores) {
Niels Möllerf9063782018-02-20 16:09:48 +010076 if (number_of_cores < 0) {
77 return false;
78 }
Åsa Persson6cb74fd2018-06-01 15:13:42 +020079 // If payload value already exists, erase old and insert new.
Niels Möller582102c2020-08-07 16:19:56 +020080 DeregisterReceiveCodec(payload_type);
Niels Möllerf9063782018-02-20 16:09:48 +010081 VideoCodec* new_receive_codec = new VideoCodec(*receive_codec);
Niels Möller582102c2020-08-07 16:19:56 +020082 dec_map_[payload_type] =
Niels Möller18c83d32020-08-07 14:14:49 +020083 new VCMDecoderMapItem(new_receive_codec, number_of_cores);
Niels Möllerf9063782018-02-20 16:09:48 +010084 return true;
85}
86
87bool VCMDecoderDataBase::DeregisterReceiveCodec(uint8_t payload_type) {
88 DecoderMap::iterator it = dec_map_.find(payload_type);
89 if (it == dec_map_.end()) {
90 return false;
91 }
92 delete it->second;
93 dec_map_.erase(it);
94 if (receive_codec_.plType == payload_type) {
95 // This codec is currently in use.
96 memset(&receive_codec_, 0, sizeof(VideoCodec));
97 }
98 return true;
99}
100
101VCMGenericDecoder* VCMDecoderDataBase::GetDecoder(
102 const VCMEncodedFrame& frame,
103 VCMDecodedFrameCallback* decoded_frame_callback) {
104 RTC_DCHECK(decoded_frame_callback->UserReceiveCallback());
105 uint8_t payload_type = frame.PayloadType();
106 if (payload_type == receive_codec_.plType || payload_type == 0) {
107 return ptr_decoder_.get();
108 }
Åsa Persson6cb74fd2018-06-01 15:13:42 +0200109 // If decoder exists - delete.
Niels Möllerf9063782018-02-20 16:09:48 +0100110 if (ptr_decoder_) {
111 ptr_decoder_.reset();
112 memset(&receive_codec_, 0, sizeof(VideoCodec));
113 }
114 ptr_decoder_ = CreateAndInitDecoder(frame, &receive_codec_);
115 if (!ptr_decoder_) {
116 return nullptr;
117 }
118 VCMReceiveCallback* callback = decoded_frame_callback->UserReceiveCallback();
119 callback->OnIncomingPayloadType(receive_codec_.plType);
120 if (ptr_decoder_->RegisterDecodeCompleteCallback(decoded_frame_callback) <
121 0) {
122 ptr_decoder_.reset();
123 memset(&receive_codec_, 0, sizeof(VideoCodec));
124 return nullptr;
125 }
126 return ptr_decoder_.get();
127}
128
Niels Möllerf9063782018-02-20 16:09:48 +0100129bool VCMDecoderDataBase::PrefersLateDecoding() const {
130 return ptr_decoder_ ? ptr_decoder_->PrefersLateDecoding() : true;
131}
132
133std::unique_ptr<VCMGenericDecoder> VCMDecoderDataBase::CreateAndInitDecoder(
134 const VCMEncodedFrame& frame,
135 VideoCodec* new_codec) const {
136 uint8_t payload_type = frame.PayloadType();
137 RTC_LOG(LS_INFO) << "Initializing decoder with payload type '"
138 << static_cast<int>(payload_type) << "'.";
139 RTC_DCHECK(new_codec);
140 const VCMDecoderMapItem* decoder_item = FindDecoderItem(payload_type);
141 if (!decoder_item) {
142 RTC_LOG(LS_ERROR) << "Can't find a decoder associated with payload type: "
143 << static_cast<int>(payload_type);
144 return nullptr;
145 }
146 std::unique_ptr<VCMGenericDecoder> ptr_decoder;
147 const VCMExtDecoderMapItem* external_dec_item =
148 FindExternalDecoderItem(payload_type);
149 if (external_dec_item) {
150 // External codec.
151 ptr_decoder.reset(new VCMGenericDecoder(
152 external_dec_item->external_decoder_instance, true));
153 } else {
Niels Möllerf9063782018-02-20 16:09:48 +0100154 RTC_LOG(LS_ERROR) << "No decoder of this type exists.";
Niels Möllerf9063782018-02-20 16:09:48 +0100155 }
156 if (!ptr_decoder)
157 return nullptr;
158
159 // Copy over input resolutions to prevent codec reinitialization due to
160 // the first frame being of a different resolution than the database values.
161 // This is best effort, since there's no guarantee that width/height have been
162 // parsed yet (and may be zero).
163 if (frame.EncodedImage()._encodedWidth > 0 &&
164 frame.EncodedImage()._encodedHeight > 0) {
165 decoder_item->settings->width = frame.EncodedImage()._encodedWidth;
166 decoder_item->settings->height = frame.EncodedImage()._encodedHeight;
167 }
Ilya Nikolaevskiy43c108b2020-05-15 12:24:29 +0200168 int err = ptr_decoder->InitDecode(decoder_item->settings.get(),
169 decoder_item->number_of_cores);
170 if (err < 0) {
171 RTC_LOG(LS_ERROR) << "Failed to initialize decoder. Error code: " << err;
Niels Möllerf9063782018-02-20 16:09:48 +0100172 return nullptr;
173 }
174 memcpy(new_codec, decoder_item->settings.get(), sizeof(VideoCodec));
175 return ptr_decoder;
176}
177
178const VCMDecoderMapItem* VCMDecoderDataBase::FindDecoderItem(
179 uint8_t payload_type) const {
180 DecoderMap::const_iterator it = dec_map_.find(payload_type);
181 if (it != dec_map_.end()) {
182 return (*it).second;
183 }
184 return nullptr;
185}
186
187const VCMExtDecoderMapItem* VCMDecoderDataBase::FindExternalDecoderItem(
188 uint8_t payload_type) const {
189 ExternalDecoderMap::const_iterator it = dec_external_map_.find(payload_type);
190 if (it != dec_external_map_.end()) {
191 return (*it).second;
192 }
193 return nullptr;
194}
195
196} // namespace webrtc