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 27class 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 40void QuitMessageLoop(base::MessageLoop* loop, media::PipelineStatus status) { 41 CHECK_EQ(status, media::PIPELINE_OK); 42 loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); 43} 44 45void 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 57static void NeedKey(const std::string& type, scoped_ptr<uint8[]> init_data, 58 int init_data_size) { 59 LOG(INFO) << "File is encrypted."; 60} 61 62int 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