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

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: s/2011/2012/ 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
« no previous file with comments | « media/filters/ffmpeg_demuxer.h ('k') | media/filters/ffmpeg_demuxer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 scoped_refptr<DecoderBuffer> buffer;
115 if (packet->data && bitstream_converter_.get() && 80 if (!packet.get()) {
116 !bitstream_converter_->ConvertPacket(packet.get())) { 81 buffer = DecoderBuffer::CreateEOSBuffer();
117 LOG(ERROR) << "Format converstion failed."; 82 } else {
83 // Convert the packet if there is a bitstream filter.
84 if (packet->data && bitstream_converter_.get() &&
85 !bitstream_converter_->ConvertPacket(packet.get())) {
86 LOG(ERROR) << "Format converstion failed.";
87 }
88
89 // 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
91 // into memory we control.
92 buffer = DecoderBuffer::CopyFrom(packet->data, packet->size);
93 buffer->SetTimestamp(ConvertStreamTimestamp(
94 stream_->time_base, packet->pts));
95 buffer->SetDuration(ConvertStreamTimestamp(
96 stream_->time_base, packet->duration));
118 } 97 }
119 98
120 // Enqueue the callback and attempt to satisfy a read immediately.
121 scoped_refptr<Buffer> buffer(
122 new AVPacketBuffer(packet.Pass(), timestamp, duration));
123 if (!buffer) {
124 NOTREACHED() << "Unable to allocate AVPacketBuffer";
125 return;
126 }
127 buffer_queue_.push_back(buffer); 99 buffer_queue_.push_back(buffer);
128 FulfillPendingRead(); 100 FulfillPendingRead();
129 return; 101 return;
130 } 102 }
131 103
132 void FFmpegDemuxerStream::FlushBuffers() { 104 void FFmpegDemuxerStream::FlushBuffers() {
133 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); 105 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop());
134 base::AutoLock auto_lock(lock_); 106 base::AutoLock auto_lock(lock_);
135 DCHECK(read_queue_.empty()) << "Read requests should be empty"; 107 DCHECK(read_queue_.empty()) << "Read requests should be empty";
136 buffer_queue_.clear(); 108 buffer_queue_.clear();
137 } 109 }
138 110
139 void FFmpegDemuxerStream::Stop() { 111 void FFmpegDemuxerStream::Stop() {
140 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); 112 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop());
141 base::AutoLock auto_lock(lock_); 113 base::AutoLock auto_lock(lock_);
142 buffer_queue_.clear(); 114 buffer_queue_.clear();
143 for (ReadQueue::iterator it = read_queue_.begin(); 115 for (ReadQueue::iterator it = read_queue_.begin();
144 it != read_queue_.end(); ++it) { 116 it != read_queue_.end(); ++it) {
145 it->Run(scoped_refptr<Buffer>(new DataBuffer(0))); 117 it->Run(scoped_refptr<DecoderBuffer>(DecoderBuffer::CreateEOSBuffer()));
146 } 118 }
147 read_queue_.clear(); 119 read_queue_.clear();
148 stopped_ = true; 120 stopped_ = true;
149 } 121 }
150 122
151 base::TimeDelta FFmpegDemuxerStream::duration() { 123 base::TimeDelta FFmpegDemuxerStream::duration() {
152 return duration_; 124 return duration_;
153 } 125 }
154 126
155 DemuxerStream::Type FFmpegDemuxerStream::type() { 127 DemuxerStream::Type FFmpegDemuxerStream::type() {
156 return type_; 128 return type_;
157 } 129 }
158 130
159 void FFmpegDemuxerStream::Read(const ReadCB& read_cb) { 131 void FFmpegDemuxerStream::Read(const ReadCB& read_cb) {
160 DCHECK(!read_cb.is_null()); 132 DCHECK(!read_cb.is_null());
161 133
162 base::AutoLock auto_lock(lock_); 134 base::AutoLock auto_lock(lock_);
163 // Don't accept any additional reads if we've been told to stop. 135 // Don't accept any additional reads if we've been told to stop.
164 // The demuxer_ may have been destroyed in the pipleine thread. 136 // The demuxer_ may have been destroyed in the pipleine thread.
165 // 137 //
166 // TODO(scherkus): it would be cleaner if we replied with an error message. 138 // TODO(scherkus): it would be cleaner if we replied with an error message.
167 if (stopped_) { 139 if (stopped_) {
168 read_cb.Run(scoped_refptr<Buffer>(new DataBuffer(0))); 140 read_cb.Run(scoped_refptr<DecoderBuffer>(DecoderBuffer::CreateEOSBuffer()));
169 return; 141 return;
170 } 142 }
171 143
172 // Buffers are only queued when there are no pending reads. 144 // Buffers are only queued when there are no pending reads.
173 DCHECK(buffer_queue_.empty() || read_queue_.empty()); 145 DCHECK(buffer_queue_.empty() || read_queue_.empty());
174 146
175 if (buffer_queue_.empty()) { 147 if (buffer_queue_.empty()) {
176 demuxer_->message_loop()->PostTask(FROM_HERE, base::Bind( 148 demuxer_->message_loop()->PostTask(FROM_HERE, base::Bind(
177 &FFmpegDemuxerStream::ReadTask, this, read_cb)); 149 &FFmpegDemuxerStream::ReadTask, this, read_cb));
178 return; 150 return;
179 } 151 }
180 152
181 // Send the oldest buffer back. 153 // Send the oldest buffer back.
182 scoped_refptr<Buffer> buffer = buffer_queue_.front(); 154 scoped_refptr<DecoderBuffer> buffer = buffer_queue_.front();
183 buffer_queue_.pop_front(); 155 buffer_queue_.pop_front();
184 read_cb.Run(buffer); 156 read_cb.Run(buffer);
185 } 157 }
186 158
187 void FFmpegDemuxerStream::ReadTask(const ReadCB& read_cb) { 159 void FFmpegDemuxerStream::ReadTask(const ReadCB& read_cb) {
188 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); 160 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop());
189 161
190 base::AutoLock auto_lock(lock_); 162 base::AutoLock auto_lock(lock_);
191 // Don't accept any additional reads if we've been told to stop. 163 // Don't accept any additional reads if we've been told to stop.
192 // 164 //
193 // TODO(scherkus): it would be cleaner if we replied with an error message. 165 // TODO(scherkus): it would be cleaner if we replied with an error message.
194 if (stopped_) { 166 if (stopped_) {
195 read_cb.Run(scoped_refptr<Buffer>(new DataBuffer(0))); 167 read_cb.Run(scoped_refptr<DecoderBuffer>(DecoderBuffer::CreateEOSBuffer()));
196 return; 168 return;
197 } 169 }
198 170
199 // Enqueue the callback and attempt to satisfy it immediately. 171 // Enqueue the callback and attempt to satisfy it immediately.
200 read_queue_.push_back(read_cb); 172 read_queue_.push_back(read_cb);
201 FulfillPendingRead(); 173 FulfillPendingRead();
202 174
203 // Check if there are still pending reads, demux some more. 175 // Check if there are still pending reads, demux some more.
204 if (!read_queue_.empty()) { 176 if (!read_queue_.empty()) {
205 demuxer_->PostDemuxTask(); 177 demuxer_->PostDemuxTask();
206 } 178 }
207 } 179 }
208 180
209 void FFmpegDemuxerStream::FulfillPendingRead() { 181 void FFmpegDemuxerStream::FulfillPendingRead() {
210 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); 182 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop());
211 lock_.AssertAcquired(); 183 lock_.AssertAcquired();
212 if (buffer_queue_.empty() || read_queue_.empty()) { 184 if (buffer_queue_.empty() || read_queue_.empty()) {
213 return; 185 return;
214 } 186 }
215 187
216 // Dequeue a buffer and pending read pair. 188 // Dequeue a buffer and pending read pair.
217 scoped_refptr<Buffer> buffer = buffer_queue_.front(); 189 scoped_refptr<DecoderBuffer> buffer = buffer_queue_.front();
218 ReadCB read_cb(read_queue_.front()); 190 ReadCB read_cb(read_queue_.front());
219 buffer_queue_.pop_front(); 191 buffer_queue_.pop_front();
220 read_queue_.pop_front(); 192 read_queue_.pop_front();
221 193
222 // Execute the callback. 194 // Execute the callback.
223 read_cb.Run(buffer); 195 read_cb.Run(buffer);
224 } 196 }
225 197
226 void FFmpegDemuxerStream::EnableBitstreamConverter() { 198 void FFmpegDemuxerStream::EnableBitstreamConverter() {
227 // Called by hardware decoder to require different bitstream converter. 199 // Called by hardware decoder to require different bitstream converter.
228 // Currently we assume that converter is determined by codec_id; 200 // Currently we assume that converter is determined by codec_id;
229 DCHECK(stream_); 201 DCHECK(stream_);
230 202
231 if (stream_->codec->codec_id == CODEC_ID_H264) { 203 if (stream_->codec->codec_id == CODEC_ID_H264) {
232 // Use Chromium bitstream converter in case of H.264 204 // Use Chromium bitstream converter in case of H.264
233 bitstream_converter_.reset( 205 bitstream_converter_.reset(
234 new FFmpegH264BitstreamConverter(stream_->codec)); 206 new FFmpegH264BitstreamConverter(stream_->codec));
235 CHECK(bitstream_converter_->Initialize()); 207 CHECK(bitstream_converter_->Initialize());
236 return; 208 } 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( 209 bitstream_converter_.reset(
250 new FFmpegBitstreamConverter(filter_name, stream_->codec)); 210 new FFmpegBitstreamConverter("mpeg4video_es", stream_->codec));
251 CHECK(bitstream_converter_->Initialize()); 211 CHECK(bitstream_converter_->Initialize());
212 } else {
213 NOTREACHED() << "Unsupported bitstream format.";
252 } 214 }
253 } 215 }
254 216
255 const AudioDecoderConfig& FFmpegDemuxerStream::audio_decoder_config() { 217 const AudioDecoderConfig& FFmpegDemuxerStream::audio_decoder_config() {
256 CHECK_EQ(type_, AUDIO); 218 CHECK_EQ(type_, AUDIO);
257 return audio_config_; 219 return audio_config_;
258 } 220 }
259 221
260 const VideoDecoderConfig& FFmpegDemuxerStream::video_decoder_config() { 222 const VideoDecoderConfig& FFmpegDemuxerStream::video_decoder_config() {
261 CHECK_EQ(type_, VIDEO); 223 CHECK_EQ(type_, VIDEO);
(...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after
669 DCHECK_GE(packet->stream_index, 0); 631 DCHECK_GE(packet->stream_index, 0);
670 DCHECK_LT(packet->stream_index, static_cast<int>(streams_.size())); 632 DCHECK_LT(packet->stream_index, static_cast<int>(streams_.size()));
671 633
672 // Defend against ffmpeg giving us a bad stream index. 634 // Defend against ffmpeg giving us a bad stream index.
673 if (packet->stream_index >= 0 && 635 if (packet->stream_index >= 0 &&
674 packet->stream_index < static_cast<int>(streams_.size()) && 636 packet->stream_index < static_cast<int>(streams_.size()) &&
675 streams_[packet->stream_index] && 637 streams_[packet->stream_index] &&
676 (!audio_disabled_ || 638 (!audio_disabled_ ||
677 streams_[packet->stream_index]->type() != DemuxerStream::AUDIO)) { 639 streams_[packet->stream_index]->type() != DemuxerStream::AUDIO)) {
678 FFmpegDemuxerStream* demuxer_stream = streams_[packet->stream_index]; 640 FFmpegDemuxerStream* demuxer_stream = streams_[packet->stream_index];
679
680 // If a packet is returned by FFmpeg's av_parser_parse2()
681 // the packet will reference an inner memory of FFmpeg.
682 // In this case, the packet's "destruct" member is NULL,
683 // and it MUST be duplicated. This fixes issue with MP3 and possibly
684 // other codecs. It is safe to call this function even if the packet does
685 // not refer to inner memory from FFmpeg.
686 av_dup_packet(packet.get());
687
688 demuxer_stream->EnqueuePacket(packet.Pass()); 641 demuxer_stream->EnqueuePacket(packet.Pass());
689 } 642 }
690 643
691 // Create a loop by posting another task. This allows seek and message loop 644 // Create a loop by posting another task. This allows seek and message loop
692 // quit tasks to get processed. 645 // quit tasks to get processed.
693 if (StreamsHavePendingReads()) { 646 if (StreamsHavePendingReads()) {
694 PostDemuxTask(); 647 PostDemuxTask();
695 } 648 }
696 } 649 }
697 650
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
732 } 685 }
733 686
734 void FFmpegDemuxer::StreamHasEnded() { 687 void FFmpegDemuxer::StreamHasEnded() {
735 DCHECK_EQ(MessageLoop::current(), message_loop_); 688 DCHECK_EQ(MessageLoop::current(), message_loop_);
736 StreamVector::iterator iter; 689 StreamVector::iterator iter;
737 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 690 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
738 if (!*iter || 691 if (!*iter ||
739 (audio_disabled_ && (*iter)->type() == DemuxerStream::AUDIO)) { 692 (audio_disabled_ && (*iter)->type() == DemuxerStream::AUDIO)) {
740 continue; 693 continue;
741 } 694 }
742 scoped_ptr_malloc<AVPacket, ScopedPtrAVFreePacket> packet(new AVPacket()); 695 (*iter)->EnqueuePacket(
743 memset(packet.get(), 0, sizeof(*packet.get())); 696 scoped_ptr_malloc<AVPacket, ScopedPtrAVFreePacket>());
744 (*iter)->EnqueuePacket(packet.Pass());
745 } 697 }
746 } 698 }
747 699
748 int FFmpegDemuxer::WaitForRead() { 700 int FFmpegDemuxer::WaitForRead() {
749 read_event_.Wait(); 701 read_event_.Wait();
750 return last_read_bytes_; 702 return last_read_bytes_;
751 } 703 }
752 704
753 void FFmpegDemuxer::SignalReadCompleted(int size) { 705 void FFmpegDemuxer::SignalReadCompleted(int size) {
754 last_read_bytes_ = size; 706 last_read_bytes_ = size;
755 read_event_.Signal(); 707 read_event_.Signal();
756 } 708 }
757 709
758 } // namespace media 710 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/ffmpeg_demuxer.h ('k') | media/filters/ffmpeg_demuxer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698