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/mp2t/mp2t_stream_parser.h" | 5 #include "media/formats/mp2t/mp2t_stream_parser.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
9 #include "base/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
210 // stream parser already involves the end of the current segment. | 210 // stream parser already involves the end of the current segment. |
211 segment_started_ = false; | 211 segment_started_ = false; |
212 | 212 |
213 // Remove any bytes left in the TS buffer. | 213 // Remove any bytes left in the TS buffer. |
214 // (i.e. any partial TS packet => less than 188 bytes). | 214 // (i.e. any partial TS packet => less than 188 bytes). |
215 ts_byte_queue_.Reset(); | 215 ts_byte_queue_.Reset(); |
216 | 216 |
217 // Reset the selected PIDs. | 217 // Reset the selected PIDs. |
218 selected_audio_pid_ = -1; | 218 selected_audio_pid_ = -1; |
219 selected_video_pid_ = -1; | 219 selected_video_pid_ = -1; |
220 | |
221 // Reset the timestamp unroller. | |
222 timestamp_unroller_.Reset(); | |
223 time_offset_ = base::TimeDelta(); | |
220 } | 224 } |
221 | 225 |
222 bool Mp2tStreamParser::Parse(const uint8* buf, int size) { | 226 bool Mp2tStreamParser::Parse(const uint8* buf, int size) { |
223 DVLOG(1) << "Mp2tStreamParser::Parse size=" << size; | 227 DVLOG(1) << "Mp2tStreamParser::Parse size=" << size; |
224 | 228 |
225 // Add the data to the parser state. | 229 // Add the data to the parser state. |
226 ts_byte_queue_.Push(buf, size); | 230 ts_byte_queue_.Push(buf, size); |
227 | 231 |
228 while (true) { | 232 while (true) { |
229 const uint8* ts_buffer; | 233 const uint8* ts_buffer; |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
349 pes_pid), | 353 pes_pid), |
350 sbr_in_mimetype_)); | 354 sbr_in_mimetype_)); |
351 is_audio = true; | 355 is_audio = true; |
352 } else { | 356 } else { |
353 return; | 357 return; |
354 } | 358 } |
355 | 359 |
356 // Create the PES state here. | 360 // Create the PES state here. |
357 DVLOG(1) << "Create a new PES state"; | 361 DVLOG(1) << "Create a new PES state"; |
358 scoped_ptr<TsSection> pes_section_parser( | 362 scoped_ptr<TsSection> pes_section_parser( |
359 new TsSectionPes(es_parser.Pass())); | 363 new TsSectionPes(es_parser.Pass(), ×tamp_unroller_)); |
360 PidState::PidType pid_type = | 364 PidState::PidType pid_type = |
361 is_audio ? PidState::kPidAudioPes : PidState::kPidVideoPes; | 365 is_audio ? PidState::kPidAudioPes : PidState::kPidVideoPes; |
362 scoped_ptr<PidState> pes_pid_state( | 366 scoped_ptr<PidState> pes_pid_state( |
363 new PidState(pes_pid, pid_type, pes_section_parser.Pass())); | 367 new PidState(pes_pid, pid_type, pes_section_parser.Pass())); |
364 pids_.insert(std::pair<int, PidState*>(pes_pid, pes_pid_state.release())); | 368 pids_.insert(std::pair<int, PidState*>(pes_pid, pes_pid_state.release())); |
365 | 369 |
366 // A new PES pid has been added, the PID filter might change. | 370 // A new PES pid has been added, the PID filter might change. |
367 UpdatePidFilter(); | 371 UpdatePidFilter(); |
368 } | 372 } |
369 | 373 |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
512 DVLOG(LOG_LEVEL_ES) | 516 DVLOG(LOG_LEVEL_ES) |
513 << "OnEmitAudioBuffer: " | 517 << "OnEmitAudioBuffer: " |
514 << " size=" | 518 << " size=" |
515 << stream_parser_buffer->data_size() | 519 << stream_parser_buffer->data_size() |
516 << " dts=" | 520 << " dts=" |
517 << stream_parser_buffer->GetDecodeTimestamp().InMilliseconds() | 521 << stream_parser_buffer->GetDecodeTimestamp().InMilliseconds() |
518 << " pts=" | 522 << " pts=" |
519 << stream_parser_buffer->timestamp().InMilliseconds() | 523 << stream_parser_buffer->timestamp().InMilliseconds() |
520 << " dur=" | 524 << " dur=" |
521 << stream_parser_buffer->duration().InMilliseconds(); | 525 << stream_parser_buffer->duration().InMilliseconds(); |
522 stream_parser_buffer->set_timestamp( | |
523 stream_parser_buffer->timestamp() - time_offset_); | |
524 stream_parser_buffer->SetDecodeTimestamp( | |
525 stream_parser_buffer->GetDecodeTimestamp() - time_offset_); | |
526 | 526 |
527 // Ignore the incoming buffer if it is not associated with any config. | 527 // Ignore the incoming buffer if it is not associated with any config. |
528 if (buffer_queue_chain_.empty()) { | 528 if (buffer_queue_chain_.empty()) { |
529 NOTREACHED() << "Cannot provide buffers before configs"; | 529 NOTREACHED() << "Cannot provide buffers before configs"; |
530 return; | 530 return; |
531 } | 531 } |
532 | 532 |
533 buffer_queue_chain_.back().audio_queue.push_back(stream_parser_buffer); | 533 buffer_queue_chain_.back().audio_queue.push_back(stream_parser_buffer); |
534 } | 534 } |
535 | 535 |
536 void Mp2tStreamParser::OnEmitVideoBuffer( | 536 void Mp2tStreamParser::OnEmitVideoBuffer( |
537 int pes_pid, | 537 int pes_pid, |
538 scoped_refptr<StreamParserBuffer> stream_parser_buffer) { | 538 scoped_refptr<StreamParserBuffer> stream_parser_buffer) { |
539 DCHECK_EQ(pes_pid, selected_video_pid_); | 539 DCHECK_EQ(pes_pid, selected_video_pid_); |
540 | 540 |
541 DVLOG(LOG_LEVEL_ES) | 541 DVLOG(LOG_LEVEL_ES) |
542 << "OnEmitVideoBuffer" | 542 << "OnEmitVideoBuffer" |
543 << " size=" | 543 << " size=" |
544 << stream_parser_buffer->data_size() | 544 << stream_parser_buffer->data_size() |
545 << " dts=" | 545 << " dts=" |
546 << stream_parser_buffer->GetDecodeTimestamp().InMilliseconds() | 546 << stream_parser_buffer->GetDecodeTimestamp().InMilliseconds() |
547 << " pts=" | 547 << " pts=" |
548 << stream_parser_buffer->timestamp().InMilliseconds() | 548 << stream_parser_buffer->timestamp().InMilliseconds() |
549 << " dur=" | 549 << " dur=" |
550 << stream_parser_buffer->duration().InMilliseconds() | 550 << stream_parser_buffer->duration().InMilliseconds() |
551 << " IsKeyframe=" | 551 << " IsKeyframe=" |
552 << stream_parser_buffer->IsKeyframe(); | 552 << stream_parser_buffer->IsKeyframe(); |
553 stream_parser_buffer->set_timestamp( | |
554 stream_parser_buffer->timestamp() - time_offset_); | |
555 stream_parser_buffer->SetDecodeTimestamp( | |
556 stream_parser_buffer->GetDecodeTimestamp() - time_offset_); | |
557 | 553 |
558 // Ignore the incoming buffer if it is not associated with any config. | 554 // Ignore the incoming buffer if it is not associated with any config. |
559 if (buffer_queue_chain_.empty()) { | 555 if (buffer_queue_chain_.empty()) { |
560 NOTREACHED() << "Cannot provide buffers before configs"; | 556 NOTREACHED() << "Cannot provide buffers before configs"; |
561 return; | 557 return; |
562 } | 558 } |
563 | 559 |
564 buffer_queue_chain_.back().video_queue.push_back(stream_parser_buffer); | 560 buffer_queue_chain_.back().video_queue.push_back(stream_parser_buffer); |
565 } | 561 } |
566 | 562 |
(...skipping 14 matching lines...) Expand all Loading... | |
581 buffer_queue_chain_.back().video_config; | 577 buffer_queue_chain_.back().video_config; |
582 | 578 |
583 // Do not have all the configs, need more data. | 579 // Do not have all the configs, need more data. |
584 if (selected_audio_pid_ >= 0 && !last_audio_config.IsValidConfig()) | 580 if (selected_audio_pid_ >= 0 && !last_audio_config.IsValidConfig()) |
585 return true; | 581 return true; |
586 if (selected_video_pid_ >= 0 && !last_video_config.IsValidConfig()) | 582 if (selected_video_pid_ >= 0 && !last_video_config.IsValidConfig()) |
587 return true; | 583 return true; |
588 | 584 |
589 // Buffer emission. | 585 // Buffer emission. |
590 while (!buffer_queue_chain_.empty()) { | 586 while (!buffer_queue_chain_.empty()) { |
587 BufferQueueWithConfig& queue_with_config = buffer_queue_chain_.front(); | |
588 | |
591 // Start a segment if needed. | 589 // Start a segment if needed. |
592 if (!segment_started_) { | 590 if (!segment_started_) { |
591 // We need at least some audio and video buffers to derive the global | |
592 // timestamp offset. | |
593 if (selected_audio_pid_ >= 0 && queue_with_config.audio_queue.empty()) | |
594 return true; | |
595 if (selected_video_pid_ >= 0 && queue_with_config.video_queue.empty()) | |
596 return true; | |
597 // Compensate if some timestamps are negative. | |
wolenetz
2014/09/05 21:18:49
I'm a bit confused why this compensation is requir
damienv1
2014/09/05 21:52:03
Timestamps in MPEG-2 TS are defined modulo 2^33. S
| |
598 if (timestamp_unroller_.GetMinUnrolledTimestamp() < 0) | |
599 time_offset_ = base::TimeDelta::FromMicroseconds( | |
600 (1000 * (INT64_C(1) << 33)) / 90); | |
601 | |
593 DVLOG(1) << "Starting a new segment"; | 602 DVLOG(1) << "Starting a new segment"; |
594 segment_started_ = true; | 603 segment_started_ = true; |
595 new_segment_cb_.Run(); | 604 new_segment_cb_.Run(); |
596 } | 605 } |
597 | 606 |
598 // Update the audio and video config if needed. | 607 // Update the audio and video config if needed. |
599 BufferQueueWithConfig& queue_with_config = buffer_queue_chain_.front(); | |
600 if (!queue_with_config.is_config_sent) { | 608 if (!queue_with_config.is_config_sent) { |
601 if (!config_cb_.Run(queue_with_config.audio_config, | 609 if (!config_cb_.Run(queue_with_config.audio_config, |
602 queue_with_config.video_config, | 610 queue_with_config.video_config, |
603 TextTrackConfigMap())) | 611 TextTrackConfigMap())) |
604 return false; | 612 return false; |
605 queue_with_config.is_config_sent = true; | 613 queue_with_config.is_config_sent = true; |
606 } | 614 } |
607 | 615 |
608 // Add buffers. | 616 // Add buffers. |
609 TextBufferQueueMap empty_text_map; | 617 TextBufferQueueMap empty_text_map; |
610 if (!queue_with_config.audio_queue.empty() || | 618 if (!queue_with_config.audio_queue.empty() || |
611 !queue_with_config.video_queue.empty()) { | 619 !queue_with_config.video_queue.empty()) { |
620 ApplyTimeOffset(&queue_with_config.audio_queue); | |
621 ApplyTimeOffset(&queue_with_config.video_queue); | |
612 if (!new_buffers_cb_.Run(queue_with_config.audio_queue, | 622 if (!new_buffers_cb_.Run(queue_with_config.audio_queue, |
613 queue_with_config.video_queue, | 623 queue_with_config.video_queue, |
614 empty_text_map)) { | 624 empty_text_map)) { |
615 return false; | 625 return false; |
616 } | 626 } |
617 } | 627 } |
618 | 628 |
619 buffer_queue_chain_.pop_front(); | 629 buffer_queue_chain_.pop_front(); |
620 } | 630 } |
621 | 631 |
622 // Push an empty queue with the last audio/video config | 632 // Push an empty queue with the last audio/video config |
623 // so that buffers with the same config can be added later on. | 633 // so that buffers with the same config can be added later on. |
624 BufferQueueWithConfig queue_with_config( | 634 BufferQueueWithConfig queue_with_config( |
625 true, last_audio_config, last_video_config); | 635 true, last_audio_config, last_video_config); |
626 buffer_queue_chain_.push_back(queue_with_config); | 636 buffer_queue_chain_.push_back(queue_with_config); |
627 | 637 |
628 return true; | 638 return true; |
629 } | 639 } |
630 | 640 |
641 void Mp2tStreamParser::ApplyTimeOffset( | |
642 StreamParser::BufferQueue* buffer_queue) { | |
643 for (StreamParser::BufferQueue::iterator it = buffer_queue->begin(); | |
644 it != buffer_queue->end(); ++it) { | |
645 (*it)->SetDecodeTimestamp((*it)->GetDecodeTimestamp() + time_offset_); | |
646 (*it)->set_timestamp((*it)->timestamp() + time_offset_); | |
647 } | |
648 } | |
649 | |
631 } // namespace mp2t | 650 } // namespace mp2t |
632 } // namespace media | 651 } // namespace media |
OLD | NEW |