Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Side by Side Diff: media/formats/mp2t/mp2t_stream_parser.cc

Issue 539343002: Make the timestamp unroll offset consistent accross PES pids. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Prevent negative timestamps. Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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(), &timestamp_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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698