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