DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs 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 "packager/base/bind.h"
10 #include "packager/base/logging.h"
11 #include "packager/base/stl_util.h"
12 #include "packager/media/base/decryptor_source.h"
13 #include "packager/media/base/key_source.h"
14 #include "packager/media/base/media_sample.h"
15 #include "packager/media/base/media_stream.h"
16 #include "packager/media/base/stream_info.h"
17 #include "packager/media/file/file.h"
18 #include "packager/media/formats/mp2t/mp2t_media_parser.h"
19 #include "packager/media/formats/mp4/mp4_media_parser.h"
20 #include "packager/media/formats/webm/webm_media_parser.h"
21 #include "packager/media/formats/webvtt/webvtt_media_parser.h"
22 #include "packager/media/formats/wvm/wvm_media_parser.h"
23 
24 namespace {
25 const size_t kInitBufSize = 0x10000; // 65KB, sufficient to determine the
26  // container and likely all init data.
27 const size_t kBufSize = 0x200000; // 2MB
28 }
29 
30 namespace edash_packager {
31 namespace media {
32 
33 Demuxer::Demuxer(const std::string& file_name)
34  : file_name_(file_name),
35  media_file_(NULL),
36  init_event_received_(false),
37  container_name_(CONTAINER_UNKNOWN),
38  buffer_(new uint8_t[kBufSize]),
39  cancelled_(false) {
40 }
41 
42 Demuxer::~Demuxer() {
43  if (media_file_)
44  media_file_->Close();
45  STLDeleteElements(&streams_);
46 }
47 
48 void Demuxer::SetKeySource(scoped_ptr<KeySource> key_source) {
49  key_source_ = key_source.Pass();
50 }
51 
53  DCHECK(!media_file_);
54  DCHECK(!init_event_received_);
55 
56  LOG(INFO) << "Initialize Demuxer for file '" << file_name_ << "'.";
57 
58  media_file_ = File::Open(file_name_.c_str(), "r");
59  if (!media_file_) {
60  return Status(error::FILE_FAILURE,
61  "Cannot open file for reading " + file_name_);
62  }
63 
64  // Read enough bytes before detecting the container.
65  size_t bytes_read = 0;
66  while (bytes_read < kInitBufSize) {
67  int64_t read_result =
68  media_file_->Read(buffer_.get() + bytes_read, kInitBufSize);
69  if (read_result < 0)
70  return Status(error::FILE_FAILURE, "Cannot read file " + file_name_);
71  if (read_result == 0)
72  break;
73  bytes_read += read_result;
74  }
75  container_name_ = DetermineContainer(buffer_.get(), bytes_read);
76 
77  // Initialize media parser.
78  switch (container_name_) {
79  case CONTAINER_MOV:
80  parser_.reset(new mp4::MP4MediaParser());
81  break;
82  case CONTAINER_MPEG2TS:
83  parser_.reset(new mp2t::Mp2tMediaParser());
84  break;
85  case CONTAINER_MPEG2PS:
86  parser_.reset(new wvm::WvmMediaParser());
87  break;
88  case CONTAINER_WEBM:
89  parser_.reset(new WebMMediaParser());
90  break;
91  case CONTAINER_WEBVTT:
92  parser_.reset(new WebVttMediaParser());
93  break;
94  default:
95  NOTIMPLEMENTED();
96  return Status(error::UNIMPLEMENTED, "Container not supported.");
97  }
98 
99  parser_->Init(base::Bind(&Demuxer::ParserInitEvent, base::Unretained(this)),
100  base::Bind(&Demuxer::NewSampleEvent, base::Unretained(this)),
101  key_source_.get());
102 
103  // Handle trailing 'moov'.
104  if (container_name_ == CONTAINER_MOV)
105  static_cast<mp4::MP4MediaParser*>(parser_.get())->LoadMoov(file_name_);
106 
107  if (!parser_->Parse(buffer_.get(), bytes_read)) {
108  init_parsing_status_ =
109  Status(error::PARSER_FAILURE, "Cannot parse media file " + file_name_);
110  }
111 
112  // Parse until init event received or on error.
113  while (!init_event_received_ && init_parsing_status_.ok())
114  init_parsing_status_ = Parse();
115  // Defer error reporting if init completed successfully.
116  return init_event_received_ ? Status::OK : init_parsing_status_;
117 }
118 
119 void Demuxer::ParserInitEvent(
120  const std::vector<scoped_refptr<StreamInfo> >& streams) {
121  init_event_received_ = true;
122 
123  std::vector<scoped_refptr<StreamInfo> >::const_iterator it = streams.begin();
124  for (; it != streams.end(); ++it) {
125  streams_.push_back(new MediaStream(*it, this));
126  }
127 }
128 
129 bool Demuxer::NewSampleEvent(uint32_t track_id,
130  const scoped_refptr<MediaSample>& sample) {
131  std::vector<MediaStream*>::iterator it = streams_.begin();
132  for (; it != streams_.end(); ++it) {
133  if (track_id == (*it)->info()->track_id()) {
134  return (*it)->PushSample(sample).ok();
135  }
136  }
137  return false;
138 }
139 
141  Status status;
142 
143  LOG(INFO) << "Demuxer::Run() on file '" << file_name_ << "'.";
144 
145  // Start the streams.
146  for (std::vector<MediaStream*>::iterator it = streams_.begin();
147  it != streams_.end();
148  ++it) {
149  status = (*it)->Start(MediaStream::kPush);
150  if (!status.ok())
151  return status;
152  }
153 
154  while (!cancelled_ && (status = Parse()).ok())
155  continue;
156 
157  if (cancelled_ && status.ok())
158  return Status(error::CANCELLED, "Demuxer run cancelled");
159 
160  if (status.error_code() == error::END_OF_STREAM) {
161  // Push EOS sample to muxer to indicate end of stream.
162  const scoped_refptr<MediaSample>& sample = MediaSample::CreateEOSBuffer();
163  for (std::vector<MediaStream*>::iterator it = streams_.begin();
164  it != streams_.end();
165  ++it) {
166  status = (*it)->PushSample(sample);
167  if (!status.ok())
168  return status;
169  }
170  }
171  return status;
172 }
173 
175  DCHECK(media_file_);
176  DCHECK(parser_);
177  DCHECK(buffer_);
178 
179  // Return early and avoid call Parse(...) again if it has already failed at
180  // the initialization.
181  if (!init_parsing_status_.ok())
182  return init_parsing_status_;
183 
184  int64_t bytes_read = media_file_->Read(buffer_.get(), kBufSize);
185  if (bytes_read == 0) {
186  parser_->Flush();
187  return Status(error::END_OF_STREAM, "");
188  } else if (bytes_read < 0) {
189  return Status(error::FILE_FAILURE, "Cannot read file " + file_name_);
190  }
191 
192  return parser_->Parse(buffer_.get(), bytes_read)
193  ? Status::OK
194  : Status(error::PARSER_FAILURE,
195  "Cannot parse media file " + file_name_);
196 }
197 
199  cancelled_ = true;
200 }
201 
202 } // namespace media
203 } // namespace edash_packager
void SetKeySource(scoped_ptr< KeySource > key_source)
Definition: demuxer.cc:48
virtual int64_t Read(void *buffer, uint64_t length)=0
const std::vector< MediaStream * > & streams()
Definition: demuxer.h:66
virtual bool Open()=0
Internal open. Should not be used directly.
static scoped_refptr< MediaSample > CreateEOSBuffer()
Definition: media_sample.cc:80
Status Parse()
Read from the source and send it to the parser.
Definition: demuxer.cc:174
Demuxer(const std::string &file_name)
Definition: demuxer.cc:33