7#include <packager/media/demuxer/demuxer.h>
19#include <absl/log/check.h>
20#include <absl/log/log.h>
21#include <absl/strings/escaping.h>
22#include <absl/strings/numbers.h>
23#include <absl/strings/str_format.h>
24#include <absl/strings/string_view.h>
26#include <packager/file.h>
27#include <packager/macros/compiler.h>
28#include <packager/macros/logging.h>
29#include <packager/media/base/container_names.h>
30#include <packager/media/base/key_source.h>
31#include <packager/media/base/media_handler.h>
32#include <packager/media/base/media_sample.h>
33#include <packager/media/base/stream_info.h>
34#include <packager/media/base/text_sample.h>
35#include <packager/media/formats/mp2t/mp2t_media_parser.h>
36#include <packager/media/formats/mp4/mp4_media_parser.h>
37#include <packager/media/formats/webm/webm_media_parser.h>
38#include <packager/media/formats/webvtt/webvtt_parser.h>
39#include <packager/media/formats/wvm/wvm_media_parser.h>
40#include <packager/status.h>
44const size_t kInitBufSize = 0x10000;
45const size_t kBufSize = 0x200000;
49const size_t kQueuedSamplesLimit = 10000;
50const size_t kInvalidStreamIndex =
static_cast<size_t>(-1);
51const size_t kBaseVideoOutputStreamIndex = 0x100;
52const size_t kBaseAudioOutputStreamIndex = 0x200;
53const size_t kBaseTextOutputStreamIndex = 0x300;
55std::string GetStreamLabel(
size_t stream_index) {
56 switch (stream_index) {
57 case kBaseVideoOutputStreamIndex:
59 case kBaseAudioOutputStreamIndex:
61 case kBaseTextOutputStreamIndex:
64 return absl::StrFormat(
"%u", stream_index);
68bool GetStreamIndex(
const std::string& stream_label,
size_t* stream_index) {
70 if (stream_label ==
"video") {
71 *stream_index = kBaseVideoOutputStreamIndex;
72 }
else if (stream_label ==
"audio") {
73 *stream_index = kBaseAudioOutputStreamIndex;
74 }
else if (stream_label ==
"text") {
75 *stream_index = kBaseTextOutputStreamIndex;
78 if (!absl::SimpleAtoi(stream_label, stream_index)) {
79 LOG(ERROR) <<
"Invalid argument --stream=" << stream_label <<
"; "
80 <<
"should be 'audio', 'video', 'text', or a number";
93 : file_name_(file_name), buffer_(new uint8_t[kBufSize]) {}
101 key_source_ = std::move(key_source);
105 LOG(INFO) <<
"Demuxer::Run() on file '" << file_name_ <<
"'.";
106 Status status = InitializeParser();
109 while (!all_streams_ready_ && status.ok())
110 status.Update(Parse());
113 if (all_streams_ready_ && output_handlers().empty())
115 if (!init_event_status_.ok())
116 return init_event_status_;
120 for (
const auto& pair : output_handlers()) {
121 if (std::find(stream_indexes_.begin(), stream_indexes_.end(), pair.first) ==
122 stream_indexes_.end()) {
123 LOG(ERROR) <<
"Invalid argument, stream=" << GetStreamLabel(pair.first)
124 <<
" not available.";
125 return Status(error::INVALID_ARGUMENT,
"Stream not available");
129 while (!cancelled_ && status.ok())
130 status.Update(Parse());
131 if (cancelled_ && status.ok())
132 return Status(error::CANCELLED,
"Demuxer run cancelled");
134 if (status.error_code() == error::END_OF_STREAM) {
135 for (
size_t stream_index : stream_indexes_) {
150 std::shared_ptr<MediaHandler> handler) {
151 size_t stream_index = kInvalidStreamIndex;
152 if (!GetStreamIndex(stream_label, &stream_index)) {
153 return Status(error::INVALID_ARGUMENT,
"Invalid stream: " + stream_label);
159 const std::string& language_override) {
160 size_t stream_index = kInvalidStreamIndex;
161 if (!GetStreamIndex(stream_label, &stream_index))
162 LOG(WARNING) <<
"Invalid stream for language override " << stream_label;
163 language_overrides_[stream_index] = language_override;
166Status Demuxer::InitializeParser() {
167 DCHECK(!media_file_);
168 DCHECK(!all_streams_ready_);
170 LOG(INFO) <<
"Initialize Demuxer for file '" << file_name_ <<
"'.";
172 media_file_ = File::Open(file_name_.c_str(),
"r");
174 return Status(error::FILE_FAILURE,
175 "Cannot open file for reading " + file_name_);
178 int64_t bytes_read = 0;
180 if (input_format_.empty()) {
182 while (
static_cast<size_t>(bytes_read) < kInitBufSize) {
183 int64_t read_result =
184 media_file_->Read(buffer_.get() + bytes_read, kInitBufSize);
186 return Status(error::FILE_FAILURE,
"Cannot read file " + file_name_);
187 if (read_result == 0) {
191 bytes_read += read_result;
193 container_name_ = DetermineContainer(buffer_.get(), bytes_read);
195 container_name_ = DetermineContainerFromFormatName(input_format_);
199 switch (container_name_) {
201 parser_.reset(
new mp4::MP4MediaParser());
203 case CONTAINER_MPEG2TS:
204 parser_.reset(
new mp2t::Mp2tMediaParser());
211 case CONTAINER_MPEG2PS:
212 FALLTHROUGH_INTENDED;
214 parser_.reset(
new wvm::WvmMediaParser());
217 parser_.reset(
new WebMMediaParser());
219 case CONTAINER_WEBVTT:
220 parser_.reset(
new WebVttParser());
222 case CONTAINER_UNKNOWN: {
223 const int64_t kDumpSizeLimit = 512;
224 LOG(ERROR) <<
"Failed to detect the container type from the buffer: "
225 << absl::BytesToHexString(absl::string_view(
226 reinterpret_cast<const char*
>(buffer_.get()),
227 std::min(bytes_read, kDumpSizeLimit)));
228 return Status(error::INVALID_ARGUMENT,
229 "Failed to detect the container type.");
232 NOTIMPLEMENTED() <<
"Container " << container_name_
233 <<
" is not supported.";
234 return Status(error::UNIMPLEMENTED,
"Container not supported.");
238 std::bind(&Demuxer::ParserInitEvent,
this, std::placeholders::_1),
239 std::bind(&Demuxer::NewMediaSampleEvent,
this, std::placeholders::_1,
240 std::placeholders::_2),
241 std::bind(&Demuxer::NewTextSampleEvent,
this, std::placeholders::_1,
242 std::placeholders::_2),
246 if (container_name_ == CONTAINER_MOV &&
247 File::IsLocalRegularFile(file_name_.c_str())) {
250 static_cast<mp4::MP4MediaParser*
>(parser_.get())->LoadMoov(file_name_);
252 if (!parser_->Parse(buffer_.get(), bytes_read) ||
253 (eof && !parser_->Flush())) {
254 return Status(error::PARSER_FAILURE,
255 "Cannot parse media file " + file_name_);
260void Demuxer::ParserInitEvent(
261 const std::vector<std::shared_ptr<StreamInfo>>& stream_infos) {
262 if (dump_stream_info_) {
263 printf(
"\nFile \"%s\":\n", file_name_.c_str());
264 printf(
"Found %zu stream(s).\n", stream_infos.size());
265 for (
size_t i = 0; i < stream_infos.size(); ++i)
266 printf(
"Stream [%zu] %s\n", i, stream_infos[i]->ToString().c_str());
269 int base_stream_index = 0;
270 bool video_handler_set =
271 output_handlers().find(kBaseVideoOutputStreamIndex) !=
272 output_handlers().end();
273 bool audio_handler_set =
274 output_handlers().find(kBaseAudioOutputStreamIndex) !=
275 output_handlers().end();
276 bool text_handler_set = output_handlers().find(kBaseTextOutputStreamIndex) !=
277 output_handlers().end();
278 for (
const std::shared_ptr<StreamInfo>& stream_info : stream_infos) {
279 size_t stream_index = base_stream_index;
280 if (video_handler_set && stream_info->stream_type() == kStreamVideo) {
281 stream_index = kBaseVideoOutputStreamIndex;
283 video_handler_set =
false;
285 if (audio_handler_set && stream_info->stream_type() == kStreamAudio) {
286 stream_index = kBaseAudioOutputStreamIndex;
288 audio_handler_set =
false;
290 if (text_handler_set && stream_info->stream_type() == kStreamText) {
291 stream_index = kBaseTextOutputStreamIndex;
292 text_handler_set =
false;
295 const bool handler_set =
296 output_handlers().find(stream_index) != output_handlers().end();
298 track_id_to_stream_index_map_[stream_info->track_id()] = stream_index;
299 stream_indexes_.push_back(stream_index);
300 auto iter = language_overrides_.find(stream_index);
301 if (iter != language_overrides_.end() &&
302 stream_info->stream_type() != kStreamVideo) {
303 stream_info->set_language(iter->second);
305 if (stream_info->is_encrypted()) {
306 init_event_status_.Update(Status(error::INVALID_ARGUMENT,
307 "A decryption key source is not "
308 "provided for an encrypted stream."));
310 init_event_status_.Update(
314 track_id_to_stream_index_map_[stream_info->track_id()] =
319 all_streams_ready_ =
true;
322bool Demuxer::NewMediaSampleEvent(uint32_t track_id,
323 std::shared_ptr<MediaSample> sample) {
324 if (!all_streams_ready_) {
325 if (queued_media_samples_.size() >= kQueuedSamplesLimit) {
326 LOG(ERROR) <<
"Queued samples limit reached: " << kQueuedSamplesLimit;
329 queued_media_samples_.emplace_back(track_id, sample);
332 if (!init_event_status_.ok()) {
336 while (!queued_media_samples_.empty()) {
337 if (!PushMediaSample(queued_media_samples_.front().track_id,
338 queued_media_samples_.front().sample)) {
341 queued_media_samples_.pop_front();
343 return PushMediaSample(track_id, sample);
346bool Demuxer::NewTextSampleEvent(uint32_t track_id,
347 std::shared_ptr<TextSample> sample) {
348 if (!all_streams_ready_) {
349 if (queued_text_samples_.size() >= kQueuedSamplesLimit) {
350 LOG(ERROR) <<
"Queued samples limit reached: " << kQueuedSamplesLimit;
353 queued_text_samples_.emplace_back(track_id, sample);
356 if (!init_event_status_.ok()) {
360 while (!queued_text_samples_.empty()) {
361 if (!PushTextSample(queued_text_samples_.front().track_id,
362 queued_text_samples_.front().sample)) {
365 queued_text_samples_.pop_front();
367 return PushTextSample(track_id, sample);
370bool Demuxer::PushMediaSample(uint32_t track_id,
371 std::shared_ptr<MediaSample> sample) {
372 auto stream_index_iter = track_id_to_stream_index_map_.find(track_id);
373 if (stream_index_iter == track_id_to_stream_index_map_.end()) {
374 LOG(ERROR) <<
"Track " << track_id <<
" not found.";
377 if (stream_index_iter->second == kInvalidStreamIndex)
381 LOG(ERROR) <<
"Failed to process sample " << stream_index_iter->second
388bool Demuxer::PushTextSample(uint32_t track_id,
389 std::shared_ptr<TextSample> sample) {
390 auto stream_index_iter = track_id_to_stream_index_map_.find(track_id);
391 if (stream_index_iter == track_id_to_stream_index_map_.end()) {
392 LOG(ERROR) <<
"Track " << track_id <<
" not found.";
395 if (stream_index_iter->second == kInvalidStreamIndex)
399 LOG(ERROR) <<
"Failed to process sample " << stream_index_iter->second
406Status Demuxer::Parse() {
411 int64_t bytes_read = media_file_->Read(buffer_.get(), kBufSize);
412 if (bytes_read == 0) {
413 if (!parser_->Flush())
414 return Status(error::PARSER_FAILURE,
"Failed to flush.");
415 return Status(error::END_OF_STREAM,
"");
416 }
else if (bytes_read < 0) {
417 return Status(error::FILE_FAILURE,
"Cannot read file " + file_name_);
420 return parser_->Parse(buffer_.get(), bytes_read)
422 : Status(error::PARSER_FAILURE,
423 "Cannot parse media file " + file_name_);
All the methods that are virtual are virtual for mocking.