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/filters/ffmpeg_demuxer.h" | 5 #include "media/filters/ffmpeg_demuxer.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 12 matching lines...) Expand all Loading... | |
23 #include "media/ffmpeg/ffmpeg_common.h" | 23 #include "media/ffmpeg/ffmpeg_common.h" |
24 #include "media/filters/bitstream_converter.h" | 24 #include "media/filters/bitstream_converter.h" |
25 #include "media/filters/ffmpeg_glue.h" | 25 #include "media/filters/ffmpeg_glue.h" |
26 #include "media/filters/ffmpeg_h264_bitstream_converter.h" | 26 #include "media/filters/ffmpeg_h264_bitstream_converter.h" |
27 | 27 |
28 namespace media { | 28 namespace media { |
29 | 29 |
30 // | 30 // |
31 // FFmpegDemuxerStream | 31 // FFmpegDemuxerStream |
32 // | 32 // |
33 FFmpegDemuxerStream::FFmpegDemuxerStream(FFmpegDemuxer* demuxer, | 33 FFmpegDemuxerStream::FFmpegDemuxerStream( |
34 AVStream* stream) | 34 const NotifyBufferedCB& notify_buffered_cb, |
35 : demuxer_(demuxer), | 35 FFmpegDemuxer* demuxer, |
36 AVStream* stream) | |
37 : notify_buffered_cb_(notify_buffered_cb), | |
38 demuxer_(demuxer), | |
36 stream_(stream), | 39 stream_(stream), |
37 type_(UNKNOWN), | 40 type_(UNKNOWN), |
38 discontinuous_(false), | 41 discontinuous_(false), |
39 stopped_(false) { | 42 stopped_(false) { |
40 DCHECK(demuxer_); | 43 DCHECK(demuxer_); |
41 | 44 |
42 // Determine our media format. | 45 // Determine our media format. |
43 switch (stream->codec->codec_type) { | 46 switch (stream->codec->codec_type) { |
44 case AVMEDIA_TYPE_AUDIO: | 47 case AVMEDIA_TYPE_AUDIO: |
45 type_ = AUDIO; | 48 type_ = AUDIO; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
85 !bitstream_converter_->ConvertPacket(packet.get())) { | 88 !bitstream_converter_->ConvertPacket(packet.get())) { |
86 LOG(ERROR) << "Format converstion failed."; | 89 LOG(ERROR) << "Format converstion failed."; |
87 } | 90 } |
88 | 91 |
89 // If a packet is returned by FFmpeg's av_parser_parse2() the packet will | 92 // If a packet is returned by FFmpeg's av_parser_parse2() the packet will |
90 // reference inner memory of FFmpeg. As such we should transfer the packet | 93 // reference inner memory of FFmpeg. As such we should transfer the packet |
91 // into memory we control. | 94 // into memory we control. |
92 buffer = DecoderBuffer::CopyFrom(packet->data, packet->size); | 95 buffer = DecoderBuffer::CopyFrom(packet->data, packet->size); |
93 buffer->SetTimestamp(ConvertStreamTimestamp( | 96 buffer->SetTimestamp(ConvertStreamTimestamp( |
94 stream_->time_base, packet->pts)); | 97 stream_->time_base, packet->pts)); |
95 buffer->SetDuration(ConvertStreamTimestamp( | 98 buffer->SetDuration(std::max( |
96 stream_->time_base, packet->duration)); | 99 base::TimeDelta(), ConvertStreamTimestamp( |
scherkus (not reviewing)
2012/06/21 21:57:04
this means duration can no longer be kNoTimestamp(
Ami GONE FROM CHROMIUM
2012/06/21 22:49:02
That's interesting that you say that.
What would y
scherkus (not reviewing)
2012/06/21 22:58:22
How negative were these durations? Were they −9,22
Ami GONE FROM CHROMIUM
2012/06/21 23:18:11
They were between 0 and -1.
| |
100 stream_->time_base, packet->duration))); | |
101 if (last_packet_timestamp_ > base::TimeDelta() && | |
scherkus (not reviewing)
2012/06/21 21:57:04
timestamps can be negative -- do you mean to check
Ami GONE FROM CHROMIUM
2012/06/21 22:49:02
No, I meant to check for TimeDelta() (to detect a
scherkus (not reviewing)
2012/06/21 22:58:22
Why not use kNoTS() to detect a flush isntead of z
Ami GONE FROM CHROMIUM
2012/06/21 23:18:11
Done.
| |
102 last_packet_timestamp_ < buffer->GetTimestamp()) { | |
103 DCHECK(buffer->GetDuration() >= base::TimeDelta()) | |
scherkus (not reviewing)
2012/06/21 21:57:04
ditto around here
Ami GONE FROM CHROMIUM
2012/06/21 22:49:02
This is leftover from debugging the aforementioned
| |
104 << buffer->GetDuration().ToInternalValue(); | |
105 notify_buffered_cb_.Run(last_packet_timestamp_, | |
106 buffer->GetTimestamp() + buffer->GetDuration()); | |
107 } | |
108 last_packet_timestamp_ = buffer->GetTimestamp(); | |
97 } | 109 } |
98 | 110 |
99 buffer_queue_.push_back(buffer); | 111 buffer_queue_.push_back(buffer); |
100 FulfillPendingRead(); | 112 FulfillPendingRead(); |
101 return; | 113 return; |
102 } | 114 } |
103 | 115 |
104 void FFmpegDemuxerStream::FlushBuffers() { | 116 void FFmpegDemuxerStream::FlushBuffers() { |
105 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); | 117 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); |
106 base::AutoLock auto_lock(lock_); | 118 base::AutoLock auto_lock(lock_); |
107 DCHECK(read_queue_.empty()) << "Read requests should be empty"; | 119 DCHECK(read_queue_.empty()) << "Read requests should be empty"; |
108 buffer_queue_.clear(); | 120 buffer_queue_.clear(); |
121 last_packet_timestamp_ = base::TimeDelta(); | |
scherkus (not reviewing)
2012/06/21 21:57:04
kNoTS() here + ctor initializer list?
| |
109 } | 122 } |
110 | 123 |
111 void FFmpegDemuxerStream::Stop() { | 124 void FFmpegDemuxerStream::Stop() { |
112 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); | 125 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); |
113 base::AutoLock auto_lock(lock_); | 126 base::AutoLock auto_lock(lock_); |
114 buffer_queue_.clear(); | 127 buffer_queue_.clear(); |
115 for (ReadQueue::iterator it = read_queue_.begin(); | 128 for (ReadQueue::iterator it = read_queue_.begin(); |
116 it != read_queue_.end(); ++it) { | 129 it != read_queue_.end(); ++it) { |
117 it->Run(scoped_refptr<DecoderBuffer>(DecoderBuffer::CreateEOSBuffer())); | 130 it->Run(scoped_refptr<DecoderBuffer>(DecoderBuffer::CreateEOSBuffer())); |
118 } | 131 } |
(...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
500 // Ensure the codec is supported. | 513 // Ensure the codec is supported. |
501 if (CodecIDToVideoCodec(codec_context->codec_id) == kUnknownVideoCodec) | 514 if (CodecIDToVideoCodec(codec_context->codec_id) == kUnknownVideoCodec) |
502 continue; | 515 continue; |
503 found_video_stream = true; | 516 found_video_stream = true; |
504 } else { | 517 } else { |
505 continue; | 518 continue; |
506 } | 519 } |
507 | 520 |
508 AVStream* stream = format_context_->streams[i]; | 521 AVStream* stream = format_context_->streams[i]; |
509 scoped_refptr<FFmpegDemuxerStream> demuxer_stream( | 522 scoped_refptr<FFmpegDemuxerStream> demuxer_stream( |
510 new FFmpegDemuxerStream(this, stream)); | 523 new FFmpegDemuxerStream( |
524 base::Bind(&DemuxerHost::AddBufferedTimeRange, | |
525 base::Unretained(host_)), | |
526 this, stream)); | |
511 | 527 |
512 streams_[i] = demuxer_stream; | 528 streams_[i] = demuxer_stream; |
513 max_duration = std::max(max_duration, demuxer_stream->duration()); | 529 max_duration = std::max(max_duration, demuxer_stream->duration()); |
514 | 530 |
515 if (stream->first_dts != static_cast<int64_t>(AV_NOPTS_VALUE)) { | 531 if (stream->first_dts != static_cast<int64_t>(AV_NOPTS_VALUE)) { |
516 const base::TimeDelta first_dts = ConvertFromTimeBase( | 532 const base::TimeDelta first_dts = ConvertFromTimeBase( |
517 stream->time_base, stream->first_dts); | 533 stream->time_base, stream->first_dts); |
518 if (start_time_ == kNoTimestamp() || first_dts < start_time_) | 534 if (start_time_ == kNoTimestamp() || first_dts < start_time_) |
519 start_time_ = first_dts; | 535 start_time_ = first_dts; |
520 } | 536 } |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
631 DCHECK_GE(packet->stream_index, 0); | 647 DCHECK_GE(packet->stream_index, 0); |
632 DCHECK_LT(packet->stream_index, static_cast<int>(streams_.size())); | 648 DCHECK_LT(packet->stream_index, static_cast<int>(streams_.size())); |
633 | 649 |
634 // Defend against ffmpeg giving us a bad stream index. | 650 // Defend against ffmpeg giving us a bad stream index. |
635 if (packet->stream_index >= 0 && | 651 if (packet->stream_index >= 0 && |
636 packet->stream_index < static_cast<int>(streams_.size()) && | 652 packet->stream_index < static_cast<int>(streams_.size()) && |
637 streams_[packet->stream_index] && | 653 streams_[packet->stream_index] && |
638 (!audio_disabled_ || | 654 (!audio_disabled_ || |
639 streams_[packet->stream_index]->type() != DemuxerStream::AUDIO)) { | 655 streams_[packet->stream_index]->type() != DemuxerStream::AUDIO)) { |
640 FFmpegDemuxerStream* demuxer_stream = streams_[packet->stream_index]; | 656 FFmpegDemuxerStream* demuxer_stream = streams_[packet->stream_index]; |
657 | |
641 demuxer_stream->EnqueuePacket(packet.Pass()); | 658 demuxer_stream->EnqueuePacket(packet.Pass()); |
642 } | 659 } |
643 | 660 |
644 // Create a loop by posting another task. This allows seek and message loop | 661 // Create a loop by posting another task. This allows seek and message loop |
645 // quit tasks to get processed. | 662 // quit tasks to get processed. |
646 if (StreamsHavePendingReads()) { | 663 if (StreamsHavePendingReads()) { |
647 PostDemuxTask(); | 664 PostDemuxTask(); |
648 } | 665 } |
649 } | 666 } |
650 | 667 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
701 read_event_.Wait(); | 718 read_event_.Wait(); |
702 return last_read_bytes_; | 719 return last_read_bytes_; |
703 } | 720 } |
704 | 721 |
705 void FFmpegDemuxer::SignalReadCompleted(int size) { | 722 void FFmpegDemuxer::SignalReadCompleted(int size) { |
706 last_read_bytes_ = size; | 723 last_read_bytes_ = size; |
707 read_event_.Signal(); | 724 read_event_.Signal(); |
708 } | 725 } |
709 | 726 |
710 } // namespace media | 727 } // namespace media |
OLD | NEW |