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
16 #ifdef RECORDER_SUPPORT
17
18 #define HST_LOG_TAG "AudioEncoderFilter"
19
20 #include "audio_encoder_filter.h"
21 #include "factory/filter_factory.h"
22 #include "foundation/cpp_ext/memory_ext.h"
23 #include "osal/utils/util.h"
24 #include "utils/steady_clock.h"
25
26 #define DEFAULT_OUT_BUFFER_POOL_SIZE 5
27 #define MAX_OUT_DECODED_DATA_SIZE_PER_FRAME 20 * 1024 // 20kB
28
29 namespace OHOS {
30 namespace Media {
31 namespace Pipeline {
32 static AutoRegisterFilter<AudioEncoderFilter> g_registerFilterHelper("builtin.recorder.audioencoder");
33
AudioEncoderFilter(const std::string & name)34 AudioEncoderFilter::AudioEncoderFilter(const std::string& name) : CodecFilterBase(name)
35 {
36 filterType_ = FilterType::AUDIO_ENCODER;
37 MEDIA_LOG_D("audio encoder ctor called");
38 }
39
~AudioEncoderFilter()40 AudioEncoderFilter::~AudioEncoderFilter()
41 {
42 MEDIA_LOG_D("audio encoder dtor called");
43 Release();
44 }
45
Start()46 ErrorCode AudioEncoderFilter::Start()
47 {
48 MEDIA_LOG_I("audio encoder start called");
49 if (state_ != FilterState::READY && state_ != FilterState::PAUSED) {
50 MEDIA_LOG_W("call encoder start() when state is not ready or working");
51 return ErrorCode::ERROR_INVALID_OPERATION;
52 }
53 rb_->SetActive(true);
54 return FilterBase::Start();
55 }
56
SetAudioEncoder(int32_t sourceId,std::shared_ptr<Plugin::Meta> encoderMeta)57 ErrorCode AudioEncoderFilter::SetAudioEncoder(int32_t sourceId, std::shared_ptr<Plugin::Meta> encoderMeta)
58 {
59 std::string mime;
60 FALSE_RETURN_V_MSG_E(encoderMeta->GetString(Plugin::MetaID::MIME, mime), ErrorCode::ERROR_INVALID_PARAMETER_VALUE,
61 "encoder meta must contains mime");
62 mime_ = mime;
63 encoderMeta_ = std::move(encoderMeta);
64 return ErrorCode::SUCCESS;
65 }
66
Negotiate(const std::string & inPort,const std::shared_ptr<const Plugin::Capability> & upstreamCap,Plugin::Capability & negotiatedCap,const Plugin::TagMap & upstreamParams,Plugin::TagMap & downstreamParams)67 bool AudioEncoderFilter::Negotiate(const std::string& inPort,
68 const std::shared_ptr<const Plugin::Capability>& upstreamCap,
69 Plugin::Capability& negotiatedCap,
70 const Plugin::TagMap& upstreamParams,
71 Plugin::TagMap& downstreamParams)
72 {
73 PROFILE_BEGIN("Audio Encoder Negotiate begin");
74 FALSE_RETURN_V_MSG_E(state_ == FilterState::PREPARING, false, "not preparing when negotiate");
75 auto targetOutPort = GetRouteOutPort(inPort);
76 FALSE_RETURN_V_MSG_E(targetOutPort != nullptr, false, "out port not found");
77 std::shared_ptr<Plugin::PluginInfo> selectedPluginInfo = nullptr;
78 bool atLeastOutCapMatched = false;
79 auto candidatePlugins = FindAvailablePlugins(*upstreamCap, Plugin::PluginType::CODEC);
80 for (const auto& candidate : candidatePlugins) {
81 FALSE_LOG_MSG(!candidate.first->outCaps.empty(), "encoder plugin must have out caps");
82 for (const auto& outCap : candidate.first->outCaps) { // each codec plugin should have at least one out cap
83 Plugin::Meta tmpMeta;
84 if (outCap.mime != mime_ || !MergeMetaWithCapability(*encoderMeta_, outCap, tmpMeta)) {
85 continue;
86 }
87 auto thisOut = std::make_shared<Plugin::Capability>();
88 if (!MergeCapabilityKeys(*upstreamCap, outCap, *thisOut)) {
89 MEDIA_LOG_I("one cap of plugin " PUBLIC_LOG_S " mismatch upstream cap", candidate.first->name.c_str());
90 continue;
91 }
92 atLeastOutCapMatched = true;
93 thisOut->mime = outCap.mime;
94 if (targetOutPort->Negotiate(thisOut, capNegWithDownstream_, upstreamParams, downstreamParams)) {
95 capNegWithUpstream_ = candidate.second;
96 selectedPluginInfo = candidate.first;
97 MEDIA_LOG_I("use plugin " PUBLIC_LOG_S, candidate.first->name.c_str());
98 MEDIA_LOG_I("neg upstream cap " PUBLIC_LOG_S, Capability2String(capNegWithUpstream_).c_str());
99 MEDIA_LOG_I("neg downstream cap " PUBLIC_LOG_S, Capability2String(capNegWithDownstream_).c_str());
100 break;
101 }
102 }
103 if (selectedPluginInfo != nullptr) {
104 break;
105 }
106 }
107 FALSE_RETURN_V_MSG_E(atLeastOutCapMatched && selectedPluginInfo != nullptr, false,
108 "can't find available encoder plugin with " PUBLIC_LOG_S, Capability2String(*upstreamCap).c_str());
109 auto res = UpdateAndInitPluginByInfo<Plugin::Codec>(plugin_, pluginInfo_, selectedPluginInfo,
110 [](const std::string& name)-> std::shared_ptr<Plugin::Codec> {
111 return Plugin::PluginManager::Instance().CreateCodecPlugin(name);
112 });
113 negotiatedCap = *upstreamCap;
114 plugin_->SetDataCallback(this);
115 PROFILE_END("audio encoder negotiate end");
116 return res;
117 }
118
CalculateBufferSize(const std::shared_ptr<const Plugin::Meta> & meta)119 uint32_t AudioEncoderFilter::CalculateBufferSize(const std::shared_ptr<const Plugin::Meta>& meta)
120 {
121 Plugin::ValueType value;
122 if (plugin_->GetParameter(Plugin::Tag::AUDIO_SAMPLE_PER_FRAME, value) != Plugin::Status::OK ||
123 !value.SameTypeWith(typeid(uint32_t))) {
124 MEDIA_LOG_E("Get samplePerFrame from plugin fail");
125 return 0;
126 }
127 auto samplesPerFrame = Plugin::AnyCast<uint32_t>(value);
128 uint32_t channels;
129 if (!meta->GetUint32(Plugin::MetaID::AUDIO_CHANNELS, channels)) {
130 return 0;
131 }
132 Plugin::AudioSampleFormat format;
133 if (!meta->GetData<Plugin::AudioSampleFormat>(Plugin::MetaID::AUDIO_SAMPLE_FORMAT, format)) {
134 return 0;
135 }
136 return GetBytesPerSample(format) * samplesPerFrame * channels;
137 }
138
Configure(const std::string & inPort,const std::shared_ptr<const Plugin::Meta> & upstreamMeta,Plugin::TagMap & upstreamParams,Plugin::TagMap & downstreamParams)139 bool AudioEncoderFilter::Configure(const std::string &inPort, const std::shared_ptr<const Plugin::Meta> &upstreamMeta,
140 Plugin::TagMap &upstreamParams, Plugin::TagMap &downstreamParams)
141 {
142 PROFILE_BEGIN("Audio encoder configure begin");
143 MEDIA_LOG_I("receive upstream meta " PUBLIC_LOG_S, Meta2String(*upstreamMeta).c_str());
144 FALSE_RETURN_V_MSG_E(plugin_ != nullptr && pluginInfo_ != nullptr, false,
145 "can't configure encoder when no plugin available");
146 auto thisMeta = std::make_shared<Plugin::Meta>();
147 // todo how to decide the caps ?
148 FALSE_RETURN_V_MSG_E(MergeMetaWithCapability(*upstreamMeta, pluginInfo_->outCaps[0], *thisMeta), false,
149 "can't configure encoder plugin since meta is not compatible with negotiated caps");
150 auto targetOutPort = GetRouteOutPort(inPort);
151 FALSE_RETURN_V_MSG_E(targetOutPort != nullptr, false, "encoder out port is not found");
152 auto err = ConfigureToStartPluginLocked(thisMeta);
153 if (err != ErrorCode::SUCCESS) {
154 MEDIA_LOG_E("encoder configure error");
155 OnEvent({name_, EventType::EVENT_ERROR, err});
156 return false;
157 }
158 FAIL_LOG(UpdateMetaFromPlugin(*thisMeta));
159 FALSE_RETURN_V_MSG_E(targetOutPort->Configure(thisMeta, upstreamParams, downstreamParams), false,
160 "fail to configure downstream");
161 state_ = FilterState::READY;
162 OnEvent({name_, EventType::EVENT_READY});
163 MEDIA_LOG_I("audio encoder send EVENT_READY");
164 PROFILE_END("Audio encoder configure end");
165 return true;
166 }
167
ConfigureToStartPluginLocked(const std::shared_ptr<const Plugin::Meta> & meta)168 ErrorCode AudioEncoderFilter::ConfigureToStartPluginLocked(const std::shared_ptr<const Plugin::Meta>& meta)
169 {
170 FAIL_RETURN_MSG(ConfigPluginWithMeta(*plugin_, *meta), "configure encoder plugin error");
171 FAIL_RETURN_MSG(TranslatePluginStatus(plugin_->Prepare()), "encoder prepare failed");
172 FAIL_RETURN_MSG(TranslatePluginStatus(plugin_->Start()), "encoder start failed");
173
174 uint32_t bufferCnt = 0;
175 if (GetPluginParameterLocked(Tag::REQUIRED_OUT_BUFFER_CNT, bufferCnt) != ErrorCode::SUCCESS) {
176 bufferCnt = DEFAULT_OUT_BUFFER_POOL_SIZE;
177 }
178 // 每次重新创建bufferPool
179 outBufferPool_ = std::make_shared<BufferPool<AVBuffer>>(bufferCnt);
180 frameSize_ = CalculateBufferSize(meta);
181 if (frameSize_ == 0) {
182 frameSize_ = MAX_OUT_DECODED_DATA_SIZE_PER_FRAME;
183 }
184 auto outAllocator = plugin_->GetAllocator();
185 if (outAllocator == nullptr) {
186 MEDIA_LOG_I("plugin doest not support out allocator, using framework allocator");
187 outBufferPool_->Init(frameSize_);
188 } else {
189 MEDIA_LOG_I("using plugin output allocator");
190 for (size_t cnt = 0; cnt < bufferCnt; cnt++) {
191 auto buf = CppExt::make_unique<AVBuffer>();
192 buf->AllocMemory(outAllocator, frameSize_);
193 outBufferPool_->Append(std::move(buf));
194 }
195 }
196 rb_ = CppExt::make_unique<RingBuffer>(frameSize_ * 10); // 最大缓存10帧
197 FALSE_RETURN_V_MSG_E(rb_ != nullptr, ErrorCode::ERROR_NO_MEMORY, "create ring buffer failed");
198 rb_->Init();
199 cahceBuffer_ = std::make_shared<AVBuffer>(Plugin::BufferMetaType::AUDIO);
200 FALSE_RETURN_V_MSG_E(cahceBuffer_->AllocMemory(nullptr, frameSize_) != nullptr, ErrorCode::ERROR_NO_MEMORY,
201 "alloc cache mem failed");
202 return ErrorCode::SUCCESS;
203 }
204
PushData(const std::string & inPort,const AVBufferPtr & buffer,int64_t offset)205 ErrorCode AudioEncoderFilter::PushData(const std::string& inPort, const AVBufferPtr& buffer, int64_t offset)
206 {
207 const static int8_t maxRetryCnt = 3; // max retry times of handling one frame
208 if (state_ != FilterState::READY && state_ != FilterState::PAUSED && state_ != FilterState::RUNNING) {
209 MEDIA_LOG_W("pushing data to encoder when state is " PUBLIC_LOG_D32, static_cast<int>(state_.load()));
210 return ErrorCode::ERROR_INVALID_OPERATION;
211 }
212 auto inputMemory = buffer->GetMemory();
213 if (inputMemory && inputMemory->GetSize() > 0) {
214 rb_->WriteBuffer(const_cast<uint8_t *>(inputMemory->GetReadOnlyData()), inputMemory->GetSize());
215 }
216 bool shouldDrainRb = buffer->flag & BUFFER_FLAG_EOS;
217 bool isRbDrained = false;
218 for (auto available = rb_->GetSize(); (available >= frameSize_) || (shouldDrainRb && !isRbDrained);
219 available = rb_->GetSize()) {
220 cahceBuffer_->Reset();
221 auto encodeSize = std::min(available, frameSize_);
222 if (encodeSize > 0) { // ring buffer has buffer available
223 if (rb_->ReadBuffer(cahceBuffer_->GetMemory()->GetWritableAddr(encodeSize), encodeSize) != encodeSize) {
224 MEDIA_LOG_E("Read data from ring buffer fail");
225 return ErrorCode::ERROR_UNKNOWN;
226 }
227 } else { // EOS
228 cahceBuffer_->flag |= BUFFER_FLAG_EOS;
229 isRbDrained = true;
230 }
231 ErrorCode handleFrameRes;
232 int8_t retryCnt = 0;
233 do {
234 handleFrameRes = HandleFrame(cahceBuffer_);
235 while (FinishFrame() == ErrorCode::SUCCESS) {
236 MEDIA_LOG_DD("finish frame");
237 }
238 retryCnt++;
239 if (retryCnt >= maxRetryCnt) { // if retry cnt exceeds we will drop this frame
240 break;
241 }
242 // if timed out or returns again we should try again
243 } while (handleFrameRes == ErrorCode::ERROR_TIMED_OUT || handleFrameRes == ErrorCode::ERROR_AGAIN);
244 }
245 return ErrorCode::SUCCESS;
246 }
247
Stop()248 ErrorCode AudioEncoderFilter::Stop()
249 {
250 MEDIA_LOG_I("AudioEncoderFilter stop start.");
251 // 先改变底层状态 然后停掉上层线程 否则会产生死锁
252 if (plugin_ != nullptr) {
253 FAIL_RETURN_MSG(TranslatePluginStatus(plugin_->Flush()), "encoder flush error");
254 FAIL_RETURN_MSG(TranslatePluginStatus(plugin_->Stop()), "encoder stop error");
255 }
256 if (rb_) {
257 rb_->SetActive(false);
258 }
259 MEDIA_LOG_I("AudioEncoderFilter stop end.");
260 return FilterBase::Stop();
261 }
262
Release()263 ErrorCode AudioEncoderFilter::Release()
264 {
265 if (plugin_) {
266 plugin_->Stop();
267 plugin_->Deinit();
268 }
269 return ErrorCode::SUCCESS;
270 }
271
HandleFrame(const std::shared_ptr<AVBuffer> & buffer)272 ErrorCode AudioEncoderFilter::HandleFrame(const std::shared_ptr<AVBuffer>& buffer)
273 {
274 MEDIA_LOG_DD("HandleFrame called");
275 auto ret = TranslatePluginStatus(plugin_->QueueInputBuffer(buffer, 0));
276 FALSE_LOG_MSG(ret == ErrorCode::SUCCESS || ret == ErrorCode::ERROR_TIMED_OUT,
277 "Queue input buffer to plugin fail: " PUBLIC_LOG_D32, ret);
278 return ret;
279 }
280
FinishFrame()281 ErrorCode AudioEncoderFilter::FinishFrame()
282 {
283 MEDIA_LOG_DD("begin finish frame");
284 auto outBuffer = outBufferPool_->AllocateAppendBufferNonBlocking();
285 FALSE_RETURN_V_MSG_E(outBuffer != nullptr, ErrorCode::ERROR_NO_MEMORY, "Get out buffer from buffer pool fail");
286 outBuffer->Reset();
287 auto status = plugin_->QueueOutputBuffer(outBuffer, 0);
288 if (status != Plugin::Status::OK && status != Plugin::Status::END_OF_STREAM) {
289 if (status != Plugin::Status::ERROR_NOT_ENOUGH_DATA) {
290 MEDIA_LOG_E("Queue output buffer to plugin fail: " PUBLIC_LOG_D32, static_cast<int32_t>((status)));
291 }
292 }
293 MEDIA_LOG_DD("end finish frame");
294 return TranslatePluginStatus(status);
295 }
296
OnInputBufferDone(const std::shared_ptr<Plugin::Buffer> & input)297 void AudioEncoderFilter::OnInputBufferDone(const std::shared_ptr<Plugin::Buffer>& input)
298 {
299 MEDIA_LOG_DD("AudioEncoderFilter::OnInputBufferDone");
300 }
301
OnOutputBufferDone(const std::shared_ptr<Plugin::Buffer> & output)302 void AudioEncoderFilter::OnOutputBufferDone(const std::shared_ptr<Plugin::Buffer>& output)
303 {
304 FALSE_RETURN(output != nullptr);
305
306 // push to port
307 auto oPort = outPorts_[0];
308 if (oPort->GetWorkMode() == WorkMode::PUSH) {
309 oPort->PushData(output, -1);
310 } else {
311 MEDIA_LOG_W("encoder out port works in pull mode");
312 }
313
314 // 释放buffer 如果没有被缓存使其回到buffer pool 如果被sink缓存 则从buffer pool拿其他的buffer
315 std::const_pointer_cast<Plugin::Buffer>(output).reset();
316 }
317 } // Pipeline
318 } // Media
319 } // OHOS
320 #endif // RECORDER_SUPPORT