7 #include <packager/media/demuxer/demuxer.h>
12 #include <absl/log/check.h>
13 #include <absl/log/log.h>
14 #include <absl/strings/escaping.h>
15 #include <absl/strings/numbers.h>
16 #include <absl/strings/str_format.h>
18 #include <packager/file.h>
19 #include <packager/macros/compiler.h>
20 #include <packager/macros/logging.h>
21 #include <packager/media/base/decryptor_source.h>
22 #include <packager/media/base/key_source.h>
23 #include <packager/media/base/media_sample.h>
24 #include <packager/media/base/stream_info.h>
25 #include <packager/media/formats/mp2t/mp2t_media_parser.h>
26 #include <packager/media/formats/mp4/mp4_media_parser.h>
27 #include <packager/media/formats/webm/webm_media_parser.h>
28 #include <packager/media/formats/webvtt/webvtt_parser.h>
29 #include <packager/media/formats/wvm/wvm_media_parser.h>
33 const size_t kInitBufSize = 0x10000;
34 const size_t kBufSize = 0x200000;
38 const size_t kQueuedSamplesLimit = 10000;
39 const size_t kInvalidStreamIndex =
static_cast<size_t>(-1);
40 const size_t kBaseVideoOutputStreamIndex = 0x100;
41 const size_t kBaseAudioOutputStreamIndex = 0x200;
42 const size_t kBaseTextOutputStreamIndex = 0x300;
44 std::string GetStreamLabel(
size_t stream_index) {
45 switch (stream_index) {
46 case kBaseVideoOutputStreamIndex:
48 case kBaseAudioOutputStreamIndex:
50 case kBaseTextOutputStreamIndex:
53 return absl::StrFormat(
"%u", stream_index);
57 bool GetStreamIndex(
const std::string& stream_label,
size_t* stream_index) {
59 if (stream_label ==
"video") {
60 *stream_index = kBaseVideoOutputStreamIndex;
61 }
else if (stream_label ==
"audio") {
62 *stream_index = kBaseAudioOutputStreamIndex;
63 }
else if (stream_label ==
"text") {
64 *stream_index = kBaseTextOutputStreamIndex;
67 if (!absl::SimpleAtoi(stream_label, stream_index)) {
68 LOG(ERROR) <<
"Invalid argument --stream=" << stream_label <<
"; "
69 <<
"should be 'audio', 'video', 'text', or a number";
82 : file_name_(file_name), buffer_(new uint8_t[kBufSize]) {}
90 key_source_ = std::move(key_source);
94 LOG(INFO) <<
"Demuxer::Run() on file '" << file_name_ <<
"'.";
95 Status status = InitializeParser();
98 while (!all_streams_ready_ && status.ok())
99 status.Update(Parse());
102 if (all_streams_ready_ && output_handlers().empty())
104 if (!init_event_status_.ok())
105 return init_event_status_;
109 for (
const auto& pair : output_handlers()) {
110 if (std::find(stream_indexes_.begin(), stream_indexes_.end(), pair.first) ==
111 stream_indexes_.end()) {
112 LOG(ERROR) <<
"Invalid argument, stream=" << GetStreamLabel(pair.first)
113 <<
" not available.";
114 return Status(error::INVALID_ARGUMENT,
"Stream not available");
118 while (!cancelled_ && status.ok())
119 status.Update(Parse());
120 if (cancelled_ && status.ok())
121 return Status(error::CANCELLED,
"Demuxer run cancelled");
123 if (status.error_code() == error::END_OF_STREAM) {
124 for (
size_t stream_index : stream_indexes_) {
139 std::shared_ptr<MediaHandler> handler) {
140 size_t stream_index = kInvalidStreamIndex;
141 if (!GetStreamIndex(stream_label, &stream_index)) {
142 return Status(error::INVALID_ARGUMENT,
143 "Invalid stream: " + stream_label);
149 const std::string& language_override) {
150 size_t stream_index = kInvalidStreamIndex;
151 if (!GetStreamIndex(stream_label, &stream_index))
152 LOG(WARNING) <<
"Invalid stream for language override " << stream_label;
153 language_overrides_[stream_index] = language_override;
156 Status Demuxer::InitializeParser() {
157 DCHECK(!media_file_);
158 DCHECK(!all_streams_ready_);
160 LOG(INFO) <<
"Initialize Demuxer for file '" << file_name_ <<
"'.";
162 media_file_ = File::Open(file_name_.c_str(),
"r");
164 return Status(error::FILE_FAILURE,
165 "Cannot open file for reading " + file_name_);
168 int64_t bytes_read = 0;
170 if (input_format_.empty()) {
172 while (
static_cast<size_t>(bytes_read) < kInitBufSize) {
173 int64_t read_result =
174 media_file_->Read(buffer_.get() + bytes_read, kInitBufSize);
176 return Status(error::FILE_FAILURE,
"Cannot read file " + file_name_);
177 if (read_result == 0) {
181 bytes_read += read_result;
183 container_name_ = DetermineContainer(buffer_.get(), bytes_read);
185 container_name_ = DetermineContainerFromFormatName(input_format_);
189 switch (container_name_) {
191 parser_.reset(
new mp4::MP4MediaParser());
193 case CONTAINER_MPEG2TS:
194 parser_.reset(
new mp2t::Mp2tMediaParser());
201 case CONTAINER_MPEG2PS:
202 FALLTHROUGH_INTENDED;
204 parser_.reset(
new wvm::WvmMediaParser());
207 parser_.reset(
new WebMMediaParser());
209 case CONTAINER_WEBVTT:
210 parser_.reset(
new WebVttParser());
212 case CONTAINER_UNKNOWN: {
213 const int64_t kDumpSizeLimit = 512;
214 LOG(ERROR) <<
"Failed to detect the container type from the buffer: "
215 << absl::BytesToHexString(absl::string_view(
216 reinterpret_cast<const char*
>(buffer_.get()),
217 std::min(bytes_read, kDumpSizeLimit)));
218 return Status(error::INVALID_ARGUMENT,
219 "Failed to detect the container type.");
222 NOTIMPLEMENTED() <<
"Container " << container_name_
223 <<
" is not supported.";
224 return Status(error::UNIMPLEMENTED,
"Container not supported.");
228 std::bind(&Demuxer::ParserInitEvent,
this, std::placeholders::_1),
229 std::bind(&Demuxer::NewMediaSampleEvent,
this, std::placeholders::_1,
230 std::placeholders::_2),
231 std::bind(&Demuxer::NewTextSampleEvent,
this, std::placeholders::_1,
232 std::placeholders::_2),
236 if (container_name_ == CONTAINER_MOV &&
237 File::IsLocalRegularFile(file_name_.c_str())) {
240 static_cast<mp4::MP4MediaParser*
>(parser_.get())->LoadMoov(file_name_);
242 if (!parser_->Parse(buffer_.get(), bytes_read) || (eof && !parser_->Flush())) {
243 return Status(error::PARSER_FAILURE,
244 "Cannot parse media file " + file_name_);
249 void Demuxer::ParserInitEvent(
250 const std::vector<std::shared_ptr<StreamInfo>>& stream_infos) {
251 if (dump_stream_info_) {
252 printf(
"\nFile \"%s\":\n", file_name_.c_str());
253 printf(
"Found %zu stream(s).\n", stream_infos.size());
254 for (
size_t i = 0; i < stream_infos.size(); ++i)
255 printf(
"Stream [%zu] %s\n", i, stream_infos[i]->ToString().c_str());
258 int base_stream_index = 0;
259 bool video_handler_set =
260 output_handlers().find(kBaseVideoOutputStreamIndex) !=
261 output_handlers().end();
262 bool audio_handler_set =
263 output_handlers().find(kBaseAudioOutputStreamIndex) !=
264 output_handlers().end();
265 bool text_handler_set =
266 output_handlers().find(kBaseTextOutputStreamIndex) !=
267 output_handlers().end();
268 for (
const std::shared_ptr<StreamInfo>& stream_info : stream_infos) {
269 size_t stream_index = base_stream_index;
270 if (video_handler_set && stream_info->stream_type() == kStreamVideo) {
271 stream_index = kBaseVideoOutputStreamIndex;
273 video_handler_set =
false;
275 if (audio_handler_set && stream_info->stream_type() == kStreamAudio) {
276 stream_index = kBaseAudioOutputStreamIndex;
278 audio_handler_set =
false;
280 if (text_handler_set && stream_info->stream_type() == kStreamText) {
281 stream_index = kBaseTextOutputStreamIndex;
282 text_handler_set =
false;
285 const bool handler_set =
286 output_handlers().find(stream_index) != output_handlers().end();
288 track_id_to_stream_index_map_[stream_info->track_id()] = stream_index;
289 stream_indexes_.push_back(stream_index);
290 auto iter = language_overrides_.find(stream_index);
291 if (iter != language_overrides_.end() &&
292 stream_info->stream_type() != kStreamVideo) {
293 stream_info->set_language(iter->second);
295 if (stream_info->is_encrypted()) {
296 init_event_status_.Update(Status(error::INVALID_ARGUMENT,
297 "A decryption key source is not "
298 "provided for an encrypted stream."));
300 init_event_status_.Update(
304 track_id_to_stream_index_map_[stream_info->track_id()] =
309 all_streams_ready_ =
true;
312 bool Demuxer::NewMediaSampleEvent(uint32_t track_id,
313 std::shared_ptr<MediaSample> sample) {
314 if (!all_streams_ready_) {
315 if (queued_media_samples_.size() >= kQueuedSamplesLimit) {
316 LOG(ERROR) <<
"Queued samples limit reached: " << kQueuedSamplesLimit;
319 queued_media_samples_.emplace_back(track_id, sample);
322 if (!init_event_status_.ok()) {
326 while (!queued_media_samples_.empty()) {
327 if (!PushMediaSample(queued_media_samples_.front().track_id,
328 queued_media_samples_.front().sample)) {
331 queued_media_samples_.pop_front();
333 return PushMediaSample(track_id, sample);
336 bool Demuxer::NewTextSampleEvent(uint32_t track_id,
337 std::shared_ptr<TextSample> sample) {
338 if (!all_streams_ready_) {
339 if (queued_text_samples_.size() >= kQueuedSamplesLimit) {
340 LOG(ERROR) <<
"Queued samples limit reached: " << kQueuedSamplesLimit;
343 queued_text_samples_.emplace_back(track_id, sample);
346 if (!init_event_status_.ok()) {
350 while (!queued_text_samples_.empty()) {
351 if (!PushTextSample(queued_text_samples_.front().track_id,
352 queued_text_samples_.front().sample)) {
355 queued_text_samples_.pop_front();
357 return PushTextSample(track_id, sample);
360 bool Demuxer::PushMediaSample(uint32_t track_id,
361 std::shared_ptr<MediaSample> sample) {
362 auto stream_index_iter = track_id_to_stream_index_map_.find(track_id);
363 if (stream_index_iter == track_id_to_stream_index_map_.end()) {
364 LOG(ERROR) <<
"Track " << track_id <<
" not found.";
367 if (stream_index_iter->second == kInvalidStreamIndex)
371 LOG(ERROR) <<
"Failed to process sample " << stream_index_iter->second
378 bool Demuxer::PushTextSample(uint32_t track_id,
379 std::shared_ptr<TextSample> sample) {
380 auto stream_index_iter = track_id_to_stream_index_map_.find(track_id);
381 if (stream_index_iter == track_id_to_stream_index_map_.end()) {
382 LOG(ERROR) <<
"Track " << track_id <<
" not found.";
385 if (stream_index_iter->second == kInvalidStreamIndex)
389 LOG(ERROR) <<
"Failed to process sample " << stream_index_iter->second
396 Status Demuxer::Parse() {
401 int64_t bytes_read = media_file_->Read(buffer_.get(), kBufSize);
402 if (bytes_read == 0) {
403 if (!parser_->Flush())
404 return Status(error::PARSER_FAILURE,
"Failed to flush.");
405 return Status(error::END_OF_STREAM,
"");
406 }
else if (bytes_read < 0) {
407 return Status(error::FILE_FAILURE,
"Cannot read file " + file_name_);
410 return parser_->Parse(buffer_.get(), bytes_read)
412 : Status(error::PARSER_FAILURE,
413 "Cannot parse media file " + file_name_);
All the methods that are virtual are virtual for mocking.