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