Chromium Code Reviews| 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 |