| // 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<int>(test_data[i][0]); |
| time_base.den = static_cast<int>(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 |