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