1 /*
2 * Copyright (C) 2021 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 "recorder_pipeline_builder.h"
17 #include "media_errors.h"
18 #include "media_log.h"
19 #include "recorder_private_param.h"
20
21 namespace {
22 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "RecorderPipelineBuilder"};
23 }
24
25 namespace OHOS {
26 namespace Media {
27 #define ADD_LINK_DESC(srcElem, dstElem, srcPad, sinkPad, isSrcPadStatic, isSinkPadStatic) \
28 do { \
29 RecorderPipelineDesc::LinkDesc linkDesc = { dstElem, srcPad, sinkPad, isSrcPadStatic, isSinkPadStatic}; \
30 pipelineDesc_->allLinkDescs[srcElem] = linkDesc; \
31 } while (false)
32
RecorderPipelineBuilder(int32_t appUid,int32_t appPid,uint32_t appTokenId)33 RecorderPipelineBuilder::RecorderPipelineBuilder(int32_t appUid, int32_t appPid, uint32_t appTokenId)
34 : appUid_(appUid), appPid_(appPid), appTokenId_(appTokenId)
35 {
36 MEDIA_LOGD("enter, ctor");
37 }
38
~RecorderPipelineBuilder()39 RecorderPipelineBuilder::~RecorderPipelineBuilder()
40 {
41 MEDIA_LOGD("enter, dtor");
42 Reset();
43 }
44
EnsureSourceOrder(bool isVideo)45 void RecorderPipelineBuilder::EnsureSourceOrder(bool isVideo)
46 {
47 auto srcIter = std::next(pipelineDesc_->allElems.end(), -1);
48 if (isVideo) {
49 auto insertPos = std::next(pipelineDesc_->allElems.begin(), videoSrcCount_);
50 (void)pipelineDesc_->allElems.insert(insertPos, *srcIter);
51 videoSrcCount_ += 1;
52 } else {
53 auto insertPos = std::next(pipelineDesc_->allElems.begin(), videoSrcCount_ + otherSrcCount_);
54 (void)pipelineDesc_->allElems.insert(insertPos, *srcIter);
55 otherSrcCount_ += 1;
56 }
57 (void)pipelineDesc_->allElems.erase(srcIter);
58 }
59
CreateElement(const std::string & name,const RecorderSourceDesc & desc,bool isSource)60 std::shared_ptr<RecorderElement> RecorderPipelineBuilder::CreateElement(
61 const std::string &name,
62 const RecorderSourceDesc &desc,
63 bool isSource)
64 {
65 if (pipelineDesc_ == nullptr) {
66 pipelineDesc_ = std::make_shared<RecorderPipelineDesc>();
67 }
68
69 RecorderElement::CreateParam createParam = { desc, name };
70 std::shared_ptr<RecorderElement> element = RecorderElementFactory::GetInstance().CreateElement(name, createParam);
71 if (element == nullptr) {
72 std::string sourceKind = desc.IsVideo() ? "video" : (desc.IsAudio() ? "audio" : "unknown");
73 MEDIA_LOGE("Unable to create element for %{public}s source type: %{public}d, element name: %{public}s",
74 sourceKind.c_str(), desc.type_, name.c_str());
75 return nullptr;
76 }
77
78 pipelineDesc_->allElems.push_back(element);
79 if (isSource) {
80 (void)pipelineDesc_->srcElems.emplace(desc.handle_, element);
81 EnsureSourceOrder(desc.IsVideo());
82 }
83
84 return element;
85 }
86
CreateMuxSink()87 int32_t RecorderPipelineBuilder::CreateMuxSink()
88 {
89 if (muxSink_ != nullptr) {
90 return MSERR_OK;
91 }
92
93 RecorderSourceDesc desc {}; // default initialization, meaninglessly
94 muxSink_ = CreateElement("MuxSinkBin", desc, false);
95 if (muxSink_ == nullptr) {
96 MEDIA_LOGE("Unable to create element for MuxSinkBin !");
97 return MSERR_INVALID_OPERATION;
98 }
99 pipelineDesc_->muxerSinkBin = muxSink_;
100
101 return MSERR_OK;
102 }
103
SetVideoSource(const RecorderSourceDesc & desc)104 int32_t RecorderPipelineBuilder::SetVideoSource(const RecorderSourceDesc &desc)
105 {
106 int32_t ret = CreateMuxSink();
107 CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
108
109 // ES Source and YUV Source is supported.
110 if (desc.type_ == VideoSourceType::VIDEO_SOURCE_SURFACE_ES ||
111 desc.type_ == VideoSourceType::VIDEO_SOURCE_SURFACE_YUV ||
112 desc.type_ == VideoSourceType::VIDEO_SOURCE_SURFACE_RGBA) {
113 videoSrcElem_ = CreateElement("VideoSource", desc, true);
114 } else {
115 MEDIA_LOGE("Video source type %{public}d currently unsupported", desc.type_);
116 }
117
118 CHECK_AND_RETURN_RET(videoSrcElem_ != nullptr, MSERR_INVALID_VAL);
119
120 videoConverElem_ = CreateElement("VideoConverter", desc, false);
121 CHECK_AND_RETURN_RET(videoConverElem_ != nullptr, MSERR_INVALID_VAL);
122
123 videoParseElem_ = CreateElement("VideoParse", desc, false);
124 CHECK_AND_RETURN_RET(videoParseElem_ != nullptr, MSERR_INVALID_VAL);
125
126 // check yuv/rgbs stream
127 if (desc.type_ == VideoSourceType::VIDEO_SOURCE_SURFACE_YUV ||
128 desc.type_ == VideoSourceType::VIDEO_SOURCE_SURFACE_RGBA) {
129 videoEncElem_ = CreateElement("VideoEncoder", desc, false);
130 CHECK_AND_RETURN_RET(videoEncElem_ != nullptr, MSERR_INVALID_VAL);
131
132 // for the second video source, the sinkpad name should be video_aux_%u
133 ADD_LINK_DESC(videoSrcElem_, videoConverElem_, "src", "sink", true, true);
134 ADD_LINK_DESC(videoConverElem_, videoEncElem_, "src", "sink", true, true);
135 ADD_LINK_DESC(videoEncElem_, muxSink_, "src", "video", true, false);
136 } else {
137 // es stream
138 ADD_LINK_DESC(videoSrcElem_, videoParseElem_, "src", "sink", true, true);
139 ADD_LINK_DESC(videoParseElem_, muxSink_, "src", "video", true, false);
140 }
141
142 currentVideoSourceType_ = desc.type_;
143
144 return MSERR_OK;
145 }
146
SetAudioSource(const RecorderSourceDesc & desc)147 int32_t RecorderPipelineBuilder::SetAudioSource(const RecorderSourceDesc &desc)
148 {
149 int32_t ret = CreateMuxSink();
150 CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
151
152 std::shared_ptr<RecorderElement> audioSrcElem;
153 // currently only the mic is supported.
154 if (desc.type_ == AudioSourceType::AUDIO_MIC) {
155 audioSrcElem = CreateElement("AudioSource", desc, true);
156 } else {
157 MEDIA_LOGE("Audio source type %{public}d currently unsupported", desc.type_);
158 }
159
160 CHECK_AND_RETURN_RET(audioSrcElem != nullptr, MSERR_INVALID_VAL);
161 (void)audioSrcElem->Configure(AppInfo {appUid_, appPid_, appTokenId_});
162
163 std::shared_ptr<RecorderElement> audioConvert = CreateElement("AudioConverter", desc, false);
164 CHECK_AND_RETURN_RET(audioConvert != nullptr, MSERR_INVALID_VAL);
165
166 std::shared_ptr<RecorderElement> audioEncElem = CreateElement("AudioEncoder", desc, false);
167 CHECK_AND_RETURN_RET(audioEncElem != nullptr, MSERR_INVALID_VAL);
168
169 ADD_LINK_DESC(audioSrcElem, audioConvert, "src", "sink", true, true);
170 ADD_LINK_DESC(audioConvert, audioEncElem, "src", "sink", true, true);
171 ADD_LINK_DESC(audioEncElem, muxSink_, "src", "audio_%u", true, false);
172
173 return MSERR_OK;
174 }
175
SetSource(const RecorderSourceDesc & desc)176 int32_t RecorderPipelineBuilder::SetSource(const RecorderSourceDesc &desc)
177 {
178 if (desc.IsVideo()) {
179 return SetVideoSource(desc);
180 } else if (desc.IsAudio()) {
181 return SetAudioSource(desc);
182 }
183
184 // should never go to here.
185 MEDIA_LOGE("Invalid source description !");
186 return MSERR_INVALID_VAL;
187 }
188
SetOutputFormat(OutputFormatType formatType)189 int32_t RecorderPipelineBuilder::SetOutputFormat(OutputFormatType formatType)
190 {
191 if (muxSink_ == nullptr) {
192 MEDIA_LOGE("No source set, set the output format invalid !");
193 return MSERR_INVALID_OPERATION;
194 }
195
196 int32_t ret = muxSink_->Configure(OutputFormat(formatType));
197 CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
198
199 outputFormatConfiged_ = true;
200 return MSERR_OK;
201 }
202
CheckConfigure(int32_t sourceId,const RecorderParam & param)203 int32_t RecorderPipelineBuilder::CheckConfigure(int32_t sourceId, const RecorderParam ¶m)
204 {
205 (void)sourceId;
206 if (param.type == RecorderPublicParamType::VID_ENC_FMT) {
207 const VidEnc &tempParam = static_cast<const VidEnc &>(param);
208
209 if ((currentVideoSourceType_ == VideoSourceType::VIDEO_SOURCE_BUTT) ||
210 ((currentVideoSourceType_ == VideoSourceType::VIDEO_SOURCE_SURFACE_ES))) {
211 needVideoParse_ = false;
212 return MSERR_OK;
213 }
214
215 if (tempParam.encFmt == VideoCodecFormat::H264) {
216 needVideoParse_ = true;
217 } else {
218 needVideoParse_ = false;
219 }
220 }
221
222 return MSERR_OK;
223 }
224
Configure(int32_t sourceId,const RecorderParam & param)225 int32_t RecorderPipelineBuilder::Configure(int32_t sourceId, const RecorderParam ¶m)
226 {
227 if (!outputFormatConfiged_) {
228 MEDIA_LOGE("Output format not set, configure the pipeline is invalid !");
229 return MSERR_INVALID_OPERATION;
230 }
231
232 int32_t ret = CheckConfigure(sourceId, param);
233 CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
234
235 // distribute parameters to elements
236 for (auto &elem : pipelineDesc_->allElems) {
237 if (elem->GetSourceId() == sourceId) {
238 ret = elem->Configure(param);
239 CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
240 }
241 }
242
243 return MSERR_OK;
244 }
245
CheckPipeline()246 int32_t RecorderPipelineBuilder::CheckPipeline()
247 {
248 if (needVideoParse_) {
249 RecorderSourceDesc desc {};
250 videoParseElem_ = CreateElement("VideoParse", desc, false);
251 CHECK_AND_RETURN_RET(videoParseElem_ != nullptr, MSERR_UNKNOWN);
252
253 for (auto iter = pipelineDesc_->allLinkDescs.begin(); iter != pipelineDesc_->allLinkDescs.end();) {
254 if (iter->first->GetName() == "VideoEncoder") {
255 pipelineDesc_->allLinkDescs.erase(iter++);
256 break;
257 } else {
258 iter++;
259 }
260 }
261
262 CHECK_AND_RETURN_RET(videoEncElem_ != nullptr, MSERR_INVALID_OPERATION);
263 ADD_LINK_DESC(videoEncElem_, videoParseElem_, "src", "sink", true, true);
264 ADD_LINK_DESC(videoParseElem_, muxSink_, "src", "video", true, false);
265 }
266
267 return MSERR_OK;
268 }
269
Build(std::shared_ptr<RecorderPipeline> & pipeline)270 int32_t RecorderPipelineBuilder::Build(std::shared_ptr<RecorderPipeline> &pipeline)
271 {
272 if (!outputFormatConfiged_) {
273 MEDIA_LOGE("Output format not configured, build pipeline failed !");
274 return MSERR_INVALID_OPERATION;
275 }
276
277 /*
278 * Execute a series of policies to filter pipeline graphs or check pipeline parameter configurations.
279 *
280 * | Remove stream policy | -> | Check parameter completeness policy | -> | Add elements policy |
281 *
282 * 1. Execute those policies firsly that maybe remove the whole audio stream or video stream
283 * 2. Now, all streams are needed. Then, execute those policies that check whether all parameters are
284 * configured completely. If not completely, refuse to build pipeline.
285 * 3. Execute those policies that maybe need to add some elements into pipeline.
286 *
287 * Specifically:
288 * 1. Process the mismatch between capture rate and frame rate. If capture rate less than the frame rate, the
289 * all audio stream need be removed.
290 * 2. Check whether the parameter fully configured. For example, the audio encoder required, but the audio encoder
291 * format is not configured or erroneously configured. The element itself can judge whether the required
292 * parameters are complete. If the parameter configured not completely, refuse to build pipeline.
293 * 3. Process the audio caps mismatch between audio source and audio encoder. If caps mismatch is true, add the
294 * audio converter element into audio stream.
295 */
296
297 int32_t ret = CheckPipeline();
298 CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
299
300 for (auto &elem : pipelineDesc_->allElems) {
301 ret = elem->CheckConfigReady(); // Check whether the parameter fully configured
302 CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
303 }
304
305 ret = ExecuteLink();
306 CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
307
308 pipeline = pipeline_;
309 return MSERR_OK;
310 }
311
ExecuteLink()312 int32_t RecorderPipelineBuilder::ExecuteLink()
313 {
314 auto pipeline = std::make_shared<RecorderPipeline>(pipelineDesc_);
315 int32_t ret = pipeline->Init();
316 CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
317
318 auto linkHelper = std::make_unique<RecorderPipelineLinkHelper>(pipeline, pipelineDesc_);
319 ret = linkHelper->ExecuteLink();
320 CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
321
322 pipeline_ = pipeline;
323 linkHelper_ = std::move(linkHelper);
324 return MSERR_OK;
325 }
326
Reset()327 void RecorderPipelineBuilder::Reset()
328 {
329 linkHelper_ = nullptr;
330 muxSink_ = nullptr;
331 videoSrcElem_ = nullptr;
332 videoEncElem_ = nullptr;
333 videoParseElem_ = nullptr;
334 videoConverElem_ = nullptr;
335 if (pipeline_ != nullptr) {
336 (void)pipeline_->Reset();
337 }
338 pipeline_ = nullptr;
339 pipelineDesc_ = nullptr;
340
341 videoSrcCount_ = 0;
342 otherSrcCount_ = 0;
343
344 outputFormatConfiged_ = false;
345 currentVideoSourceType_ = VideoSourceType::VIDEO_SOURCE_BUTT;
346 needVideoParse_ = false;
347 }
348 } // namespace Media
349 } // namespace OHOS
350