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