| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/mp4/mp4_stream_parser.h" | 5 #include "media/mp4/mp4_stream_parser.h" |
| 6 | 6 |
| 7 #include "base/callback.h" | 7 #include "base/callback.h" |
| 8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/time.h" | 10 #include "base/time.h" |
| (...skipping 24 matching lines...) Expand all Loading... |
| 35 } | 35 } |
| 36 | 36 |
| 37 MP4StreamParser::~MP4StreamParser() {} | 37 MP4StreamParser::~MP4StreamParser() {} |
| 38 | 38 |
| 39 void MP4StreamParser::Init(const InitCB& init_cb, | 39 void MP4StreamParser::Init(const InitCB& init_cb, |
| 40 const NewConfigCB& config_cb, | 40 const NewConfigCB& config_cb, |
| 41 const NewBuffersCB& audio_cb, | 41 const NewBuffersCB& audio_cb, |
| 42 const NewBuffersCB& video_cb, | 42 const NewBuffersCB& video_cb, |
| 43 const NeedKeyCB& need_key_cb, | 43 const NeedKeyCB& need_key_cb, |
| 44 const NewMediaSegmentCB& new_segment_cb, | 44 const NewMediaSegmentCB& new_segment_cb, |
| 45 const base::Closure& end_of_segment_cb) { | 45 const base::Closure& end_of_segment_cb, |
| 46 const LogCB& log_cb) { |
| 46 DCHECK_EQ(state_, kWaitingForInit); | 47 DCHECK_EQ(state_, kWaitingForInit); |
| 47 DCHECK(init_cb_.is_null()); | 48 DCHECK(init_cb_.is_null()); |
| 48 DCHECK(!init_cb.is_null()); | 49 DCHECK(!init_cb.is_null()); |
| 49 DCHECK(!config_cb.is_null()); | 50 DCHECK(!config_cb.is_null()); |
| 50 DCHECK(!audio_cb.is_null() || !video_cb.is_null()); | 51 DCHECK(!audio_cb.is_null() || !video_cb.is_null()); |
| 51 DCHECK(!need_key_cb.is_null()); | 52 DCHECK(!need_key_cb.is_null()); |
| 52 DCHECK(!end_of_segment_cb.is_null()); | 53 DCHECK(!end_of_segment_cb.is_null()); |
| 53 | 54 |
| 54 ChangeState(kParsingBoxes); | 55 ChangeState(kParsingBoxes); |
| 55 init_cb_ = init_cb; | 56 init_cb_ = init_cb; |
| 56 config_cb_ = config_cb; | 57 config_cb_ = config_cb; |
| 57 audio_cb_ = audio_cb; | 58 audio_cb_ = audio_cb; |
| 58 video_cb_ = video_cb; | 59 video_cb_ = video_cb; |
| 59 need_key_cb_ = need_key_cb; | 60 need_key_cb_ = need_key_cb; |
| 60 new_segment_cb_ = new_segment_cb; | 61 new_segment_cb_ = new_segment_cb; |
| 61 end_of_segment_cb_ = end_of_segment_cb; | 62 end_of_segment_cb_ = end_of_segment_cb; |
| 63 log_cb_ = log_cb; |
| 62 } | 64 } |
| 63 | 65 |
| 64 void MP4StreamParser::Reset() { | 66 void MP4StreamParser::Reset() { |
| 65 queue_.Reset(); | 67 queue_.Reset(); |
| 66 moov_.reset(); | 68 moov_.reset(); |
| 67 runs_.reset(); | 69 runs_.reset(); |
| 68 moof_head_ = 0; | 70 moof_head_ = 0; |
| 69 mdat_tail_ = 0; | 71 mdat_tail_ = 0; |
| 70 } | 72 } |
| 71 | 73 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 113 | 115 |
| 114 return true; | 116 return true; |
| 115 } | 117 } |
| 116 | 118 |
| 117 bool MP4StreamParser::ParseBox(bool* err) { | 119 bool MP4StreamParser::ParseBox(bool* err) { |
| 118 const uint8* buf; | 120 const uint8* buf; |
| 119 int size; | 121 int size; |
| 120 queue_.Peek(&buf, &size); | 122 queue_.Peek(&buf, &size); |
| 121 if (!size) return false; | 123 if (!size) return false; |
| 122 | 124 |
| 123 scoped_ptr<BoxReader> reader(BoxReader::ReadTopLevelBox(buf, size, err)); | 125 scoped_ptr<BoxReader> reader( |
| 126 BoxReader::ReadTopLevelBox(buf, size, log_cb_, err)); |
| 124 if (reader.get() == NULL) return false; | 127 if (reader.get() == NULL) return false; |
| 125 | 128 |
| 126 if (reader->type() == FOURCC_MOOV) { | 129 if (reader->type() == FOURCC_MOOV) { |
| 127 *err = !ParseMoov(reader.get()); | 130 *err = !ParseMoov(reader.get()); |
| 128 } else if (reader->type() == FOURCC_MOOF) { | 131 } else if (reader->type() == FOURCC_MOOF) { |
| 129 moof_head_ = queue_.head(); | 132 moof_head_ = queue_.head(); |
| 130 *err = !ParseMoof(reader.get()); | 133 *err = !ParseMoof(reader.get()); |
| 131 | 134 |
| 132 // Set up first mdat offset for ReadMDATsUntil(). | 135 // Set up first mdat offset for ReadMDATsUntil(). |
| 133 mdat_tail_ = queue_.head() + reader->size(); | 136 mdat_tail_ = queue_.head() + reader->size(); |
| 134 | 137 |
| 135 // Return early to avoid evicting 'moof' data from queue. Auxiliary info may | 138 // Return early to avoid evicting 'moof' data from queue. Auxiliary info may |
| 136 // be located anywhere in the file, including inside the 'moof' itself. | 139 // be located anywhere in the file, including inside the 'moof' itself. |
| 137 // (Since 'default-base-is-moof' is mandated, no data references can come | 140 // (Since 'default-base-is-moof' is mandated, no data references can come |
| 138 // before the head of the 'moof', so keeping this box around is sufficient.) | 141 // before the head of the 'moof', so keeping this box around is sufficient.) |
| 139 return !(*err); | 142 return !(*err); |
| 140 } else { | 143 } else { |
| 141 DVLOG(2) << "Skipping unrecognized top-level box: " | 144 MEDIA_LOG(log_cb_) << "Skipping unrecognized top-level box: " |
| 142 << FourCCToString(reader->type()); | 145 << FourCCToString(reader->type()); |
| 143 } | 146 } |
| 144 | 147 |
| 145 queue_.Pop(reader->size()); | 148 queue_.Pop(reader->size()); |
| 146 return !(*err); | 149 return !(*err); |
| 147 } | 150 } |
| 148 | 151 |
| 149 | 152 |
| 150 bool MP4StreamParser::ParseMoov(BoxReader* reader) { | 153 bool MP4StreamParser::ParseMoov(BoxReader* reader) { |
| 151 moov_.reset(new Movie); | 154 moov_.reset(new Movie); |
| 152 RCHECK(moov_->Parse(reader)); | 155 RCHECK(moov_->Parse(reader)); |
| 153 runs_.reset(new TrackRunIterator(moov_.get())); | 156 runs_.reset(new TrackRunIterator(moov_.get(), log_cb_)); |
| 154 | 157 |
| 155 has_audio_ = false; | 158 has_audio_ = false; |
| 156 has_video_ = false; | 159 has_video_ = false; |
| 157 | 160 |
| 158 AudioDecoderConfig audio_config; | 161 AudioDecoderConfig audio_config; |
| 159 VideoDecoderConfig video_config; | 162 VideoDecoderConfig video_config; |
| 160 | 163 |
| 161 for (std::vector<Track>::const_iterator track = moov_->tracks.begin(); | 164 for (std::vector<Track>::const_iterator track = moov_->tracks.begin(); |
| 162 track != moov_->tracks.end(); ++track) { | 165 track != moov_->tracks.end(); ++track) { |
| 163 // TODO(strobe): Only the first audio and video track present in a file are | 166 // TODO(strobe): Only the first audio and video track present in a file are |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 405 std::vector<SubsampleEntry> subsamples; | 408 std::vector<SubsampleEntry> subsamples; |
| 406 if (runs_->is_encrypted()) { | 409 if (runs_->is_encrypted()) { |
| 407 decrypt_config = runs_->GetDecryptConfig(); | 410 decrypt_config = runs_->GetDecryptConfig(); |
| 408 subsamples = decrypt_config->subsamples(); | 411 subsamples = decrypt_config->subsamples(); |
| 409 } | 412 } |
| 410 | 413 |
| 411 std::vector<uint8> frame_buf(buf, buf + runs_->sample_size()); | 414 std::vector<uint8> frame_buf(buf, buf + runs_->sample_size()); |
| 412 if (video) { | 415 if (video) { |
| 413 if (!PrepareAVCBuffer(runs_->video_description().avcc, | 416 if (!PrepareAVCBuffer(runs_->video_description().avcc, |
| 414 &frame_buf, &subsamples)) { | 417 &frame_buf, &subsamples)) { |
| 415 DLOG(ERROR) << "Failed to prepare AVC sample for decode"; | 418 MEDIA_LOG(log_cb_) << "Failed to prepare AVC sample for decode"; |
| 416 *err = true; | 419 *err = true; |
| 417 return false; | 420 return false; |
| 418 } | 421 } |
| 419 } | 422 } |
| 420 | 423 |
| 421 if (audio) { | 424 if (audio) { |
| 422 if (!PrepareAACBuffer(runs_->audio_description().esds.aac, | 425 if (!PrepareAACBuffer(runs_->audio_description().esds.aac, |
| 423 &frame_buf, &subsamples)) { | 426 &frame_buf, &subsamples)) { |
| 424 DLOG(ERROR) << "Failed to prepare AAC sample for decode"; | 427 MEDIA_LOG(log_cb_) << "Failed to prepare AAC sample for decode"; |
| 425 *err = true; | 428 *err = true; |
| 426 return false; | 429 return false; |
| 427 } | 430 } |
| 428 } | 431 } |
| 429 | 432 |
| 430 if (decrypt_config.get() != NULL && !subsamples.empty()) { | 433 if (decrypt_config.get() != NULL && !subsamples.empty()) { |
| 431 decrypt_config.reset(new DecryptConfig( | 434 decrypt_config.reset(new DecryptConfig( |
| 432 decrypt_config->key_id(), | 435 decrypt_config->key_id(), |
| 433 decrypt_config->iv(), | 436 decrypt_config->iv(), |
| 434 decrypt_config->data_offset(), | 437 decrypt_config->data_offset(), |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 479 | 482 |
| 480 bool MP4StreamParser::ReadAndDiscardMDATsUntil(const int64 offset) { | 483 bool MP4StreamParser::ReadAndDiscardMDATsUntil(const int64 offset) { |
| 481 bool err = false; | 484 bool err = false; |
| 482 while (mdat_tail_ < offset) { | 485 while (mdat_tail_ < offset) { |
| 483 const uint8* buf; | 486 const uint8* buf; |
| 484 int size; | 487 int size; |
| 485 queue_.PeekAt(mdat_tail_, &buf, &size); | 488 queue_.PeekAt(mdat_tail_, &buf, &size); |
| 486 | 489 |
| 487 FourCC type; | 490 FourCC type; |
| 488 int box_sz; | 491 int box_sz; |
| 489 if (!BoxReader::StartTopLevelBox(buf, size, &type, &box_sz, &err)) | 492 if (!BoxReader::StartTopLevelBox(buf, size, log_cb_, |
| 493 &type, &box_sz, &err)) |
| 490 break; | 494 break; |
| 491 | 495 |
| 492 if (type != FOURCC_MDAT) { | 496 if (type != FOURCC_MDAT) { |
| 493 DLOG(WARNING) << "Unexpected box type while parsing MDATs: " | 497 MEDIA_LOG(log_cb_) << "Unexpected box type while parsing MDATs: " |
| 494 << FourCCToString(type); | 498 << FourCCToString(type); |
| 495 } | 499 } |
| 496 mdat_tail_ += box_sz; | 500 mdat_tail_ += box_sz; |
| 497 } | 501 } |
| 498 queue_.Trim(std::min(mdat_tail_, offset)); | 502 queue_.Trim(std::min(mdat_tail_, offset)); |
| 499 return !err; | 503 return !err; |
| 500 } | 504 } |
| 501 | 505 |
| 502 void MP4StreamParser::ChangeState(State new_state) { | 506 void MP4StreamParser::ChangeState(State new_state) { |
| 503 DVLOG(2) << "Changing state: " << new_state; | 507 DVLOG(2) << "Changing state: " << new_state; |
| 504 state_ = new_state; | 508 state_ = new_state; |
| 505 } | 509 } |
| 506 | 510 |
| 507 } // namespace mp4 | 511 } // namespace mp4 |
| 508 } // namespace media | 512 } // namespace media |
| OLD | NEW |