• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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