• 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 #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