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