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/wvm/wvm_media_parser.h" 27 const size_t kInitBufSize = 0x10000;
28 const size_t kBufSize = 0x200000;
32 const size_t kQueuedSamplesLimit = 10000;
33 const size_t kInvalidStreamIndex =
static_cast<size_t>(-1);
34 const size_t kBaseVideoOutputStreamIndex = 0x100;
35 const size_t kBaseAudioOutputStreamIndex = 0x200;
36 const size_t kBaseTextOutputStreamIndex = 0x300;
38 std::string GetStreamLabel(
size_t stream_index) {
39 switch (stream_index) {
40 case kBaseVideoOutputStreamIndex:
42 case kBaseAudioOutputStreamIndex:
44 case kBaseTextOutputStreamIndex:
47 return base::SizeTToString(stream_index);
51 bool GetStreamIndex(
const std::string& stream_label,
size_t* stream_index) {
53 if (stream_label ==
"video") {
54 *stream_index = kBaseVideoOutputStreamIndex;
55 }
else if (stream_label ==
"audio") {
56 *stream_index = kBaseAudioOutputStreamIndex;
57 }
else if (stream_label ==
"text") {
58 *stream_index = kBaseTextOutputStreamIndex;
61 if (!base::StringToSizeT(stream_label, stream_index)) {
62 LOG(ERROR) <<
"Invalid argument --stream=" << stream_label <<
"; " 63 <<
"should be 'audio', 'video', 'text', or a number";
76 : file_name_(file_name), buffer_(new uint8_t[kBufSize]) {}
84 key_source_ = std::move(key_source);
88 LOG(INFO) <<
"Demuxer::Run() on file '" << file_name_ <<
"'.";
89 Status status = InitializeParser();
92 while (!all_streams_ready_ && status.ok())
96 if (all_streams_ready_ && output_handlers().empty())
98 if (!init_event_status_.ok())
99 return init_event_status_;
103 for (
const auto& pair : output_handlers()) {
104 if (std::find(stream_indexes_.begin(), stream_indexes_.end(), pair.first) ==
105 stream_indexes_.end()) {
106 LOG(ERROR) <<
"Invalid argument, stream=" << GetStreamLabel(pair.first)
107 <<
" not available.";
108 return Status(error::INVALID_ARGUMENT,
"Stream not available");
112 while (!cancelled_ && status.ok())
114 if (cancelled_ && status.ok())
115 return Status(error::CANCELLED,
"Demuxer run cancelled");
117 if (status.error_code() == error::END_OF_STREAM) {
118 for (
size_t stream_index : stream_indexes_) {
133 std::shared_ptr<MediaHandler> handler) {
134 size_t stream_index = kInvalidStreamIndex;
135 if (!GetStreamIndex(stream_label, &stream_index)) {
136 return Status(error::INVALID_ARGUMENT,
137 "Invalid stream: " + stream_label);
143 const std::string& language_override) {
144 size_t stream_index = kInvalidStreamIndex;
145 if (!GetStreamIndex(stream_label, &stream_index))
146 LOG(WARNING) <<
"Invalid stream for language override " << stream_label;
147 language_overrides_[stream_index] = language_override;
150 Demuxer::QueuedSample::QueuedSample(uint32_t local_track_id,
151 std::shared_ptr<MediaSample> local_sample)
152 : track_id(local_track_id), sample(local_sample) {}
154 Demuxer::QueuedSample::~QueuedSample() {}
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_);
169 int64_t bytes_read = 0;
170 while (static_cast<size_t>(bytes_read) < kInitBufSize) {
171 int64_t read_result =
172 media_file_->
Read(buffer_.get() + bytes_read, kInitBufSize);
174 return Status(error::FILE_FAILURE,
"Cannot read file " + file_name_);
175 if (read_result == 0)
177 bytes_read += read_result;
179 container_name_ = DetermineContainer(buffer_.get(), bytes_read);
182 switch (container_name_) {
186 case CONTAINER_MPEG2TS:
194 case CONTAINER_MPEG2PS:
195 FALLTHROUGH_INTENDED;
202 case CONTAINER_UNKNOWN: {
203 const int64_t kDumpSizeLimit = 512;
204 LOG(ERROR) <<
"Failed to detect the container type from the buffer: " 205 << base::HexEncode(buffer_.get(),
206 std::min(bytes_read, kDumpSizeLimit));
207 return Status(error::INVALID_ARGUMENT,
208 "Failed to detect the container type.");
211 NOTIMPLEMENTED() <<
"Container " << container_name_
212 <<
" is not supported.";
213 return Status(error::UNIMPLEMENTED,
"Container not supported.");
216 parser_->Init(base::Bind(&Demuxer::ParserInitEvent, base::Unretained(
this)),
217 base::Bind(&Demuxer::NewSampleEvent, base::Unretained(
this)),
221 if (container_name_ == CONTAINER_MOV)
223 if (!parser_->Parse(buffer_.get(), bytes_read)) {
224 return Status(error::PARSER_FAILURE,
225 "Cannot parse media file " + file_name_);
230 void Demuxer::ParserInitEvent(
231 const std::vector<std::shared_ptr<StreamInfo>>& stream_infos) {
232 if (dump_stream_info_) {
233 printf(
"\nFile \"%s\":\n", file_name_.c_str());
234 printf(
"Found %zu stream(s).\n", stream_infos.size());
235 for (
size_t i = 0; i < stream_infos.size(); ++i)
236 printf(
"Stream [%zu] %s\n", i, stream_infos[i]->ToString().c_str());
239 int base_stream_index = 0;
240 bool video_handler_set =
241 output_handlers().find(kBaseVideoOutputStreamIndex) !=
242 output_handlers().end();
243 bool audio_handler_set =
244 output_handlers().find(kBaseAudioOutputStreamIndex) !=
245 output_handlers().end();
246 bool text_handler_set =
247 output_handlers().find(kBaseTextOutputStreamIndex) !=
248 output_handlers().end();
249 for (
const std::shared_ptr<StreamInfo>& stream_info : stream_infos) {
250 size_t stream_index = base_stream_index;
251 if (video_handler_set && stream_info->stream_type() == kStreamVideo) {
252 stream_index = kBaseVideoOutputStreamIndex;
254 video_handler_set =
false;
256 if (audio_handler_set && stream_info->stream_type() == kStreamAudio) {
257 stream_index = kBaseAudioOutputStreamIndex;
259 audio_handler_set =
false;
261 if (text_handler_set && stream_info->stream_type() == kStreamText) {
262 stream_index = kBaseTextOutputStreamIndex;
263 text_handler_set =
false;
266 const bool handler_set =
267 output_handlers().find(stream_index) != output_handlers().end();
269 track_id_to_stream_index_map_[stream_info->track_id()] = stream_index;
270 stream_indexes_.push_back(stream_index);
271 auto iter = language_overrides_.find(stream_index);
272 if (iter != language_overrides_.end() &&
273 stream_info->stream_type() != kStreamVideo) {
274 stream_info->set_language(iter->second);
276 if (stream_info->is_encrypted()) {
277 init_event_status_.
Update(
Status(error::INVALID_ARGUMENT,
278 "A decryption key source is not " 279 "provided for an encrypted stream."));
281 init_event_status_.
Update(
285 track_id_to_stream_index_map_[stream_info->track_id()] =
290 all_streams_ready_ =
true;
293 bool Demuxer::NewSampleEvent(uint32_t track_id,
294 const std::shared_ptr<MediaSample>& sample) {
295 if (!all_streams_ready_) {
296 if (queued_samples_.size() >= kQueuedSamplesLimit) {
297 LOG(ERROR) <<
"Queued samples limit reached: " << kQueuedSamplesLimit;
300 queued_samples_.push_back(QueuedSample(track_id, sample));
303 if (!init_event_status_.ok()) {
306 while (!queued_samples_.empty()) {
307 if (!PushSample(queued_samples_.front().track_id,
308 queued_samples_.front().sample)) {
311 queued_samples_.pop_front();
313 return PushSample(track_id, sample);
316 bool Demuxer::PushSample(uint32_t track_id,
317 const std::shared_ptr<MediaSample>& sample) {
318 auto stream_index_iter = track_id_to_stream_index_map_.find(track_id);
319 if (stream_index_iter == track_id_to_stream_index_map_.end()) {
320 LOG(ERROR) <<
"Track " << track_id <<
" not found.";
323 if (stream_index_iter->second == kInvalidStreamIndex)
327 LOG(ERROR) <<
"Failed to process sample " << stream_index_iter->second
338 int64_t bytes_read = media_file_->
Read(buffer_.get(), kBufSize);
339 if (bytes_read == 0) {
340 if (!parser_->Flush())
341 return Status(error::PARSER_FAILURE,
"Failed to flush.");
342 return Status(error::END_OF_STREAM,
"");
343 }
else if (bytes_read < 0) {
344 return Status(error::FILE_FAILURE,
"Cannot read file " + file_name_);
347 return parser_->Parse(buffer_.get(), bytes_read)
349 :
Status(error::PARSER_FAILURE,
350 "Cannot parse media file " + file_name_);
virtual int64_t Read(void *buffer, uint64_t length)=0
All the methods that are virtual are virtual for mocking.
void Update(Status new_status)
virtual bool Open()=0
Internal open. Should not be used directly.