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 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
254 message_loop()->PostTask(FROM_HERE, | 254 message_loop()->PostTask(FROM_HERE, |
255 NewRunnableMethod(this, &FFmpegDemuxer::DemuxTask)); | 255 NewRunnableMethod(this, &FFmpegDemuxer::DemuxTask)); |
256 } | 256 } |
257 | 257 |
258 void FFmpegDemuxer::Stop() { | 258 void FFmpegDemuxer::Stop() { |
259 // Post a task to notify the streams to stop as well. | 259 // Post a task to notify the streams to stop as well. |
260 message_loop()->PostTask(FROM_HERE, | 260 message_loop()->PostTask(FROM_HERE, |
261 NewRunnableMethod(this, &FFmpegDemuxer::StopTask)); | 261 NewRunnableMethod(this, &FFmpegDemuxer::StopTask)); |
262 } | 262 } |
263 | 263 |
264 void FFmpegDemuxer::Seek(base::TimeDelta time) { | 264 void FFmpegDemuxer::Seek(base::TimeDelta time, FilterCallback* callback) { |
265 // TODO(hclam): by returning from this method, it is assumed that the seek | 265 // TODO(hclam): by returning from this method, it is assumed that the seek |
266 // operation is completed and filters behind the demuxer is good to issue | 266 // operation is completed and filters behind the demuxer is good to issue |
267 // more reads, but we are posting a task here, which makes the seek operation | 267 // more reads, but we are posting a task here, which makes the seek operation |
268 // asynchronous, should change how seek works to make it fully asynchronous. | 268 // asynchronous, should change how seek works to make it fully asynchronous. |
269 message_loop()->PostTask(FROM_HERE, | 269 message_loop()->PostTask(FROM_HERE, |
270 NewRunnableMethod(this, &FFmpegDemuxer::SeekTask, time)); | 270 NewRunnableMethod(this, &FFmpegDemuxer::SeekTask, time, callback)); |
271 } | 271 } |
272 | 272 |
273 bool FFmpegDemuxer::Initialize(DataSource* data_source) { | 273 void FFmpegDemuxer::Initialize(DataSource* data_source, |
| 274 FilterCallback* callback) { |
274 message_loop()->PostTask(FROM_HERE, | 275 message_loop()->PostTask(FROM_HERE, |
275 NewRunnableMethod(this, &FFmpegDemuxer::InititalizeTask, data_source)); | 276 NewRunnableMethod(this, &FFmpegDemuxer::InititalizeTask, data_source, |
276 return true; | 277 callback)); |
277 } | 278 } |
278 | 279 |
279 size_t FFmpegDemuxer::GetNumberOfStreams() { | 280 size_t FFmpegDemuxer::GetNumberOfStreams() { |
280 return streams_.size(); | 281 return streams_.size(); |
281 } | 282 } |
282 | 283 |
283 scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream(int stream) { | 284 scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream(int stream) { |
284 DCHECK(stream >= 0); | 285 DCHECK(stream >= 0); |
285 DCHECK(stream < static_cast<int>(streams_.size())); | 286 DCHECK(stream < static_cast<int>(streams_.size())); |
286 return streams_[stream].get(); | 287 return streams_[stream].get(); |
287 } | 288 } |
288 | 289 |
289 void FFmpegDemuxer::InititalizeTask(DataSource* data_source) { | 290 void FFmpegDemuxer::InititalizeTask(DataSource* data_source, |
| 291 FilterCallback* callback) { |
290 DCHECK_EQ(MessageLoop::current(), message_loop()); | 292 DCHECK_EQ(MessageLoop::current(), message_loop()); |
| 293 scoped_ptr<FilterCallback> c(callback); |
291 | 294 |
292 // In order to get FFmpeg to use |data_source| for file IO we must transfer | 295 // In order to get FFmpeg to use |data_source| for file IO we must transfer |
293 // ownership via FFmpegGlue. We'll add |data_source| to FFmpegGlue and pass | 296 // ownership via FFmpegGlue. We'll add |data_source| to FFmpegGlue and pass |
294 // the resulting key to FFmpeg. FFmpeg will pass the key to FFmpegGlue which | 297 // the resulting key to FFmpeg. FFmpeg will pass the key to FFmpegGlue which |
295 // will take care of attaching |data_source| to an FFmpeg context. After | 298 // will take care of attaching |data_source| to an FFmpeg context. After |
296 // we finish initializing the FFmpeg context we can remove |data_source| from | 299 // we finish initializing the FFmpeg context we can remove |data_source| from |
297 // FFmpegGlue. | 300 // FFmpegGlue. |
298 // | 301 // |
299 // Refer to media/filters/ffmpeg_glue.h for details. | 302 // Refer to media/filters/ffmpeg_glue.h for details. |
300 | 303 |
301 // Add our data source and get our unique key. | 304 // Add our data source and get our unique key. |
302 std::string key = FFmpegGlue::get()->AddDataSource(data_source); | 305 std::string key = FFmpegGlue::get()->AddDataSource(data_source); |
303 | 306 |
304 // Open FFmpeg AVFormatContext. | 307 // Open FFmpeg AVFormatContext. |
305 DCHECK(!format_context_); | 308 DCHECK(!format_context_); |
306 AVFormatContext* context = NULL; | 309 AVFormatContext* context = NULL; |
307 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); |
308 | 311 |
309 // Remove our data source. | 312 // Remove our data source. |
310 FFmpegGlue::get()->RemoveDataSource(data_source); | 313 FFmpegGlue::get()->RemoveDataSource(data_source); |
311 | 314 |
312 if (result < 0) { | 315 if (result < 0) { |
313 host()->Error(DEMUXER_ERROR_COULD_NOT_OPEN); | 316 host()->Error(DEMUXER_ERROR_COULD_NOT_OPEN); |
| 317 callback->Run(); |
314 return; | 318 return; |
315 } | 319 } |
316 | 320 |
317 DCHECK(context); | 321 DCHECK(context); |
318 format_context_ = context; | 322 format_context_ = context; |
319 | 323 |
320 // Serialize calls to av_find_stream_info(). | 324 // Serialize calls to av_find_stream_info(). |
321 { | 325 { |
322 AutoLock auto_lock(FFmpegLock::get()->lock()); | 326 AutoLock auto_lock(FFmpegLock::get()->lock()); |
323 | 327 |
324 // Fully initialize AVFormatContext by parsing the stream a little. | 328 // Fully initialize AVFormatContext by parsing the stream a little. |
325 result = av_find_stream_info(format_context_); | 329 result = av_find_stream_info(format_context_); |
326 if (result < 0) { | 330 if (result < 0) { |
327 host()->Error(DEMUXER_ERROR_COULD_NOT_PARSE); | 331 host()->Error(DEMUXER_ERROR_COULD_NOT_PARSE); |
| 332 callback->Run(); |
328 return; | 333 return; |
329 } | 334 } |
330 } | 335 } |
331 | 336 |
332 // Create demuxer streams for all supported streams. | 337 // Create demuxer streams for all supported streams. |
333 base::TimeDelta max_duration; | 338 base::TimeDelta max_duration; |
334 for (size_t i = 0; i < format_context_->nb_streams; ++i) { | 339 for (size_t i = 0; i < format_context_->nb_streams; ++i) { |
335 CodecType codec_type = format_context_->streams[i]->codec->codec_type; | 340 CodecType codec_type = format_context_->streams[i]->codec->codec_type; |
336 if (codec_type == CODEC_TYPE_AUDIO || codec_type == CODEC_TYPE_VIDEO) { | 341 if (codec_type == CODEC_TYPE_AUDIO || codec_type == CODEC_TYPE_VIDEO) { |
337 AVStream* stream = format_context_->streams[i]; | 342 AVStream* stream = format_context_->streams[i]; |
338 FFmpegDemuxerStream* demuxer_stream | 343 FFmpegDemuxerStream* demuxer_stream |
339 = new FFmpegDemuxerStream(this, stream); | 344 = new FFmpegDemuxerStream(this, stream); |
340 DCHECK(demuxer_stream); | 345 DCHECK(demuxer_stream); |
341 streams_.push_back(demuxer_stream); | 346 streams_.push_back(demuxer_stream); |
342 packet_streams_.push_back(demuxer_stream); | 347 packet_streams_.push_back(demuxer_stream); |
343 max_duration = std::max(max_duration, demuxer_stream->duration()); | 348 max_duration = std::max(max_duration, demuxer_stream->duration()); |
344 } else { | 349 } else { |
345 packet_streams_.push_back(NULL); | 350 packet_streams_.push_back(NULL); |
346 } | 351 } |
347 } | 352 } |
348 if (streams_.empty()) { | 353 if (streams_.empty()) { |
349 host()->Error(DEMUXER_ERROR_NO_SUPPORTED_STREAMS); | 354 host()->Error(DEMUXER_ERROR_NO_SUPPORTED_STREAMS); |
| 355 callback->Run(); |
350 return; | 356 return; |
351 } | 357 } |
352 | 358 |
353 // Good to go: set the duration and notify we're done initializing. | 359 // Good to go: set the duration and notify we're done initializing. |
354 host()->SetDuration(max_duration); | 360 host()->SetDuration(max_duration); |
355 host()->InitializationComplete(); | 361 callback->Run(); |
356 } | 362 } |
357 | 363 |
358 void FFmpegDemuxer::SeekTask(base::TimeDelta time) { | 364 void FFmpegDemuxer::SeekTask(base::TimeDelta time, FilterCallback* callback) { |
359 DCHECK_EQ(MessageLoop::current(), message_loop()); | 365 DCHECK_EQ(MessageLoop::current(), message_loop()); |
| 366 scoped_ptr<FilterCallback> c(callback); |
360 | 367 |
361 // Tell streams to flush buffers due to seeking. | 368 // Tell streams to flush buffers due to seeking. |
362 StreamVector::iterator iter; | 369 StreamVector::iterator iter; |
363 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 370 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
364 (*iter)->FlushBuffers(); | 371 (*iter)->FlushBuffers(); |
365 } | 372 } |
366 | 373 |
367 // Seek backwards if requested timestamp is behind FFmpeg's current time. | 374 // Seek backwards if requested timestamp is behind FFmpeg's current time. |
368 int flags = 0; | 375 int flags = 0; |
369 if (time <= current_timestamp_) { | 376 if (time <= current_timestamp_) { |
370 flags |= AVSEEK_FLAG_BACKWARD; | 377 flags |= AVSEEK_FLAG_BACKWARD; |
371 } | 378 } |
372 | 379 |
373 if (av_seek_frame(format_context_, -1, time.InMicroseconds(), | 380 if (av_seek_frame(format_context_, -1, time.InMicroseconds(), |
374 flags) < 0) { | 381 flags) < 0) { |
375 // TODO(scherkus): signal error. | 382 // TODO(scherkus): signal error. |
376 NOTIMPLEMENTED(); | 383 NOTIMPLEMENTED(); |
377 } | 384 } |
| 385 |
| 386 // Notify we're finished seeking. |
| 387 callback->Run(); |
378 } | 388 } |
379 | 389 |
380 void FFmpegDemuxer::DemuxTask() { | 390 void FFmpegDemuxer::DemuxTask() { |
381 DCHECK_EQ(MessageLoop::current(), message_loop()); | 391 DCHECK_EQ(MessageLoop::current(), message_loop()); |
382 | 392 |
383 // Make sure we have work to do before demuxing. | 393 // Make sure we have work to do before demuxing. |
384 if (!StreamsHavePendingReads()) { | 394 if (!StreamsHavePendingReads()) { |
385 return; | 395 return; |
386 } | 396 } |
387 | 397 |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
457 DCHECK_EQ(MessageLoop::current(), message_loop()); | 467 DCHECK_EQ(MessageLoop::current(), message_loop()); |
458 StreamVector::iterator iter; | 468 StreamVector::iterator iter; |
459 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 469 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
460 AVPacket* packet = new AVPacket(); | 470 AVPacket* packet = new AVPacket(); |
461 memset(packet, 0, sizeof(*packet)); | 471 memset(packet, 0, sizeof(*packet)); |
462 (*iter)->EnqueuePacket(packet); | 472 (*iter)->EnqueuePacket(packet); |
463 } | 473 } |
464 } | 474 } |
465 | 475 |
466 } // namespace media | 476 } // namespace media |
OLD | NEW |