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

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

Powered by Google App Engine
This is Rietveld 408576698