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