• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 #define HST_LOG_TAG "MediaMuxer"
17 
18 #include "media_muxer.h"
19 
20 #include <set>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <string>
24 #include <unordered_map>
25 
26 #include "securec.h"
27 #include "meta/mime_type.h"
28 #include "plugin/plugin_manager_v2.h"
29 #include "common/log.h"
30 #include "data_sink_fd.h"
31 #include "data_sink_file.h"
32 
33 namespace {
34 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_MUXER, "HiStreamer" };
35 }
36 
37 namespace {
38 using namespace OHOS::Media;
39 using namespace Plugins;
40 
41 constexpr int32_t ERR_TRACK_INDEX = -1;
42 constexpr uint32_t MAX_BUFFER_COUNT = 10;
43 
44 const std::unordered_map<OutputFormat, std::set<std::string>> MUX_FORMAT_INFO = {
45     {OutputFormat::MPEG_4, {MimeType::AUDIO_MPEG, MimeType::AUDIO_AAC,
46                             MimeType::VIDEO_AVC, MimeType::VIDEO_MPEG4,
47                             MimeType::VIDEO_HEVC,
48                             MimeType::IMAGE_JPG, MimeType::IMAGE_PNG,
49                             MimeType::IMAGE_BMP, MimeType::TIMED_METADATA}},
50     {OutputFormat::M4A, {MimeType::AUDIO_AAC,
51                          MimeType::IMAGE_JPG, MimeType::IMAGE_PNG,
52                          MimeType::IMAGE_BMP}},
53     {OutputFormat::AMR, {MimeType::AUDIO_AMR_NB, MimeType::AUDIO_AMR_WB}},
54     {OutputFormat::MP3, {MimeType::AUDIO_MPEG, MimeType::IMAGE_JPG}},
55     {OutputFormat::WAV, {MimeType::AUDIO_RAW, MimeType::AUDIO_G711MU}},
56     {OutputFormat::AAC, {MimeType::AUDIO_AAC}},
57     {OutputFormat::FLAC, {MimeType::AUDIO_FLAC, MimeType::IMAGE_JPG,
58                           MimeType::IMAGE_PNG, MimeType::IMAGE_BMP}},
59 };
60 
61 const std::map<std::string, std::set<std::string>> MUX_MIME_INFO = {
62     {MimeType::AUDIO_MPEG, {Tag::AUDIO_SAMPLE_RATE, Tag::AUDIO_CHANNEL_COUNT}},
63     {MimeType::AUDIO_AAC, {Tag::AUDIO_SAMPLE_RATE, Tag::AUDIO_CHANNEL_COUNT}},
64     {MimeType::AUDIO_RAW, {Tag::AUDIO_SAMPLE_RATE, Tag::AUDIO_CHANNEL_COUNT, Tag::AUDIO_SAMPLE_FORMAT}},
65     {MimeType::AUDIO_G711MU, {Tag::AUDIO_SAMPLE_RATE, Tag::AUDIO_CHANNEL_COUNT, Tag::MEDIA_BITRATE}},
66     {MimeType::AUDIO_FLAC, {Tag::AUDIO_SAMPLE_RATE, Tag::AUDIO_CHANNEL_COUNT}},
67     {MimeType::VIDEO_AVC, {Tag::VIDEO_WIDTH, Tag::VIDEO_HEIGHT}},
68     {MimeType::VIDEO_MPEG4, {Tag::VIDEO_WIDTH, Tag::VIDEO_HEIGHT}},
69     {MimeType::VIDEO_HEVC, {Tag::VIDEO_WIDTH, Tag::VIDEO_HEIGHT}},
70     {MimeType::IMAGE_JPG, {Tag::VIDEO_WIDTH, Tag::VIDEO_HEIGHT}},
71     {MimeType::IMAGE_PNG, {Tag::VIDEO_WIDTH, Tag::VIDEO_HEIGHT}},
72     {MimeType::IMAGE_BMP, {Tag::VIDEO_WIDTH, Tag::VIDEO_HEIGHT}},
73     {MimeType::TIMED_METADATA, {Tag::TIMED_METADATA_KEY, Tag::TIMED_METADATA_SRC_TRACK}},
74 };
75 
76 const std::map<std::string, std::set<std::string>> MUX_MIME_INFO_EXT = {
77     {MimeType::AUDIO_AAC, {Tag::AUDIO_AAC_IS_ADTS, Tag::MEDIA_PROFILE}},
78 };
79 
80 const std::set<std::string> MUX_AUXILIARY_TRACK_INFO = {
81     Tag::REFERENCE_TRACK_IDS, Tag::TRACK_REFERENCE_TYPE, Tag::TRACK_DESCRIPTION,
82 };
83 }
84 
85 namespace OHOS {
86 namespace Media {
MediaMuxer(int32_t appUid,int32_t appPid)87 MediaMuxer::MediaMuxer(int32_t appUid, int32_t appPid)
88     : appUid_(appUid), appPid_(appPid), format_(Plugins::OutputFormat::DEFAULT)
89 {
90     MEDIA_LOG_D("0x%{public}06" PRIXPTR " instances create", FAKE_POINTER(this));
91 }
92 
~MediaMuxer()93 MediaMuxer::~MediaMuxer()
94 {
95     MEDIA_LOG_D("Destroy");
96     if (state_ == State::STARTED) {
97         Stop();
98     }
99 
100     appUid_ = -1;
101     appPid_ = -1;
102     muxer_ = nullptr;
103     tracks_.clear();
104     MEDIA_LOG_D("0x%{public}06" PRIXPTR " instances destroy", FAKE_POINTER(this));
105 }
106 
Init(int32_t fd,Plugins::OutputFormat format)107 Status MediaMuxer::Init(int32_t fd, Plugins::OutputFormat format)
108 {
109     MEDIA_LOG_I("Init");
110     std::lock_guard<std::mutex> lock(mutex_);
111     FALSE_RETURN_V_MSG_E(state_ == State::UNINITIALIZED, Status::ERROR_WRONG_STATE,
112         "The state is not UNINITIALIZED, the current state is %{public}s.", StateConvert(state_).c_str());
113 
114     FALSE_RETURN_V_MSG_E(fd >= 0, Status::ERROR_INVALID_PARAMETER, "The fd %{public}d is error!", fd);
115     uint32_t fdPermission = static_cast<uint32_t>(fcntl(fd, F_GETFL, 0));
116     FALSE_RETURN_V_MSG_E((fdPermission & O_WRONLY) == O_WRONLY || (fdPermission & O_RDWR) == O_RDWR,
117         Status::ERROR_INVALID_PARAMETER, "No permission to write fd.");
118     FALSE_RETURN_V_MSG_E(lseek(fd, 0, SEEK_CUR) != -1, Status::ERROR_INVALID_PARAMETER,
119         "The fd is not seekable.");
120     format_ = format == Plugins::OutputFormat::DEFAULT ? Plugins::OutputFormat::MPEG_4 : format;
121     muxer_ = CreatePlugin(format_);
122     if (muxer_ != nullptr) {
123         state_ = State::INITIALIZED;
124         muxer_->SetCallback(this);
125         MEDIA_LOG_I("The state is INITIALIZED");
126     } else {
127         MEDIA_LOG_E("The state is UNINITIALIZED");
128     }
129     FALSE_RETURN_V_MSG_E(state_ == State::INITIALIZED, Status::ERROR_WRONG_STATE,
130         "The state is UNINITIALIZED");
131     return muxer_->SetDataSink(std::make_shared<DataSinkFd>(fd));
132 }
133 
Init(FILE * file,Plugins::OutputFormat format)134 Status MediaMuxer::Init(FILE *file, Plugins::OutputFormat format)
135 {
136     MEDIA_LOG_I("Init");
137     std::lock_guard<std::mutex> lock(mutex_);
138     FALSE_RETURN_V_MSG_E(state_ == State::UNINITIALIZED, Status::ERROR_WRONG_STATE,
139         "The state is not UNINITIALIZED, the current state is %{public}s.", StateConvert(state_).c_str());
140 
141     FALSE_RETURN_V_MSG_E(file != nullptr, Status::ERROR_INVALID_PARAMETER, "The file handle is null!");
142     FALSE_RETURN_V_MSG_E(fseek(file, 0L, SEEK_CUR) >= 0, Status::ERROR_INVALID_PARAMETER,
143         "The file handle is not seekable.");
144     format_ = format == Plugins::OutputFormat::DEFAULT ? Plugins::OutputFormat::MPEG_4 : format;
145     muxer_ = CreatePlugin(format_);
146     if (muxer_ != nullptr) {
147         state_ = State::INITIALIZED;
148         muxer_->SetCallback(this);
149         MEDIA_LOG_I("The state is INITIALIZED");
150     } else {
151         MEDIA_LOG_E("The state is UNINITIALIZED");
152     }
153     FALSE_RETURN_V_MSG_E(state_ == State::INITIALIZED, Status::ERROR_WRONG_STATE,
154                          "The state is UNINITIALIZED");
155     return muxer_->SetDataSink(std::make_shared<DataSinkFile>(file));
156 }
157 
SetParameter(const std::shared_ptr<Meta> & param)158 Status MediaMuxer::SetParameter(const std::shared_ptr<Meta> &param)
159 {
160     MEDIA_LOG_I("SetParameter");
161     std::lock_guard<std::mutex> lock(mutex_);
162     FALSE_RETURN_V_MSG_E(state_ == State::INITIALIZED, Status::ERROR_WRONG_STATE,
163         "The state is not INITIALIZED, the interface must be called after constructor and before Start(). "
164         "The current state is %{public}s.", StateConvert(state_).c_str());
165     return muxer_->SetParameter(param);
166 }
167 
SetUserMeta(const std::shared_ptr<Meta> & userMeta)168 Status MediaMuxer::SetUserMeta(const std::shared_ptr<Meta> &userMeta)
169 {
170     MEDIA_LOG_I("SetUserMeta");
171     std::lock_guard<std::mutex> lock(mutex_);
172     std::vector<std::string> keys;
173     userMeta->GetKeys(keys);
174     for (auto& k: keys) {
175         if (k.compare("com.openharmony.recorder.timestamp") == 0) {
176             MEDIA_LOG_I("set com.openharmony.recorder.timestamp");
177             return muxer_->SetUserMeta(userMeta);
178         }
179     }
180     FALSE_RETURN_V_MSG_E(state_ == State::INITIALIZED || state_ == State::STARTED, Status::ERROR_WRONG_STATE,
181         "The state is not INITIALIZED, the interface must be called at initialized or started state. "
182         "The current state is %{public}s.", StateConvert(state_).c_str());
183     return muxer_->SetUserMeta(userMeta);
184 }
185 
AddTrack(int32_t & trackIndex,const std::shared_ptr<Meta> & trackDesc)186 Status MediaMuxer::AddTrack(int32_t &trackIndex, const std::shared_ptr<Meta> &trackDesc)
187 {
188     MEDIA_LOG_I("AddTrack");
189     std::lock_guard<std::mutex> lock(mutex_);
190     trackIndex = ERR_TRACK_INDEX;
191     FALSE_RETURN_V_MSG_E(state_ == State::INITIALIZED, Status::ERROR_WRONG_STATE,
192         "The state is not INITIALIZED, the interface must be called after constructor and before Start(). "
193         "The current state is %{public}s.", StateConvert(state_).c_str());
194     std::string mimeType = {};
195     FALSE_RETURN_V_MSG_E(trackDesc->Get<Tag::MIME_TYPE>(mimeType), Status::ERROR_INVALID_DATA,
196         "The track format does not contain mime.");
197     FALSE_RETURN_V_MSG_E(CanAddTrack(mimeType), Status::ERROR_UNSUPPORTED_FORMAT,
198         "The track mime is unsupported: %{public}s.", mimeType.c_str());
199     FALSE_RETURN_V_MSG_E(CheckKeys(mimeType, trackDesc), Status::ERROR_INVALID_DATA,
200         "The track format keys not contained.");
201     FALSE_RETURN_V_MSG_E(CheckKeysExt(mimeType, trackDesc, format_), Status::ERROR_INVALID_DATA,
202         "The track format keys not contained.");
203     MEDIA_LOG_I("The track is %{public}s.", mimeType.c_str());
204 
205     int32_t trackId = -1;
206     Status ret = muxer_->AddTrack(trackId, trackDesc);
207     FALSE_RETURN_V_MSG_E(ret == Status::NO_ERROR, ret, "AddTrack failed! %{public}s.", mimeType.c_str());
208     FALSE_RETURN_V_MSG_E(trackId >= 0, Status::ERROR_INVALID_DATA,
209         "The track index is greater than or equal to 0.");
210     trackIndex = static_cast<int32_t>(tracks_.size());
211     sptr<Track> track = new Track();
212     track->trackId_ = trackId;
213     track->mimeType_ = mimeType;
214     track->trackDesc_ = trackDesc;
215     track->bufferQ_ = AVBufferQueue::Create(MAX_BUFFER_COUNT, MemoryType::UNKNOWN_MEMORY, mimeType);
216     track->producer_ = track->bufferQ_->GetProducer();
217     track->consumer_ = track->bufferQ_->GetConsumer();
218     tracks_.emplace_back(track);
219     return Status::NO_ERROR;
220 }
221 
GetInputBufferQueue(uint32_t trackIndex)222 sptr<AVBufferQueueProducer> MediaMuxer::GetInputBufferQueue(uint32_t trackIndex)
223 {
224     MEDIA_LOG_I("GetInputBufferQueue");
225     std::lock_guard<std::mutex> lock(mutex_);
226     FALSE_RETURN_V_MSG_E(state_ == State::INITIALIZED, nullptr,
227         "The state is not INITIALIZED, the interface must be called after AddTrack() and before Start(). "
228         "The current state is %{public}s.", StateConvert(state_).c_str());
229     FALSE_RETURN_V_MSG_E(trackIndex < tracks_.size(), nullptr,
230         "The track index does not exist, the interface must be called after AddTrack() and before Start().");
231     return tracks_[trackIndex]->producer_;
232 }
233 
WriteSample(uint32_t trackIndex,const std::shared_ptr<AVBuffer> & sample)234 Status MediaMuxer::WriteSample(uint32_t trackIndex, const std::shared_ptr<AVBuffer> &sample)
235 {
236     std::lock_guard<std::mutex> lock(mutex_);
237     FALSE_RETURN_V_MSG_E(state_ == State::STARTED, Status::ERROR_WRONG_STATE,
238         "The state is not STARTED, the interface must be called after Start() and before Stop(). "
239         "The current state is %{public}s", StateConvert(state_).c_str());
240     FALSE_RETURN_V_MSG_E(trackIndex < tracks_.size(), Status::ERROR_INVALID_DATA,
241         "The track index does not exist, the interface must be called after AddTrack() and before Start().");
242     FALSE_RETURN_V_MSG_E(sample != nullptr && sample->memory_ != nullptr, Status::ERROR_INVALID_DATA,
243         "Invalid sample");
244     MEDIA_LOG_D("WriteSample track:" PUBLIC_LOG_U32 ", pts:" PUBLIC_LOG_D64 ", size:" PUBLIC_LOG_D32
245         ", flags:" PUBLIC_LOG_U32, trackIndex, sample->pts_, sample->memory_->GetSize(), sample->flag_);
246     std::shared_ptr<AVBuffer> buffer = nullptr;
247     AVBufferConfig avBufferConfig;
248     avBufferConfig.size = sample->memory_->GetSize();
249     avBufferConfig.memoryType = MemoryType::VIRTUAL_MEMORY;
250     Status ret = tracks_[trackIndex]->producer_->RequestBuffer(buffer, avBufferConfig, -1);
251     FALSE_RETURN_V_MSG_E(ret == Status::OK && buffer != nullptr, Status::ERROR_NO_MEMORY,
252         "Request buffer failed.");
253     buffer->pts_ = sample->pts_;
254     buffer->dts_ = sample->dts_;
255     buffer->flag_ = sample->flag_;
256     buffer->duration_ = sample->duration_;
257     *buffer->meta_.get() = *sample->meta_.get(); // copy meta
258     if (sample->memory_ != nullptr && sample->memory_->GetSize() > 0) { // copy data
259         int32_t retInt = buffer->memory_->Write(sample->memory_->GetAddr(), sample->memory_->GetSize(), 0);
260         FALSE_RETURN_V_MSG_E(retInt > 0, Status::ERROR_NO_MEMORY, "Write sample in buffer failed.");
261     } else {
262         MEDIA_LOG_W("No data in the sample.");
263         buffer->memory_->SetSize(0); // no data in the buffer, clear buffer size
264     }
265     return tracks_[trackIndex]->producer_->PushBuffer(buffer, true);
266 }
267 
Start()268 Status MediaMuxer::Start()
269 {
270     MEDIA_LOG_I("Start");
271     std::lock_guard<std::mutex> lock(mutex_);
272     FALSE_RETURN_V_MSG_E(state_ == State::INITIALIZED, Status::ERROR_WRONG_STATE,
273         "The state is not INITIALIZED, the interface must be called after AddTrack() and before WriteSample(). "
274         "The current state is %{public}s.", StateConvert(state_).c_str());
275     FALSE_RETURN_V_MSG_E(tracks_.size() > 0, Status::ERROR_INVALID_OPERATION,
276         "The track count is error, count is %{public}zu.", tracks_.size());
277     Status ret = muxer_->Start();
278     FALSE_RETURN_V_MSG_E(ret == Status::NO_ERROR, ret, "Start failed!");
279     state_ = State::STARTED;
280     for (const auto& track : tracks_) {
281         track->SetBufferAvailableListener(this);
282         sptr<IConsumerListener> listener = track;
283         track->consumer_->SetBufferAvailableListener(listener);
284     }
285     StartThread("OS_MUXER_WRITE");
286     return Status::NO_ERROR;
287 }
288 
StartThread(const std::string & name)289 void MediaMuxer::StartThread(const std::string &name)
290 {
291     threadName_ = name;
292     if (thread_ != nullptr) {
293         MEDIA_LOG_W("Started already! [%{public}s]", threadName_.c_str());
294         return;
295     }
296     isThreadExit_ = false;
297     thread_ = std::make_unique<std::thread>(&MediaMuxer::ThreadProcessor, this);
298     MEDIA_LOG_D("The thread started! [%{public}s]", threadName_.c_str());
299 }
300 
Stop()301 Status MediaMuxer::Stop()
302 {
303     MEDIA_LOG_I("Stop");
304     std::lock_guard<std::mutex> lock(mutex_);
305     if (state_ == State::STOPPED) {
306         MEDIA_LOG_W("The current state is STOPPED!");
307         return Status::ERROR_INVALID_OPERATION;
308     }
309     FALSE_RETURN_V_MSG_E(state_ == State::STARTED, Status::ERROR_WRONG_STATE,
310         "The state is not STARTED. The current state is %{public}s.", StateConvert(state_).c_str());
311     state_ = State::STOPPED;
312     for (auto& track : tracks_) { // Stop the producer first
313         sptr<IConsumerListener> listener = nullptr;
314         track->consumer_->SetBufferAvailableListener(listener);
315     }
316     StopThread();
317     PrintWriteCount();
318     Status ret = muxer_->Stop();
319     FALSE_RETURN_V_MSG_E(ret == Status::NO_ERROR, ret, "Stop failed!");
320     MEDIA_LOG_I("Stopped successfully.");
321     return Status::NO_ERROR;
322 }
323 
StopThread()324 void MediaMuxer::StopThread()
325 {
326     if (isThreadExit_) {
327         MEDIA_LOG_D("Stopped already! [%{public}s]", threadName_.c_str());
328         return;
329     }
330 
331     {
332         std::lock_guard<std::mutex> lock(mutexBufferAvailable_);
333         isThreadExit_ = true;
334         condBufferAvailable_.notify_all();
335     }
336 
337     MEDIA_LOG_D("Stopping ! [%{public}s]", threadName_.c_str());
338     if (thread_ != nullptr) {
339         if (thread_->joinable()) {
340             thread_->join();
341         }
342         thread_ = nullptr;
343     }
344 }
345 
Reset()346 Status MediaMuxer::Reset()
347 {
348     MEDIA_LOG_I("Reset");
349     if (state_ == State::STARTED) {
350         Stop();
351     }
352     state_ = State::UNINITIALIZED;
353     muxer_ = nullptr;
354     tracks_.clear();
355 
356     return Status::NO_ERROR;
357 }
358 
ThreadProcessor()359 void MediaMuxer::ThreadProcessor()
360 {
361     MEDIA_LOG_D("Enter ThreadProcessor [%{public}s]", threadName_.c_str());
362     constexpr int32_t timeoutMs = 500;
363     constexpr uint32_t nameSizeMax = 15;
364     pthread_setname_np(pthread_self(), threadName_.substr(0, nameSizeMax).c_str());
365     int32_t trackCount = static_cast<int32_t>(tracks_.size());
366     for (;;) {
367         if (isThreadExit_ && bufferAvailableCount_ <= 0) {
368             MEDIA_LOG_D("Exit ThreadProcessor [%{public}s]", threadName_.c_str());
369             return;
370         }
371         std::unique_lock<std::mutex> lock(mutexBufferAvailable_);
372         condBufferAvailable_.wait_for(lock, std::chrono::milliseconds(timeoutMs),
373             [this] { return isThreadExit_ || bufferAvailableCount_ > 0; });
374         int32_t trackIdx = -1;
375         std::shared_ptr<AVBuffer> buffer1 = nullptr;
376         for (int i = 0; i < trackCount; ++i) {
377             std::shared_ptr<AVBuffer> buffer2 = tracks_[i]->GetBuffer();
378             if ((buffer1 != nullptr && buffer2 != nullptr && buffer1->pts_ > buffer2->pts_) ||
379                 (buffer1 == nullptr && buffer2 != nullptr)) {
380                 buffer1 = buffer2;
381                 trackIdx = i;
382             }
383         }
384         if (buffer1 != nullptr) {
385             muxer_->WriteSample(tracks_[trackIdx]->trackId_, tracks_[trackIdx]->curBuffer_);
386             tracks_[trackIdx]->ReleaseBuffer();
387             tracks_[trackIdx]->writeCount_++;
388         }
389         MEDIA_LOG_D("Track " PUBLIC_LOG_S " 2 bufferAvailableCount_ :" PUBLIC_LOG_D32,
390             threadName_.c_str(), bufferAvailableCount_.load());
391     }
392 }
393 
OnBufferAvailable()394 void MediaMuxer::OnBufferAvailable()
395 {
396     ++bufferAvailableCount_;
397     condBufferAvailable_.notify_one();
398     MEDIA_LOG_D("Track " PUBLIC_LOG_S " 1 bufferAvailableCount_ :" PUBLIC_LOG_D32,
399         threadName_.c_str(), bufferAvailableCount_.load());
400 }
401 
ReleaseBuffer()402 void MediaMuxer::ReleaseBuffer()
403 {
404     --bufferAvailableCount_;
405 }
406 
GetBuffer()407 std::shared_ptr<AVBuffer> MediaMuxer::Track::GetBuffer()
408 {
409     if (curBuffer_ == nullptr && bufferAvailableCount_ > 0) {
410         Status ret = consumer_->AcquireBuffer(curBuffer_);
411         if (ret != Status::OK) {
412             MEDIA_LOG_E("Track " PUBLIC_LOG_S " lost " PUBLIC_LOG_D32 " frames",
413                 mimeType_.c_str(), bufferAvailableCount_.load());
414             --bufferAvailableCount_;
415             listener_->ReleaseBuffer();
416         }
417     }
418     return curBuffer_;
419 }
420 
ReleaseBuffer()421 void MediaMuxer::Track::ReleaseBuffer()
422 {
423     if (curBuffer_ != nullptr) {
424         consumer_->ReleaseBuffer(curBuffer_);
425         curBuffer_ = nullptr;
426         --bufferAvailableCount_;
427         listener_->ReleaseBuffer();
428     }
429 }
430 
SetBufferAvailableListener(MediaMuxer * listener)431 void MediaMuxer::Track::SetBufferAvailableListener(MediaMuxer *listener)
432 {
433     listener_ = listener;
434 }
435 
OnBufferAvailable()436 void MediaMuxer::Track::OnBufferAvailable()
437 {
438     ++bufferAvailableCount_;
439     MEDIA_LOG_D("Track " PUBLIC_LOG_S " bufferAvailableCount_ :" PUBLIC_LOG_D32,
440         mimeType_.c_str(), bufferAvailableCount_.load());
441     listener_->OnBufferAvailable();
442 }
443 
CreatePlugin(Plugins::OutputFormat format)444 std::shared_ptr<Plugins::MuxerPlugin> MediaMuxer::CreatePlugin(Plugins::OutputFormat format)
445 {
446     static const std::unordered_map<Plugins::OutputFormat, std::string> table = {
447         {Plugins::OutputFormat::DEFAULT, MimeType::MEDIA_MP4},
448         {Plugins::OutputFormat::MPEG_4, MimeType::MEDIA_MP4},
449         {Plugins::OutputFormat::M4A, MimeType::MEDIA_M4A},
450         {Plugins::OutputFormat::AMR, MimeType::MEDIA_AMR},
451         {Plugins::OutputFormat::MP3, MimeType::MEDIA_MP3},
452         {Plugins::OutputFormat::WAV, MimeType::MEDIA_WAV},
453         {Plugins::OutputFormat::AAC, MimeType::MEDIA_AAC},
454         {Plugins::OutputFormat::FLAC, MimeType::MEDIA_FLAC},
455     };
456     FALSE_RETURN_V_MSG_E(table.find(format) != table.end(), nullptr,
457         "The output format %{public}d is not supported!", format);
458 
459     auto plugin = Plugins::PluginManagerV2::Instance().CreatePluginByMime(Plugins::PluginType::MUXER, table.at(format));
460     if (plugin == nullptr) {
461         return nullptr;
462     }
463     return std::reinterpret_pointer_cast<Plugins::MuxerPlugin>(plugin);
464 }
465 
CanAddTrack(const std::string & mimeType)466 bool MediaMuxer::CanAddTrack(const std::string &mimeType)
467 {
468     auto it = MUX_FORMAT_INFO.find(format_);
469     if (it == MUX_FORMAT_INFO.end()) {
470         return false;
471     }
472     return it->second.find(mimeType) != it->second.end();
473 }
474 
CheckKeys(const std::string & mimeType,const std::shared_ptr<Meta> & trackDesc)475 bool MediaMuxer::CheckKeys(const std::string &mimeType, const std::shared_ptr<Meta> &trackDesc)
476 {
477     bool ret = true;
478     auto it = MUX_MIME_INFO.find(mimeType);
479     if (it == MUX_MIME_INFO.end()) {
480         return ret; // 不做检查
481     }
482 
483     for (auto &key : it->second) {
484         if (trackDesc->Find(key.c_str()) == trackDesc->end()) {
485             ret = false;
486             MEDIA_LOG_E("The format key %{public}s not contained.", key.data());
487         }
488     }
489     return ret;
490 }
491 
CheckKeysExt(const std::string & mimeType,const std::shared_ptr<Meta> & trackDesc,Plugins::OutputFormat format)492 bool MediaMuxer::CheckKeysExt(const std::string &mimeType, const std::shared_ptr<Meta> &trackDesc,
493     Plugins::OutputFormat format)
494 {
495     bool ret = true;
496     if (format == Plugins::OutputFormat::AAC) { // AAC Muxer need
497         auto it = MUX_MIME_INFO_EXT.find(mimeType);
498         if (it == MUX_MIME_INFO_EXT.end()) {
499             return ret; // find mimeType failed, skip check
500         }
501 
502         for (auto &key : it->second) {
503             if (trackDesc->Find(key.c_str()) == trackDesc->end()) {
504                 ret = false;
505                 MEDIA_LOG_E("The format key %{public}s not contained.", key.data());
506             }
507         }
508     }
509 
510     if (!ret) {
511         return ret;
512     }
513 
514     // auxiliary track
515     Plugins::MediaType mediaType = Plugins::MediaType::UNKNOWN;
516     if (!trackDesc->Get<Tag::MEDIA_TYPE>(mediaType)) {
517         MEDIA_LOG_W("missing media type");
518     }
519 
520     if (mediaType == Plugins::MediaType::AUXILIARY) {
521         for (auto &key : MUX_AUXILIARY_TRACK_INFO) {
522             if (trackDesc->Find(key.c_str()) == trackDesc->end()) {
523                 ret = false;
524                 MEDIA_LOG_E("The auxiliary track key %{public}s not contained.", key.data());
525             }
526         }
527     }
528     return ret;
529 }
530 
StateConvert(State state)531 std::string MediaMuxer::StateConvert(State state)
532 {
533     static const std::map<State, std::string> table = {
534         {State::UNINITIALIZED, "UNINITIALIZED"},
535         {State::INITIALIZED, "INITIALIZED"},
536         {State::STARTED, "STARTED"},
537         {State::STOPPED, "STOPPED"},
538     };
539     auto it = table.find(state);
540     if (it != table.end()) {
541         return it->second;
542     }
543     return "";
544 }
545 
OnEvent(const PluginEvent & event)546 void MediaMuxer::OnEvent(const PluginEvent &event)
547 {
548     MEDIA_LOG_D("OnEvent");
549 }
550 
PrintWriteCount()551 void MediaMuxer::PrintWriteCount()
552 {
553     for (auto& track : tracks_) { // print track write count
554         MEDIA_LOG_I("The track is %{public}s, the count of writes is %{public}" PRIu64,
555             track->mimeType_.c_str(), track->writeCount_);
556     }
557 }
558 } // Media
559 } // OHOS
560