1 /*
2 * Copyright (c) 2021-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 #ifdef RECORDER_SUPPORT
16
17 #define HST_LOG_TAG "OutputSinkFilter"
18
19 #include "pipeline/filters/sink/output_sink/output_sink_filter.h"
20 #include <cstdio>
21 #include "foundation/cpp_ext/type_traits_ext.h"
22 #include "foundation/log.h"
23 #include "foundation/utils/steady_clock.h"
24 #include "pipeline/factory/filter_factory.h"
25 #include "pipeline/filters/common/plugin_settings.h"
26 #include "pipeline/filters/common/plugin_utils.h"
27 #include "plugin/common/plugin_tags.h"
28
29 namespace OHOS {
30 namespace Media {
31 namespace Pipeline {
32 static AutoRegisterFilter<OutputSinkFilter> g_registerFilterHelper("builtin.recorder.output_sink");
33
OutputSinkFilter(std::string name)34 OutputSinkFilter::OutputSinkFilter(std::string name) : FilterBase(std::move(name))
35 {
36 filterType_ = FilterType::OUTPUT_SINK;
37 }
38
~OutputSinkFilter()39 OutputSinkFilter::~OutputSinkFilter()
40 {
41 if (!bufferEos_) {
42 MEDIA_LOG_E("OutputSink send EVENT_ERROR: No EOS Received");
43 }
44 }
45
Init(EventReceiver * receiver,FilterCallback * callback)46 void OutputSinkFilter::Init(EventReceiver *receiver, FilterCallback *callback)
47 {
48 FilterBase::Init(receiver, callback);
49 outPorts_.clear();
50 }
Negotiate(const std::string & inPort,const std::shared_ptr<const Plugin::Capability> & upstreamCap,Plugin::Capability & negotiatedCap,const Plugin::Meta & upstreamParams,Plugin::Meta & downstreamParams)51 bool OutputSinkFilter::Negotiate(const std::string& inPort,
52 const std::shared_ptr<const Plugin::Capability>& upstreamCap,
53 Plugin::Capability& negotiatedCap,
54 const Plugin::Meta& upstreamParams,
55 Plugin::Meta& downstreamParams)
56 {
57 auto candidatePlugins = FindAvailablePlugins(*upstreamCap, Plugin::PluginType::OUTPUT_SINK);
58 if (candidatePlugins.empty()) {
59 MEDIA_LOG_E("no available output sink plugin");
60 return false;
61 }
62 std::shared_ptr<Plugin::PluginInfo> selectedPluginInfo = nullptr;
63 for (const auto& candidate : candidatePlugins) {
64 const auto& tmp = candidate.first->extra[PLUGIN_INFO_EXTRA_OUTPUT_TYPE];
65 if (!Plugin::Any::IsSameTypeWith<Plugin::ProtocolType>(tmp)) {
66 continue;
67 }
68 if (Plugin::AnyCast<Plugin::ProtocolType>(tmp) == protocolType_) {
69 if (selectedPluginInfo == nullptr) {
70 selectedPluginInfo = candidate.first;
71 negotiatedCap = candidate.second;
72 } else if (candidate.first->rank > selectedPluginInfo->rank) {
73 selectedPluginInfo = candidate.first;
74 negotiatedCap = candidate.second;
75 }
76 }
77 }
78 if (selectedPluginInfo == nullptr) {
79 MEDIA_LOG_W("no available output sink plugin with output type of " PUBLIC_LOG_D32,
80 static_cast<int32_t>(protocolType_));
81 return false;
82 }
83 auto res = UpdateAndInitPluginByInfo<Plugin::OutputSink>(plugin_, pluginInfo_, selectedPluginInfo,
84 [](const std::string& name) -> std::shared_ptr<Plugin::OutputSink> {
85 return Plugin::PluginManager::Instance().CreateOutputSinkPlugin(name);
86 });
87 return res;
88 }
89
Configure(const std::string & inPort,const std::shared_ptr<const Plugin::Meta> & upstreamMeta,Plugin::Meta & upstreamParams,Plugin::Meta & downstreamParams)90 bool OutputSinkFilter::Configure(const std::string& inPort, const std::shared_ptr<const Plugin::Meta>& upstreamMeta,
91 Plugin::Meta& upstreamParams, Plugin::Meta& downstreamParams)
92 {
93 PROFILE_BEGIN("Output sink configure begin");
94 if (plugin_ == nullptr || pluginInfo_ == nullptr) {
95 MEDIA_LOG_E("cannot configure decoder when no plugin available");
96 return false;
97 }
98
99 if (ConfigureToPreparePlugin() != ErrorCode::SUCCESS) {
100 return false;
101 }
102 state_ = FilterState::READY;
103 OnEvent({name_, EventType::EVENT_READY});
104 MEDIA_LOG_I("Output sink send EVENT_READY");
105 PROFILE_END("Output sink configure end");
106 return true;
107 }
108
SetSink(const MediaSink & sink)109 ErrorCode OutputSinkFilter::SetSink(const MediaSink& sink)
110 {
111 auto protocolType = sink.GetProtocolType();
112 FALSE_RETURN_V(protocolType != Plugin::ProtocolType::UNKNOWN, ErrorCode::ERROR_INVALID_PARAMETER_VALUE);
113 sink_ = sink;
114 protocolType_ = protocolType;
115 return ErrorCode::SUCCESS;
116 }
117
PushData(const std::string & inPort,const AVBufferPtr & buffer,int64_t offset)118 ErrorCode OutputSinkFilter::PushData(const std::string &inPort, const AVBufferPtr& buffer, int64_t offset)
119 {
120 auto ret = ErrorCode::SUCCESS;
121 if (offset >= 0 && offset != currentPos_) {
122 auto seekable = plugin_->GetSeekable();
123 if (seekable == Plugin::Seekable::UNSEEKABLE || seekable == Plugin::Seekable::INVALID) {
124 MEDIA_LOG_E("plugin " PUBLIC_LOG_S " does not support seekable", pluginInfo_->name.c_str());
125 return ErrorCode::ERROR_INVALID_OPERATION;
126 } else {
127 ret = TranslatePluginStatus(plugin_->SeekTo(offset));
128 if (ret != ErrorCode::SUCCESS) {
129 MEDIA_LOG_E("plugin " PUBLIC_LOG_S " seek to " PUBLIC_LOG_D64 " failed",
130 pluginInfo_->name.c_str(), offset);
131 // should call back to client here
132 return ErrorCode::ERROR_INVALID_OPERATION;
133 }
134 currentPos_ = offset;
135 }
136 }
137 if (!buffer->IsEmpty()) {
138 ret = TranslatePluginStatus(plugin_->Write(buffer));
139 if (ret != ErrorCode::SUCCESS) {
140 MEDIA_LOG_E("write to plugin failed with error code " PUBLIC_LOG_D32, CppExt::to_underlying(ret));
141 return ret;
142 }
143 currentPos_ += buffer->GetMemory()->GetSize();
144 }
145 if (buffer->flag & BUFFER_FLAG_EOS) {
146 plugin_->Flush();
147 Event event {
148 .srcFilter = name_,
149 .type = EventType::EVENT_COMPLETE,
150 };
151 MEDIA_LOG_D("file sink push data send event_complete");
152 OnEvent(event);
153 bufferEos_ = true;
154 }
155 return ret;
156 }
157
Prepare()158 ErrorCode OutputSinkFilter::Prepare()
159 {
160 FilterBase::Prepare();
161 if (plugin_) {
162 plugin_->Prepare();
163 }
164 return ErrorCode::SUCCESS;
165 }
166
Start()167 ErrorCode OutputSinkFilter::Start()
168 {
169 FilterBase::Start();
170 if (plugin_ == nullptr) {
171 MEDIA_LOG_E("no valid plugin");
172 return ErrorCode::ERROR_INVALID_STATE;
173 }
174 FAIL_RETURN_MSG_W(TranslatePluginStatus(plugin_->Start()), "plugin start failed");
175 bufferEos_ = false;
176 return ErrorCode::SUCCESS;
177 }
178
Stop()179 ErrorCode OutputSinkFilter::Stop()
180 {
181 FilterBase::Stop();
182 currentPos_ = 0;
183 if (plugin_) {
184 if (bufferEos_) {
185 plugin_->Stop();
186 } else {
187 plugin_->Reset();
188 }
189 }
190 return ErrorCode::SUCCESS;
191 }
192
ConfigureToPreparePlugin()193 ErrorCode OutputSinkFilter::ConfigureToPreparePlugin()
194 {
195 if (plugin_ == nullptr) {
196 MEDIA_LOG_E("no available plugin");
197 return ErrorCode::ERROR_INVALID_STATE;
198 }
199 auto err = TranslatePluginStatus(plugin_->SetSink(sink_));
200 if (err != ErrorCode::SUCCESS) {
201 MEDIA_LOG_E("Output sink configure error");
202 OnEvent({name_, EventType::EVENT_ERROR, err});
203 return err;
204 }
205 FAIL_RETURN_MSG_W(TranslatePluginStatus(plugin_->Prepare()), "plugin prepare failed");
206 return ErrorCode::SUCCESS;
207 }
208 } // Pipeline
209 } // Media
210 } // OHOS
211 #endif // RECORDER_SUPPORT