Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(27)

Side by Side Diff: media/capture/video/video_capture_device_client_unittest.cc

Issue 2686763002: [Mojo Video Capture] Split OnIncomingCapturedVideoFrame() to OnNewBuffer() and OnFrameReadyInBuffer( (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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/capture/video/video_capture_device_client.h" 5 #include "media/capture/video/video_capture_device_client.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <memory> 9 #include <memory>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/macros.h" 13 #include "base/macros.h"
14 #include "base/run_loop.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/threading/thread_task_runner_handle.h"
17 #include "build/build_config.h" 14 #include "build/build_config.h"
18 #include "content/browser/renderer_host/media/video_capture_controller.h"
19 #include "content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h"
20 #include "content/browser/renderer_host/media/video_frame_receiver_on_io_thread. h"
21 #include "content/public/test/test_browser_thread_bundle.h"
22 #include "media/base/limits.h" 15 #include "media/base/limits.h"
23 #include "media/capture/video/video_capture_buffer_pool_impl.h" 16 #include "media/capture/video/video_capture_buffer_pool_impl.h"
24 #include "media/capture/video/video_capture_buffer_tracker_factory_impl.h" 17 #include "media/capture/video/video_capture_buffer_tracker_factory_impl.h"
18 #include "media/capture/video/video_capture_jpeg_decoder.h"
19 #include "media/capture/video/video_frame_receiver.h"
25 #include "testing/gmock/include/gmock/gmock.h" 20 #include "testing/gmock/include/gmock/gmock.h"
26 #include "testing/gtest/include/gtest/gtest.h" 21 #include "testing/gtest/include/gtest/gtest.h"
27 22
28 using ::testing::_; 23 using ::testing::_;
29 using ::testing::Mock; 24 using ::testing::Mock;
30 using ::testing::InSequence; 25 using ::testing::InSequence;
26 using ::testing::Invoke;
31 using ::testing::SaveArg; 27 using ::testing::SaveArg;
32 28
33 namespace content { 29 namespace media {
34 30
35 namespace { 31 namespace {
36 32
37 class MockVideoCaptureController : public VideoCaptureController { 33 class MockVideoCaptureController : public VideoFrameReceiver {
38 public: 34 public:
39 explicit MockVideoCaptureController() : VideoCaptureController() {} 35 MOCK_METHOD1(MockOnNewBufferHandle, void(int buffer_id));
40 ~MockVideoCaptureController() override {} 36 MOCK_METHOD3(
41 37 MockOnFrameReadyInBuffer,
42 MOCK_METHOD1(MockOnIncomingCapturedVideoFrame, void(const gfx::Size&)); 38 void(int buffer_id,
39 std::unique_ptr<media::VideoCaptureDevice::Client::Buffer::
40 ScopedAccessPermission>* buffer_read_permission,
41 const gfx::Size&));
43 MOCK_METHOD0(OnError, void()); 42 MOCK_METHOD0(OnError, void());
44 MOCK_METHOD1(OnLog, void(const std::string& message)); 43 MOCK_METHOD1(OnLog, void(const std::string& message));
45 MOCK_METHOD1(OnBufferRetired, void(int buffer_id)); 44 MOCK_METHOD1(OnBufferRetired, void(int buffer_id));
46 45
47 void OnIncomingCapturedVideoFrame( 46 void OnNewBufferHandle(
48 media::VideoCaptureDevice::Client::Buffer buffer, 47 int buffer_id,
49 scoped_refptr<media::VideoFrame> frame) override { 48 std::unique_ptr<media::VideoCaptureDevice::Client::Buffer::HandleProvider>
50 MockOnIncomingCapturedVideoFrame(frame->coded_size()); 49 handle_provider) override {
50 MockOnNewBufferHandle(buffer_id);
51 }
52
53 void OnFrameReadyInBuffer(
54 int32_t buffer_id,
55 int frame_feedback_id,
56 std::unique_ptr<
57 media::VideoCaptureDevice::Client::Buffer::ScopedAccessPermission>
58 buffer_read_permission,
59 media::mojom::VideoFrameInfoPtr frame_info) override {
60 MockOnFrameReadyInBuffer(buffer_id, &buffer_read_permission,
61 frame_info->coded_size);
51 } 62 }
52 }; 63 };
53 64
54 std::unique_ptr<media::VideoCaptureJpegDecoder> CreateGpuJpegDecoder( 65 std::unique_ptr<media::VideoCaptureJpegDecoder> ReturnNullPtrAsJpecDecoder() {
55 const media::VideoCaptureJpegDecoder::DecodeDoneCB& decode_done_cb) { 66 return nullptr;
56 return base::MakeUnique<content::VideoCaptureGpuJpegDecoder>(decode_done_cb);
57 } 67 }
58 68
59 // Test fixture for testing a unit consisting of an instance of 69 // Test fixture for testing a unit consisting of an instance of
60 // VideoCaptureDeviceClient connected to a partly-mocked instance of 70 // VideoCaptureDeviceClient connected to a partly-mocked instance of
61 // VideoCaptureController, and an instance of VideoCaptureBufferPoolImpl 71 // VideoCaptureController, and an instance of VideoCaptureBufferPoolImpl
62 // as well as related threading glue that replicates how it is used in 72 // as well as related threading glue that replicates how it is used in
63 // production. 73 // production.
64 class VideoCaptureDeviceClientTest : public ::testing::Test { 74 class VideoCaptureDeviceClientTest : public ::testing::Test {
65 public: 75 public:
66 VideoCaptureDeviceClientTest() 76 VideoCaptureDeviceClientTest() {
67 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {
68 scoped_refptr<media::VideoCaptureBufferPoolImpl> buffer_pool( 77 scoped_refptr<media::VideoCaptureBufferPoolImpl> buffer_pool(
69 new media::VideoCaptureBufferPoolImpl( 78 new media::VideoCaptureBufferPoolImpl(
70 base::MakeUnique<media::VideoCaptureBufferTrackerFactoryImpl>(), 79 base::MakeUnique<media::VideoCaptureBufferTrackerFactoryImpl>(),
71 1)); 80 1));
72 controller_ = base::MakeUnique<MockVideoCaptureController>(); 81 auto controller = base::MakeUnique<MockVideoCaptureController>();
82 controller_ = controller.get();
73 device_client_ = base::MakeUnique<media::VideoCaptureDeviceClient>( 83 device_client_ = base::MakeUnique<media::VideoCaptureDeviceClient>(
74 base::MakeUnique<VideoFrameReceiverOnIOThread>( 84 std::move(controller), buffer_pool,
75 controller_->GetWeakPtrForIOThread()), 85 base::Bind(&ReturnNullPtrAsJpecDecoder));
76 buffer_pool,
77 base::Bind(
78 &CreateGpuJpegDecoder,
79 base::Bind(&media::VideoFrameReceiver::OnIncomingCapturedVideoFrame,
80 controller_->GetWeakPtrForIOThread())));
81 } 86 }
82 ~VideoCaptureDeviceClientTest() override {} 87 ~VideoCaptureDeviceClientTest() override {}
83 88
84 void TearDown() override { base::RunLoop().RunUntilIdle(); }
85
86 protected: 89 protected:
87 const content::TestBrowserThreadBundle thread_bundle_; 90 MockVideoCaptureController* controller_;
88 std::unique_ptr<MockVideoCaptureController> controller_;
89 std::unique_ptr<media::VideoCaptureDeviceClient> device_client_; 91 std::unique_ptr<media::VideoCaptureDeviceClient> device_client_;
90 92
91 private: 93 private:
92 DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceClientTest); 94 DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceClientTest);
93 }; 95 };
94 96
95 } // namespace 97 } // namespace
96 98
97 // A small test for reference and to verify VideoCaptureDeviceClient is 99 // A small test for reference and to verify VideoCaptureDeviceClient is
98 // minimally functional. 100 // minimally functional.
99 TEST_F(VideoCaptureDeviceClientTest, Minimal) { 101 TEST_F(VideoCaptureDeviceClientTest, Minimal) {
100 const size_t kScratchpadSizeInBytes = 400; 102 const size_t kScratchpadSizeInBytes = 400;
101 unsigned char data[kScratchpadSizeInBytes] = {}; 103 unsigned char data[kScratchpadSizeInBytes] = {};
102 const media::VideoCaptureFormat kFrameFormat( 104 const media::VideoCaptureFormat kFrameFormat(
103 gfx::Size(10, 10), 30.0f /*frame_rate*/, 105 gfx::Size(10, 10), 30.0f /*frame_rate*/, media::PIXEL_FORMAT_I420,
104 media::PIXEL_FORMAT_I420,
105 media::PIXEL_STORAGE_CPU); 106 media::PIXEL_STORAGE_CPU);
106 DCHECK(device_client_.get()); 107 DCHECK(device_client_.get());
107 EXPECT_CALL(*controller_, OnLog(_)).Times(1); 108 {
108 EXPECT_CALL(*controller_, MockOnIncomingCapturedVideoFrame(_)).Times(1); 109 InSequence s;
110 const int expected_buffer_id = 0;
111 EXPECT_CALL(*controller_, OnLog(_));
112 EXPECT_CALL(*controller_, MockOnNewBufferHandle(expected_buffer_id));
113 EXPECT_CALL(*controller_,
114 MockOnFrameReadyInBuffer(expected_buffer_id, _, _));
115 EXPECT_CALL(*controller_, OnBufferRetired(expected_buffer_id));
116 }
109 device_client_->OnIncomingCapturedData(data, kScratchpadSizeInBytes, 117 device_client_->OnIncomingCapturedData(data, kScratchpadSizeInBytes,
110 kFrameFormat, 0 /*clockwise rotation*/, 118 kFrameFormat, 0 /*clockwise rotation*/,
111 base::TimeTicks(), base::TimeDelta()); 119 base::TimeTicks(), base::TimeDelta());
112 base::RunLoop().RunUntilIdle(); 120 // Releasing |device_client_| will also release |controller_|.
113 Mock::VerifyAndClearExpectations(controller_.get()); 121 device_client_.reset();
114 } 122 }
115 123
116 // Tests that we don't try to pass on frames with an invalid frame format. 124 // Tests that we don't try to pass on frames with an invalid frame format.
117 TEST_F(VideoCaptureDeviceClientTest, FailsSilentlyGivenInvalidFrameFormat) { 125 TEST_F(VideoCaptureDeviceClientTest, FailsSilentlyGivenInvalidFrameFormat) {
118 const size_t kScratchpadSizeInBytes = 400; 126 const size_t kScratchpadSizeInBytes = 400;
119 unsigned char data[kScratchpadSizeInBytes] = {}; 127 unsigned char data[kScratchpadSizeInBytes] = {};
120 // kFrameFormat is invalid in a number of ways. 128 // kFrameFormat is invalid in a number of ways.
121 const media::VideoCaptureFormat kFrameFormat( 129 const media::VideoCaptureFormat kFrameFormat(
122 gfx::Size(media::limits::kMaxDimension + 1, media::limits::kMaxDimension), 130 gfx::Size(media::limits::kMaxDimension + 1, media::limits::kMaxDimension),
123 media::limits::kMaxFramesPerSecond + 1, 131 media::limits::kMaxFramesPerSecond + 1,
124 media::VideoPixelFormat::PIXEL_FORMAT_I420, 132 media::VideoPixelFormat::PIXEL_FORMAT_I420,
125 media::VideoPixelStorage::PIXEL_STORAGE_CPU); 133 media::VideoPixelStorage::PIXEL_STORAGE_CPU);
126 DCHECK(device_client_.get()); 134 DCHECK(device_client_.get());
127 // Expect the the call to fail silently inside the VideoCaptureDeviceClient. 135 // Expect the the call to fail silently inside the VideoCaptureDeviceClient.
128 EXPECT_CALL(*controller_, OnLog(_)).Times(1); 136 EXPECT_CALL(*controller_, OnLog(_)).Times(1);
129 EXPECT_CALL(*controller_, MockOnIncomingCapturedVideoFrame(_)).Times(0); 137 EXPECT_CALL(*controller_, MockOnFrameReadyInBuffer(_, _, _)).Times(0);
130 device_client_->OnIncomingCapturedData(data, kScratchpadSizeInBytes, 138 device_client_->OnIncomingCapturedData(data, kScratchpadSizeInBytes,
131 kFrameFormat, 0 /*clockwise rotation*/, 139 kFrameFormat, 0 /*clockwise rotation*/,
132 base::TimeTicks(), base::TimeDelta()); 140 base::TimeTicks(), base::TimeDelta());
133 base::RunLoop().RunUntilIdle(); 141 Mock::VerifyAndClearExpectations(controller_);
134 Mock::VerifyAndClearExpectations(controller_.get());
135 } 142 }
136 143
137 // Tests that we fail silently if no available buffers to use. 144 // Tests that we fail silently if no available buffers to use.
138 TEST_F(VideoCaptureDeviceClientTest, DropsFrameIfNoBuffer) { 145 TEST_F(VideoCaptureDeviceClientTest, DropsFrameIfNoBuffer) {
139 const size_t kScratchpadSizeInBytes = 400; 146 const size_t kScratchpadSizeInBytes = 400;
140 unsigned char data[kScratchpadSizeInBytes] = {}; 147 unsigned char data[kScratchpadSizeInBytes] = {};
141 const media::VideoCaptureFormat kFrameFormat( 148 const media::VideoCaptureFormat kFrameFormat(
142 gfx::Size(10, 10), 30.0f /*frame_rate*/, 149 gfx::Size(10, 10), 30.0f /*frame_rate*/, media::PIXEL_FORMAT_I420,
143 media::PIXEL_FORMAT_I420,
144 media::PIXEL_STORAGE_CPU); 150 media::PIXEL_STORAGE_CPU);
145 // We expect the second frame to be silently dropped, so these should
146 // only be called once despite the two frames.
147 EXPECT_CALL(*controller_, OnLog(_)).Times(1); 151 EXPECT_CALL(*controller_, OnLog(_)).Times(1);
148 EXPECT_CALL(*controller_, MockOnIncomingCapturedVideoFrame(_)).Times(1); 152 // Simulate that receiver still holds |buffer_read_permission| for the first
153 // buffer when the second call to OnIncomingCapturedData comes in.
154 // Since we set up the buffer pool to max out at 1 buffer, this should cause
155 // |device_client_| to drop the frame.
156 std::unique_ptr<VideoCaptureDevice::Client::Buffer::ScopedAccessPermission>
157 read_permission;
158 EXPECT_CALL(*controller_, MockOnFrameReadyInBuffer(_, _, _))
159 .WillOnce(Invoke([&read_permission](
160 int buffer_id,
161 std::unique_ptr<media::VideoCaptureDevice::Client::Buffer::
162 ScopedAccessPermission>* buffer_read_permission,
163 const gfx::Size&) {
164 read_permission = std::move(*buffer_read_permission);
165 }));
149 // Pass two frames. The second will be dropped. 166 // Pass two frames. The second will be dropped.
150 device_client_->OnIncomingCapturedData(data, kScratchpadSizeInBytes, 167 device_client_->OnIncomingCapturedData(data, kScratchpadSizeInBytes,
151 kFrameFormat, 0 /*clockwise rotation*/, 168 kFrameFormat, 0 /*clockwise rotation*/,
152 base::TimeTicks(), base::TimeDelta()); 169 base::TimeTicks(), base::TimeDelta());
153 device_client_->OnIncomingCapturedData(data, kScratchpadSizeInBytes, 170 device_client_->OnIncomingCapturedData(data, kScratchpadSizeInBytes,
154 kFrameFormat, 0 /*clockwise rotation*/, 171 kFrameFormat, 0 /*clockwise rotation*/,
155 base::TimeTicks(), base::TimeDelta()); 172 base::TimeTicks(), base::TimeDelta());
156 base::RunLoop().RunUntilIdle(); 173 Mock::VerifyAndClearExpectations(controller_);
157 Mock::VerifyAndClearExpectations(controller_.get());
158 } 174 }
159 175
160 // Tests that buffer-based capture API accepts some memory-backed pixel formats. 176 // Tests that buffer-based capture API accepts some memory-backed pixel formats.
161 TEST_F(VideoCaptureDeviceClientTest, DataCaptureGoodPixelFormats) { 177 TEST_F(VideoCaptureDeviceClientTest, DataCaptureGoodPixelFormats) {
162 // The usual ReserveOutputBuffer() -> OnIncomingCapturedVideoFrame() cannot 178 // The usual ReserveOutputBuffer() -> OnIncomingCapturedVideoFrame() cannot
163 // be used since it does not accept all pixel formats. The memory backed 179 // be used since it does not accept all pixel formats. The memory backed
164 // buffer OnIncomingCapturedData() is used instead, with a dummy scratchpad 180 // buffer OnIncomingCapturedData() is used instead, with a dummy scratchpad
165 // buffer. 181 // buffer.
166 const size_t kScratchpadSizeInBytes = 400; 182 const size_t kScratchpadSizeInBytes = 400;
167 unsigned char data[kScratchpadSizeInBytes] = {}; 183 unsigned char data[kScratchpadSizeInBytes] = {};
(...skipping 19 matching lines...) Expand all
187 #endif 203 #endif
188 media::PIXEL_FORMAT_RGB32, 204 media::PIXEL_FORMAT_RGB32,
189 media::PIXEL_FORMAT_ARGB, 205 media::PIXEL_FORMAT_ARGB,
190 media::PIXEL_FORMAT_Y16, 206 media::PIXEL_FORMAT_Y16,
191 }; 207 };
192 208
193 for (media::VideoPixelFormat format : kSupportedFormats) { 209 for (media::VideoPixelFormat format : kSupportedFormats) {
194 params.requested_format.pixel_format = format; 210 params.requested_format.pixel_format = format;
195 211
196 EXPECT_CALL(*controller_, OnLog(_)).Times(1); 212 EXPECT_CALL(*controller_, OnLog(_)).Times(1);
197 EXPECT_CALL(*controller_, MockOnIncomingCapturedVideoFrame(_)).Times(1); 213 EXPECT_CALL(*controller_, MockOnFrameReadyInBuffer(_, _, _)).Times(1);
198 device_client_->OnIncomingCapturedData( 214 device_client_->OnIncomingCapturedData(
199 data, params.requested_format.ImageAllocationSize(), 215 data, params.requested_format.ImageAllocationSize(),
200 params.requested_format, 0 /* clockwise_rotation */, base::TimeTicks(), 216 params.requested_format, 0 /* clockwise_rotation */, base::TimeTicks(),
201 base::TimeDelta()); 217 base::TimeDelta());
202 base::RunLoop().RunUntilIdle(); 218 Mock::VerifyAndClearExpectations(controller_);
203 Mock::VerifyAndClearExpectations(controller_.get());
204 } 219 }
205 } 220 }
206 221
207 // Test that we receive the expected resolution for a given captured frame 222 // Test that we receive the expected resolution for a given captured frame
208 // resolution and rotation. Odd resolutions are also cropped. 223 // resolution and rotation. Odd resolutions are also cropped.
209 TEST_F(VideoCaptureDeviceClientTest, CheckRotationsAndCrops) { 224 TEST_F(VideoCaptureDeviceClientTest, CheckRotationsAndCrops) {
210 const struct SizeAndRotation { 225 const struct SizeAndRotation {
211 gfx::Size input_resolution; 226 gfx::Size input_resolution;
212 int rotation; 227 int rotation;
213 gfx::Size output_resolution; 228 gfx::Size output_resolution;
214 } kSizeAndRotations[] = {{{6, 4}, 0, {6, 4}}, 229 } kSizeAndRotations[] = {{{6, 4}, 0, {6, 4}}, {{6, 4}, 90, {4, 6}},
215 {{6, 4}, 90, {4, 6}}, 230 {{6, 4}, 180, {6, 4}}, {{6, 4}, 270, {4, 6}},
216 {{6, 4}, 180, {6, 4}}, 231 {{7, 4}, 0, {6, 4}}, {{7, 4}, 90, {4, 6}},
217 {{6, 4}, 270, {4, 6}}, 232 {{7, 4}, 180, {6, 4}}, {{7, 4}, 270, {4, 6}}};
218 {{7, 4}, 0, {6, 4}},
219 {{7, 4}, 90, {4, 6}},
220 {{7, 4}, 180, {6, 4}},
221 {{7, 4}, 270, {4, 6}}};
222 233
223 // The usual ReserveOutputBuffer() -> OnIncomingCapturedVideoFrame() cannot 234 // The usual ReserveOutputBuffer() -> OnIncomingCapturedVideoFrame() cannot
224 // be used since it does not resolve rotations or crops. The memory backed 235 // be used since it does not resolve rotations or crops. The memory backed
225 // buffer OnIncomingCapturedData() is used instead, with a dummy scratchpad 236 // buffer OnIncomingCapturedData() is used instead, with a dummy scratchpad
226 // buffer. 237 // buffer.
227 const size_t kScratchpadSizeInBytes = 400; 238 const size_t kScratchpadSizeInBytes = 400;
228 unsigned char data[kScratchpadSizeInBytes] = {}; 239 unsigned char data[kScratchpadSizeInBytes] = {};
229 240
230 EXPECT_CALL(*controller_, OnLog(_)).Times(1); 241 EXPECT_CALL(*controller_, OnLog(_)).Times(1);
231 242
232 media::VideoCaptureParams params; 243 media::VideoCaptureParams params;
233 for (const auto& size_and_rotation : kSizeAndRotations) { 244 for (const auto& size_and_rotation : kSizeAndRotations) {
234 ASSERT_GE(kScratchpadSizeInBytes, 245 ASSERT_GE(kScratchpadSizeInBytes,
235 size_and_rotation.input_resolution.GetArea() * 4u) 246 size_and_rotation.input_resolution.GetArea() * 4u)
236 << "Scratchpad is too small to hold the largest pixel format (ARGB)."; 247 << "Scratchpad is too small to hold the largest pixel format (ARGB).";
237 params.requested_format = 248 params.requested_format = media::VideoCaptureFormat(
238 media::VideoCaptureFormat(size_and_rotation.input_resolution, 30.0f, 249 size_and_rotation.input_resolution, 30.0f, media::PIXEL_FORMAT_ARGB);
239 media::PIXEL_FORMAT_ARGB);
240 gfx::Size coded_size; 250 gfx::Size coded_size;
241 EXPECT_CALL(*controller_, MockOnIncomingCapturedVideoFrame(_)) 251 EXPECT_CALL(*controller_, MockOnFrameReadyInBuffer(_, _, _))
242 .Times(1) 252 .Times(1)
243 .WillOnce(SaveArg<0>(&coded_size)); 253 .WillOnce(SaveArg<2>(&coded_size));
244 device_client_->OnIncomingCapturedData( 254 device_client_->OnIncomingCapturedData(
245 data, params.requested_format.ImageAllocationSize(), 255 data, params.requested_format.ImageAllocationSize(),
246 params.requested_format, size_and_rotation.rotation, base::TimeTicks(), 256 params.requested_format, size_and_rotation.rotation, base::TimeTicks(),
247 base::TimeDelta()); 257 base::TimeDelta());
248 base::RunLoop().RunUntilIdle();
249 258
250 EXPECT_EQ(coded_size.width(), size_and_rotation.output_resolution.width()); 259 EXPECT_EQ(coded_size.width(), size_and_rotation.output_resolution.width());
251 EXPECT_EQ(coded_size.height(), 260 EXPECT_EQ(coded_size.height(),
252 size_and_rotation.output_resolution.height()); 261 size_and_rotation.output_resolution.height());
253 262
254 Mock::VerifyAndClearExpectations(controller_.get()); 263 Mock::VerifyAndClearExpectations(controller_);
255 } 264 }
256 } 265 }
257 266
258 } // namespace content 267 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698