OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/gpu/vaapi_wrapper.h" | 5 #include "media/gpu/vaapi_wrapper.h" |
6 | 6 |
7 #include <dlfcn.h> | 7 #include <dlfcn.h> |
8 #include <string.h> | 8 #include <string.h> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
88 case gfx::BufferFormat::BGRA_8888: | 88 case gfx::BufferFormat::BGRA_8888: |
89 return VA_RT_FORMAT_RGB32; | 89 return VA_RT_FORMAT_RGB32; |
90 case gfx::BufferFormat::YVU_420: | 90 case gfx::BufferFormat::YVU_420: |
91 return VA_RT_FORMAT_YUV420; | 91 return VA_RT_FORMAT_YUV420; |
92 default: | 92 default: |
93 NOTREACHED(); | 93 NOTREACHED(); |
94 return 0; | 94 return 0; |
95 } | 95 } |
96 } | 96 } |
97 | 97 |
98 VADisplayState* GetDisplayState() { | |
99 static VADisplayState* display_state = new VADisplayState(); | |
100 return display_state; | |
101 } | |
102 | |
103 LazyProfileInfos* GetProfileInfos() { | |
104 static LazyProfileInfos* profile_infos = new LazyProfileInfos(); | |
105 return profile_infos; | |
106 } | |
107 | |
98 } // namespace | 108 } // namespace |
99 #endif | 109 #endif |
100 | 110 |
101 namespace media { | 111 namespace media { |
102 | 112 |
103 // Maximum framerate of encoded profile. This value is an arbitary limit | 113 // Maximum framerate of encoded profile. This value is an arbitary limit |
104 // and not taken from HW documentation. | 114 // and not taken from HW documentation. |
105 const int kMaxEncoderFramerate = 30; | 115 const int kMaxEncoderFramerate = 30; |
106 | 116 |
107 base::LazyInstance<VaapiWrapper::VADisplayState> | |
108 VaapiWrapper::va_display_state_ = LAZY_INSTANCE_INITIALIZER; | |
109 | |
110 base::LazyInstance<VaapiWrapper::LazyProfileInfos> | |
111 VaapiWrapper::profile_infos_ = LAZY_INSTANCE_INITIALIZER; | |
112 | |
113 // Config attributes common for both encode and decode. | 117 // Config attributes common for both encode and decode. |
114 static const VAConfigAttrib kCommonVAConfigAttribs[] = { | 118 static const VAConfigAttrib kCommonVAConfigAttribs[] = { |
115 {VAConfigAttribRTFormat, VA_RT_FORMAT_YUV420}, | 119 {VAConfigAttribRTFormat, VA_RT_FORMAT_YUV420}, |
116 }; | 120 }; |
117 | 121 |
118 // Attributes required for encode. | 122 // Attributes required for encode. |
119 static const VAConfigAttrib kEncodeVAConfigAttribs[] = { | 123 static const VAConfigAttrib kEncodeVAConfigAttribs[] = { |
120 {VAConfigAttribRateControl, VA_RC_CBR}, | 124 {VAConfigAttribRateControl, VA_RC_CBR}, |
121 {VAConfigAttribEncPackedHeaders, | 125 {VAConfigAttribEncPackedHeaders, |
122 VA_ENC_PACKED_HEADER_SEQUENCE | VA_ENC_PACKED_HEADER_PICTURE}, | 126 VA_ENC_PACKED_HEADER_SEQUENCE | VA_ENC_PACKED_HEADER_PICTURE}, |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
170 } | 174 } |
171 | 175 |
172 VaapiWrapper::VaapiWrapper() | 176 VaapiWrapper::VaapiWrapper() |
173 : va_surface_format_(0), | 177 : va_surface_format_(0), |
174 va_display_(NULL), | 178 va_display_(NULL), |
175 va_config_id_(VA_INVALID_ID), | 179 va_config_id_(VA_INVALID_ID), |
176 va_context_id_(VA_INVALID_ID), | 180 va_context_id_(VA_INVALID_ID), |
177 va_vpp_config_id_(VA_INVALID_ID), | 181 va_vpp_config_id_(VA_INVALID_ID), |
178 va_vpp_context_id_(VA_INVALID_ID), | 182 va_vpp_context_id_(VA_INVALID_ID), |
179 va_vpp_buffer_id_(VA_INVALID_ID) { | 183 va_vpp_buffer_id_(VA_INVALID_ID) { |
180 va_lock_ = va_display_state_.Get().va_lock(); | 184 va_lock_ = GetDisplayState()->va_lock(); |
Mark Mentovai
2017/01/31 22:16:00
For consistency, you can deal with this in the ini
| |
181 } | 185 } |
182 | 186 |
183 VaapiWrapper::~VaapiWrapper() { | 187 VaapiWrapper::~VaapiWrapper() { |
184 DestroyPendingBuffers(); | 188 DestroyPendingBuffers(); |
185 DestroyCodedBuffers(); | 189 DestroyCodedBuffers(); |
186 DestroySurfaces(); | 190 DestroySurfaces(); |
187 DeinitializeVpp(); | 191 DeinitializeVpp(); |
188 Deinitialize(); | 192 Deinitialize(); |
189 } | 193 } |
190 | 194 |
191 // static | 195 // static |
192 scoped_refptr<VaapiWrapper> VaapiWrapper::Create( | 196 scoped_refptr<VaapiWrapper> VaapiWrapper::Create( |
193 CodecMode mode, | 197 CodecMode mode, |
194 VAProfile va_profile, | 198 VAProfile va_profile, |
195 const base::Closure& report_error_to_uma_cb) { | 199 const base::Closure& report_error_to_uma_cb) { |
196 if (!profile_infos_.Get().IsProfileSupported(mode, va_profile)) { | 200 if (!GetProfileInfos()->IsProfileSupported(mode, va_profile)) { |
197 DVLOG(1) << "Unsupported va_profile: " << va_profile; | 201 DVLOG(1) << "Unsupported va_profile: " << va_profile; |
198 return nullptr; | 202 return nullptr; |
199 } | 203 } |
200 | 204 |
201 scoped_refptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper()); | 205 scoped_refptr<VaapiWrapper> vaapi_wrapper(new VaapiWrapper()); |
202 if (vaapi_wrapper->VaInitialize(report_error_to_uma_cb)) { | 206 if (vaapi_wrapper->VaInitialize(report_error_to_uma_cb)) { |
203 if (vaapi_wrapper->Initialize(mode, va_profile)) | 207 if (vaapi_wrapper->Initialize(mode, va_profile)) |
204 return vaapi_wrapper; | 208 return vaapi_wrapper; |
205 } | 209 } |
206 LOG(ERROR) << "Failed to create VaapiWrapper for va_profile: " << va_profile; | 210 LOG(ERROR) << "Failed to create VaapiWrapper for va_profile: " << va_profile; |
207 return nullptr; | 211 return nullptr; |
208 } | 212 } |
209 | 213 |
210 // static | 214 // static |
211 scoped_refptr<VaapiWrapper> VaapiWrapper::CreateForVideoCodec( | 215 scoped_refptr<VaapiWrapper> VaapiWrapper::CreateForVideoCodec( |
212 CodecMode mode, | 216 CodecMode mode, |
213 VideoCodecProfile profile, | 217 VideoCodecProfile profile, |
214 const base::Closure& report_error_to_uma_cb) { | 218 const base::Closure& report_error_to_uma_cb) { |
215 VAProfile va_profile = ProfileToVAProfile(profile, mode); | 219 VAProfile va_profile = ProfileToVAProfile(profile, mode); |
216 scoped_refptr<VaapiWrapper> vaapi_wrapper = | 220 scoped_refptr<VaapiWrapper> vaapi_wrapper = |
217 Create(mode, va_profile, report_error_to_uma_cb); | 221 Create(mode, va_profile, report_error_to_uma_cb); |
218 return vaapi_wrapper; | 222 return vaapi_wrapper; |
219 } | 223 } |
220 | 224 |
221 // static | 225 // static |
222 VideoEncodeAccelerator::SupportedProfiles | 226 VideoEncodeAccelerator::SupportedProfiles |
223 VaapiWrapper::GetSupportedEncodeProfiles() { | 227 VaapiWrapper::GetSupportedEncodeProfiles() { |
224 VideoEncodeAccelerator::SupportedProfiles profiles; | 228 VideoEncodeAccelerator::SupportedProfiles profiles; |
225 std::vector<ProfileInfo> encode_profile_infos = | 229 std::vector<ProfileInfo> encode_profile_infos = |
226 profile_infos_.Get().GetSupportedProfileInfosForCodecMode(kEncode); | 230 GetProfileInfos()->GetSupportedProfileInfosForCodecMode(kEncode); |
227 | 231 |
228 for (size_t i = 0; i < arraysize(kProfileMap); ++i) { | 232 for (size_t i = 0; i < arraysize(kProfileMap); ++i) { |
229 VAProfile va_profile = ProfileToVAProfile(kProfileMap[i].profile, kEncode); | 233 VAProfile va_profile = ProfileToVAProfile(kProfileMap[i].profile, kEncode); |
230 if (va_profile == VAProfileNone) | 234 if (va_profile == VAProfileNone) |
231 continue; | 235 continue; |
232 for (const auto& profile_info : encode_profile_infos) { | 236 for (const auto& profile_info : encode_profile_infos) { |
233 if (profile_info.va_profile == va_profile) { | 237 if (profile_info.va_profile == va_profile) { |
234 VideoEncodeAccelerator::SupportedProfile profile; | 238 VideoEncodeAccelerator::SupportedProfile profile; |
235 profile.profile = kProfileMap[i].profile; | 239 profile.profile = kProfileMap[i].profile; |
236 profile.max_resolution = profile_info.max_resolution; | 240 profile.max_resolution = profile_info.max_resolution; |
237 profile.max_framerate_numerator = kMaxEncoderFramerate; | 241 profile.max_framerate_numerator = kMaxEncoderFramerate; |
238 profile.max_framerate_denominator = 1; | 242 profile.max_framerate_denominator = 1; |
239 profiles.push_back(profile); | 243 profiles.push_back(profile); |
240 break; | 244 break; |
241 } | 245 } |
242 } | 246 } |
243 } | 247 } |
244 return profiles; | 248 return profiles; |
245 } | 249 } |
246 | 250 |
247 // static | 251 // static |
248 VideoDecodeAccelerator::SupportedProfiles | 252 VideoDecodeAccelerator::SupportedProfiles |
249 VaapiWrapper::GetSupportedDecodeProfiles() { | 253 VaapiWrapper::GetSupportedDecodeProfiles() { |
250 VideoDecodeAccelerator::SupportedProfiles profiles; | 254 VideoDecodeAccelerator::SupportedProfiles profiles; |
251 std::vector<ProfileInfo> decode_profile_infos = | 255 std::vector<ProfileInfo> decode_profile_infos = |
252 profile_infos_.Get().GetSupportedProfileInfosForCodecMode(kDecode); | 256 GetProfileInfos()->GetSupportedProfileInfosForCodecMode(kDecode); |
253 | 257 |
254 for (size_t i = 0; i < arraysize(kProfileMap); ++i) { | 258 for (size_t i = 0; i < arraysize(kProfileMap); ++i) { |
255 VAProfile va_profile = ProfileToVAProfile(kProfileMap[i].profile, kDecode); | 259 VAProfile va_profile = ProfileToVAProfile(kProfileMap[i].profile, kDecode); |
256 if (va_profile == VAProfileNone) | 260 if (va_profile == VAProfileNone) |
257 continue; | 261 continue; |
258 for (const auto& profile_info : decode_profile_infos) { | 262 for (const auto& profile_info : decode_profile_infos) { |
259 if (profile_info.va_profile == va_profile) { | 263 if (profile_info.va_profile == va_profile) { |
260 VideoDecodeAccelerator::SupportedProfile profile; | 264 VideoDecodeAccelerator::SupportedProfile profile; |
261 profile.profile = kProfileMap[i].profile; | 265 profile.profile = kProfileMap[i].profile; |
262 profile.max_resolution = profile_info.max_resolution; | 266 profile.max_resolution = profile_info.max_resolution; |
263 profile.min_resolution.SetSize(16, 16); | 267 profile.min_resolution.SetSize(16, 16); |
264 profiles.push_back(profile); | 268 profiles.push_back(profile); |
265 break; | 269 break; |
266 } | 270 } |
267 } | 271 } |
268 } | 272 } |
269 return profiles; | 273 return profiles; |
270 } | 274 } |
271 | 275 |
272 // static | 276 // static |
273 bool VaapiWrapper::IsJpegDecodeSupported() { | 277 bool VaapiWrapper::IsJpegDecodeSupported() { |
274 return profile_infos_.Get().IsProfileSupported(kDecode, | 278 return GetProfileInfos()->IsProfileSupported(kDecode, VAProfileJPEGBaseline); |
275 VAProfileJPEGBaseline); | |
276 } | 279 } |
277 | 280 |
278 void VaapiWrapper::TryToSetVADisplayAttributeToLocalGPU() { | 281 void VaapiWrapper::TryToSetVADisplayAttributeToLocalGPU() { |
279 base::AutoLock auto_lock(*va_lock_); | 282 base::AutoLock auto_lock(*va_lock_); |
280 VADisplayAttribute item = {VADisplayAttribRenderMode, | 283 VADisplayAttribute item = {VADisplayAttribRenderMode, |
281 1, // At least support '_LOCAL_OVERLAY'. | 284 1, // At least support '_LOCAL_OVERLAY'. |
282 -1, // The maximum possible support 'ALL'. | 285 -1, // The maximum possible support 'ALL'. |
283 VA_RENDER_MODE_LOCAL_GPU, | 286 VA_RENDER_MODE_LOCAL_GPU, |
284 VA_DISPLAY_ATTRIB_SETTABLE}; | 287 VA_DISPLAY_ATTRIB_SETTABLE}; |
285 | 288 |
286 VAStatus va_res = vaSetDisplayAttributes(va_display_, &item, 1); | 289 VAStatus va_res = vaSetDisplayAttributes(va_display_, &item, 1); |
287 if (va_res != VA_STATUS_SUCCESS) | 290 if (va_res != VA_STATUS_SUCCESS) |
288 DVLOG(2) << "vaSetDisplayAttributes unsupported, ignoring by default."; | 291 DVLOG(2) << "vaSetDisplayAttributes unsupported, ignoring by default."; |
289 } | 292 } |
290 | 293 |
291 // static | 294 // static |
292 VAProfile VaapiWrapper::ProfileToVAProfile(VideoCodecProfile profile, | 295 VAProfile VaapiWrapper::ProfileToVAProfile(VideoCodecProfile profile, |
293 CodecMode mode) { | 296 CodecMode mode) { |
294 VAProfile va_profile = VAProfileNone; | 297 VAProfile va_profile = VAProfileNone; |
295 for (size_t i = 0; i < arraysize(kProfileMap); ++i) { | 298 for (size_t i = 0; i < arraysize(kProfileMap); ++i) { |
296 if (kProfileMap[i].profile == profile) { | 299 if (kProfileMap[i].profile == profile) { |
297 va_profile = kProfileMap[i].va_profile; | 300 va_profile = kProfileMap[i].va_profile; |
298 break; | 301 break; |
299 } | 302 } |
300 } | 303 } |
301 if (!profile_infos_.Get().IsProfileSupported(mode, va_profile) && | 304 if (!GetProfileInfos()->IsProfileSupported(mode, va_profile) && |
302 va_profile == VAProfileH264Baseline) { | 305 va_profile == VAProfileH264Baseline) { |
303 // crbug.com/345569: ProfileIDToVideoCodecProfile() currently strips | 306 // crbug.com/345569: ProfileIDToVideoCodecProfile() currently strips |
304 // the information whether the profile is constrained or not, so we have no | 307 // the information whether the profile is constrained or not, so we have no |
305 // way to know here. Try for baseline first, but if it is not supported, | 308 // way to know here. Try for baseline first, but if it is not supported, |
306 // try constrained baseline and hope this is what it actually is | 309 // try constrained baseline and hope this is what it actually is |
307 // (which in practice is true for a great majority of cases). | 310 // (which in practice is true for a great majority of cases). |
308 if (profile_infos_.Get().IsProfileSupported( | 311 if (GetProfileInfos()->IsProfileSupported( |
309 mode, VAProfileH264ConstrainedBaseline)) { | 312 mode, VAProfileH264ConstrainedBaseline)) { |
310 va_profile = VAProfileH264ConstrainedBaseline; | 313 va_profile = VAProfileH264ConstrainedBaseline; |
311 DVLOG(1) << "Fall back to constrained baseline profile."; | 314 DVLOG(1) << "Fall back to constrained baseline profile."; |
312 } | 315 } |
313 } | 316 } |
314 return va_profile; | 317 return va_profile; |
315 } | 318 } |
316 | 319 |
317 std::vector<VaapiWrapper::ProfileInfo> | 320 std::vector<VaapiWrapper::ProfileInfo> |
318 VaapiWrapper::GetSupportedProfileInfosForCodecModeInternal(CodecMode mode) { | 321 VaapiWrapper::GetSupportedProfileInfosForCodecModeInternal(CodecMode mode) { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
357 if (running_on_chromeos) | 360 if (running_on_chromeos) |
358 LOG(ERROR) << kErrorMsg; | 361 LOG(ERROR) << kErrorMsg; |
359 else | 362 else |
360 DVLOG(1) << kErrorMsg; | 363 DVLOG(1) << kErrorMsg; |
361 return false; | 364 return false; |
362 } | 365 } |
363 | 366 |
364 report_error_to_uma_cb_ = report_error_to_uma_cb; | 367 report_error_to_uma_cb_ = report_error_to_uma_cb; |
365 | 368 |
366 base::AutoLock auto_lock(*va_lock_); | 369 base::AutoLock auto_lock(*va_lock_); |
367 | 370 if (!GetDisplayState()->Initialize()) |
368 VADisplayState* va_display_state = &va_display_state_.Get(); | |
369 if (!va_display_state) { | |
370 LOG(ERROR) << "Failed to allocate VA display state"; | |
371 return false; | |
372 } | |
373 | |
374 if (!va_display_state->Initialize()) | |
375 return false; | 371 return false; |
376 | 372 |
377 va_display_ = va_display_state->va_display(); | 373 va_display_ = GetDisplayState()->va_display(); |
378 return true; | 374 return true; |
379 } | 375 } |
380 | 376 |
381 bool VaapiWrapper::GetSupportedVaProfiles(std::vector<VAProfile>* profiles) { | 377 bool VaapiWrapper::GetSupportedVaProfiles(std::vector<VAProfile>* profiles) { |
382 base::AutoLock auto_lock(*va_lock_); | 378 base::AutoLock auto_lock(*va_lock_); |
383 // Query the driver for supported profiles. | 379 // Query the driver for supported profiles. |
384 int max_profiles = vaMaxNumProfiles(va_display_); | 380 int max_profiles = vaMaxNumProfiles(va_display_); |
385 std::vector<VAProfile> supported_profiles( | 381 std::vector<VAProfile> supported_profiles( |
386 base::checked_cast<size_t>(max_profiles)); | 382 base::checked_cast<size_t>(max_profiles)); |
387 | 383 |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
513 } | 509 } |
514 | 510 |
515 void VaapiWrapper::Deinitialize() { | 511 void VaapiWrapper::Deinitialize() { |
516 base::AutoLock auto_lock(*va_lock_); | 512 base::AutoLock auto_lock(*va_lock_); |
517 | 513 |
518 if (va_config_id_ != VA_INVALID_ID) { | 514 if (va_config_id_ != VA_INVALID_ID) { |
519 VAStatus va_res = vaDestroyConfig(va_display_, va_config_id_); | 515 VAStatus va_res = vaDestroyConfig(va_display_, va_config_id_); |
520 VA_LOG_ON_ERROR(va_res, "vaDestroyConfig failed"); | 516 VA_LOG_ON_ERROR(va_res, "vaDestroyConfig failed"); |
521 } | 517 } |
522 | 518 |
523 VADisplayState* va_display_state = &va_display_state_.Get(); | 519 VAStatus va_res = VA_STATUS_SUCCESS; |
524 if (va_display_state) { | 520 GetDisplayState()->Deinitialize(&va_res); |
525 VAStatus va_res = VA_STATUS_SUCCESS; | 521 VA_LOG_ON_ERROR(va_res, "vaTerminate failed"); |
526 va_display_state->Deinitialize(&va_res); | |
527 VA_LOG_ON_ERROR(va_res, "vaTerminate failed"); | |
528 } | |
529 | 522 |
530 va_config_id_ = VA_INVALID_ID; | 523 va_config_id_ = VA_INVALID_ID; |
531 va_display_ = NULL; | 524 va_display_ = NULL; |
532 } | 525 } |
533 | 526 |
534 bool VaapiWrapper::CreateSurfaces(unsigned int va_format, | 527 bool VaapiWrapper::CreateSurfaces(unsigned int va_format, |
535 const gfx::Size& size, | 528 const gfx::Size& size, |
536 size_t num_surfaces, | 529 size_t num_surfaces, |
537 std::vector<VASurfaceID>* va_surfaces) { | 530 std::vector<VASurfaceID>* va_surfaces) { |
538 base::AutoLock auto_lock(*va_lock_); | 531 base::AutoLock auto_lock(*va_lock_); |
(...skipping 600 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1139 } | 1132 } |
1140 | 1133 |
1141 // static | 1134 // static |
1142 void VaapiWrapper::PreSandboxInitialization() { | 1135 void VaapiWrapper::PreSandboxInitialization() { |
1143 #if defined(USE_OZONE) | 1136 #if defined(USE_OZONE) |
1144 const char kDriRenderNode0Path[] = "/dev/dri/renderD128"; | 1137 const char kDriRenderNode0Path[] = "/dev/dri/renderD128"; |
1145 base::File drm_file = base::File( | 1138 base::File drm_file = base::File( |
1146 base::FilePath::FromUTF8Unsafe(kDriRenderNode0Path), | 1139 base::FilePath::FromUTF8Unsafe(kDriRenderNode0Path), |
1147 base::File::FLAG_OPEN | base::File::FLAG_READ | base::File::FLAG_WRITE); | 1140 base::File::FLAG_OPEN | base::File::FLAG_READ | base::File::FLAG_WRITE); |
1148 if (drm_file.IsValid()) | 1141 if (drm_file.IsValid()) |
1149 va_display_state_.Get().SetDrmFd(drm_file.GetPlatformFile()); | 1142 GetDisplayState()->SetDrmFd(drm_file.GetPlatformFile()); |
1150 #endif | 1143 #endif |
1151 } | 1144 } |
1152 | 1145 |
1153 // static | 1146 // static |
1154 bool VaapiWrapper::PostSandboxInitialization() { | 1147 bool VaapiWrapper::PostSandboxInitialization() { |
1155 StubPathMap paths; | 1148 StubPathMap paths; |
1156 | 1149 |
1157 paths[kModuleVa].push_back("libva.so.1"); | 1150 paths[kModuleVa].push_back("libva.so.1"); |
1158 | 1151 |
1159 #if defined(USE_X11) | 1152 #if defined(USE_X11) |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1258 drm_fd_.reset(HANDLE_EINTR(dup(fd))); | 1251 drm_fd_.reset(HANDLE_EINTR(dup(fd))); |
1259 } | 1252 } |
1260 #endif // USE_OZONE | 1253 #endif // USE_OZONE |
1261 | 1254 |
1262 bool VaapiWrapper::VADisplayState::VAAPIVersionLessThan(int major, int minor) { | 1255 bool VaapiWrapper::VADisplayState::VAAPIVersionLessThan(int major, int minor) { |
1263 return (major_version_ < major) || | 1256 return (major_version_ < major) || |
1264 (major_version_ == major && minor_version_ < minor); | 1257 (major_version_ == major && minor_version_ < minor); |
1265 } | 1258 } |
1266 | 1259 |
1267 } // namespace media | 1260 } // namespace media |
OLD | NEW |