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