DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator
file.cc
1 // Copyright 2014 Google Inc. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file or at
5 // https://developers.google.com/open-source/licenses/bsd
6 
7 #include "packager/media/file/file.h"
8 
9 #include <gflags/gflags.h>
10 #include <algorithm>
11 #include <memory>
12 #include "packager/base/logging.h"
13 #include "packager/media/file/local_file.h"
14 #include "packager/media/file/memory_file.h"
15 #include "packager/media/file/threaded_io_file.h"
16 #include "packager/media/file/udp_file.h"
17 
18 DEFINE_uint64(io_cache_size,
19  32ULL << 20,
20  "Size of the threaded I/O cache, in bytes. Specify 0 to disable "
21  "threaded I/O.");
22 DEFINE_uint64(io_block_size,
23  2ULL << 20,
24  "Size of the block size used for threaded I/O, in bytes.");
25 
26 // Needed for Windows weirdness which somewhere defines CopyFile as CopyFileW.
27 #ifdef CopyFile
28 #undef CopyFile
29 #endif // CopyFile
30 
31 namespace shaka {
32 namespace media {
33 
34 const char* kLocalFilePrefix = "file://";
35 const char* kUdpFilePrefix = "udp://";
36 const char* kMemoryFilePrefix = "memory://";
37 
38 namespace {
39 
40 typedef File* (*FileFactoryFunction)(const char* file_name, const char* mode);
41 typedef bool (*FileDeleteFunction)(const char* file_name);
42 
43 struct SupportedTypeInfo {
44  const char* type;
45  size_t type_length;
46  const FileFactoryFunction factory_function;
47  const FileDeleteFunction delete_function;
48 };
49 
50 File* CreateLocalFile(const char* file_name, const char* mode) {
51  return new LocalFile(file_name, mode);
52 }
53 
54 bool DeleteLocalFile(const char* file_name) {
55  return LocalFile::Delete(file_name);
56 }
57 
58 File* CreateUdpFile(const char* file_name, const char* mode) {
59  if (strcmp(mode, "r")) {
60  NOTIMPLEMENTED() << "UdpFile only supports read (receive) mode.";
61  return NULL;
62  }
63  return new UdpFile(file_name);
64 }
65 
66 File* CreateMemoryFile(const char* file_name, const char* mode) {
67  return new MemoryFile(file_name, mode);
68 }
69 
70 bool DeleteMemoryFile(const char* file_name) {
71  MemoryFile::Delete(file_name);
72  return true;
73 }
74 
75 static const SupportedTypeInfo kSupportedTypeInfo[] = {
76  {
77  kLocalFilePrefix,
78  strlen(kLocalFilePrefix),
79  &CreateLocalFile,
80  &DeleteLocalFile
81  },
82  {
83  kUdpFilePrefix,
84  strlen(kUdpFilePrefix),
85  &CreateUdpFile,
86  NULL
87  },
88  {
89  kMemoryFilePrefix,
90  strlen(kMemoryFilePrefix),
91  &CreateMemoryFile,
92  &DeleteMemoryFile
93  },
94 };
95 
96 } // namespace
97 
98 File* File::Create(const char* file_name, const char* mode) {
99  std::unique_ptr<File, FileCloser> internal_file(
100  CreateInternalFile(file_name, mode));
101 
102  if (!strncmp(file_name, kMemoryFilePrefix, strlen(kMemoryFilePrefix))) {
103  // Disable caching for memory files.
104  return internal_file.release();
105  }
106 
107  if (FLAGS_io_cache_size) {
108  // Enable threaded I/O for "r", "w", and "a" modes only.
109  if (!strcmp(mode, "r")) {
110  return new ThreadedIoFile(std::move(internal_file),
111  ThreadedIoFile::kInputMode, FLAGS_io_cache_size,
112  FLAGS_io_block_size);
113  } else if (!strcmp(mode, "w") || !strcmp(mode, "a")) {
114  return new ThreadedIoFile(std::move(internal_file),
115  ThreadedIoFile::kOutputMode,
116  FLAGS_io_cache_size, FLAGS_io_block_size);
117  }
118  }
119 
120  // Threaded I/O is disabled.
121  DLOG(WARNING) << "Threaded I/O is disabled. Performance may be decreased.";
122  return internal_file.release();
123 }
124 
125 File* File::CreateInternalFile(const char* file_name, const char* mode) {
126  std::unique_ptr<File, FileCloser> internal_file;
127  for (size_t i = 0; i < arraysize(kSupportedTypeInfo); ++i) {
128  const SupportedTypeInfo& type_info = kSupportedTypeInfo[i];
129  if (strncmp(type_info.type, file_name, type_info.type_length) == 0) {
130  internal_file.reset(type_info.factory_function(
131  file_name + type_info.type_length, mode));
132  }
133  }
134  // Otherwise we assume it is a local file
135  if (!internal_file)
136  internal_file.reset(CreateLocalFile(file_name, mode));
137 
138  return internal_file.release();
139 }
140 
141 File* File::Open(const char* file_name, const char* mode) {
142  File* file = File::Create(file_name, mode);
143  if (!file)
144  return NULL;
145  if (!file->Open()) {
146  delete file;
147  return NULL;
148  }
149  return file;
150 }
151 
152 File* File::OpenWithNoBuffering(const char* file_name, const char* mode) {
153  File* file = File::CreateInternalFile(file_name, mode);
154  if (!file)
155  return NULL;
156  if (!file->Open()) {
157  delete file;
158  return NULL;
159  }
160  return file;
161 }
162 
163 bool File::Delete(const char* file_name) {
164  for (size_t i = 0; i < arraysize(kSupportedTypeInfo); ++i) {
165  const SupportedTypeInfo& type_info = kSupportedTypeInfo[i];
166  if (strncmp(type_info.type, file_name, type_info.type_length) == 0) {
167  return type_info.delete_function ?
168  type_info.delete_function(file_name + type_info.type_length) :
169  false;
170  }
171  }
172  // Otherwise we assume it is a local file
173  return DeleteLocalFile(file_name);
174 }
175 
176 int64_t File::GetFileSize(const char* file_name) {
177  File* file = File::Open(file_name, "r");
178  if (!file)
179  return -1;
180  int64_t res = file->Size();
181  file->Close();
182  return res;
183 }
184 
185 bool File::ReadFileToString(const char* file_name, std::string* contents) {
186  DCHECK(contents);
187 
188  File* file = File::Open(file_name, "r");
189  if (!file)
190  return false;
191 
192  const size_t kBufferSize = 0x40000; // 256KB.
193  std::unique_ptr<char[]> buf(new char[kBufferSize]);
194 
195  int64_t len;
196  while ((len = file->Read(buf.get(), kBufferSize)) > 0)
197  contents->append(buf.get(), len);
198 
199  file->Close();
200  return len == 0;
201 }
202 
203 bool File::Copy(const char* from_file_name, const char* to_file_name) {
204  std::string content;
205  if (!ReadFileToString(from_file_name, &content)) {
206  LOG(ERROR) << "Failed to open file " << from_file_name;
207  return false;
208  }
209 
210  std::unique_ptr<File, FileCloser> output_file(File::Open(to_file_name, "w"));
211  if (!output_file) {
212  LOG(ERROR) << "Failed to write to " << to_file_name;
213  return false;
214  }
215 
216  uint64_t bytes_left = content.size();
217  uint64_t total_bytes_written = 0;
218  const char* content_cstr = content.c_str();
219  while (bytes_left > total_bytes_written) {
220  const int64_t bytes_written =
221  output_file->Write(content_cstr + total_bytes_written, bytes_left);
222  if (bytes_written < 0) {
223  LOG(ERROR) << "Failure while writing to " << to_file_name;
224  return false;
225  }
226 
227  total_bytes_written += bytes_written;
228  }
229  return true;
230 }
231 
232 int64_t File::CopyFile(File* source, File* destination) {
233  return CopyFile(source, destination, kWholeFile);
234 }
235 
236 int64_t File::CopyFile(File* source, File* destination, int64_t max_copy) {
237  DCHECK(source);
238  DCHECK(destination);
239  if (max_copy < 0)
240  max_copy = std::numeric_limits<int64_t>::max();
241 
242  const int64_t kBufferSize = 0x40000; // 256KB.
243  std::unique_ptr<uint8_t[]> buffer(new uint8_t[kBufferSize]);
244  int64_t bytes_copied = 0;
245  while (bytes_copied < max_copy) {
246  const int64_t size = std::min(kBufferSize, max_copy - bytes_copied);
247  const int64_t bytes_read = source->Read(buffer.get(), size);
248  if (bytes_read < 0)
249  return bytes_read;
250  if (bytes_read == 0)
251  break;
252 
253  int64_t total_bytes_written = 0;
254  while (total_bytes_written < bytes_read) {
255  const int64_t bytes_written = destination->Write(
256  buffer.get() + total_bytes_written, bytes_read - total_bytes_written);
257  if (bytes_written < 0)
258  return bytes_written;
259 
260  total_bytes_written += bytes_written;
261  }
262 
263  DCHECK_EQ(total_bytes_written, bytes_read);
264  bytes_copied += bytes_read;
265  }
266 
267  return bytes_copied;
268 }
269 
270 } // namespace media
271 } // namespace shaka
virtual bool Open()=0
Internal open. Should not be used directly.
static File * OpenWithNoBuffering(const char *file_name, const char *mode)
Definition: file.cc:152
static bool Copy(const char *from_file_name, const char *to_file_name)
Definition: file.cc:203
virtual int64_t Size()=0
virtual bool Close()=0
virtual int64_t Write(const void *buffer, uint64_t length)=0
Define an abstract file interface.
Definition: file.h:24
static File * Open(const char *file_name, const char *mode)
Definition: file.cc:141
static void Delete(const std::string &file_name)
Definition: memory_file.cc:134
virtual int64_t Read(void *buffer, uint64_t length)=0
static int64_t CopyFile(File *source, File *destination)
Definition: file.cc:232
static int64_t GetFileSize(const char *file_name)
Definition: file.cc:176
static bool ReadFileToString(const char *file_name, std::string *contents)
Definition: file.cc:185
static bool Delete(const char *file_name)
Definition: local_file.cc:104
static bool Delete(const char *file_name)
Definition: file.cc:163