1 /*
2 * Copyright (C) 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 "media_log.h"
17 #include "composite_engine/impl/video_composite_engine.h"
18
19 namespace OHOS {
20 namespace Media {
21
22 namespace {
23 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_VIDEOEDITOR, "VideoComposite"};
24 }
25 const int WAIT_TIMEOUT_DEC = 30000;
26
VideoCompositeEngine(uint64_t id)27 VideoCompositeEngine::VideoCompositeEngine(uint64_t id) : id_(id)
28 {
29 logTag_ = "eng-id:" + std::to_string(id);
30 }
31
~VideoCompositeEngine()32 VideoCompositeEngine::~VideoCompositeEngine()
33 {
34 MEDIA_LOGD("[%{public}s] destruct.", logTag_.c_str());
35 if (taskMgr_ != nullptr) {
36 taskMgr_->Wait();
37 }
38 }
39
GetId() const40 uint64_t VideoCompositeEngine::GetId() const
41 {
42 return id_;
43 }
44
StartComposite(const std::shared_ptr<CompositionOptions> & options)45 VEFError VideoCompositeEngine::StartComposite(const std::shared_ptr<CompositionOptions>& options)
46 {
47 MEDIA_LOGI("[%{public}s] start composite.", logTag_.c_str());
48 std::lock_guard<ffrt::mutex> lk(selfLock_);
49 auto err = CheckCompositeOptions(options);
50 if (err != VEFError::ERR_OK) {
51 MEDIA_LOGE("[%{public}s] check composite options failed, err: %{public}d.", logTag_.c_str(), err);
52 return err;
53 }
54 callback_ = options->callback_;
55 targetFileFd_ = options->targetFileFd_;
56 err = OrchestratePipelines();
57 if (err != VEFError::ERR_OK) {
58 MEDIA_LOGE("[%{public}s] orchestrate piplines failed, error: %{public}d.", logTag_.c_str(), err);
59 return err;
60 }
61 auto duration = decoderEngine_->GetVideoDuration();
62 if (duration == -1) {
63 MEDIA_LOGW("[%{public}s] get video duration failed .", logTag_.c_str());
64 } else {
65 duration_ = static_cast<uint64_t>(duration);
66 }
67 err = StartComposite();
68 if (err != VEFError::ERR_OK) {
69 MEDIA_LOGE("[%{public}s] start composite engine failed with error: %{public}d.", logTag_.c_str(), err);
70 return err;
71 }
72 MEDIA_LOGI("[%{public}s] start composite success.", logTag_.c_str());
73 return VEFError::ERR_OK;
74 }
75
StopComposite()76 VEFError VideoCompositeEngine::StopComposite()
77 {
78 MEDIA_LOGI("[%{public}s] stop composite.", logTag_.c_str());
79 std::lock_guard<ffrt::mutex> lk(selfLock_);
80 if (this->state_ == CompositeState::COMPOSITING) {
81 decoderEngine_->StopDecode();
82 graphicsRenderEngine_->StopRender();
83 encoderEngine_->StopEncode();
84 this->state_ = CompositeState::CANCLED; // confirm state
85 }
86
87 return VEFError::ERR_OK;
88 }
89
Init(const std::shared_ptr<IDataCenter> & dataCenter)90 VEFError VideoCompositeEngine::Init(const std::shared_ptr<IDataCenter>& dataCenter)
91 {
92 MEDIA_LOGI("[%{public}s] init composite engine.", logTag_.c_str());
93 std::lock_guard<ffrt::mutex> lk(selfLock_);
94 taskMgr_ = std::make_shared<TaskManager>("compositeEngine", TaskManagerTimeOpt::SEQUENTIAL);
95 if (dataCenter == nullptr) {
96 MEDIA_LOGE("[%{public}s] data center is null.", logTag_.c_str());
97 return VEFError::ERR_INTERNAL_ERROR;
98 }
99 dataCenter_ = dataCenter;
100 return VEFError::ERR_OK;
101 }
102
OrchestratePipelines()103 VEFError VideoCompositeEngine::OrchestratePipelines()
104 {
105 auto videoList = dataCenter_->GetAssetList();
106 if (videoList.empty()) {
107 MEDIA_LOGE("[%{public}s] can not find any video from data center.", logTag_.c_str());
108 return VEFError::ERR_NOT_SET_INPUT_VIDEO;
109 }
110 std::shared_ptr<VideoAsset> mainAsset = std::static_pointer_cast<VideoAsset>(videoList[0]);
111 std::vector<const std::shared_ptr<Effect>> effectList = mainAsset->GetEffectList();
112 renderInfo_ = std::make_shared<GraphicsRenderInfo>();
113 for (auto effect : effectList) {
114 renderInfo_->effectInfoList_.emplace_back(effect->GetRenderInfo());
115 }
116 auto fd = mainAsset->GetFd();
117 decoderEngine_ = IVideoDecoderEngine::Create(fd, this);
118 if (decoderEngine_ == nullptr) {
119 MEDIA_LOGE("[%{public}s] create video decoder failed.", logTag_.c_str());
120 return VEFError::ERR_INTERNAL_ERROR;
121 }
122 VideoEncodeParam encodeParam;
123 VEFError error = BuildEncoderParameter(encodeParam);
124 if (error != VEFError::ERR_OK) {
125 MEDIA_LOGE("[%{public}s] build encoder parameter failed, error: %{public}d.", logTag_.c_str(), error);
126 return VEFError::ERR_INTERNAL_ERROR;
127 }
128 encoderEngine_ = IVideoEncoderEngine::Create(encodeParam, this);
129 if (encoderEngine_ == nullptr) {
130 MEDIA_LOGE("[%{public}s] create encoder engine failed.", logTag_.c_str());
131 return VEFError::ERR_INTERNAL_ERROR;
132 }
133 OHNativeWindow* nativeWindowEncoder = encoderEngine_->GetVideoInputWindow();
134 if (nativeWindowEncoder == nullptr) {
135 MEDIA_LOGE("[%{public}s] get native window from encoder engine failed.", logTag_.c_str());
136 return VEFError::ERR_INTERNAL_ERROR;
137 }
138 graphicsRenderEngine_ = IGraphicsRenderEngine::Create(nativeWindowEncoder);
139 if (graphicsRenderEngine_ == nullptr) {
140 MEDIA_LOGE("[%{public}s] create graphics render engine failed.", logTag_.c_str());
141 return VEFError::ERR_INTERNAL_ERROR;
142 }
143 OHNativeWindow* inputWindowOfRender = graphicsRenderEngine_->GetInputWindow();
144 if (inputWindowOfRender == nullptr) {
145 MEDIA_LOGE("[%{public}s] get input window.", logTag_.c_str());
146 return VEFError::ERR_INTERNAL_ERROR;
147 }
148 auto inputPcmBufferQueue = encoderEngine_->GetAudioInputBufferQueue();
149 decoderEngine_->SetVideoOutputWindow(inputWindowOfRender);
150 decoderEngine_->SetAudioOutputBufferQueue(inputPcmBufferQueue);
151 MEDIA_LOGI("[%{public}s] Orchestrate pipelines success.", logTag_.c_str());
152 return VEFError::ERR_OK;
153 }
154
StartComposite()155 VEFError VideoCompositeEngine::StartComposite()
156 {
157 MEDIA_LOGI("[%{public}s] start composite.", logTag_.c_str());
158 VEFError error = encoderEngine_->StartEncode();
159 if (error != VEFError::ERR_OK) {
160 this->state_ = CompositeState::FAILED;
161 MEDIA_LOGE("[%{public}s] start encode engine failed with error: %{public}d.", logTag_.c_str(), error);
162 return error;
163 }
164 error = graphicsRenderEngine_->StartRender();
165 if (error != VEFError::ERR_OK) {
166 MEDIA_LOGE("[%{public}s] start render engine failed with error: %{public}d.", logTag_.c_str(), error);
167 this->state_ = CompositeState::FAILED;
168 return error;
169 }
170 error = decoderEngine_->StartDecode();
171 if (error != VEFError::ERR_OK) {
172 MEDIA_LOGE("[%{public}s] start decoder engine failed with error: %{public}d.", logTag_.c_str(), error);
173 this->state_ = CompositeState::FAILED;
174 return error;
175 }
176 this->state_ = CompositeState::COMPOSITING;
177 MEDIA_LOGI("[%{public}s] start composite success.", logTag_.c_str());
178 return VEFError::ERR_OK;
179 }
180
BuildEncoderParameter(VideoEncodeParam & param)181 VEFError VideoCompositeEngine::BuildEncoderParameter(VideoEncodeParam& param)
182 {
183 OH_AVFormat* videoFormat = decoderEngine_->GetVideoFormat();
184 if (videoFormat == nullptr) {
185 MEDIA_LOGE("[%{public}s] get video format from decode engine failed.", logTag_.c_str());
186 return VEFError::ERR_INTERNAL_ERROR;
187 }
188 param.videoTrunkFormat = videoFormat;
189 param.audioTrunkFormat = decoderEngine_->GetAudioFormat();
190
191 param.muxerParam.targetFileFd = targetFileFd_;
192 param.muxerParam.avOutputFormat = AV_OUTPUT_FORMAT_MPEG_4;
193 param.muxerParam.rotation = decoderEngine_->GetRotation();
194
195 return VEFError::ERR_OK;
196 }
197
OnDecodeFrame(uint64_t pts)198 void VideoCompositeEngine::OnDecodeFrame(uint64_t pts)
199 {
200 MEDIA_LOGD("[%{public}s] OnDecodeFrame[pts = %{public}" PRIu64 "].", logTag_.c_str(), pts);
201 {
202 std::unique_lock lk(renderingCntLock_);
203 renderingCnt_++;
204 }
205 renderInfo_->rotation_ = decoderEngine_->GetRotation();
206 taskMgr_->Submit([this, pts]() {
207 RenderResultCallback onRenderFinishCb = [this, pts](GraphicsRenderResult result) {
208 this->OnRenderFinish(pts, result);
209 };
210 graphicsRenderEngine_->Render(pts, renderInfo_, onRenderFinishCb);
211 });
212 }
213
OnDecodeResult(CodecResult result)214 void VideoCompositeEngine::OnDecodeResult(CodecResult result)
215 {
216 MEDIA_LOGI("[%{public}s] OnDecodeResult[result = %{public}u].", logTag_.c_str(), result);
217 if (result != CodecResult::SUCCESS) {
218 MEDIA_LOGE("[%{public}s] decode with error: %{public}u.", logTag_.c_str(), result);
219 return;
220 }
221 {
222 std::unique_lock lk(renderingCntLock_);
223 if (renderingCnt_ > 0) {
224 bool res = renderingCntCv_.wait_for(lk, std::chrono::milliseconds(WAIT_TIMEOUT_DEC),
225 [this]() {
226 return renderingCnt_ == 0;
227 });
228 if (!res) {
229 MEDIA_LOGE("[%{public}s] OnDecodeResult time out.", logTag_.c_str());
230 }
231 }
232 }
233
234 taskMgr_->Submit([this]() {
235 std::lock_guard<ffrt::mutex> lk(selfLock_);
236 decoderEngine_->StopDecode();
237 encoderEngine_->SendEos();
238 });
239 }
240
OnEncodeFrame(uint64_t pts)241 void VideoCompositeEngine::OnEncodeFrame(uint64_t pts)
242 {
243 MEDIA_LOGD("[%{public}s] OnEncodeFrame[pts = %{public}" PRIu64 "].", logTag_.c_str(), pts);
244 std::lock_guard<ffrt::mutex> lk(selfLock_);
245 if (this->state_ != CompositeState::COMPOSITING) {
246 return;
247 }
248 auto callback = callback_;
249 auto duration = duration_;
250 ffrt::submit([callback, pts, duration]() {
251 if (duration <= 0) {
252 callback->onProgress(0);
253 } else if (pts < 0) {
254 callback->onProgress(0);
255 } else if (pts > duration) {
256 callback->onProgress(100); // 100表示完整进度
257 } else if (duration != 0) {
258 callback->onProgress(static_cast<int>((pts * 100) / duration)); // 100表示完整进度
259 }
260 });
261 }
262
OnEncodeResult(CodecResult result)263 void VideoCompositeEngine::OnEncodeResult(CodecResult result)
264 {
265 MEDIA_LOGI("[%{public}s] OnEncodeResult[result = %{public}u].", logTag_.c_str(), result);
266 VEFResult res = result == CodecResult::SUCCESS ? VEFResult::SUCCESS : VEFResult::FAILED;
267 VEFError errCode = result == CodecResult::SUCCESS ? VEFError::ERR_OK : VEFError::ERR_INTERNAL_ERROR;
268 std::lock_guard<ffrt::mutex> lk(selfLock_);
269 this->state_ = CompositeState::FINISHING;
270 taskMgr_->Submit([this, res, errCode]() {
271 std::lock_guard<ffrt::mutex> lk(selfLock_);
272 encoderEngine_->Flush();
273 graphicsRenderEngine_->StopRender();
274 encoderEngine_->StopEncode();
275 auto callback = callback_;
276 ffrt::submit([callback, res, errCode]() {
277 callback->onResult(res, errCode);
278 });
279 this->state_ = (res == VEFResult::SUCCESS) ? CompositeState::FINISHED : CompositeState::FAILED;
280 });
281 }
282
OnRenderFinish(uint64_t pts,GraphicsRenderResult result)283 void VideoCompositeEngine::OnRenderFinish(uint64_t pts, GraphicsRenderResult result)
284 {
285 MEDIA_LOGD("[%{public}s] OnRenderFinish, pts: %{public}" PRIu64 ", result = %{public}u.",
286 logTag_.c_str(), pts, result);
287 {
288 std::unique_lock lk(renderingCntLock_);
289 renderingCnt_--;
290 renderingCntCv_.notify_all();
291 }
292 }
293
CheckCompositeOptions(const std::shared_ptr<CompositionOptions> & options)294 VEFError VideoCompositeEngine::CheckCompositeOptions(const std::shared_ptr<CompositionOptions>& options)
295 {
296 if (options == nullptr) {
297 MEDIA_LOGE("options for composition is nullptr.");
298 return VEFError::ERR_INVALID_PARAM;
299 }
300 if (options->callback_ == nullptr) {
301 MEDIA_LOGE("callback for composition is nullptr.");
302 return VEFError::ERR_INVALID_PARAM;
303 }
304 if (options->targetFileFd_ <= 0) {
305 MEDIA_LOGE("target fd[%{public}d] for composition is invalid(<=0).", options->targetFileFd_);
306 return VEFError::ERR_INVALID_PARAM;
307 }
308 return VEFError::ERR_OK;
309 }
310
311 } // namespace Media
312 } // namespace OHOS
313