Home | History | Annotate | Download | only in seek_tester
      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
      3 // found in the LICENSE file.
      4 //
      5 // This standalone binary is a helper for diagnosing seek behavior of the
      6 // demuxer setup in media/ code.  It answers the question: "if I ask the demuxer
      7 // to Seek to X ms, where will it actually seek to? (necessitating
      8 // frame-dropping until the original seek target is reached)".  Sample run:
      9 //
     10 // $ ./out/Debug/seek_tester .../LayoutTests/media/content/test.ogv 6300
     11 // [0207/130327:INFO:seek_tester.cc(63)] Requested: 6123ms
     12 // [0207/130327:INFO:seek_tester.cc(68)]   audio seeked to: 5526ms
     13 // [0207/130327:INFO:seek_tester.cc(74)]   video seeked to: 5577ms
     14 
     15 
     16 #include "base/at_exit.h"
     17 #include "base/bind.h"
     18 #include "base/files/file_path.h"
     19 #include "base/logging.h"
     20 #include "base/message_loop/message_loop.h"
     21 #include "base/strings/string_number_conversions.h"
     22 #include "media/base/media.h"
     23 #include "media/base/media_log.h"
     24 #include "media/filters/ffmpeg_demuxer.h"
     25 #include "media/filters/file_data_source.h"
     26 
     27 class DemuxerHostImpl : public media::DemuxerHost {
     28  public:
     29   // DataSourceHost implementation.
     30   virtual void SetTotalBytes(int64 total_bytes) OVERRIDE {}
     31   virtual void AddBufferedByteRange(int64 start, int64 end) OVERRIDE {}
     32   virtual void AddBufferedTimeRange(base::TimeDelta start,
     33                                     base::TimeDelta end) OVERRIDE {}
     34 
     35   // DemuxerHost implementation.
     36   virtual void SetDuration(base::TimeDelta duration) OVERRIDE {}
     37   virtual void OnDemuxerError(media::PipelineStatus error) OVERRIDE {}
     38 };
     39 
     40 void QuitMessageLoop(base::MessageLoop* loop, media::PipelineStatus status) {
     41   CHECK_EQ(status, media::PIPELINE_OK);
     42   loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
     43 }
     44 
     45 void TimestampExtractor(uint64* timestamp_ms,
     46                         base::MessageLoop* loop,
     47                         media::DemuxerStream::Status status,
     48                         const scoped_refptr<media::DecoderBuffer>& buffer) {
     49   CHECK_EQ(status, media::DemuxerStream::kOk);
     50   if (buffer->timestamp() == media::kNoTimestamp())
     51     *timestamp_ms = -1;
     52   else
     53     *timestamp_ms = buffer->timestamp().InMillisecondsF();
     54   loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
     55 }
     56 
     57 static void NeedKey(const std::string& type, scoped_ptr<uint8[]> init_data,
     58              int init_data_size) {
     59   LOG(INFO) << "File is encrypted.";
     60 }
     61 
     62 int main(int argc, char** argv) {
     63   base::AtExitManager at_exit;
     64   media::InitializeMediaLibraryForTesting();
     65 
     66   CHECK_EQ(argc, 3) << "\nUsage: " << argv[0] << " <file> <seekTimeInMs>";
     67   uint64 seek_target_ms;
     68   CHECK(base::StringToUint64(argv[2], &seek_target_ms));
     69   scoped_ptr<media::FileDataSource> file_data_source(
     70       new media::FileDataSource());
     71   CHECK(file_data_source->Initialize(base::FilePath::FromUTF8Unsafe(argv[1])));
     72 
     73   DemuxerHostImpl host;
     74   base::MessageLoop loop;
     75   media::PipelineStatusCB quitter = base::Bind(&QuitMessageLoop, &loop);
     76   media::FFmpegNeedKeyCB need_key_cb = base::Bind(&NeedKey);
     77   scoped_ptr<media::FFmpegDemuxer> demuxer(
     78       new media::FFmpegDemuxer(loop.message_loop_proxy(),
     79                                file_data_source.get(),
     80                                need_key_cb,
     81                                new media::MediaLog()));
     82   demuxer->Initialize(&host, quitter);
     83   loop.Run();
     84 
     85   demuxer->Seek(base::TimeDelta::FromMilliseconds(seek_target_ms), quitter);
     86   loop.Run();
     87 
     88   uint64 audio_seeked_to_ms;
     89   uint64 video_seeked_to_ms;
     90   media::DemuxerStream* audio_stream =
     91       demuxer->GetStream(media::DemuxerStream::AUDIO);
     92   media::DemuxerStream* video_stream =
     93       demuxer->GetStream(media::DemuxerStream::VIDEO);
     94   LOG(INFO) << "Requested: " << seek_target_ms << "ms";
     95   if (audio_stream) {
     96     audio_stream->Read(base::Bind(
     97         &TimestampExtractor, &audio_seeked_to_ms, &loop));
     98     loop.Run();
     99     LOG(INFO) << "  audio seeked to: " << audio_seeked_to_ms << "ms";
    100   }
    101   if (video_stream) {
    102     video_stream->Read(
    103         base::Bind(&TimestampExtractor, &video_seeked_to_ms, &loop));
    104     loop.Run();
    105     LOG(INFO) << "  video seeked to: " << video_seeked_to_ms << "ms";
    106   }
    107 
    108   demuxer->Stop(base::Bind(&base::MessageLoop::Quit, base::Unretained(&loop)));
    109   loop.Run();
    110 
    111   return 0;
    112 }
    113