7 #include "packager/media/file/file.h"
9 #include <gflags/gflags.h>
12 #include "packager/base/files/important_file_writer.h"
13 #include "packager/base/logging.h"
14 #include "packager/base/strings/string_piece.h"
15 #include "packager/media/file/local_file.h"
16 #include "packager/media/file/memory_file.h"
17 #include "packager/media/file/threaded_io_file.h"
18 #include "packager/media/file/udp_file.h"
20 DEFINE_uint64(io_cache_size,
22 "Size of the threaded I/O cache, in bytes. Specify 0 to disable "
24 DEFINE_uint64(io_block_size,
26 "Size of the block size used for threaded I/O, in bytes.");
36 const char* kLocalFilePrefix =
"file://";
37 const char* kUdpFilePrefix =
"udp://";
38 const char* kMemoryFilePrefix =
"memory://";
42 typedef File* (*FileFactoryFunction)(
const char* file_name,
const char* mode);
43 typedef bool (*FileDeleteFunction)(
const char* file_name);
44 typedef bool (*FileAtomicWriteFunction)(
const char* file_name,
45 const std::string& contents);
50 const FileFactoryFunction factory_function;
51 const FileDeleteFunction delete_function;
52 const FileAtomicWriteFunction atomic_write_function;
55 File* CreateLocalFile(
const char* file_name,
const char* mode) {
56 return new LocalFile(file_name, mode);
59 bool DeleteLocalFile(
const char* file_name) {
63 bool WriteLocalFileAtomically(
const char* file_name,
64 const std::string& contents) {
65 return base::ImportantFileWriter::WriteFileAtomically(
66 base::FilePath::FromUTF8Unsafe(file_name), contents);
69 File* CreateUdpFile(
const char* file_name,
const char* mode) {
70 if (strcmp(mode,
"r")) {
71 NOTIMPLEMENTED() <<
"UdpFile only supports read (receive) mode.";
74 return new UdpFile(file_name);
77 File* CreateMemoryFile(
const char* file_name,
const char* mode) {
78 return new MemoryFile(file_name, mode);
81 bool DeleteMemoryFile(
const char* file_name) {
86 static const FileTypeInfo kFileTypeInfo[] = {
89 strlen(kLocalFilePrefix),
92 &WriteLocalFileAtomically,
96 strlen(kUdpFilePrefix),
103 strlen(kMemoryFilePrefix),
110 const FileTypeInfo* GetFileTypeInfo(base::StringPiece file_name,
111 base::StringPiece* real_file_name) {
112 for (
const FileTypeInfo& file_type : kFileTypeInfo) {
113 if (strncmp(file_type.type, file_name.data(), file_type.type_length) == 0) {
114 *real_file_name = file_name.substr(file_type.type_length);
119 *real_file_name = file_name;
120 return &kFileTypeInfo[0];
125 File* File::Create(
const char* file_name,
const char* mode) {
126 std::unique_ptr<File, FileCloser> internal_file(
127 CreateInternalFile(file_name, mode));
129 if (!strncmp(file_name, kMemoryFilePrefix, strlen(kMemoryFilePrefix))) {
131 return internal_file.release();
134 if (FLAGS_io_cache_size) {
136 if (!strcmp(mode,
"r")) {
137 return new ThreadedIoFile(std::move(internal_file),
138 ThreadedIoFile::kInputMode, FLAGS_io_cache_size,
139 FLAGS_io_block_size);
140 }
else if (!strcmp(mode,
"w") || !strcmp(mode,
"a")) {
141 return new ThreadedIoFile(std::move(internal_file),
142 ThreadedIoFile::kOutputMode,
143 FLAGS_io_cache_size, FLAGS_io_block_size);
148 DLOG(WARNING) <<
"Threaded I/O is disabled. Performance may be decreased.";
149 return internal_file.release();
152 File* File::CreateInternalFile(
const char* file_name,
const char* mode) {
153 base::StringPiece real_file_name;
154 const FileTypeInfo* file_type = GetFileTypeInfo(file_name, &real_file_name);
156 return file_type->factory_function(real_file_name.data(), mode);
160 File* file = File::Create(file_name, mode);
171 File* file = File::CreateInternalFile(file_name, mode);
182 base::StringPiece real_file_name;
183 const FileTypeInfo* file_type = GetFileTypeInfo(file_name, &real_file_name);
185 return file_type->delete_function
186 ? file_type->delete_function(real_file_name.data())
194 int64_t res = file->
Size();
206 const size_t kBufferSize = 0x40000;
207 std::unique_ptr<char[]> buf(
new char[kBufferSize]);
210 while ((len = file->
Read(buf.get(), kBufferSize)) > 0)
211 contents->append(buf.get(), len);
218 base::StringPiece real_file_name;
219 const FileTypeInfo* file_type = GetFileTypeInfo(file_name, &real_file_name);
221 if (file_type->atomic_write_function)
222 return file_type->atomic_write_function(real_file_name.data(), contents);
228 if (strncmp(file_name, kMemoryFilePrefix, strlen(kMemoryFilePrefix)) != 0) {
229 LOG(WARNING) <<
"Writing to " << file_name
230 <<
" is not guaranteed to be atomic.";
235 LOG(ERROR) <<
"Failed to open file " <<
file_name;
238 int64_t bytes_written = file->Write(contents.data(), contents.size());
239 if (bytes_written < 0) {
240 LOG(ERROR) <<
"Failed to write to file '" << file_name <<
"' ("
241 << bytes_written <<
").";
244 if (static_cast<size_t>(bytes_written) != contents.size()) {
245 LOG(ERROR) <<
"Failed to write the whole file to " << file_name
246 <<
". Wrote " << bytes_written <<
" but expecting "
247 << contents.size() <<
" bytes.";
253 bool File::Copy(
const char* from_file_name,
const char* to_file_name) {
256 LOG(ERROR) <<
"Failed to open file " << from_file_name;
260 std::unique_ptr<File, FileCloser> output_file(
File::Open(to_file_name,
"w"));
262 LOG(ERROR) <<
"Failed to write to " << to_file_name;
266 uint64_t bytes_left = content.size();
267 uint64_t total_bytes_written = 0;
268 const char* content_cstr = content.c_str();
269 while (bytes_left > total_bytes_written) {
270 const int64_t bytes_written =
271 output_file->Write(content_cstr + total_bytes_written, bytes_left);
272 if (bytes_written < 0) {
273 LOG(ERROR) <<
"Failure while writing to " << to_file_name;
277 total_bytes_written += bytes_written;
283 return CopyFile(source, destination, kWholeFile);
290 max_copy = std::numeric_limits<int64_t>::max();
292 const int64_t kBufferSize = 0x40000;
293 std::unique_ptr<uint8_t[]> buffer(
new uint8_t[kBufferSize]);
294 int64_t bytes_copied = 0;
295 while (bytes_copied < max_copy) {
296 const int64_t size = std::min(kBufferSize, max_copy - bytes_copied);
297 const int64_t bytes_read = source->
Read(buffer.get(), size);
303 int64_t total_bytes_written = 0;
304 while (total_bytes_written < bytes_read) {
305 const int64_t bytes_written = destination->
Write(
306 buffer.get() + total_bytes_written, bytes_read - total_bytes_written);
307 if (bytes_written < 0)
308 return bytes_written;
310 total_bytes_written += bytes_written;
313 DCHECK_EQ(total_bytes_written, bytes_read);
314 bytes_copied += bytes_read;