| 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 25 matching lines...) Expand all Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |