1 /*
2  * Copyright (c) 2024-2024 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 "moving_photo_video_cache.h"
17 #include <cinttypes>
18 #include <unistd.h>
19 #include <chrono>
20 #include <fcntl.h>
21 #include <memory>
22 #include <utility>
23 #include "external_window.h"
24 #include "native_buffer_inner.h"
25 #include "camera_log.h"
26 #include "refbase.h"
27 #include "surface_buffer.h"
28 
29 namespace {
30     using namespace std::string_literals;
31     using namespace std::chrono_literals;
32 }
33 namespace OHOS {
34 namespace CameraStandard {
35 
~MovingPhotoVideoCache()36 MovingPhotoVideoCache::~MovingPhotoVideoCache()
37 {
38     MEDIA_DEBUG_LOG("~MovingPhotoVideoCache enter");
39     taskManagerLock_.lock();
40     taskManager_ = nullptr;
41     taskManagerLock_.unlock();
42     std::lock_guard<std::mutex> lock(callbackVecLock_);
43     cachedFrameCallbackHandles_.clear();
44 }
45 
MovingPhotoVideoCache(sptr<AvcodecTaskManager> taskManager)46 MovingPhotoVideoCache::MovingPhotoVideoCache(sptr<AvcodecTaskManager> taskManager) : taskManager_(taskManager)
47 {
48 }
49 
CacheFrame(sptr<FrameRecord> frameRecord)50 void MovingPhotoVideoCache::CacheFrame(sptr<FrameRecord> frameRecord)
51 {
52     MEDIA_DEBUG_LOG("CacheFrame enter");
53     std::lock_guard<std::mutex> lock(taskManagerLock_);
54     if (taskManager_) {
55         frameRecord->SetStatusReadyConvertStatus();
56         auto thisPtr = sptr<MovingPhotoVideoCache>(this);
57         taskManager_->EncodeVideoBuffer(frameRecord, [thisPtr](sptr<FrameRecord> frameRecord, bool encodeResult) {
58             thisPtr->OnImageEncoded(frameRecord, encodeResult);
59         });
60     }
61 }
62 
DoMuxerVideo(std::vector<sptr<FrameRecord>> frameRecords,uint64_t taskName,int32_t rotation,int32_t captureId)63 void MovingPhotoVideoCache::DoMuxerVideo(std::vector<sptr<FrameRecord>> frameRecords, uint64_t taskName,
64                                          int32_t rotation, int32_t captureId)
65 {
66     CAMERA_SYNC_TRACE;
67     MEDIA_INFO_LOG("DoMuxerVideo enter");
68     std::sort(frameRecords.begin(), frameRecords.end(),
69         [](const sptr<FrameRecord>& a, const sptr<FrameRecord>& b) {
70         return a->GetTimeStamp() < b->GetTimeStamp();
71     });
72     std::lock_guard<std::mutex> lock(taskManagerLock_);
73     if (taskManager_) {
74         taskManager_->DoMuxerVideo(frameRecords, taskName, rotation, captureId);
75         auto thisPtr = sptr<MovingPhotoVideoCache>(this);
76         taskManager_->SubmitTask([thisPtr]() {
77             thisPtr->ClearCallbackHandler();
78         });
79     }
80 }
81 
82 // Call this function after buffer has been encoded
OnImageEncoded(sptr<FrameRecord> frameRecord,bool encodeResult)83 void MovingPhotoVideoCache::OnImageEncoded(sptr<FrameRecord> frameRecord, bool encodeResult)
84 {
85     CAMERA_SYNC_TRACE;
86     std::lock_guard<std::mutex> lock(callbackVecLock_);
87     for (auto cachedFrameCallbackHandle : cachedFrameCallbackHandles_) {
88         if (cachedFrameCallbackHandle == nullptr) {
89             MEDIA_ERR_LOG("MovingPhotoVideoCache::OnImageEncoded with null cachedFrameCallbackHandle");
90             continue;
91         }
92         cachedFrameCallbackHandle->OnCacheFrameFinish(frameRecord, encodeResult);
93     }
94 }
95 
GetFrameCachedResult(std::vector<sptr<FrameRecord>> frameRecords,EncodedEndCbFunc encodedEndCbFunc,uint64_t taskName,int32_t rotation,int32_t captureId)96 void MovingPhotoVideoCache::GetFrameCachedResult(std::vector<sptr<FrameRecord>> frameRecords,
97     EncodedEndCbFunc encodedEndCbFunc, uint64_t taskName, int32_t rotation, int32_t captureId)
98 {
99     callbackVecLock_.lock();
100     MEDIA_INFO_LOG("GetFrameCachedResult enter frameRecords size: %{public}zu", frameRecords.size());
101     sptr<CachedFrameCallbackHandle> cacheFrameHandler =
102         new CachedFrameCallbackHandle(frameRecords, encodedEndCbFunc, taskName, rotation, captureId);
103     cachedFrameCallbackHandles_.push_back(cacheFrameHandler);
104     callbackVecLock_.unlock();
105     for (auto frameRecord : frameRecords) {
106         if (frameRecord->IsFinishCache()) {
107             cacheFrameHandler->OnCacheFrameFinish(frameRecord, frameRecord->IsEncoded());
108         }
109     }
110 }
111 
ClearCallbackHandler()112 void MovingPhotoVideoCache::ClearCallbackHandler()
113 {
114     // OnImageEncoded has callbackVecLock_
115     MEDIA_INFO_LOG("ClearCallbackHandler enter");
116     std::lock_guard<std::mutex> lock(callbackVecLock_);
117     MEDIA_DEBUG_LOG("ClearCallbackHandler get callbackVecLock_");
118     cachedFrameCallbackHandles_.erase(std::remove_if(cachedFrameCallbackHandles_.begin(),
119         cachedFrameCallbackHandles_.end(),
120         [](const sptr<CachedFrameCallbackHandle>& obj) {return obj->GetCacheRecord().empty();}),
121         cachedFrameCallbackHandles_.end());
122 }
123 
ClearCache()124 void MovingPhotoVideoCache::ClearCache()
125 {
126     MEDIA_INFO_LOG("ClearCache enter");
127     // clear cache and muxer success buffer
128     std::lock_guard<std::mutex> lock(callbackVecLock_);
129     for (auto cachedFrameCallbackHandle : cachedFrameCallbackHandles_) {
130         cachedFrameCallbackHandle->AbortCapture();
131     }
132     cachedFrameCallbackHandles_.clear();
133 }
134 
CachedFrameCallbackHandle(std::vector<sptr<FrameRecord>> frameRecords,EncodedEndCbFunc encodedEndCbFunc,uint64_t taskName,int32_t rotation,int32_t captureId)135 CachedFrameCallbackHandle::CachedFrameCallbackHandle(std::vector<sptr<FrameRecord>> frameRecords,
136     EncodedEndCbFunc encodedEndCbFunc, uint64_t taskName, int32_t rotation, int32_t captureId)
137     : encodedEndCbFunc_(encodedEndCbFunc), isAbort_(false), taskName_(taskName), rotation_(rotation),
138       captureId_(captureId)
139 {
140     std::lock_guard<std::mutex> lock(cacheFrameMutex_);
141     cacheRecords_.insert(frameRecords.begin(), frameRecords.end());
142 }
143 
~CachedFrameCallbackHandle()144 CachedFrameCallbackHandle::~CachedFrameCallbackHandle()
145 {
146     MEDIA_INFO_LOG("~CachedFrameCallbackHandle enter");
147 }
148 
OnCacheFrameFinish(sptr<FrameRecord> frameRecord,bool cachedSuccess)149 void CachedFrameCallbackHandle::OnCacheFrameFinish(sptr<FrameRecord> frameRecord, bool cachedSuccess)
150 {
151     MEDIA_INFO_LOG("OnCacheFrameFinish enter cachedSuccess: %{public}d", cachedSuccess);
152     std::lock_guard<std::mutex> lock(cacheFrameMutex_);
153     if (isAbort_) {
154         // Handle abort
155         MEDIA_INFO_LOG("OnCacheFrameFinish is abort");
156         return;
157     }
158     auto it = cacheRecords_.find(frameRecord);
159     if (it != cacheRecords_.end()) {
160         cacheRecords_.erase(it);
161         if (cachedSuccess && frameRecord != nullptr && frameRecord->encodedBuffer != nullptr) {
162             successCacheRecords_.push_back(frameRecord);
163         } else {
164             errorCacheRecords_.push_back(frameRecord);
165         }
166         if (!cacheRecords_.empty()) {
167             // Still waiting for more cache encoded buffer
168             return;
169         }
170         MEDIA_INFO_LOG("encodedEndCbFunc_ is called success count: %{public}zu", successCacheRecords_.size());
171         // All buffer have been encoded
172         if (encodedEndCbFunc_ != nullptr) {
173             encodedEndCbFunc_(successCacheRecords_, taskName_, rotation_, captureId_);
174             encodedEndCbFunc_ = nullptr;
175         }
176     }
177 }
178 
179 // This function is called when prestop capture
AbortCapture()180 void CachedFrameCallbackHandle::AbortCapture()
181 {
182     std::lock_guard<std::mutex> lock(cacheFrameMutex_);
183     isAbort_ = true;
184     cacheRecords_.clear();
185     if (encodedEndCbFunc_ != nullptr) {
186         encodedEndCbFunc_(successCacheRecords_, taskName_, rotation_, captureId_);
187         encodedEndCbFunc_ = nullptr;
188     }
189 }
190 
GetCacheRecord()191 CachedFrameSet CachedFrameCallbackHandle::GetCacheRecord()
192 {
193     std::lock_guard<std::mutex> lock(cacheFrameMutex_);
194     return cacheRecords_;
195 }
196 
197 } // CameraStandard
198 } // OHOS