15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/common/gpu/media/dxva_video_decode_accelerator.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_WIN) 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#error This file should only be built on Windows. 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // !defined(OS_WIN) 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <ks.h> 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <codecapi.h> 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <mfapi.h> 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <mferror.h> 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <wmcodecdsp.h> 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/callback.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/debug/trace_event.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_handle.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h" 247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/memory/shared_memory.h" 259ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/video/video_decode_accelerator.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gl_bindings.h" 287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "ui/gl/gl_surface_egl.h" 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gl/gl_switches.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We only request 5 picture buffers from the client which are used to hold the 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// decoded samples. These buffers are then reused when the client tells us that 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// it is done with the buffer. 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kNumPictureBuffers = 5; 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DXVAVideoDecodeAccelerator::pre_sandbox_init_done_ = false; 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uint32 DXVAVideoDecodeAccelerator::dev_manager_reset_token_ = 0; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IDirect3DDeviceManager9* DXVAVideoDecodeAccelerator::device_manager_ = NULL; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IDirect3DDevice9Ex* DXVAVideoDecodeAccelerator::device_ = NULL; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IDirect3DQuery9* DXVAVideoDecodeAccelerator::query_ = NULL; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IDirect3D9Ex* DXVAVideoDecodeAccelerator::d3d9_ = NULL; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define RETURN_ON_FAILURE(result, log, ret) \ 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { \ 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!(result)) { \ 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(ERROR) << log; \ 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ret; \ 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } \ 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (0) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define RETURN_ON_HR_FAILURE(result, log, ret) \ 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_FAILURE(SUCCEEDED(result), \ 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) log << ", HRESULT: 0x" << std::hex << result, \ 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ret); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define RETURN_AND_NOTIFY_ON_FAILURE(result, log, error_code, ret) \ 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { \ 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!(result)) { \ 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << log; \ 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StopOnError(error_code); \ 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ret; \ 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } \ 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (0) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define RETURN_AND_NOTIFY_ON_HR_FAILURE(result, log, error_code, ret) \ 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE(SUCCEEDED(result), \ 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) log << ", HRESULT: 0x" << std::hex << result, \ 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error_code, ret); 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Maximum number of iterations we allow before aborting the attempt to flush 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// the batched queries to the driver and allow torn/corrupt frames to be 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// rendered. 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)enum { kMaxIterationsForD3DFlush = 10 }; 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static IMFSample* CreateEmptySample() { 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IMFSample> sample; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = MFCreateSample(sample.Receive()); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "MFCreateSample failed", NULL); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sample.Detach(); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Creates a Media Foundation sample with one buffer of length |buffer_length| 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// on a |align|-byte boundary. Alignment must be a perfect power of 2 or 0. 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static IMFSample* CreateEmptySampleWithBuffer(int buffer_length, int align) { 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_GT(buffer_length, 0); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IMFSample> sample; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sample.Attach(CreateEmptySample()); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IMFMediaBuffer> buffer; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = E_FAIL; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (align == 0) { 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note that MFCreateMemoryBuffer is same as MFCreateAlignedMemoryBuffer 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // with the align argument being 0. 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = MFCreateMemoryBuffer(buffer_length, buffer.Receive()); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = MFCreateAlignedMemoryBuffer(buffer_length, 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) align - 1, 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer.Receive()); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to create memory buffer for sample", NULL); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = sample->AddBuffer(buffer); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to add buffer to sample", NULL); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sample.Detach(); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Creates a Media Foundation sample with one buffer containing a copy of the 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// given Annex B stream data. 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If duration and sample time are not known, provide 0. 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |min_size| specifies the minimum size of the buffer (might be required by 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the decoder for input). If no alignment is required, provide 0. 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static IMFSample* CreateInputSample(const uint8* stream, int size, 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int min_size, int alignment) { 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(stream); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_GT(size, 0); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IMFSample> sample; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sample.Attach(CreateEmptySampleWithBuffer(std::max(min_size, size), 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) alignment)); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_FAILURE(sample, "Failed to create empty sample", NULL); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IMFMediaBuffer> buffer; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = sample->GetBufferByIndex(0, buffer.Receive()); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from sample", NULL); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD max_length = 0; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD current_length = 0; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8* destination = NULL; 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = buffer->Lock(&destination, &max_length, ¤t_length); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to lock buffer", NULL); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(current_length, 0u); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_GE(static_cast<int>(max_length), size); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(destination, stream, size); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = buffer->Unlock(); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to unlock buffer", NULL); 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = buffer->SetCurrentLength(size); 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to set buffer length", NULL); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return sample.Detach(); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static IMFSample* CreateSampleFromInputBuffer( 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const media::BitstreamBuffer& bitstream_buffer, 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD stream_size, 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD alignment) { 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::SharedMemory shm(bitstream_buffer.handle(), true); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_FAILURE(shm.Map(bitstream_buffer.size()), 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Failed in base::SharedMemory::Map", NULL); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return CreateInputSample(reinterpret_cast<const uint8*>(shm.memory()), 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bitstream_buffer.size(), 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stream_size, 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) alignment); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maintains information about a DXVA picture buffer, i.e. whether it is 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// available for rendering, the texture information, etc. 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct DXVAVideoDecodeAccelerator::DXVAPictureBuffer { 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static linked_ptr<DXVAPictureBuffer> Create( 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const media::PictureBuffer& buffer, EGLConfig egl_config); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~DXVAPictureBuffer(); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void ReusePictureBuffer(); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Copies the output sample data to the picture buffer provided by the 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // client. 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The dest_surface parameter contains the decoded bits. 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool CopyOutputSampleDataToPictureBuffer(IDirect3DSurface9* dest_surface); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool available() const { 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return available_; 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void set_available(bool available) { 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) available_ = available; 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int id() const { 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return picture_buffer_.id(); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) explicit DXVAPictureBuffer(const media::PictureBuffer& buffer); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool available_; 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) media::PictureBuffer picture_buffer_; 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EGLSurface decoding_surface_; 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IDirect3DTexture9> decoding_texture_; 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(DXVAPictureBuffer); 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)linked_ptr<DXVAVideoDecodeAccelerator::DXVAPictureBuffer> 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DXVAVideoDecodeAccelerator::DXVAPictureBuffer::Create( 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const media::PictureBuffer& buffer, EGLConfig egl_config) { 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) linked_ptr<DXVAPictureBuffer> picture_buffer(new DXVAPictureBuffer(buffer)); 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); 2067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EGLint attrib_list[] = { 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EGL_WIDTH, buffer.size().width(), 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EGL_HEIGHT, buffer.size().height(), 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB, 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EGL_NONE 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) picture_buffer->decoding_surface_ = eglCreatePbufferSurface( 2167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch egl_display, 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) egl_config, 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) attrib_list); 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_FAILURE(picture_buffer->decoding_surface_, 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Failed to create surface", 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) linked_ptr<DXVAPictureBuffer>(NULL)); 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HANDLE share_handle = NULL; 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EGLBoolean ret = eglQuerySurfacePointerANGLE( 2257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch egl_display, 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) picture_buffer->decoding_surface_, 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &share_handle); 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_FAILURE(share_handle && ret == EGL_TRUE, 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Failed to query ANGLE surface pointer", 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) linked_ptr<DXVAPictureBuffer>(NULL)); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = DXVAVideoDecodeAccelerator::device_->CreateTexture( 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer.size().width(), 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer.size().height(), 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1, 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) D3DUSAGE_RENDERTARGET, 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) D3DFMT_X8R8G8B8, 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) D3DPOOL_DEFAULT, 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) picture_buffer->decoding_texture_.Receive(), 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &share_handle); 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to create texture", 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) linked_ptr<DXVAPictureBuffer>(NULL)); 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return picture_buffer; 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DXVAVideoDecodeAccelerator::DXVAPictureBuffer::DXVAPictureBuffer( 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const media::PictureBuffer& buffer) 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : available_(true), 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) picture_buffer_(buffer), 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) decoding_surface_(NULL) { 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DXVAVideoDecodeAccelerator::DXVAPictureBuffer::~DXVAPictureBuffer() { 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (decoding_surface_) { 2587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); 2597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) eglReleaseTexImage( 2617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch egl_display, 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) decoding_surface_, 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EGL_BACK_BUFFER); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) eglDestroySurface( 2667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch egl_display, 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) decoding_surface_); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) decoding_surface_ = NULL; 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DXVAVideoDecodeAccelerator::DXVAPictureBuffer::ReusePictureBuffer() { 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(decoding_surface_); 2747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) eglReleaseTexImage( 2767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch egl_display, 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) decoding_surface_, 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EGL_BACK_BUFFER); 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_available(true); 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DXVAVideoDecodeAccelerator::DXVAPictureBuffer:: 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CopyOutputSampleDataToPictureBuffer(IDirect3DSurface9* dest_surface) { 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(dest_surface); 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) D3DSURFACE_DESC surface_desc; 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = dest_surface->GetDesc(&surface_desc); 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) D3DSURFACE_DESC texture_desc; 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) decoding_texture_->GetLevelDesc(0, &texture_desc); 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(ananta) 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We need to support mid stream resize. 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (texture_desc.Width != surface_desc.Width || 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) texture_desc.Height != surface_desc.Height) { 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "Decode surface of different dimension than texture"; 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = d3d9_->CheckDeviceFormatConversion(D3DADAPTER_DEFAULT, 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) D3DDEVTYPE_HAL, 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) surface_desc.Format, 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) D3DFMT_X8R8G8B8); 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool device_supports_format_conversion = (hr == S_OK); 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RETURN_ON_FAILURE(device_supports_format_conversion, 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "Device does not support format converision", 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) false); 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This function currently executes in the context of IPC handlers in the 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // GPU process which ensures that there is always an OpenGL context. 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GLint current_texture = 0; 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture); 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) glBindTexture(GL_TEXTURE_2D, picture_buffer_.texture_id()); 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::win::ScopedComPtr<IDirect3DSurface9> d3d_surface; 3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = decoding_texture_->GetSurfaceLevel(0, d3d_surface.Receive()); 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to get surface from texture", false); 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = device_->StretchRect(dest_surface, 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NULL, 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) d3d_surface, 3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NULL, 3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) D3DTEXF_NONE); 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Colorspace conversion via StretchRect failed", 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) false); 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Ideally, this should be done immediately before the draw call that uses 3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the texture. Flush it once here though. 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = query_->Issue(D3DISSUE_END); 3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to issue END", false); 3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The DXVA decoder has its own device which it uses for decoding. ANGLE 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // has its own device which we don't have access to. 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The above code attempts to copy the decoded picture into a surface 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // which is owned by ANGLE. As there are multiple devices involved in 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // this, the StretchRect call above is not synchronous. 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We attempt to flush the batched operations to ensure that the picture is 3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // copied to the surface owned by ANGLE. 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We need to do this in a loop and call flush multiple times. 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We have seen the GetData call for flushing the command buffer fail to 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // return success occassionally on multi core machines, leading to an 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // infinite loop. 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Workaround is to have an upper limit of 10 on the number of iterations to 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // wait for the Flush to finish. 3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int iterations = 0; 3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) while ((query_->GetData(NULL, 0, D3DGETDATA_FLUSH) == S_FALSE) && 3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++iterations < kMaxIterationsForD3DFlush) { 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Sleep(1); // Poor-man's Yield(). 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) eglBindTexImage( 3567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch egl_display, 3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decoding_surface_, 3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EGL_BACK_BUFFER); 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) glBindTexture(GL_TEXTURE_2D, current_texture); 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DXVAVideoDecodeAccelerator::PendingSampleInfo::PendingSampleInfo( 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int32 buffer_id, IMFSample* sample) 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : input_buffer_id(buffer_id) { 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output_sample.Attach(sample); 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DXVAVideoDecodeAccelerator::PendingSampleInfo::~PendingSampleInfo() {} 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DXVAVideoDecodeAccelerator::PreSandboxInitialization() { 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Should be called only once during program startup. 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!pre_sandbox_init_done_); 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 377eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch static const wchar_t* kDecodingDlls[] = { 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) L"d3d9.dll", 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) L"dxva2.dll", 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) L"mf.dll", 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) L"mfplat.dll", 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) L"msmpeg2vdec.dll", 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (int i = 0; i < arraysize(kDecodingDlls); ++i) { 386eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!::LoadLibrary(kDecodingDlls[i])) { 387eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DLOG(ERROR) << "Failed to load decoder dll: " << kDecodingDlls[i] 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << ", Error: " << ::GetLastError(); 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_FAILURE(CreateD3DDevManager(), 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Failed to initialize D3D device and manager",); 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pre_sandbox_init_done_ = true; 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DXVAVideoDecodeAccelerator::CreateD3DDevManager() { 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, &d3d9_); 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Direct3DCreate9Ex failed", false); 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) D3DPRESENT_PARAMETERS present_params = {0}; 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) present_params.BackBufferWidth = 1; 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) present_params.BackBufferHeight = 1; 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) present_params.BackBufferFormat = D3DFMT_UNKNOWN; 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) present_params.BackBufferCount = 1; 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) present_params.SwapEffect = D3DSWAPEFFECT_DISCARD; 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) present_params.hDeviceWindow = ::GetShellWindow(); 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) present_params.Windowed = TRUE; 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) present_params.Flags = D3DPRESENTFLAG_VIDEO; 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) present_params.FullScreen_RefreshRateInHz = 0; 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) present_params.PresentationInterval = 0; 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = d3d9_->CreateDeviceEx(D3DADAPTER_DEFAULT, 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) D3DDEVTYPE_HAL, 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ::GetShellWindow(), 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) D3DCREATE_FPU_PRESERVE | 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) D3DCREATE_SOFTWARE_VERTEXPROCESSING | 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) D3DCREATE_DISABLE_PSGP_THREADING | 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) D3DCREATE_MULTITHREADED, 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &present_params, 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL, 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &device_); 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device", false); 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = DXVA2CreateDirect3DDeviceManager9(&dev_manager_reset_token_, 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &device_manager_); 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "DXVA2CreateDirect3DDeviceManager9 failed", false); 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = device_manager_->ResetDevice(device_, dev_manager_reset_token_); 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, &query_); 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device query", false); 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ensure query_ API works (to avoid an infinite loop later in 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // CopyOutputSampleDataToPictureBuffer). 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = query_->Issue(D3DISSUE_END); 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to issue END test query", false); 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator( 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) media::VideoDecodeAccelerator::Client* client, 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const base::Callback<bool(void)>& make_context_current) 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : client_(client), 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) egl_config_(NULL), 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_(kUninitialized), 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pictures_requested_(false), 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inputs_before_decode_(0), 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) make_context_current_(make_context_current) { 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(&input_stream_info_, 0, sizeof(input_stream_info_)); 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memset(&output_stream_info_, 0, sizeof(output_stream_info_)); 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() { 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_ = NULL; 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DXVAVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile) { 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(ananta) 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // H264PROFILE_HIGH video decoding is janky at times. Needs more 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // investigation. 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (profile != media::H264PROFILE_BASELINE && 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile != media::H264PROFILE_MAIN && 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) profile != media::H264PROFILE_HIGH) { 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE(false, 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Unsupported h264 profile", PLATFORM_FAILURE, false); 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE(pre_sandbox_init_done_, 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "PreSandbox initialization not completed", PLATFORM_FAILURE, false); 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE( 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::g_driver_egl.ext.b_EGL_ANGLE_surface_d3d_texture_2d_share_handle, 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "EGL_ANGLE_surface_d3d_texture_2d_share_handle unavailable", 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PLATFORM_FAILURE, 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) false); 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE((state_ == kUninitialized), 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Initialize: invalid state: " << state_, ILLEGAL_STATE, false); 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "MFStartup failed.", PLATFORM_FAILURE, 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) false); 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE(InitDecoder(), 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Failed to initialize decoder", PLATFORM_FAILURE, false); 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE(GetStreamsInfoAndBufferReqs(), 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Failed to get input/output stream info.", PLATFORM_FAILURE, false); 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE( 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendMFTMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0), 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Send MFT_MESSAGE_NOTIFY_BEGIN_STREAMING notification failed", 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PLATFORM_FAILURE, false); 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE( 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendMFTMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0), 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Send MFT_MESSAGE_NOTIFY_START_OF_STREAM notification failed", 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PLATFORM_FAILURE, false); 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_ = kNormal; 506c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &DXVAVideoDecodeAccelerator::NotifyInitializeDone, 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AsWeakPtr(this))); 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DXVAVideoDecodeAccelerator::Decode( 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const media::BitstreamBuffer& bitstream_buffer) { 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE((state_ == kNormal || state_ == kStopped || 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_ == kFlushing), 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Invalid state: " << state_, ILLEGAL_STATE,); 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IMFSample> sample; 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sample.Attach(CreateSampleFromInputBuffer(bitstream_buffer, 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) input_stream_info_.cbSize, 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) input_stream_info_.cbAlignment)); 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE(sample, "Failed to create input sample", 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PLATFORM_FAILURE,); 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_HR_FAILURE(sample->SetSampleTime(bitstream_buffer.id()), 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Failed to associate input buffer id with sample", PLATFORM_FAILURE,); 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DecodeInternal(sample); 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DXVAVideoDecodeAccelerator::AssignPictureBuffers( 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::vector<media::PictureBuffer>& buffers) { 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE((state_ != kUninitialized), 5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "Invalid state: " << state_, ILLEGAL_STATE,); 539c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE((kNumPictureBuffers == buffers.size()), 540c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "Failed to provide requested picture buffers. (Got " << buffers.size() << 541c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ", requested " << kNumPictureBuffers << ")", INVALID_ARGUMENT,); 5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Copy the picture buffers provided by the client to the available list, 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and mark these buffers as available for use. 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t buffer_index = 0; buffer_index < buffers.size(); 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++buffer_index) { 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) linked_ptr<DXVAPictureBuffer> picture_buffer = 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DXVAPictureBuffer::Create(buffers[buffer_index], egl_config_); 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE(picture_buffer.get(), 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Failed to allocate picture buffer", PLATFORM_FAILURE,); 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool inserted = output_picture_buffers_.insert(std::make_pair( 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffers[buffer_index].id(), picture_buffer)).second; 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(inserted); 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProcessPendingSamples(); 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (state_ == kFlushing && pending_output_samples_.empty()) 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FlushInternal(); 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DXVAVideoDecodeAccelerator::ReusePictureBuffer( 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int32 picture_buffer_id) { 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE((state_ != kUninitialized), 5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "Invalid state: " << state_, ILLEGAL_STATE,); 5672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OutputBuffers::iterator it = output_picture_buffers_.find(picture_buffer_id); 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE(it != output_picture_buffers_.end(), 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Invalid picture id: " << picture_buffer_id, INVALID_ARGUMENT,); 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it->second->ReusePictureBuffer(); 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProcessPendingSamples(); 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (state_ == kFlushing && pending_output_samples_.empty()) 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FlushInternal(); 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DXVAVideoDecodeAccelerator::Flush() { 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "DXVAVideoDecodeAccelerator::Flush"; 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE((state_ == kNormal || state_ == kStopped), 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Unexpected decoder state: " << state_, ILLEGAL_STATE,); 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_ = kFlushing; 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE(SendMFTMessage(MFT_MESSAGE_COMMAND_DRAIN, 0), 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Failed to send drain message", PLATFORM_FAILURE,); 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!pending_output_samples_.empty()) 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FlushInternal(); 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DXVAVideoDecodeAccelerator::Reset() { 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "DXVAVideoDecodeAccelerator::Reset"; 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE((state_ == kNormal || state_ == kStopped), 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Reset: invalid state: " << state_, ILLEGAL_STATE,); 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_ = kResetting; 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_output_samples_.clear(); 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NotifyInputBuffersDropped(); 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE(SendMFTMessage(MFT_MESSAGE_COMMAND_FLUSH, 0), 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Reset: Failed to send message.", PLATFORM_FAILURE,); 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &DXVAVideoDecodeAccelerator::NotifyResetDone, base::AsWeakPtr(this))); 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_ = DXVAVideoDecodeAccelerator::kNormal; 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DXVAVideoDecodeAccelerator::Destroy() { 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Invalidate(); 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete this; 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DXVAVideoDecodeAccelerator::InitDecoder() { 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We cannot use CoCreateInstance to instantiate the decoder object as that 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // fails in the sandbox. We mimic the steps CoCreateInstance uses to 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // instantiate the object. 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HMODULE decoder_dll = ::GetModuleHandle(L"msmpeg2vdec.dll"); 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_FAILURE(decoder_dll, 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "msmpeg2vdec.dll required for decoding is not loaded", 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) false); 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef HRESULT (WINAPI* GetClassObject)(const CLSID& clsid, 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const IID& iid, 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void** object); 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetClassObject get_class_object = reinterpret_cast<GetClassObject>( 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetProcAddress(decoder_dll, "DllGetClassObject")); 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_FAILURE(get_class_object, 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Failed to get DllGetClassObject pointer", false); 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IClassFactory> factory; 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = get_class_object(__uuidof(CMSH264DecoderMFT), 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __uuidof(IClassFactory), 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<void**>(factory.Receive())); 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "DllGetClassObject for decoder failed", false); 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = factory->CreateInstance(NULL, __uuidof(IMFTransform), 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<void**>(decoder_.Receive())); 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to create decoder instance", false); 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_FAILURE(CheckDecoderDxvaSupport(), 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Failed to check decoder DXVA support", false); 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = decoder_->ProcessMessage( 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MFT_MESSAGE_SET_D3D_MANAGER, 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<ULONG_PTR>(device_manager_)); 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to pass D3D manager to decoder", false); 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); 6647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EGLint config_attribs[] = { 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EGL_BUFFER_SIZE, 32, 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EGL_RED_SIZE, 8, 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EGL_GREEN_SIZE, 8, 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EGL_BLUE_SIZE, 8, 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EGL_ALPHA_SIZE, 0, 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EGL_NONE 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EGLint num_configs; 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!eglChooseConfig( 6787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch egl_display, 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) config_attribs, 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &egl_config_, 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1, 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &num_configs)) 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SetDecoderMediaTypes(); 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DXVAVideoDecodeAccelerator::CheckDecoderDxvaSupport() { 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IMFAttributes> attributes; 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = decoder_->GetAttributes(attributes.Receive()); 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to get decoder attributes", false); 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UINT32 dxva = 0; 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = attributes->GetUINT32(MF_SA_D3D_AWARE, &dxva); 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to check if decoder supports DXVA", false); 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = attributes->SetUINT32(CODECAPI_AVDecVideoAcceleration_H264, TRUE); 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to enable DXVA H/W decoding", false); 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DXVAVideoDecodeAccelerator::SetDecoderMediaTypes() { 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_FAILURE(SetDecoderInputMediaType(), 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Failed to set decoder input media type", false); 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SetDecoderOutputMediaType(MFVideoFormat_NV12); 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DXVAVideoDecodeAccelerator::SetDecoderInputMediaType() { 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IMFMediaType> media_type; 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = MFCreateMediaType(media_type.Receive()); 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "MFCreateMediaType failed", false); 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = media_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to set major input type", false); 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = media_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264); 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to set subtype", false); 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Not sure about this. msdn recommends setting this value on the input 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // media type. 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = media_type->SetUINT32(MF_MT_INTERLACE_MODE, 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MFVideoInterlace_MixedInterlaceOrProgressive); 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to set interlace mode", false); 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = decoder_->SetInputType(0, media_type, 0); // No flags 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to set decoder input type", false); 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DXVAVideoDecodeAccelerator::SetDecoderOutputMediaType( 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GUID& subtype) { 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IMFMediaType> out_media_type; 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (uint32 i = 0; 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SUCCEEDED(decoder_->GetOutputAvailableType(0, i, 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_media_type.Receive())); 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++i) { 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GUID out_subtype = {0}; 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = out_media_type->GetGUID(MF_MT_SUBTYPE, &out_subtype); 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to get output major type", false); 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (out_subtype == subtype) { 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = decoder_->SetOutputType(0, out_media_type, 0); // No flags 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to set decoder output type", false); 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_media_type.Release(); 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DXVAVideoDecodeAccelerator::SendMFTMessage(MFT_MESSAGE_TYPE msg, 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int32 param) { 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = decoder_->ProcessMessage(msg, param); 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SUCCEEDED(hr); 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Gets the minimum buffer sizes for input and output samples. The MFT will not 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// allocate buffer for input nor output, so we have to do it ourselves and make 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// sure they're the correct size. We only provide decoding if DXVA is enabled. 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DXVAVideoDecodeAccelerator::GetStreamsInfoAndBufferReqs() { 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = decoder_->GetInputStreamInfo(0, &input_stream_info_); 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to get input stream info", false); 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = decoder_->GetOutputStreamInfo(0, &output_stream_info_); 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to get decoder output stream info", false); 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Input stream info: "; 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Max latency: " << input_stream_info_.hnsMaxLatency; 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There should be three flags, one for requiring a whole frame be in a 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // single sample, one for requiring there be one buffer only in a single 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // sample, and one that specifies a fixed sample size. (as in cbSize) 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(input_stream_info_.dwFlags, 0x7u); 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Min buffer size: " << input_stream_info_.cbSize; 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Max lookahead: " << input_stream_info_.cbMaxLookahead; 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Alignment: " << input_stream_info_.cbAlignment; 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Output stream info: "; 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The flags here should be the same and mean the same thing, except when 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // DXVA is enabled, there is an extra 0x100 flag meaning decoder will 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // allocate its own sample. 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Flags: " 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << std::hex << std::showbase << output_stream_info_.dwFlags; 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(output_stream_info_.dwFlags, 0x107u); 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Min buffer size: " << output_stream_info_.cbSize; 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Alignment: " << output_stream_info_.cbAlignment; 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DXVAVideoDecodeAccelerator::DoDecode() { 7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This function is also called from FlushInternal in a loop which could 7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // result in the state transitioning to kStopped due to no decoded output. 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE((state_ == kNormal || state_ == kFlushing || 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_ == kStopped), 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "DoDecode: not in normal/flushing/stopped state", ILLEGAL_STATE,); 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MFT_OUTPUT_DATA_BUFFER output_data_buffer = {0}; 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD status = 0; 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = decoder_->ProcessOutput(0, // No flags 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1, // # of out streams to pull from 8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &output_data_buffer, 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &status); 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IMFCollection* events = output_data_buffer.pEvents; 8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (events != NULL) { 8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(1) << "Got events from ProcessOuput, but discarding"; 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) events->Release(); 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) { 8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A stream change needs further ProcessInput calls to get back decoder 8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // output which is why we need to set the state to stopped. 8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (hr == MF_E_TRANSFORM_STREAM_CHANGE) { 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!SetDecoderOutputMediaType(MFVideoFormat_NV12)) { 8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Decoder didn't let us set NV12 output format. Not sure as to why 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // this can happen. Give up in disgust. 8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "Failed to set decoder output media type to NV12"; 8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_ = kStopped; 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Received output format change from the decoder." 8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) " Recursively invoking DoDecode"; 8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DoDecode(); 8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // No more output from the decoder. Stop playback. 8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_ = kStopped; 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "Unhandled error in DoDecode()"; 8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TRACE_EVENT_END_ETW("DXVAVideoDecodeAccelerator.Decoding", this, ""); 8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TRACE_COUNTER1("DXVA Decoding", "TotalPacketsBeforeDecode", 8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inputs_before_decode_); 8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inputs_before_decode_ = 0; 8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE(ProcessOutputSample(output_data_buffer.pSample), 8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Failed to process output sample.", PLATFORM_FAILURE,); 8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DXVAVideoDecodeAccelerator::ProcessOutputSample(IMFSample* sample) { 8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_FAILURE(sample, "Decode succeeded with NULL output sample", false); 8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IMFMediaBuffer> output_buffer; 8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = sample->GetBufferByIndex(0, output_buffer.Receive()); 8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to get buffer from output sample", false); 8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IDirect3DSurface9> surface; 8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = MFGetService(output_buffer, MR_BUFFER_SERVICE, 8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IID_PPV_ARGS(surface.Receive())); 8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to get D3D surface from output sample", 8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) false); 8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LONGLONG input_buffer_id = 0; 8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(sample->GetSampleTime(&input_buffer_id), 8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Failed to get input buffer id associated with sample", 8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) false); 8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_output_samples_.push_back( 8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PendingSampleInfo(input_buffer_id, sample)); 8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we have available picture buffers to copy the output data then use the 8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // first one and then flag it as not being available for use. 8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (output_picture_buffers_.size()) { 8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProcessPendingSamples(); 8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pictures_requested_) { 8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Waiting for picture slots from the client."; 8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We only read the surface description, which contains its width/height when 8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we need the picture buffers from the client. Once we have those, then they 8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // are reused. This won't work if the frame sizes change mid stream. 8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There is a TODO comment in the 8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // DXVAVideoDecodeAccelerator::RequestPictureBuffers function which talks 8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // about supporting this. 8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) D3DSURFACE_DESC surface_desc; 8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = surface->GetDesc(&surface_desc); 8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); 8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Go ahead and request picture buffers. 888c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &DXVAVideoDecodeAccelerator::RequestPictureBuffers, 8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AsWeakPtr(this), surface_desc.Width, surface_desc.Height)); 8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pictures_requested_ = true; 8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DXVAVideoDecodeAccelerator::ProcessPendingSamples() { 8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(), 8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Failed to make context current", PLATFORM_FAILURE,); 8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OutputBuffers::iterator index; 9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (index = output_picture_buffers_.begin(); 9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) index != output_picture_buffers_.end() && 9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !pending_output_samples_.empty(); 9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++index) { 9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (index->second->available()) { 9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PendingSampleInfo sample_info = pending_output_samples_.front(); 9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IMFMediaBuffer> output_buffer; 9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = sample_info.output_sample->GetBufferByIndex( 9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, output_buffer.Receive()); 9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_HR_FAILURE( 9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr, "Failed to get buffer from output sample", PLATFORM_FAILURE,); 9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedComPtr<IDirect3DSurface9> surface; 9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = MFGetService(output_buffer, MR_BUFFER_SERVICE, 9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IID_PPV_ARGS(surface.Receive())); 9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_HR_FAILURE( 9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr, "Failed to get D3D surface from output sample", 9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PLATFORM_FAILURE,); 9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE( 9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) index->second->CopyOutputSampleDataToPictureBuffer( 9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) surface), 9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "Failed to copy output sample", PLATFORM_FAILURE,); 9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) media::Picture output_picture(index->second->id(), 9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sample_info.input_buffer_id); 929c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &DXVAVideoDecodeAccelerator::NotifyPictureReady, 9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AsWeakPtr(this), output_picture)); 9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) index->second->set_available(false); 9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_output_samples_.pop_front(); 9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!pending_input_buffers_.empty() && pending_output_samples_.empty()) { 939c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, 9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::AsWeakPtr(this))); 9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DXVAVideoDecodeAccelerator::StopOnError( 9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) media::VideoDecodeAccelerator::Error error) { 9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(CalledOnValidThread()); 9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (client_) 9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_->NotifyError(error); 9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_ = NULL; 9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (state_ != kUninitialized) { 9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Invalidate(); 9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DXVAVideoDecodeAccelerator::Invalidate() { 9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (state_ == kUninitialized) 9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output_picture_buffers_.clear(); 9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_output_samples_.clear(); 9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_input_buffers_.clear(); 9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) decoder_.Release(); 9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MFShutdown(); 9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_ = kUninitialized; 9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DXVAVideoDecodeAccelerator::NotifyInitializeDone() { 9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (client_) 9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_->NotifyInitializeDone(); 9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DXVAVideoDecodeAccelerator::NotifyInputBufferRead(int input_buffer_id) { 9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (client_) 9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_->NotifyEndOfBitstreamBuffer(input_buffer_id); 9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DXVAVideoDecodeAccelerator::NotifyFlushDone() { 9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (client_) 9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_->NotifyFlushDone(); 9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DXVAVideoDecodeAccelerator::NotifyResetDone() { 9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (client_) 9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_->NotifyResetDone(); 9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DXVAVideoDecodeAccelerator::RequestPictureBuffers(int width, int height) { 9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This task could execute after the decoder has been torn down. 9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(ananta) 9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We need to support mid stream resize. 9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (state_ != kUninitialized && client_) { 9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_->ProvidePictureBuffers( 9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kNumPictureBuffers, 9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Size(width, height), 9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GL_TEXTURE_2D); 9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DXVAVideoDecodeAccelerator::NotifyPictureReady( 10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const media::Picture& picture) { 10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This task could execute after the decoder has been torn down. 10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (state_ != kUninitialized && client_) 10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_->PictureReady(picture); 10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DXVAVideoDecodeAccelerator::NotifyInputBuffersDropped() { 10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!client_ || !pending_output_samples_.empty()) 10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (PendingInputs::iterator it = pending_input_buffers_.begin(); 10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != pending_input_buffers_.end(); ++it) { 10142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LONGLONG input_buffer_id = 0; 10152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RETURN_ON_HR_FAILURE((*it)->GetSampleTime(&input_buffer_id), 10162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "Failed to get buffer id associated with sample",); 10172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) client_->NotifyEndOfBitstreamBuffer(input_buffer_id); 10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_input_buffers_.clear(); 10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DXVAVideoDecodeAccelerator::DecodePendingInputBuffers() { 10232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE((state_ != kUninitialized), 10242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "Invalid state: " << state_, ILLEGAL_STATE,); 10252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pending_input_buffers_.empty() || !pending_output_samples_.empty()) 10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PendingInputs pending_input_buffers_copy; 10302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::swap(pending_input_buffers_, pending_input_buffers_copy); 10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (PendingInputs::iterator it = pending_input_buffers_copy.begin(); 10332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) it != pending_input_buffers_copy.end(); ++it) { 10342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DecodeInternal(*it); 10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DXVAVideoDecodeAccelerator::FlushInternal() { 10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The DoDecode function sets the state to kStopped when the decoder returns 10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // MF_E_TRANSFORM_NEED_MORE_INPUT. 10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The MFT decoder can buffer upto 30 frames worth of input before returning 10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // an output frame. This loop here attempts to retrieve as many output frames 10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // as possible from the buffered set. 10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (state_ != kStopped) { 10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DoDecode(); 10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!pending_output_samples_.empty()) 10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1050c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &DXVAVideoDecodeAccelerator::NotifyFlushDone, base::AsWeakPtr(this))); 10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state_ = kNormal; 10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DXVAVideoDecodeAccelerator::DecodeInternal( 10572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::win::ScopedComPtr<IMFSample>& sample) { 10582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(CalledOnValidThread()); 10592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 10602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (state_ == kUninitialized) 10612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 10622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 10632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!pending_output_samples_.empty() || !pending_input_buffers_.empty()) { 10642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pending_input_buffers_.push_back(sample); 10652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 10662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 10672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 10682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!inputs_before_decode_) { 10692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TRACE_EVENT_BEGIN_ETW("DXVAVideoDecodeAccelerator.Decoding", this, ""); 10702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 10712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) inputs_before_decode_++; 10722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 10732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HRESULT hr = decoder_->ProcessInput(0, sample, 0); 10742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // As per msdn if the decoder returns MF_E_NOTACCEPTING then it means that it 10752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // has enough data to produce one or more output samples. In this case the 10762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // recommended options are to 10772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 1. Generate new output by calling IMFTransform::ProcessOutput until it 10782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // returns MF_E_TRANSFORM_NEED_MORE_INPUT. 10792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 2. Flush the input data 10802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We implement the first option, i.e to retrieve the output sample and then 10812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // process the input again. Failure in either of these steps is treated as a 10822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // decoder failure. 10832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (hr == MF_E_NOTACCEPTING) { 10842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DoDecode(); 10852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE((state_ == kStopped || state_ == kNormal), 10862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "Failed to process output. Unexpected decoder state: " << state_, 10872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PLATFORM_FAILURE,); 10882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = decoder_->ProcessInput(0, sample, 0); 1089868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // If we continue to get the MF_E_NOTACCEPTING error we do the following:- 1090868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // 1. Add the input sample to the pending queue. 1091868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // 2. If we don't have any output samples we post the 1092868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // DecodePendingInputBuffers task to process the pending input samples. 1093868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // If we have an output sample then the above task is posted when the 1094868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // output samples are sent to the client. 1095868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // This is because we only support 1 pending output sample at any 10962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // given time due to the limitation with the Microsoft media foundation 10972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // decoder where it recycles the output Decoder surfaces. 1098868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (hr == MF_E_NOTACCEPTING) { 10992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pending_input_buffers_.push_back(sample); 1100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (pending_output_samples_.empty()) { 1101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 1102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) &DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, 1103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::AsWeakPtr(this))); 1104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 11052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 11062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 11072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 11082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to process input sample", 11092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) PLATFORM_FAILURE,); 11102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 11112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DoDecode(); 11122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 11132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RETURN_AND_NOTIFY_ON_FAILURE((state_ == kStopped || state_ == kNormal), 11142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "Failed to process output. Unexpected decoder state: " << state_, 11152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ILLEGAL_STATE,); 11162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 11172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LONGLONG input_buffer_id = 0; 11182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RETURN_ON_HR_FAILURE(sample->GetSampleTime(&input_buffer_id), 11192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "Failed to get input buffer id associated with sample",); 11202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The Microsoft Media foundation decoder internally buffers up to 30 frames 11212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // before returning a decoded frame. We need to inform the client that this 11222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // input buffer is processed as it may stop sending us further input. 11232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Note: This may break clients which expect every input buffer to be 11242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // associated with a decoded output buffer. 11252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(ananta) 11262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Do some more investigation into whether it is possible to get the MFT 11272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // decoder to emit an output packet for every input packet. 11282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // http://code.google.com/p/chromium/issues/detail?id=108121 11292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // http://code.google.com/p/chromium/issues/detail?id=150925 1130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 11312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &DXVAVideoDecodeAccelerator::NotifyInputBufferRead, 11322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::AsWeakPtr(this), input_buffer_id)); 11332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 11342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace content 1136