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 "avcodec_errors.h"
18 #include "avcodec_log.h"
19 #include "avcodec_parcel.h"
20 #include "avsharedmemory_ipc.h"
21
22 namespace {
23 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "CodecListenerStub"};
24 }
25
26 namespace OHOS {
27 namespace MediaAVCodec {
28 class CodecListenerStub::CodecBufferCache : public NoCopyable {
29 public:
30 CodecBufferCache() = default;
31 ~CodecBufferCache() = default;
32
ReadFromParcel(uint32_t index,MessageParcel & parcel,std::shared_ptr<AVSharedMemory> & memory)33 void ReadFromParcel(uint32_t index, MessageParcel &parcel, std::shared_ptr<AVSharedMemory> &memory)
34 {
35 std::lock_guard<std::mutex> lock(mutex_);
36 auto iter = caches_.find(index);
37 CacheFlag flag = static_cast<CacheFlag>(parcel.ReadUint8());
38 if (flag == CacheFlag::HIT_CACHE) {
39 if (iter == caches_.end()) {
40 AVCODEC_LOGE("Mark hit cache, but can find the index's cache, index: %{public}u", index);
41 return;
42 }
43 memory = iter->second;
44 return;
45 }
46
47 if (flag == CacheFlag::UPDATE_CACHE) {
48 memory = ReadAVSharedMemoryFromParcel(parcel);
49 CHECK_AND_RETURN_LOG(memory != nullptr, "Read memory from parcel failed");
50
51 if (iter == caches_.end()) {
52 AVCODEC_LOGI("Add cache, index: %{public}u", index);
53 caches_.emplace(index, memory);
54 } else {
55 iter->second = memory;
56 AVCODEC_LOGI("Update cache, index: %{public}u", index);
57 }
58 return;
59 }
60
61 // invalidate cache flag
62 if (iter != caches_.end()) {
63 iter->second = nullptr;
64 caches_.erase(iter);
65 }
66 memory = nullptr;
67 AVCODEC_LOGD("Invalidate cache for index: %{public}u, flag: %{public}hhu", index, flag);
68 return;
69 }
70
ClearCaches()71 void ClearCaches()
72 {
73 std::lock_guard<std::mutex> lock(mutex_);
74 caches_.clear();
75 }
76
77 private:
78 std::mutex mutex_;
79 enum class CacheFlag : uint8_t {
80 HIT_CACHE = 1,
81 UPDATE_CACHE,
82 INVALIDATE_CACHE,
83 };
84 std::unordered_map<uint32_t, std::shared_ptr<AVSharedMemory>> caches_;
85 };
86
CodecListenerStub()87 CodecListenerStub::CodecListenerStub()
88 {
89 if (inputBufferCache_ == nullptr) {
90 inputBufferCache_ = std::make_unique<CodecBufferCache>();
91 }
92
93 if (outputBufferCache_ == nullptr) {
94 outputBufferCache_ = std::make_unique<CodecBufferCache>();
95 }
96 AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
97 }
98
~CodecListenerStub()99 CodecListenerStub::~CodecListenerStub()
100 {
101 inputBufferCache_ = nullptr;
102 outputBufferCache_ = nullptr;
103 AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
104 }
105
OnRemoteRequest(uint32_t code,MessageParcel & data,MessageParcel & reply,MessageOption & option)106 int CodecListenerStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)
107 {
108 auto remoteDescriptor = data.ReadInterfaceToken();
109 CHECK_AND_RETURN_RET_LOG(CodecListenerStub::GetDescriptor() == remoteDescriptor, AVCS_ERR_INVALID_OPERATION,
110 "Invalid descriptor");
111 CHECK_AND_RETURN_RET_LOG(inputBufferCache_ != nullptr, AVCS_ERR_INVALID_OPERATION, "inputBufferCache is nullptr");
112 CHECK_AND_RETURN_RET_LOG(outputBufferCache_ != nullptr, AVCS_ERR_INVALID_OPERATION, "outputBufferCache is nullptr");
113
114 std::unique_lock<std::mutex> lock(syncMutex_, std::try_to_lock);
115 CHECK_AND_RETURN_RET_LOG(lock.owns_lock() && CheckGeneration(data.ReadUint64()), AVCS_ERR_OK, "abandon message");
116
117 callbackIsDoing_ = true;
118 switch (code) {
119 case static_cast<uint32_t>(CodecListenerInterfaceCode::ON_ERROR): {
120 int32_t errorType = data.ReadInt32();
121 int32_t errorCode = data.ReadInt32();
122 OnError(static_cast<AVCodecErrorType>(errorType), errorCode);
123 return AVCS_ERR_OK;
124 }
125 case static_cast<uint32_t>(CodecListenerInterfaceCode::ON_OUTPUT_FORMAT_CHANGED): {
126 Format format;
127 (void)AVCodecParcel::Unmarshalling(data, format);
128 outputBufferCache_->ClearCaches();
129 OnOutputFormatChanged(format);
130 return AVCS_ERR_OK;
131 }
132 case static_cast<uint32_t>(CodecListenerInterfaceCode::ON_INPUT_BUFFER_AVAILABLE): {
133 uint32_t index = data.ReadUint32();
134 std::shared_ptr<AVSharedMemory> memory = nullptr;
135 inputBufferCache_->ReadFromParcel(index, data, memory);
136 OnInputBufferAvailable(index, memory);
137 return AVCS_ERR_OK;
138 }
139 case static_cast<uint32_t>(CodecListenerInterfaceCode::ON_OUTPUT_BUFFER_AVAILABLE): {
140 uint32_t index = data.ReadUint32();
141 AVCodecBufferInfo info { data.ReadInt64(), data.ReadInt32(), data.ReadInt32() };
142 AVCodecBufferFlag flag = static_cast<AVCodecBufferFlag>(data.ReadInt32());
143 std::shared_ptr<AVSharedMemory> memory = nullptr;
144 outputBufferCache_->ReadFromParcel(index, data, memory);
145 OnOutputBufferAvailable(index, info, flag, memory);
146 return AVCS_ERR_OK;
147 }
148 default: {
149 AVCODEC_LOGE("Default case, please check codec listener stub");
150 Finalize();
151 return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
152 }
153 }
154 }
155
OnError(AVCodecErrorType errorType,int32_t errorCode)156 void CodecListenerStub::OnError(AVCodecErrorType errorType, int32_t errorCode)
157 {
158 std::shared_ptr<AVCodecCallback> cb = callback_.lock();
159 if (cb != nullptr) {
160 cb->OnError(errorType, errorCode);
161 }
162 Finalize();
163 }
164
OnOutputFormatChanged(const Format & format)165 void CodecListenerStub::OnOutputFormatChanged(const Format &format)
166 {
167 std::shared_ptr<AVCodecCallback> cb = callback_.lock();
168 if (cb != nullptr) {
169 cb->OnOutputFormatChanged(format);
170 }
171 Finalize();
172 }
173
OnInputBufferAvailable(uint32_t index,std::shared_ptr<AVSharedMemory> buffer)174 void CodecListenerStub::OnInputBufferAvailable(uint32_t index, std::shared_ptr<AVSharedMemory> buffer)
175 {
176 std::shared_ptr<AVCodecCallback> cb = callback_.lock();
177 if (cb != nullptr) {
178 cb->OnInputBufferAvailable(index, buffer);
179 }
180 Finalize();
181 }
182
OnOutputBufferAvailable(uint32_t index,AVCodecBufferInfo info,AVCodecBufferFlag flag,std::shared_ptr<AVSharedMemory> buffer)183 void CodecListenerStub::OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag,
184 std::shared_ptr<AVSharedMemory> buffer)
185 {
186 std::shared_ptr<AVCodecCallback> cb = callback_.lock();
187 if (cb != nullptr) {
188 cb->OnOutputBufferAvailable(index, info, flag, buffer);
189 }
190 Finalize();
191 }
192
SetCallback(const std::shared_ptr<AVCodecCallback> & callback)193 void CodecListenerStub::SetCallback(const std::shared_ptr<AVCodecCallback> &callback)
194 {
195 callback_ = callback;
196 }
197
WaitCallbackDone()198 void CodecListenerStub::WaitCallbackDone()
199 {
200 std::unique_lock<std::mutex> lock(syncMutex_);
201 syncCv_.wait(lock, [this]() { return !callbackIsDoing_; });
202 }
203
CheckGeneration(uint64_t messageGeneration) const204 bool CodecListenerStub::CheckGeneration(uint64_t messageGeneration) const
205 {
206 return messageGeneration >= GetGeneration();
207 }
208
Finalize()209 void CodecListenerStub::Finalize()
210 {
211 callbackIsDoing_ = false;
212 syncCv_.notify_one();
213 }
214 } // namespace MediaAVCodec
215 } // namespace OHOS
216