blob: da3a87bdcc922b65fc98ecf66bcbe25e4aec93cd [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öllerf9063782018-02-20 16:09:48 +010073bool VCMDecoderDataBase::RegisterReceiveCodec(const VideoCodec* receive_codec,
Niels Möller18c83d32020-08-07 14:14:49 +020074 int number_of_cores) {
Niels Möllerf9063782018-02-20 16:09:48 +010075 if (number_of_cores < 0) {
76 return false;
77 }
Åsa Persson6cb74fd2018-06-01 15:13:42 +020078 // If payload value already exists, erase old and insert new.
Niels Möllerf9063782018-02-20 16:09:48 +010079 DeregisterReceiveCodec(receive_codec->plType);
Niels Möllerf9063782018-02-20 16:09:48 +010080 VideoCodec* new_receive_codec = new VideoCodec(*receive_codec);
Niels Möller18c83d32020-08-07 14:14:49 +020081 dec_map_[receive_codec->plType] =
82 new VCMDecoderMapItem(new_receive_codec, number_of_cores);
Niels Möllerf9063782018-02-20 16:09:48 +010083 return true;
84}
85
86bool VCMDecoderDataBase::DeregisterReceiveCodec(uint8_t payload_type) {
87 DecoderMap::iterator it = dec_map_.find(payload_type);
88 if (it == dec_map_.end()) {
89 return false;
90 }
91 delete it->second;
92 dec_map_.erase(it);
93 if (receive_codec_.plType == payload_type) {
94 // This codec is currently in use.
95 memset(&receive_codec_, 0, sizeof(VideoCodec));
96 }
97 return true;
98}
99
100VCMGenericDecoder* VCMDecoderDataBase::GetDecoder(
101 const VCMEncodedFrame& frame,
102 VCMDecodedFrameCallback* decoded_frame_callback) {
103 RTC_DCHECK(decoded_frame_callback->UserReceiveCallback());
104 uint8_t payload_type = frame.PayloadType();
105 if (payload_type == receive_codec_.plType || payload_type == 0) {
106 return ptr_decoder_.get();
107 }
Åsa Persson6cb74fd2018-06-01 15:13:42 +0200108 // If decoder exists - delete.
Niels Möllerf9063782018-02-20 16:09:48 +0100109 if (ptr_decoder_) {
110 ptr_decoder_.reset();
111 memset(&receive_codec_, 0, sizeof(VideoCodec));
112 }
113 ptr_decoder_ = CreateAndInitDecoder(frame, &receive_codec_);
114 if (!ptr_decoder_) {
115 return nullptr;
116 }
117 VCMReceiveCallback* callback = decoded_frame_callback->UserReceiveCallback();
118 callback->OnIncomingPayloadType(receive_codec_.plType);
119 if (ptr_decoder_->RegisterDecodeCompleteCallback(decoded_frame_callback) <
120 0) {
121 ptr_decoder_.reset();
122 memset(&receive_codec_, 0, sizeof(VideoCodec));
123 return nullptr;
124 }
125 return ptr_decoder_.get();
126}
127
Niels Möllerf9063782018-02-20 16:09:48 +0100128bool VCMDecoderDataBase::PrefersLateDecoding() const {
129 return ptr_decoder_ ? ptr_decoder_->PrefersLateDecoding() : true;
130}
131
132std::unique_ptr<VCMGenericDecoder> VCMDecoderDataBase::CreateAndInitDecoder(
133 const VCMEncodedFrame& frame,
134 VideoCodec* new_codec) const {
135 uint8_t payload_type = frame.PayloadType();
136 RTC_LOG(LS_INFO) << "Initializing decoder with payload type '"
137 << static_cast<int>(payload_type) << "'.";
138 RTC_DCHECK(new_codec);
139 const VCMDecoderMapItem* decoder_item = FindDecoderItem(payload_type);
140 if (!decoder_item) {
141 RTC_LOG(LS_ERROR) << "Can't find a decoder associated with payload type: "
142 << static_cast<int>(payload_type);
143 return nullptr;
144 }
145 std::unique_ptr<VCMGenericDecoder> ptr_decoder;
146 const VCMExtDecoderMapItem* external_dec_item =
147 FindExternalDecoderItem(payload_type);
148 if (external_dec_item) {
149 // External codec.
150 ptr_decoder.reset(new VCMGenericDecoder(
151 external_dec_item->external_decoder_instance, true));
152 } else {
Niels Möllerf9063782018-02-20 16:09:48 +0100153 RTC_LOG(LS_ERROR) << "No decoder of this type exists.";
Niels Möllerf9063782018-02-20 16:09:48 +0100154 }
155 if (!ptr_decoder)
156 return nullptr;
157
158 // Copy over input resolutions to prevent codec reinitialization due to
159 // the first frame being of a different resolution than the database values.
160 // This is best effort, since there's no guarantee that width/height have been
161 // parsed yet (and may be zero).
162 if (frame.EncodedImage()._encodedWidth > 0 &&
163 frame.EncodedImage()._encodedHeight > 0) {
164 decoder_item->settings->width = frame.EncodedImage()._encodedWidth;
165 decoder_item->settings->height = frame.EncodedImage()._encodedHeight;
166 }
Ilya Nikolaevskiy43c108b2020-05-15 12:24:29 +0200167 int err = ptr_decoder->InitDecode(decoder_item->settings.get(),
168 decoder_item->number_of_cores);
169 if (err < 0) {
170 RTC_LOG(LS_ERROR) << "Failed to initialize decoder. Error code: " << err;
Niels Möllerf9063782018-02-20 16:09:48 +0100171 return nullptr;
172 }
173 memcpy(new_codec, decoder_item->settings.get(), sizeof(VideoCodec));
174 return ptr_decoder;
175}
176
177const VCMDecoderMapItem* VCMDecoderDataBase::FindDecoderItem(
178 uint8_t payload_type) const {
179 DecoderMap::const_iterator it = dec_map_.find(payload_type);
180 if (it != dec_map_.end()) {
181 return (*it).second;
182 }
183 return nullptr;
184}
185
186const VCMExtDecoderMapItem* VCMDecoderDataBase::FindExternalDecoderItem(
187 uint8_t payload_type) const {
188 ExternalDecoderMap::const_iterator it = dec_external_map_.find(payload_type);
189 if (it != dec_external_map_.end()) {
190 return (*it).second;
191 }
192 return nullptr;
193}
194
195} // namespace webrtc