DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs 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 <algorithm>
10 
11 #include <gflags/gflags.h>
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 namespace edash_packager {
29 namespace media {
30 
31 const char* kLocalFilePrefix = "file://";
32 const char* kUdpFilePrefix = "udp://";
33 const char* kMemoryFilePrefix = "memory://";
34 
35 namespace {
36 
37 typedef File* (*FileFactoryFunction)(const char* file_name, const char* mode);
38 typedef bool (*FileDeleteFunction)(const char* file_name);
39 
40 struct SupportedTypeInfo {
41  const char* type;
42  size_t type_length;
43  const FileFactoryFunction factory_function;
44  const FileDeleteFunction delete_function;
45 };
46 
47 File* CreateLocalFile(const char* file_name, const char* mode) {
48  return new LocalFile(file_name, mode);
49 }
50 
51 bool DeleteLocalFile(const char* file_name) {
52  return LocalFile::Delete(file_name);
53 }
54 
55 File* CreateUdpFile(const char* file_name, const char* mode) {
56  if (base::strcasecmp(mode, "r")) {
57  NOTIMPLEMENTED() << "UdpFile only supports read (receive) mode.";
58  return NULL;
59  }
60  return new UdpFile(file_name);
61 }
62 
63 File* CreateMemoryFile(const char* file_name, const char* mode) {
64  return new MemoryFile(file_name);
65 }
66 
67 bool DeleteMemoryFile(const char* file_name) {
68  MemoryFile::Delete(file_name);
69  return true;
70 }
71 
72 static const SupportedTypeInfo kSupportedTypeInfo[] = {
73  {
74  kLocalFilePrefix,
75  strlen(kLocalFilePrefix),
76  &CreateLocalFile,
77  &DeleteLocalFile
78  },
79  {
80  kUdpFilePrefix,
81  strlen(kUdpFilePrefix),
82  &CreateUdpFile,
83  NULL
84  },
85  {
86  kMemoryFilePrefix,
87  strlen(kMemoryFilePrefix),
88  &CreateMemoryFile,
89  &DeleteMemoryFile
90  },
91 };
92 
93 } // namespace
94 
95 File* File::Create(const char* file_name, const char* mode) {
96  scoped_ptr<File, FileCloser> internal_file(
97  CreateInternalFile(file_name, mode));
98 
99  if (!strncmp(file_name, kMemoryFilePrefix, strlen(kMemoryFilePrefix))) {
100  // Disable caching for memory files.
101  return internal_file.release();
102  }
103 
104  if (FLAGS_io_cache_size) {
105  // Enable threaded I/O for "r", "w", and "a" modes only.
106  if (!strcmp(mode, "r")) {
107  return new ThreadedIoFile(internal_file.Pass(),
108  ThreadedIoFile::kInputMode,
109  FLAGS_io_cache_size,
110  FLAGS_io_block_size);
111  } else if (!strcmp(mode, "w") || !strcmp(mode, "a")) {
112  return new ThreadedIoFile(internal_file.Pass(),
113  ThreadedIoFile::kOutputMode,
114  FLAGS_io_cache_size,
115  FLAGS_io_block_size);
116  }
117  }
118 
119  // Threaded I/O is disabled.
120  DLOG(WARNING) << "Threaded I/O is disabled. Performance may be decreased.";
121  return internal_file.release();
122 }
123 
124 File* File::CreateInternalFile(const char* file_name, const char* mode) {
125  scoped_ptr<File, FileCloser> internal_file;
126  for (size_t i = 0; i < arraysize(kSupportedTypeInfo); ++i) {
127  const SupportedTypeInfo& type_info = kSupportedTypeInfo[i];
128  if (strncmp(type_info.type, file_name, type_info.type_length) == 0) {
129  internal_file.reset(type_info.factory_function(
130  file_name + type_info.type_length, mode));
131  }
132  }
133  // Otherwise we assume it is a local file
134  if (!internal_file)
135  internal_file.reset(CreateLocalFile(file_name, mode));
136 
137  return internal_file.release();
138 }
139 
140 File* File::Open(const char* file_name, const char* mode) {
141  File* file = File::Create(file_name, mode);
142  if (!file)
143  return NULL;
144  if (!file->Open()) {
145  delete file;
146  return NULL;
147  }
148  return file;
149 }
150 
151 File* File::OpenWithNoBuffering(const char* file_name, const char* mode) {
152  File* file = File::CreateInternalFile(file_name, mode);
153  if (!file)
154  return NULL;
155  if (!file->Open()) {
156  delete file;
157  return NULL;
158  }
159  return file;
160 }
161 
162 bool File::Delete(const char* file_name) {
163  for (size_t i = 0; i < arraysize(kSupportedTypeInfo); ++i) {
164  const SupportedTypeInfo& type_info = kSupportedTypeInfo[i];
165  if (strncmp(type_info.type, file_name, type_info.type_length) == 0) {
166  return type_info.delete_function ?
167  type_info.delete_function(file_name + type_info.type_length) :
168  false;
169  }
170  }
171  // Otherwise we assume it is a local file
172  return DeleteLocalFile(file_name);
173 }
174 
175 int64_t File::GetFileSize(const char* file_name) {
176  File* file = File::Open(file_name, "r");
177  if (!file)
178  return -1;
179  int64_t res = file->Size();
180  file->Close();
181  return res;
182 }
183 
184 bool File::ReadFileToString(const char* file_name, std::string* contents) {
185  DCHECK(contents);
186 
187  File* file = File::Open(file_name, "r");
188  if (!file)
189  return false;
190 
191  const size_t kBufferSize = 0x40000; // 256KB.
192  scoped_ptr<char[]> buf(new char[kBufferSize]);
193 
194  int64_t len;
195  while ((len = file->Read(buf.get(), kBufferSize)) > 0)
196  contents->append(buf.get(), len);
197 
198  file->Close();
199  return len == 0;
200 }
201 
202 bool File::Copy(const char* from_file_name, const char* to_file_name) {
203  std::string content;
204  if (!ReadFileToString(from_file_name, &content)) {
205  LOG(ERROR) << "Failed to open file " << from_file_name;
206  return false;
207  }
208 
209  scoped_ptr<edash_packager::media::File, edash_packager::media::FileCloser>
210  output_file(edash_packager::media::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  scoped_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 edash_packager
static bool ReadFileToString(const char *file_name, std::string *contents)
Definition: file.cc:184
virtual int64_t Read(void *buffer, uint64_t length)=0
static bool Delete(const char *file_name)
Definition: file.cc:162
static int64_t CopyFile(File *source, File *destination)
Definition: file.cc:232
Define an abstract file interface.
Definition: file.h:23
virtual bool Open()=0
Internal open. Should not be used directly.
static File * Open(const char *file_name, const char *mode)
Definition: file.cc:140
virtual int64_t Size()=0
static bool Delete(const char *file_name)
Definition: local_file.cc:84
static void Delete(const std::string &file_name)
Definition: memory_file.cc:118
static bool Copy(const char *from_file_name, const char *to_file_name)
Definition: file.cc:202
virtual int64_t Write(const void *buffer, uint64_t length)=0
static int64_t GetFileSize(const char *file_name)
Definition: file.cc:175
static File * OpenWithNoBuffering(const char *file_name, const char *mode)
Definition: file.cc:151