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, &current_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, &current_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