2014-02-14 23:21:05 +00:00
|
|
|
// Copyright 2014 Google Inc. All rights reserved.
|
|
|
|
//
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file or at
|
|
|
|
// https://developers.google.com/open-source/licenses/bsd
|
2013-10-11 21:44:55 +00:00
|
|
|
|
2014-10-01 22:10:21 +00:00
|
|
|
#include "packager/media/base/demuxer.h"
|
|
|
|
|
|
|
|
#include "packager/base/bind.h"
|
|
|
|
#include "packager/base/logging.h"
|
|
|
|
#include "packager/base/stl_util.h"
|
|
|
|
#include "packager/media/base/decryptor_source.h"
|
|
|
|
#include "packager/media/base/key_source.h"
|
|
|
|
#include "packager/media/base/media_sample.h"
|
|
|
|
#include "packager/media/base/media_stream.h"
|
|
|
|
#include "packager/media/base/stream_info.h"
|
|
|
|
#include "packager/media/file/file.h"
|
|
|
|
#include "packager/media/formats/mp2t/mp2t_media_parser.h"
|
|
|
|
#include "packager/media/formats/mp4/mp4_media_parser.h"
|
2015-10-26 20:50:22 +00:00
|
|
|
#include "packager/media/formats/webm/webm_media_parser.h"
|
2015-11-19 23:58:29 +00:00
|
|
|
#include "packager/media/formats/webvtt/webvtt_media_parser.h"
|
2014-10-01 22:10:21 +00:00
|
|
|
#include "packager/media/formats/wvm/wvm_media_parser.h"
|
2013-10-11 21:44:55 +00:00
|
|
|
|
|
|
|
namespace {
|
2016-01-21 18:30:29 +00:00
|
|
|
// 65KB, sufficient to determine the container and likely all init data.
|
|
|
|
const size_t kInitBufSize = 0x10000;
|
|
|
|
const size_t kBufSize = 0x200000; // 2MB
|
|
|
|
// Maximum number of allowed queued samples. If we are receiving a lot of
|
|
|
|
// samples before seeing init_event, something is not right. The number
|
|
|
|
// set here is arbitrary though.
|
|
|
|
const size_t kQueuedSamplesLimit = 10000;
|
2013-10-11 21:44:55 +00:00
|
|
|
}
|
|
|
|
|
2014-09-19 20:41:13 +00:00
|
|
|
namespace edash_packager {
|
2013-10-11 21:44:55 +00:00
|
|
|
namespace media {
|
|
|
|
|
2014-08-25 22:51:19 +00:00
|
|
|
Demuxer::Demuxer(const std::string& file_name)
|
|
|
|
: file_name_(file_name),
|
2013-10-11 21:44:55 +00:00
|
|
|
media_file_(NULL),
|
|
|
|
init_event_received_(false),
|
2015-06-02 21:41:49 +00:00
|
|
|
container_name_(CONTAINER_UNKNOWN),
|
2015-02-09 18:22:28 +00:00
|
|
|
buffer_(new uint8_t[kBufSize]),
|
|
|
|
cancelled_(false) {
|
2014-09-30 21:52:21 +00:00
|
|
|
}
|
2013-10-11 21:44:55 +00:00
|
|
|
|
|
|
|
Demuxer::~Demuxer() {
|
|
|
|
if (media_file_)
|
|
|
|
media_file_->Close();
|
|
|
|
STLDeleteElements(&streams_);
|
|
|
|
}
|
|
|
|
|
2014-08-25 22:51:19 +00:00
|
|
|
void Demuxer::SetKeySource(scoped_ptr<KeySource> key_source) {
|
|
|
|
key_source_ = key_source.Pass();
|
|
|
|
}
|
|
|
|
|
2013-10-11 21:44:55 +00:00
|
|
|
Status Demuxer::Initialize() {
|
2014-04-09 17:34:55 +00:00
|
|
|
DCHECK(!media_file_);
|
2013-10-11 21:44:55 +00:00
|
|
|
DCHECK(!init_event_received_);
|
|
|
|
|
2015-05-12 00:52:53 +00:00
|
|
|
LOG(INFO) << "Initialize Demuxer for file '" << file_name_ << "'.";
|
|
|
|
|
2013-10-11 21:44:55 +00:00
|
|
|
media_file_ = File::Open(file_name_.c_str(), "r");
|
2014-04-09 17:34:55 +00:00
|
|
|
if (!media_file_) {
|
2013-10-11 21:44:55 +00:00
|
|
|
return Status(error::FILE_FAILURE,
|
2014-04-09 17:34:55 +00:00
|
|
|
"Cannot open file for reading " + file_name_);
|
2013-10-11 21:44:55 +00:00
|
|
|
}
|
|
|
|
|
2015-03-20 18:45:49 +00:00
|
|
|
// Read enough bytes before detecting the container.
|
|
|
|
size_t bytes_read = 0;
|
|
|
|
while (bytes_read < kInitBufSize) {
|
|
|
|
int64_t read_result =
|
|
|
|
media_file_->Read(buffer_.get() + bytes_read, kInitBufSize);
|
|
|
|
if (read_result < 0)
|
|
|
|
return Status(error::FILE_FAILURE, "Cannot read file " + file_name_);
|
|
|
|
if (read_result == 0)
|
|
|
|
break;
|
|
|
|
bytes_read += read_result;
|
|
|
|
}
|
2015-06-02 21:41:49 +00:00
|
|
|
container_name_ = DetermineContainer(buffer_.get(), bytes_read);
|
2013-10-11 21:44:55 +00:00
|
|
|
|
|
|
|
// Initialize media parser.
|
2015-06-02 21:41:49 +00:00
|
|
|
switch (container_name_) {
|
2013-10-11 21:44:55 +00:00
|
|
|
case CONTAINER_MOV:
|
|
|
|
parser_.reset(new mp4::MP4MediaParser());
|
|
|
|
break;
|
2014-04-15 23:51:32 +00:00
|
|
|
case CONTAINER_MPEG2TS:
|
2014-04-16 23:22:31 +00:00
|
|
|
parser_.reset(new mp2t::Mp2tMediaParser());
|
2014-04-15 23:51:32 +00:00
|
|
|
break;
|
2014-07-14 21:35:57 +00:00
|
|
|
case CONTAINER_MPEG2PS:
|
|
|
|
parser_.reset(new wvm::WvmMediaParser());
|
|
|
|
break;
|
2015-10-26 20:50:22 +00:00
|
|
|
case CONTAINER_WEBM:
|
|
|
|
parser_.reset(new WebMMediaParser());
|
|
|
|
break;
|
2015-11-19 23:58:29 +00:00
|
|
|
case CONTAINER_WEBVTT:
|
|
|
|
parser_.reset(new WebVttMediaParser());
|
|
|
|
break;
|
2013-10-11 21:44:55 +00:00
|
|
|
default:
|
|
|
|
NOTIMPLEMENTED();
|
|
|
|
return Status(error::UNIMPLEMENTED, "Container not supported.");
|
|
|
|
}
|
|
|
|
|
2013-11-12 20:32:44 +00:00
|
|
|
parser_->Init(base::Bind(&Demuxer::ParserInitEvent, base::Unretained(this)),
|
|
|
|
base::Bind(&Demuxer::NewSampleEvent, base::Unretained(this)),
|
2014-08-25 22:51:19 +00:00
|
|
|
key_source_.get());
|
2013-10-11 21:44:55 +00:00
|
|
|
|
2015-05-21 00:38:09 +00:00
|
|
|
// Handle trailing 'moov'.
|
2015-06-02 21:41:49 +00:00
|
|
|
if (container_name_ == CONTAINER_MOV)
|
2015-05-21 00:38:09 +00:00
|
|
|
static_cast<mp4::MP4MediaParser*>(parser_.get())->LoadMoov(file_name_);
|
|
|
|
|
2014-10-14 02:34:29 +00:00
|
|
|
if (!parser_->Parse(buffer_.get(), bytes_read)) {
|
|
|
|
init_parsing_status_ =
|
|
|
|
Status(error::PARSER_FAILURE, "Cannot parse media file " + file_name_);
|
2013-10-11 21:44:55 +00:00
|
|
|
}
|
2014-10-14 02:34:29 +00:00
|
|
|
|
|
|
|
// Parse until init event received or on error.
|
|
|
|
while (!init_event_received_ && init_parsing_status_.ok())
|
|
|
|
init_parsing_status_ = Parse();
|
|
|
|
// Defer error reporting if init completed successfully.
|
|
|
|
return init_event_received_ ? Status::OK : init_parsing_status_;
|
2013-10-11 21:44:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Demuxer::ParserInitEvent(
|
|
|
|
const std::vector<scoped_refptr<StreamInfo> >& streams) {
|
|
|
|
init_event_received_ = true;
|
|
|
|
|
|
|
|
std::vector<scoped_refptr<StreamInfo> >::const_iterator it = streams.begin();
|
|
|
|
for (; it != streams.end(); ++it) {
|
|
|
|
streams_.push_back(new MediaStream(*it, this));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-21 18:30:29 +00:00
|
|
|
Demuxer::QueuedSample::QueuedSample(uint32_t local_track_id,
|
|
|
|
scoped_refptr<MediaSample> local_sample)
|
|
|
|
: track_id(local_track_id), sample(local_sample) {}
|
|
|
|
Demuxer::QueuedSample::~QueuedSample() {}
|
|
|
|
|
2014-09-30 21:52:21 +00:00
|
|
|
bool Demuxer::NewSampleEvent(uint32_t track_id,
|
2013-11-12 20:32:44 +00:00
|
|
|
const scoped_refptr<MediaSample>& sample) {
|
2016-01-21 18:30:29 +00:00
|
|
|
if (!init_event_received_) {
|
|
|
|
if (queued_samples_.size() >= kQueuedSamplesLimit) {
|
|
|
|
LOG(ERROR) << "Queued samples limit reached: " << kQueuedSamplesLimit;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
queued_samples_.push_back(QueuedSample(track_id, sample));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
while (!queued_samples_.empty()) {
|
|
|
|
if (!PushSample(queued_samples_.front().track_id,
|
|
|
|
queued_samples_.front().sample)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
queued_samples_.pop_front();
|
|
|
|
}
|
|
|
|
return PushSample(track_id, sample);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Demuxer::PushSample(uint32_t track_id,
|
|
|
|
const scoped_refptr<MediaSample>& sample) {
|
2013-10-11 21:44:55 +00:00
|
|
|
std::vector<MediaStream*>::iterator it = streams_.begin();
|
|
|
|
for (; it != streams_.end(); ++it) {
|
|
|
|
if (track_id == (*it)->info()->track_id()) {
|
|
|
|
return (*it)->PushSample(sample).ok();
|
|
|
|
}
|
|
|
|
}
|
2016-01-21 18:30:29 +00:00
|
|
|
LOG(ERROR) << "Track " << track_id << " not found.";
|
2013-10-11 21:44:55 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status Demuxer::Run() {
|
|
|
|
Status status;
|
|
|
|
|
2015-05-12 00:52:53 +00:00
|
|
|
LOG(INFO) << "Demuxer::Run() on file '" << file_name_ << "'.";
|
|
|
|
|
2013-10-11 21:44:55 +00:00
|
|
|
// Start the streams.
|
|
|
|
for (std::vector<MediaStream*>::iterator it = streams_.begin();
|
|
|
|
it != streams_.end();
|
|
|
|
++it) {
|
|
|
|
status = (*it)->Start(MediaStream::kPush);
|
|
|
|
if (!status.ok())
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2015-02-09 18:22:28 +00:00
|
|
|
while (!cancelled_ && (status = Parse()).ok())
|
2013-11-12 20:32:44 +00:00
|
|
|
continue;
|
2014-04-09 17:34:55 +00:00
|
|
|
|
2015-02-09 18:22:28 +00:00
|
|
|
if (cancelled_ && status.ok())
|
|
|
|
return Status(error::CANCELLED, "Demuxer run cancelled");
|
|
|
|
|
2014-04-09 17:34:55 +00:00
|
|
|
if (status.error_code() == error::END_OF_STREAM) {
|
|
|
|
// Push EOS sample to muxer to indicate end of stream.
|
|
|
|
const scoped_refptr<MediaSample>& sample = MediaSample::CreateEOSBuffer();
|
|
|
|
for (std::vector<MediaStream*>::iterator it = streams_.begin();
|
|
|
|
it != streams_.end();
|
|
|
|
++it) {
|
|
|
|
status = (*it)->PushSample(sample);
|
|
|
|
if (!status.ok())
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return status;
|
2013-10-11 21:44:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Status Demuxer::Parse() {
|
2014-04-09 17:34:55 +00:00
|
|
|
DCHECK(media_file_);
|
|
|
|
DCHECK(parser_);
|
|
|
|
DCHECK(buffer_);
|
2013-10-11 21:44:55 +00:00
|
|
|
|
2014-10-14 02:34:29 +00:00
|
|
|
// Return early and avoid call Parse(...) again if it has already failed at
|
|
|
|
// the initialization.
|
|
|
|
if (!init_parsing_status_.ok())
|
|
|
|
return init_parsing_status_;
|
|
|
|
|
2014-09-30 21:52:21 +00:00
|
|
|
int64_t bytes_read = media_file_->Read(buffer_.get(), kBufSize);
|
2015-03-17 20:59:12 +00:00
|
|
|
if (bytes_read == 0) {
|
2016-01-21 18:30:29 +00:00
|
|
|
if (!parser_->Flush())
|
|
|
|
return Status(error::PARSER_FAILURE, "Failed to flush.");
|
2015-03-17 20:59:12 +00:00
|
|
|
return Status(error::END_OF_STREAM, "");
|
|
|
|
} else if (bytes_read < 0) {
|
2014-04-24 18:37:33 +00:00
|
|
|
return Status(error::FILE_FAILURE, "Cannot read file " + file_name_);
|
2013-10-11 21:44:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return parser_->Parse(buffer_.get(), bytes_read)
|
|
|
|
? Status::OK
|
|
|
|
: Status(error::PARSER_FAILURE,
|
|
|
|
"Cannot parse media file " + file_name_);
|
|
|
|
}
|
|
|
|
|
2015-02-09 18:22:28 +00:00
|
|
|
void Demuxer::Cancel() {
|
|
|
|
cancelled_ = true;
|
|
|
|
}
|
|
|
|
|
2013-10-11 21:44:55 +00:00
|
|
|
} // namespace media
|
2014-09-19 20:41:13 +00:00
|
|
|
} // namespace edash_packager
|