OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 <deque> | 5 #include <deque> |
6 | 6 |
| 7 #include "media/base/mock_ffmpeg.h" |
7 #include "media/ffmpeg/ffmpeg_common.h" | 8 #include "media/ffmpeg/ffmpeg_common.h" |
8 #include "media/filters/bitstream_converter.h" | 9 #include "media/filters/bitstream_converter.h" |
9 #include "testing/gtest/include/gtest/gtest.h" | 10 #include "testing/gtest/include/gtest/gtest.h" |
10 | 11 |
| 12 using ::testing::DoAll; |
| 13 using ::testing::Mock; |
| 14 using ::testing::Return; |
| 15 using ::testing::ReturnNull; |
| 16 using ::testing::SetArgumentPointee; |
| 17 using ::testing::StrEq; |
| 18 using ::testing::StrictMock; |
| 19 using ::testing::_; |
| 20 |
11 namespace media { | 21 namespace media { |
12 | 22 |
13 static const char kTestFilterName[] = "test_filter"; | |
14 static uint8_t kFailData[] = { 3, 2, 1 }; | |
15 static uint8_t kNewBufferData[] = { 2, 1 }; | |
16 static uint8_t kInPlaceData[] = { 1 }; | |
17 static const int kFailSize = 3; | |
18 static const int kNewBufferSize = 2; | |
19 static const int kInPlaceSize = 1; | |
20 | |
21 | |
22 // Test filter function that looks for specific input data and changes it's | |
23 // behavior based on what is passed to |buf| & |buf_size|. The three behaviors | |
24 // simulated are the following: | |
25 // - Create a new output buffer. Triggered by |buf| == |kNewBufferData|. | |
26 // - Use the existing output buffer. Triggered by |buf| == |kInPlaceData|. | |
27 // - Signal an error. Triggered by |buf| == |kFailData|. | |
28 static int DoFilter(AVBitStreamFilterContext* bsfc, | |
29 AVCodecContext* avctx, | |
30 const char* args, | |
31 uint8_t** poutbuf, | |
32 int* poutbuf_size, | |
33 const uint8_t* buf, | |
34 int buf_size, | |
35 int keyframe) { | |
36 if (buf_size == kNewBufferSize && | |
37 !memcmp(buf, kNewBufferData, kNewBufferSize)) { | |
38 *poutbuf_size = buf_size + 1; | |
39 *poutbuf = static_cast<uint8*>(av_malloc(*poutbuf_size)); | |
40 *poutbuf[0] = 0; | |
41 memcpy((*poutbuf) + 1, buf, buf_size); | |
42 return 0; | |
43 } else if (buf_size == kInPlaceSize && | |
44 !memcmp(buf, kInPlaceData, kInPlaceSize)) { | |
45 return 0; | |
46 } | |
47 | |
48 return -1; | |
49 } | |
50 | |
51 static void DoClose(AVBitStreamFilterContext* bsfc) {} | |
52 | |
53 static AVBitStreamFilter g_stream_filter = { | |
54 kTestFilterName, | |
55 0, // Private Data Size | |
56 DoFilter, | |
57 DoClose, | |
58 0, // Next filter pointer. | |
59 }; | |
60 | |
61 class BitstreamConverterTest : public testing::Test { | 23 class BitstreamConverterTest : public testing::Test { |
62 protected: | 24 protected: |
63 BitstreamConverterTest() { | 25 BitstreamConverterTest() { |
64 memset(&test_stream_context_, 0, sizeof(test_stream_context_)); | 26 memset(&test_stream_context_, 0, sizeof(test_stream_context_)); |
| 27 memset(&test_filter_, 0, sizeof(test_filter_)); |
65 memset(&test_packet_, 0, sizeof(test_packet_)); | 28 memset(&test_packet_, 0, sizeof(test_packet_)); |
66 test_packet_.data = kFailData; | 29 test_packet_.data = kData1; |
67 test_packet_.size = kFailSize; | 30 test_packet_.size = kTestSize1; |
68 } | 31 } |
69 | 32 |
70 virtual ~BitstreamConverterTest() {} | 33 virtual ~BitstreamConverterTest() {} |
71 | 34 |
72 static void SetUpTestCase() { | 35 AVCodecContext test_stream_context_; |
73 // Register g_stream_filter if it isn't already registered. | 36 AVBitStreamFilterContext test_filter_; |
74 if (!g_stream_filter.next) | 37 AVPacket test_packet_; |
75 av_register_bitstream_filter(&g_stream_filter); | |
76 } | |
77 | 38 |
78 AVCodecContext test_stream_context_; | 39 StrictMock<MockFFmpeg> mock_ffmpeg_; |
79 AVPacket test_packet_; | 40 |
| 41 static const char kTestFilterName[]; |
| 42 static uint8_t kData1[]; |
| 43 static uint8_t kData2[]; |
| 44 static const int kTestSize1; |
| 45 static const int kTestSize2; |
80 | 46 |
81 private: | 47 private: |
82 DISALLOW_COPY_AND_ASSIGN(BitstreamConverterTest); | 48 DISALLOW_COPY_AND_ASSIGN(BitstreamConverterTest); |
83 }; | 49 }; |
84 | 50 |
85 TEST_F(BitstreamConverterTest, InitializeFailed) { | 51 const char BitstreamConverterTest::kTestFilterName[] = "test_filter"; |
86 FFmpegBitstreamConverter converter("BAD_FILTER_NAME", &test_stream_context_); | 52 uint8_t BitstreamConverterTest::kData1[] = { 1 }; |
| 53 uint8_t BitstreamConverterTest::kData2[] = { 2 }; |
| 54 const int BitstreamConverterTest::kTestSize1 = 1; |
| 55 const int BitstreamConverterTest::kTestSize2 = 2; |
87 | 56 |
| 57 TEST_F(BitstreamConverterTest, Initialize) { |
| 58 FFmpegBitstreamConverter converter(kTestFilterName, &test_stream_context_); |
| 59 |
| 60 // Test Initialize returns false on a bad initialization, and cleanup is not |
| 61 // done. |
| 62 EXPECT_CALL(mock_ffmpeg_, AVBitstreamFilterInit(StrEq(kTestFilterName))) |
| 63 .WillOnce(ReturnNull()); |
88 EXPECT_FALSE(converter.Initialize()); | 64 EXPECT_FALSE(converter.Initialize()); |
89 } | |
90 | 65 |
91 TEST_F(BitstreamConverterTest, InitializeSuccess) { | 66 EXPECT_TRUE(Mock::VerifyAndClearExpectations(&mock_ffmpeg_)); |
92 FFmpegBitstreamConverter converter(kTestFilterName, &test_stream_context_); | 67 |
| 68 // Test Initialize returns true on successful initialization, and cleanup is |
| 69 // done. The cleanup will be activated when the converter object goes out of |
| 70 // scope. |
| 71 EXPECT_CALL(mock_ffmpeg_, AVBitstreamFilterInit(StrEq(kTestFilterName))) |
| 72 .WillOnce(Return(&test_filter_)); |
| 73 EXPECT_CALL(mock_ffmpeg_, AVBitstreamFilterClose(&test_filter_)); |
93 EXPECT_TRUE(converter.Initialize()); | 74 EXPECT_TRUE(converter.Initialize()); |
94 } | 75 } |
95 | 76 |
96 TEST_F(BitstreamConverterTest, ConvertPacket_NotInitialized) { | 77 TEST_F(BitstreamConverterTest, ConvertPacket_NotInitialized) { |
97 FFmpegBitstreamConverter converter(kTestFilterName, &test_stream_context_); | 78 FFmpegBitstreamConverter converter(kTestFilterName, &test_stream_context_); |
98 | 79 |
99 EXPECT_FALSE(converter.ConvertPacket(&test_packet_)); | 80 EXPECT_FALSE(converter.ConvertPacket(&test_packet_)); |
100 } | 81 } |
101 | 82 |
102 TEST_F(BitstreamConverterTest, ConvertPacket_FailedFilter) { | 83 TEST_F(BitstreamConverterTest, ConvertPacket_FailedFilter) { |
103 FFmpegBitstreamConverter converter(kTestFilterName, &test_stream_context_); | 84 FFmpegBitstreamConverter converter(kTestFilterName, &test_stream_context_); |
104 | 85 |
105 EXPECT_TRUE(converter.Initialize()); | 86 // Inject mock filter instance. |
| 87 converter.stream_filter_ = &test_filter_; |
| 88 |
| 89 // Simulate a successful filter call, that allocates a new data buffer. |
| 90 EXPECT_CALL(mock_ffmpeg_, |
| 91 AVBitstreamFilterFilter(&test_filter_, &test_stream_context_, |
| 92 NULL, _, _, |
| 93 test_packet_.data, test_packet_.size, _)) |
| 94 .WillOnce(Return(AVERROR(EINVAL))); |
106 | 95 |
107 EXPECT_FALSE(converter.ConvertPacket(&test_packet_)); | 96 EXPECT_FALSE(converter.ConvertPacket(&test_packet_)); |
| 97 |
| 98 // Uninject mock filter instance to avoid cleanup code on destruction of |
| 99 // converter. |
| 100 converter.stream_filter_ = NULL; |
108 } | 101 } |
109 | 102 |
110 TEST_F(BitstreamConverterTest, ConvertPacket_Success) { | 103 TEST_F(BitstreamConverterTest, ConvertPacket_Success) { |
111 FFmpegBitstreamConverter converter(kTestFilterName, &test_stream_context_); | 104 FFmpegBitstreamConverter converter(kTestFilterName, &test_stream_context_); |
112 | 105 |
113 EXPECT_TRUE(converter.Initialize()); | 106 // Inject mock filter instance. |
| 107 converter.stream_filter_ = &test_filter_; |
114 | 108 |
115 // Ensure our packet doesn't already have a destructor. | 109 // Ensure our packet doesn't already have a destructor. |
116 ASSERT_TRUE(test_packet_.destruct == NULL); | 110 ASSERT_TRUE(test_packet_.destruct == NULL); |
117 | 111 |
118 test_packet_.data = kNewBufferData; | 112 // Simulate a successful filter call, that allocates a new data buffer. |
119 test_packet_.size = kNewBufferSize; | 113 EXPECT_CALL(mock_ffmpeg_, |
| 114 AVBitstreamFilterFilter(&test_filter_, &test_stream_context_, |
| 115 NULL, _, _, |
| 116 test_packet_.data, test_packet_.size, _)) |
| 117 .WillOnce(DoAll(SetArgumentPointee<3>(&kData2[0]), |
| 118 SetArgumentPointee<4>(kTestSize2), |
| 119 Return(0))); |
| 120 EXPECT_CALL(mock_ffmpeg_, AVFreePacket(&test_packet_)); |
120 | 121 |
121 EXPECT_TRUE(converter.ConvertPacket(&test_packet_)); | 122 EXPECT_TRUE(converter.ConvertPacket(&test_packet_)); |
122 EXPECT_NE(kNewBufferData, test_packet_.data); | 123 EXPECT_EQ(kData2, test_packet_.data); |
123 EXPECT_EQ(kNewBufferSize + 1, test_packet_.size); | 124 EXPECT_EQ(kTestSize2, test_packet_.size); |
124 EXPECT_TRUE(test_packet_.destruct != NULL); | 125 EXPECT_TRUE(test_packet_.destruct != NULL); |
| 126 |
| 127 // Uninject mock filter instance to avoid cleanup code on destruction of |
| 128 // converter. |
| 129 converter.stream_filter_ = NULL; |
125 } | 130 } |
126 | 131 |
127 TEST_F(BitstreamConverterTest, ConvertPacket_SuccessInPlace) { | 132 TEST_F(BitstreamConverterTest, ConvertPacket_SuccessInPlace) { |
128 FFmpegBitstreamConverter converter(kTestFilterName, &test_stream_context_); | 133 FFmpegBitstreamConverter converter(kTestFilterName, &test_stream_context_); |
129 | 134 |
130 EXPECT_TRUE(converter.Initialize()); | 135 // Inject mock filter instance. |
| 136 converter.stream_filter_ = &test_filter_; |
131 | 137 |
132 // Ensure our packet is in a sane start state. | 138 // Ensure our packet is in a sane start state. |
133 ASSERT_TRUE(test_packet_.destruct == NULL); | 139 ASSERT_TRUE(test_packet_.destruct == NULL); |
134 test_packet_.data = kInPlaceData; | 140 ASSERT_EQ(kData1, test_packet_.data); |
135 test_packet_.size = kInPlaceSize; | 141 ASSERT_EQ(kTestSize1, test_packet_.size); |
| 142 |
| 143 // Simulate a successful filter call, that reuses the input buffer. We should |
| 144 // not free the packet here or alter the packet's destructor. |
| 145 EXPECT_CALL(mock_ffmpeg_, |
| 146 AVBitstreamFilterFilter(&test_filter_, &test_stream_context_, |
| 147 NULL, _, _, |
| 148 test_packet_.data, test_packet_.size, _)) |
| 149 .WillOnce(DoAll(SetArgumentPointee<3>(test_packet_.data), |
| 150 SetArgumentPointee<4>(test_packet_.size), |
| 151 Return(0))); |
136 | 152 |
137 EXPECT_TRUE(converter.ConvertPacket(&test_packet_)); | 153 EXPECT_TRUE(converter.ConvertPacket(&test_packet_)); |
138 EXPECT_EQ(kInPlaceData, test_packet_.data); | 154 EXPECT_EQ(kData1, test_packet_.data); |
139 EXPECT_EQ(kInPlaceSize, test_packet_.size); | 155 EXPECT_EQ(kTestSize1, test_packet_.size); |
140 EXPECT_TRUE(test_packet_.destruct == NULL); | 156 EXPECT_TRUE(test_packet_.destruct == NULL); |
| 157 |
| 158 // Uninject mock filter instance to avoid cleanup code on destruction of |
| 159 // converter. |
| 160 converter.stream_filter_ = NULL; |
141 } | 161 } |
142 | 162 |
143 } // namespace media | 163 } // namespace media |
OLD | NEW |