DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator
mpd_generator.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/app/mpd_generator_flags.h"
8 #include "packager/app/vlog_flags.h"
9 #include "packager/base/at_exit.h"
10 #include "packager/base/command_line.h"
11 #include "packager/base/logging.h"
12 #include "packager/base/strings/string_split.h"
13 #include "packager/base/strings/stringprintf.h"
14 #include "packager/mpd/util/mpd_writer.h"
15 #include "packager/version/version.h"
16 
17 #if defined(OS_WIN)
18 #include <codecvt>
19 #include <functional>
20 #include <locale>
21 #endif // defined(OS_WIN)
22 
23 namespace shaka {
24 namespace {
25 const char kUsage[] =
26  "MPD generation driver program.\n"
27  "This program accepts MediaInfo files in human readable text "
28  "format and outputs an MPD.\n"
29  "The main use case for this is to output MPD for VOD.\n"
30  "Limitations:\n"
31  " Each MediaInfo can only have one of VideoInfo, AudioInfo, or TextInfo.\n"
32  " There will be at most 3 AdaptationSets in the MPD, i.e. 1 video, 1 "
33  "audio, and 1 text.\n"
34  "Sample Usage:\n"
35  "%s --input=\"video1.media_info,video2.media_info,audio1.media_info\" "
36  "--output=\"video_audio.mpd\"";
37 
38 enum ExitStatus {
39  kSuccess = 0,
40  kEmptyInputError,
41  kEmptyOutputError,
42  kFailedToWriteMpdToFileError
43 };
44 
45 ExitStatus CheckRequiredFlags() {
46  if (FLAGS_input.empty()) {
47  LOG(ERROR) << "--input is required.";
48  return kEmptyInputError;
49  }
50 
51  if (FLAGS_output.empty()) {
52  LOG(ERROR) << "--output is required.";
53  return kEmptyOutputError;
54  }
55 
56  return kSuccess;
57 }
58 
59 ExitStatus RunMpdGenerator() {
60  DCHECK_EQ(CheckRequiredFlags(), kSuccess);
61  std::vector<std::string> base_urls;
62  typedef std::vector<std::string>::const_iterator Iterator;
63 
64  std::vector<std::string> input_files = base::SplitString(
65  FLAGS_input, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
66 
67  if (!FLAGS_base_urls.empty()) {
68  base_urls = base::SplitString(FLAGS_base_urls, ",", base::KEEP_WHITESPACE,
69  base::SPLIT_WANT_ALL);
70  }
71 
72  MpdWriter mpd_writer;
73  for (Iterator it = base_urls.begin(); it != base_urls.end(); ++it)
74  mpd_writer.AddBaseUrl(*it);
75 
76  for (Iterator it = input_files.begin(); it != input_files.end(); ++it) {
77  if (!mpd_writer.AddFile(it->c_str(), FLAGS_output)) {
78  LOG(WARNING) << "MpdWriter failed to read " << *it << ", skipping.";
79  }
80  }
81 
82  if (!mpd_writer.WriteMpdToFile(FLAGS_output.c_str())) {
83  LOG(ERROR) << "Failed to write MPD to " << FLAGS_output;
84  return kFailedToWriteMpdToFileError;
85  }
86 
87  return kSuccess;
88 }
89 
90 int MpdMain(int argc, char** argv) {
91  base::AtExitManager exit;
92  // Needed to enable VLOG/DVLOG through --vmodule or --v.
93  base::CommandLine::Init(argc, argv);
94 
95  // Set up logging.
96  logging::LoggingSettings log_settings;
97  log_settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
98  CHECK(logging::InitLogging(log_settings));
99 
100  google::SetUsageMessage(base::StringPrintf(kUsage, argv[0]));
101  google::ParseCommandLineFlags(&argc, &argv, true);
102 
103  ExitStatus status = CheckRequiredFlags();
104  if (status != kSuccess) {
105  const std::string version_string = base::StringPrintf(
106  "mpd_generator version %s", GetPackagerVersion().c_str());
107  google::ShowUsageWithFlags(version_string.c_str());
108  return status;
109  }
110 
111  return RunMpdGenerator();
112 }
113 
114 } // namespace
115 } // namespace shaka
116 
117 #if defined(OS_WIN)
118 // Windows wmain, which converts wide character arguments to UTF-8.
119 int wmain(int argc, wchar_t* argv[], wchar_t* envp[]) {
120  std::unique_ptr<char* [], std::function<void(char**)>> utf8_argv(
121  new char*[argc], [argc](char** utf8_args) {
122  // TODO(tinskip): This leaks, but if this code is enabled, it crashes.
123  // Figure out why. I suspect gflags does something funny with the
124  // argument array.
125  // for (int idx = 0; idx < argc; ++idx)
126  // delete[] utf8_args[idx];
127  delete[] utf8_args;
128  });
129  std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
130  for (int idx = 0; idx < argc; ++idx) {
131  std::string utf8_arg(converter.to_bytes(argv[idx]));
132  utf8_arg += '\0';
133  utf8_argv[idx] = new char[utf8_arg.size()];
134  memcpy(utf8_argv[idx], &utf8_arg[0], utf8_arg.size());
135  }
136  return shaka::MpdMain(argc, utf8_argv.get());
137 }
138 #else
139 int main(int argc, char** argv) {
140  return shaka::MpdMain(argc, argv);
141 }
142 #endif // !defined(OS_WIN)