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

Side by Side Diff: content/common/gpu/media/dxva_video_decode_accelerator_win.cc

Issue 1839193003: Reland: Introduce GpuVideoDecodeAcceleratorFactory. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 8 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 (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "content/common/gpu/media/dxva_video_decode_accelerator_win.h" 5 #include "content/common/gpu/media/dxva_video_decode_accelerator_win.h"
6 6
7 #if !defined(OS_WIN) 7 #if !defined(OS_WIN)
8 #error This file should only be built on Windows. 8 #error This file should only be built on Windows.
9 #endif // !defined(OS_WIN) 9 #endif // !defined(OS_WIN)
10 10
(...skipping 830 matching lines...) Expand 10 before | Expand all | Expand 10 after
841 DXVAVideoDecodeAccelerator::PendingSampleInfo::PendingSampleInfo( 841 DXVAVideoDecodeAccelerator::PendingSampleInfo::PendingSampleInfo(
842 int32_t buffer_id, 842 int32_t buffer_id,
843 IMFSample* sample) 843 IMFSample* sample)
844 : input_buffer_id(buffer_id), picture_buffer_id(-1) { 844 : input_buffer_id(buffer_id), picture_buffer_id(-1) {
845 output_sample.Attach(sample); 845 output_sample.Attach(sample);
846 } 846 }
847 847
848 DXVAVideoDecodeAccelerator::PendingSampleInfo::~PendingSampleInfo() {} 848 DXVAVideoDecodeAccelerator::PendingSampleInfo::~PendingSampleInfo() {}
849 849
850 DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator( 850 DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator(
851 const base::Callback<bool(void)>& make_context_current, 851 const GetGLContextCallback& get_gl_context_cb,
852 gfx::GLContext* gl_context, 852 const MakeGLContextCurrentCallback& make_context_current_cb,
853 bool enable_accelerated_vpx_decode) 853 bool enable_accelerated_vpx_decode)
854 : client_(NULL), 854 : client_(NULL),
855 dev_manager_reset_token_(0), 855 dev_manager_reset_token_(0),
856 dx11_dev_manager_reset_token_(0), 856 dx11_dev_manager_reset_token_(0),
857 egl_config_(NULL), 857 egl_config_(NULL),
858 state_(kUninitialized), 858 state_(kUninitialized),
859 pictures_requested_(false), 859 pictures_requested_(false),
860 inputs_before_decode_(0), 860 inputs_before_decode_(0),
861 sent_drain_message_(false), 861 sent_drain_message_(false),
862 make_context_current_(make_context_current), 862 get_gl_context_cb_(get_gl_context_cb),
863 make_context_current_cb_(make_context_current_cb),
863 codec_(media::kUnknownVideoCodec), 864 codec_(media::kUnknownVideoCodec),
864 decoder_thread_("DXVAVideoDecoderThread"), 865 decoder_thread_("DXVAVideoDecoderThread"),
865 pending_flush_(false), 866 pending_flush_(false),
866 use_dx11_(false), 867 use_dx11_(false),
867 use_keyed_mutex_(false), 868 use_keyed_mutex_(false),
868 dx11_video_format_converter_media_type_needs_init_(true), 869 dx11_video_format_converter_media_type_needs_init_(true),
869 gl_context_(gl_context),
870 using_angle_device_(false), 870 using_angle_device_(false),
871 enable_accelerated_vpx_decode_(enable_accelerated_vpx_decode), 871 enable_accelerated_vpx_decode_(enable_accelerated_vpx_decode),
872 weak_this_factory_(this) { 872 weak_this_factory_(this) {
873 weak_ptr_ = weak_this_factory_.GetWeakPtr(); 873 weak_ptr_ = weak_this_factory_.GetWeakPtr();
874 memset(&input_stream_info_, 0, sizeof(input_stream_info_)); 874 memset(&input_stream_info_, 0, sizeof(input_stream_info_));
875 memset(&output_stream_info_, 0, sizeof(output_stream_info_)); 875 memset(&output_stream_info_, 0, sizeof(output_stream_info_));
876 } 876 }
877 877
878 DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() { 878 DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() {
879 client_ = NULL; 879 client_ = NULL;
880 } 880 }
881 881
882 bool DXVAVideoDecodeAccelerator::Initialize(const Config& config, 882 bool DXVAVideoDecodeAccelerator::Initialize(const Config& config,
883 Client* client) { 883 Client* client) {
884 if (get_gl_context_cb_.is_null() || make_context_current_cb_.is_null()) {
885 NOTREACHED() << "GL callbacks are required for this VDA";
886 return false;
887 }
888
884 if (config.is_encrypted) { 889 if (config.is_encrypted) {
885 NOTREACHED() << "Encrypted streams are not supported for this VDA"; 890 NOTREACHED() << "Encrypted streams are not supported for this VDA";
886 return false; 891 return false;
887 } 892 }
888 893
889 client_ = client; 894 client_ = client;
890 895
891 main_thread_task_runner_ = base::MessageLoop::current()->task_runner(); 896 main_thread_task_runner_ = base::MessageLoop::current()->task_runner();
892 897
893 bool profile_supported = false; 898 bool profile_supported = false;
(...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after
1241 "Failed to reuse picture buffer", 1246 "Failed to reuse picture buffer",
1242 PLATFORM_FAILURE, ); 1247 PLATFORM_FAILURE, );
1243 1248
1244 ProcessPendingSamples(); 1249 ProcessPendingSamples();
1245 if (pending_flush_) { 1250 if (pending_flush_) {
1246 decoder_thread_task_runner_->PostTask( 1251 decoder_thread_task_runner_->PostTask(
1247 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, 1252 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal,
1248 base::Unretained(this))); 1253 base::Unretained(this)));
1249 } 1254 }
1250 } else { 1255 } else {
1251 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(), 1256 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_cb_.Run(),
1252 "Failed to make context current", 1257 "Failed to make context current",
1253 PLATFORM_FAILURE, ); 1258 PLATFORM_FAILURE, );
1254 it->second->ResetReuseFence(); 1259 it->second->ResetReuseFence();
1255 1260
1256 WaitForOutputBuffer(picture_buffer_id, 0); 1261 WaitForOutputBuffer(picture_buffer_id, 0);
1257 } 1262 }
1258 } 1263 }
1259 1264
1260 void DXVAVideoDecodeAccelerator::WaitForOutputBuffer(int32_t picture_buffer_id, 1265 void DXVAVideoDecodeAccelerator::WaitForOutputBuffer(int32_t picture_buffer_id,
1261 int count) { 1266 int count) {
1262 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); 1267 DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
1263 OutputBuffers::iterator it = output_picture_buffers_.find(picture_buffer_id); 1268 OutputBuffers::iterator it = output_picture_buffers_.find(picture_buffer_id);
1264 if (it == output_picture_buffers_.end()) 1269 if (it == output_picture_buffers_.end())
1265 return; 1270 return;
1266 1271
1267 DXVAPictureBuffer* picture_buffer = it->second.get(); 1272 DXVAPictureBuffer* picture_buffer = it->second.get();
1268 1273
1269 DCHECK(!picture_buffer->available()); 1274 DCHECK(!picture_buffer->available());
1270 DCHECK(picture_buffer->waiting_to_reuse()); 1275 DCHECK(picture_buffer->waiting_to_reuse());
1271 1276
1272 gfx::GLFence* fence = picture_buffer->reuse_fence(); 1277 gfx::GLFence* fence = picture_buffer->reuse_fence();
1273 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(), 1278 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_cb_.Run(),
1274 "Failed to make context current", 1279 "Failed to make context current",
1275 PLATFORM_FAILURE, ); 1280 PLATFORM_FAILURE, );
1276 if (count <= kMaxIterationsForANGLEReuseFlush && !fence->HasCompleted()) { 1281 if (count <= kMaxIterationsForANGLEReuseFlush && !fence->HasCompleted()) {
1277 main_thread_task_runner_->PostDelayedTask( 1282 main_thread_task_runner_->PostDelayedTask(
1278 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::WaitForOutputBuffer, 1283 FROM_HERE, base::Bind(&DXVAVideoDecodeAccelerator::WaitForOutputBuffer,
1279 weak_this_factory_.GetWeakPtr(), 1284 weak_this_factory_.GetWeakPtr(),
1280 picture_buffer_id, count + 1), 1285 picture_buffer_id, count + 1),
1281 base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs)); 1286 base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs));
1282 return; 1287 return;
1283 } 1288 }
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
1357 StartDecoderThread(); 1362 StartDecoderThread();
1358 SetState(kNormal); 1363 SetState(kNormal);
1359 } 1364 }
1360 1365
1361 void DXVAVideoDecodeAccelerator::Destroy() { 1366 void DXVAVideoDecodeAccelerator::Destroy() {
1362 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); 1367 DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
1363 Invalidate(); 1368 Invalidate();
1364 delete this; 1369 delete this;
1365 } 1370 }
1366 1371
1367 bool DXVAVideoDecodeAccelerator::CanDecodeOnIOThread() { 1372 bool DXVAVideoDecodeAccelerator::TryToSetupDecodeOnSeparateThread(
1373 const base::WeakPtr<Client>& decode_client,
1374 const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) {
1368 return false; 1375 return false;
1369 } 1376 }
1370 1377
1371 GLenum DXVAVideoDecodeAccelerator::GetSurfaceInternalFormat() const { 1378 GLenum DXVAVideoDecodeAccelerator::GetSurfaceInternalFormat() const {
1372 return GL_BGRA_EXT; 1379 return GL_BGRA_EXT;
1373 } 1380 }
1374 1381
1375 // static 1382 // static
1376 media::VideoDecodeAccelerator::SupportedProfiles 1383 media::VideoDecodeAccelerator::SupportedProfiles
1377 DXVAVideoDecodeAccelerator::GetSupportedProfiles() { 1384 DXVAVideoDecodeAccelerator::GetSupportedProfiles() {
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after
1690 RETURN_ON_HR_FAILURE(hr, "Failed to enable DXVA H/W decoding", false); 1697 RETURN_ON_HR_FAILURE(hr, "Failed to enable DXVA H/W decoding", false);
1691 } 1698 }
1692 1699
1693 hr = attributes->SetUINT32(CODECAPI_AVLowLatencyMode, TRUE); 1700 hr = attributes->SetUINT32(CODECAPI_AVLowLatencyMode, TRUE);
1694 if (SUCCEEDED(hr)) { 1701 if (SUCCEEDED(hr)) {
1695 DVLOG(1) << "Successfully set Low latency mode on decoder."; 1702 DVLOG(1) << "Successfully set Low latency mode on decoder.";
1696 } else { 1703 } else {
1697 DVLOG(1) << "Failed to set Low latency mode on decoder. Error: " << hr; 1704 DVLOG(1) << "Failed to set Low latency mode on decoder. Error: " << hr;
1698 } 1705 }
1699 1706
1707 auto gl_context = get_gl_context_cb_.Run();
1708 RETURN_ON_FAILURE(gl_context, "Couldn't get GL context", false);
1709
1700 // The decoder should use DX11 iff 1710 // The decoder should use DX11 iff
1701 // 1. The underlying H/W decoder supports it. 1711 // 1. The underlying H/W decoder supports it.
1702 // 2. We have a pointer to the MFCreateDXGIDeviceManager function needed for 1712 // 2. We have a pointer to the MFCreateDXGIDeviceManager function needed for
1703 // this. This should always be true for Windows 8+. 1713 // this. This should always be true for Windows 8+.
1704 // 3. ANGLE is using DX11. 1714 // 3. ANGLE is using DX11.
1705 DCHECK(gl_context_);
1706 if (create_dxgi_device_manager_ && 1715 if (create_dxgi_device_manager_ &&
1707 (gl_context_->GetGLRenderer().find("Direct3D11") != 1716 (gl_context->GetGLRenderer().find("Direct3D11") != std::string::npos)) {
1708 std::string::npos)) {
1709 UINT32 dx11_aware = 0; 1717 UINT32 dx11_aware = 0;
1710 attributes->GetUINT32(MF_SA_D3D11_AWARE, &dx11_aware); 1718 attributes->GetUINT32(MF_SA_D3D11_AWARE, &dx11_aware);
1711 use_dx11_ = !!dx11_aware; 1719 use_dx11_ = !!dx11_aware;
1712 } 1720 }
1713 1721
1714 use_keyed_mutex_ = 1722 use_keyed_mutex_ =
1715 use_dx11_ && gfx::GLSurfaceEGL::HasEGLExtension("EGL_ANGLE_keyed_mutex"); 1723 use_dx11_ && gfx::GLSurfaceEGL::HasEGLExtension("EGL_ANGLE_keyed_mutex");
1716 1724
1717 return true; 1725 return true;
1718 } 1726 }
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
1900 pictures_requested_ = true; 1908 pictures_requested_ = true;
1901 return true; 1909 return true;
1902 } 1910 }
1903 1911
1904 void DXVAVideoDecodeAccelerator::ProcessPendingSamples() { 1912 void DXVAVideoDecodeAccelerator::ProcessPendingSamples() {
1905 DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); 1913 DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
1906 1914
1907 if (!output_picture_buffers_.size()) 1915 if (!output_picture_buffers_.size())
1908 return; 1916 return;
1909 1917
1910 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(), 1918 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_cb_.Run(),
1911 "Failed to make context current", PLATFORM_FAILURE,); 1919 "Failed to make context current",
1920 PLATFORM_FAILURE, );
1912 1921
1913 OutputBuffers::iterator index; 1922 OutputBuffers::iterator index;
1914 1923
1915 for (index = output_picture_buffers_.begin(); 1924 for (index = output_picture_buffers_.begin();
1916 index != output_picture_buffers_.end() && 1925 index != output_picture_buffers_.end() &&
1917 OutputSamplesPresent(); 1926 OutputSamplesPresent();
1918 ++index) { 1927 ++index) {
1919 if (index->second->available()) { 1928 if (index->second->available()) {
1920 PendingSampleInfo* pending_sample = NULL; 1929 PendingSampleInfo* pending_sample = NULL;
1921 { 1930 {
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
1997 if (GetState() != kUninitialized) { 2006 if (GetState() != kUninitialized) {
1998 Invalidate(); 2007 Invalidate();
1999 } 2008 }
2000 } 2009 }
2001 2010
2002 void DXVAVideoDecodeAccelerator::Invalidate() { 2011 void DXVAVideoDecodeAccelerator::Invalidate() {
2003 if (GetState() == kUninitialized) 2012 if (GetState() == kUninitialized)
2004 return; 2013 return;
2005 2014
2006 // Best effort to make the GL context current. 2015 // Best effort to make the GL context current.
2007 make_context_current_.Run(); 2016 make_context_current_cb_.Run();
2008 2017
2009 decoder_thread_.Stop(); 2018 decoder_thread_.Stop();
2010 weak_this_factory_.InvalidateWeakPtrs(); 2019 weak_this_factory_.InvalidateWeakPtrs();
2011 output_picture_buffers_.clear(); 2020 output_picture_buffers_.clear();
2012 stale_output_picture_buffers_.clear(); 2021 stale_output_picture_buffers_.clear();
2013 pending_output_samples_.clear(); 2022 pending_output_samples_.clear();
2014 // We want to continue processing pending input after detecting a config 2023 // We want to continue processing pending input after detecting a config
2015 // change. 2024 // change.
2016 if (GetState() != kConfigChange) 2025 if (GetState() != kConfigChange)
2017 pending_input_buffers_.clear(); 2026 pending_input_buffers_.clear();
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after
2290 2299
2291 main_thread_task_runner_->PostTask( 2300 main_thread_task_runner_->PostTask(
2292 FROM_HERE, 2301 FROM_HERE,
2293 base::Bind(&DXVAVideoDecodeAccelerator::RequestPictureBuffers, 2302 base::Bind(&DXVAVideoDecodeAccelerator::RequestPictureBuffers,
2294 weak_this_factory_.GetWeakPtr(), 2303 weak_this_factory_.GetWeakPtr(),
2295 width, 2304 width,
2296 height)); 2305 height));
2297 } 2306 }
2298 2307
2299 void DXVAVideoDecodeAccelerator::DismissStaleBuffers(bool force) { 2308 void DXVAVideoDecodeAccelerator::DismissStaleBuffers(bool force) {
2300 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(), 2309 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_cb_.Run(),
2301 "Failed to make context current", PLATFORM_FAILURE, ); 2310 "Failed to make context current",
2311 PLATFORM_FAILURE, );
2302 2312
2303 OutputBuffers::iterator index; 2313 OutputBuffers::iterator index;
2304 2314
2305 for (index = output_picture_buffers_.begin(); 2315 for (index = output_picture_buffers_.begin();
2306 index != output_picture_buffers_.end(); 2316 index != output_picture_buffers_.end();
2307 ++index) { 2317 ++index) {
2308 if (force || index->second->available()) { 2318 if (force || index->second->available()) {
2309 DVLOG(1) << "Dismissing picture id: " << index->second->id(); 2319 DVLOG(1) << "Dismissing picture id: " << index->second->id();
2310 client_->DismissPictureBuffer(index->second->id()); 2320 client_->DismissPictureBuffer(index->second->id());
2311 } else { 2321 } else {
2312 // Move to |stale_output_picture_buffers_| for deferred deletion. 2322 // Move to |stale_output_picture_buffers_| for deferred deletion.
2313 stale_output_picture_buffers_.insert( 2323 stale_output_picture_buffers_.insert(
2314 std::make_pair(index->first, index->second)); 2324 std::make_pair(index->first, index->second));
2315 } 2325 }
2316 } 2326 }
2317 2327
2318 output_picture_buffers_.clear(); 2328 output_picture_buffers_.clear();
2319 } 2329 }
2320 2330
2321 void DXVAVideoDecodeAccelerator::DeferredDismissStaleBuffer( 2331 void DXVAVideoDecodeAccelerator::DeferredDismissStaleBuffer(
2322 int32_t picture_buffer_id) { 2332 int32_t picture_buffer_id) {
2323 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(), 2333 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_cb_.Run(),
2324 "Failed to make context current", PLATFORM_FAILURE, ); 2334 "Failed to make context current",
2335 PLATFORM_FAILURE, );
2325 2336
2326 OutputBuffers::iterator it = stale_output_picture_buffers_.find( 2337 OutputBuffers::iterator it = stale_output_picture_buffers_.find(
2327 picture_buffer_id); 2338 picture_buffer_id);
2328 DCHECK(it != stale_output_picture_buffers_.end()); 2339 DCHECK(it != stale_output_picture_buffers_.end());
2329 DVLOG(1) << "Dismissing picture id: " << it->second->id(); 2340 DVLOG(1) << "Dismissing picture id: " << it->second->id();
2330 client_->DismissPictureBuffer(it->second->id()); 2341 client_->DismissPictureBuffer(it->second->id());
2331 stale_output_picture_buffers_.erase(it); 2342 stale_output_picture_buffers_.erase(it);
2332 } 2343 }
2333 2344
2334 DXVAVideoDecodeAccelerator::State 2345 DXVAVideoDecodeAccelerator::State
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
2430 OutputBuffers::iterator it = output_picture_buffers_.find(picture_buffer_id); 2441 OutputBuffers::iterator it = output_picture_buffers_.find(picture_buffer_id);
2431 if (it == output_picture_buffers_.end()) 2442 if (it == output_picture_buffers_.end())
2432 return; 2443 return;
2433 2444
2434 // If the picture buffer is marked as available it probably means that there 2445 // If the picture buffer is marked as available it probably means that there
2435 // was a Reset operation which dropped the output frame. 2446 // was a Reset operation which dropped the output frame.
2436 DXVAPictureBuffer* picture_buffer = it->second.get(); 2447 DXVAPictureBuffer* picture_buffer = it->second.get();
2437 if (picture_buffer->available()) 2448 if (picture_buffer->available())
2438 return; 2449 return;
2439 2450
2440 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(), 2451 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_cb_.Run(),
2441 "Failed to make context current", PLATFORM_FAILURE,); 2452 "Failed to make context current",
2453 PLATFORM_FAILURE, );
2442 2454
2443 DCHECK(!output_picture_buffers_.empty()); 2455 DCHECK(!output_picture_buffers_.empty());
2444 2456
2445 bool result = picture_buffer->CopySurfaceComplete(src_surface, dest_surface); 2457 bool result = picture_buffer->CopySurfaceComplete(src_surface, dest_surface);
2446 RETURN_AND_NOTIFY_ON_FAILURE(result, "Failed to complete copying surface", 2458 RETURN_AND_NOTIFY_ON_FAILURE(result, "Failed to complete copying surface",
2447 PLATFORM_FAILURE, ); 2459 PLATFORM_FAILURE, );
2448 2460
2449 NotifyPictureReady(picture_buffer->id(), input_buffer_id); 2461 NotifyPictureReady(picture_buffer->id(), input_buffer_id);
2450 2462
2451 { 2463 {
(...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after
2846 DismissStaleBuffers(true); 2858 DismissStaleBuffers(true);
2847 Invalidate(); 2859 Invalidate();
2848 Initialize(config_, client_); 2860 Initialize(config_, client_);
2849 decoder_thread_task_runner_->PostTask( 2861 decoder_thread_task_runner_->PostTask(
2850 FROM_HERE, 2862 FROM_HERE,
2851 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, 2863 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers,
2852 base::Unretained(this))); 2864 base::Unretained(this)));
2853 } 2865 }
2854 2866
2855 } // namespace content 2867 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698