1 /*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "codec_listener_proxy.h"
17 #include <shared_mutex>
18 #include "avcodec_errors.h"
19 #include "avcodec_log.h"
20 #include "avcodec_parcel.h"
21 #include "avsharedmemory_ipc.h"
22 #include "buffer/avbuffer.h"
23 #include "meta/meta.h"
24
25 namespace {
26 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_FRAMEWORK, "CodecListenerProxy"};
27 }
28
29 namespace OHOS {
30 namespace MediaAVCodec {
31 class CodecListenerProxy::CodecBufferCache : public NoCopyable {
32 public:
33 CodecBufferCache() = default;
34 ~CodecBufferCache() = default;
35
WriteToParcel(uint32_t index,const std::shared_ptr<AVBuffer> & buffer,MessageParcel & parcel)36 bool WriteToParcel(uint32_t index, const std::shared_ptr<AVBuffer> &buffer, MessageParcel &parcel)
37 {
38 std::lock_guard<std::shared_mutex> lock(mutex_);
39 CacheFlag flag = CacheFlag::UPDATE_CACHE;
40 if (buffer == nullptr) {
41 AVCODEC_LOGD("Invalid buffer for index: %{public}u", index);
42 flag = CacheFlag::INVALIDATE_CACHE;
43 parcel.WriteUint8(static_cast<uint8_t>(flag));
44 auto iter = caches_.find(index);
45 if (iter != caches_.end()) {
46 iter->second = std::shared_ptr<AVBuffer>(nullptr);
47 caches_.erase(iter);
48 }
49 return true;
50 }
51
52 auto iter = caches_.find(index);
53 if (iter != caches_.end() && iter->second.lock() == buffer) {
54 flag = CacheFlag::HIT_CACHE;
55 parcel.WriteUint8(static_cast<uint8_t>(flag));
56 return buffer->WriteToMessageParcel(parcel);
57 }
58
59 if (iter == caches_.end()) {
60 AVCODEC_LOGD("Add cache codec buffer, index: %{public}u", index);
61 caches_.emplace(index, buffer);
62 } else {
63 AVCODEC_LOGD("Update cache codec buffer, index: %{public}u", index);
64 iter->second = buffer;
65 }
66
67 parcel.WriteUint8(static_cast<uint8_t>(flag));
68
69 return buffer->WriteToMessageParcel(parcel);
70 }
71
FindBufferFromIndex(uint32_t index)72 std::shared_ptr<AVBuffer> FindBufferFromIndex(uint32_t index)
73 {
74 std::shared_lock<std::shared_mutex> lock(mutex_);
75 auto iter = caches_.find(index);
76 if (iter != caches_.end()) {
77 return iter->second.lock();
78 }
79 return nullptr;
80 }
81
ClearCaches()82 void ClearCaches()
83 {
84 std::lock_guard<std::shared_mutex> lock(mutex_);
85 for (auto iter = caches_.begin(); iter != caches_.end();) {
86 if (iter->second.expired()) {
87 iter = caches_.erase(iter);
88 } else {
89 ++iter;
90 }
91 }
92 }
93
94 private:
95 std::shared_mutex mutex_;
96 enum class CacheFlag : uint8_t {
97 HIT_CACHE = 1,
98 UPDATE_CACHE,
99 INVALIDATE_CACHE,
100 };
101
102 std::unordered_map<uint32_t, std::weak_ptr<AVBuffer>> caches_;
103 };
104
CodecListenerProxy(const sptr<IRemoteObject> & impl)105 CodecListenerProxy::CodecListenerProxy(const sptr<IRemoteObject> &impl) : IRemoteProxy<IStandardCodecListener>(impl)
106 {
107 if (inputBufferCache_ == nullptr) {
108 inputBufferCache_ = std::make_unique<CodecBufferCache>();
109 }
110 if (outputBufferCache_ == nullptr) {
111 outputBufferCache_ = std::make_unique<CodecBufferCache>();
112 }
113 AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
114 }
115
~CodecListenerProxy()116 CodecListenerProxy::~CodecListenerProxy()
117 {
118 inputBufferCache_ = nullptr;
119 outputBufferCache_ = nullptr;
120 AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
121 }
122
OnError(AVCodecErrorType errorType,int32_t errorCode)123 void CodecListenerProxy::OnError(AVCodecErrorType errorType, int32_t errorCode)
124 {
125 MessageParcel data;
126 MessageParcel reply;
127 MessageOption option(MessageOption::TF_ASYNC);
128 bool token = data.WriteInterfaceToken(CodecListenerProxy::GetDescriptor());
129 CHECK_AND_RETURN_LOG(token, "Write descriptor failed!");
130
131 data.WriteUint64(GetGeneration());
132 data.WriteInt32(static_cast<int32_t>(errorType));
133 data.WriteInt32(errorCode);
134 int error = Remote()->SendRequest(static_cast<uint32_t>(CodecListenerInterfaceCode::ON_ERROR), data, reply, option);
135 CHECK_AND_RETURN_LOG(error == AVCS_ERR_OK, "Send request failed");
136 }
137
OnOutputFormatChanged(const Format & format)138 void CodecListenerProxy::OnOutputFormatChanged(const Format &format)
139 {
140 MessageParcel data;
141 MessageParcel reply;
142 MessageOption option(MessageOption::TF_ASYNC);
143 bool token = data.WriteInterfaceToken(CodecListenerProxy::GetDescriptor());
144 CHECK_AND_RETURN_LOG(token, "Write descriptor failed!");
145
146 data.WriteUint64(GetGeneration());
147 (void)AVCodecParcel::Marshalling(data, format);
148 CHECK_AND_RETURN_LOG(outputBufferCache_ != nullptr, "Output buffer cache is nullptr");
149 outputBufferCache_->ClearCaches();
150 int error = Remote()->SendRequest(static_cast<uint32_t>(CodecListenerInterfaceCode::ON_OUTPUT_FORMAT_CHANGED), data,
151 reply, option);
152 CHECK_AND_RETURN_LOG(error == AVCS_ERR_OK, "Send request failed");
153 }
154
OnInputBufferAvailable(uint32_t index,std::shared_ptr<AVBuffer> buffer)155 void CodecListenerProxy::OnInputBufferAvailable(uint32_t index, std::shared_ptr<AVBuffer> buffer)
156 {
157 CHECK_AND_RETURN_LOG(inputBufferCache_ != nullptr, "Input buffer cache is nullptr");
158 MessageParcel data;
159 MessageParcel reply;
160 MessageOption option(MessageOption::TF_ASYNC);
161 bool token = data.WriteInterfaceToken(CodecListenerProxy::GetDescriptor());
162 CHECK_AND_RETURN_LOG(token, "Write descriptor failed!");
163
164 uint64_t currentGeneration = GetGeneration();
165 if (inputBufferGeneration_ != currentGeneration) {
166 inputBufferCache_->ClearCaches();
167 inputBufferGeneration_ = currentGeneration;
168 }
169
170 data.WriteUint64(inputBufferGeneration_);
171 data.WriteUint32(index);
172 if (buffer != nullptr && buffer->meta_ != nullptr) {
173 buffer->meta_->Clear();
174 }
175 bool ret = inputBufferCache_->WriteToParcel(index, buffer, data);
176 CHECK_AND_RETURN_LOG(ret, "InputBufferCache write parcel failed");
177 int error = Remote()->SendRequest(static_cast<uint32_t>(CodecListenerInterfaceCode::ON_INPUT_BUFFER_AVAILABLE),
178 data, reply, option);
179 CHECK_AND_RETURN_LOG(error == AVCS_ERR_OK, "Send request failed");
180 }
181
OnOutputBufferAvailable(uint32_t index,std::shared_ptr<AVBuffer> buffer)182 void CodecListenerProxy::OnOutputBufferAvailable(uint32_t index, std::shared_ptr<AVBuffer> buffer)
183 {
184 CHECK_AND_RETURN_LOG(outputBufferCache_ != nullptr, "Output buffer cache is nullptr");
185 MessageParcel data;
186 MessageParcel reply;
187 MessageOption option(MessageOption::TF_ASYNC);
188 bool token = data.WriteInterfaceToken(CodecListenerProxy::GetDescriptor());
189 CHECK_AND_RETURN_LOG(token, "Write descriptor failed!");
190
191 uint64_t currentGeneration = GetGeneration();
192 if (outputBufferGeneration_ != currentGeneration) {
193 outputBufferCache_->ClearCaches();
194 outputBufferGeneration_ = currentGeneration;
195 }
196
197 data.WriteUint64(outputBufferGeneration_);
198 data.WriteUint32(index);
199 bool ret = outputBufferCache_->WriteToParcel(index, buffer, data);
200 CHECK_AND_RETURN_LOG(ret, "OutputBufferCache write parcel failed");
201 int error = Remote()->SendRequest(static_cast<uint32_t>(CodecListenerInterfaceCode::ON_OUTPUT_BUFFER_AVAILABLE),
202 data, reply, option);
203 CHECK_AND_RETURN_LOG(error == AVCS_ERR_OK, "Send request failed");
204 }
205
InputBufferInfoFromParcel(uint32_t index,AVCodecBufferInfo & info,AVCodecBufferFlag & flag,MessageParcel & data)206 bool CodecListenerProxy::InputBufferInfoFromParcel(uint32_t index, AVCodecBufferInfo &info, AVCodecBufferFlag &flag,
207 MessageParcel &data)
208 {
209 std::shared_ptr<AVBuffer> buffer = inputBufferCache_->FindBufferFromIndex(index);
210 CHECK_AND_RETURN_RET_LOG(buffer != nullptr, false, "Input buffer in cache is nullptr");
211 CHECK_AND_RETURN_RET_LOG(buffer->meta_ != nullptr, false, "buffer meta is nullptr");
212 if (buffer->memory_ == nullptr) {
213 return buffer->meta_->FromParcel(data);
214 }
215 uint32_t flagTemp = 0;
216 bool ret = data.ReadInt64(info.presentationTimeUs) && data.ReadInt32(info.offset) && data.ReadInt32(info.size) &&
217 data.ReadUint32(flagTemp);
218 flag = static_cast<AVCodecBufferFlag>(flagTemp);
219 buffer->pts_ = info.presentationTimeUs;
220 buffer->flag_ = flag;
221 buffer->memory_->SetOffset(info.offset);
222 buffer->memory_->SetSize(info.size);
223 return ret && buffer->meta_->FromParcel(data);
224 }
225
SetOutputBufferRenderTimestamp(uint32_t index,int64_t renderTimestampNs)226 bool CodecListenerProxy::SetOutputBufferRenderTimestamp(uint32_t index, int64_t renderTimestampNs)
227 {
228 std::shared_ptr<AVBuffer> buffer = outputBufferCache_->FindBufferFromIndex(index);
229 CHECK_AND_RETURN_RET_LOG(buffer != nullptr, false, "Input buffer in cache is nullptr");
230 buffer->meta_->SetData(Media::Tag::VIDEO_DECODER_DESIRED_PRESENT_TIMESTAMP, renderTimestampNs);
231 return true;
232 }
233
ClearListenerCache()234 void CodecListenerProxy::ClearListenerCache()
235 {
236 inputBufferCache_->ClearCaches();
237 outputBufferCache_->ClearCaches();
238 }
239
CodecListenerCallback(const sptr<IStandardCodecListener> & listener)240 CodecListenerCallback::CodecListenerCallback(const sptr<IStandardCodecListener> &listener) : listener_(listener)
241 {
242 AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
243 }
244
~CodecListenerCallback()245 CodecListenerCallback::~CodecListenerCallback()
246 {
247 AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
248 }
249
OnError(AVCodecErrorType errorType,int32_t errorCode)250 void CodecListenerCallback::OnError(AVCodecErrorType errorType, int32_t errorCode)
251 {
252 if (listener_ != nullptr) {
253 listener_->OnError(errorType, errorCode);
254 }
255 }
256
OnOutputFormatChanged(const Format & format)257 void CodecListenerCallback::OnOutputFormatChanged(const Format &format)
258 {
259 if (listener_ != nullptr) {
260 listener_->OnOutputFormatChanged(format);
261 }
262 }
263
OnInputBufferAvailable(uint32_t index,std::shared_ptr<AVBuffer> buffer)264 void CodecListenerCallback::OnInputBufferAvailable(uint32_t index, std::shared_ptr<AVBuffer> buffer)
265 {
266 if (listener_ != nullptr) {
267 listener_->OnInputBufferAvailable(index, buffer);
268 }
269 }
270
OnOutputBufferAvailable(uint32_t index,std::shared_ptr<AVBuffer> buffer)271 void CodecListenerCallback::OnOutputBufferAvailable(uint32_t index, std::shared_ptr<AVBuffer> buffer)
272 {
273 if (listener_ != nullptr) {
274 listener_->OnOutputBufferAvailable(index, buffer);
275 }
276 }
277 } // namespace MediaAVCodec
278 } // namespace OHOS
279