2 * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
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.
11 #include "modules/video_coding/decoder_database.h"
16 #include "rtc_base/checks.h"
17 #include "rtc_base/logging.h"
21 VCMDecoderDatabase::VCMDecoderDatabase() {
22 decoder_sequence_checker_
.Detach();
25 void VCMDecoderDatabase::DeregisterExternalDecoder(uint8_t payload_type
) {
26 RTC_DCHECK_RUN_ON(&decoder_sequence_checker_
);
27 auto it
= decoders_
.find(payload_type
);
28 if (it
== decoders_
.end()) {
32 // We can't use payload_type to check if the decoder is currently in use,
33 // because payload type may be out of date (e.g. before we decode the first
34 // frame after RegisterReceiveCodec).
35 if (current_decoder_
&& current_decoder_
->IsSameDecoder(it
->second
.get())) {
36 // Release it if it was registered and in use.
37 current_decoder_
= absl::nullopt
;
42 // Add the external decoder object to the list of external decoders.
43 // Won't be registered as a receive codec until RegisterReceiveCodec is called.
44 void VCMDecoderDatabase::RegisterExternalDecoder(
46 std::unique_ptr
<VideoDecoder
> external_decoder
) {
47 RTC_DCHECK_RUN_ON(&decoder_sequence_checker_
);
48 // If payload value already exists, erase old and insert new.
49 DeregisterExternalDecoder(payload_type
);
50 if (external_decoder
) {
52 std::make_pair(payload_type
, std::move(external_decoder
)));
56 bool VCMDecoderDatabase::IsExternalDecoderRegistered(
57 uint8_t payload_type
) const {
58 RTC_DCHECK_RUN_ON(&decoder_sequence_checker_
);
59 return decoders_
.find(payload_type
) != decoders_
.end();
62 void VCMDecoderDatabase::RegisterReceiveCodec(
64 const VideoDecoder::Settings
& settings
) {
65 // If payload value already exists, erase old and insert new.
66 if (payload_type
== current_payload_type_
) {
67 current_payload_type_
= absl::nullopt
;
69 decoder_settings_
[payload_type
] = settings
;
72 bool VCMDecoderDatabase::DeregisterReceiveCodec(uint8_t payload_type
) {
73 if (decoder_settings_
.erase(payload_type
) == 0) {
76 if (payload_type
== current_payload_type_
) {
77 // This codec is currently in use.
78 current_payload_type_
= absl::nullopt
;
83 void VCMDecoderDatabase::DeregisterReceiveCodecs() {
84 current_payload_type_
= absl::nullopt
;
85 decoder_settings_
.clear();
88 VCMGenericDecoder
* VCMDecoderDatabase::GetDecoder(
89 const EncodedFrame
& frame
,
90 VCMDecodedFrameCallback
* decoded_frame_callback
) {
91 RTC_DCHECK_RUN_ON(&decoder_sequence_checker_
);
92 RTC_DCHECK(decoded_frame_callback
->UserReceiveCallback());
93 uint8_t payload_type
= frame
.PayloadType();
94 if (payload_type
== current_payload_type_
|| payload_type
== 0) {
95 return current_decoder_
.has_value() ? &*current_decoder_
: nullptr;
97 // If decoder exists - delete.
98 if (current_decoder_
.has_value()) {
99 current_decoder_
= absl::nullopt
;
100 current_payload_type_
= absl::nullopt
;
103 CreateAndInitDecoder(frame
);
104 if (current_decoder_
== absl::nullopt
) {
108 VCMReceiveCallback
* callback
= decoded_frame_callback
->UserReceiveCallback();
109 callback
->OnIncomingPayloadType(payload_type
);
110 if (current_decoder_
->RegisterDecodeCompleteCallback(decoded_frame_callback
) <
112 current_decoder_
= absl::nullopt
;
116 current_payload_type_
= payload_type
;
117 return &*current_decoder_
;
120 void VCMDecoderDatabase::CreateAndInitDecoder(const EncodedFrame
& frame
) {
121 uint8_t payload_type
= frame
.PayloadType();
122 RTC_DLOG(LS_INFO
) << "Initializing decoder with payload type '"
123 << int{payload_type
} << "'.";
124 auto decoder_item
= decoder_settings_
.find(payload_type
);
125 if (decoder_item
== decoder_settings_
.end()) {
126 RTC_LOG(LS_ERROR
) << "Can't find a decoder associated with payload type: "
127 << int{payload_type
};
130 auto external_dec_item
= decoders_
.find(payload_type
);
131 if (external_dec_item
== decoders_
.end()) {
132 RTC_LOG(LS_ERROR
) << "No decoder of this type exists.";
135 current_decoder_
.emplace(external_dec_item
->second
.get());
137 // Copy over input resolutions to prevent codec reinitialization due to
138 // the first frame being of a different resolution than the database values.
139 // This is best effort, since there's no guarantee that width/height have been
140 // parsed yet (and may be zero).
141 RenderResolution
frame_resolution(frame
.EncodedImage()._encodedWidth
,
142 frame
.EncodedImage()._encodedHeight
);
143 if (frame_resolution
.Valid()) {
144 decoder_item
->second
.set_max_render_resolution(frame_resolution
);
146 if (!current_decoder_
->Configure(decoder_item
->second
)) {
147 current_decoder_
= absl::nullopt
;
148 RTC_LOG(LS_ERROR
) << "Failed to initialize decoder.";
152 } // namespace webrtc