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

Side by Side Diff: media/filters/ffmpeg_demuxer.cc

Issue 155469: Splitting media filter's Initialize() into Create() + callback and Seek() + callback. (Closed)
Patch Set: Fixed valgrind errors Created 11 years, 5 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
« no previous file with comments | « media/filters/ffmpeg_demuxer.h ('k') | media/filters/ffmpeg_demuxer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
OLDNEW
« no previous file with comments | « media/filters/ffmpeg_demuxer.h ('k') | media/filters/ffmpeg_demuxer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698