blob: c203721e5d7b16e71439225c57bd34727f6eb729 [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öllerf9063782018-02-20 16:09:48 +010018VCMDecoderMapItem::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
27VCMExtDecoderMapItem::VCMExtDecoderMapItem(
28 VideoDecoder* external_decoder_instance,
29 uint8_t payload_type)
30 : payload_type(payload_type),
31 external_decoder_instance(external_decoder_instance) {}
32
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020033VCMDecoderMapItem::~VCMDecoderMapItem() {}
34
Niels Möllerf9063782018-02-20 16:09:48 +010035VCMDecoderDataBase::VCMDecoderDataBase()
36 : receive_codec_(), dec_map_(), dec_external_map_() {}
37
38VCMDecoderDataBase::~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
46bool VCMDecoderDataBase::DeregisterExternalDecoder(uint8_t payload_type) {
47 ExternalDecoderMap::iterator it = dec_external_map_.find(payload_type);
48 if (it == dec_external_map_.end()) {
Åsa Persson6cb74fd2018-06-01 15:13:42 +020049 // Not found.
Niels Möllerf9063782018-02-20 16:09:48 +010050 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
Åsa Persson6cb74fd2018-06-01 15:13:42 +020054 // frame after RegisterReceiveCodec).
Niels Möllerf9063782018-02-20 16:09:48 +010055 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
Åsa Persson6cb74fd2018-06-01 15:13:42 +020066// Add the external decoder object to the list of external decoders.
Niels Möllerf9063782018-02-20 16:09:48 +010067// Won't be registered as a receive codec until RegisterReceiveCodec is called.
68void VCMDecoderDataBase::RegisterExternalDecoder(VideoDecoder* external_decoder,
69 uint8_t payload_type) {
Åsa Persson6cb74fd2018-06-01 15:13:42 +020070 // If payload value already exists, erase old and insert new.
Niels Möllerf9063782018-02-20 16:09:48 +010071 VCMExtDecoderMapItem* ext_decoder =
72 new VCMExtDecoderMapItem(external_decoder, payload_type);
73 DeregisterExternalDecoder(payload_type);
74 dec_external_map_[payload_type] = ext_decoder;
75}
76
Niels Möllerf9063782018-02-20 16:09:48 +010077bool 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 }
Åsa Persson6cb74fd2018-06-01 15:13:42 +020083 // If payload value already exists, erase old and insert new.
Niels Möllerf9063782018-02-20 16:09:48 +010084 DeregisterReceiveCodec(receive_codec->plType);
Niels Möllerf9063782018-02-20 16:09:48 +010085 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
91bool 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
105VCMGenericDecoder* 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 }
Åsa Persson6cb74fd2018-06-01 15:13:42 +0200113 // If decoder exists - delete.
Niels Möllerf9063782018-02-20 16:09:48 +0100114 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
Niels Möllerf9063782018-02-20 16:09:48 +0100133bool VCMDecoderDataBase::PrefersLateDecoding() const {
134 return ptr_decoder_ ? ptr_decoder_->PrefersLateDecoding() : true;
135}
136
137std::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 {
Niels Möllerf9063782018-02-20 16:09:48 +0100158 RTC_LOG(LS_ERROR) << "No decoder of this type exists.";
Niels Möllerf9063782018-02-20 16:09:48 +0100159 }
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 if (ptr_decoder->InitDecode(decoder_item->settings.get(),
173 decoder_item->number_of_cores) < 0) {
174 return nullptr;
175 }
176 memcpy(new_codec, decoder_item->settings.get(), sizeof(VideoCodec));
177 return ptr_decoder;
178}
179
180const VCMDecoderMapItem* VCMDecoderDataBase::FindDecoderItem(
181 uint8_t payload_type) const {
182 DecoderMap::const_iterator it = dec_map_.find(payload_type);
183 if (it != dec_map_.end()) {
184 return (*it).second;
185 }
186 return nullptr;
187}
188
189const VCMExtDecoderMapItem* VCMDecoderDataBase::FindExternalDecoderItem(
190 uint8_t payload_type) const {
191 ExternalDecoderMap::const_iterator it = dec_external_map_.find(payload_type);
192 if (it != dec_external_map_.end()) {
193 return (*it).second;
194 }
195 return nullptr;
196}
197
198} // namespace webrtc