| OLD | NEW |
| 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.h" | 5 #include "content/common/gpu/media/dxva_video_decode_accelerator.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 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 64 error_code, ret); | 64 error_code, ret); |
| 65 | 65 |
| 66 // Maximum number of iterations we allow before aborting the attempt to flush | 66 // Maximum number of iterations we allow before aborting the attempt to flush |
| 67 // the batched queries to the driver and allow torn/corrupt frames to be | 67 // the batched queries to the driver and allow torn/corrupt frames to be |
| 68 // rendered. | 68 // rendered. |
| 69 enum { kMaxIterationsForD3DFlush = 10 }; | 69 enum { kMaxIterationsForD3DFlush = 10 }; |
| 70 | 70 |
| 71 static IMFSample* CreateEmptySample() { | 71 static IMFSample* CreateEmptySample() { |
| 72 base::win::ScopedComPtr<IMFSample> sample; | 72 base::win::ScopedComPtr<IMFSample> sample; |
| 73 HRESULT hr = MFCreateSample(sample.Receive()); | 73 HRESULT hr = MFCreateSample(sample.Receive()); |
| 74 RETURN_ON_HR_FAILURE(hr, "MFCreateSample failed", NULL); | 74 RETURN_ON_HR_FAILURE(hr, "MFCreateSample failed", nullptr); |
| 75 return sample.Detach(); | 75 return sample.Detach(); |
| 76 } | 76 } |
| 77 | 77 |
| 78 // Creates a Media Foundation sample with one buffer of length |buffer_length| | 78 // Creates a Media Foundation sample with one buffer of length |buffer_length| |
| 79 // on a |align|-byte boundary. Alignment must be a perfect power of 2 or 0. | 79 // on a |align|-byte boundary. Alignment must be a perfect power of 2 or 0. |
| 80 static IMFSample* CreateEmptySampleWithBuffer(int buffer_length, int align) { | 80 static IMFSample* CreateEmptySampleWithBuffer(int buffer_length, int align) { |
| 81 CHECK_GT(buffer_length, 0); | 81 CHECK_GT(buffer_length, 0); |
| 82 | 82 |
| 83 base::win::ScopedComPtr<IMFSample> sample; | 83 base::win::ScopedComPtr<IMFSample> sample; |
| 84 sample.Attach(CreateEmptySample()); | 84 sample.Attach(CreateEmptySample()); |
| 85 | 85 |
| 86 base::win::ScopedComPtr<IMFMediaBuffer> buffer; | 86 base::win::ScopedComPtr<IMFMediaBuffer> buffer; |
| 87 HRESULT hr = E_FAIL; | 87 HRESULT hr = E_FAIL; |
| 88 if (align == 0) { | 88 if (align == 0) { |
| 89 // Note that MFCreateMemoryBuffer is same as MFCreateAlignedMemoryBuffer | 89 // Note that MFCreateMemoryBuffer is same as MFCreateAlignedMemoryBuffer |
| 90 // with the align argument being 0. | 90 // with the align argument being 0. |
| 91 hr = MFCreateMemoryBuffer(buffer_length, buffer.Receive()); | 91 hr = MFCreateMemoryBuffer(buffer_length, buffer.Receive()); |
| 92 } else { | 92 } else { |
| 93 hr = MFCreateAlignedMemoryBuffer(buffer_length, | 93 hr = MFCreateAlignedMemoryBuffer(buffer_length, |
| 94 align - 1, | 94 align - 1, |
| 95 buffer.Receive()); | 95 buffer.Receive()); |
| 96 } | 96 } |
| 97 RETURN_ON_HR_FAILURE(hr, "Failed to create memory buffer for sample", NULL); | 97 RETURN_ON_HR_FAILURE(hr, "Failed to create memory buffer for sample", |
| 98 nullptr); |
| 98 | 99 |
| 99 hr = sample->AddBuffer(buffer); | 100 hr = sample->AddBuffer(buffer); |
| 100 RETURN_ON_HR_FAILURE(hr, "Failed to add buffer to sample", NULL); | 101 RETURN_ON_HR_FAILURE(hr, "Failed to add buffer to sample", nullptr); |
| 101 | 102 |
| 102 return sample.Detach(); | 103 return sample.Detach(); |
| 103 } | 104 } |
| 104 | 105 |
| 105 // Creates a Media Foundation sample with one buffer containing a copy of the | 106 // Creates a Media Foundation sample with one buffer containing a copy of the |
| 106 // given Annex B stream data. | 107 // given Annex B stream data. |
| 107 // If duration and sample time are not known, provide 0. | 108 // If duration and sample time are not known, provide 0. |
| 108 // |min_size| specifies the minimum size of the buffer (might be required by | 109 // |min_size| specifies the minimum size of the buffer (might be required by |
| 109 // the decoder for input). If no alignment is required, provide 0. | 110 // the decoder for input). If no alignment is required, provide 0. |
| 110 static IMFSample* CreateInputSample(const uint8* stream, int size, | 111 static IMFSample* CreateInputSample(const uint8* stream, int size, |
| 111 int min_size, int alignment) { | 112 int min_size, int alignment) { |
| 112 CHECK(stream); | 113 CHECK(stream); |
| 113 CHECK_GT(size, 0); | 114 CHECK_GT(size, 0); |
| 114 base::win::ScopedComPtr<IMFSample> sample; | 115 base::win::ScopedComPtr<IMFSample> sample; |
| 115 sample.Attach(CreateEmptySampleWithBuffer(std::max(min_size, size), | 116 sample.Attach(CreateEmptySampleWithBuffer(std::max(min_size, size), |
| 116 alignment)); | 117 alignment)); |
| 117 RETURN_ON_FAILURE(sample, "Failed to create empty sample", NULL); | 118 RETURN_ON_FAILURE(sample, "Failed to create empty sample", nullptr); |
| 118 | 119 |
| 119 base::win::ScopedComPtr<IMFMediaBuffer> buffer; | 120 base::win::ScopedComPtr<IMFMediaBuffer> buffer; |
| 120 HRESULT hr = sample->GetBufferByIndex(0, buffer.Receive()); | 121 HRESULT hr = sample->GetBufferByIndex(0, buffer.Receive()); |
| 121 RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from sample", NULL); | 122 RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from sample", nullptr); |
| 122 | 123 |
| 123 DWORD max_length = 0; | 124 DWORD max_length = 0; |
| 124 DWORD current_length = 0; | 125 DWORD current_length = 0; |
| 125 uint8* destination = NULL; | 126 uint8* destination = nullptr; |
| 126 hr = buffer->Lock(&destination, &max_length, ¤t_length); | 127 hr = buffer->Lock(&destination, &max_length, ¤t_length); |
| 127 RETURN_ON_HR_FAILURE(hr, "Failed to lock buffer", NULL); | 128 RETURN_ON_HR_FAILURE(hr, "Failed to lock buffer", nullptr); |
| 128 | 129 |
| 129 CHECK_EQ(current_length, 0u); | 130 CHECK_EQ(current_length, 0u); |
| 130 CHECK_GE(static_cast<int>(max_length), size); | 131 CHECK_GE(static_cast<int>(max_length), size); |
| 131 memcpy(destination, stream, size); | 132 memcpy(destination, stream, size); |
| 132 | 133 |
| 133 hr = buffer->Unlock(); | 134 hr = buffer->Unlock(); |
| 134 RETURN_ON_HR_FAILURE(hr, "Failed to unlock buffer", NULL); | 135 RETURN_ON_HR_FAILURE(hr, "Failed to unlock buffer", nullptr); |
| 135 | 136 |
| 136 hr = buffer->SetCurrentLength(size); | 137 hr = buffer->SetCurrentLength(size); |
| 137 RETURN_ON_HR_FAILURE(hr, "Failed to set buffer length", NULL); | 138 RETURN_ON_HR_FAILURE(hr, "Failed to set buffer length", nullptr); |
| 138 | 139 |
| 139 return sample.Detach(); | 140 return sample.Detach(); |
| 140 } | 141 } |
| 141 | 142 |
| 142 static IMFSample* CreateSampleFromInputBuffer( | 143 static IMFSample* CreateSampleFromInputBuffer( |
| 143 const media::BitstreamBuffer& bitstream_buffer, | 144 const media::BitstreamBuffer& bitstream_buffer, |
| 144 DWORD stream_size, | 145 DWORD stream_size, |
| 145 DWORD alignment) { | 146 DWORD alignment) { |
| 146 base::SharedMemory shm(bitstream_buffer.handle(), true); | 147 base::SharedMemory shm(bitstream_buffer.handle(), true); |
| 147 RETURN_ON_FAILURE(shm.Map(bitstream_buffer.size()), | 148 RETURN_ON_FAILURE(shm.Map(bitstream_buffer.size()), |
| 148 "Failed in base::SharedMemory::Map", NULL); | 149 "Failed in base::SharedMemory::Map", nullptr); |
| 149 | 150 |
| 150 return CreateInputSample(reinterpret_cast<const uint8*>(shm.memory()), | 151 return CreateInputSample(reinterpret_cast<const uint8*>(shm.memory()), |
| 151 bitstream_buffer.size(), | 152 bitstream_buffer.size(), |
| 152 stream_size, | 153 stream_size, |
| 153 alignment); | 154 alignment); |
| 154 } | 155 } |
| 155 | 156 |
| 156 // Maintains information about a DXVA picture buffer, i.e. whether it is | 157 // Maintains information about a DXVA picture buffer, i.e. whether it is |
| 157 // available for rendering, the texture information, etc. | 158 // available for rendering, the texture information, etc. |
| 158 struct DXVAVideoDecodeAccelerator::DXVAPictureBuffer { | 159 struct DXVAVideoDecodeAccelerator::DXVAPictureBuffer { |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 222 EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, | 223 EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, |
| 223 EGL_NONE | 224 EGL_NONE |
| 224 }; | 225 }; |
| 225 | 226 |
| 226 picture_buffer->decoding_surface_ = eglCreatePbufferSurface( | 227 picture_buffer->decoding_surface_ = eglCreatePbufferSurface( |
| 227 egl_display, | 228 egl_display, |
| 228 egl_config, | 229 egl_config, |
| 229 attrib_list); | 230 attrib_list); |
| 230 RETURN_ON_FAILURE(picture_buffer->decoding_surface_, | 231 RETURN_ON_FAILURE(picture_buffer->decoding_surface_, |
| 231 "Failed to create surface", | 232 "Failed to create surface", |
| 232 linked_ptr<DXVAPictureBuffer>(NULL)); | 233 linked_ptr<DXVAPictureBuffer>(nullptr)); |
| 233 | 234 |
| 234 HANDLE share_handle = NULL; | 235 HANDLE share_handle = nullptr; |
| 235 EGLBoolean ret = eglQuerySurfacePointerANGLE( | 236 EGLBoolean ret = eglQuerySurfacePointerANGLE( |
| 236 egl_display, | 237 egl_display, |
| 237 picture_buffer->decoding_surface_, | 238 picture_buffer->decoding_surface_, |
| 238 EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, | 239 EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, |
| 239 &share_handle); | 240 &share_handle); |
| 240 | 241 |
| 241 RETURN_ON_FAILURE(share_handle && ret == EGL_TRUE, | 242 RETURN_ON_FAILURE(share_handle && ret == EGL_TRUE, |
| 242 "Failed to query ANGLE surface pointer", | 243 "Failed to query ANGLE surface pointer", |
| 243 linked_ptr<DXVAPictureBuffer>(NULL)); | 244 linked_ptr<DXVAPictureBuffer>(nullptr)); |
| 244 | 245 |
| 245 HRESULT hr = decoder.device_->CreateTexture( | 246 HRESULT hr = decoder.device_->CreateTexture( |
| 246 buffer.size().width(), | 247 buffer.size().width(), |
| 247 buffer.size().height(), | 248 buffer.size().height(), |
| 248 1, | 249 1, |
| 249 D3DUSAGE_RENDERTARGET, | 250 D3DUSAGE_RENDERTARGET, |
| 250 use_rgb ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8, | 251 use_rgb ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8, |
| 251 D3DPOOL_DEFAULT, | 252 D3DPOOL_DEFAULT, |
| 252 picture_buffer->decoding_texture_.Receive(), | 253 picture_buffer->decoding_texture_.Receive(), |
| 253 &share_handle); | 254 &share_handle); |
| 254 | 255 |
| 255 RETURN_ON_HR_FAILURE(hr, "Failed to create texture", | 256 RETURN_ON_HR_FAILURE(hr, "Failed to create texture", |
| 256 linked_ptr<DXVAPictureBuffer>(NULL)); | 257 linked_ptr<DXVAPictureBuffer>(nullptr)); |
| 257 picture_buffer->use_rgb_ = !!use_rgb; | 258 picture_buffer->use_rgb_ = !!use_rgb; |
| 258 return picture_buffer; | 259 return picture_buffer; |
| 259 } | 260 } |
| 260 | 261 |
| 261 DXVAVideoDecodeAccelerator::DXVAPictureBuffer::DXVAPictureBuffer( | 262 DXVAVideoDecodeAccelerator::DXVAPictureBuffer::DXVAPictureBuffer( |
| 262 const media::PictureBuffer& buffer) | 263 const media::PictureBuffer& buffer) |
| 263 : available_(true), | 264 : available_(true), |
| 264 picture_buffer_(buffer), | 265 picture_buffer_(buffer), |
| 265 decoding_surface_(NULL), | 266 decoding_surface_(nullptr), |
| 266 use_rgb_(true) { | 267 use_rgb_(true) { |
| 267 } | 268 } |
| 268 | 269 |
| 269 DXVAVideoDecodeAccelerator::DXVAPictureBuffer::~DXVAPictureBuffer() { | 270 DXVAVideoDecodeAccelerator::DXVAPictureBuffer::~DXVAPictureBuffer() { |
| 270 if (decoding_surface_) { | 271 if (decoding_surface_) { |
| 271 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); | 272 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); |
| 272 | 273 |
| 273 eglReleaseTexImage( | 274 eglReleaseTexImage( |
| 274 egl_display, | 275 egl_display, |
| 275 decoding_surface_, | 276 decoding_surface_, |
| 276 EGL_BACK_BUFFER); | 277 EGL_BACK_BUFFER); |
| 277 | 278 |
| 278 eglDestroySurface( | 279 eglDestroySurface( |
| 279 egl_display, | 280 egl_display, |
| 280 decoding_surface_); | 281 decoding_surface_); |
| 281 decoding_surface_ = NULL; | 282 decoding_surface_ = nullptr; |
| 282 } | 283 } |
| 283 } | 284 } |
| 284 | 285 |
| 285 void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::ReusePictureBuffer() { | 286 void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::ReusePictureBuffer() { |
| 286 DCHECK(decoding_surface_); | 287 DCHECK(decoding_surface_); |
| 287 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); | 288 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); |
| 288 eglReleaseTexImage( | 289 eglReleaseTexImage( |
| 289 egl_display, | 290 egl_display, |
| 290 decoding_surface_, | 291 decoding_surface_, |
| 291 EGL_BACK_BUFFER); | 292 EGL_BACK_BUFFER); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 323 | 324 |
| 324 glBindTexture(GL_TEXTURE_2D, picture_buffer_.texture_id()); | 325 glBindTexture(GL_TEXTURE_2D, picture_buffer_.texture_id()); |
| 325 | 326 |
| 326 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | 327 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| 327 | 328 |
| 328 base::win::ScopedComPtr<IDirect3DSurface9> d3d_surface; | 329 base::win::ScopedComPtr<IDirect3DSurface9> d3d_surface; |
| 329 hr = decoding_texture_->GetSurfaceLevel(0, d3d_surface.Receive()); | 330 hr = decoding_texture_->GetSurfaceLevel(0, d3d_surface.Receive()); |
| 330 RETURN_ON_HR_FAILURE(hr, "Failed to get surface from texture", false); | 331 RETURN_ON_HR_FAILURE(hr, "Failed to get surface from texture", false); |
| 331 | 332 |
| 332 hr = decoder.device_->StretchRect( | 333 hr = decoder.device_->StretchRect( |
| 333 dest_surface, NULL, d3d_surface, NULL, D3DTEXF_NONE); | 334 dest_surface, nullptr, d3d_surface, nullptr, D3DTEXF_NONE); |
| 334 RETURN_ON_HR_FAILURE(hr, "Colorspace conversion via StretchRect failed", | 335 RETURN_ON_HR_FAILURE(hr, "Colorspace conversion via StretchRect failed", |
| 335 false); | 336 false); |
| 336 | 337 |
| 337 // Ideally, this should be done immediately before the draw call that uses | 338 // Ideally, this should be done immediately before the draw call that uses |
| 338 // the texture. Flush it once here though. | 339 // the texture. Flush it once here though. |
| 339 hr = decoder.query_->Issue(D3DISSUE_END); | 340 hr = decoder.query_->Issue(D3DISSUE_END); |
| 340 RETURN_ON_HR_FAILURE(hr, "Failed to issue END", false); | 341 RETURN_ON_HR_FAILURE(hr, "Failed to issue END", false); |
| 341 | 342 |
| 342 // The DXVA decoder has its own device which it uses for decoding. ANGLE | 343 // The DXVA decoder has its own device which it uses for decoding. ANGLE |
| 343 // has its own device which we don't have access to. | 344 // has its own device which we don't have access to. |
| 344 // The above code attempts to copy the decoded picture into a surface | 345 // The above code attempts to copy the decoded picture into a surface |
| 345 // which is owned by ANGLE. As there are multiple devices involved in | 346 // which is owned by ANGLE. As there are multiple devices involved in |
| 346 // this, the StretchRect call above is not synchronous. | 347 // this, the StretchRect call above is not synchronous. |
| 347 // We attempt to flush the batched operations to ensure that the picture is | 348 // We attempt to flush the batched operations to ensure that the picture is |
| 348 // copied to the surface owned by ANGLE. | 349 // copied to the surface owned by ANGLE. |
| 349 // We need to do this in a loop and call flush multiple times. | 350 // We need to do this in a loop and call flush multiple times. |
| 350 // We have seen the GetData call for flushing the command buffer fail to | 351 // We have seen the GetData call for flushing the command buffer fail to |
| 351 // return success occassionally on multi core machines, leading to an | 352 // return success occassionally on multi core machines, leading to an |
| 352 // infinite loop. | 353 // infinite loop. |
| 353 // Workaround is to have an upper limit of 10 on the number of iterations to | 354 // Workaround is to have an upper limit of 10 on the number of iterations to |
| 354 // wait for the Flush to finish. | 355 // wait for the Flush to finish. |
| 355 int iterations = 0; | 356 int iterations = 0; |
| 356 while ((decoder.query_->GetData(NULL, 0, D3DGETDATA_FLUSH) == S_FALSE) && | 357 while ((decoder.query_->GetData(nullptr, 0, D3DGETDATA_FLUSH) == S_FALSE) && |
| 357 ++iterations < kMaxIterationsForD3DFlush) { | 358 ++iterations < kMaxIterationsForD3DFlush) { |
| 358 Sleep(1); // Poor-man's Yield(). | 359 Sleep(1); // Poor-man's Yield(). |
| 359 } | 360 } |
| 360 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); | 361 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); |
| 361 eglBindTexImage( | 362 eglBindTexImage( |
| 362 egl_display, | 363 egl_display, |
| 363 decoding_surface_, | 364 decoding_surface_, |
| 364 EGL_BACK_BUFFER); | 365 EGL_BACK_BUFFER); |
| 365 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | 366 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| 366 glBindTexture(GL_TEXTURE_2D, current_texture); | 367 glBindTexture(GL_TEXTURE_2D, current_texture); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 395 present_params.PresentationInterval = 0; | 396 present_params.PresentationInterval = 0; |
| 396 | 397 |
| 397 hr = d3d9_->CreateDeviceEx(D3DADAPTER_DEFAULT, | 398 hr = d3d9_->CreateDeviceEx(D3DADAPTER_DEFAULT, |
| 398 D3DDEVTYPE_HAL, | 399 D3DDEVTYPE_HAL, |
| 399 ::GetShellWindow(), | 400 ::GetShellWindow(), |
| 400 D3DCREATE_FPU_PRESERVE | | 401 D3DCREATE_FPU_PRESERVE | |
| 401 D3DCREATE_SOFTWARE_VERTEXPROCESSING | | 402 D3DCREATE_SOFTWARE_VERTEXPROCESSING | |
| 402 D3DCREATE_DISABLE_PSGP_THREADING | | 403 D3DCREATE_DISABLE_PSGP_THREADING | |
| 403 D3DCREATE_MULTITHREADED, | 404 D3DCREATE_MULTITHREADED, |
| 404 &present_params, | 405 &present_params, |
| 405 NULL, | 406 nullptr, |
| 406 device_.Receive()); | 407 device_.Receive()); |
| 407 RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device", false); | 408 RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device", false); |
| 408 | 409 |
| 409 hr = DXVA2CreateDirect3DDeviceManager9(&dev_manager_reset_token_, | 410 hr = DXVA2CreateDirect3DDeviceManager9(&dev_manager_reset_token_, |
| 410 device_manager_.Receive()); | 411 device_manager_.Receive()); |
| 411 RETURN_ON_HR_FAILURE(hr, "DXVA2CreateDirect3DDeviceManager9 failed", false); | 412 RETURN_ON_HR_FAILURE(hr, "DXVA2CreateDirect3DDeviceManager9 failed", false); |
| 412 | 413 |
| 413 hr = device_manager_->ResetDevice(device_, dev_manager_reset_token_); | 414 hr = device_manager_->ResetDevice(device_, dev_manager_reset_token_); |
| 414 RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); | 415 RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); |
| 415 | 416 |
| 416 hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive()); | 417 hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive()); |
| 417 RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device query", false); | 418 RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device query", false); |
| 418 // Ensure query_ API works (to avoid an infinite loop later in | 419 // Ensure query_ API works (to avoid an infinite loop later in |
| 419 // CopyOutputSampleDataToPictureBuffer). | 420 // CopyOutputSampleDataToPictureBuffer). |
| 420 hr = query_->Issue(D3DISSUE_END); | 421 hr = query_->Issue(D3DISSUE_END); |
| 421 RETURN_ON_HR_FAILURE(hr, "Failed to issue END test query", false); | 422 RETURN_ON_HR_FAILURE(hr, "Failed to issue END test query", false); |
| 422 return true; | 423 return true; |
| 423 } | 424 } |
| 424 | 425 |
| 425 DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator( | 426 DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator( |
| 426 const base::Callback<bool(void)>& make_context_current) | 427 const base::Callback<bool(void)>& make_context_current) |
| 427 : client_(NULL), | 428 : client_(nullptr), |
| 428 dev_manager_reset_token_(0), | 429 dev_manager_reset_token_(0), |
| 429 egl_config_(NULL), | 430 egl_config_(nullptr), |
| 430 state_(kUninitialized), | 431 state_(kUninitialized), |
| 431 pictures_requested_(false), | 432 pictures_requested_(false), |
| 432 inputs_before_decode_(0), | 433 inputs_before_decode_(0), |
| 433 make_context_current_(make_context_current), | 434 make_context_current_(make_context_current), |
| 434 weak_this_factory_(this) { | 435 weak_this_factory_(this) { |
| 435 memset(&input_stream_info_, 0, sizeof(input_stream_info_)); | 436 memset(&input_stream_info_, 0, sizeof(input_stream_info_)); |
| 436 memset(&output_stream_info_, 0, sizeof(output_stream_info_)); | 437 memset(&output_stream_info_, 0, sizeof(output_stream_info_)); |
| 437 } | 438 } |
| 438 | 439 |
| 439 DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() { | 440 DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() { |
| 440 client_ = NULL; | 441 client_ = nullptr; |
| 441 } | 442 } |
| 442 | 443 |
| 443 bool DXVAVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, | 444 bool DXVAVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, |
| 444 Client* client) { | 445 Client* client) { |
| 445 DCHECK(CalledOnValidThread()); | 446 DCHECK(CalledOnValidThread()); |
| 446 | 447 |
| 447 client_ = client; | 448 client_ = client; |
| 448 | 449 |
| 449 // Not all versions of Windows 7 and later include Media Foundation DLLs. | 450 // Not all versions of Windows 7 and later include Media Foundation DLLs. |
| 450 // Instead of crashing while delay loading the DLL when calling MFStartup() | 451 // Instead of crashing while delay loading the DLL when calling MFStartup() |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 672 GetProcAddress(decoder_dll, "DllGetClassObject")); | 673 GetProcAddress(decoder_dll, "DllGetClassObject")); |
| 673 RETURN_ON_FAILURE( | 674 RETURN_ON_FAILURE( |
| 674 get_class_object, "Failed to get DllGetClassObject pointer", false); | 675 get_class_object, "Failed to get DllGetClassObject pointer", false); |
| 675 | 676 |
| 676 base::win::ScopedComPtr<IClassFactory> factory; | 677 base::win::ScopedComPtr<IClassFactory> factory; |
| 677 HRESULT hr = get_class_object(__uuidof(CMSH264DecoderMFT), | 678 HRESULT hr = get_class_object(__uuidof(CMSH264DecoderMFT), |
| 678 __uuidof(IClassFactory), | 679 __uuidof(IClassFactory), |
| 679 reinterpret_cast<void**>(factory.Receive())); | 680 reinterpret_cast<void**>(factory.Receive())); |
| 680 RETURN_ON_HR_FAILURE(hr, "DllGetClassObject for decoder failed", false); | 681 RETURN_ON_HR_FAILURE(hr, "DllGetClassObject for decoder failed", false); |
| 681 | 682 |
| 682 hr = factory->CreateInstance(NULL, | 683 hr = factory->CreateInstance(nullptr, |
| 683 __uuidof(IMFTransform), | 684 __uuidof(IMFTransform), |
| 684 reinterpret_cast<void**>(decoder_.Receive())); | 685 reinterpret_cast<void**>(decoder_.Receive())); |
| 685 RETURN_ON_HR_FAILURE(hr, "Failed to create decoder instance", false); | 686 RETURN_ON_HR_FAILURE(hr, "Failed to create decoder instance", false); |
| 686 | 687 |
| 687 RETURN_ON_FAILURE(CheckDecoderDxvaSupport(), | 688 RETURN_ON_FAILURE(CheckDecoderDxvaSupport(), |
| 688 "Failed to check decoder DXVA support", false); | 689 "Failed to check decoder DXVA support", false); |
| 689 | 690 |
| 690 hr = decoder_->ProcessMessage( | 691 hr = decoder_->ProcessMessage( |
| 691 MFT_MESSAGE_SET_D3D_MANAGER, | 692 MFT_MESSAGE_SET_D3D_MANAGER, |
| 692 reinterpret_cast<ULONG_PTR>(device_manager_.get())); | 693 reinterpret_cast<ULONG_PTR>(device_manager_.get())); |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 828 "DoDecode: not in normal/flushing/stopped state", ILLEGAL_STATE,); | 829 "DoDecode: not in normal/flushing/stopped state", ILLEGAL_STATE,); |
| 829 | 830 |
| 830 MFT_OUTPUT_DATA_BUFFER output_data_buffer = {0}; | 831 MFT_OUTPUT_DATA_BUFFER output_data_buffer = {0}; |
| 831 DWORD status = 0; | 832 DWORD status = 0; |
| 832 | 833 |
| 833 HRESULT hr = decoder_->ProcessOutput(0, // No flags | 834 HRESULT hr = decoder_->ProcessOutput(0, // No flags |
| 834 1, // # of out streams to pull from | 835 1, // # of out streams to pull from |
| 835 &output_data_buffer, | 836 &output_data_buffer, |
| 836 &status); | 837 &status); |
| 837 IMFCollection* events = output_data_buffer.pEvents; | 838 IMFCollection* events = output_data_buffer.pEvents; |
| 838 if (events != NULL) { | 839 if (events != nullptr) { |
| 839 VLOG(1) << "Got events from ProcessOuput, but discarding"; | 840 VLOG(1) << "Got events from ProcessOuput, but discarding"; |
| 840 events->Release(); | 841 events->Release(); |
| 841 } | 842 } |
| 842 if (FAILED(hr)) { | 843 if (FAILED(hr)) { |
| 843 // A stream change needs further ProcessInput calls to get back decoder | 844 // A stream change needs further ProcessInput calls to get back decoder |
| 844 // output which is why we need to set the state to stopped. | 845 // output which is why we need to set the state to stopped. |
| 845 if (hr == MF_E_TRANSFORM_STREAM_CHANGE) { | 846 if (hr == MF_E_TRANSFORM_STREAM_CHANGE) { |
| 846 if (!SetDecoderOutputMediaType(MFVideoFormat_NV12)) { | 847 if (!SetDecoderOutputMediaType(MFVideoFormat_NV12)) { |
| 847 // Decoder didn't let us set NV12 output format. Not sure as to why | 848 // Decoder didn't let us set NV12 output format. Not sure as to why |
| 848 // this can happen. Give up in disgust. | 849 // this can happen. Give up in disgust. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 868 TRACE_COUNTER1("DXVA Decoding", "TotalPacketsBeforeDecode", | 869 TRACE_COUNTER1("DXVA Decoding", "TotalPacketsBeforeDecode", |
| 869 inputs_before_decode_); | 870 inputs_before_decode_); |
| 870 | 871 |
| 871 inputs_before_decode_ = 0; | 872 inputs_before_decode_ = 0; |
| 872 | 873 |
| 873 RETURN_AND_NOTIFY_ON_FAILURE(ProcessOutputSample(output_data_buffer.pSample), | 874 RETURN_AND_NOTIFY_ON_FAILURE(ProcessOutputSample(output_data_buffer.pSample), |
| 874 "Failed to process output sample.", PLATFORM_FAILURE,); | 875 "Failed to process output sample.", PLATFORM_FAILURE,); |
| 875 } | 876 } |
| 876 | 877 |
| 877 bool DXVAVideoDecodeAccelerator::ProcessOutputSample(IMFSample* sample) { | 878 bool DXVAVideoDecodeAccelerator::ProcessOutputSample(IMFSample* sample) { |
| 878 RETURN_ON_FAILURE(sample, "Decode succeeded with NULL output sample", false); | 879 RETURN_ON_FAILURE(sample, "Decode succeeded with nullptr output sample", |
| 880 false); |
| 879 | 881 |
| 880 base::win::ScopedComPtr<IMFMediaBuffer> output_buffer; | 882 base::win::ScopedComPtr<IMFMediaBuffer> output_buffer; |
| 881 HRESULT hr = sample->GetBufferByIndex(0, output_buffer.Receive()); | 883 HRESULT hr = sample->GetBufferByIndex(0, output_buffer.Receive()); |
| 882 RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from output sample", false); | 884 RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from output sample", false); |
| 883 | 885 |
| 884 base::win::ScopedComPtr<IDirect3DSurface9> surface; | 886 base::win::ScopedComPtr<IDirect3DSurface9> surface; |
| 885 hr = MFGetService(output_buffer, MR_BUFFER_SERVICE, | 887 hr = MFGetService(output_buffer, MR_BUFFER_SERVICE, |
| 886 IID_PPV_ARGS(surface.Receive())); | 888 IID_PPV_ARGS(surface.Receive())); |
| 887 RETURN_ON_HR_FAILURE(hr, "Failed to get D3D surface from output sample", | 889 RETURN_ON_HR_FAILURE(hr, "Failed to get D3D surface from output sample", |
| 888 false); | 890 false); |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 990 weak_this_factory_.GetWeakPtr())); | 992 weak_this_factory_.GetWeakPtr())); |
| 991 } | 993 } |
| 992 } | 994 } |
| 993 | 995 |
| 994 void DXVAVideoDecodeAccelerator::StopOnError( | 996 void DXVAVideoDecodeAccelerator::StopOnError( |
| 995 media::VideoDecodeAccelerator::Error error) { | 997 media::VideoDecodeAccelerator::Error error) { |
| 996 DCHECK(CalledOnValidThread()); | 998 DCHECK(CalledOnValidThread()); |
| 997 | 999 |
| 998 if (client_) | 1000 if (client_) |
| 999 client_->NotifyError(error); | 1001 client_->NotifyError(error); |
| 1000 client_ = NULL; | 1002 client_ = nullptr; |
| 1001 | 1003 |
| 1002 if (state_ != kUninitialized) { | 1004 if (state_ != kUninitialized) { |
| 1003 Invalidate(); | 1005 Invalidate(); |
| 1004 } | 1006 } |
| 1005 } | 1007 } |
| 1006 | 1008 |
| 1007 void DXVAVideoDecodeAccelerator::Invalidate() { | 1009 void DXVAVideoDecodeAccelerator::Invalidate() { |
| 1008 if (state_ == kUninitialized) | 1010 if (state_ == kUninitialized) |
| 1009 return; | 1011 return; |
| 1010 weak_this_factory_.InvalidateWeakPtrs(); | 1012 weak_this_factory_.InvalidateWeakPtrs(); |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1219 int32 picture_buffer_id) { | 1221 int32 picture_buffer_id) { |
| 1220 OutputBuffers::iterator it = stale_output_picture_buffers_.find( | 1222 OutputBuffers::iterator it = stale_output_picture_buffers_.find( |
| 1221 picture_buffer_id); | 1223 picture_buffer_id); |
| 1222 DCHECK(it != stale_output_picture_buffers_.end()); | 1224 DCHECK(it != stale_output_picture_buffers_.end()); |
| 1223 DVLOG(1) << "Dismissing picture id: " << it->second->id(); | 1225 DVLOG(1) << "Dismissing picture id: " << it->second->id(); |
| 1224 client_->DismissPictureBuffer(it->second->id()); | 1226 client_->DismissPictureBuffer(it->second->id()); |
| 1225 stale_output_picture_buffers_.erase(it); | 1227 stale_output_picture_buffers_.erase(it); |
| 1226 } | 1228 } |
| 1227 | 1229 |
| 1228 } // namespace content | 1230 } // namespace content |
| OLD | NEW |