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

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

Powered by Google App Engine
This is Rietveld 408576698