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