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

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

Issue 13813016: Remove reference counting from media::Demuxer and friends. (Closed) Base URL: http://git.chromium.org/chromium/src.git@vd_scoped
Patch Set: demuxer only Created 7 years, 8 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
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/base64.h" 10 #include "base/base64.h"
(...skipping 24 matching lines...) Expand all
35 // 35 //
36 // FFmpegDemuxerStream 36 // FFmpegDemuxerStream
37 // 37 //
38 FFmpegDemuxerStream::FFmpegDemuxerStream( 38 FFmpegDemuxerStream::FFmpegDemuxerStream(
39 FFmpegDemuxer* demuxer, 39 FFmpegDemuxer* demuxer,
40 AVStream* stream) 40 AVStream* stream)
41 : demuxer_(demuxer), 41 : demuxer_(demuxer),
42 message_loop_(base::MessageLoopProxy::current()), 42 message_loop_(base::MessageLoopProxy::current()),
43 stream_(stream), 43 stream_(stream),
44 type_(UNKNOWN), 44 type_(UNKNOWN),
45 stopped_(false),
46 end_of_stream_(false), 45 end_of_stream_(false),
47 last_packet_timestamp_(kNoTimestamp()), 46 last_packet_timestamp_(kNoTimestamp()),
48 bitstream_converter_enabled_(false) { 47 bitstream_converter_enabled_(false) {
49 DCHECK(demuxer_); 48 DCHECK(demuxer_);
50 49
51 bool is_encrypted = false; 50 bool is_encrypted = false;
52 51
53 // Determine our media format. 52 // Determine our media format.
54 switch (stream->codec->codec_type) { 53 switch (stream->codec->codec_type) {
55 case AVMEDIA_TYPE_AUDIO: 54 case AVMEDIA_TYPE_AUDIO:
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
90 return; 89 return;
91 90
92 encryption_key_id_.assign(enc_key_id); 91 encryption_key_id_.assign(enc_key_id);
93 demuxer_->FireNeedKey(kWebMEncryptInitDataType, enc_key_id); 92 demuxer_->FireNeedKey(kWebMEncryptInitDataType, enc_key_id);
94 } 93 }
95 } 94 }
96 95
97 void FFmpegDemuxerStream::EnqueuePacket(ScopedAVPacket packet) { 96 void FFmpegDemuxerStream::EnqueuePacket(ScopedAVPacket packet) {
98 DCHECK(message_loop_->BelongsToCurrentThread()); 97 DCHECK(message_loop_->BelongsToCurrentThread());
99 98
100 if (stopped_ || end_of_stream_) { 99 if (!demuxer_ || end_of_stream_) {
101 NOTREACHED() << "Attempted to enqueue packet on a stopped stream"; 100 NOTREACHED() << "Attempted to enqueue packet on a stopped stream";
102 return; 101 return;
103 } 102 }
104 103
105 // Convert the packet if there is a bitstream filter. 104 // Convert the packet if there is a bitstream filter.
106 if (packet->data && bitstream_converter_enabled_ && 105 if (packet->data && bitstream_converter_enabled_ &&
107 !bitstream_converter_->ConvertPacket(packet.get())) { 106 !bitstream_converter_->ConvertPacket(packet.get())) {
108 LOG(ERROR) << "Format conversion failed."; 107 LOG(ERROR) << "Format conversion failed.";
109 } 108 }
110 109
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
155 last_packet_timestamp_ = kNoTimestamp(); 154 last_packet_timestamp_ = kNoTimestamp();
156 } 155 }
157 156
158 void FFmpegDemuxerStream::Stop() { 157 void FFmpegDemuxerStream::Stop() {
159 DCHECK(message_loop_->BelongsToCurrentThread()); 158 DCHECK(message_loop_->BelongsToCurrentThread());
160 buffer_queue_.Clear(); 159 buffer_queue_.Clear();
161 if (!read_cb_.is_null()) { 160 if (!read_cb_.is_null()) {
162 base::ResetAndReturn(&read_cb_).Run( 161 base::ResetAndReturn(&read_cb_).Run(
163 DemuxerStream::kOk, DecoderBuffer::CreateEOSBuffer()); 162 DemuxerStream::kOk, DecoderBuffer::CreateEOSBuffer());
164 } 163 }
165 stopped_ = true; 164 demuxer_ = NULL;
165 stream_ = NULL;
166 end_of_stream_ = true; 166 end_of_stream_ = true;
167 } 167 }
168 168
169 base::TimeDelta FFmpegDemuxerStream::duration() { 169 base::TimeDelta FFmpegDemuxerStream::duration() {
170 return duration_; 170 return duration_;
171 } 171 }
172 172
173 DemuxerStream::Type FFmpegDemuxerStream::type() { 173 DemuxerStream::Type FFmpegDemuxerStream::type() {
174 DCHECK(message_loop_->BelongsToCurrentThread()); 174 DCHECK(message_loop_->BelongsToCurrentThread());
175 return type_; 175 return type_;
176 } 176 }
177 177
178 void FFmpegDemuxerStream::Read(const ReadCB& read_cb) { 178 void FFmpegDemuxerStream::Read(const ReadCB& read_cb) {
179 DCHECK(message_loop_->BelongsToCurrentThread()); 179 DCHECK(message_loop_->BelongsToCurrentThread());
180 CHECK(read_cb_.is_null()) << "Overlapping reads are not supported"; 180 CHECK(read_cb_.is_null()) << "Overlapping reads are not supported";
181 read_cb_ = BindToCurrentLoop(read_cb); 181 read_cb_ = BindToCurrentLoop(read_cb);
182 182
183 // Don't accept any additional reads if we've been told to stop. 183 // Don't accept any additional reads if we've been told to stop.
184 // The |demuxer_| may have been destroyed in the pipeline thread. 184 // The |demuxer_| may have been destroyed in the pipeline thread.
185 // 185 //
186 // TODO(scherkus): it would be cleaner to reply with an error message. 186 // TODO(scherkus): it would be cleaner to reply with an error message.
187 if (stopped_) { 187 if (!demuxer_) {
188 base::ResetAndReturn(&read_cb_).Run( 188 base::ResetAndReturn(&read_cb_).Run(
189 DemuxerStream::kOk, DecoderBuffer::CreateEOSBuffer()); 189 DemuxerStream::kOk, DecoderBuffer::CreateEOSBuffer());
190 return; 190 return;
191 } 191 }
192 192
193 SatisfyPendingRead(); 193 SatisfyPendingRead();
194 } 194 }
195 195
196 void FFmpegDemuxerStream::EnableBitstreamConverter() { 196 void FFmpegDemuxerStream::EnableBitstreamConverter() {
197 DCHECK(message_loop_->BelongsToCurrentThread()); 197 DCHECK(message_loop_->BelongsToCurrentThread());
198 CHECK(bitstream_converter_.get()); 198 CHECK(bitstream_converter_.get());
199 bitstream_converter_enabled_ = true; 199 bitstream_converter_enabled_ = true;
200 } 200 }
201 201
202 const AudioDecoderConfig& FFmpegDemuxerStream::audio_decoder_config() { 202 const AudioDecoderConfig& FFmpegDemuxerStream::audio_decoder_config() {
203 DCHECK(message_loop_->BelongsToCurrentThread()); 203 DCHECK(message_loop_->BelongsToCurrentThread());
204 CHECK_EQ(type_, AUDIO); 204 CHECK_EQ(type_, AUDIO);
205 return audio_config_; 205 return audio_config_;
206 } 206 }
207 207
208 const VideoDecoderConfig& FFmpegDemuxerStream::video_decoder_config() { 208 const VideoDecoderConfig& FFmpegDemuxerStream::video_decoder_config() {
209 DCHECK(message_loop_->BelongsToCurrentThread()); 209 DCHECK(message_loop_->BelongsToCurrentThread());
210 CHECK_EQ(type_, VIDEO); 210 CHECK_EQ(type_, VIDEO);
211 return video_config_; 211 return video_config_;
212 } 212 }
213 213
214 FFmpegDemuxerStream::~FFmpegDemuxerStream() { 214 FFmpegDemuxerStream::~FFmpegDemuxerStream() {
215 DCHECK(stopped_); 215 DCHECK(!demuxer_);
216 DCHECK(read_cb_.is_null()); 216 DCHECK(read_cb_.is_null());
217 DCHECK(buffer_queue_.IsEmpty()); 217 DCHECK(buffer_queue_.IsEmpty());
218 } 218 }
219 219
220 base::TimeDelta FFmpegDemuxerStream::GetElapsedTime() const { 220 base::TimeDelta FFmpegDemuxerStream::GetElapsedTime() const {
221 return ConvertStreamTimestamp(stream_->time_base, stream_->cur_dts); 221 return ConvertStreamTimestamp(stream_->time_base, stream_->cur_dts);
222 } 222 }
223 223
224 Ranges<base::TimeDelta> FFmpegDemuxerStream::GetBufferedRanges() const { 224 Ranges<base::TimeDelta> FFmpegDemuxerStream::GetBufferedRanges() const {
225 return buffered_ranges_; 225 return buffered_ranges_;
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 265
266 // 266 //
267 // FFmpegDemuxer 267 // FFmpegDemuxer
268 // 268 //
269 FFmpegDemuxer::FFmpegDemuxer( 269 FFmpegDemuxer::FFmpegDemuxer(
270 const scoped_refptr<base::MessageLoopProxy>& message_loop, 270 const scoped_refptr<base::MessageLoopProxy>& message_loop,
271 const scoped_refptr<DataSource>& data_source, 271 const scoped_refptr<DataSource>& data_source,
272 const FFmpegNeedKeyCB& need_key_cb) 272 const FFmpegNeedKeyCB& need_key_cb)
273 : host_(NULL), 273 : host_(NULL),
274 message_loop_(message_loop), 274 message_loop_(message_loop),
275 weak_factory_(this),
275 blocking_thread_("FFmpegDemuxer"), 276 blocking_thread_("FFmpegDemuxer"),
276 pending_read_(false), 277 pending_read_(false),
277 pending_seek_(false), 278 pending_seek_(false),
278 data_source_(data_source), 279 data_source_(data_source),
279 bitrate_(0), 280 bitrate_(0),
280 start_time_(kNoTimestamp()), 281 start_time_(kNoTimestamp()),
281 audio_disabled_(false), 282 audio_disabled_(false),
282 duration_known_(false), 283 duration_known_(false),
283 url_protocol_(data_source, BindToLoop(message_loop_, base::Bind( 284 url_protocol_(data_source, BindToLoop(message_loop_, base::Bind(
284 &FFmpegDemuxer::OnDataSourceError, base::Unretained(this)))), 285 &FFmpegDemuxer::OnDataSourceError, base::Unretained(this)))),
285 need_key_cb_(need_key_cb) { 286 need_key_cb_(need_key_cb) {
286 DCHECK(message_loop_); 287 DCHECK(message_loop_);
287 DCHECK(data_source_); 288 DCHECK(data_source_);
288 } 289 }
289 290
290 FFmpegDemuxer::~FFmpegDemuxer() {} 291 FFmpegDemuxer::~FFmpegDemuxer() {}
291 292
292 void FFmpegDemuxer::Stop(const base::Closure& callback) { 293 void FFmpegDemuxer::Stop(const base::Closure& callback) {
293 DCHECK(message_loop_->BelongsToCurrentThread()); 294 DCHECK(message_loop_->BelongsToCurrentThread());
294 url_protocol_.Abort(); 295 url_protocol_.Abort();
295 data_source_->Stop(BindToCurrentLoop(base::Bind( 296 data_source_->Stop(BindToCurrentLoop(base::Bind(
296 &FFmpegDemuxer::OnDataSourceStopped, this, BindToCurrentLoop(callback)))); 297 &FFmpegDemuxer::OnDataSourceStopped, weak_this_,
298 BindToCurrentLoop(callback))));
297 } 299 }
298 300
299 void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) { 301 void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) {
300 DCHECK(message_loop_->BelongsToCurrentThread()); 302 DCHECK(message_loop_->BelongsToCurrentThread());
301 CHECK(!pending_seek_); 303 CHECK(!pending_seek_);
302 304
303 // TODO(scherkus): Inspect |pending_read_| and cancel IO via |blocking_url_|, 305 // TODO(scherkus): Inspect |pending_read_| and cancel IO via |blocking_url_|,
304 // otherwise we can end up waiting for a pre-seek read to complete even though 306 // otherwise we can end up waiting for a pre-seek read to complete even though
305 // we know we're going to drop it on the floor. 307 // we know we're going to drop it on the floor.
306 308
307 // Always seek to a timestamp less than or equal to the desired timestamp. 309 // Always seek to a timestamp less than or equal to the desired timestamp.
308 int flags = AVSEEK_FLAG_BACKWARD; 310 int flags = AVSEEK_FLAG_BACKWARD;
309 311
310 // Passing -1 as our stream index lets FFmpeg pick a default stream. FFmpeg 312 // Passing -1 as our stream index lets FFmpeg pick a default stream. FFmpeg
311 // will attempt to use the lowest-index video stream, if present, followed by 313 // will attempt to use the lowest-index video stream, if present, followed by
312 // the lowest-index audio stream. 314 // the lowest-index audio stream.
313 pending_seek_ = true; 315 pending_seek_ = true;
314 base::PostTaskAndReplyWithResult( 316 base::PostTaskAndReplyWithResult(
315 blocking_thread_.message_loop_proxy(), FROM_HERE, 317 blocking_thread_.message_loop_proxy(), FROM_HERE,
316 base::Bind(&av_seek_frame, glue_->format_context(), -1, 318 base::Bind(&av_seek_frame, glue_->format_context(), -1,
317 time.InMicroseconds(), flags), 319 time.InMicroseconds(), flags),
318 base::Bind(&FFmpegDemuxer::OnSeekFrameDone, this, cb)); 320 base::Bind(&FFmpegDemuxer::OnSeekFrameDone, weak_this_, cb));
319 } 321 }
320 322
321 void FFmpegDemuxer::SetPlaybackRate(float playback_rate) { 323 void FFmpegDemuxer::SetPlaybackRate(float playback_rate) {
322 DCHECK(message_loop_->BelongsToCurrentThread()); 324 DCHECK(message_loop_->BelongsToCurrentThread());
323 data_source_->SetPlaybackRate(playback_rate); 325 data_source_->SetPlaybackRate(playback_rate);
324 } 326 }
325 327
326 void FFmpegDemuxer::OnAudioRendererDisabled() { 328 void FFmpegDemuxer::OnAudioRendererDisabled() {
327 DCHECK(message_loop_->BelongsToCurrentThread()); 329 DCHECK(message_loop_->BelongsToCurrentThread());
328 audio_disabled_ = true; 330 audio_disabled_ = true;
329 StreamVector::iterator iter; 331 StreamVector::iterator iter;
330 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 332 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
331 if (*iter && (*iter)->type() == DemuxerStream::AUDIO) { 333 if (*iter && (*iter)->type() == DemuxerStream::AUDIO) {
332 (*iter)->Stop(); 334 (*iter)->Stop();
333 } 335 }
334 } 336 }
335 } 337 }
336 338
337 void FFmpegDemuxer::Initialize(DemuxerHost* host, 339 void FFmpegDemuxer::Initialize(DemuxerHost* host,
338 const PipelineStatusCB& status_cb) { 340 const PipelineStatusCB& status_cb) {
339 DCHECK(message_loop_->BelongsToCurrentThread()); 341 DCHECK(message_loop_->BelongsToCurrentThread());
340 host_ = host; 342 host_ = host;
343 weak_this_ = weak_factory_.GetWeakPtr();
341 344
342 // TODO(scherkus): DataSource should have a host by this point, 345 // TODO(scherkus): DataSource should have a host by this point,
343 // see http://crbug.com/122071 346 // see http://crbug.com/122071
344 data_source_->set_host(host); 347 data_source_->set_host(host);
345 348
346 glue_.reset(new FFmpegGlue(&url_protocol_)); 349 glue_.reset(new FFmpegGlue(&url_protocol_));
347 AVFormatContext* format_context = glue_->format_context(); 350 AVFormatContext* format_context = glue_->format_context();
348 351
349 // Disable ID3v1 tag reading to avoid costly seeks to end of file for data we 352 // Disable ID3v1 tag reading to avoid costly seeks to end of file for data we
350 // don't use. FFmpeg will only read ID3v1 tags if no other metadata is 353 // don't use. FFmpeg will only read ID3v1 tags if no other metadata is
351 // available, so add a metadata entry to ensure some is always present. 354 // available, so add a metadata entry to ensure some is always present.
352 av_dict_set(&format_context->metadata, "skip_id3v1_tags", "", 0); 355 av_dict_set(&format_context->metadata, "skip_id3v1_tags", "", 0);
353 356
354 // Open the AVFormatContext using our glue layer. 357 // Open the AVFormatContext using our glue layer.
355 CHECK(blocking_thread_.Start()); 358 CHECK(blocking_thread_.Start());
356 base::PostTaskAndReplyWithResult( 359 base::PostTaskAndReplyWithResult(
357 blocking_thread_.message_loop_proxy(), FROM_HERE, 360 blocking_thread_.message_loop_proxy(), FROM_HERE,
358 base::Bind(&FFmpegGlue::OpenContext, base::Unretained(glue_.get())), 361 base::Bind(&FFmpegGlue::OpenContext, base::Unretained(glue_.get())),
359 base::Bind(&FFmpegDemuxer::OnOpenContextDone, this, status_cb)); 362 base::Bind(&FFmpegDemuxer::OnOpenContextDone, weak_this_, status_cb));
360 } 363 }
361 364
362 scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream( 365 scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream(
363 DemuxerStream::Type type) { 366 DemuxerStream::Type type) {
364 DCHECK(message_loop_->BelongsToCurrentThread()); 367 DCHECK(message_loop_->BelongsToCurrentThread());
365 return GetFFmpegStream(type); 368 return GetFFmpegStream(type);
366 } 369 }
367 370
368 scoped_refptr<FFmpegDemuxerStream> FFmpegDemuxer::GetFFmpegStream( 371 scoped_refptr<FFmpegDemuxerStream> FFmpegDemuxer::GetFFmpegStream(
369 DemuxerStream::Type type) const { 372 DemuxerStream::Type type) const {
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
428 if (!result) { 431 if (!result) {
429 status_cb.Run(DEMUXER_ERROR_COULD_NOT_OPEN); 432 status_cb.Run(DEMUXER_ERROR_COULD_NOT_OPEN);
430 return; 433 return;
431 } 434 }
432 435
433 // Fully initialize AVFormatContext by parsing the stream a little. 436 // Fully initialize AVFormatContext by parsing the stream a little.
434 base::PostTaskAndReplyWithResult( 437 base::PostTaskAndReplyWithResult(
435 blocking_thread_.message_loop_proxy(), FROM_HERE, 438 blocking_thread_.message_loop_proxy(), FROM_HERE,
436 base::Bind(&avformat_find_stream_info, glue_->format_context(), 439 base::Bind(&avformat_find_stream_info, glue_->format_context(),
437 static_cast<AVDictionary**>(NULL)), 440 static_cast<AVDictionary**>(NULL)),
438 base::Bind(&FFmpegDemuxer::OnFindStreamInfoDone, this, status_cb)); 441 base::Bind(&FFmpegDemuxer::OnFindStreamInfoDone, weak_this_, status_cb));
439 } 442 }
440 443
441 void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, 444 void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb,
442 int result) { 445 int result) {
443 DCHECK(message_loop_->BelongsToCurrentThread()); 446 DCHECK(message_loop_->BelongsToCurrentThread());
444 if (!blocking_thread_.IsRunning()) { 447 if (!blocking_thread_.IsRunning()) {
445 status_cb.Run(PIPELINE_ERROR_ABORT); 448 status_cb.Run(PIPELINE_ERROR_ABORT);
446 return; 449 return;
447 } 450 }
448 451
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
579 // Allocate and read an AVPacket from the media. Save |packet_ptr| since 582 // Allocate and read an AVPacket from the media. Save |packet_ptr| since
580 // evaluation order of packet.get() and base::Passed(&packet) is 583 // evaluation order of packet.get() and base::Passed(&packet) is
581 // undefined. 584 // undefined.
582 ScopedAVPacket packet(new AVPacket()); 585 ScopedAVPacket packet(new AVPacket());
583 AVPacket* packet_ptr = packet.get(); 586 AVPacket* packet_ptr = packet.get();
584 587
585 pending_read_ = true; 588 pending_read_ = true;
586 base::PostTaskAndReplyWithResult( 589 base::PostTaskAndReplyWithResult(
587 blocking_thread_.message_loop_proxy(), FROM_HERE, 590 blocking_thread_.message_loop_proxy(), FROM_HERE,
588 base::Bind(&av_read_frame, glue_->format_context(), packet_ptr), 591 base::Bind(&av_read_frame, glue_->format_context(), packet_ptr),
589 base::Bind(&FFmpegDemuxer::OnReadFrameDone, this, base::Passed(&packet))); 592 base::Bind(&FFmpegDemuxer::OnReadFrameDone, weak_this_,
593 base::Passed(&packet)));
590 } 594 }
591 595
592 void FFmpegDemuxer::OnReadFrameDone(ScopedAVPacket packet, int result) { 596 void FFmpegDemuxer::OnReadFrameDone(ScopedAVPacket packet, int result) {
593 DCHECK(message_loop_->BelongsToCurrentThread()); 597 DCHECK(message_loop_->BelongsToCurrentThread());
594 DCHECK(pending_read_); 598 DCHECK(pending_read_);
595 pending_read_ = false; 599 pending_read_ = false;
596 600
597 if (!blocking_thread_.IsRunning() || pending_seek_) { 601 if (!blocking_thread_.IsRunning() || pending_seek_) {
598 return; 602 return;
599 } 603 }
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
730 } 734 }
731 for (size_t i = 0; i < buffered.size(); ++i) 735 for (size_t i = 0; i < buffered.size(); ++i)
732 host_->AddBufferedTimeRange(buffered.start(i), buffered.end(i)); 736 host_->AddBufferedTimeRange(buffered.start(i), buffered.end(i));
733 } 737 }
734 738
735 void FFmpegDemuxer::OnDataSourceError() { 739 void FFmpegDemuxer::OnDataSourceError() {
736 host_->OnDemuxerError(PIPELINE_ERROR_READ); 740 host_->OnDemuxerError(PIPELINE_ERROR_READ);
737 } 741 }
738 742
739 } // namespace media 743 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698