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_util.h"
17 #include <tuple>
18 #include "media_errors.h"
19 #include "media_log.h"
20
21 namespace {
22 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVMuxerUtil"};
23 }
24
25 namespace OHOS {
26 namespace Media {
27 struct MultiValue {
MultiValueOHOS::Media::MultiValue28 explicit MultiValue(int32_t val)
29 {
30 val_.intVal = val;
31 }
MultiValueOHOS::Media::MultiValue32 explicit MultiValue(const char *val)
33 {
34 val_.stringVal = val;
35 }
36 union Val {
37 int32_t intVal;
38 const char *stringVal;
39 } val_ = {0};
40 };
41
42 struct FormatInfo {
43 std::string mux_;
44 std::set<std::string> mimeTypes_;
45 };
46
47 struct MimeInfo {
48 std::string innerType_;
49 std::string parse_;
50 MediaType mediaType_;
51 };
52
53 struct CapsInfo {
54 std::string key_;
55 GType type_;
56 MultiValue value_;
57 };
58
59 const std::map<std::string, FormatInfo> FORMAT_INFO = {
60 {"mp4", {"mp4mux", {"video/avc", "video/mp4v-es", "video/h263", "audio/mp4a-latm", "audio/mpeg"}}},
61 {"m4a", {"mp4mux", {"audio/mp4a-latm"}}},
62 };
63
64 const std::map<const std::string, MimeInfo> MIME_INFO = {
65 {"video/avc", {"video/x-h264", "h264parse", MEDIA_TYPE_VID}},
66 {"video/h263", {"video/x-h263", "", MEDIA_TYPE_VID}},
67 {"video/mp4v-es", {"video/mpeg", "mpeg4videoparse", MEDIA_TYPE_VID}},
68 {"audio/mp4a-latm", {"audio/mpeg", "aacparse", MEDIA_TYPE_AUD}},
69 {"audio/mpeg", {"audio/mpeg", "", MEDIA_TYPE_AUD}}
70 };
71
72 std::map<std::string, std::vector<CapsInfo>> optionCapsMap = {
73 {"video/avc", {
74 {"alignment", G_TYPE_STRING, MultiValue("nal")},
75 {"stream-format", G_TYPE_STRING, MultiValue("byte-stream")}
76 }},
77 {"video/h263", {
78 }},
79 {"video/mp4v-es", {
80 {"mpegversion", G_TYPE_INT, MultiValue(4)},
81 {"systemstream", G_TYPE_BOOLEAN, MultiValue(FALSE)}
82 }},
83 {"audio/mp4a-latm", {
84 {"mpegversion", G_TYPE_INT, MultiValue(4)},
85 {"stream-format", G_TYPE_STRING, MultiValue("adts")}
86 }},
87 {"audio/mpeg", {
88 {"mpegversion", G_TYPE_INT, MultiValue(1)},
89 {"layer", G_TYPE_INT, MultiValue(3)}
90 }}
91 };
92
parseParam(FormatParam & param,const MediaDescription & trackDesc,const std::string & mimeType)93 static int32_t parseParam(FormatParam ¶m, const MediaDescription &trackDesc, const std::string &mimeType)
94 {
95 MediaType mediaType;
96 CHECK_AND_RETURN_RET_LOG(AVMuxerUtil::FindMediaType(mimeType, mediaType), MSERR_INVALID_VAL, "Illegal mimeType");
97 if (mediaType == MEDIA_TYPE_VID) {
98 CHECK_AND_RETURN_RET_LOG(trackDesc.GetIntValue(MediaDescriptionKey::MD_KEY_WIDTH, param.width),
99 MSERR_INVALID_VAL, "Failed to get MD_KEY_WIDTH");
100 CHECK_AND_RETURN_RET_LOG(trackDesc.GetIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, param.height),
101 MSERR_INVALID_VAL, "Failed to get MD_KEY_HEIGHT");
102 CHECK_AND_RETURN_RET_LOG(trackDesc.GetIntValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, param.frameRate),
103 MSERR_INVALID_VAL, "Failed to get MD_KEY_FRAME_RATE");
104 MEDIA_LOGD("width is: %{public}d, height is: %{public}d, frameRate is: %{public}d",
105 param.width, param.height, param.frameRate);
106 } else if (mediaType == MEDIA_TYPE_AUD) {
107 CHECK_AND_RETURN_RET_LOG(
108 trackDesc.GetIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, param.channels),
109 MSERR_INVALID_VAL, "Failed to get MD_KEY_CHANNEL_COUNT");
110 CHECK_AND_RETURN_RET_LOG(trackDesc.GetIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, param.rate),
111 MSERR_INVALID_VAL, "Failed to get MD_KEY_SAMPLE_RATE");
112 MEDIA_LOGD("channels is: %{public}d, rate is: %{public}d", param.channels, param.rate);
113 } else {
114 MEDIA_LOGD("Faild to check track type");
115 return MSERR_INVALID_VAL;
116 }
117
118 return MSERR_OK;
119 }
120
AddOptionCaps(GstCaps * src_caps,const std::string & mimeType)121 static void AddOptionCaps(GstCaps *src_caps, const std::string &mimeType)
122 {
123 for (auto& elements : optionCapsMap[mimeType]) {
124 switch (elements.type_) {
125 case G_TYPE_BOOLEAN:
126 case G_TYPE_INT:
127 gst_caps_set_simple(src_caps,
128 elements.key_.c_str(),
129 elements.type_,
130 elements.value_.val_.intVal,
131 nullptr);
132 break;
133 case G_TYPE_STRING:
134 gst_caps_set_simple(src_caps,
135 elements.key_.c_str(),
136 elements.type_,
137 elements.value_.val_.stringVal,
138 nullptr);
139 break;
140 default:
141 break;
142 }
143 }
144 }
145
CreateCaps(FormatParam & param,const std::string & mimeType)146 static GstCaps *CreateCaps(FormatParam ¶m, const std::string &mimeType)
147 {
148 GstCaps *src_caps = nullptr;
149 std::string innerType;
150 MediaType mediaType;
151 CHECK_AND_RETURN_RET_LOG(AVMuxerUtil::FindInnerTypes(mimeType, innerType), nullptr, "Illegal mimeType");
152 CHECK_AND_RETURN_RET_LOG(AVMuxerUtil::FindMediaType(mimeType, mediaType), nullptr, "Illegal mimeType");
153 if (mediaType == MEDIA_TYPE_VID) {
154 src_caps = gst_caps_new_simple(innerType.c_str(),
155 "width", G_TYPE_INT, param.width,
156 "height", G_TYPE_INT, param.height,
157 "framerate", GST_TYPE_FRACTION, param.frameRate, 1,
158 nullptr);
159 } else if (mediaType == MEDIA_TYPE_AUD) {
160 src_caps = gst_caps_new_simple(innerType.c_str(),
161 "channels", G_TYPE_INT, param.channels,
162 "rate", G_TYPE_INT, param.rate,
163 nullptr);
164 } else {
165 MEDIA_LOGE("Failed to check track type");
166 return nullptr;
167 }
168 AddOptionCaps(src_caps, mimeType);
169
170 return src_caps;
171 }
172
SetCaps(const MediaDescription & trackDesc,const std::string & mimeType,GstCaps ** src_caps)173 bool AVMuxerUtil::SetCaps(const MediaDescription &trackDesc, const std::string &mimeType,
174 GstCaps **src_caps)
175 {
176 MEDIA_LOGD("Set %{public}s caps", mimeType.c_str());
177 CHECK_AND_RETURN_RET_LOG(src_caps != nullptr, false, "src_caps is nullptr");
178 FormatParam param;
179 bool ret = parseParam(param, trackDesc, mimeType);
180 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, false, "Failed to call parseParam");
181 *src_caps = CreateCaps(param, mimeType);
182
183 return true;
184 }
185
FindFormat()186 std::vector<std::string> AVMuxerUtil::FindFormat()
187 {
188 std::vector<std::string> formatList;
189 for (auto& formats : FORMAT_INFO) {
190 formatList.push_back(formats.first);
191 }
192 return formatList;
193 }
194
FindMux(const std::string & format,std::string & mux)195 bool AVMuxerUtil::FindMux(const std::string &format, std::string &mux)
196 {
197 if (FORMAT_INFO.find(format) == FORMAT_INFO.end()) {
198 return false;
199 }
200 mux = FORMAT_INFO.at(format).mux_;
201 return true;
202 }
203
FindMimeTypes(const std::string & format,std::set<std::string> & mimeTypes)204 bool AVMuxerUtil::FindMimeTypes(const std::string &format, std::set<std::string> &mimeTypes)
205 {
206 if (FORMAT_INFO.find(format) == FORMAT_INFO.end()) {
207 return false;
208 }
209 mimeTypes = FORMAT_INFO.at(format).mimeTypes_;
210 return true;
211 }
212
FindInnerTypes(const std::string & mimeType,std::string & innerType)213 bool AVMuxerUtil::FindInnerTypes(const std::string &mimeType, std::string &innerType)
214 {
215 if (MIME_INFO.find(mimeType) == MIME_INFO.end()) {
216 return false;
217 }
218 innerType = MIME_INFO.at(mimeType).innerType_;
219 return true;
220 }
221
FindParse(const std::string & mimeType,std::string & parse)222 bool AVMuxerUtil::FindParse(const std::string &mimeType, std::string &parse)
223 {
224 if (MIME_INFO.find(mimeType) == MIME_INFO.end()) {
225 return false;
226 }
227 parse = MIME_INFO.at(mimeType).parse_;
228 return true;
229 }
230
FindMediaType(const std::string & mimeType,MediaType & mediaType)231 bool AVMuxerUtil::FindMediaType(const std::string &mimeType, MediaType &mediaType)
232 {
233 if (MIME_INFO.find(mimeType) == MIME_INFO.end()) {
234 return false;
235 }
236 mediaType = MIME_INFO.at(mimeType).mediaType_;
237 return true;
238 }
239 }
240 }