| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |