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> ¶m)
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