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