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 #include "source.h"
16 #include <iostream>
17 #include <dlfcn.h>
18 #include <memory>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #include <malloc.h>
22 #include "avcodec_errors.h"
23 #include "avcodec_dfx.h"
24 #include "media_description.h"
25 #include "avcodec_log.h"
26 #include "avcodec_info.h"
27 #include "avcodec_common.h"
28 #include "media_description.h"
29 #include "media_source.h"
30 #include "ffmpeg_converter.h"
31 #include "format.h"
32
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 #include "libavutil/avstring.h"
37 #ifdef __cplusplus
38 }
39 #endif
40
41 static std::string g_libFileHead = "libhistreamer_plugin_";
42 static std::string g_fileSeparator = "/";
43 static std::string g_libFileTail = ".z.so";
44
45 namespace OHOS {
46 namespace MediaAVCodec {
47 namespace Plugin {
48 namespace {
49 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "Source"};
50
FileIsExists(const char * name)51 inline bool FileIsExists(const char* name)
52 {
53 struct stat buffer;
54 return (stat(name, &buffer) == 0);
55 }
56
57 static std::map<std::string, std::string> g_pluginMap = {
58 {"http", "libhistreamer_plugin_HttpSource.z.so"},
59 {"https", "libhistreamer_plugin_HttpSource.z.so"},
60 {"fd", "libhistreamer_plugin_FileFdSource.z.so"}
61 };
62
63 static std::map<AVCodecID, std::string_view> g_codecIdToMime = {
64 {AV_CODEC_ID_MP3, CodecMimeType::AUDIO_MPEG},
65 {AV_CODEC_ID_FLAC, CodecMimeType::AUDIO_FLAC},
66 {AV_CODEC_ID_AAC, CodecMimeType::AUDIO_AAC},
67 {AV_CODEC_ID_VORBIS, CodecMimeType::AUDIO_VORBIS},
68 {AV_CODEC_ID_OPUS, CodecMimeType::AUDIO_OPUS},
69 {AV_CODEC_ID_AMR_NB, CodecMimeType::AUDIO_AMR_NB},
70 {AV_CODEC_ID_AMR_WB, CodecMimeType::AUDIO_AMR_WB},
71 {AV_CODEC_ID_H264, CodecMimeType::VIDEO_AVC},
72 {AV_CODEC_ID_MPEG4, CodecMimeType::VIDEO_MPEG4},
73 {AV_CODEC_ID_MJPEG, CodecMimeType::IMAGE_JPG},
74 {AV_CODEC_ID_PNG, CodecMimeType::IMAGE_PNG},
75 {AV_CODEC_ID_BMP, CodecMimeType::IMAGE_BMP},
76 {AV_CODEC_ID_H263, CodecMimeType::VIDEO_H263},
77 {AV_CODEC_ID_MPEG2TS, CodecMimeType::VIDEO_MPEG2},
78 {AV_CODEC_ID_MPEG2VIDEO, CodecMimeType::VIDEO_MPEG2},
79 {AV_CODEC_ID_HEVC, CodecMimeType::VIDEO_HEVC},
80 {AV_CODEC_ID_VP8, CodecMimeType::VIDEO_VP8},
81 {AV_CODEC_ID_VP9, CodecMimeType::VIDEO_VP9},
82 };
83
84 static std::map<AVMediaType, int32_t> g_convertFfmpegType = {
85 {AVMEDIA_TYPE_VIDEO, MEDIA_TYPE_VID},
86 {AVMEDIA_TYPE_AUDIO, MEDIA_TYPE_AUD},
87 {AVMEDIA_TYPE_SUBTITLE, MEDIA_TYPE_SUBTITLE},
88 };
89
90 std::map<std::string, std::shared_ptr<AVInputFormat>> g_pluginInputFormat;
91
ParseProtocol(const std::string & uri,std::string & protocol)92 int32_t ParseProtocol(const std::string& uri, std::string& protocol)
93 {
94 AVCODEC_LOGD("ParseProtocol, input: uri=%{private}s, protocol=%{public}s", uri.c_str(), protocol.c_str());
95 int32_t ret;
96 auto const pos = uri.find("://");
97 if (pos != std::string::npos) {
98 auto prefix = uri.substr(0, pos);
99 protocol.append(prefix);
100 ret = AVCS_ERR_OK;
101 }
102
103 if (protocol.empty()) {
104 AVCODEC_LOGE("ERROR:Invalid protocol: %{public}s", protocol.c_str());
105 ret = AVCS_ERR_INVALID_OPERATION;
106 }
107 return ret;
108 }
109
OpenFilePlugin(const std::string & path,const std::string & name,void ** handler)110 RegisterFunc OpenFilePlugin(const std::string& path, const std::string& name, void** handler)
111 {
112 AVCODEC_LOGD("OpenFilePlugin, input: path=%{private}s, name=%{private}s", path.c_str(), name.c_str());
113 if (FileIsExists(path.c_str())) {
114 *handler = ::dlopen(path.c_str(), RTLD_NOW);
115 if (*handler == nullptr) {
116 AVCODEC_LOGE("dlopen failed due to %{private}s", ::dlerror());
117 }
118 }
119 if (*handler) {
120 std::string registerFuncName = "register_" + name;
121 RegisterFunc registerFunc = nullptr;
122 registerFunc = (RegisterFunc)(::dlsym(*handler, registerFuncName.c_str()));
123 if (registerFunc) {
124 return registerFunc;
125 } else {
126 AVCODEC_LOGE("register is not found in %{public}s", registerFuncName.c_str());
127 }
128 } else {
129 AVCODEC_LOGE("dlopen failed: %{private}s", path.c_str());
130 }
131 return {};
132 }
133
StartWith(const char * name,const char * chars)134 bool StartWith(const char* name, const char* chars)
135 {
136 return !strncmp(name, chars, strlen(chars));
137 }
138
IsInputFormatSupported(const char * name)139 bool IsInputFormatSupported(const char* name)
140 {
141 if (!strcmp(name, "audio_device") || StartWith(name, "image") ||
142 !strcmp(name, "mjpeg") || !strcmp(name, "redir") || StartWith(name, "u8") ||
143 StartWith(name, "u16") || StartWith(name, "u24") ||
144 StartWith(name, "u32") ||
145 StartWith(name, "s8") || StartWith(name, "s16") ||
146 StartWith(name, "s24") ||
147 StartWith(name, "s32") || StartWith(name, "f32") ||
148 StartWith(name, "f64") ||
149 !strcmp(name, "mulaw") || !strcmp(name, "alaw")) {
150 return false;
151 }
152 if (!strcmp(name, "sdp") || !strcmp(name, "rtsp") || !strcmp(name, "applehttp")) {
153 return false;
154 }
155 return true;
156 }
157
IsPCM(AVCodecID codecID)158 bool IsPCM(AVCodecID codecID)
159 {
160 return StartWith(avcodec_get_name(codecID), "pcm_");
161 }
162
ReplaceDelimiter(const std::string & delmiters,char newDelimiter,std::string & str)163 void ReplaceDelimiter(const std::string& delmiters, char newDelimiter, std::string& str)
164 {
165 for (auto it = str.begin(); it != str.end(); ++it) {
166 if (delmiters.find(newDelimiter) != std::string::npos) {
167 *it = newDelimiter;
168 }
169 }
170 };
171 }
172
AddPlugin(const PluginDefBase & def)173 Status SourceRegister::AddPlugin(const PluginDefBase& def)
174 {
175 auto& tmpDef = (SourcePluginDef&) def;
176 sourcePlugin = (tmpDef.creator)(tmpDef.name);
177 return Status::OK;
178 }
179
AddPackage(const PackageDef & def)180 Status SourceRegister::AddPackage(const PackageDef& def)
181 {
182 packageDef = std::make_shared<PackageDef>(def);
183 return Status::OK;
184 }
185 constexpr size_t DEFAULT_READ_SIZE = 4096;
186
Source()187 Source::Source()
188 :formatContext_(nullptr), inputFormat_(nullptr)
189 {
190 AVCODEC_LOGI("Source::Source is on call");
191 av_log_set_level(AV_LOG_ERROR);
192 (void)mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_DISABLE);
193 (void)mallopt(M_DELAYED_FREE, M_DELAYED_FREE_DISABLE);
194 }
195
~Source()196 Source::~Source()
197 {
198 (void)mallopt(M_FLUSH_THREAD_CACHE, 0);
199 formatContext_ = nullptr;
200 inputFormat_ = nullptr;
201 if (sourcePlugin_ != nullptr) {
202 sourcePlugin_->Stop();
203 sourcePlugin_ = nullptr;
204 }
205 register_ = nullptr;
206 avioContext_ = nullptr;
207 handler_ = nullptr;
208 AVCODEC_LOGI("Source::~Source is on call");
209 }
210
GetTrackCount(uint32_t & trackCount)211 int32_t Source::GetTrackCount(uint32_t &trackCount)
212 {
213 CHECK_AND_RETURN_RET_LOG(formatContext_ != nullptr, AVCS_ERR_INVALID_OPERATION,
214 "call GetTrackCount failed, because create source failed!");
215 trackCount = static_cast<uint32_t>(formatContext_->nb_streams);
216 return AVCS_ERR_OK;
217 }
218
GetStringFormatFromMetadata(const std::string key,std::string_view formatName,Format & format)219 void Source::GetStringFormatFromMetadata(const std::string key, std::string_view formatName, Format &format)
220 {
221 AVDictionaryEntry *valPtr = nullptr;
222 valPtr = av_dict_get(formatContext_->metadata, key.c_str(), nullptr, AV_DICT_MATCH_CASE);
223 if (valPtr == nullptr) {
224 AVCODEC_LOGW("Put source info failed: miss %{public}s info in file", key.c_str());
225 } else {
226 bool ret = format.PutStringValue(formatName, valPtr->value);
227 if (!ret) {
228 AVCODEC_LOGW("Put source info failed: miss %{public}s info in file", key.c_str());
229 }
230 }
231 }
232
GetSourceFormat(Format & format)233 int32_t Source::GetSourceFormat(Format &format)
234 {
235 AVCODEC_LOGI("Source::GetSourceFormat is on call");
236 CHECK_AND_RETURN_RET_LOG(formatContext_ != nullptr, AVCS_ERR_INVALID_OPERATION, "formatContext_ is nullptr!");
237 Format::FormatDataMap formatMap = format.GetFormatMap();
238
239 GetStringFormatFromMetadata("title", AVSourceFormat::SOURCE_TITLE, format);
240 GetStringFormatFromMetadata("artist", AVSourceFormat::SOURCE_ARTIST, format);
241 GetStringFormatFromMetadata("album", AVSourceFormat::SOURCE_ALBUM, format);
242 GetStringFormatFromMetadata("album_artist", AVSourceFormat::SOURCE_ALBUM_ARTIST, format);
243 GetStringFormatFromMetadata("date", AVSourceFormat::SOURCE_DATE, format);
244 GetStringFormatFromMetadata("comment", AVSourceFormat::SOURCE_COMMENT, format);
245 GetStringFormatFromMetadata("genre", AVSourceFormat::SOURCE_GENRE, format);
246 GetStringFormatFromMetadata("copyright", AVSourceFormat::SOURCE_COPYRIGHT, format);
247 GetStringFormatFromMetadata("language", AVSourceFormat::SOURCE_LANGUAGE, format);
248 GetStringFormatFromMetadata("description", AVSourceFormat::SOURCE_DESCRIPTION, format);
249 GetStringFormatFromMetadata("lyrics", AVSourceFormat::SOURCE_LYRICS, format);
250
251 int64_t duration = formatContext_->duration;
252 AVRational timeBase = AV_TIME_BASE_Q;
253 if (duration == AV_NOPTS_VALUE) {
254 for (uint32_t i = 0; i < formatContext_->nb_streams; ++i) {
255 auto streamDuration = formatContext_->streams[i]->duration;
256 if (streamDuration > duration) {
257 duration = streamDuration;
258 timeBase = {formatContext_->streams[i]->time_base.num, formatContext_->streams[i]->time_base.den};
259 }
260 }
261 }
262 bool ret = format.PutLongValue(MediaDescriptionKey::MD_KEY_DURATION, duration);
263 if (!ret) {
264 AVCODEC_LOGW("Put source info failed: miss duration info in file");
265 }
266
267 ret = format.PutIntValue(
268 MediaDescriptionKey::MD_KEY_TRACK_COUNT, static_cast<uint32_t>(formatContext_->nb_streams));
269 if (!ret) {
270 AVCODEC_LOGW("Put source info failed: miss track count info in file");
271 }
272
273 AVCODEC_LOGD("Source::GetSourceFormat result: %{public}s", format.Stringify().c_str());
274 return AVCS_ERR_OK;
275 }
276
GetPublicTrackFormat(Format & format,AVStream * avStream)277 void Source::GetPublicTrackFormat(Format &format, AVStream *avStream)
278 {
279 int32_t media_type = -1;
280 if (g_convertFfmpegType.count(avStream->codecpar->codec_type) > 0) {
281 media_type = static_cast<int32_t>(g_convertFfmpegType[avStream->codecpar->codec_type]);
282 }
283 bool ret = format.PutIntValue(MediaDescriptionKey::MD_KEY_TRACK_TYPE, media_type);
284 if (!ret) {
285 AVCODEC_LOGW("Get track info failed: miss track type info in track %{public}d", avStream->index);
286 }
287 ret = format.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, avStream->codecpar->bit_rate);
288 if (!ret) {
289 AVCODEC_LOGW("Get track info failed: miss bitrate info in track %{public}d", avStream->index);
290 }
291 if (g_codecIdToMime.count(avStream->codecpar->codec_id) != 0) {
292 ret = format.PutStringValue(
293 MediaDescriptionKey::MD_KEY_CODEC_MIME, g_codecIdToMime[avStream->codecpar->codec_id]);
294 } else if (IsPCM(avStream->codecpar->codec_id)) {
295 ret = format.PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::AUDIO_RAW);
296 } else {
297 ret = false;
298 }
299 if (!ret) {
300 AVCODEC_LOGW("Get track info failed: miss mime type info in track %{public}d", avStream->index);
301 }
302 if (avStream->codecpar->extradata_size > 0 && avStream->codecpar->extradata != nullptr) {
303 ret = format.PutBuffer(MediaDescriptionKey::MD_KEY_CODEC_CONFIG, avStream->codecpar->extradata,
304 avStream->codecpar->extradata_size);
305 } else {
306 ret = false;
307 }
308 if (!ret) {
309 AVCODEC_LOGW("Get track info failed: miss extradata in track %{public}d", avStream->index);
310 }
311 }
312
GetVideoTrackFormat(Format & format,AVStream * avStream)313 void Source::GetVideoTrackFormat(Format &format, AVStream *avStream)
314 {
315 bool ret = format.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, avStream->codecpar->width);
316 if (!ret) {
317 AVCODEC_LOGW("Get track info failed: miss width info in track %{public}d", avStream->index);
318 }
319 ret = format.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, avStream->codecpar->height);
320 if (!ret) {
321 AVCODEC_LOGW("Get track info failed: miss height info in track %{public}d", avStream->index);
322 }
323 if (avStream->avg_frame_rate.den == 0 || avStream->avg_frame_rate.num == 0) {
324 ret = format.PutDoubleValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, av_q2d(avStream->r_frame_rate));
325 } else {
326 ret = format.PutDoubleValue(MediaDescriptionKey::MD_KEY_FRAME_RATE, av_q2d(avStream->avg_frame_rate));
327 }
328 if (!ret) {
329 AVCODEC_LOGW("Get track info failed: miss frame rate info in track %{public}d", avStream->index);
330 }
331 }
332
GetAudioTrackFormat(Format & format,AVStream * avStream)333 void Source::GetAudioTrackFormat(Format &format, AVStream *avStream)
334 {
335 bool ret = format.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, avStream->codecpar->sample_rate);
336 if (!ret) {
337 AVCODEC_LOGW("Get track info failed: miss sample rate info in track %{public}d", avStream->index);
338 }
339 if (!IsPCM(avStream->codecpar->codec_id)) {
340 auto sampleFormat = static_cast<AVSampleFormat>(avStream->codecpar->format);
341 ret = format.PutIntValue(MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT,
342 FFMpegConverter::ConvertFFMpegToOHAudioFormat(sampleFormat));
343 } else {
344 ret = format.PutIntValue(MediaDescriptionKey::MD_KEY_AUDIO_SAMPLE_FORMAT,
345 FFMpegConverter::ConvertFFMpegAVCodecIdToOHAudioFormat(avStream->codecpar->codec_id));
346 }
347 if (!ret) {
348 AVCODEC_LOGW("Get track info failed: miss sample format info in track %{public}d", avStream->index);
349 }
350 ret = format.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, avStream->codecpar->channels);
351 if (!ret) {
352 AVCODEC_LOGW("Get track info failed: miss channel count info in track %{public}d", avStream->index);
353 }
354 if (avStream->codecpar->codec_id == AV_CODEC_ID_AAC) {
355 ret = format.PutIntValue(MediaDescriptionKey::MD_KEY_AAC_IS_ADTS, 1);
356 if (!ret) {
357 AVCODEC_LOGW("Get track info failed: miss bitrate info in track %{public}d", avStream->index);
358 }
359 }
360 if (avStream->codecpar->codec_id == AV_CODEC_ID_AAC_LATM) {
361 ret = format.PutIntValue(MediaDescriptionKey::MD_KEY_AAC_IS_ADTS, 0);
362 if (!ret) {
363 AVCODEC_LOGW("Get track info failed: miss bitrate info in track %{public}d", avStream->index);
364 }
365 }
366 }
367
GetTrackFormat(Format & format,uint32_t trackIndex)368 int32_t Source::GetTrackFormat(Format &format, uint32_t trackIndex)
369 {
370 AVCODEC_LOGI("Source::GetTrackFormat is on call: trackIndex=%{public}u", trackIndex);
371 CHECK_AND_RETURN_RET_LOG(formatContext_ != nullptr, AVCS_ERR_INVALID_OPERATION,
372 "GetTrackFormat failed, formatContext_ is nullptr!");
373 if (trackIndex >= static_cast<uint32_t>(formatContext_->nb_streams)) {
374 AVCODEC_LOGE("trackIndex is invalid!");
375 return AVCS_ERR_INVALID_VAL;
376 }
377 auto avStream = formatContext_->streams[trackIndex];
378 GetPublicTrackFormat(format, avStream);
379 if (avStream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
380 GetVideoTrackFormat(format, avStream);
381 } else if (avStream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
382 GetAudioTrackFormat(format, avStream);
383 }
384
385 AVCODEC_LOGD("Source::GetTrackFormat result: %{public}s", format.Stringify().c_str());
386 return AVCS_ERR_OK;
387 }
388
Init(std::string & uri)389 int32_t Source::Init(std::string& uri)
390 {
391 AVCODEC_LOGI("Source::Init is called");
392 int32_t ret = LoadDynamicPlugin(uri);
393 CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED,
394 "init source failed when load source plugin!");
395 std::shared_ptr<MediaSource> mediaSource = std::make_shared<MediaSource>(uri);
396 AVCODEC_LOGD("mediaSource Init: %{private}s", mediaSource->GetSourceUri().c_str());
397 if (sourcePlugin_ == nullptr) {
398 AVCODEC_LOGE("load sourcePlugin_ fail !");
399 return AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED;
400 }
401 Status pluginRet = sourcePlugin_->SetSource(mediaSource);
402
403 CHECK_AND_RETURN_RET_LOG(pluginRet == Status::OK, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED,
404 "init source failed when set data source for plugin!");
405 ret = LoadInputFormatList();
406 CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED,
407 "init source failed when load demuxerlist!");
408 ret = SniffInputFormat(uri);
409 if (ret != AVCS_ERR_OK) {
410 FaultEventWrite(FaultType::FAULT_TYPE_INNER_ERROR, "Sniff failed", "Source");
411 }
412 CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED,
413 "init source failed when find input format!");
414 CHECK_AND_RETURN_RET_LOG(inputFormat_ != nullptr, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED,
415 "init source failed when find input format, cannnot match any input format!");
416 ret = InitAVFormatContext();
417 CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED,
418 "init source failed when parse source info!");
419 CHECK_AND_RETURN_RET_LOG(formatContext_ != nullptr, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED,
420 "init source failed when init AVFormatContext!");
421 return AVCS_ERR_OK;
422 }
423
424
LoadInputFormatList()425 int32_t Source::LoadInputFormatList()
426 {
427 const AVInputFormat* plugin = nullptr;
428 constexpr size_t strMax = 4;
429 void* i = nullptr;
430 while ((plugin = av_demuxer_iterate(&i))) {
431 if (plugin->long_name != nullptr) {
432 if (!strncmp(plugin->long_name, "pcm ", strMax)) {
433 continue;
434 }
435 }
436 if (!IsInputFormatSupported(plugin->name)) {
437 continue;
438 }
439 std::string pluginName = "avdemux_" + std::string(plugin->name);
440 ReplaceDelimiter(".,|-<> ", '_', pluginName);
441 g_pluginInputFormat[pluginName] =
442 std::shared_ptr<AVInputFormat>(const_cast<AVInputFormat*>(plugin), [](void*) {});
443 }
444 if (g_pluginInputFormat.empty()) {
445 AVCODEC_LOGW("cannot load any format demuxer");
446 return AVCS_ERR_INVALID_OPERATION;
447 }
448 return AVCS_ERR_OK;
449 }
450
451
LoadDynamicPlugin(const std::string & path)452 int32_t Source::LoadDynamicPlugin(const std::string& path)
453 {
454 AVCODEC_LOGI("LoadDynamicPlugin: %{private}s", path.c_str());
455 std::string protocol;
456 if (ParseProtocol(path, protocol) != AVCS_ERR_OK) {
457 AVCODEC_LOGE("Couldn't find valid protocol for %{private}s", path.c_str());
458 return AVCS_ERR_INVALID_OPERATION;
459 }
460 if (g_pluginMap.count(protocol) == 0) {
461 AVCODEC_LOGE("Unsupport protocol: %{public}s", protocol.c_str());
462 return AVCS_ERR_INVALID_OPERATION;
463 }
464 std::string libFileName = g_pluginMap[protocol];
465 std::string filePluginPath = OH_FILE_PLUGIN_PATH + g_fileSeparator + libFileName;
466 std::string pluginName =
467 libFileName.substr(g_libFileHead.size(), libFileName.size() - g_libFileHead.size() - g_libFileTail.size());
468 RegisterFunc registerFunc = OpenFilePlugin(filePluginPath, pluginName, &handler_);
469 if (registerFunc) {
470 register_ = std::make_shared<SourceRegister>();
471 registerFunc(register_);
472 sourcePlugin_ = register_->sourcePlugin;
473 AVCODEC_LOGD("regist source plugin successful");
474 return AVCS_ERR_OK;
475 } else {
476 AVCODEC_LOGD("regist source plugin failed, sourcePlugin path: %{private}s", filePluginPath.c_str());
477 return AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED;
478 }
479 }
480
SniffInputFormat(const std::string & uri)481 int32_t Source::SniffInputFormat(const std::string& uri)
482 {
483 size_t bufferSize = DEFAULT_READ_SIZE;
484 uint64_t fileSize = 0;
485 if (sourcePlugin_->GetSize(fileSize) == Status::OK) {
486 bufferSize = (static_cast<uint64_t>(bufferSize) < fileSize) ? bufferSize : fileSize;
487 }
488 std::vector<uint8_t> buff(bufferSize);
489 auto bufferInfo = std::make_shared<Buffer>();
490 auto bufferMemory = bufferInfo->WrapMemory(buff.data(), bufferSize, 0);
491 if (bufferMemory == nullptr) {
492 return AVCS_ERR_NO_MEMORY;
493 }
494 auto ret = static_cast<int>(sourcePlugin_->Read(bufferInfo, bufferSize));
495 CHECK_AND_RETURN_RET_LOG(ret == 0, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED,
496 "create source service failed when probe source format!");
497 CHECK_AND_RETURN_RET_LOG(buff.data() != nullptr, AVCS_ERR_INVALID_DATA,
498 "data cannot be read when probe source format!");
499 AVProbeData probeData = {"", buff.data(), static_cast<int>(bufferSize), ""};
500 constexpr int probThresh = 50;
501 int maxProb = 0;
502 std::map<std::string, std::shared_ptr<AVInputFormat>>::iterator iter;
503 for (iter = g_pluginInputFormat.begin(); iter != g_pluginInputFormat.end(); ++iter) {
504 std::shared_ptr<AVInputFormat> inputFormat = iter -> second;
505 if (inputFormat->read_probe) {
506 auto prob = inputFormat->read_probe(&probeData);
507 if (prob > probThresh) {
508 inputFormat_ = inputFormat;
509 break;
510 }
511 if (prob > maxProb) {
512 maxProb = prob;
513 inputFormat_ = inputFormat;
514 }
515 }
516 }
517 if (inputFormat_ == nullptr) {
518 AVCODEC_LOGE("sniff input format failed, can't find proper input format");
519 return AVCS_ERR_INVALID_OPERATION;
520 }
521 return AVCS_ERR_OK;
522 }
523
InitAVIOContext(int flags)524 void Source::InitAVIOContext(int flags)
525 {
526 constexpr int bufferSize = 4096;
527 customIOContext_.sourcePlugin = sourcePlugin_.get();
528 Status pluginRet = sourcePlugin_->GetSize(customIOContext_.fileSize);
529 if (pluginRet != Status::OK) {
530 AVCODEC_LOGE("get file size failed when set data source for plugin!");
531 return;
532 }
533 pluginRet = Status::ERROR_UNKNOWN;
534 while (pluginRet == Status::ERROR_UNKNOWN) {
535 pluginRet = sourcePlugin_->SeekTo(0);
536 if (static_cast<int32_t>(pluginRet) < 0 && pluginRet != Status::ERROR_UNKNOWN) {
537 AVCODEC_LOGE("Seek to 0 failed when set data source for plugin!");
538 return;
539 } else if (pluginRet == Status::ERROR_UNKNOWN) {
540 AVCODEC_LOGW("Seek to 0 failed when set data source for plugin, try again");
541 sleep(1);
542 }
543 }
544 customIOContext_.offset = 0;
545 customIOContext_.eof = false;
546 auto buffer = static_cast<unsigned char*>(av_malloc(bufferSize));
547 if (buffer == nullptr) {
548 AVCODEC_LOGE("AllocAVIOContext failed to av_malloc...");
549 return;
550 }
551 avioContext_ = avio_alloc_context(buffer, bufferSize, flags & AVIO_FLAG_WRITE,
552 (void*)(&customIOContext_), AVReadPacket, NULL, AVSeek);
553 customIOContext_.avioContext = avioContext_;
554 if (avioContext_ == nullptr) {
555 AVCODEC_LOGE("AllocAVIOContext failed to avio_alloc_context...");
556 av_free(buffer);
557 return;
558 }
559 Seekable seekable = sourcePlugin_->GetSeekable();
560 AVCODEC_LOGD("seekable_ is %{public}d", (int)seekable);
561 avioContext_->seekable = (seekable == Seekable::SEEKABLE) ? AVIO_SEEKABLE_NORMAL : 0;
562 if (!(static_cast<uint32_t>(flags) & static_cast<uint32_t>(AVIO_FLAG_WRITE))) {
563 avioContext_->buf_ptr = avioContext_->buf_end;
564 avioContext_->write_flag = 0;
565 }
566 }
567
AVSeek(void * opaque,int64_t offset,int whence)568 int64_t Source::AVSeek(void *opaque, int64_t offset, int whence)
569 {
570 auto customIOContext = static_cast<CustomIOContext*>(opaque);
571 uint64_t newPos = 0;
572 switch (whence) {
573 case SEEK_SET:
574 newPos = static_cast<uint64_t>(offset);
575 customIOContext->offset = newPos;
576 break;
577 case SEEK_CUR:
578 newPos = customIOContext->offset + offset;
579 break;
580 case SEEK_END:
581 case AVSEEK_SIZE: {
582 uint64_t mediaDataSize = 0;
583 customIOContext->sourcePlugin->GetSize(mediaDataSize);
584 if (mediaDataSize > 0) {
585 newPos = mediaDataSize + offset;
586 }
587 break;
588 }
589 default:
590 AVCODEC_LOGW("AVSeek unexpected whence: %{public}d", whence);
591 break;
592 }
593 if (whence != AVSEEK_SIZE) {
594 customIOContext->offset = newPos;
595 }
596 return newPos;
597 }
598
AVReadPacket(void * opaque,uint8_t * buf,int bufSize)599 int Source::AVReadPacket(void *opaque, uint8_t *buf, int bufSize)
600 {
601 int rtv = -1;
602 auto readSize = bufSize;
603 auto customIOContext = static_cast<CustomIOContext*>(opaque);
604 auto buffer = std::make_shared<Buffer>();
605 auto bufData = buffer->WrapMemory(buf, bufSize, 0);
606 if ((customIOContext->avioContext->seekable != static_cast<int>(Seekable::SEEKABLE)) ||
607 (customIOContext->fileSize == 0)) {
608 return rtv;
609 }
610
611 if (customIOContext->offset > customIOContext->fileSize) {
612 AVCODEC_LOGW("ERROR: offset: %{public}zu is larger than totalSize: %{public}" PRIu64,
613 customIOContext->offset, customIOContext->fileSize);
614 return AVCS_ERR_INVALID_OPERATION;
615 }
616 if (static_cast<size_t>(customIOContext->offset + bufSize) > customIOContext->fileSize) {
617 readSize = customIOContext->fileSize - customIOContext->offset;
618 }
619 if (customIOContext->position != customIOContext->offset) {
620 Status pluginRet = Status::ERROR_UNKNOWN;
621 while (pluginRet == Status::ERROR_UNKNOWN) {
622 pluginRet = customIOContext->sourcePlugin->SeekTo(customIOContext->offset);
623 if (static_cast<int32_t>(pluginRet) < 0 && pluginRet != Status::ERROR_UNKNOWN) {
624 AVCODEC_LOGE("Seek to %{public}zu failed when read AVPacket!", customIOContext->offset);
625 return AVCS_ERR_SEEK_FAILED;
626 } else if (pluginRet == Status::ERROR_UNKNOWN) {
627 AVCODEC_LOGW("Seek to %{public}zu failed when read AVPacket, try again", customIOContext->offset);
628 sleep(1);
629 }
630 }
631 customIOContext->position = customIOContext->offset;
632 }
633 int32_t result = static_cast<int32_t>(
634 customIOContext->sourcePlugin->Read(buffer, static_cast<size_t>(readSize)));
635 if (result == 0) {
636 rtv = buffer->GetMemory()->GetSize();
637 customIOContext->offset += rtv;
638 customIOContext->position += rtv;
639 } else if (static_cast<int>(result) == 1) {
640 customIOContext->eof = true;
641 rtv = AVERROR_EOF;
642 } else {
643 AVCODEC_LOGE("AVReadPacket failed with rtv = %{public}d", static_cast<int>(result));
644 }
645
646 return rtv;
647 }
648
InitAVFormatContext()649 int32_t Source::InitAVFormatContext()
650 {
651 AVFormatContext *formatContext = avformat_alloc_context();
652 if (formatContext == nullptr) {
653 AVCODEC_LOGE("InitAVFormatContext failed, because alloc AVFormatContext failed.");
654 return AVCS_ERR_INVALID_OPERATION;
655 }
656
657 InitAVIOContext(AVIO_FLAG_READ);
658 if (avioContext_ == nullptr) {
659 AVCODEC_LOGE("InitAVFormatContext failed, because init AVIOContext failed.");
660 return AVCS_ERR_INVALID_OPERATION;
661 }
662 formatContext->pb = avioContext_;
663 formatContext->flags |= AVFMT_FLAG_CUSTOM_IO;
664
665 int ret = avformat_open_input(&formatContext, nullptr, inputFormat_.get(), nullptr);
666 if (ret != 0) {
667 AVCODEC_LOGE("avformat_open_input failed by %{public}s, err:%{public}s", inputFormat_->name, av_err2str(ret));
668 return AVCS_ERR_INVALID_OPERATION;
669 }
670
671 ret = avformat_find_stream_info(formatContext, NULL);
672 if (ret < 0) {
673 AVCODEC_LOGE("avformat_find_stream_info failed by %{public}s, err:%{public}s",
674 inputFormat_->name, av_err2str(ret));
675 return AVCS_ERR_INVALID_OPERATION;
676 }
677
678 formatContext_ = std::shared_ptr<AVFormatContext>(formatContext, [](AVFormatContext* ptr) {
679 if (ptr != nullptr) {
680 auto p = ptr->pb;
681 avformat_close_input(&ptr);
682 if (p != nullptr) {
683 p->opaque = nullptr;
684 av_freep(&(p->buffer));
685 av_opt_free(p);
686 avio_context_free(&p);
687 p = nullptr;
688 }
689 }
690 });
691
692 return AVCS_ERR_OK;
693 }
694
GetSourceAddr()695 uintptr_t Source::GetSourceAddr()
696 {
697 CHECK_AND_RETURN_RET_LOG(formatContext_ != nullptr, AVCS_ERR_INVALID_OPERATION,
698 "GetSourceAddr failed, formatContext_ is nullptr!");
699 return (uintptr_t)(formatContext_.get());
700 }
701 } // namespace Plugin
702 } // namespace MediaAVCodec
703 } // namespace OHOS