shaka-packager/media/base/demuxer.cc

142 lines
3.9 KiB
C++
Raw Normal View History

// Copyright (c) 2013 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.
#include "media/base/demuxer.h"
#include "base/bind.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "media/base/container_names.h"
#include "media/base/decryptor_source.h"
#include "media/base/media_stream.h"
#include "media/base/stream_info.h"
#include "media/file/file.h"
#include "media/mp4/mp4_media_parser.h"
namespace {
const int kBufSize = 0x40000; // 256KB.
}
namespace media {
Demuxer::Demuxer(const std::string& file_name,
DecryptorSource* decryptor_source)
: decryptor_source_(decryptor_source),
file_name_(file_name),
media_file_(NULL),
init_event_received_(false),
buffer_(new uint8[kBufSize]) {}
Demuxer::~Demuxer() {
if (media_file_)
media_file_->Close();
STLDeleteElements(&streams_);
}
Status Demuxer::Initialize() {
DCHECK(media_file_ == NULL);
DCHECK(!init_event_received_);
media_file_ = File::Open(file_name_.c_str(), "r");
if (media_file_ == NULL) {
return Status(error::FILE_FAILURE,
"Cannot open file for read " + file_name_);
}
// Determine media container.
int64 bytes_read = media_file_->Read(buffer_.get(), kBufSize);
if (bytes_read <= 0)
return Status(error::FILE_FAILURE, "Cannot read file " + file_name_);
MediaContainerName container = DetermineContainer(buffer_.get(), bytes_read);
// Initialize media parser.
switch (container) {
case CONTAINER_MOV:
parser_.reset(new mp4::MP4MediaParser());
break;
default:
NOTIMPLEMENTED();
return Status(error::UNIMPLEMENTED, "Container not supported.");
}
parser_->Init(
base::Bind(&Demuxer::ParserInitEvent, base::Unretained(this)),
base::Bind(&Demuxer::NewSampleEvent, base::Unretained(this)),
base::Bind(&Demuxer::KeyNeededEvent, base::Unretained(this)));
if (!parser_->Parse(buffer_.get(), bytes_read))
return Status(error::PARSER_FAILURE,
"Cannot parse media file " + file_name_);
// TODO(kqyang): Does not look clean. Consider refactoring later.
Status status;
while (!init_event_received_) {
if (!(status = Parse()).ok()) break;
}
return status;
}
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));
}
}
bool Demuxer::NewSampleEvent(
uint32 track_id, const scoped_refptr<MediaSample>& sample) {
std::vector<MediaStream*>::iterator it = streams_.begin();
for (; it != streams_.end(); ++it) {
if (track_id == (*it)->info()->track_id()) {
return (*it)->PushSample(sample).ok();
}
}
return false;
}
void Demuxer::KeyNeededEvent(
MediaContainerName container, scoped_ptr<uint8[]> init_data,
int init_data_size) {
NOTIMPLEMENTED();
}
Status Demuxer::Run() {
Status status;
// 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;
}
while ((status = Parse()).ok()) continue;
return status.Matches(Status(error::EOF, "")) ? Status::OK : status;
}
Status Demuxer::Parse() {
DCHECK(media_file_ != NULL);
DCHECK(parser_ != NULL);
DCHECK(buffer_ != NULL);
int64 bytes_read = media_file_->Read(buffer_.get(), kBufSize);
if (bytes_read <= 0) {
return media_file_->Eof() ?
Status(error::EOF, "End of file") :
Status(error::FILE_FAILURE, "Cannot read file " + file_name_);
}
return parser_->Parse(buffer_.get(), bytes_read)
? Status::OK
: Status(error::PARSER_FAILURE,
"Cannot parse media file " + file_name_);
}
} // namespace media