• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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