// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/file_path.h" #include "base/logging.h" #include "base/path_service.h" #include "media/base/media.h" #include "media/ffmpeg/ffmpeg_common.h" #include "testing/gtest/include/gtest/gtest.h" using base::TimeDelta; namespace media { static AVIndexEntry kIndexEntries[] = { // pos, timestamp, flags, size, min_distance { 0, 0, AVINDEX_KEYFRAME, 0, 0 }, { 2000, 1000, AVINDEX_KEYFRAME, 0, 0 }, { 3000, 2000, 0, 0, 0 }, { 5000, 3000, AVINDEX_KEYFRAME, 0, 0 }, { 6000, 4000, 0, 0, 0 }, { 8000, 5000, AVINDEX_KEYFRAME, 0, 0 }, { 9000, 6000, AVINDEX_KEYFRAME, 0, 0 }, { 11500, 7000, AVINDEX_KEYFRAME, 0, 0 }, }; static const AVRational kTimeBase = { 1, 1000 }; class FFmpegCommonTest : public testing::Test { public: FFmpegCommonTest(); virtual ~FFmpegCommonTest(); protected: AVStream stream_; DISALLOW_COPY_AND_ASSIGN(FFmpegCommonTest); }; static bool InitFFmpeg() { static bool initialized = false; if (initialized) { return true; } FilePath path; PathService::Get(base::DIR_MODULE, &path); return media::InitializeMediaLibrary(path); } FFmpegCommonTest::FFmpegCommonTest() { CHECK(InitFFmpeg()); stream_.time_base = kTimeBase; stream_.index_entries = kIndexEntries; stream_.index_entries_allocated_size = sizeof(kIndexEntries); stream_.nb_index_entries = arraysize(kIndexEntries); } FFmpegCommonTest::~FFmpegCommonTest() {} TEST_F(FFmpegCommonTest, TestTimeBaseConversions) { int64 test_data[][5] = { {1, 2, 1, 500000, 1 }, {1, 3, 1, 333333, 1 }, {1, 3, 2, 666667, 2 }, }; for (size_t i = 0; i < arraysize(test_data); ++i) { SCOPED_TRACE(i); AVRational time_base; time_base.num = static_cast(test_data[i][0]); time_base.den = static_cast(test_data[i][1]); TimeDelta time_delta = ConvertFromTimeBase(time_base, test_data[i][2]); EXPECT_EQ(time_delta.InMicroseconds(), test_data[i][3]); EXPECT_EQ(ConvertToTimeBase(time_base, time_delta), test_data[i][4]); } } TEST_F(FFmpegCommonTest, GetSeekTimeAfterSuccess) { int64 test_data[][2] = { {5000, 5000}, // Timestamp is a keyframe seek point. {2400, 3000}, // Timestamp is just before a keyframe seek point. {2000, 3000}, // Timestamp is a non-keyframe entry. {1800, 3000}, // Timestamp is just before a non-keyframe entry. }; for (size_t i = 0; i < arraysize(test_data); ++i) { SCOPED_TRACE(i); TimeDelta seek_point; TimeDelta timestamp = TimeDelta::FromMilliseconds(test_data[i][0]); ASSERT_TRUE(GetSeekTimeAfter(&stream_, timestamp, &seek_point)); EXPECT_EQ(seek_point.InMilliseconds(), test_data[i][1]); } } TEST_F(FFmpegCommonTest, GetSeekTimeAfterFailures) { TimeDelta seek_point; // Timestamp after last index entry. ASSERT_FALSE(GetSeekTimeAfter(&stream_, TimeDelta::FromSeconds(8), &seek_point)); AVStream stream; memcpy(&stream, &stream_, sizeof(stream)); stream.index_entries = NULL; // Stream w/o index data. ASSERT_FALSE(GetSeekTimeAfter(&stream, TimeDelta::FromSeconds(1), &seek_point)); } TEST_F(FFmpegCommonTest, GetStreamByteCountOverRangeSuccess) { int64 test_data[][5] = { { 0, 1000, 2000, 0, 1000}, // Bytes between two adjacent keyframe // entries. {1000, 2000, 3000, 1000, 3000}, // Bytes between two keyframe entries with a // non-keyframe entry between them. {5500, 5600, 1000, 5000, 6000}, // Bytes for a range that starts and ends // between two index entries. {4500, 7000, 6500, 3000, 7000}, // Bytes for a range that ends on the last // seek point. }; for (size_t i = 0; i < arraysize(test_data); ++i) { SCOPED_TRACE(i); TimeDelta start_time = TimeDelta::FromMilliseconds(test_data[i][0]); TimeDelta end_time = TimeDelta::FromMilliseconds(test_data[i][1]); int64 bytes; TimeDelta range_start; TimeDelta range_end; ASSERT_TRUE(GetStreamByteCountOverRange(&stream_, start_time, end_time, &bytes, &range_start, &range_end)); EXPECT_EQ(bytes, test_data[i][2]); EXPECT_EQ(range_start.InMilliseconds(), test_data[i][3]); EXPECT_EQ(range_end.InMilliseconds(), test_data[i][4]); } } TEST_F(FFmpegCommonTest, GetStreamByteCountOverRangeFailures) { int64 test_data[][2] = { {7000, 7600}, // Test a range that starts at the last seek point. {7500, 7600}, // Test a range after the last seek point }; int64 bytes; TimeDelta range_start; TimeDelta range_end; for (size_t i = 0; i < arraysize(test_data); ++i) { SCOPED_TRACE(i); TimeDelta start_time = TimeDelta::FromMilliseconds(test_data[i][0]); TimeDelta end_time = TimeDelta::FromMilliseconds(test_data[i][1]); EXPECT_FALSE(GetStreamByteCountOverRange(&stream_, start_time, end_time, &bytes, &range_start, &range_end)); } AVStream stream; memcpy(&stream, &stream_, sizeof(stream)); stream.index_entries = NULL; // Stream w/o index data. ASSERT_FALSE(GetStreamByteCountOverRange(&stream, TimeDelta::FromSeconds(1), TimeDelta::FromSeconds(2), &bytes, &range_start, &range_end)); } } // namespace media