OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/formats/mp4/mp4_stream_parser.h" | 5 #include "media/formats/mp4/mp4_stream_parser.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <limits> | 9 #include <limits> |
10 #include <memory> | 10 #include <memory> |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
94 } | 94 } |
95 | 95 |
96 bool MP4StreamParser::Parse(const uint8_t* buf, int size) { | 96 bool MP4StreamParser::Parse(const uint8_t* buf, int size) { |
97 DCHECK_NE(state_, kWaitingForInit); | 97 DCHECK_NE(state_, kWaitingForInit); |
98 | 98 |
99 if (state_ == kError) | 99 if (state_ == kError) |
100 return false; | 100 return false; |
101 | 101 |
102 queue_.Push(buf, size); | 102 queue_.Push(buf, size); |
103 | 103 |
104 BufferQueue audio_buffers; | 104 BufferQueueMap buffers; |
105 BufferQueue video_buffers; | |
106 | 105 |
107 bool result = false; | 106 bool result = false; |
108 bool err = false; | 107 bool err = false; |
109 | 108 |
110 do { | 109 do { |
111 switch (state_) { | 110 switch (state_) { |
112 case kWaitingForInit: | 111 case kWaitingForInit: |
113 case kError: | 112 case kError: |
114 NOTREACHED(); | 113 NOTREACHED(); |
115 return false; | 114 return false; |
116 | 115 |
117 case kParsingBoxes: | 116 case kParsingBoxes: |
118 result = ParseBox(&err); | 117 result = ParseBox(&err); |
119 break; | 118 break; |
120 | 119 |
121 case kWaitingForSampleData: | 120 case kWaitingForSampleData: |
122 result = HaveEnoughDataToEnqueueSamples(); | 121 result = HaveEnoughDataToEnqueueSamples(); |
123 if (result) | 122 if (result) |
124 ChangeState(kEmittingSamples); | 123 ChangeState(kEmittingSamples); |
125 break; | 124 break; |
126 | 125 |
127 case kEmittingSamples: | 126 case kEmittingSamples: |
128 result = EnqueueSample(&audio_buffers, &video_buffers, &err); | 127 result = EnqueueSample(&buffers, &err); |
129 if (result) { | 128 if (result) { |
130 int64_t max_clear = runs_->GetMaxClearOffset() + moof_head_; | 129 int64_t max_clear = runs_->GetMaxClearOffset() + moof_head_; |
131 err = !ReadAndDiscardMDATsUntil(max_clear); | 130 err = !ReadAndDiscardMDATsUntil(max_clear); |
132 } | 131 } |
133 break; | 132 break; |
134 } | 133 } |
135 } while (result && !err); | 134 } while (result && !err); |
136 | 135 |
137 if (!err) | 136 if (!err) |
138 err = !SendAndFlushSamples(&audio_buffers, &video_buffers); | 137 err = !SendAndFlushSamples(&buffers); |
139 | 138 |
140 if (err) { | 139 if (err) { |
141 DLOG(ERROR) << "Error while parsing MP4"; | 140 DLOG(ERROR) << "Error while parsing MP4"; |
142 moov_.reset(); | 141 moov_.reset(); |
143 Reset(); | 142 Reset(); |
144 ChangeState(kError); | 143 ChangeState(kError); |
145 return false; | 144 return false; |
146 } | 145 } |
147 | 146 |
148 return true; | 147 return true; |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
193 | 192 |
194 std::unique_ptr<MediaTracks> media_tracks(new MediaTracks()); | 193 std::unique_ptr<MediaTracks> media_tracks(new MediaTracks()); |
195 AudioDecoderConfig audio_config; | 194 AudioDecoderConfig audio_config; |
196 VideoDecoderConfig video_config; | 195 VideoDecoderConfig video_config; |
197 int detected_audio_track_count = 0; | 196 int detected_audio_track_count = 0; |
198 int detected_video_track_count = 0; | 197 int detected_video_track_count = 0; |
199 int detected_text_track_count = 0; | 198 int detected_text_track_count = 0; |
200 | 199 |
201 for (std::vector<Track>::const_iterator track = moov_->tracks.begin(); | 200 for (std::vector<Track>::const_iterator track = moov_->tracks.begin(); |
202 track != moov_->tracks.end(); ++track) { | 201 track != moov_->tracks.end(); ++track) { |
203 // TODO(strobe): Only the first audio and video track present in a file are | |
204 // used. (Track selection is better accomplished via Source IDs, though, so | |
205 // adding support for track selection within a stream is low-priority.) | |
206 const SampleDescription& samp_descr = | 202 const SampleDescription& samp_descr = |
207 track->media.information.sample_table.description; | 203 track->media.information.sample_table.description; |
208 | 204 |
209 // TODO(strobe): When codec reconfigurations are supported, detect and send | 205 // TODO(strobe): When codec reconfigurations are supported, detect and send |
210 // a codec reconfiguration for fragments using a sample description index | 206 // a codec reconfiguration for fragments using a sample description index |
211 // different from the previous one | 207 // different from the previous one |
212 size_t desc_idx = 0; | 208 size_t desc_idx = 0; |
213 for (size_t t = 0; t < moov_->extends.tracks.size(); t++) { | 209 for (size_t t = 0; t < moov_->extends.tracks.size(); t++) { |
214 const TrackExtends& trex = moov_->extends.tracks[t]; | 210 const TrackExtends& trex = moov_->extends.tracks[t]; |
215 if (trex.track_id == track->header.track_id) { | 211 if (trex.track_id == track->header.track_id) { |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
479 // not required to use subsample encryption, so we may need to add an entry. | 475 // not required to use subsample encryption, so we may need to add an entry. |
480 if (subsamples->empty()) { | 476 if (subsamples->empty()) { |
481 subsamples->push_back(SubsampleEntry( | 477 subsamples->push_back(SubsampleEntry( |
482 kADTSHeaderMinSize, frame_buf->size() - kADTSHeaderMinSize)); | 478 kADTSHeaderMinSize, frame_buf->size() - kADTSHeaderMinSize)); |
483 } else { | 479 } else { |
484 (*subsamples)[0].clear_bytes += kADTSHeaderMinSize; | 480 (*subsamples)[0].clear_bytes += kADTSHeaderMinSize; |
485 } | 481 } |
486 return true; | 482 return true; |
487 } | 483 } |
488 | 484 |
489 bool MP4StreamParser::EnqueueSample(BufferQueue* audio_buffers, | 485 bool MP4StreamParser::EnqueueSample(BufferQueueMap* buffers, bool* err) { |
490 BufferQueue* video_buffers, | |
491 bool* err) { | |
492 DCHECK_EQ(state_, kEmittingSamples); | 486 DCHECK_EQ(state_, kEmittingSamples); |
493 | 487 |
494 if (!runs_->IsRunValid()) { | 488 if (!runs_->IsRunValid()) { |
495 // Flush any buffers we've gotten in this chunk so that buffers don't | 489 // Flush any buffers we've gotten in this chunk so that buffers don't |
496 // cross |new_segment_cb_| calls | 490 // cross |new_segment_cb_| calls |
497 *err = !SendAndFlushSamples(audio_buffers, video_buffers); | 491 *err = !SendAndFlushSamples(buffers); |
498 if (*err) | 492 if (*err) |
499 return false; | 493 return false; |
500 | 494 |
501 // Remain in kEmittingSamples state, discarding data, until the end of | 495 // Remain in kEmittingSamples state, discarding data, until the end of |
502 // the current 'mdat' box has been appended to the queue. | 496 // the current 'mdat' box has been appended to the queue. |
503 if (!queue_.Trim(mdat_tail_)) | 497 if (!queue_.Trim(mdat_tail_)) |
504 return false; | 498 return false; |
505 | 499 |
506 ChangeState(kParsingBoxes); | 500 ChangeState(kParsingBoxes); |
507 end_of_segment_cb_.Run(); | 501 end_of_segment_cb_.Run(); |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
616 stream_buf->set_timestamp(runs_->cts()); | 610 stream_buf->set_timestamp(runs_->cts()); |
617 stream_buf->SetDecodeTimestamp(runs_->dts()); | 611 stream_buf->SetDecodeTimestamp(runs_->dts()); |
618 | 612 |
619 DVLOG(3) << "Pushing frame: aud=" << audio | 613 DVLOG(3) << "Pushing frame: aud=" << audio |
620 << ", key=" << runs_->is_keyframe() | 614 << ", key=" << runs_->is_keyframe() |
621 << ", dur=" << runs_->duration().InMilliseconds() | 615 << ", dur=" << runs_->duration().InMilliseconds() |
622 << ", dts=" << runs_->dts().InMilliseconds() | 616 << ", dts=" << runs_->dts().InMilliseconds() |
623 << ", cts=" << runs_->cts().InMilliseconds() | 617 << ", cts=" << runs_->cts().InMilliseconds() |
624 << ", size=" << runs_->sample_size(); | 618 << ", size=" << runs_->sample_size(); |
625 | 619 |
626 if (audio) { | 620 (*buffers)[runs_->track_id()].push_back(stream_buf); |
627 audio_buffers->push_back(stream_buf); | |
628 } else { | |
629 video_buffers->push_back(stream_buf); | |
630 } | |
631 | |
632 runs_->AdvanceSample(); | 621 runs_->AdvanceSample(); |
633 return true; | 622 return true; |
634 } | 623 } |
635 | 624 |
636 bool MP4StreamParser::SendAndFlushSamples(BufferQueue* audio_buffers, | 625 bool MP4StreamParser::SendAndFlushSamples(BufferQueueMap* buffers) { |
637 BufferQueue* video_buffers) { | 626 if (buffers->empty()) |
638 if (audio_buffers->empty() && video_buffers->empty()) | |
639 return true; | 627 return true; |
640 | 628 bool success = new_buffers_cb_.Run(*buffers); |
641 TextBufferQueueMap empty_text_map; | 629 buffers->clear(); |
642 bool success = new_buffers_cb_.Run(*audio_buffers, | |
643 *video_buffers, | |
644 empty_text_map); | |
645 audio_buffers->clear(); | |
646 video_buffers->clear(); | |
647 return success; | 630 return success; |
648 } | 631 } |
649 | 632 |
650 bool MP4StreamParser::ReadAndDiscardMDATsUntil(int64_t max_clear_offset) { | 633 bool MP4StreamParser::ReadAndDiscardMDATsUntil(int64_t max_clear_offset) { |
651 bool err = false; | 634 bool err = false; |
652 int64_t upper_bound = std::min(max_clear_offset, queue_.tail()); | 635 int64_t upper_bound = std::min(max_clear_offset, queue_.tail()); |
653 while (mdat_tail_ < upper_bound) { | 636 while (mdat_tail_ < upper_bound) { |
654 const uint8_t* buf = NULL; | 637 const uint8_t* buf = NULL; |
655 int size = 0; | 638 int size = 0; |
656 queue_.PeekAt(mdat_tail_, &buf, &size); | 639 queue_.PeekAt(mdat_tail_, &buf, &size); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
707 runs.AdvanceSample(); | 690 runs.AdvanceSample(); |
708 } | 691 } |
709 runs.AdvanceRun(); | 692 runs.AdvanceRun(); |
710 } | 693 } |
711 | 694 |
712 return true; | 695 return true; |
713 } | 696 } |
714 | 697 |
715 } // namespace mp4 | 698 } // namespace mp4 |
716 } // namespace media | 699 } // namespace media |
OLD | NEW |