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

Side by Side Diff: media/filters/ffmpeg_demuxer.cc

Issue 10447035: Introducing DecoderBuffer and general Buffer cleanup. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Buffer Bonanza! Created 8 years, 7 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 | Annotate | Revision Log
OLDNEW
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698