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