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