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(), // ¶meter_set_pointers 130116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch &nalu_data_sizes.front(), // ¶meter_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