1 /*
2 * Copyright (c) 2021-2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #define HST_LOG_TAG "FileFdSourcePlugin"
17
18 #include "file_fd_source_plugin.h"
19 #include <cerrno>
20 #include <cstring>
21 #include <regex>
22 #ifdef WIN32
23 #include <fcntl.h>
24 #else
25 #include <sys/types.h>
26 #include <unistd.h>
27 #endif
28 #include <sys/stat.h>
29 #include "foundation/log.h"
30 #include "foundation/osal/filesystem/file_system.h"
31
32 namespace OHOS {
33 namespace Media {
34 namespace Plugin {
35 namespace FileFdSource {
36 namespace {
GetFileSize(int32_t fd)37 uint64_t GetFileSize(int32_t fd)
38 {
39 uint64_t fileSize = 0;
40 struct stat s {};
41 if (fstat(fd, &s) == 0) {
42 fileSize = static_cast<uint64_t>(s.st_size);
43 return fileSize;
44 }
45 return fileSize;
46 }
47 }
FileFdSourceRegister(const std::shared_ptr<Register> & reg)48 Status FileFdSourceRegister(const std::shared_ptr<Register>& reg)
49 {
50 SourcePluginDef definition;
51 definition.name = "FileFdSource";
52 definition.description = "File Fd source";
53 definition.rank = 100; // 100: max rank
54 definition.protocol.emplace_back(ProtocolType::FD);
55 definition.creator = [](const std::string& name) -> std::shared_ptr<SourcePlugin> {
56 return std::make_shared<FileFdSourcePlugin>(name);
57 };
58 return reg->AddPlugin(definition);
59 }
60
__anondfd822370302null61 PLUGIN_DEFINITION(FileFdSource, LicenseType::APACHE_V2, FileFdSourceRegister, [] {});
62
FileFdSourcePlugin(std::string name)63 FileFdSourcePlugin::FileFdSourcePlugin(std::string name)
64 : SourcePlugin(std::move(name))
65 {
66 }
67
SetCallback(Callback * cb)68 Status FileFdSourcePlugin::SetCallback(Callback* cb)
69 {
70 MEDIA_LOG_D("IN");
71 return Status::ERROR_UNIMPLEMENTED;
72 }
73
SetSource(std::shared_ptr<MediaSource> source)74 Status FileFdSourcePlugin::SetSource(std::shared_ptr<MediaSource> source)
75 {
76 MEDIA_LOG_D("IN");
77 auto err = ParseUriInfo(source->GetSourceUri());
78 if (err != Status::OK) {
79 MEDIA_LOG_E("Parse file name from uri fail, uri: " PUBLIC_LOG "s", source->GetSourceUri().c_str());
80 return err;
81 }
82 return err;
83 }
84
Read(std::shared_ptr<Buffer> & buffer,size_t expectedLen)85 Status FileFdSourcePlugin::Read(std::shared_ptr<Buffer>& buffer, size_t expectedLen)
86 {
87 if (!buffer) {
88 buffer = std::make_shared<Buffer>();
89 }
90 std::shared_ptr<Memory> bufData;
91 if (buffer->IsEmpty()) {
92 bufData = buffer->AllocMemory(GetAllocator(), expectedLen);
93 } else {
94 bufData = buffer->GetMemory();
95 }
96 expectedLen = std::min(static_cast<size_t>(fileSize_ - position_), expectedLen);
97 expectedLen = std::min(bufData->GetCapacity(), expectedLen);
98 MEDIA_LOG_DD("buffer position " PUBLIC_LOG_U64 ", expectedLen " PUBLIC_LOG_ZU, position_, expectedLen);
99 auto size = read(fd_, bufData->GetWritableAddr(expectedLen), expectedLen);
100 bufData->UpdateDataSize(size);
101 position_ += bufData->GetSize();
102 MEDIA_LOG_DD("position_: " PUBLIC_LOG_U64 ", readSize: " PUBLIC_LOG_ZU, position_, bufData->GetSize());
103 return Status::OK;
104 }
105
GetSize(size_t & size)106 Status FileFdSourcePlugin::GetSize(size_t& size)
107 {
108 MEDIA_LOG_DD("IN");
109 size = fileSize_;
110 MEDIA_LOG_DD("fileSize_: " PUBLIC_LOG_ZU, size);
111 return Status::OK;
112 }
113
GetSeekable()114 Seekable FileFdSourcePlugin::GetSeekable()
115 {
116 MEDIA_LOG_DD("IN");
117 return seekable_;
118 }
119
SeekTo(uint64_t offset)120 Status FileFdSourcePlugin::SeekTo(uint64_t offset)
121 {
122 FALSE_RETURN_V_MSG_E(fd_ != -1 && seekable_ == Seekable::SEEKABLE,
123 Status::ERROR_WRONG_STATE, "no valid fd or no seekable.");
124 int32_t ret = lseek(fd_, offset, SEEK_SET);
125 if (ret == -1) {
126 MEDIA_LOG_E("seek to " PUBLIC_LOG_U64 " failed due to " PUBLIC_LOG_S, offset, strerror(errno));
127 return Status::ERROR_UNKNOWN;
128 }
129 position_ = offset;
130 MEDIA_LOG_D("now seek to " PUBLIC_LOG_D32, ret);
131 return Status::OK;
132 }
133
134 // uri format:fd://xxxx?offset=xxxx&size=xxx or fd://xxxx
ParseUriInfo(const std::string & uri)135 Status FileFdSourcePlugin::ParseUriInfo(const std::string& uri)
136 {
137 if (uri.empty()) {
138 MEDIA_LOG_E("uri is empty");
139 return Status::ERROR_INVALID_PARAMETER;
140 }
141 MEDIA_LOG_D("uri: " PUBLIC_LOG_S, uri.c_str());
142 std::smatch fdUriMatch;
143 FALSE_RETURN_V_MSG_E(std::regex_match(uri, fdUriMatch, std::regex("^fd://(.*)?offset=(.*)&size=(.*)")) ||
144 std::regex_match(uri, fdUriMatch, std::regex("^fd://(.*)")),
145 Status::ERROR_INVALID_PARAMETER, "Invalid fd uri format: " PUBLIC_LOG_S, uri.c_str());
146 fd_ = std::stoi(fdUriMatch[1].str()); // 1: sub match fd subscript
147 FALSE_RETURN_V_MSG_E(fd_ != -1 && OSAL::FileSystem::IsRegularFile(fd_),
148 Status::ERROR_INVALID_PARAMETER, "Invalid fd: " PUBLIC_LOG_D32, fd_);
149 fileSize_ = GetFileSize(fd_);
150 if (fdUriMatch.size() == 4) { // 4:4 sub match
151 offset_ = std::stoll(fdUriMatch[2].str()); // 2: sub match offset subscript
152 if (offset_ > fileSize_) {
153 offset_ = fileSize_;
154 }
155 size_ = std::stoll(fdUriMatch[3].str()); // 3: sub match size subscript
156 if ((offset_ + size_) > fileSize_) {
157 size_ = fileSize_ - offset_;
158 }
159 } else {
160 size_ = fileSize_;
161 }
162 position_ = offset_;
163 seekable_ = OSAL::FileSystem::IsSeekable(fd_) ? Seekable::SEEKABLE : Seekable::UNSEEKABLE;
164 if (seekable_ == Seekable::SEEKABLE) {
165 NOK_LOG(SeekTo(offset_));
166 }
167 MEDIA_LOG_D("fd: " PUBLIC_LOG_D32 ", offset: " PUBLIC_LOG_D64 ", size: " PUBLIC_LOG_D64, fd_, offset_, size_);
168 return Status::OK;
169 }
170 } // namespace FileFdSource
171 } // namespace Plugin
172 } // namespace Media
173 } // namespace OHOS
174
175