• 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_trace.h"
24 #include "avcodec_sysevent.h"
25 #include "media_description.h"
26 #include "avcodec_log.h"
27 #include "avcodec_info.h"
28 #include "avcodec_common.h"
29 #include "media_description.h"
30 #include "media_source.h"
31 #include "ffmpeg_converter.h"
32 #include "ffmpeg_format_helper.h"
33 #include "meta/format.h"
34 
35 #ifdef __cplusplus
36 extern "C" {
37 #endif
38 #include "libavutil/avstring.h"
39 #ifdef __cplusplus
40 }
41 #endif
42 
43 static std::string g_libFileHead = "libhistreamer_plugin_";
44 static std::string g_fileSeparator = "/";
45 static std::string g_libFileTail = ".z.so";
46 
47 #define CUVA_VERSION_MAP (static_cast<uint16_t>(1))
48 #define TERMINAL_PROVIDE_CODE (static_cast<uint16_t>(4))
49 #define TERMINAL_PROVIDE_ORIENTED_CODE (static_cast<uint16_t>(5))
50 
51 namespace OHOS {
52 namespace MediaAVCodec {
53 namespace Plugin {
54 namespace {
55     constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "Source"};
56 
FileIsExists(const char * name)57     inline bool FileIsExists(const char* name)
58     {
59         struct stat buffer;
60         return (stat(name, &buffer) == 0);
61     }
62 
63     static std::map<std::string, std::string> g_pluginMap = {
64         {"http", "libhistreamer_plugin_HttpSource.z.so"},
65         {"https", "libhistreamer_plugin_HttpSource.z.so"},
66         {"fd", "libhistreamer_plugin_FileFdSource.z.so"}
67     };
68 
69     static std::vector<AVCodecID> g_imageCodecID = {
70         AV_CODEC_ID_MJPEG,
71         AV_CODEC_ID_PNG,
72         AV_CODEC_ID_PAM,
73         AV_CODEC_ID_BMP,
74         AV_CODEC_ID_JPEG2000,
75         AV_CODEC_ID_TARGA,
76         AV_CODEC_ID_TIFF,
77         AV_CODEC_ID_GIF,
78         AV_CODEC_ID_PCX,
79         AV_CODEC_ID_XWD,
80         AV_CODEC_ID_XBM,
81         AV_CODEC_ID_WEBP,
82         AV_CODEC_ID_APNG,
83         AV_CODEC_ID_XPM,
84         AV_CODEC_ID_SVG,
85     };
86 
ParseProtocol(const std::string & uri,std::string & protocol)87     int32_t ParseProtocol(const std::string& uri, std::string& protocol)
88     {
89         AVCODEC_LOGD("ParseProtocol, input: uri=%{private}s, protocol=%{public}s", uri.c_str(), protocol.c_str());
90         int32_t ret;
91         auto const pos = uri.find("://");
92         if (pos != std::string::npos) {
93             auto prefix = uri.substr(0, pos);
94             protocol.append(prefix);
95             ret = AVCS_ERR_OK;
96         }
97 
98         if (protocol.empty()) {
99             AVCODEC_LOGE("ERROR:Invalid protocol: %{public}s", protocol.c_str());
100             ret = AVCS_ERR_INVALID_OPERATION;
101         }
102         return ret;
103     }
104 
OpenFilePlugin(const std::string & path,const std::string & name,void ** handler)105     RegisterFunc OpenFilePlugin(const std::string& path, const std::string& name, void** handler)
106     {
107         AVCODEC_LOGD("OpenFilePlugin, input: path=%{private}s, name=%{private}s", path.c_str(), name.c_str());
108         if (FileIsExists(path.c_str())) {
109             *handler = ::dlopen(path.c_str(), RTLD_NOW);
110             if (*handler == nullptr) {
111                 AVCODEC_LOGE("dlopen failed due to %{private}s", ::dlerror());
112             }
113         }
114         if (*handler) {
115             std::string registerFuncName = "register_" + name;
116             RegisterFunc registerFunc = nullptr;
117             registerFunc = (RegisterFunc)(::dlsym(*handler, registerFuncName.c_str()));
118             if (registerFunc) {
119                 return registerFunc;
120             } else {
121                 AVCODEC_LOGE("register is not found in %{public}s", registerFuncName.c_str());
122             }
123         } else {
124             AVCODEC_LOGE("dlopen failed: %{private}s", path.c_str());
125         }
126         return {};
127     }
128 
StartWith(const char * name,const char * chars)129     bool StartWith(const char* name, const char* chars)
130     {
131         return !strncmp(name, chars, strlen(chars));
132     }
133 
IsInputFormatSupported(const char * name)134     bool IsInputFormatSupported(const char* name)
135     {
136         if (!strcmp(name, "audio_device") || StartWith(name, "image") ||
137             !strcmp(name, "mjpeg") || !strcmp(name, "redir") || StartWith(name, "u8") ||
138             StartWith(name, "u16") || StartWith(name, "u24") ||
139             StartWith(name, "u32") ||
140             StartWith(name, "s8") || StartWith(name, "s16") ||
141             StartWith(name, "s24") ||
142             StartWith(name, "s32") || StartWith(name, "f32") ||
143             StartWith(name, "f64") ||
144             !strcmp(name, "mulaw") || !strcmp(name, "alaw")) {
145             return false;
146         }
147         if (!strcmp(name, "sdp") || !strcmp(name, "rtsp") || !strcmp(name, "applehttp")) {
148             return false;
149         }
150         return true;
151     }
152 }
153 
AddPlugin(const PluginDefBase & def)154 Status SourceRegister::AddPlugin(const PluginDefBase& def)
155 {
156     auto& tmpDef = (SourcePluginDef&) def;
157     sourcePlugin = (tmpDef.creator)(tmpDef.name);
158     return Status::OK;
159 }
160 
AddPackage(const PackageDef & def)161 Status SourceRegister::AddPackage(const PackageDef& def)
162 {
163     packageDef = std::make_shared<PackageDef>(def);
164     return Status::OK;
165 }
166 constexpr size_t DEFAULT_READ_SIZE = 4096;
167 
Source()168 Source::Source()
169     :formatContext_(nullptr), inputFormat_(nullptr)
170 {
171     AVCODEC_LOGI("Source::Source is on call");
172     av_log_set_level(AV_LOG_ERROR);
173     (void)mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_DISABLE);
174     (void)mallopt(M_DELAYED_FREE, M_DELAYED_FREE_DISABLE);
175     hevcParser_ = HevcParserManager::Create();
176 }
177 
~Source()178 Source::~Source()
179 {
180     (void)mallopt(M_FLUSH_THREAD_CACHE, 0);
181     formatContext_ = nullptr;
182     inputFormat_ = nullptr;
183     if (sourcePlugin_ != nullptr) {
184         sourcePlugin_->Stop();
185         sourcePlugin_ = nullptr;
186     }
187     register_ = nullptr;
188     avioContext_ = nullptr;
189     handler_ = nullptr;
190     hevcParser_ = nullptr;
191     if (firstFrame_ != nullptr) {
192         av_packet_free(&firstFrame_);
193         av_free(firstFrame_);
194         firstFrame_ = nullptr;
195     }
196     AVCODEC_LOGI("Source::~Source is on call");
197 }
198 
GetTrackCount(uint32_t & trackCount)199 int32_t Source::GetTrackCount(uint32_t &trackCount)
200 {
201     CHECK_AND_RETURN_RET_LOG(formatContext_ != nullptr, AVCS_ERR_INVALID_OPERATION,
202         "call GetTrackCount failed, because create source failed!");
203     trackCount = static_cast<uint32_t>(formatContext_->nb_streams);
204     return AVCS_ERR_OK;
205 }
206 
GetSourceFormat(Format & format)207 int32_t Source::GetSourceFormat(Format &format)
208 {
209     AVCODEC_LOGI("Source::GetSourceFormat is on call");
210     CHECK_AND_RETURN_RET_LOG(formatContext_ != nullptr, AVCS_ERR_INVALID_OPERATION, "formatContext_ is nullptr!");
211 
212     FFmpegFormatHelper::ParseMediaInfo(*formatContext_, format);
213     AVCODEC_LOGI("Source::GetSourceFormat result: %{public}s", format.Stringify().c_str());
214     return AVCS_ERR_OK;
215 }
216 
GetTrackFormat(Format & format,uint32_t trackIndex)217 int32_t Source::GetTrackFormat(Format &format, uint32_t trackIndex)
218 {
219     AVCODEC_LOGI("Source::GetTrackFormat is on call: trackIndex=%{public}u", trackIndex);
220     CHECK_AND_RETURN_RET_LOG(formatContext_ != nullptr, AVCS_ERR_INVALID_OPERATION, "formatContext_ is nullptr!");
221     CHECK_AND_RETURN_RET_LOG(trackIndex < static_cast<uint32_t>(formatContext_->nb_streams),
222                              AVCS_ERR_INVALID_VAL, "trackIndex is invalid!");
223 
224     auto avStream = formatContext_->streams[trackIndex];
225     CHECK_AND_RETURN_RET_LOG(avStream != nullptr, AVCS_ERR_INVALID_OPERATION, "stream is nullptr!");
226 
227     FFmpegFormatHelper::ParseTrackInfo(*avStream, format);
228     if (avStream->codecpar->codec_id == AV_CODEC_ID_HEVC) {
229         if (hevcParser_ != nullptr && firstFrame_ != nullptr) {
230             hevcParser_->ConvertExtraDataToAnnexb(avStream->codecpar->extradata, avStream->codecpar->extradata_size);
231             hevcParser_->ConvertPacketToAnnexb(&(firstFrame_->data), firstFrame_->size);
232             hevcParser_->ParseAnnexbExtraData(firstFrame_->data, firstFrame_->size);
233             ParseHEVCMetadataInfo(*avStream, format);
234         } else {
235             AVCODEC_LOGW("hevcParser_ is nullptr, parser hevc fail");
236         }
237     }
238     AVCODEC_LOGD("Source::GetTrackFormat result: %{public}s", format.Stringify().c_str());
239     return AVCS_ERR_OK;
240 }
241 
IsAVTrack(const AVStream & avStream)242 bool Source::IsAVTrack(const AVStream& avStream)
243 {
244     if (avStream.codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
245         return true;
246     } else if (avStream.codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
247         if ((avStream.disposition & AV_DISPOSITION_ATTACHED_PIC) ||
248             (std::count(g_imageCodecID.begin(), g_imageCodecID.end(), avStream.codecpar->codec_id) > 0)) {
249                 return false;
250         }
251         return true;
252     }
253     return false;
254 }
255 
GetVideoFirstKeyFrame()256 void Source::GetVideoFirstKeyFrame()
257 {
258     if (formatContext_ == nullptr) {
259         return;
260     }
261     int64_t startPts = 0;
262     int startTrackIndex = -1;
263     for (uint32_t trackIndex = 0; trackIndex < formatContext_->nb_streams; ++trackIndex) {
264         auto avStream = formatContext_->streams[trackIndex];
265         if (avStream->codecpar->codec_id != AV_CODEC_ID_HEVC || firstFrame_ != nullptr) {
266             continue;
267         }
268         hasHevc_ = true;
269         firstFrame_ = av_packet_alloc();
270         if (firstFrame_ == nullptr) {
271             return;
272         }
273         while (av_read_frame(formatContext_.get(), firstFrame_) >= 0) {
274             auto tempStream = formatContext_->streams[firstFrame_->stream_index];
275             if (startTrackIndex < 0 && IsAVTrack(*tempStream)) {
276                 startPts = firstFrame_->pts;
277                 startTrackIndex = firstFrame_->stream_index;
278             }
279 
280             if (static_cast<uint32_t>(firstFrame_->stream_index) == trackIndex) {
281                 break;
282             }
283             av_packet_unref(firstFrame_);
284         }
285 
286         startPts = (startPts > 0) ? 0 : startPts;
287         auto rtv = av_seek_frame(formatContext_.get(), startTrackIndex, startPts, AVSEEK_FLAG_BACKWARD);
288         if (rtv < 0) {
289             AVCODEC_LOGW("seek failed, return value: ffmpeg error:%{public}d", rtv);
290             firstFrame_ = nullptr;
291         }
292     }
293 }
294 
ParseHEVCMetadataInfo(const AVStream & avStream,Format & format)295 void Source::ParseHEVCMetadataInfo(const AVStream& avStream, Format &format)
296 {
297     HevcParseFormat parse;
298     parse.isHdrVivid = hevcParser_->IsHdrVivid();
299     parse.colorRange = hevcParser_->GetColorRange();
300     parse.colorPrimaries = hevcParser_->GetColorPrimaries();
301     parse.colorTransfer = hevcParser_->GetColorTransfer();
302     parse.colorMatrixCoeff = hevcParser_->GetColorMatrixCoeff();
303     parse.profile = hevcParser_->GetProfileIdc();
304     parse.level = hevcParser_->GetLevelIdc();
305     parse.chromaLocation = hevcParser_->GetChromaLocation();
306     parse.picWidInLumaSamples = hevcParser_->GetPicWidInLumaSamples();
307     parse.picHetInLumaSamples = hevcParser_->GetPicHetInLumaSamples();
308 
309     FFmpegFormatHelper::ParseHevcInfo(*formatContext_, parse, format);
310     if (parse.isHdrVivid) {
311         ParseHDRVividCUVVInfo(format);
312     }
313 }
314 
ParseHDRVividCUVVInfo(Format & format)315 void Source::ParseHDRVividCUVVInfo(Format &format)
316 {
317     CUVVConfigBox cuvvBox = {CUVA_VERSION_MAP, TERMINAL_PROVIDE_CODE, TERMINAL_PROVIDE_ORIENTED_CODE};
318     bool ret = format.PutBuffer(MediaDescriptionKey::MD_KEY_VIDEO_CUVV_CONFIG_BOX,
319         reinterpret_cast<uint8_t*>(&cuvvBox), sizeof(cuvvBox));
320     if (!ret) {
321         AVCODEC_LOGW("Put hdr vivid cuvv info failed");
322     }
323 }
324 
Init(std::string & uri)325 int32_t Source::Init(std::string& uri)
326 {
327     AVCODEC_LOGI("Source::Init is called");
328     int32_t ret = LoadDynamicPlugin(uri);
329     CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED,
330                              "init source failed when load source plugin!");
331     std::shared_ptr<MediaSource> mediaSource = std::make_shared<MediaSource>(uri);
332     AVCODEC_LOGD("mediaSource Init: %{private}s", mediaSource->GetSourceUri().c_str());
333     if (sourcePlugin_ == nullptr) {
334         AVCODEC_LOGE("load sourcePlugin_ fail !");
335         return AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED;
336     }
337     Status pluginRet = sourcePlugin_->SetSource(mediaSource);
338 
339     CHECK_AND_RETURN_RET_LOG(pluginRet == Status::OK, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED,
340                              "init source failed when set data source for plugin!");
341     ret = SniffInputFormat();
342     if (ret != AVCS_ERR_OK) {
343         FaultEventWrite(FaultType::FAULT_TYPE_INNER_ERROR, "Sniff failed", "Source");
344     }
345     CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED,
346                              "init source failed when find input format!");
347     CHECK_AND_RETURN_RET_LOG(inputFormat_ != nullptr, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED,
348                              "init source failed when find input format, cannnot match any input format!");
349     ret = InitAVFormatContext();
350     CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED,
351                              "init source failed when parse source info!");
352     CHECK_AND_RETURN_RET_LOG(formatContext_ != nullptr, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED,
353                              "init source failed when init AVFormatContext!");
354     return AVCS_ERR_OK;
355 }
356 
LoadDynamicPlugin(const std::string & path)357 int32_t Source::LoadDynamicPlugin(const std::string& path)
358 {
359     AVCODEC_LOGI("LoadDynamicPlugin: %{private}s", path.c_str());
360     std::string protocol;
361     if (ParseProtocol(path, protocol) != AVCS_ERR_OK) {
362         AVCODEC_LOGE("Couldn't find valid protocol for %{private}s", path.c_str());
363         return AVCS_ERR_INVALID_OPERATION;
364     }
365     if (g_pluginMap.count(protocol) == 0) {
366         AVCODEC_LOGE("Unsupport protocol: %{public}s", protocol.c_str());
367         return AVCS_ERR_INVALID_OPERATION;
368     }
369     std::string libFileName = g_pluginMap[protocol];
370     std::string filePluginPath = OH_FILE_PLUGIN_PATH + g_fileSeparator + libFileName;
371     std::string pluginName =
372         libFileName.substr(g_libFileHead.size(), libFileName.size() - g_libFileHead.size() - g_libFileTail.size());
373     RegisterFunc registerFunc = OpenFilePlugin(filePluginPath, pluginName, &handler_);
374     if (registerFunc) {
375         register_ = std::make_shared<SourceRegister>();
376         registerFunc(register_);
377         sourcePlugin_ = register_->sourcePlugin;
378         AVCODEC_LOGD("regist source plugin successful");
379         return AVCS_ERR_OK;
380     } else {
381         AVCODEC_LOGD("regist source plugin failed, sourcePlugin path: %{private}s", filePluginPath.c_str());
382         return AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED;
383     }
384 }
385 
SniffInputFormat()386 int32_t Source::SniffInputFormat()
387 {
388     size_t bufferSize = DEFAULT_READ_SIZE;
389     uint64_t fileSize = 0;
390     constexpr int probThresh = 50;
391     constexpr size_t strMax = 4;
392     int maxProb = 0;
393     void* i = nullptr;
394     if (sourcePlugin_->GetSize(fileSize) == Status::OK) {
395         bufferSize = (static_cast<uint64_t>(bufferSize) < fileSize) ? bufferSize : fileSize;
396     }
397     // fix ffmpeg probe crash,refer to ffmpeg/tools/probetest.c
398     std::vector<uint8_t> buff(bufferSize + AVPROBE_PADDING_SIZE);
399     auto bufferInfo = std::make_shared<Buffer>();
400     auto bufferMemory = bufferInfo->WrapMemory(buff.data(), bufferSize, 0);
401     if (bufferMemory == nullptr) {
402         return AVCS_ERR_NO_MEMORY;
403     }
404     auto ret = static_cast<int>(sourcePlugin_->Read(bufferInfo, bufferSize));
405     CHECK_AND_RETURN_RET_LOG(ret == 0, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED,
406         "create source service failed when probe source format!");
407     CHECK_AND_RETURN_RET_LOG(buff.data() != nullptr, AVCS_ERR_INVALID_DATA,
408         "data cannot be read when probe source format!");
409     AVProbeData probeData = {"", buff.data(), static_cast<int>(bufferSize), ""};
410     const AVInputFormat* inputFormat = nullptr;
411     while ((inputFormat = av_demuxer_iterate(&i))) {
412         if (inputFormat->long_name != nullptr && !strncmp(inputFormat->long_name, "pcm ", strMax)) {
413             continue;
414         }
415         if (!IsInputFormatSupported(inputFormat->name)) {
416             continue;
417         }
418         if (inputFormat->read_probe) {
419             auto prob = inputFormat->read_probe(&probeData);
420             if (prob > probThresh) {
421                 inputFormat_ = std::shared_ptr<AVInputFormat>(const_cast<AVInputFormat*>(inputFormat), [](void*) {});
422                 break;
423             }
424             if (prob > maxProb) {
425                 maxProb = prob;
426                 inputFormat_ = std::shared_ptr<AVInputFormat>(const_cast<AVInputFormat*>(inputFormat), [](void*) {});
427             }
428         }
429     }
430     if (inputFormat_ == nullptr) {
431         AVCODEC_LOGE("sniff input format failed, can't find proper input format");
432         return AVCS_ERR_INVALID_OPERATION;
433     }
434     return AVCS_ERR_OK;
435 }
436 
InitAVIOContext(int flags)437 void Source::InitAVIOContext(int flags)
438 {
439     constexpr int bufferSize = 4096;
440     customIOContext_.sourcePlugin = sourcePlugin_.get();
441     Status pluginRet = sourcePlugin_->GetSize(customIOContext_.fileSize);
442     if (pluginRet != Status::OK) {
443         AVCODEC_LOGE("get file size failed when set data source for plugin!");
444         return;
445     }
446     pluginRet = Status::ERROR_UNKNOWN;
447     while (pluginRet == Status::ERROR_UNKNOWN) {
448         pluginRet = sourcePlugin_->SeekTo(0);
449         if (static_cast<int32_t>(pluginRet) < 0 && pluginRet != Status::ERROR_UNKNOWN) {
450             AVCODEC_LOGE("Seek to 0 failed when set data source for plugin!");
451             return;
452         } else if (pluginRet == Status::ERROR_UNKNOWN) {
453             AVCODEC_LOGW("Seek to 0 failed when set data source for plugin, try again");
454             sleep(1);
455         }
456     }
457     customIOContext_.offset = 0;
458     customIOContext_.eof = false;
459     auto buffer = static_cast<unsigned char*>(av_malloc(bufferSize));
460     if (buffer == nullptr) {
461         AVCODEC_LOGE("AllocAVIOContext failed to av_malloc...");
462         return;
463     }
464     avioContext_ = avio_alloc_context(buffer, bufferSize, flags & AVIO_FLAG_WRITE,
465                                     (void*)(&customIOContext_), AVReadPacket, NULL, AVSeek);
466     customIOContext_.avioContext = avioContext_;
467     if (avioContext_ == nullptr) {
468         AVCODEC_LOGE("AllocAVIOContext failed to avio_alloc_context...");
469         av_free(buffer);
470         return;
471     }
472     Seekable seekable = sourcePlugin_->GetSeekable();
473     AVCODEC_LOGD("seekable_ is %{public}d", (int)seekable);
474     avioContext_->seekable = (seekable == Seekable::SEEKABLE) ? AVIO_SEEKABLE_NORMAL : 0;
475     if (!(static_cast<uint32_t>(flags) & static_cast<uint32_t>(AVIO_FLAG_WRITE))) {
476         avioContext_->buf_ptr = avioContext_->buf_end;
477         avioContext_->write_flag = 0;
478     }
479 }
480 
AVSeek(void * opaque,int64_t offset,int whence)481 int64_t Source::AVSeek(void *opaque, int64_t offset, int whence)
482 {
483     auto customIOContext = static_cast<CustomIOContext*>(opaque);
484     uint64_t newPos = 0;
485     switch (whence) {
486         case SEEK_SET:
487             newPos = static_cast<uint64_t>(offset);
488             customIOContext->offset = newPos;
489             break;
490         case SEEK_CUR:
491             newPos = customIOContext->offset + offset;
492             break;
493         case SEEK_END:
494         case AVSEEK_SIZE: {
495             uint64_t mediaDataSize = 0;
496             customIOContext->sourcePlugin->GetSize(mediaDataSize);
497             if (mediaDataSize > 0) {
498                 newPos = mediaDataSize + offset;
499             }
500             break;
501         }
502         default:
503             AVCODEC_LOGW("AVSeek unexpected whence: %{public}d", whence);
504             break;
505     }
506     if (whence != AVSEEK_SIZE) {
507         customIOContext->offset = newPos;
508     }
509     return newPos;
510 }
511 
AVReadPacket(void * opaque,uint8_t * buf,int bufSize)512 int Source::AVReadPacket(void *opaque, uint8_t *buf, int bufSize)
513 {
514     int rtv = -1;
515     auto readSize = bufSize;
516     auto customIOContext = static_cast<CustomIOContext*>(opaque);
517     auto buffer = std::make_shared<Buffer>();
518     auto bufData = buffer->WrapMemory(buf, bufSize, 0);
519     if ((customIOContext->avioContext->seekable != static_cast<int>(Seekable::SEEKABLE)) ||
520         (customIOContext->fileSize == 0)) {
521         return rtv;
522     }
523 
524     if (customIOContext->offset > customIOContext->fileSize) {
525         AVCODEC_LOGW("ERROR: offset: %{public}zu is larger than totalSize: %{public}" PRIu64,
526                         customIOContext->offset, customIOContext->fileSize);
527         return rtv;
528     }
529     if (static_cast<size_t>(customIOContext->offset + bufSize) > customIOContext->fileSize) {
530         readSize = customIOContext->fileSize - customIOContext->offset;
531     }
532     if (customIOContext->position != customIOContext->offset) {
533         Status pluginRet = Status::ERROR_UNKNOWN;
534         while (pluginRet == Status::ERROR_UNKNOWN) {
535             pluginRet = customIOContext->sourcePlugin->SeekTo(customIOContext->offset);
536             if (static_cast<int32_t>(pluginRet) < 0 && pluginRet != Status::ERROR_UNKNOWN) {
537                 AVCODEC_LOGE("Seek to %{public}zu failed when read AVPacket!", customIOContext->offset);
538                 return rtv;
539             } else if (pluginRet == Status::ERROR_UNKNOWN) {
540                 AVCODEC_LOGW("Seek to %{public}zu failed when read AVPacket, try again", customIOContext->offset);
541                 sleep(1);
542             }
543         }
544         customIOContext->position = customIOContext->offset;
545     }
546     int32_t result = static_cast<int32_t>(
547                 customIOContext->sourcePlugin->Read(buffer, static_cast<size_t>(readSize)));
548     if (result == 0) {
549         rtv = buffer->GetMemory()->GetSize();
550         customIOContext->offset += rtv;
551         customIOContext->position += rtv;
552     } else if (static_cast<int>(result) == 1) {
553         customIOContext->eof = true;
554         rtv = AVERROR_EOF;
555     } else {
556         AVCODEC_LOGE("AVReadPacket failed with rtv = %{public}d", static_cast<int>(result));
557     }
558 
559     return rtv;
560 }
561 
InitAVFormatContext()562 int32_t Source::InitAVFormatContext()
563 {
564     AVFormatContext *formatContext = avformat_alloc_context();
565     if (formatContext == nullptr) {
566         AVCODEC_LOGE("InitAVFormatContext failed, because  alloc AVFormatContext failed.");
567         return AVCS_ERR_INVALID_OPERATION;
568     }
569     InitAVIOContext(AVIO_FLAG_READ);
570     if (avioContext_ == nullptr) {
571         AVCODEC_LOGE("InitAVFormatContext failed, because  init AVIOContext failed.");
572         return AVCS_ERR_INVALID_OPERATION;
573     }
574     formatContext->pb = avioContext_;
575     formatContext->flags |= AVFMT_FLAG_CUSTOM_IO;
576 
577     int ret = avformat_open_input(&formatContext, nullptr, inputFormat_.get(), nullptr);
578     if (ret != 0) {
579         AVCODEC_LOGE("avformat_open_input failed by %{public}s, err:%{public}s", inputFormat_->name,
580             FFMpegConverter::AVStrError(ret).c_str());
581         return AVCS_ERR_INVALID_OPERATION;
582     }
583 
584     ret = avformat_find_stream_info(formatContext, NULL);
585     if (ret < 0) {
586         AVCODEC_LOGE("avformat_find_stream_info failed by %{public}s, err:%{public}s",
587             inputFormat_->name, FFMpegConverter::AVStrError(ret).c_str());
588         return AVCS_ERR_INVALID_OPERATION;
589     }
590 
591     formatContext_ = std::shared_ptr<AVFormatContext>(formatContext, [](AVFormatContext* ptr) {
592         if (ptr != nullptr) {
593             auto p = ptr->pb;
594             avformat_close_input(&ptr);
595             if (p != nullptr) {
596                 p->opaque = nullptr;
597                 av_freep(&(p->buffer));
598                 av_opt_free(p);
599                 avio_context_free(&p);
600                 p = nullptr;
601             }
602         }
603     });
604 
605     GetVideoFirstKeyFrame(); // 如果是hevc,需要获取视频轨的第一帧关键帧获取sei里边的属性
606     if (hasHevc_) {
607         CHECK_AND_RETURN_RET_LOG(firstFrame_ != nullptr && firstFrame_->data != nullptr,
608             AVCS_ERR_INVALID_STATE, "Init AVFormatContext failed due to get sei info failed.");
609     }
610     return AVCS_ERR_OK;
611 }
612 
GetSourceAddr()613 uintptr_t Source::GetSourceAddr()
614 {
615     CHECK_AND_RETURN_RET_LOG(formatContext_ != nullptr, AVCS_ERR_INVALID_OPERATION,
616                              "GetSourceAddr failed, formatContext_ is nullptr!");
617     return (uintptr_t)(formatContext_.get());
618 }
619 } // namespace Plugin
620 } // namespace MediaAVCodec
621 } // namespace OHOS