7 #include "packager/media/demuxer/demuxer.h"
11 #include "packager/base/bind.h"
12 #include "packager/base/logging.h"
13 #include "packager/base/strings/string_number_conversions.h"
14 #include "packager/file/file.h"
15 #include "packager/media/base/decryptor_source.h"
16 #include "packager/media/base/key_source.h"
17 #include "packager/media/base/macros.h"
18 #include "packager/media/base/media_sample.h"
19 #include "packager/media/base/stream_info.h"
20 #include "packager/media/formats/mp2t/mp2t_media_parser.h"
21 #include "packager/media/formats/mp4/mp4_media_parser.h"
22 #include "packager/media/formats/webm/webm_media_parser.h"
23 #include "packager/media/formats/webvtt/webvtt_parser.h"
24 #include "packager/media/formats/wvm/wvm_media_parser.h"
28 const size_t kInitBufSize = 0x10000;
29 const size_t kBufSize = 0x200000;
33 const size_t kQueuedSamplesLimit = 10000;
34 const size_t kInvalidStreamIndex =
static_cast<size_t>(-1);
35 const size_t kBaseVideoOutputStreamIndex = 0x100;
36 const size_t kBaseAudioOutputStreamIndex = 0x200;
37 const size_t kBaseTextOutputStreamIndex = 0x300;
39 std::string GetStreamLabel(
size_t stream_index) {
40 switch (stream_index) {
41 case kBaseVideoOutputStreamIndex:
43 case kBaseAudioOutputStreamIndex:
45 case kBaseTextOutputStreamIndex:
48 return base::SizeTToString(stream_index);
52 bool GetStreamIndex(
const std::string& stream_label,
size_t* stream_index) {
54 if (stream_label ==
"video") {
55 *stream_index = kBaseVideoOutputStreamIndex;
56 }
else if (stream_label ==
"audio") {
57 *stream_index = kBaseAudioOutputStreamIndex;
58 }
else if (stream_label ==
"text") {
59 *stream_index = kBaseTextOutputStreamIndex;
62 if (!base::StringToSizeT(stream_label, stream_index)) {
63 LOG(ERROR) <<
"Invalid argument --stream=" << stream_label <<
"; "
64 <<
"should be 'audio', 'video', 'text', or a number";
77 : file_name_(file_name), buffer_(new uint8_t[kBufSize]) {}
85 key_source_ = std::move(key_source);
89 LOG(INFO) <<
"Demuxer::Run() on file '" << file_name_ <<
"'.";
90 Status status = InitializeParser();
93 while (!all_streams_ready_ && status.ok())
97 if (all_streams_ready_ && output_handlers().empty())
99 if (!init_event_status_.ok())
100 return init_event_status_;
104 for (
const auto& pair : output_handlers()) {
105 if (std::find(stream_indexes_.begin(), stream_indexes_.end(), pair.first) ==
106 stream_indexes_.end()) {
107 LOG(ERROR) <<
"Invalid argument, stream=" << GetStreamLabel(pair.first)
108 <<
" not available.";
109 return Status(error::INVALID_ARGUMENT,
"Stream not available");
113 while (!cancelled_ && status.ok())
115 if (cancelled_ && status.ok())
116 return Status(error::CANCELLED,
"Demuxer run cancelled");
118 if (status.error_code() == error::END_OF_STREAM) {
119 for (
size_t stream_index : stream_indexes_) {
134 std::shared_ptr<MediaHandler> handler) {
135 size_t stream_index = kInvalidStreamIndex;
136 if (!GetStreamIndex(stream_label, &stream_index)) {
137 return Status(error::INVALID_ARGUMENT,
138 "Invalid stream: " + stream_label);
144 const std::string& language_override) {
145 size_t stream_index = kInvalidStreamIndex;
146 if (!GetStreamIndex(stream_label, &stream_index))
147 LOG(WARNING) <<
"Invalid stream for language override " << stream_label;
148 language_overrides_[stream_index] = language_override;
151 Status Demuxer::InitializeParser() {
152 DCHECK(!media_file_);
153 DCHECK(!all_streams_ready_);
155 LOG(INFO) <<
"Initialize Demuxer for file '" << file_name_ <<
"'.";
157 media_file_ =
File::Open(file_name_.c_str(),
"r");
159 return Status(error::FILE_FAILURE,
160 "Cannot open file for reading " + file_name_);
164 int64_t bytes_read = 0;
165 while (
static_cast<size_t>(bytes_read) < kInitBufSize) {
166 int64_t read_result =
167 media_file_->
Read(buffer_.get() + bytes_read, kInitBufSize);
169 return Status(error::FILE_FAILURE,
"Cannot read file " + file_name_);
170 if (read_result == 0)
172 bytes_read += read_result;
174 container_name_ = DetermineContainer(buffer_.get(), bytes_read);
177 switch (container_name_) {
179 parser_.reset(
new mp4::MP4MediaParser());
181 case CONTAINER_MPEG2TS:
182 parser_.reset(
new mp2t::Mp2tMediaParser());
189 case CONTAINER_MPEG2PS:
190 FALLTHROUGH_INTENDED;
192 parser_.reset(
new wvm::WvmMediaParser());
195 parser_.reset(
new WebMMediaParser());
197 case CONTAINER_WEBVTT:
198 parser_.reset(
new WebVttParser());
200 case CONTAINER_UNKNOWN: {
201 const int64_t kDumpSizeLimit = 512;
202 LOG(ERROR) <<
"Failed to detect the container type from the buffer: "
203 << base::HexEncode(buffer_.get(),
204 std::min(bytes_read, kDumpSizeLimit));
205 return Status(error::INVALID_ARGUMENT,
206 "Failed to detect the container type.");
209 NOTIMPLEMENTED() <<
"Container " << container_name_
210 <<
" is not supported.";
211 return Status(error::UNIMPLEMENTED,
"Container not supported.");
215 base::Bind(&Demuxer::ParserInitEvent, base::Unretained(
this)),
216 base::Bind(&Demuxer::NewMediaSampleEvent, base::Unretained(
this)),
217 base::Bind(&Demuxer::NewTextSampleEvent, base::Unretained(
this)),
221 if (container_name_ == CONTAINER_MOV &&
225 static_cast<mp4::MP4MediaParser*
>(parser_.get())->LoadMoov(file_name_);
227 if (!parser_->Parse(buffer_.get(), bytes_read)) {
228 return Status(error::PARSER_FAILURE,
229 "Cannot parse media file " + file_name_);
234 void Demuxer::ParserInitEvent(
235 const std::vector<std::shared_ptr<StreamInfo>>& stream_infos) {
236 if (dump_stream_info_) {
237 printf(
"\nFile \"%s\":\n", file_name_.c_str());
238 printf(
"Found %zu stream(s).\n", stream_infos.size());
239 for (
size_t i = 0; i < stream_infos.size(); ++i)
240 printf(
"Stream [%zu] %s\n", i, stream_infos[i]->ToString().c_str());
243 int base_stream_index = 0;
244 bool video_handler_set =
245 output_handlers().find(kBaseVideoOutputStreamIndex) !=
246 output_handlers().end();
247 bool audio_handler_set =
248 output_handlers().find(kBaseAudioOutputStreamIndex) !=
249 output_handlers().end();
250 bool text_handler_set =
251 output_handlers().find(kBaseTextOutputStreamIndex) !=
252 output_handlers().end();
253 for (
const std::shared_ptr<StreamInfo>& stream_info : stream_infos) {
254 size_t stream_index = base_stream_index;
255 if (video_handler_set && stream_info->stream_type() == kStreamVideo) {
256 stream_index = kBaseVideoOutputStreamIndex;
258 video_handler_set =
false;
260 if (audio_handler_set && stream_info->stream_type() == kStreamAudio) {
261 stream_index = kBaseAudioOutputStreamIndex;
263 audio_handler_set =
false;
265 if (text_handler_set && stream_info->stream_type() == kStreamText) {
266 stream_index = kBaseTextOutputStreamIndex;
267 text_handler_set =
false;
270 const bool handler_set =
271 output_handlers().find(stream_index) != output_handlers().end();
273 track_id_to_stream_index_map_[stream_info->track_id()] = stream_index;
274 stream_indexes_.push_back(stream_index);
275 auto iter = language_overrides_.find(stream_index);
276 if (iter != language_overrides_.end() &&
277 stream_info->stream_type() != kStreamVideo) {
278 stream_info->set_language(iter->second);
280 if (stream_info->is_encrypted()) {
281 init_event_status_.
Update(Status(error::INVALID_ARGUMENT,
282 "A decryption key source is not "
283 "provided for an encrypted stream."));
285 init_event_status_.
Update(
289 track_id_to_stream_index_map_[stream_info->track_id()] =
294 all_streams_ready_ =
true;
297 bool Demuxer::NewMediaSampleEvent(uint32_t track_id,
298 std::shared_ptr<MediaSample> sample) {
299 if (!all_streams_ready_) {
300 if (queued_media_samples_.size() >= kQueuedSamplesLimit) {
301 LOG(ERROR) <<
"Queued samples limit reached: " << kQueuedSamplesLimit;
304 queued_media_samples_.emplace_back(track_id, sample);
307 if (!init_event_status_.ok()) {
311 while (!queued_media_samples_.empty()) {
312 if (!PushMediaSample(queued_media_samples_.front().track_id,
313 queued_media_samples_.front().sample)) {
316 queued_media_samples_.pop_front();
318 return PushMediaSample(track_id, sample);
321 bool Demuxer::NewTextSampleEvent(uint32_t track_id,
322 std::shared_ptr<TextSample> sample) {
323 if (!all_streams_ready_) {
324 if (queued_text_samples_.size() >= kQueuedSamplesLimit) {
325 LOG(ERROR) <<
"Queued samples limit reached: " << kQueuedSamplesLimit;
328 queued_text_samples_.emplace_back(track_id, sample);
331 if (!init_event_status_.ok()) {
335 while (!queued_text_samples_.empty()) {
336 if (!PushTextSample(queued_text_samples_.front().track_id,
337 queued_text_samples_.front().sample)) {
340 queued_text_samples_.pop_front();
342 return PushTextSample(track_id, sample);
345 bool Demuxer::PushMediaSample(uint32_t track_id,
346 std::shared_ptr<MediaSample> sample) {
347 auto stream_index_iter = track_id_to_stream_index_map_.find(track_id);
348 if (stream_index_iter == track_id_to_stream_index_map_.end()) {
349 LOG(ERROR) <<
"Track " << track_id <<
" not found.";
352 if (stream_index_iter->second == kInvalidStreamIndex)
356 LOG(ERROR) <<
"Failed to process sample " << stream_index_iter->second
363 bool Demuxer::PushTextSample(uint32_t track_id,
364 std::shared_ptr<TextSample> sample) {
365 auto stream_index_iter = track_id_to_stream_index_map_.find(track_id);
366 if (stream_index_iter == track_id_to_stream_index_map_.end()) {
367 LOG(ERROR) <<
"Track " << track_id <<
" not found.";
370 if (stream_index_iter->second == kInvalidStreamIndex)
374 LOG(ERROR) <<
"Failed to process sample " << stream_index_iter->second
381 Status Demuxer::Parse() {
386 int64_t bytes_read = media_file_->
Read(buffer_.get(), kBufSize);
387 if (bytes_read == 0) {
388 if (!parser_->Flush())
389 return Status(error::PARSER_FAILURE,
"Failed to flush.");
390 return Status(error::END_OF_STREAM,
"");
391 }
else if (bytes_read < 0) {
392 return Status(error::FILE_FAILURE,
"Cannot read file " + file_name_);
395 return parser_->Parse(buffer_.get(), bytes_read)
397 : Status(error::PARSER_FAILURE,
398 "Cannot parse media file " + file_name_);
virtual bool Open()=0
Internal open. Should not be used directly.
virtual int64_t Read(void *buffer, uint64_t length)=0
static bool IsLocalRegularFile(const char *file_name)
void Update(Status new_status)
All the methods that are virtual are virtual for mocking.