OLD | NEW |
1 // Copyright (c) 2010 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 "media/base/mock_ffmpeg.h" | 5 #include "media/base/mock_ffmpeg.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "media/ffmpeg/ffmpeg_common.h" | 8 #include "media/ffmpeg/ffmpeg_common.h" |
9 | 9 |
10 using ::testing::_; | 10 using ::testing::_; |
11 using ::testing::AtMost; | 11 using ::testing::AtMost; |
12 using ::testing::DoAll; | 12 using ::testing::DoAll; |
13 using ::testing::Return; | 13 using ::testing::Return; |
14 using ::testing::SaveArg; | 14 using ::testing::SaveArg; |
15 | 15 |
16 namespace media { | 16 namespace media { |
17 | 17 |
18 MockFFmpeg* MockFFmpeg::instance_ = NULL; | 18 static MockFFmpeg* g_instance = NULL; |
19 URLProtocol* MockFFmpeg::protocol_ = NULL; | 19 URLProtocol* MockFFmpeg::protocol_ = NULL; |
20 | 20 |
21 MockFFmpeg::MockFFmpeg() | 21 MockFFmpeg::MockFFmpeg() |
22 : outstanding_packets_(0) { | 22 : outstanding_packets_(0) { |
| 23 CHECK(g_instance == NULL) << "Only a single MockFFmpeg instance can exist"; |
| 24 g_instance = this; |
| 25 |
23 // If we haven't assigned our static copy of URLProtocol, set up expectations | 26 // If we haven't assigned our static copy of URLProtocol, set up expectations |
24 // to catch the URLProtocol registered when the singleton instance of | 27 // to catch the URLProtocol registered when the singleton instance of |
25 // FFmpegGlue is created. | 28 // FFmpegGlue is created. |
26 // | 29 // |
27 // TODO(scherkus): this feels gross and I need to think of a way to better | 30 // TODO(scherkus): this feels gross and I need to think of a way to better |
28 // inject/mock singletons. | 31 // inject/mock singletons. |
29 if (!protocol_) { | 32 if (!protocol_) { |
30 EXPECT_CALL(*this, AVLogSetLevel(AV_LOG_QUIET)) | 33 EXPECT_CALL(*this, AVLogSetLevel(AV_LOG_QUIET)) |
31 .Times(AtMost(1)) | 34 .Times(AtMost(1)) |
32 .WillOnce(Return()); | 35 .WillOnce(Return()); |
33 EXPECT_CALL(*this, AVCodecInit()) | 36 EXPECT_CALL(*this, AVCodecInit()) |
34 .Times(AtMost(1)) | 37 .Times(AtMost(1)) |
35 .WillOnce(Return()); | 38 .WillOnce(Return()); |
36 EXPECT_CALL(*this, AVRegisterProtocol2(_,_)) | 39 EXPECT_CALL(*this, AVRegisterProtocol2(_,_)) |
37 .Times(AtMost(1)) | 40 .Times(AtMost(1)) |
38 .WillOnce(DoAll(SaveArg<0>(&protocol_), Return(0))); | 41 .WillOnce(DoAll(SaveArg<0>(&protocol_), Return(0))); |
39 EXPECT_CALL(*this, AVRegisterAll()) | 42 EXPECT_CALL(*this, AVRegisterAll()) |
40 .Times(AtMost(1)) | 43 .Times(AtMost(1)) |
41 .WillOnce(Return()); | 44 .WillOnce(Return()); |
42 } | 45 } |
43 // av_lockmgr_register() is also called from ~FFmpegLock(), so we expect | |
44 // it to be called at the end. | |
45 EXPECT_CALL(*this, AVRegisterLockManager(_)) | |
46 .Times(AtMost(2)) | |
47 .WillRepeatedly(Return(0)); | |
48 } | 46 } |
49 | 47 |
50 MockFFmpeg::~MockFFmpeg() { | 48 MockFFmpeg::~MockFFmpeg() { |
51 CHECK(!outstanding_packets_) | 49 CHECK(!outstanding_packets_) |
52 << "MockFFmpeg destroyed with outstanding packets"; | 50 << "MockFFmpeg destroyed with outstanding packets"; |
| 51 CHECK(g_instance); |
| 52 g_instance = NULL; |
53 } | 53 } |
54 | 54 |
55 void MockFFmpeg::inc_outstanding_packets() { | 55 void MockFFmpeg::inc_outstanding_packets() { |
56 ++outstanding_packets_; | 56 ++outstanding_packets_; |
57 } | 57 } |
58 | 58 |
59 void MockFFmpeg::dec_outstanding_packets() { | 59 void MockFFmpeg::dec_outstanding_packets() { |
60 CHECK(outstanding_packets_ > 0); | 60 CHECK(outstanding_packets_ > 0); |
61 --outstanding_packets_; | 61 --outstanding_packets_; |
62 } | 62 } |
63 | 63 |
64 // static | 64 // static |
65 void MockFFmpeg::set(MockFFmpeg* instance) { | |
66 instance_ = instance; | |
67 } | |
68 | |
69 // static | |
70 MockFFmpeg* MockFFmpeg::get() { | |
71 return instance_; | |
72 } | |
73 | |
74 // static | |
75 URLProtocol* MockFFmpeg::protocol() { | 65 URLProtocol* MockFFmpeg::protocol() { |
76 return protocol_; | 66 return protocol_; |
77 } | 67 } |
78 | 68 |
79 // static | 69 // static |
80 void MockFFmpeg::DestructPacket(AVPacket* packet) { | 70 void MockFFmpeg::DestructPacket(AVPacket* packet) { |
81 delete [] packet->data; | 71 delete [] packet->data; |
82 packet->data = NULL; | 72 packet->data = NULL; |
83 packet->size = 0; | 73 packet->size = 0; |
84 } | 74 } |
85 | 75 |
86 // FFmpeg stubs that delegate to the FFmpegMock instance. | 76 // FFmpeg stubs that delegate to the FFmpegMock instance. |
87 extern "C" { | 77 extern "C" { |
88 void avcodec_init() { | 78 void avcodec_init() { |
89 media::MockFFmpeg::get()->AVCodecInit(); | 79 g_instance->AVCodecInit(); |
90 } | 80 } |
91 | 81 |
92 int av_register_protocol2(URLProtocol* protocol, int size) { | 82 int av_register_protocol2(URLProtocol* protocol, int size) { |
93 return media::MockFFmpeg::get()->AVRegisterProtocol2(protocol, size); | 83 return g_instance->AVRegisterProtocol2(protocol, size); |
94 } | 84 } |
95 | 85 |
96 void av_register_all() { | 86 void av_register_all() { |
97 media::MockFFmpeg::get()->AVRegisterAll(); | 87 g_instance->AVRegisterAll(); |
98 } | 88 } |
99 | 89 |
100 int av_lockmgr_register(int (*cb)(void**, enum AVLockOp)) { | 90 int av_lockmgr_register(int (*cb)(void**, enum AVLockOp)) { |
101 media::MockFFmpeg* mock = media::MockFFmpeg::get(); | |
102 // Here |mock| may be NULL when this function is called from ~FFmpegGlue(). | 91 // Here |mock| may be NULL when this function is called from ~FFmpegGlue(). |
103 if (mock != NULL) { | 92 if (g_instance) { |
104 return mock->AVRegisterLockManager(cb); | 93 return g_instance->AVRegisterLockManager(cb); |
105 } else { | |
106 return 0; | |
107 } | 94 } |
| 95 return 0; |
108 } | 96 } |
109 | 97 |
110 AVCodec* avcodec_find_decoder(enum CodecID id) { | 98 AVCodec* avcodec_find_decoder(enum CodecID id) { |
111 return media::MockFFmpeg::get()->AVCodecFindDecoder(id); | 99 return g_instance->AVCodecFindDecoder(id); |
112 } | 100 } |
113 | 101 |
114 int avcodec_open(AVCodecContext* avctx, AVCodec* codec) { | 102 int avcodec_open(AVCodecContext* avctx, AVCodec* codec) { |
115 return media::MockFFmpeg::get()->AVCodecOpen(avctx, codec); | 103 return g_instance->AVCodecOpen(avctx, codec); |
116 } | 104 } |
117 | 105 |
118 int avcodec_close(AVCodecContext* avctx) { | 106 int avcodec_close(AVCodecContext* avctx) { |
119 return media::MockFFmpeg::get()->AVCodecClose(avctx); | 107 return g_instance->AVCodecClose(avctx); |
120 } | 108 } |
121 | 109 |
122 int avcodec_thread_init(AVCodecContext* avctx, int threads) { | 110 int avcodec_thread_init(AVCodecContext* avctx, int threads) { |
123 return media::MockFFmpeg::get()->AVCodecThreadInit(avctx, threads); | 111 return g_instance->AVCodecThreadInit(avctx, threads); |
124 } | 112 } |
125 | 113 |
126 void avcodec_flush_buffers(AVCodecContext* avctx) { | 114 void avcodec_flush_buffers(AVCodecContext* avctx) { |
127 return media::MockFFmpeg::get()->AVCodecFlushBuffers(avctx); | 115 return g_instance->AVCodecFlushBuffers(avctx); |
128 } | 116 } |
129 | 117 |
130 AVFrame* avcodec_alloc_frame() { | 118 AVFrame* avcodec_alloc_frame() { |
131 return media::MockFFmpeg::get()->AVCodecAllocFrame(); | 119 return g_instance->AVCodecAllocFrame(); |
132 } | 120 } |
133 | 121 |
134 int avcodec_decode_video2(AVCodecContext* avctx, AVFrame* picture, | 122 int avcodec_decode_video2(AVCodecContext* avctx, AVFrame* picture, |
135 int* got_picture_ptr, AVPacket* avpkt) { | 123 int* got_picture_ptr, AVPacket* avpkt) { |
136 return media::MockFFmpeg::get()-> | 124 return g_instance-> |
137 AVCodecDecodeVideo2(avctx, picture, got_picture_ptr, avpkt); | 125 AVCodecDecodeVideo2(avctx, picture, got_picture_ptr, avpkt); |
138 } | 126 } |
139 | 127 |
140 AVBitStreamFilterContext* av_bitstream_filter_init(const char* name) { | 128 AVBitStreamFilterContext* av_bitstream_filter_init(const char* name) { |
141 return media::MockFFmpeg::get()->AVBitstreamFilterInit(name); | 129 return g_instance->AVBitstreamFilterInit(name); |
142 } | 130 } |
143 | 131 |
144 int av_bitstream_filter_filter(AVBitStreamFilterContext* bsfc, | 132 int av_bitstream_filter_filter(AVBitStreamFilterContext* bsfc, |
145 AVCodecContext* avctx, | 133 AVCodecContext* avctx, |
146 const char* args, | 134 const char* args, |
147 uint8_t** poutbuf, | 135 uint8_t** poutbuf, |
148 int* poutbuf_size, | 136 int* poutbuf_size, |
149 const uint8_t* buf, | 137 const uint8_t* buf, |
150 int buf_size, | 138 int buf_size, |
151 int keyframe) { | 139 int keyframe) { |
152 return media::MockFFmpeg::get()-> | 140 return g_instance-> |
153 AVBitstreamFilterFilter(bsfc, avctx, args, poutbuf, poutbuf_size, buf, | 141 AVBitstreamFilterFilter(bsfc, avctx, args, poutbuf, poutbuf_size, buf, |
154 buf_size, keyframe); | 142 buf_size, keyframe); |
155 } | 143 } |
156 | 144 |
157 void av_bitstream_filter_close(AVBitStreamFilterContext* bsf) { | 145 void av_bitstream_filter_close(AVBitStreamFilterContext* bsf) { |
158 return media::MockFFmpeg::get()->AVBitstreamFilterClose(bsf); | 146 return g_instance->AVBitstreamFilterClose(bsf); |
159 } | 147 } |
160 | 148 |
161 int av_open_input_file(AVFormatContext** format, const char* filename, | 149 int av_open_input_file(AVFormatContext** format, const char* filename, |
162 AVInputFormat* input_format, int buffer_size, | 150 AVInputFormat* input_format, int buffer_size, |
163 AVFormatParameters* parameters) { | 151 AVFormatParameters* parameters) { |
164 return media::MockFFmpeg::get()->AVOpenInputFile(format, filename, | 152 return g_instance->AVOpenInputFile(format, filename, |
165 input_format, buffer_size, | 153 input_format, buffer_size, |
166 parameters); | 154 parameters); |
167 } | 155 } |
168 | 156 |
169 void av_close_input_file(AVFormatContext* format) { | 157 void av_close_input_file(AVFormatContext* format) { |
170 media::MockFFmpeg::get()->AVCloseInputFile(format); | 158 g_instance->AVCloseInputFile(format); |
171 } | 159 } |
172 | 160 |
173 int av_find_stream_info(AVFormatContext* format) { | 161 int av_find_stream_info(AVFormatContext* format) { |
174 return media::MockFFmpeg::get()->AVFindStreamInfo(format); | 162 return g_instance->AVFindStreamInfo(format); |
175 } | 163 } |
176 | 164 |
177 int64 av_rescale_q(int64 a, AVRational bq, AVRational cq) { | 165 int64 av_rescale_q(int64 a, AVRational bq, AVRational cq) { |
178 // Because this is a math function there's little point in mocking it, so we | 166 // Because this is a math function there's little point in mocking it, so we |
179 // implement a cheap version that's capable of overflowing. | 167 // implement a cheap version that's capable of overflowing. |
180 int64 num = bq.num * cq.den; | 168 int64 num = bq.num * cq.den; |
181 int64 den = cq.num * bq.den; | 169 int64 den = cq.num * bq.den; |
182 return a * num / den; | 170 return a * num / den; |
183 } | 171 } |
184 | 172 |
185 int av_read_frame(AVFormatContext* format, AVPacket* packet) { | 173 int av_read_frame(AVFormatContext* format, AVPacket* packet) { |
186 return media::MockFFmpeg::get()->AVReadFrame(format, packet); | 174 return g_instance->AVReadFrame(format, packet); |
187 } | 175 } |
188 | 176 |
189 int av_seek_frame(AVFormatContext *format, int stream_index, int64_t timestamp, | 177 int av_seek_frame(AVFormatContext *format, int stream_index, int64_t timestamp, |
190 int flags) { | 178 int flags) { |
191 return media::MockFFmpeg::get()->AVSeekFrame(format, stream_index, timestamp, | 179 return g_instance->AVSeekFrame(format, stream_index, timestamp, |
192 flags); | 180 flags); |
193 } | 181 } |
194 | 182 |
195 void av_init_packet(AVPacket* pkt) { | 183 void av_init_packet(AVPacket* pkt) { |
196 return media::MockFFmpeg::get()->AVInitPacket(pkt); | 184 return g_instance->AVInitPacket(pkt); |
197 } | 185 } |
198 | 186 |
199 int av_new_packet(AVPacket* packet, int size) { | 187 int av_new_packet(AVPacket* packet, int size) { |
200 return media::MockFFmpeg::get()->AVNewPacket(packet, size); | 188 return g_instance->AVNewPacket(packet, size); |
201 } | 189 } |
202 | 190 |
203 void av_free_packet(AVPacket* packet) { | 191 void av_free_packet(AVPacket* packet) { |
204 media::MockFFmpeg::get()->AVFreePacket(packet); | 192 g_instance->AVFreePacket(packet); |
205 } | 193 } |
206 | 194 |
207 void av_free(void* ptr) { | 195 void av_free(void* ptr) { |
208 // Freeing NULL pointers are valid, but they aren't interesting from a mock | 196 // Freeing NULL pointers are valid, but they aren't interesting from a mock |
209 // perspective. | 197 // perspective. |
210 if (ptr) { | 198 if (ptr) { |
211 media::MockFFmpeg::get()->AVFree(ptr); | 199 g_instance->AVFree(ptr); |
212 } | 200 } |
213 } | 201 } |
214 | 202 |
215 int av_dup_packet(AVPacket* packet) { | 203 int av_dup_packet(AVPacket* packet) { |
216 return media::MockFFmpeg::get()->AVDupPacket(packet); | 204 return g_instance->AVDupPacket(packet); |
217 } | 205 } |
218 | 206 |
219 void av_log_set_level(int level) { | 207 void av_log_set_level(int level) { |
220 media::MockFFmpeg::get()->AVLogSetLevel(level); | 208 g_instance->AVLogSetLevel(level); |
221 } | 209 } |
222 | 210 |
223 void av_destruct_packet(AVPacket *pkt) { | 211 void av_destruct_packet(AVPacket *pkt) { |
224 media::MockFFmpeg::get()->AVDestructPacket(pkt); | 212 g_instance->AVDestructPacket(pkt); |
225 } | 213 } |
226 | 214 |
227 } // extern "C" | 215 } // extern "C" |
228 | 216 |
229 } // namespace media | 217 } // namespace media |
OLD | NEW |