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