DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator
demuxer.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/base/demuxer.h"
8 
9 #include <algorithm>
10 
11 #include "packager/base/bind.h"
12 #include "packager/base/logging.h"
13 #include "packager/base/strings/string_number_conversions.h"
14 #include "packager/media/base/decryptor_source.h"
15 #include "packager/media/base/key_source.h"
16 #include "packager/media/base/media_sample.h"
17 #include "packager/media/base/stream_info.h"
18 #include "packager/media/file/file.h"
19 #include "packager/media/formats/mp2t/mp2t_media_parser.h"
20 #include "packager/media/formats/mp4/mp4_media_parser.h"
21 #include "packager/media/formats/webm/webm_media_parser.h"
22 #include "packager/media/formats/webvtt/webvtt_media_parser.h"
23 #include "packager/media/formats/wvm/wvm_media_parser.h"
24 
25 namespace {
26 // 65KB, sufficient to determine the container and likely all init data.
27 const size_t kInitBufSize = 0x10000;
28 const size_t kBufSize = 0x200000; // 2MB
29 // Maximum number of allowed queued samples. If we are receiving a lot of
30 // samples before seeing init_event, something is not right. The number
31 // set here is arbitrary though.
32 const size_t kQueuedSamplesLimit = 10000;
33 const size_t kInvalidStreamIndex = static_cast<size_t>(-1);
34 const size_t kBaseVideoOutputStreamIndex = 0x100;
35 const size_t kBaseAudioOutputStreamIndex = 0x200;
36 
37 std::string GetStreamLabel(size_t stream_index) {
38  switch (stream_index) {
39  case kBaseVideoOutputStreamIndex:
40  return "video";
41  case kBaseAudioOutputStreamIndex:
42  return "audio";
43  default:
44  return base::SizeTToString(stream_index);
45  }
46 }
47 
48 bool GetStreamIndex(const std::string& stream_label, size_t* stream_index) {
49  DCHECK(stream_index);
50  if (stream_label == "video") {
51  *stream_index = kBaseVideoOutputStreamIndex;
52  } else if (stream_label == "audio") {
53  *stream_index = kBaseAudioOutputStreamIndex;
54  } else {
55  // Expect stream_label to be a zero based stream id.
56  if (!base::StringToSizeT(stream_label, stream_index)) {
57  LOG(ERROR) << "Invalid argument --stream=" << stream_label << "; "
58  << "should be 'audio', 'video', or a number";
59  return false;
60  }
61  }
62  return true;
63 }
64 
65 }
66 
67 namespace shaka {
68 namespace media {
69 
70 Demuxer::Demuxer(const std::string& file_name)
71  : file_name_(file_name), buffer_(new uint8_t[kBufSize]) {}
72 
73 Demuxer::~Demuxer() {
74  if (media_file_)
75  media_file_->Close();
76 }
77 
78 void Demuxer::SetKeySource(std::unique_ptr<KeySource> key_source) {
79  key_source_ = std::move(key_source);
80 }
81 
83  LOG(INFO) << "Demuxer::Run() on file '" << file_name_ << "'.";
84  Status status = InitializeParser();
85  // ParserInitEvent callback is called after a few calls to Parse(), which sets
86  // up the streams. Only after that, we can verify the outputs below.
87  while (!all_streams_ready_ && status.ok())
88  status.Update(Parse());
89  // If no output is defined, then return success after receiving all stream
90  // info.
91  if (all_streams_ready_ && output_handlers().empty())
92  return Status::OK;
93  // Check if all specified outputs exists.
94  for (const auto& pair : output_handlers()) {
95  if (std::find(stream_indexes_.begin(), stream_indexes_.end(), pair.first) ==
96  stream_indexes_.end()) {
97  LOG(ERROR) << "Invalid argument, stream=" << GetStreamLabel(pair.first)
98  << " not available.";
99  return Status(error::INVALID_ARGUMENT, "Stream not available");
100  }
101  }
102 
103  while (!cancelled_ && status.ok())
104  status.Update(Parse());
105  if (cancelled_ && status.ok())
106  return Status(error::CANCELLED, "Demuxer run cancelled");
107 
108  if (status.error_code() == error::END_OF_STREAM) {
109  for (size_t stream_index : stream_indexes_) {
110  status = FlushDownstream(stream_index);
111  if (!status.ok())
112  return status;
113  }
114  return Status::OK;
115  }
116  return status;
117 }
118 
120  cancelled_ = true;
121 }
122 
123 Status Demuxer::SetHandler(const std::string& stream_label,
124  std::shared_ptr<MediaHandler> handler) {
125  size_t stream_index = kInvalidStreamIndex;
126  if (!GetStreamIndex(stream_label, &stream_index)) {
127  return Status(error::INVALID_ARGUMENT,
128  "Invalid stream: " + stream_label);
129  }
130  return MediaHandler::SetHandler(stream_index, std::move(handler));
131 }
132 
133 void Demuxer::SetLanguageOverride(const std::string& stream_label,
134  const std::string& language_override) {
135  size_t stream_index = kInvalidStreamIndex;
136  if (!GetStreamIndex(stream_label, &stream_index))
137  LOG(WARNING) << "Invalid stream for language override " << stream_label;
138  language_overrides_[stream_index] = language_override;
139 }
140 
141 Demuxer::QueuedSample::QueuedSample(uint32_t local_track_id,
142  std::shared_ptr<MediaSample> local_sample)
143  : track_id(local_track_id), sample(local_sample) {}
144 
145 Demuxer::QueuedSample::~QueuedSample() {}
146 
147 Status Demuxer::InitializeParser() {
148  DCHECK(!media_file_);
149  DCHECK(!all_streams_ready_);
150 
151  LOG(INFO) << "Initialize Demuxer for file '" << file_name_ << "'.";
152 
153  media_file_ = File::Open(file_name_.c_str(), "r");
154  if (!media_file_) {
155  return Status(error::FILE_FAILURE,
156  "Cannot open file for reading " + file_name_);
157  }
158 
159  // Read enough bytes before detecting the container.
160  size_t bytes_read = 0;
161  while (bytes_read < kInitBufSize) {
162  int64_t read_result =
163  media_file_->Read(buffer_.get() + bytes_read, kInitBufSize);
164  if (read_result < 0)
165  return Status(error::FILE_FAILURE, "Cannot read file " + file_name_);
166  if (read_result == 0)
167  break;
168  bytes_read += read_result;
169  }
170  container_name_ = DetermineContainer(buffer_.get(), bytes_read);
171 
172  // Initialize media parser.
173  switch (container_name_) {
174  case CONTAINER_MOV:
175  parser_.reset(new mp4::MP4MediaParser());
176  break;
177  case CONTAINER_MPEG2TS:
178  parser_.reset(new mp2t::Mp2tMediaParser());
179  break;
180  case CONTAINER_MPEG2PS:
181  parser_.reset(new wvm::WvmMediaParser());
182  break;
183  case CONTAINER_WEBM:
184  parser_.reset(new WebMMediaParser());
185  break;
186  case CONTAINER_WEBVTT:
187  parser_.reset(new WebVttMediaParser());
188  break;
189  default:
190  NOTIMPLEMENTED();
191  return Status(error::UNIMPLEMENTED, "Container not supported.");
192  }
193 
194  parser_->Init(base::Bind(&Demuxer::ParserInitEvent, base::Unretained(this)),
195  base::Bind(&Demuxer::NewSampleEvent, base::Unretained(this)),
196  key_source_.get());
197 
198  // Handle trailing 'moov'.
199  if (container_name_ == CONTAINER_MOV)
200  static_cast<mp4::MP4MediaParser*>(parser_.get())->LoadMoov(file_name_);
201  if (!parser_->Parse(buffer_.get(), bytes_read)) {
202  return Status(error::PARSER_FAILURE,
203  "Cannot parse media file " + file_name_);
204  }
205  return Status::OK;
206 }
207 
208 void Demuxer::ParserInitEvent(
209  const std::vector<std::shared_ptr<StreamInfo>>& stream_infos) {
210  if (dump_stream_info_) {
211  printf("\nFile \"%s\":\n", file_name_.c_str());
212  printf("Found %zu stream(s).\n", stream_infos.size());
213  for (size_t i = 0; i < stream_infos.size(); ++i)
214  printf("Stream [%zu] %s\n", i, stream_infos[i]->ToString().c_str());
215  }
216 
217  int base_stream_index = 0;
218  bool video_handler_set =
219  output_handlers().find(kBaseVideoOutputStreamIndex) !=
220  output_handlers().end();
221  bool audio_handler_set =
222  output_handlers().find(kBaseAudioOutputStreamIndex) !=
223  output_handlers().end();
224  for (const std::shared_ptr<StreamInfo>& stream_info : stream_infos) {
225  size_t stream_index = base_stream_index;
226  if (video_handler_set && stream_info->stream_type() == kStreamVideo) {
227  stream_index = kBaseVideoOutputStreamIndex;
228  // Only for the first video stream.
229  video_handler_set = false;
230  }
231  if (audio_handler_set && stream_info->stream_type() == kStreamAudio) {
232  stream_index = kBaseAudioOutputStreamIndex;
233  // Only for the first audio stream.
234  audio_handler_set = false;
235  }
236 
237  const bool handler_set =
238  output_handlers().find(stream_index) != output_handlers().end();
239  if (handler_set) {
240  track_id_to_stream_index_map_[stream_info->track_id()] = stream_index;
241  stream_indexes_.push_back(stream_index);
242  auto iter = language_overrides_.find(stream_index);
243  if (iter != language_overrides_.end() &&
244  stream_info->stream_type() != kStreamVideo) {
245  stream_info->set_language(iter->second);
246  }
247  DispatchStreamInfo(stream_index, stream_info);
248  } else {
249  track_id_to_stream_index_map_[stream_info->track_id()] =
250  kInvalidStreamIndex;
251  }
252  ++base_stream_index;
253  }
254  all_streams_ready_ = true;
255 }
256 
257 bool Demuxer::NewSampleEvent(uint32_t track_id,
258  const std::shared_ptr<MediaSample>& sample) {
259  if (!all_streams_ready_) {
260  if (queued_samples_.size() >= kQueuedSamplesLimit) {
261  LOG(ERROR) << "Queued samples limit reached: " << kQueuedSamplesLimit;
262  return false;
263  }
264  queued_samples_.push_back(QueuedSample(track_id, sample));
265  return true;
266  }
267  while (!queued_samples_.empty()) {
268  if (!PushSample(queued_samples_.front().track_id,
269  queued_samples_.front().sample)) {
270  return false;
271  }
272  queued_samples_.pop_front();
273  }
274  return PushSample(track_id, sample);
275 }
276 
277 bool Demuxer::PushSample(uint32_t track_id,
278  const std::shared_ptr<MediaSample>& sample) {
279  auto stream_index_iter = track_id_to_stream_index_map_.find(track_id);
280  if (stream_index_iter == track_id_to_stream_index_map_.end()) {
281  LOG(ERROR) << "Track " << track_id << " not found.";
282  return false;
283  }
284  if (stream_index_iter->second == kInvalidStreamIndex)
285  return true;
286  Status status = DispatchMediaSample(stream_index_iter->second, sample);
287  if (!status.ok()) {
288  LOG(ERROR) << "Failed to process sample " << stream_index_iter->second
289  << " " << status;
290  }
291  return status.ok();
292 }
293 
294 Status Demuxer::Parse() {
295  DCHECK(media_file_);
296  DCHECK(parser_);
297  DCHECK(buffer_);
298 
299  int64_t bytes_read = media_file_->Read(buffer_.get(), kBufSize);
300  if (bytes_read == 0) {
301  if (!parser_->Flush())
302  return Status(error::PARSER_FAILURE, "Failed to flush.");
303  return Status(error::END_OF_STREAM, "");
304  } else if (bytes_read < 0) {
305  return Status(error::FILE_FAILURE, "Cannot read file " + file_name_);
306  }
307 
308  return parser_->Parse(buffer_.get(), bytes_read)
309  ? Status::OK
310  : Status(error::PARSER_FAILURE,
311  "Cannot parse media file " + file_name_);
312 }
313 
314 } // namespace media
315 } // namespace shaka
virtual bool Open()=0
Internal open. Should not be used directly.
Status DispatchMediaSample(size_t stream_index, std::shared_ptr< MediaSample > media_sample)
Dispatch the media sample to downstream handlers.
Status SetHandler(const std::string &stream_label, std::shared_ptr< MediaHandler > handler)
Definition: demuxer.cc:123
virtual bool Close()=0
void SetLanguageOverride(const std::string &stream_label, const std::string &language_override)
Definition: demuxer.cc:133
void Update(const Status &new_status)
Definition: status.h:130
Status DispatchStreamInfo(size_t stream_index, std::shared_ptr< StreamInfo > stream_info)
Dispatch the stream info to downstream handlers.
void SetKeySource(std::unique_ptr< KeySource > key_source)
Definition: demuxer.cc:78
virtual int64_t Read(void *buffer, uint64_t length)=0
Status FlushDownstream(size_t output_stream_index)
Flush the downstream connected at the specified output stream index.
Demuxer(const std::string &file_name)
Definition: demuxer.cc:70
Status SetHandler(size_t output_stream_index, std::shared_ptr< MediaHandler > handler)
Connect downstream handler at the specified output stream index.