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