1f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// found in the LICENSE file.
4f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
5116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <CoreVideo/CoreVideo.h>
6116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <OpenGL/CGLIOSurface.h>
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <OpenGL/gl.h>
8116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
9116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/bind.h"
105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/command_line.h"
115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/sys_byteorder.h"
12116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/thread_task_runner_handle.h"
13f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "content/common/gpu/media/vt_video_decode_accelerator.h"
145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "content/public/common/content_switches.h"
15116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "media/filters/h264_parser.h"
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "ui/gl/scoped_binders.h"
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "ui/gl/scoped_cgl.h"
18116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
19116680a4aac90f2aa7413d9095a592090648e557Ben Murdochusing content_common_gpu_media::kModuleVt;
20116680a4aac90f2aa7413d9095a592090648e557Ben Murdochusing content_common_gpu_media::InitializeStubs;
21116680a4aac90f2aa7413d9095a592090648e557Ben Murdochusing content_common_gpu_media::IsVtInitialized;
22116680a4aac90f2aa7413d9095a592090648e557Ben Murdochusing content_common_gpu_media::StubPathMap;
23f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace content {
25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Size of NALU length headers in AVCC/MPEG-4 format (can be 1, 2, or 4).
27116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic const int kNALUHeaderLength = 4;
28116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// We only request 5 picture buffers from the client which are used to hold the
305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// decoded samples. These buffers are then reused when the client tells us that
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// it is done with the buffer.
325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static const int kNumPictureBuffers = 5;
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Route decoded frame callbacks back into the VTVideoDecodeAccelerator.
35116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic void OutputThunk(
36116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    void* decompression_output_refcon,
37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    void* source_frame_refcon,
38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    OSStatus status,
39116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    VTDecodeInfoFlags info_flags,
40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    CVImageBufferRef image_buffer,
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    CMTime presentation_time_stamp,
42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    CMTime presentation_duration) {
43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  VTVideoDecodeAccelerator* vda =
44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      reinterpret_cast<VTVideoDecodeAccelerator*>(decompression_output_refcon);
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int32_t bitstream_id = reinterpret_cast<intptr_t>(source_frame_refcon);
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  vda->Output(bitstream_id, status, image_buffer);
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)VTVideoDecodeAccelerator::DecodedFrame::DecodedFrame(
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    int32_t bitstream_id,
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    CVImageBufferRef image_buffer)
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    : bitstream_id(bitstream_id),
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      image_buffer(image_buffer) {
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)VTVideoDecodeAccelerator::DecodedFrame::~DecodedFrame() {
57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciVTVideoDecodeAccelerator::PendingAction::PendingAction(
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    Action action,
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int32_t bitstream_id)
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : action(action),
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      bitstream_id(bitstream_id) {
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciVTVideoDecodeAccelerator::PendingAction::~PendingAction() {
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)VTVideoDecodeAccelerator::VTVideoDecodeAccelerator(CGLContextObj cgl_context)
70116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    : cgl_context_(cgl_context),
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      client_(NULL),
72116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      format_(NULL),
73116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      session_(NULL),
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      gpu_task_runner_(base::ThreadTaskRunnerHandle::Get()),
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      weak_this_factory_(this),
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      decoder_thread_("VTDecoderThread") {
77116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  callback_.decompressionOutputCallback = OutputThunk;
78116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  callback_.decompressionOutputRefCon = this;
79f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
81f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)VTVideoDecodeAccelerator::~VTVideoDecodeAccelerator() {
82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
83f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
84f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool VTVideoDecodeAccelerator::Initialize(
85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    media::VideoCodecProfile profile,
86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    Client* client) {
87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(CalledOnValidThread());
88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  client_ = client;
89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Only H.264 is supported.
91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (profile < media::H264PROFILE_MIN || profile > media::H264PROFILE_MAX)
92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Require --no-sandbox until VideoToolbox library loading is part of sandbox
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // startup (and this VDA is ready for regular users).
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoSandbox))
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return false;
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!IsVtInitialized()) {
100116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // CoreVideo is also required, but the loader stops after the first
101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // path is loaded. Instead we rely on the transitive dependency from
102116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // VideoToolbox to CoreVideo.
103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // TODO(sandersd): Fallback to PrivateFrameworks for VideoToolbox.
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    StubPathMap paths;
105116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    paths[kModuleVt].push_back(FILE_PATH_LITERAL(
106116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        "/System/Library/Frameworks/VideoToolbox.framework/VideoToolbox"));
107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!InitializeStubs(paths))
108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return false;
109116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
111116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Spawn a thread to handle parsing and calling VideoToolbox.
112116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!decoder_thread_.Start())
113116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return true;
116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
117116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
118116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// TODO(sandersd): Proper error reporting instead of CHECKs.
119116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid VTVideoDecodeAccelerator::ConfigureDecoder(
120116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const std::vector<const uint8_t*>& nalu_data_ptrs,
121116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const std::vector<size_t>& nalu_data_sizes) {
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread());
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Construct a new format description from the parameter sets.
1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // TODO(sandersd): Replace this with custom code to support OS X < 10.9.
125116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  format_.reset();
126116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CHECK(!CMVideoFormatDescriptionCreateFromH264ParameterSets(
127116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      kCFAllocatorDefault,
128116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      nalu_data_ptrs.size(),      // parameter_set_count
129116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      &nalu_data_ptrs.front(),    // &parameter_set_pointers
130116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      &nalu_data_sizes.front(),   // &parameter_set_sizes
131116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      kNALUHeaderLength,          // nal_unit_header_length
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      format_.InitializeInto()));
1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CMVideoDimensions coded_dimensions =
1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      CMVideoFormatDescriptionGetDimensions(format_);
135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Prepare VideoToolbox configuration dictionaries.
137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::ScopedCFTypeRef<CFMutableDictionaryRef> decoder_config(
138116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      CFDictionaryCreateMutable(
139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          kCFAllocatorDefault,
140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          1,  // capacity
141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          &kCFTypeDictionaryKeyCallBacks,
142116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          &kCFTypeDictionaryValueCallBacks));
143116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CFDictionarySetValue(
145116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      decoder_config,
146116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder
147116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      CFSTR("EnableHardwareAcceleratedVideoDecoder"),
148116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      kCFBooleanTrue);
149116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
150116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config(
151116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      CFDictionaryCreateMutable(
152116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          kCFAllocatorDefault,
153116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          4,  // capacity
154116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          &kCFTypeDictionaryKeyCallBacks,
155116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          &kCFTypeDictionaryValueCallBacks));
156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
157116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i)
1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // TODO(sandersd): RGBA option for 4:4:4 video.
1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  int32_t pixel_format = kCVPixelFormatType_422YpCbCr8;
160116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::ScopedCFTypeRef<CFNumberRef> cf_pixel_format(CFINT(pixel_format));
1615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::ScopedCFTypeRef<CFNumberRef> cf_width(CFINT(coded_dimensions.width));
1625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::ScopedCFTypeRef<CFNumberRef> cf_height(CFINT(coded_dimensions.height));
163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#undef CFINT
164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CFDictionarySetValue(
165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      image_config, kCVPixelBufferPixelFormatTypeKey, cf_pixel_format);
166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CFDictionarySetValue(image_config, kCVPixelBufferWidthKey, cf_width);
167116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CFDictionarySetValue(image_config, kCVPixelBufferHeightKey, cf_height);
168116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CFDictionarySetValue(
169116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      image_config, kCVPixelBufferOpenGLCompatibilityKey, kCFBooleanTrue);
170116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // TODO(sandersd): Check if the session is already compatible.
172116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  session_.reset();
173116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CHECK(!VTDecompressionSessionCreate(
174116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      kCFAllocatorDefault,
175116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      format_,              // video_format_description
176116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      decoder_config,       // video_decoder_specification
177116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      image_config,         // destination_image_buffer_attributes
178116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      &callback_,           // output_callback
1795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      session_.InitializeInto()));
1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // If the size has changed, trigger a request for new picture buffers.
1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // TODO(sandersd): Move to SendPictures(), and use this just as a hint for an
1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // upcoming size change.
1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  gfx::Size new_coded_size(coded_dimensions.width, coded_dimensions.height);
1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (coded_size_ != new_coded_size) {
1865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    coded_size_ = new_coded_size;
1875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    gpu_task_runner_->PostTask(FROM_HERE, base::Bind(
1885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        &VTVideoDecodeAccelerator::SizeChangedTask,
1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        weak_this_factory_.GetWeakPtr(),
1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        coded_size_));;
1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
192f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
193f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
194f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void VTVideoDecodeAccelerator::Decode(const media::BitstreamBuffer& bitstream) {
195f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(CalledOnValidThread());
1961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK_GE(bitstream.id(), 0) << "Negative bitstream_id";
1971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  pending_bitstream_ids_.push(bitstream.id());
198116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  decoder_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
199116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      &VTVideoDecodeAccelerator::DecodeTask, base::Unretained(this),
200116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      bitstream));
201116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
202116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// TODO(sandersd): Proper error reporting instead of CHECKs.
204116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid VTVideoDecodeAccelerator::DecodeTask(
205116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const media::BitstreamBuffer bitstream) {
206116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread());
207116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
208116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Map the bitstream buffer.
209116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::SharedMemory memory(bitstream.handle(), true);
210116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  size_t size = bitstream.size();
211116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CHECK(memory.Map(size));
212116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const uint8_t* buf = static_cast<uint8_t*>(memory.memory());
213116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // NALUs are stored with Annex B format in the bitstream buffer (start codes),
2155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // but VideoToolbox expects AVCC/MPEG-4 format (length headers), so we must
2165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // rewrite the data.
2175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  //
2185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // 1. Locate relevant NALUs and compute the size of the translated data.
2195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  //    Also record any parameter sets for VideoToolbox initialization.
220116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  size_t data_size = 0;
221116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::vector<media::H264NALU> nalus;
222116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::vector<const uint8_t*> config_nalu_data_ptrs;
223116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::vector<size_t> config_nalu_data_sizes;
224116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  parser_.SetStream(buf, size);
225116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  media::H264NALU nalu;
226116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  while (true) {
227116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    media::H264Parser::Result result = parser_.AdvanceToNextNALU(&nalu);
228116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (result == media::H264Parser::kEOStream)
229116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      break;
230116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    CHECK_EQ(result, media::H264Parser::kOk);
2315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // TODO(sandersd): Check that these are only at the start.
232116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (nalu.nal_unit_type == media::H264NALU::kSPS ||
233116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        nalu.nal_unit_type == media::H264NALU::kPPS ||
234116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        nalu.nal_unit_type == media::H264NALU::kSPSExt) {
2355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      DVLOG(2) << "Parameter set " << nalu.nal_unit_type;
236116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      config_nalu_data_ptrs.push_back(nalu.data);
237116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      config_nalu_data_sizes.push_back(nalu.size);
2385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    } else {
2395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      nalus.push_back(nalu);
2405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      data_size += kNALUHeaderLength + nalu.size;
241116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
242116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
243116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // 2. Initialize VideoToolbox.
2455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // TODO(sandersd): Reinitialize when there are new parameter sets.
2465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!session_)
247116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ConfigureDecoder(config_nalu_data_ptrs, config_nalu_data_sizes);
248116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // If there are no non-configuration units, immediately return an empty
2501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // (ie. dropped) frame. It is an error to create a MemoryBlock with zero
2511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // size.
2521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!data_size) {
2531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    gpu_task_runner_->PostTask(FROM_HERE, base::Bind(
2541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        &VTVideoDecodeAccelerator::OutputTask,
2551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        weak_this_factory_.GetWeakPtr(),
2561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        DecodedFrame(bitstream.id(), NULL)));
2571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
2581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // 3. Allocate a memory-backed CMBlockBuffer for the translated data.
2615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::ScopedCFTypeRef<CMBlockBufferRef> data;
2625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CHECK(!CMBlockBufferCreateWithMemoryBlock(
2635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      kCFAllocatorDefault,
2645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      NULL,                 // &memory_block
2655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      data_size,            // block_length
2665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      kCFAllocatorDefault,  // block_allocator
2675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      NULL,                 // &custom_block_source
2685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      0,                    // offset_to_data
2695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      data_size,            // data_length
2705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      0,                    // flags
2715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      data.InitializeInto()));
2725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // 4. Copy NALU data, inserting length headers.
2745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  size_t offset = 0;
2755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  for (size_t i = 0; i < nalus.size(); i++) {
2765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    media::H264NALU& nalu = nalus[i];
2775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    uint32_t header = base::HostToNet32(static_cast<uint32_t>(nalu.size));
2785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    CHECK(!CMBlockBufferReplaceDataBytes(
2795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        &header, data, offset, kNALUHeaderLength));
2805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    offset += kNALUHeaderLength;
2815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    CHECK(!CMBlockBufferReplaceDataBytes(nalu.data, data, offset, nalu.size));
2825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    offset += nalu.size;
2835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
2845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // 5. Package the data for VideoToolbox and request decoding.
2865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::ScopedCFTypeRef<CMSampleBufferRef> frame;
2875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CHECK(!CMSampleBufferCreate(
2885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      kCFAllocatorDefault,
2895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      data,                 // data_buffer
2905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      true,                 // data_ready
2915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      NULL,                 // make_data_ready_callback
2925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      NULL,                 // make_data_ready_refcon
2935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      format_,              // format_description
2945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      1,                    // num_samples
2955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      0,                    // num_sample_timing_entries
2965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      NULL,                 // &sample_timing_array
2975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      0,                    // num_sample_size_entries
2985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      NULL,                 // &sample_size_array
2995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      frame.InitializeInto()));
3005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Asynchronous Decompression allows for parallel submission of frames
3025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // (without it, DecodeFrame() does not return until the frame has been
3035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // decoded). We don't enable Temporal Processing so that frames are always
3045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // returned in decode order; this makes it easier to avoid deadlock.
3055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VTDecodeFrameFlags decode_flags =
3065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      kVTDecodeFrame_EnableAsynchronousDecompression;
3075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  intptr_t bitstream_id = bitstream.id();
3095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CHECK(!VTDecompressionSessionDecodeFrame(
3105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      session_,
3115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      frame,                                  // sample_buffer
3125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      decode_flags,                           // decode_flags
3135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      reinterpret_cast<void*>(bitstream_id),  // source_frame_refcon
3145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      NULL));                                 // &info_flags_out
315116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
316116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
317116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// This method may be called on any VideoToolbox thread.
3185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// TODO(sandersd): Proper error reporting instead of CHECKs.
319116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid VTVideoDecodeAccelerator::Output(
320116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    int32_t bitstream_id,
321116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    OSStatus status,
322116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    CVImageBufferRef image_buffer) {
3235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CHECK(!status);
3245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CHECK_EQ(CFGetTypeID(image_buffer), CVPixelBufferGetTypeID());
3255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CFRetain(image_buffer);
3265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  gpu_task_runner_->PostTask(FROM_HERE, base::Bind(
3275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      &VTVideoDecodeAccelerator::OutputTask,
3285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      weak_this_factory_.GetWeakPtr(),
3295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      DecodedFrame(bitstream_id, image_buffer)));
3305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void VTVideoDecodeAccelerator::OutputTask(DecodedFrame frame) {
3335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(CalledOnValidThread());
3345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  decoded_frames_.push(frame);
3351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ProcessDecodedFrames();
3365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void VTVideoDecodeAccelerator::SizeChangedTask(gfx::Size coded_size) {
3395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(CalledOnValidThread());
3405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  texture_size_ = coded_size;
3415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // TODO(sandersd): Dismiss existing picture buffers.
3425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  client_->ProvidePictureBuffers(
3435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      kNumPictureBuffers, texture_size_, GL_TEXTURE_RECTANGLE_ARB);
344f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
345f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
346f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void VTVideoDecodeAccelerator::AssignPictureBuffers(
347f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::vector<media::PictureBuffer>& pictures) {
348f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(CalledOnValidThread());
3495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  for (size_t i = 0; i < pictures.size(); i++) {
3515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    CHECK(!texture_ids_.count(pictures[i].id()));
3525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    available_picture_ids_.push(pictures[i].id());
3535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    texture_ids_[pictures[i].id()] = pictures[i].texture_id();
3545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
3555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Pictures are not marked as uncleared until after this method returns, and
3571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // they will be broken if they are used before that happens. So, schedule
3581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // future work after that happens.
3595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  gpu_task_runner_->PostTask(FROM_HERE, base::Bind(
3601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      &VTVideoDecodeAccelerator::ProcessDecodedFrames,
3615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      weak_this_factory_.GetWeakPtr()));
362f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
363f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
364f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void VTVideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_id) {
365f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(CalledOnValidThread());
3665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK_EQ(CFGetRetainCount(picture_bindings_[picture_id]), 1);
3675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  picture_bindings_.erase(picture_id);
3685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  available_picture_ids_.push(picture_id);
3691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ProcessDecodedFrames();
3705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid VTVideoDecodeAccelerator::CompleteAction(Action action) {
3735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(CalledOnValidThread());
3741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  switch (action) {
3751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    case ACTION_FLUSH:
3761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      client_->NotifyFlushDone();
3771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      break;
3781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    case ACTION_RESET:
3791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      client_->NotifyResetDone();
3801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      break;
3811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    case ACTION_DESTROY:
3821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      delete this;
3831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      break;
3841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
3851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid VTVideoDecodeAccelerator::CompleteActions(int32_t bitstream_id) {
3881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(CalledOnValidThread());
3891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  while (!pending_actions_.empty() &&
3901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci         pending_actions_.front().bitstream_id == bitstream_id) {
3911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    CompleteAction(pending_actions_.front().action);
3921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    pending_actions_.pop();
3931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
3941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid VTVideoDecodeAccelerator::ProcessDecodedFrames() {
3971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(CalledOnValidThread());
3981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  while (!decoded_frames_.empty()) {
4001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (pending_actions_.empty()) {
4011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      // No pending actions; send frames normally.
4021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      SendPictures(pending_bitstream_ids_.back());
4031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return;
4041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
4051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int32_t next_action_bitstream_id = pending_actions_.front().bitstream_id;
4071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int32_t last_sent_bitstream_id = -1;
4081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    switch (pending_actions_.front().action) {
4091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      case ACTION_FLUSH:
4101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        // Send frames normally.
4111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        last_sent_bitstream_id = SendPictures(next_action_bitstream_id);
4121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        break;
4131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      case ACTION_RESET:
4151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        // Drop decoded frames.
4161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        while (!decoded_frames_.empty() &&
4171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci               last_sent_bitstream_id != next_action_bitstream_id) {
4181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          last_sent_bitstream_id = decoded_frames_.front().bitstream_id;
4191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          decoded_frames_.pop();
4201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          DCHECK_EQ(pending_bitstream_ids_.front(), last_sent_bitstream_id);
4211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          pending_bitstream_ids_.pop();
4221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          client_->NotifyEndOfBitstreamBuffer(last_sent_bitstream_id);
4231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        }
4241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        break;
4251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      case ACTION_DESTROY:
4271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        // Drop decoded frames, without bookkeeping.
4281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        while (!decoded_frames_.empty()) {
4291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          last_sent_bitstream_id = decoded_frames_.front().bitstream_id;
4301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          decoded_frames_.pop();
4311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        }
4321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        // Handle completing the action specially, as it is important not to
4341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        // access |this| after calling CompleteAction().
4351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        if (last_sent_bitstream_id == next_action_bitstream_id)
4361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          CompleteAction(ACTION_DESTROY);
4371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        // Either |this| was deleted or no more progress can be made.
4391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        return;
4401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
4411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // If we ran out of buffers (or pictures), no more progress can be made
4431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // until more frames are decoded.
4441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (last_sent_bitstream_id != next_action_bitstream_id)
4451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return;
4461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Complete all actions pending for this |bitstream_id|, then loop to see
4481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // if progress can be made on the next action.
4491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    CompleteActions(next_action_bitstream_id);
4501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
4511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
4521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciint32_t VTVideoDecodeAccelerator::SendPictures(int32_t up_to_bitstream_id) {
4541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(CalledOnValidThread());
4551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(!decoded_frames_.empty());
4561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (available_picture_ids_.empty())
4581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return -1;
4595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  gfx::ScopedCGLSetCurrentContext scoped_set_current_context(cgl_context_);
4615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  glEnable(GL_TEXTURE_RECTANGLE_ARB);
4625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
4631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  int32_t last_sent_bitstream_id = -1;
4641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  while (!available_picture_ids_.empty() &&
4651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci         !decoded_frames_.empty() &&
4661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci         last_sent_bitstream_id != up_to_bitstream_id) {
4675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    DecodedFrame frame = decoded_frames_.front();
4685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    decoded_frames_.pop();
4691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK_EQ(pending_bitstream_ids_.front(), frame.bitstream_id);
4701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    pending_bitstream_ids_.pop();
4711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int32_t picture_id = available_picture_ids_.front();
4721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    available_picture_ids_.pop();
4731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    CVImageBufferRef image_buffer = frame.image_buffer.get();
4751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (image_buffer) {
4761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      IOSurfaceRef surface = CVPixelBufferGetIOSurface(image_buffer);
4771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      // TODO(sandersd): Find out why this sometimes fails due to no GL context.
4791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      gfx::ScopedTextureBinder
4801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          texture_binder(GL_TEXTURE_RECTANGLE_ARB, texture_ids_[picture_id]);
4811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      CHECK(!CGLTexImageIOSurface2D(
4821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          cgl_context_,                 // ctx
4831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          GL_TEXTURE_RECTANGLE_ARB,     // target
4841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          GL_RGB,                       // internal_format
4851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          texture_size_.width(),        // width
4861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          texture_size_.height(),       // height
4871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          GL_YCBCR_422_APPLE,           // format
4881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          GL_UNSIGNED_SHORT_8_8_APPLE,  // type
4891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          surface,                      // io_surface
4901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          0));                          // plane
4911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      picture_bindings_[picture_id] = frame.image_buffer;
4931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      client_->PictureReady(media::Picture(
4941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          picture_id, frame.bitstream_id, gfx::Rect(texture_size_)));
4951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
4961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    client_->NotifyEndOfBitstreamBuffer(frame.bitstream_id);
4981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    last_sent_bitstream_id = frame.bitstream_id;
4995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
5005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
5015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  glDisable(GL_TEXTURE_RECTANGLE_ARB);
5021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return last_sent_bitstream_id;
5031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
5041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
5051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid VTVideoDecodeAccelerator::FlushTask() {
5061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread());
5071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK(!VTDecompressionSessionFinishDelayedFrames(session_));
5081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
5091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
5101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid VTVideoDecodeAccelerator::QueueAction(Action action) {
5111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(CalledOnValidThread());
5121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (pending_bitstream_ids_.empty()) {
5131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // If there are no pending frames, all actions complete immediately.
5141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    CompleteAction(action);
5151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else {
5161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Otherwise, queue the action.
5171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    pending_actions_.push(PendingAction(action, pending_bitstream_ids_.back()));
5181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
5191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Request a flush to make sure the action will eventually complete.
5201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    decoder_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
5211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        &VTVideoDecodeAccelerator::FlushTask, base::Unretained(this)));
5221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
5231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // See if we can make progress now that there is a new pending action.
5241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ProcessDecodedFrames();
5251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
526f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
527f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
528f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void VTVideoDecodeAccelerator::Flush() {
529f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(CalledOnValidThread());
5301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  QueueAction(ACTION_FLUSH);
531f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
532f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
533f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void VTVideoDecodeAccelerator::Reset() {
534f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(CalledOnValidThread());
5351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  QueueAction(ACTION_RESET);
536f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
537f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
538f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void VTVideoDecodeAccelerator::Destroy() {
539f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(CalledOnValidThread());
5401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Drop any other pending actions.
5411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  while (!pending_actions_.empty())
5421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    pending_actions_.pop();
5431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Return all bitstream buffers.
5441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  while (!pending_bitstream_ids_.empty()) {
5451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    client_->NotifyEndOfBitstreamBuffer(pending_bitstream_ids_.front());
5461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    pending_bitstream_ids_.pop();
5471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
5481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  QueueAction(ACTION_DESTROY);
549f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
550f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
551f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() {
552f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return false;
553f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
554f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
555f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}  // namespace content
556