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_stub.h"
17 #include <shared_mutex>
18 #include <sstream>
19 #include <string>
20 #include "avcodec_errors.h"
21 #include "avcodec_parcel.h"
22 #include "avcodec_trace.h"
23 #include "avsharedmemory_ipc.h"
24 #include "buffer/avsharedmemorybase.h"
25 #include "meta/meta.h"
26 namespace {
27 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_FRAMEWORK, "CodecListenerStub"};
28 constexpr uint8_t LOG_FREQ = 10;
29 const int32_t MAX_SIZE = 100;
30 } // namespace
31
32 namespace OHOS {
33 namespace MediaAVCodec {
34 using namespace Media;
35 class CodecListenerStub::CodecBufferCache : public AVCodecDfxComponent, public NoCopyable {
36 public:
CodecBufferCache(bool isOutput)37 explicit CodecBufferCache(bool isOutput) : isOutput_(isOutput) {}
38 ~CodecBufferCache() = default;
39
ReadFromParcel(uint32_t index,MessageParcel & parcel,std::shared_ptr<AVBuffer> & buffer)40 bool ReadFromParcel(uint32_t index, MessageParcel &parcel, std::shared_ptr<AVBuffer> &buffer)
41 {
42 std::lock_guard<std::shared_mutex> lock(mutex_);
43 auto iter = caches_.find(index);
44 flag_ = static_cast<CacheFlag>(parcel.ReadUint8());
45 if (flag_ == CacheFlag::HIT_CACHE && iter == caches_.end()) {
46 AVCODEC_LOGW_WITH_TAG("Mark hit cache, but can find the index's cache, index: %{public}u", index);
47 flag_ = CacheFlag::UPDATE_CACHE;
48 }
49 if (flag_ == CacheFlag::HIT_CACHE) {
50 isOutput_ ? HitOutputCache(iter->second, parcel) : HitInputCache(iter->second, parcel);
51 buffer = iter->second;
52 return true;
53 }
54 if (flag_ == CacheFlag::UPDATE_CACHE) {
55 isOutput_ ? UpdateOutputCache(buffer, parcel) : UpdateInputCache(buffer, parcel);
56 if (iter == caches_.end()) {
57 caches_.emplace(index, buffer);
58 } else {
59 iter->second = buffer;
60 }
61 return true;
62 }
63 // invalidate cache flag_
64 if (iter != caches_.end()) {
65 caches_.erase(iter);
66 }
67 AVCODEC_LOGE_WITH_TAG("Invalidate cache for index: %{public}u, flag: %{public}hhu", index, flag_);
68 return false;
69 }
70
GetBuffer(uint32_t index,std::shared_ptr<AVBuffer> & buffer)71 void GetBuffer(uint32_t index, std::shared_ptr<AVBuffer> &buffer)
72 {
73 std::shared_lock<std::shared_mutex> lock(mutex_);
74 if (isFirstSend_) {
75 AVCODEC_LOGI_WITH_TAG("first send buffer to service");
76 isFirstSend_ = false;
77 }
78 auto iter = caches_.find(index);
79 if (iter == caches_.end()) {
80 AVCODEC_LOGE_WITH_TAG("Get cache failed, index: %{public}u", index);
81 return;
82 }
83 buffer = iter->second;
84 }
85
ClearCaches()86 void ClearCaches()
87 {
88 std::lock_guard<std::shared_mutex> lock(mutex_);
89 isFirstReceive_ = true;
90 isFirstSend_ = true;
91 caches_.clear();
92 }
93
FlushCaches()94 void FlushCaches()
95 {
96 std::lock_guard<std::shared_mutex> lock(mutex_);
97 isFirstReceive_ = true;
98 isFirstSend_ = true;
99 }
100
101 private:
HitInputCache(std::shared_ptr<AVBuffer> & buffer,MessageParcel & parcel)102 void HitInputCache(std::shared_ptr<AVBuffer> &buffer, MessageParcel &parcel)
103 {
104 CHECK_AND_RETURN_LOG_WITH_TAG(buffer != nullptr, "buffer is nullptr");
105 bool isReadSuc = buffer->ReadFromMessageParcel(parcel);
106 CHECK_AND_RETURN_LOG_WITH_TAG(isReadSuc, "Read buffer from parcel failed");
107 buffer->flag_ = 0;
108 if (buffer->memory_ != nullptr) {
109 buffer->memory_->SetOffset(0);
110 buffer->memory_->SetSize(0);
111 }
112 if (isFirstReceive_) {
113 AVCODEC_LOGI_WITH_TAG("first receive buffer from service");
114 isFirstReceive_ = false;
115 }
116 }
117
HitOutputCache(std::shared_ptr<AVBuffer> & buffer,MessageParcel & parcel)118 void HitOutputCache(std::shared_ptr<AVBuffer> &buffer, MessageParcel &parcel)
119 {
120 CHECK_AND_RETURN_LOG_WITH_TAG(buffer != nullptr, "buffer is nullptr");
121 bool isReadSuc = buffer->ReadFromMessageParcel(parcel);
122 CHECK_AND_RETURN_LOG_WITH_TAG(isReadSuc, "Read buffer from parcel failed");
123 if (isFirstReceive_) {
124 AVCODEC_LOGI_WITH_TAG("first receive buffer from service");
125 isFirstReceive_ = false;
126 }
127 }
128
UpdateInputCache(std::shared_ptr<AVBuffer> & buffer,MessageParcel & parcel)129 void UpdateInputCache(std::shared_ptr<AVBuffer> &buffer, MessageParcel &parcel)
130 {
131 buffer = AVBuffer::CreateAVBuffer();
132 bool isReadSuc = (buffer != nullptr) && buffer->ReadFromMessageParcel(parcel);
133 CHECK_AND_RETURN_LOG_WITH_TAG(isReadSuc, "Create buffer from parcel failed");
134 buffer->flag_ = 0;
135 if (buffer->memory_ != nullptr) {
136 buffer->memory_->SetOffset(0);
137 buffer->memory_->SetSize(0);
138 }
139 if (isFirstReceive_) {
140 AVCODEC_LOGI_WITH_TAG("first receive buffer from service");
141 isFirstReceive_ = false;
142 }
143 }
144
UpdateOutputCache(std::shared_ptr<AVBuffer> & buffer,MessageParcel & parcel)145 void UpdateOutputCache(std::shared_ptr<AVBuffer> &buffer, MessageParcel &parcel)
146 {
147 buffer = AVBuffer::CreateAVBuffer();
148 bool isReadSuc = (buffer != nullptr) && buffer->ReadFromMessageParcel(parcel);
149 CHECK_AND_RETURN_LOG_WITH_TAG(isReadSuc, "Create buffer from parcel failed");
150 if (isFirstReceive_) {
151 AVCODEC_LOGI_WITH_TAG("first receive buffer from service");
152 isFirstReceive_ = false;
153 }
154 }
155
156 enum class CacheFlag : uint8_t {
157 HIT_CACHE = 1,
158 UPDATE_CACHE,
159 INVALIDATE_CACHE,
160 };
161 bool isOutput_ = false;
162 bool isFirstReceive_ = true;
163 bool isFirstSend_ = true;
164 CacheFlag flag_ = CacheFlag::INVALIDATE_CACHE;
165 std::shared_mutex mutex_;
166 std::unordered_map<uint32_t, std::shared_ptr<AVBuffer>> caches_;
167 };
168
CodecListenerStub()169 CodecListenerStub::CodecListenerStub()
170 {
171 if (inputBufferCache_ == nullptr) {
172 inputBufferCache_ = std::make_unique<CodecBufferCache>(false);
173 }
174
175 if (outputBufferCache_ == nullptr) {
176 outputBufferCache_ = std::make_unique<CodecBufferCache>(true);
177 }
178 AVCODEC_LOGD_WITH_TAG("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
179 }
180
~CodecListenerStub()181 CodecListenerStub::~CodecListenerStub()
182 {
183 inputBufferCache_ = nullptr;
184 outputBufferCache_ = nullptr;
185 AVCODEC_LOGD_WITH_TAG("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
186 }
187
Init()188 void CodecListenerStub::Init()
189 {
190 const std::string &tag = this->GetTag();
191 inputBufferCache_->SetTag(tag + "[in]");
192 outputBufferCache_->SetTag(tag + "[out]");
193 }
194
OnRemoteRequest(uint32_t code,MessageParcel & data,MessageParcel & reply,MessageOption & option)195 int CodecListenerStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)
196 {
197 auto remoteDescriptor = data.ReadInterfaceToken();
198 CHECK_AND_RETURN_RET_LOG_WITH_TAG(CodecListenerStub::GetDescriptor() == remoteDescriptor,
199 AVCS_ERR_INVALID_OPERATION, "Invalid descriptor");
200 CHECK_AND_RETURN_RET_LOG_WITH_TAG(inputBufferCache_ != nullptr, AVCS_ERR_INVALID_OPERATION,
201 "inputBufferCache is nullptr");
202 CHECK_AND_RETURN_RET_LOG_WITH_TAG(outputBufferCache_ != nullptr, AVCS_ERR_INVALID_OPERATION,
203 "outputBufferCache is nullptr");
204
205 CHECK_AND_RETURN_RET_LOG_WITH_TAG(syncMutex_ != nullptr, AVCS_ERR_INVALID_OPERATION, "sync mutex is nullptr");
206 std::lock_guard<std::recursive_mutex> lock(*syncMutex_);
207 if (!needListen_ || !CheckGeneration(data.ReadUint64())) {
208 AVCODEC_LOGW_LIMIT(LOG_FREQ, "abandon message");
209 return AVCS_ERR_OK;
210 }
211 switch (code) {
212 case static_cast<uint32_t>(CodecListenerInterfaceCode::ON_ERROR): {
213 int32_t errorType = data.ReadInt32();
214 int32_t errorCode = data.ReadInt32();
215 OnError(static_cast<AVCodecErrorType>(errorType), errorCode);
216 return AVCS_ERR_OK;
217 }
218 case static_cast<uint32_t>(CodecListenerInterfaceCode::ON_OUTPUT_FORMAT_CHANGED): {
219 Format format;
220 (void)AVCodecParcel::Unmarshalling(data, format);
221 outputBufferCache_->ClearCaches();
222 OnOutputFormatChanged(format);
223 return AVCS_ERR_OK;
224 }
225 case static_cast<uint32_t>(CodecListenerInterfaceCode::ON_INPUT_BUFFER_AVAILABLE): {
226 uint32_t index = data.ReadUint32();
227 OnInputBufferAvailable(index, data);
228 return AVCS_ERR_OK;
229 }
230 case static_cast<uint32_t>(CodecListenerInterfaceCode::ON_OUTPUT_BUFFER_AVAILABLE): {
231 uint32_t index = data.ReadUint32();
232 OnOutputBufferAvailable(index, data);
233 return AVCS_ERR_OK;
234 }
235 default: {
236 return OnRequestExtras(code, data, reply, option);
237 }
238 }
239 }
240
OnRequestExtras(uint32_t code,MessageParcel & data,MessageParcel & reply,MessageOption & option)241 int CodecListenerStub::OnRequestExtras(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)
242 {
243 switch (code) {
244 case static_cast<uint32_t>(CodecListenerInterfaceCode::ON_OUTPUT_BUFFER_BINDED): {
245 OnOutputBufferBinded(data);
246 return AVCS_ERR_OK;
247 }
248 case static_cast<uint32_t>(CodecListenerInterfaceCode::ON_OUTPUT_BUFFER_UN_BINDED): {
249 OnOutputBufferUnbinded(data);
250 return AVCS_ERR_OK;
251 }
252 default: {
253 AVCODEC_LOGE_WITH_TAG("Default case, please check codec listener stub");
254 return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
255 }
256 }
257 }
258
OnError(AVCodecErrorType errorType,int32_t errorCode)259 void CodecListenerStub::OnError(AVCodecErrorType errorType, int32_t errorCode)
260 {
261 std::shared_ptr<MediaCodecCallback> vCb = callback_.lock();
262 if (vCb != nullptr) {
263 vCb->OnError(errorType, errorCode);
264 return;
265 }
266 }
267
OnOutputFormatChanged(const Format & format)268 void CodecListenerStub::OnOutputFormatChanged(const Format &format)
269 {
270 std::shared_ptr<MediaCodecCallback> vCb = callback_.lock();
271 if (vCb != nullptr) {
272 vCb->OnOutputFormatChanged(format);
273 return;
274 }
275 }
276
OnInputBufferAvailable(uint32_t index,std::shared_ptr<AVBuffer> buffer)277 void CodecListenerStub::OnInputBufferAvailable(uint32_t index, std::shared_ptr<AVBuffer> buffer)
278 {
279 (void)index;
280 (void)buffer;
281 }
282
OnOutputBufferAvailable(uint32_t index,std::shared_ptr<AVBuffer> buffer)283 void CodecListenerStub::OnOutputBufferAvailable(uint32_t index, std::shared_ptr<AVBuffer> buffer)
284 {
285 (void)index;
286 (void)buffer;
287 }
288
OnOutputBufferBinded(std::map<uint32_t,sptr<SurfaceBuffer>> & bufferMap)289 void CodecListenerStub::OnOutputBufferBinded(std::map<uint32_t, sptr<SurfaceBuffer>> &bufferMap)
290 {
291 (void)bufferMap;
292 }
OnOutputBufferUnbinded()293 void CodecListenerStub::OnOutputBufferUnbinded()
294 {
295 }
296
OnInputBufferAvailable(uint32_t index,MessageParcel & data)297 void CodecListenerStub::OnInputBufferAvailable(uint32_t index, MessageParcel &data)
298 {
299 std::shared_ptr<AVBuffer> buffer;
300 std::shared_ptr<MediaCodecCallback> mediaCb = callback_.lock();
301 if (mediaCb != nullptr) {
302 bool ret = inputBufferCache_->ReadFromParcel(index, data, buffer);
303 CHECK_AND_RETURN_LOG_WITH_TAG(ret, "read from parel failed");
304 mediaCb->OnInputBufferAvailable(index, buffer);
305 return;
306 }
307 }
308
OnOutputBufferAvailable(uint32_t index,MessageParcel & data)309 void CodecListenerStub::OnOutputBufferAvailable(uint32_t index, MessageParcel &data)
310 {
311 std::shared_ptr<AVBuffer> buffer;
312 std::shared_ptr<MediaCodecCallback> mediaCb = callback_.lock();
313 if (mediaCb != nullptr) {
314 bool ret = outputBufferCache_->ReadFromParcel(index, data, buffer);
315 CHECK_AND_RETURN_LOG_WITH_TAG(ret, "read from parel failed");
316 mediaCb->OnOutputBufferAvailable(index, buffer);
317 return;
318 }
319 }
320
OnOutputBufferBinded(MessageParcel & data)321 void CodecListenerStub::OnOutputBufferBinded(MessageParcel &data)
322 {
323 std::shared_ptr<MediaCodecCallback> mediaCb = callback_.lock();
324 if (mediaCb != nullptr) {
325 std::map<uint32_t, sptr<SurfaceBuffer>> bufferMap;
326 const MediaAVCodec::Format format;
327 uint32_t size = data.ReadUint32();
328 if (size > MAX_SIZE) {
329 bufferMap.clear();
330 return;
331 }
332 for (uint32_t i = 0; i < size; i++) {
333 uint32_t key = data.ReadUint32();
334 sptr<SurfaceBuffer> surfaceBuffer = SurfaceBuffer::Create();
335 surfaceBuffer->ReadFromMessageParcel(data);
336 bufferMap.emplace(key, surfaceBuffer);
337 }
338 AVCODEC_LOGI("LowPowerPlayer CodecListenerStub OnOutputBufferBinded Write Map Success");
339 mediaCb->OnOutputBufferBinded(bufferMap);
340 return;
341 }
342 }
343
OnOutputBufferUnbinded(MessageParcel & data)344 void CodecListenerStub::OnOutputBufferUnbinded(MessageParcel &data)
345 {
346 AVCODEC_LOGI("LowPowerPlayer CodecListenerStub OnOutputBufferUnbinded Enter");
347 std::shared_ptr<MediaCodecCallback> mediaCb = callback_.lock();
348 CHECK_AND_RETURN_LOG(mediaCb != nullptr, "mediaCb is nullptr");
349 mediaCb->OnOutputBufferUnbinded();
350 }
351
SetCallback(const std::shared_ptr<MediaCodecCallback> & callback)352 void CodecListenerStub::SetCallback(const std::shared_ptr<MediaCodecCallback> &callback)
353 {
354 callback_ = callback;
355 }
356
ClearListenerCache()357 void CodecListenerStub::ClearListenerCache()
358 {
359 inputBufferCache_->ClearCaches();
360 outputBufferCache_->ClearCaches();
361 }
362
FlushListenerCache()363 void CodecListenerStub::FlushListenerCache()
364 {
365 inputBufferCache_->FlushCaches();
366 outputBufferCache_->FlushCaches();
367 }
368
WriteInputBufferToParcel(uint32_t index,MessageParcel & data)369 bool CodecListenerStub::WriteInputBufferToParcel(uint32_t index, MessageParcel &data)
370 {
371 std::shared_ptr<AVBuffer> buffer = nullptr;
372 inputBufferCache_->GetBuffer(index, buffer);
373 CHECK_AND_RETURN_RET_LOG_WITH_TAG(buffer != nullptr, false, "Get buffer is nullptr");
374 CHECK_AND_RETURN_RET_LOG_WITH_TAG(buffer->meta_ != nullptr, false, "Get buffer meta is nullptr");
375 if (buffer->memory_ == nullptr) {
376 return buffer->meta_->ToParcel(data);
377 }
378 return data.WriteInt64(buffer->pts_) && data.WriteInt32(buffer->memory_->GetOffset()) &&
379 data.WriteInt32(buffer->memory_->GetSize()) && data.WriteUint32(buffer->flag_) &&
380 buffer->meta_->ToParcel(data);
381 }
382
WriteOutputBufferToParcel(uint32_t index,MessageParcel & data)383 bool CodecListenerStub::WriteOutputBufferToParcel(uint32_t index, MessageParcel &data)
384 {
385 (void)data;
386 std::shared_ptr<AVBuffer> buffer = nullptr;
387 outputBufferCache_->GetBuffer(index, buffer);
388 return true;
389 }
390
CheckGeneration(uint64_t messageGeneration) const391 bool CodecListenerStub::CheckGeneration(uint64_t messageGeneration) const
392 {
393 return messageGeneration >= GetGeneration();
394 }
395
SetMutex(std::shared_ptr<std::recursive_mutex> & mutex)396 void CodecListenerStub::SetMutex(std::shared_ptr<std::recursive_mutex> &mutex)
397 {
398 syncMutex_ = mutex;
399 }
400
SetNeedListen(const bool needListen)401 void CodecListenerStub::SetNeedListen(const bool needListen)
402 {
403 needListen_ = needListen;
404 }
405 } // namespace MediaAVCodec
406 } // namespace OHOS
407