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