blob: 9cb78232568baa0849a2a08a3000b25809e03f3d [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"
Niels Möllerf9063782018-02-20 16:09:48 +010012#include "rtc_base/checks.h"
13#include "rtc_base/logging.h"
14
15namespace webrtc {
16
Niels Möllerf9063782018-02-20 16:09:48 +010017VCMDecoderMapItem::VCMDecoderMapItem(VideoCodec* settings,
18 int number_of_cores,
19 bool require_key_frame)
20 : settings(settings),
21 number_of_cores(number_of_cores),
22 require_key_frame(require_key_frame) {
23 RTC_DCHECK_GE(number_of_cores, 0);
24}
25
26VCMExtDecoderMapItem::VCMExtDecoderMapItem(
27 VideoDecoder* external_decoder_instance,
28 uint8_t payload_type)
29 : payload_type(payload_type),
30 external_decoder_instance(external_decoder_instance) {}
31
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020032VCMDecoderMapItem::~VCMDecoderMapItem() {}
33
Niels Möllerf9063782018-02-20 16:09:48 +010034VCMDecoderDataBase::VCMDecoderDataBase()
35 : receive_codec_(), dec_map_(), dec_external_map_() {}
36
37VCMDecoderDataBase::~VCMDecoderDataBase() {
38 ptr_decoder_.reset();
39 for (auto& kv : dec_map_)
40 delete kv.second;
41 for (auto& kv : dec_external_map_)
42 delete kv.second;
43}
44
45bool VCMDecoderDataBase::DeregisterExternalDecoder(uint8_t payload_type) {
46 ExternalDecoderMap::iterator it = dec_external_map_.find(payload_type);
47 if (it == dec_external_map_.end()) {
Åsa Persson6cb74fd2018-06-01 15:13:42 +020048 // Not found.
Niels Möllerf9063782018-02-20 16:09:48 +010049 return false;
50 }
51 // We can't use payload_type to check if the decoder is currently in use,
52 // because payload type may be out of date (e.g. before we decode the first
Åsa Persson6cb74fd2018-06-01 15:13:42 +020053 // frame after RegisterReceiveCodec).
Niels Möllerf9063782018-02-20 16:09:48 +010054 if (ptr_decoder_ &&
55 ptr_decoder_->IsSameDecoder((*it).second->external_decoder_instance)) {
56 // Release it if it was registered and in use.
57 ptr_decoder_.reset();
58 }
59 DeregisterReceiveCodec(payload_type);
60 delete it->second;
61 dec_external_map_.erase(it);
62 return true;
63}
64
Åsa Persson6cb74fd2018-06-01 15:13:42 +020065// Add the external decoder object to the list of external decoders.
Niels Möllerf9063782018-02-20 16:09:48 +010066// Won't be registered as a receive codec until RegisterReceiveCodec is called.
67void VCMDecoderDataBase::RegisterExternalDecoder(VideoDecoder* external_decoder,
68 uint8_t payload_type) {
Åsa Persson6cb74fd2018-06-01 15:13:42 +020069 // If payload value already exists, erase old and insert new.
Niels Möllerf9063782018-02-20 16:09:48 +010070 VCMExtDecoderMapItem* ext_decoder =
71 new VCMExtDecoderMapItem(external_decoder, payload_type);
72 DeregisterExternalDecoder(payload_type);
73 dec_external_map_[payload_type] = ext_decoder;
74}
75
Niels Möllerf9063782018-02-20 16:09:48 +010076bool VCMDecoderDataBase::RegisterReceiveCodec(const VideoCodec* receive_codec,
77 int number_of_cores,
78 bool require_key_frame) {
79 if (number_of_cores < 0) {
80 return false;
81 }
Åsa Persson6cb74fd2018-06-01 15:13:42 +020082 // If payload value already exists, erase old and insert new.
Niels Möllerf9063782018-02-20 16:09:48 +010083 DeregisterReceiveCodec(receive_codec->plType);
84 if (receive_codec->codecType == kVideoCodecUnknown) {
85 return false;
86 }
87 VideoCodec* new_receive_codec = new VideoCodec(*receive_codec);
88 dec_map_[receive_codec->plType] = new VCMDecoderMapItem(
89 new_receive_codec, number_of_cores, require_key_frame);
90 return true;
91}
92
93bool VCMDecoderDataBase::DeregisterReceiveCodec(uint8_t payload_type) {
94 DecoderMap::iterator it = dec_map_.find(payload_type);
95 if (it == dec_map_.end()) {
96 return false;
97 }
98 delete it->second;
99 dec_map_.erase(it);
100 if (receive_codec_.plType == payload_type) {
101 // This codec is currently in use.
102 memset(&receive_codec_, 0, sizeof(VideoCodec));
103 }
104 return true;
105}
106
107VCMGenericDecoder* VCMDecoderDataBase::GetDecoder(
108 const VCMEncodedFrame& frame,
109 VCMDecodedFrameCallback* decoded_frame_callback) {
110 RTC_DCHECK(decoded_frame_callback->UserReceiveCallback());
111 uint8_t payload_type = frame.PayloadType();
112 if (payload_type == receive_codec_.plType || payload_type == 0) {
113 return ptr_decoder_.get();
114 }
Åsa Persson6cb74fd2018-06-01 15:13:42 +0200115 // If decoder exists - delete.
Niels Möllerf9063782018-02-20 16:09:48 +0100116 if (ptr_decoder_) {
117 ptr_decoder_.reset();
118 memset(&receive_codec_, 0, sizeof(VideoCodec));
119 }
120 ptr_decoder_ = CreateAndInitDecoder(frame, &receive_codec_);
121 if (!ptr_decoder_) {
122 return nullptr;
123 }
124 VCMReceiveCallback* callback = decoded_frame_callback->UserReceiveCallback();
125 callback->OnIncomingPayloadType(receive_codec_.plType);
126 if (ptr_decoder_->RegisterDecodeCompleteCallback(decoded_frame_callback) <
127 0) {
128 ptr_decoder_.reset();
129 memset(&receive_codec_, 0, sizeof(VideoCodec));
130 return nullptr;
131 }
132 return ptr_decoder_.get();
133}
134
Niels Möllerf9063782018-02-20 16:09:48 +0100135bool VCMDecoderDataBase::PrefersLateDecoding() const {
136 return ptr_decoder_ ? ptr_decoder_->PrefersLateDecoding() : true;
137}
138
139std::unique_ptr<VCMGenericDecoder> VCMDecoderDataBase::CreateAndInitDecoder(
140 const VCMEncodedFrame& frame,
141 VideoCodec* new_codec) const {
142 uint8_t payload_type = frame.PayloadType();
143 RTC_LOG(LS_INFO) << "Initializing decoder with payload type '"
144 << static_cast<int>(payload_type) << "'.";
145 RTC_DCHECK(new_codec);
146 const VCMDecoderMapItem* decoder_item = FindDecoderItem(payload_type);
147 if (!decoder_item) {
148 RTC_LOG(LS_ERROR) << "Can't find a decoder associated with payload type: "
149 << static_cast<int>(payload_type);
150 return nullptr;
151 }
152 std::unique_ptr<VCMGenericDecoder> ptr_decoder;
153 const VCMExtDecoderMapItem* external_dec_item =
154 FindExternalDecoderItem(payload_type);
155 if (external_dec_item) {
156 // External codec.
157 ptr_decoder.reset(new VCMGenericDecoder(
158 external_dec_item->external_decoder_instance, true));
159 } else {
Niels Möllerf9063782018-02-20 16:09:48 +0100160 RTC_LOG(LS_ERROR) << "No decoder of this type exists.";
Niels Möllerf9063782018-02-20 16:09:48 +0100161 }
162 if (!ptr_decoder)
163 return nullptr;
164
165 // Copy over input resolutions to prevent codec reinitialization due to
166 // the first frame being of a different resolution than the database values.
167 // This is best effort, since there's no guarantee that width/height have been
168 // parsed yet (and may be zero).
169 if (frame.EncodedImage()._encodedWidth > 0 &&
170 frame.EncodedImage()._encodedHeight > 0) {
171 decoder_item->settings->width = frame.EncodedImage()._encodedWidth;
172 decoder_item->settings->height = frame.EncodedImage()._encodedHeight;
173 }
174 if (ptr_decoder->InitDecode(decoder_item->settings.get(),
175 decoder_item->number_of_cores) < 0) {
176 return nullptr;
177 }
178 memcpy(new_codec, decoder_item->settings.get(), sizeof(VideoCodec));
179 return ptr_decoder;
180}
181
182const 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
191const 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