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 "base/bind.h" | 5 #include "base/bind.h" |
6 #include "base/callback.h" | 6 #include "base/callback.h" |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
11 #include "base/string_util.h" | 11 #include "base/string_util.h" |
12 #include "base/time.h" | 12 #include "base/time.h" |
13 #include "media/base/audio_decoder_config.h" | 13 #include "media/base/audio_decoder_config.h" |
14 #include "media/base/data_buffer.h" | 14 #include "media/base/decoder_buffer.h" |
15 #include "media/base/limits.h" | 15 #include "media/base/limits.h" |
16 #include "media/base/media_switches.h" | 16 #include "media/base/media_switches.h" |
17 #include "media/base/video_decoder_config.h" | 17 #include "media/base/video_decoder_config.h" |
18 #include "media/ffmpeg/ffmpeg_common.h" | 18 #include "media/ffmpeg/ffmpeg_common.h" |
19 #include "media/filters/bitstream_converter.h" | 19 #include "media/filters/bitstream_converter.h" |
20 #include "media/filters/ffmpeg_demuxer.h" | 20 #include "media/filters/ffmpeg_demuxer.h" |
21 #include "media/filters/ffmpeg_glue.h" | 21 #include "media/filters/ffmpeg_glue.h" |
22 #include "media/filters/ffmpeg_h264_bitstream_converter.h" | 22 #include "media/filters/ffmpeg_h264_bitstream_converter.h" |
23 | 23 |
24 namespace media { | 24 namespace media { |
25 | 25 |
26 // | 26 // |
27 // AVPacketBuffer | |
28 // | |
29 class AVPacketBuffer : public Buffer { | |
30 public: | |
31 AVPacketBuffer(scoped_ptr_malloc<AVPacket, ScopedPtrAVFreePacket> packet, | |
32 const base::TimeDelta& timestamp, | |
33 const base::TimeDelta& duration) | |
34 : Buffer(timestamp, duration), | |
35 packet_(packet.Pass()) { | |
36 } | |
37 | |
38 // Buffer implementation. | |
39 virtual const uint8* GetData() const { | |
40 return reinterpret_cast<const uint8*>(packet_->data); | |
41 } | |
42 | |
43 virtual int GetDataSize() const { | |
44 return packet_->size; | |
45 } | |
46 | |
47 protected: | |
48 virtual ~AVPacketBuffer() {} | |
49 | |
50 private: | |
51 scoped_ptr_malloc<AVPacket, ScopedPtrAVFreePacket> packet_; | |
52 | |
53 DISALLOW_COPY_AND_ASSIGN(AVPacketBuffer); | |
54 }; | |
55 | |
56 | |
57 // | |
58 // FFmpegDemuxerStream | 27 // FFmpegDemuxerStream |
59 // | 28 // |
60 FFmpegDemuxerStream::FFmpegDemuxerStream(FFmpegDemuxer* demuxer, | 29 FFmpegDemuxerStream::FFmpegDemuxerStream(FFmpegDemuxer* demuxer, |
61 AVStream* stream) | 30 AVStream* stream) |
62 : demuxer_(demuxer), | 31 : demuxer_(demuxer), |
63 stream_(stream), | 32 stream_(stream), |
64 type_(UNKNOWN), | 33 type_(UNKNOWN), |
65 discontinuous_(false), | 34 discontinuous_(false), |
66 stopped_(false) { | 35 stopped_(false) { |
67 DCHECK(demuxer_); | 36 DCHECK(demuxer_); |
(...skipping 21 matching lines...) Expand all Loading... |
89 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); | 58 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); |
90 base::AutoLock auto_lock(lock_); | 59 base::AutoLock auto_lock(lock_); |
91 DCHECK(!stopped_ || read_queue_.empty()) | 60 DCHECK(!stopped_ || read_queue_.empty()) |
92 << "Read queue should have been emptied if demuxing stream is stopped"; | 61 << "Read queue should have been emptied if demuxing stream is stopped"; |
93 return !read_queue_.empty(); | 62 return !read_queue_.empty(); |
94 } | 63 } |
95 | 64 |
96 void FFmpegDemuxerStream::EnqueuePacket( | 65 void FFmpegDemuxerStream::EnqueuePacket( |
97 scoped_ptr_malloc<AVPacket, ScopedPtrAVFreePacket> packet) { | 66 scoped_ptr_malloc<AVPacket, ScopedPtrAVFreePacket> packet) { |
98 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); | 67 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); |
99 base::TimeDelta timestamp = | |
100 ConvertStreamTimestamp(stream_->time_base, packet->pts); | |
101 base::TimeDelta duration = | |
102 ConvertStreamTimestamp(stream_->time_base, packet->duration); | |
103 | 68 |
104 base::AutoLock auto_lock(lock_); | 69 base::AutoLock auto_lock(lock_); |
105 if (stopped_) { | 70 if (stopped_) { |
106 NOTREACHED() << "Attempted to enqueue packet on a stopped stream"; | 71 NOTREACHED() << "Attempted to enqueue packet on a stopped stream"; |
107 return; | 72 return; |
108 } | 73 } |
109 | 74 |
110 // Convert if the packet if there is bitstream filter. | 75 // Convert if the packet if there is bitstream filter. |
111 if (packet->data && bitstream_converter_.get() && | 76 if (packet->data && bitstream_converter_.get() && |
112 !bitstream_converter_->ConvertPacket(packet.get())) { | 77 !bitstream_converter_->ConvertPacket(packet.get())) { |
113 LOG(ERROR) << "Format converstion failed."; | 78 LOG(ERROR) << "Format converstion failed."; |
114 } | 79 } |
115 | 80 |
116 // Enqueue the callback and attempt to satisfy a read immediately. | 81 // If a packet is returned by FFmpeg's av_parser_parse2() the packet will |
117 scoped_refptr<Buffer> buffer( | 82 // reference inner memory of FFmpeg. As such we should transfer the packet |
118 new AVPacketBuffer(packet.Pass(), timestamp, duration)); | 83 // into memory we control. |
119 if (!buffer) { | 84 scoped_refptr<DecoderBuffer> buffer = DecoderBuffer::CopyFrom( |
120 NOTREACHED() << "Unable to allocate AVPacketBuffer"; | 85 packet->data, packet->size); |
121 return; | 86 buffer->SetTimestamp(ConvertStreamTimestamp(stream_->time_base, packet->pts)); |
122 } | 87 buffer->SetDuration(ConvertStreamTimestamp( |
| 88 stream_->time_base, packet->duration)); |
123 buffer_queue_.push_back(buffer); | 89 buffer_queue_.push_back(buffer); |
124 FulfillPendingRead(); | 90 FulfillPendingRead(); |
125 return; | 91 return; |
126 } | 92 } |
127 | 93 |
128 void FFmpegDemuxerStream::FlushBuffers() { | 94 void FFmpegDemuxerStream::FlushBuffers() { |
129 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); | 95 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); |
130 base::AutoLock auto_lock(lock_); | 96 base::AutoLock auto_lock(lock_); |
131 DCHECK(read_queue_.empty()) << "Read requests should be empty"; | 97 DCHECK(read_queue_.empty()) << "Read requests should be empty"; |
132 buffer_queue_.clear(); | 98 buffer_queue_.clear(); |
133 } | 99 } |
134 | 100 |
135 void FFmpegDemuxerStream::Stop() { | 101 void FFmpegDemuxerStream::Stop() { |
136 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); | 102 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); |
137 base::AutoLock auto_lock(lock_); | 103 base::AutoLock auto_lock(lock_); |
138 buffer_queue_.clear(); | 104 buffer_queue_.clear(); |
139 for (ReadQueue::iterator it = read_queue_.begin(); | 105 for (ReadQueue::iterator it = read_queue_.begin(); |
140 it != read_queue_.end(); ++it) { | 106 it != read_queue_.end(); ++it) { |
141 it->Run(scoped_refptr<Buffer>(new DataBuffer(0))); | 107 it->Run(scoped_refptr<DecoderBuffer>(new DecoderBuffer(0))); |
142 } | 108 } |
143 read_queue_.clear(); | 109 read_queue_.clear(); |
144 stopped_ = true; | 110 stopped_ = true; |
145 } | 111 } |
146 | 112 |
147 base::TimeDelta FFmpegDemuxerStream::duration() { | 113 base::TimeDelta FFmpegDemuxerStream::duration() { |
148 return duration_; | 114 return duration_; |
149 } | 115 } |
150 | 116 |
151 DemuxerStream::Type FFmpegDemuxerStream::type() { | 117 DemuxerStream::Type FFmpegDemuxerStream::type() { |
152 return type_; | 118 return type_; |
153 } | 119 } |
154 | 120 |
155 void FFmpegDemuxerStream::Read(const ReadCB& read_cb) { | 121 void FFmpegDemuxerStream::Read(const ReadCB& read_cb) { |
156 DCHECK(!read_cb.is_null()); | 122 DCHECK(!read_cb.is_null()); |
157 | 123 |
158 base::AutoLock auto_lock(lock_); | 124 base::AutoLock auto_lock(lock_); |
159 // Don't accept any additional reads if we've been told to stop. | 125 // Don't accept any additional reads if we've been told to stop. |
160 // The demuxer_ may have been destroyed in the pipleine thread. | 126 // The demuxer_ may have been destroyed in the pipleine thread. |
161 // | 127 // |
162 // TODO(scherkus): it would be cleaner if we replied with an error message. | 128 // TODO(scherkus): it would be cleaner if we replied with an error message. |
163 if (stopped_) { | 129 if (stopped_) { |
164 read_cb.Run(scoped_refptr<Buffer>(new DataBuffer(0))); | 130 read_cb.Run(scoped_refptr<DecoderBuffer>(new DecoderBuffer(0))); |
165 return; | 131 return; |
166 } | 132 } |
167 | 133 |
168 // Buffers are only queued when there are no pending reads. | 134 // Buffers are only queued when there are no pending reads. |
169 DCHECK(buffer_queue_.empty() || read_queue_.empty()); | 135 DCHECK(buffer_queue_.empty() || read_queue_.empty()); |
170 | 136 |
171 if (buffer_queue_.empty()) { | 137 if (buffer_queue_.empty()) { |
172 demuxer_->message_loop()->PostTask(FROM_HERE, base::Bind( | 138 demuxer_->message_loop()->PostTask(FROM_HERE, base::Bind( |
173 &FFmpegDemuxerStream::ReadTask, this, read_cb)); | 139 &FFmpegDemuxerStream::ReadTask, this, read_cb)); |
174 return; | 140 return; |
175 } | 141 } |
176 | 142 |
177 // Send the oldest buffer back. | 143 // Send the oldest buffer back. |
178 scoped_refptr<Buffer> buffer = buffer_queue_.front(); | 144 scoped_refptr<DecoderBuffer> buffer = buffer_queue_.front(); |
179 buffer_queue_.pop_front(); | 145 buffer_queue_.pop_front(); |
180 read_cb.Run(buffer); | 146 read_cb.Run(buffer); |
181 } | 147 } |
182 | 148 |
183 void FFmpegDemuxerStream::ReadTask(const ReadCB& read_cb) { | 149 void FFmpegDemuxerStream::ReadTask(const ReadCB& read_cb) { |
184 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); | 150 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); |
185 | 151 |
186 base::AutoLock auto_lock(lock_); | 152 base::AutoLock auto_lock(lock_); |
187 // Don't accept any additional reads if we've been told to stop. | 153 // Don't accept any additional reads if we've been told to stop. |
188 // | 154 // |
189 // TODO(scherkus): it would be cleaner if we replied with an error message. | 155 // TODO(scherkus): it would be cleaner if we replied with an error message. |
190 if (stopped_) { | 156 if (stopped_) { |
191 read_cb.Run(scoped_refptr<Buffer>(new DataBuffer(0))); | 157 read_cb.Run(scoped_refptr<DecoderBuffer>(new DecoderBuffer(0))); |
192 return; | 158 return; |
193 } | 159 } |
194 | 160 |
195 // Enqueue the callback and attempt to satisfy it immediately. | 161 // Enqueue the callback and attempt to satisfy it immediately. |
196 read_queue_.push_back(read_cb); | 162 read_queue_.push_back(read_cb); |
197 FulfillPendingRead(); | 163 FulfillPendingRead(); |
198 | 164 |
199 // Check if there are still pending reads, demux some more. | 165 // Check if there are still pending reads, demux some more. |
200 if (!read_queue_.empty()) { | 166 if (!read_queue_.empty()) { |
201 demuxer_->PostDemuxTask(); | 167 demuxer_->PostDemuxTask(); |
202 } | 168 } |
203 } | 169 } |
204 | 170 |
205 void FFmpegDemuxerStream::FulfillPendingRead() { | 171 void FFmpegDemuxerStream::FulfillPendingRead() { |
206 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); | 172 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); |
207 lock_.AssertAcquired(); | 173 lock_.AssertAcquired(); |
208 if (buffer_queue_.empty() || read_queue_.empty()) { | 174 if (buffer_queue_.empty() || read_queue_.empty()) { |
209 return; | 175 return; |
210 } | 176 } |
211 | 177 |
212 // Dequeue a buffer and pending read pair. | 178 // Dequeue a buffer and pending read pair. |
213 scoped_refptr<Buffer> buffer = buffer_queue_.front(); | 179 scoped_refptr<DecoderBuffer> buffer = buffer_queue_.front(); |
214 ReadCB read_cb(read_queue_.front()); | 180 ReadCB read_cb(read_queue_.front()); |
215 buffer_queue_.pop_front(); | 181 buffer_queue_.pop_front(); |
216 read_queue_.pop_front(); | 182 read_queue_.pop_front(); |
217 | 183 |
218 // Execute the callback. | 184 // Execute the callback. |
219 read_cb.Run(buffer); | 185 read_cb.Run(buffer); |
220 } | 186 } |
221 | 187 |
222 void FFmpegDemuxerStream::EnableBitstreamConverter() { | 188 void FFmpegDemuxerStream::EnableBitstreamConverter() { |
223 // Called by hardware decoder to require different bitstream converter. | 189 // Called by hardware decoder to require different bitstream converter. |
224 // Currently we assume that converter is determined by codec_id; | 190 // Currently we assume that converter is determined by codec_id; |
225 DCHECK(stream_); | 191 DCHECK(stream_); |
226 | 192 |
227 if (stream_->codec->codec_id == CODEC_ID_H264) { | 193 if (stream_->codec->codec_id == CODEC_ID_H264) { |
228 // Use Chromium bitstream converter in case of H.264 | 194 // Use Chromium bitstream converter in case of H.264 |
229 bitstream_converter_.reset( | 195 bitstream_converter_.reset( |
230 new FFmpegH264BitstreamConverter(stream_->codec)); | 196 new FFmpegH264BitstreamConverter(stream_->codec)); |
231 CHECK(bitstream_converter_->Initialize()); | 197 CHECK(bitstream_converter_->Initialize()); |
232 return; | 198 } else if (stream_->codec->codec_id == CODEC_ID_MPEG4) { |
233 } | |
234 | |
235 const char* filter_name = NULL; | |
236 if (stream_->codec->codec_id == CODEC_ID_MPEG4) { | |
237 filter_name = "mpeg4video_es"; | |
238 } else if (stream_->codec->codec_id == CODEC_ID_WMV3) { | |
239 filter_name = "vc1_asftorcv"; | |
240 } else if (stream_->codec->codec_id == CODEC_ID_VC1) { | |
241 filter_name = "vc1_asftoannexg"; | |
242 } | |
243 | |
244 if (filter_name) { | |
245 bitstream_converter_.reset( | 199 bitstream_converter_.reset( |
246 new FFmpegBitstreamConverter(filter_name, stream_->codec)); | 200 new FFmpegBitstreamConverter("mpeg4video_es", stream_->codec)); |
247 CHECK(bitstream_converter_->Initialize()); | 201 CHECK(bitstream_converter_->Initialize()); |
248 } | 202 } |
249 } | 203 } |
250 | 204 |
251 const AudioDecoderConfig& FFmpegDemuxerStream::audio_decoder_config() { | 205 const AudioDecoderConfig& FFmpegDemuxerStream::audio_decoder_config() { |
252 CHECK_EQ(type_, AUDIO); | 206 CHECK_EQ(type_, AUDIO); |
253 return audio_config_; | 207 return audio_config_; |
254 } | 208 } |
255 | 209 |
256 const VideoDecoderConfig& FFmpegDemuxerStream::video_decoder_config() { | 210 const VideoDecoderConfig& FFmpegDemuxerStream::video_decoder_config() { |
(...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
643 DCHECK_GE(packet->stream_index, 0); | 597 DCHECK_GE(packet->stream_index, 0); |
644 DCHECK_LT(packet->stream_index, static_cast<int>(streams_.size())); | 598 DCHECK_LT(packet->stream_index, static_cast<int>(streams_.size())); |
645 | 599 |
646 // Defend against ffmpeg giving us a bad stream index. | 600 // Defend against ffmpeg giving us a bad stream index. |
647 if (packet->stream_index >= 0 && | 601 if (packet->stream_index >= 0 && |
648 packet->stream_index < static_cast<int>(streams_.size()) && | 602 packet->stream_index < static_cast<int>(streams_.size()) && |
649 streams_[packet->stream_index] && | 603 streams_[packet->stream_index] && |
650 (!audio_disabled_ || | 604 (!audio_disabled_ || |
651 streams_[packet->stream_index]->type() != DemuxerStream::AUDIO)) { | 605 streams_[packet->stream_index]->type() != DemuxerStream::AUDIO)) { |
652 FFmpegDemuxerStream* demuxer_stream = streams_[packet->stream_index]; | 606 FFmpegDemuxerStream* demuxer_stream = streams_[packet->stream_index]; |
653 | |
654 // If a packet is returned by FFmpeg's av_parser_parse2() | |
655 // the packet will reference an inner memory of FFmpeg. | |
656 // In this case, the packet's "destruct" member is NULL, | |
657 // and it MUST be duplicated. This fixes issue with MP3 and possibly | |
658 // other codecs. It is safe to call this function even if the packet does | |
659 // not refer to inner memory from FFmpeg. | |
660 av_dup_packet(packet.get()); | |
661 | |
662 demuxer_stream->EnqueuePacket(packet.Pass()); | 607 demuxer_stream->EnqueuePacket(packet.Pass()); |
663 } | 608 } |
664 | 609 |
665 // Create a loop by posting another task. This allows seek and message loop | 610 // Create a loop by posting another task. This allows seek and message loop |
666 // quit tasks to get processed. | 611 // quit tasks to get processed. |
667 if (StreamsHavePendingReads()) { | 612 if (StreamsHavePendingReads()) { |
668 PostDemuxTask(); | 613 PostDemuxTask(); |
669 } | 614 } |
670 } | 615 } |
671 | 616 |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
723 read_event_.Wait(); | 668 read_event_.Wait(); |
724 return last_read_bytes_; | 669 return last_read_bytes_; |
725 } | 670 } |
726 | 671 |
727 void FFmpegDemuxer::SignalReadCompleted(int size) { | 672 void FFmpegDemuxer::SignalReadCompleted(int size) { |
728 last_read_bytes_ = size; | 673 last_read_bytes_ = size; |
729 read_event_.Signal(); | 674 read_event_.Signal(); |
730 } | 675 } |
731 | 676 |
732 } // namespace media | 677 } // namespace media |
OLD | NEW |