• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 #include "avmuxer_engine_gst_impl.h"
17 #include <unistd.h>
18 #include "gst_utils.h"
19 #include "media_errors.h"
20 #include "media_log.h"
21 #include "uri_helper.h"
22 
23 namespace {
24     constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVMuxerEngineGstImpl"};
25     constexpr int32_t MAX_LATITUDE = 90;
26     constexpr int32_t MIN_LATITUDE = -90;
27     constexpr int32_t MAX_LONGITUDE = 180;
28     constexpr int32_t MIN_LONGITUDE = -180;
29     constexpr uint32_t MULTIPLY10000 = 10000;
30     constexpr uint32_t MAX_VIDEO_TRACK_NUM = 1;
31     constexpr uint32_t MAX_AUDIO_TRACK_NUM = 16;
32     constexpr uint32_t US_TO_NS = 1000;
33 }
34 
35 namespace OHOS {
36 namespace Media {
StartFeed(const GstElement * src,guint length,gpointer userData)37 static void StartFeed(const GstElement *src, guint length, gpointer userData)
38 {
39     (void)length;
40     CHECK_AND_RETURN_LOG(src != nullptr, "AppSrc does not exist");
41     CHECK_AND_RETURN_LOG(userData != nullptr, "User data does not exist");
42     std::map<int32_t, TrackInfo> trackInfo = *reinterpret_cast<std::map<int32_t, TrackInfo> *>(userData);
43     for (auto& info : trackInfo) {
44         if (info.second.src_ == src) {
45             info.second.needData_ = true;
46             break;
47         }
48     }
49 }
50 
StopFeed(const GstElement * src,gpointer userData)51 static void StopFeed(const GstElement *src, gpointer userData)
52 {
53     CHECK_AND_RETURN_LOG(src != nullptr, "AppSrc does not exist");
54     CHECK_AND_RETURN_LOG(userData != nullptr, "User data does not exist");
55     std::map<int32_t, TrackInfo> trackInfo = *reinterpret_cast<std::map<int32_t, TrackInfo> *>(userData);
56     for (auto& info : trackInfo) {
57         if (info.second.src_ == src) {
58             info.second.needData_ = false;
59             break;
60         }
61     }
62 }
63 
AVMuxerEngineGstImpl()64 AVMuxerEngineGstImpl::AVMuxerEngineGstImpl()
65 {
66     MEDIA_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
67 }
68 
~AVMuxerEngineGstImpl()69 AVMuxerEngineGstImpl::~AVMuxerEngineGstImpl()
70 {
71     MEDIA_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
72     if (muxBin_ != nullptr) {
73         gst_object_unref(muxBin_);
74         muxBin_ = nullptr;
75     }
76     if (allocator_ != nullptr) {
77         gst_object_unref(allocator_);
78         allocator_ = nullptr;
79     }
80 }
81 
Init()82 int32_t AVMuxerEngineGstImpl::Init()
83 {
84     MEDIA_LOGD("Init");
85     muxBin_ = GST_ELEMENT(gst_object_ref_sink(gst_element_factory_make("muxbin", "avmuxerbin")));
86     CHECK_AND_RETURN_RET_LOG(muxBin_ != nullptr, MSERR_UNKNOWN, "Failed to create muxbin");
87 
88     int32_t ret = SetupMsgProcessor();
89     CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "Failed to setup message processor");
90 
91     allocator_ = gst_shmem_wrap_allocator_new();
92     CHECK_AND_RETURN_RET_LOG(allocator_ != nullptr, MSERR_NO_MEMORY, "Failed to create allocator");
93 
94     return MSERR_OK;
95 }
96 
GetAVMuxerFormatList()97 std::vector<std::string> AVMuxerEngineGstImpl::GetAVMuxerFormatList()
98 {
99     MEDIA_LOGD("GetAVMuxerFormatList");
100     CHECK_AND_RETURN_RET_LOG(muxBin_ != nullptr, std::vector<std::string>(), "Muxbin does not exist");
101 
102     return AVMuxerUtil::FindFormat();
103 }
104 
SetOutput(int32_t fd,const std::string & format)105 int32_t AVMuxerEngineGstImpl::SetOutput(int32_t fd, const std::string &format)
106 {
107     MEDIA_LOGD("SetOutput");
108     CHECK_AND_RETURN_RET_LOG(muxBin_ != nullptr, MSERR_INVALID_OPERATION, "Muxbin does not exist");
109 
110     std::string mux;
111     CHECK_AND_RETURN_RET_LOG(AVMuxerUtil::FindMux(format, mux), MSERR_INVALID_VAL, "Illegal format");
112     g_object_set(muxBin_, "fd", fd, "mux", mux.c_str(), nullptr);
113     format_ = format;
114 
115     return MSERR_OK;
116 }
117 
SetLocation(float latitude,float longitude)118 int32_t AVMuxerEngineGstImpl::SetLocation(float latitude, float longitude)
119 {
120     MEDIA_LOGD("SetLocation");
121     CHECK_AND_RETURN_RET_LOG(muxBin_ != nullptr, MSERR_INVALID_OPERATION, "Muxbin does not exist");
122 
123     bool setLocationToMux = true;
124     if (latitude < MIN_LATITUDE || latitude > MAX_LATITUDE || longitude < MIN_LONGITUDE
125         || longitude > MAX_LONGITUDE) {
126         setLocationToMux = false;
127         MEDIA_LOGW("Invalid GeoLocation, latitude must be greater than %{public}d and less than %{public}d,"
128             "longitude must be greater than %{public}d and less than %{public}d",
129             MIN_LATITUDE, MAX_LATITUDE, MIN_LONGITUDE, MAX_LONGITUDE);
130     }
131 
132     if (setLocationToMux) {
133         int32_t latitudex10000 = latitude * MULTIPLY10000;
134         int32_t longitudex10000 = longitude * MULTIPLY10000;
135         g_object_set(muxBin_, "latitude", latitudex10000, "longitude", longitudex10000, nullptr);
136     }
137 
138     return MSERR_OK;
139 }
140 
SetRotation(int32_t rotation)141 int32_t AVMuxerEngineGstImpl::SetRotation(int32_t rotation)
142 {
143     MEDIA_LOGD("SetRotation");
144     CHECK_AND_RETURN_RET_LOG(muxBin_ != nullptr, MSERR_INVALID_OPERATION, "Muxbin does not exist");
145 
146     bool setRotationToMux = true;
147     if (rotation != VIDEO_ROTATION_90 && rotation != VIDEO_ROTATION_180 && rotation != VIDEO_ROTATION_270) {
148         setRotationToMux = false;
149         MEDIA_LOGW("Invalid rotation: %{public}d, keep default 0", rotation);
150     }
151 
152     if (setRotationToMux) {
153         g_object_set(muxBin_, "rotation", rotation, nullptr);
154     }
155 
156     return MSERR_OK;
157 }
158 
AddTrack(const MediaDescription & trackDesc,int32_t & trackId)159 int32_t AVMuxerEngineGstImpl::AddTrack(const MediaDescription &trackDesc, int32_t &trackId)
160 {
161     MEDIA_LOGD("AddTrack");
162     CHECK_AND_RETURN_RET_LOG(muxBin_ != nullptr, MSERR_INVALID_OPERATION, "Muxbin does not exist");
163 
164     std::string mimeType;
165     bool val = trackDesc.GetStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, mimeType);
166     CHECK_AND_RETURN_RET_LOG(val, MSERR_INVALID_VAL, "Failed to get MD_KEY_CODEC_MIME");
167     std::set<std::string> mimeTypes;
168     CHECK_AND_RETURN_RET_LOG(AVMuxerUtil::FindMimeTypes(format_, mimeTypes), MSERR_INVALID_VAL, "Illegal format");
169     CHECK_AND_RETURN_RET_LOG(mimeTypes.find(mimeType) != mimeTypes.end(),
170         MSERR_INVALID_OPERATION, "The mime type can not be added in current container format");
171 
172     trackId = trackInfo_.size() + 1;
173     trackInfo_[trackId] = TrackInfo();
174     trackInfo_[trackId].mimeType_ = mimeType;
175 
176     GstCaps *srcCaps = nullptr;
177     uint32_t *trackNum = nullptr;
178     MediaType mediaType;
179     CHECK_AND_RETURN_RET_LOG(AVMuxerUtil::FindMediaType(mimeType, mediaType), MSERR_INVALID_VAL, "Illegal mimeType");
180     if (mediaType == MEDIA_TYPE_VID) {
181         CHECK_AND_RETURN_RET_LOG(videoTrackNum_ < MAX_VIDEO_TRACK_NUM, MSERR_INVALID_OPERATION,
182             "Only 1 video Track can be added");
183         trackNum = &videoTrackNum_;
184     } else if (mediaType == MEDIA_TYPE_AUD) {
185         CHECK_AND_RETURN_RET_LOG(audioTrackNum_ < MAX_AUDIO_TRACK_NUM, MSERR_INVALID_OPERATION,
186             "Only 16 audio Tracks can be added");
187         trackNum = &audioTrackNum_;
188     } else {
189         MEDIA_LOGE("Failed to check track type");
190         return MSERR_INVALID_VAL;
191     }
192 
193     if (!AVMuxerUtil::SetCaps(trackDesc, mimeType, &srcCaps)) {
194         MEDIA_LOGE("Failed to call SetCaps");
195         trackInfo_.erase(trackId);
196         return MSERR_INVALID_VAL;
197     }
198 
199     trackInfo_[trackId].caps_ = srcCaps;
200 
201     gst_caps_ref(trackInfo_[trackId].caps_);
202     MEDIA_LOGD("caps ref: %{public}d", GST_MINI_OBJECT(trackInfo_[trackId].caps_)->refcount);
203     std::string name = "src_";
204     name += static_cast<char>('0' + trackId);
205     std::string parse;
206     if (!AVMuxerUtil::FindParse(mimeType, parse)) {
207         MEDIA_LOGE("Failed to call FindParse");
208         trackInfo_.erase(trackId);
209         return MSERR_INVALID_VAL;
210     }
211     g_signal_emit_by_name(muxBin_, "add-track", name.c_str(),
212         (parse + std::to_string(trackId)).c_str(), static_cast<int32_t>(mediaType));
213     (*trackNum)++;
214 
215     return MSERR_OK;
216 }
217 
Start()218 int32_t AVMuxerEngineGstImpl::Start()
219 {
220     MEDIA_LOGD("Start");
221     std::unique_lock<std::mutex> lock(mutex_);
222     CHECK_AND_RETURN_RET_LOG(muxBin_ != nullptr, MSERR_INVALID_OPERATION, "Muxbin does not exist");
223     gst_element_set_state(GST_ELEMENT_CAST(muxBin_), GST_STATE_PLAYING);
224 
225     for (auto& info : trackInfo_) {
226         std::string name = "src_";
227         name += static_cast<char>('0' + info.first);
228         GstElement *src = gst_bin_get_by_name(GST_BIN_CAST(muxBin_), name.c_str());
229         CHECK_AND_RETURN_RET_LOG(src != nullptr, MSERR_INVALID_OPERATION, "src does not exist");
230         g_signal_connect(src, "need-data", G_CALLBACK(StartFeed), reinterpret_cast<gpointer *>(&trackInfo_));
231         g_signal_connect(src, "enough-data", G_CALLBACK(StopFeed), reinterpret_cast<gpointer *>(&trackInfo_));
232         info.second.src_ = src;
233     }
234 
235     return MSERR_OK;
236 }
237 
WriteData(std::shared_ptr<AVSharedMemory> sampleData,const TrackSampleInfo & sampleInfo,GstElement * src)238 int32_t AVMuxerEngineGstImpl::WriteData(std::shared_ptr<AVSharedMemory> sampleData,
239     const TrackSampleInfo &sampleInfo, GstElement *src)
240 {
241     CHECK_AND_RETURN_RET_LOG(sampleData != nullptr, MSERR_INVALID_VAL, "sampleData is nullptr");
242     CHECK_AND_RETURN_RET_LOG(src != nullptr, MSERR_INVALID_VAL, "src is nullptr");
243     CHECK_AND_RETURN_RET_LOG(allocator_ != nullptr, MSERR_INVALID_VAL, "allocator is nullptr");
244 
245     GstMemory *mem = gst_shmem_wrap(GST_ALLOCATOR_CAST(allocator_), sampleData);
246     CHECK_AND_RETURN_RET_LOG(mem != nullptr, MSERR_NO_MEMORY, "Failed to call gst_shmem_wrap");
247 
248     GstBuffer *buffer = gst_buffer_new();
249     if (buffer == nullptr) {
250         gst_memory_unref(mem);
251         MEDIA_LOGE("Failed to call gst_buffer_new");
252         return MSERR_NO_MEMORY;
253     }
254 
255     gst_buffer_append_memory(buffer, mem);
256     GST_BUFFER_DTS(buffer) = static_cast<uint64_t>(sampleInfo.timeUs * US_TO_NS);
257     GST_BUFFER_PTS(buffer) = static_cast<uint64_t>(sampleInfo.timeUs * US_TO_NS);
258 
259     GstFlowReturn ret;
260     g_signal_emit_by_name(src, "push-buffer", buffer, &ret);
261     if (ret != GST_FLOW_OK) {
262         gst_buffer_unref(buffer);
263         MEDIA_LOGE("Failed to call g_signal_emit_by_name");
264         return MSERR_INVALID_OPERATION;
265     }
266     gst_buffer_unref(buffer);
267 
268     return MSERR_OK;
269 }
270 
WriteTrackSample(std::shared_ptr<AVSharedMemory> sampleData,const TrackSampleInfo & sampleInfo)271 int32_t AVMuxerEngineGstImpl::WriteTrackSample(std::shared_ptr<AVSharedMemory> sampleData,
272     const TrackSampleInfo &sampleInfo)
273 {
274     MEDIA_LOGD("WriteTrackSample, sampleInfo.trackIdx is %{public}d", sampleInfo.trackIdx);
275     std::unique_lock<std::mutex> lock(mutex_);
276     CHECK_AND_RETURN_RET_LOG(errHappened_ != true, MSERR_INVALID_OPERATION, "Error happend");
277     CHECK_AND_RETURN_RET_LOG(muxBin_ != nullptr, MSERR_INVALID_OPERATION, "Muxbin does not exist");
278     CHECK_AND_RETURN_RET_LOG(sampleData != nullptr, MSERR_INVALID_VAL, "sampleData is nullptr");
279     CHECK_AND_RETURN_RET_LOG(trackInfo_[sampleInfo.trackIdx].needData_ == true, MSERR_INVALID_OPERATION,
280         "Failed to push data, the queue is full");
281     CHECK_AND_RETURN_RET_LOG(sampleInfo.timeUs >= 0, MSERR_INVALID_VAL, "Failed to check dts, dts muxt >= 0");
282 
283     int32_t ret;
284     GstElement *src = trackInfo_[sampleInfo.trackIdx].src_;
285     CHECK_AND_RETURN_RET_LOG(src != nullptr, MSERR_INVALID_VAL, "Failed to get AppSrc");
286 
287     if ((sampleInfo.flags & AVCODEC_BUFFER_FLAG_CODEC_DATA) &&
288         trackInfo_[sampleInfo.trackIdx].hasCodecData_ != true) {
289         CHECK_AND_RETURN_RET_LOG(trackInfo_[sampleInfo.trackIdx].caps_ != nullptr,
290             MSERR_INVALID_OPERATION, "Failed to check caps");
291         g_object_set(src, "caps", trackInfo_[sampleInfo.trackIdx].caps_, nullptr);
292         ret = WriteData(sampleData, sampleInfo, src);
293         CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "Failed to call WriteData");
294         trackInfo_[sampleInfo.trackIdx].hasCodecData_ = true;
295     } else if (!(sampleInfo.flags & AVCODEC_BUFFER_FLAG_CODEC_DATA & AVCODEC_BUFFER_FLAG_EOS) &&
296         trackInfo_[sampleInfo.trackIdx].hasCodecData_ == true) {
297         ret = WriteData(sampleData, sampleInfo, src);
298         CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "Failed to call WriteData");
299     } else {
300         MEDIA_LOGW("Failed to Write sample, note: first frame must be code_data");
301     }
302 
303     return MSERR_OK;
304 }
305 
Stop()306 int32_t AVMuxerEngineGstImpl::Stop()
307 {
308     MEDIA_LOGD("Stop");
309     std::unique_lock<std::mutex> lock(mutex_);
310     CHECK_AND_RETURN_RET_LOG(muxBin_ != nullptr, MSERR_INVALID_OPERATION, "Muxbin does not exist");
311 
312     GstFlowReturn ret;
313     if (isPlay_) {
314         for (auto& info : trackInfo_) {
315             g_signal_emit_by_name(info.second.src_, "end-of-stream", &ret);
316             CHECK_AND_RETURN_RET_LOG(ret == GST_FLOW_OK, ret, "Failed to push end of stream");
317         }
318         cond_.wait(lock, [this]() {
319             return endFlag_ || errHappened_;
320         });
321     }
322     gst_element_set_state(GST_ELEMENT_CAST(muxBin_), GST_STATE_NULL);
323     Clear();
324     return MSERR_OK;
325 }
326 
SetupMsgProcessor()327 int32_t AVMuxerEngineGstImpl::SetupMsgProcessor()
328 {
329     CHECK_AND_RETURN_RET_LOG(muxBin_ != nullptr, MSERR_INVALID_OPERATION, "Muxbin does not exist");
330     GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE_CAST(muxBin_));
331     CHECK_AND_RETURN_RET_LOG(bus != nullptr, MSERR_INVALID_OPERATION, "Failed to create GstBus");
332 
333     auto msgNotifier = std::bind(&AVMuxerEngineGstImpl::OnNotifyMessage, this, std::placeholders::_1);
334     msgProcessor_ = std::make_unique<GstMsgProcessor>(*bus, msgNotifier);
335     gst_object_unref(bus);
336     bus = nullptr;
337 
338     int32_t ret = msgProcessor_->Init();
339     CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);
340 
341     msgProcessor_->AddMsgFilter(ELEM_NAME(GST_ELEMENT_CAST(muxBin_)));
342 
343     return MSERR_OK;
344 }
345 
OnNotifyMessage(const InnerMessage & msg)346 void AVMuxerEngineGstImpl::OnNotifyMessage(const InnerMessage &msg)
347 {
348     switch (msg.type) {
349         case InnerMsgType::INNER_MSG_EOS: {
350             std::unique_lock<std::mutex> lock(mutex_);
351             MEDIA_LOGD("End of stream");
352             endFlag_ = true;
353             cond_.notify_all();
354             break;
355         }
356         case InnerMsgType::INNER_MSG_ERROR: {
357             std::unique_lock<std::mutex> lock(mutex_);
358             MEDIA_LOGE("Error happened");
359             msgProcessor_->FlushBegin();
360             msgProcessor_->Reset();
361             errHappened_ = true;
362             cond_.notify_all();
363             break;
364         }
365         case InnerMsgType::INNER_MSG_STATE_CHANGED: {
366             std::unique_lock<std::mutex> lock(mutex_);
367             MEDIA_LOGD("State change");
368             GstState currState = static_cast<GstState>(msg.detail2);
369             if (currState == GST_STATE_PLAYING) {
370                 isPlay_ = true;
371             }
372             cond_.notify_all();
373             break;
374         }
375         default:
376             break;
377     }
378 }
379 
Clear()380 void AVMuxerEngineGstImpl::Clear()
381 {
382     for (auto iter = trackInfo_.begin(); iter != trackInfo_.end(); iter++) {
383         gst_caps_unref(iter->second.caps_);
384     }
385     trackInfo_.clear();
386     endFlag_ = false;
387     errHappened_ = false;
388     isPlay_ = false;
389 
390     mutex_.unlock();
391     msgProcessor_->Reset();
392     mutex_.lock();
393 }
394 }  // namespace Media
395 }  // namespace OHOS
396