| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 "base/scoped_ptr.h" | 5 #include "base/scoped_ptr.h" |
| 6 #include "base/stl_util-inl.h" | 6 #include "base/stl_util-inl.h" |
| 7 #include "base/string_util.h" | 7 #include "base/string_util.h" |
| 8 #include "base/time.h" | 8 #include "base/time.h" |
| 9 #include "media/base/filter_host.h" | 9 #include "media/base/filter_host.h" |
| 10 #include "media/filters/ffmpeg_common.h" | 10 #include "media/filters/ffmpeg_common.h" |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 149 STLDeleteElements(&read_queue_); | 149 STLDeleteElements(&read_queue_); |
| 150 stopped_ = true; | 150 stopped_ = true; |
| 151 } | 151 } |
| 152 | 152 |
| 153 const MediaFormat& FFmpegDemuxerStream::media_format() { | 153 const MediaFormat& FFmpegDemuxerStream::media_format() { |
| 154 return media_format_; | 154 return media_format_; |
| 155 } | 155 } |
| 156 | 156 |
| 157 void FFmpegDemuxerStream::Read(Callback1<Buffer*>::Type* read_callback) { | 157 void FFmpegDemuxerStream::Read(Callback1<Buffer*>::Type* read_callback) { |
| 158 DCHECK(read_callback); | 158 DCHECK(read_callback); |
| 159 demuxer_->message_loop_->PostTask(FROM_HERE, | 159 demuxer_->message_loop()->PostTask(FROM_HERE, |
| 160 NewRunnableMethod(this, &FFmpegDemuxerStream::ReadTask, read_callback)); | 160 NewRunnableMethod(this, &FFmpegDemuxerStream::ReadTask, read_callback)); |
| 161 } | 161 } |
| 162 | 162 |
| 163 void FFmpegDemuxerStream::ReadTask(Callback1<Buffer*>::Type* read_callback) { | 163 void FFmpegDemuxerStream::ReadTask(Callback1<Buffer*>::Type* read_callback) { |
| 164 DCHECK_EQ(PlatformThread::CurrentId(), demuxer_->thread_id_); | 164 DCHECK_EQ(PlatformThread::CurrentId(), demuxer_->thread_id_); |
| 165 | 165 |
| 166 // Don't accept any additional reads if we've been told to stop. | 166 // Don't accept any additional reads if we've been told to stop. |
| 167 // | 167 // |
| 168 // TODO(scherkus): it would be cleaner if we replied with an error message. | 168 // TODO(scherkus): it would be cleaner if we replied with an error message. |
| 169 if (stopped_) { | 169 if (stopped_) { |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 245 avcodec_close(stream->codec); | 245 avcodec_close(stream->codec); |
| 246 } | 246 } |
| 247 } | 247 } |
| 248 | 248 |
| 249 // Then finally cleanup the format context. | 249 // Then finally cleanup the format context. |
| 250 av_close_input_file(format_context_); | 250 av_close_input_file(format_context_); |
| 251 format_context_ = NULL; | 251 format_context_ = NULL; |
| 252 } | 252 } |
| 253 | 253 |
| 254 void FFmpegDemuxer::PostDemuxTask() { | 254 void FFmpegDemuxer::PostDemuxTask() { |
| 255 message_loop_->PostTask(FROM_HERE, | 255 message_loop()->PostTask(FROM_HERE, |
| 256 NewRunnableMethod(this, &FFmpegDemuxer::DemuxTask)); | 256 NewRunnableMethod(this, &FFmpegDemuxer::DemuxTask)); |
| 257 } | 257 } |
| 258 | 258 |
| 259 void FFmpegDemuxer::Stop() { | 259 void FFmpegDemuxer::Stop() { |
| 260 // Post a task to notify the streams to stop as well. | 260 // Post a task to notify the streams to stop as well. |
| 261 message_loop_->PostTask(FROM_HERE, | 261 message_loop()->PostTask(FROM_HERE, |
| 262 NewRunnableMethod(this, &FFmpegDemuxer::StopTask)); | 262 NewRunnableMethod(this, &FFmpegDemuxer::StopTask)); |
| 263 } | 263 } |
| 264 | 264 |
| 265 void FFmpegDemuxer::Seek(base::TimeDelta time) { | 265 void FFmpegDemuxer::Seek(base::TimeDelta time) { |
| 266 // TODO(hclam): by returning from this method, it is assumed that the seek | 266 // TODO(hclam): by returning from this method, it is assumed that the seek |
| 267 // operation is completed and filters behind the demuxer is good to issue | 267 // operation is completed and filters behind the demuxer is good to issue |
| 268 // more reads, but we are posting a task here, which makes the seek operation | 268 // more reads, but we are posting a task here, which makes the seek operation |
| 269 // asynchronous, should change how seek works to make it fully asynchronous. | 269 // asynchronous, should change how seek works to make it fully asynchronous. |
| 270 message_loop_->PostTask(FROM_HERE, | 270 message_loop()->PostTask(FROM_HERE, |
| 271 NewRunnableMethod(this, &FFmpegDemuxer::SeekTask, time)); | 271 NewRunnableMethod(this, &FFmpegDemuxer::SeekTask, time)); |
| 272 } | 272 } |
| 273 | 273 |
| 274 bool FFmpegDemuxer::Initialize(DataSource* data_source) { | 274 bool FFmpegDemuxer::Initialize(DataSource* data_source) { |
| 275 message_loop_->PostTask(FROM_HERE, | 275 message_loop()->PostTask(FROM_HERE, |
| 276 NewRunnableMethod(this, &FFmpegDemuxer::InititalizeTask, data_source)); | 276 NewRunnableMethod(this, &FFmpegDemuxer::InititalizeTask, data_source)); |
| 277 return true; | 277 return true; |
| 278 } | 278 } |
| 279 | 279 |
| 280 size_t FFmpegDemuxer::GetNumberOfStreams() { | 280 size_t FFmpegDemuxer::GetNumberOfStreams() { |
| 281 return streams_.size(); | 281 return streams_.size(); |
| 282 } | 282 } |
| 283 | 283 |
| 284 scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream(int stream) { | 284 scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream(int stream) { |
| 285 DCHECK(stream >= 0); | 285 DCHECK(stream >= 0); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 306 | 306 |
| 307 // Open FFmpeg AVFormatContext. | 307 // Open FFmpeg AVFormatContext. |
| 308 DCHECK(!format_context_); | 308 DCHECK(!format_context_); |
| 309 AVFormatContext* context = NULL; | 309 AVFormatContext* context = NULL; |
| 310 int result = av_open_input_file(&context, key.c_str(), NULL, 0, NULL); | 310 int result = av_open_input_file(&context, key.c_str(), NULL, 0, NULL); |
| 311 | 311 |
| 312 // Remove our data source. | 312 // Remove our data source. |
| 313 FFmpegGlue::get()->RemoveDataSource(data_source); | 313 FFmpegGlue::get()->RemoveDataSource(data_source); |
| 314 | 314 |
| 315 if (result < 0) { | 315 if (result < 0) { |
| 316 host_->Error(DEMUXER_ERROR_COULD_NOT_OPEN); | 316 host()->Error(DEMUXER_ERROR_COULD_NOT_OPEN); |
| 317 return; | 317 return; |
| 318 } | 318 } |
| 319 | 319 |
| 320 DCHECK(context); | 320 DCHECK(context); |
| 321 format_context_ = context; | 321 format_context_ = context; |
| 322 | 322 |
| 323 // Serialize calls to av_find_stream_info(). | 323 // Serialize calls to av_find_stream_info(). |
| 324 { | 324 { |
| 325 AutoLock auto_lock(FFmpegLock::get()->lock()); | 325 AutoLock auto_lock(FFmpegLock::get()->lock()); |
| 326 | 326 |
| 327 // Fully initialize AVFormatContext by parsing the stream a little. | 327 // Fully initialize AVFormatContext by parsing the stream a little. |
| 328 result = av_find_stream_info(format_context_); | 328 result = av_find_stream_info(format_context_); |
| 329 if (result < 0) { | 329 if (result < 0) { |
| 330 host_->Error(DEMUXER_ERROR_COULD_NOT_PARSE); | 330 host()->Error(DEMUXER_ERROR_COULD_NOT_PARSE); |
| 331 return; | 331 return; |
| 332 } | 332 } |
| 333 } | 333 } |
| 334 | 334 |
| 335 // Create demuxer streams for all supported streams. | 335 // Create demuxer streams for all supported streams. |
| 336 base::TimeDelta max_duration; | 336 base::TimeDelta max_duration; |
| 337 for (size_t i = 0; i < format_context_->nb_streams; ++i) { | 337 for (size_t i = 0; i < format_context_->nb_streams; ++i) { |
| 338 CodecType codec_type = format_context_->streams[i]->codec->codec_type; | 338 CodecType codec_type = format_context_->streams[i]->codec->codec_type; |
| 339 if (codec_type == CODEC_TYPE_AUDIO || codec_type == CODEC_TYPE_VIDEO) { | 339 if (codec_type == CODEC_TYPE_AUDIO || codec_type == CODEC_TYPE_VIDEO) { |
| 340 AVStream* stream = format_context_->streams[i]; | 340 AVStream* stream = format_context_->streams[i]; |
| 341 FFmpegDemuxerStream* demuxer_stream | 341 FFmpegDemuxerStream* demuxer_stream |
| 342 = new FFmpegDemuxerStream(this, stream); | 342 = new FFmpegDemuxerStream(this, stream); |
| 343 DCHECK(demuxer_stream); | 343 DCHECK(demuxer_stream); |
| 344 streams_.push_back(demuxer_stream); | 344 streams_.push_back(demuxer_stream); |
| 345 packet_streams_.push_back(demuxer_stream); | 345 packet_streams_.push_back(demuxer_stream); |
| 346 max_duration = std::max(max_duration, demuxer_stream->duration()); | 346 max_duration = std::max(max_duration, demuxer_stream->duration()); |
| 347 } else { | 347 } else { |
| 348 packet_streams_.push_back(NULL); | 348 packet_streams_.push_back(NULL); |
| 349 } | 349 } |
| 350 } | 350 } |
| 351 if (streams_.empty()) { | 351 if (streams_.empty()) { |
| 352 host_->Error(DEMUXER_ERROR_NO_SUPPORTED_STREAMS); | 352 host()->Error(DEMUXER_ERROR_NO_SUPPORTED_STREAMS); |
| 353 return; | 353 return; |
| 354 } | 354 } |
| 355 | 355 |
| 356 // Good to go: set the duration and notify we're done initializing. | 356 // Good to go: set the duration and notify we're done initializing. |
| 357 host_->SetDuration(max_duration); | 357 host()->SetDuration(max_duration); |
| 358 host_->InitializationComplete(); | 358 host()->InitializationComplete(); |
| 359 } | 359 } |
| 360 | 360 |
| 361 void FFmpegDemuxer::SeekTask(base::TimeDelta time) { | 361 void FFmpegDemuxer::SeekTask(base::TimeDelta time) { |
| 362 DCHECK_EQ(PlatformThread::CurrentId(), thread_id_); | 362 DCHECK_EQ(PlatformThread::CurrentId(), thread_id_); |
| 363 | 363 |
| 364 // Tell streams to flush buffers due to seeking. | 364 // Tell streams to flush buffers due to seeking. |
| 365 StreamVector::iterator iter; | 365 StreamVector::iterator iter; |
| 366 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 366 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
| 367 (*iter)->FlushBuffers(); | 367 (*iter)->FlushBuffers(); |
| 368 } | 368 } |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 460 DCHECK_EQ(PlatformThread::CurrentId(), thread_id_); | 460 DCHECK_EQ(PlatformThread::CurrentId(), thread_id_); |
| 461 StreamVector::iterator iter; | 461 StreamVector::iterator iter; |
| 462 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 462 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
| 463 AVPacket* packet = new AVPacket(); | 463 AVPacket* packet = new AVPacket(); |
| 464 memset(packet, 0, sizeof(*packet)); | 464 memset(packet, 0, sizeof(*packet)); |
| 465 (*iter)->EnqueuePacket(packet); | 465 (*iter)->EnqueuePacket(packet); |
| 466 } | 466 } |
| 467 } | 467 } |
| 468 | 468 |
| 469 } // namespace media | 469 } // namespace media |
| OLD | NEW |