1bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 3bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// found in the LICENSE file. 4bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 5bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "base/bind.h" 6bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "base/debug/trace_event.h" 7bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "base/logging.h" 8bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "base/metrics/histogram.h" 9bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "base/stl_util.h" 10bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "base/strings/string_util.h" 11bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "base/synchronization/waitable_event.h" 12bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "base/threading/non_thread_safe.h" 13bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "content/common/gpu/gpu_channel.h" 140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "content/common/gpu/media/vaapi_video_decode_accelerator.h" 150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "media/base/bind_to_current_loop.h" 160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "media/video/picture.h" 170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "ui/gl/gl_bindings.h" 180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "ui/gl/scoped_binders.h" 190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)static void ReportToUMA( 210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) content::VaapiH264Decoder::VAVDAH264DecoderFailure failure) { 220f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION( 230f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) "Media.VAVDAH264.DecoderFailure", 240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) failure, 250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) content::VaapiH264Decoder::VAVDA_H264_DECODER_FAILURES_MAX); 260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)} 270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 280f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)namespace content { 290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 300f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#define RETURN_AND_NOTIFY_ON_FAILURE(result, log, error_code, ret) \ 310f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) do { \ 320f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) if (!(result)) { \ 330f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) DVLOG(1) << log; \ 340f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) NotifyError(error_code); \ 35bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch return ret; \ 36bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch } \ 37bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch } while (0) 38bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 39bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochVaapiVideoDecodeAccelerator::InputBuffer::InputBuffer() : id(0), size(0) { 40bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch} 410f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 42bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochVaapiVideoDecodeAccelerator::InputBuffer::~InputBuffer() { 430f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)} 44bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 45bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochvoid VaapiVideoDecodeAccelerator::NotifyError(Error error) { 46bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch if (message_loop_ != base::MessageLoop::current()) { 47bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch DCHECK(decoder_thread_proxy_->BelongsToCurrentThread()); 48bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch message_loop_->PostTask(FROM_HERE, base::Bind( 49bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch &VaapiVideoDecodeAccelerator::NotifyError, weak_this_, error)); 50bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch return; 51bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch } 52bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 53bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // Post Cleanup() as a task so we don't recursively acquire lock_. 5458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) message_loop_->PostTask(FROM_HERE, base::Bind( 55bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch &VaapiVideoDecodeAccelerator::Cleanup, weak_this_)); 56bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 57bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch DVLOG(1) << "Notifying of error " << error; 58bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch if (client_) { 59bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch client_->NotifyError(error); 60bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch client_ptr_factory_.reset(); 61bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch } 62bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch} 63bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 64bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// TFPPicture allocates X Pixmaps and binds them to textures passed 65bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// in PictureBuffers from clients to them. TFPPictures are created as 660f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// a consequence of receiving a set of PictureBuffers from clients and released 670f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// at the end of decode (or when a new set of PictureBuffers is required). 68bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// 69bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// TFPPictures are used for output, contents of VASurfaces passed from decoder 70bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// are put into the associated pixmap memory and sent to client. 71bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochclass VaapiVideoDecodeAccelerator::TFPPicture : public base::NonThreadSafe { 72bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch public: 73bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch ~TFPPicture(); 74bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 75bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch static linked_ptr<TFPPicture> Create( 7658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const base::Callback<bool(void)>& make_context_current, 77bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch const GLXFBConfig& fb_config, 78bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch Display* x_display, 79bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch int32 picture_buffer_id, 80bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch uint32 texture_id, 81bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch gfx::Size size); 82bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 83bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch int32 picture_buffer_id() { 84bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch return picture_buffer_id_; 85bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch } 86bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 87bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch gfx::Size size() { 880f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) return size_; 890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) } 90bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 91bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch int x_pixmap() { 92bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch return x_pixmap_; 93bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch } 94bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 95bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // Bind texture to pixmap. Needs to be called every frame. 96bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch bool Bind(); 97bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 9858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) private: 99bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch TFPPicture(const base::Callback<bool(void)>& make_context_current, 100bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch Display* x_display, 101bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch int32 picture_buffer_id, 102bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch uint32 texture_id, 103bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch gfx::Size size); 104bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 105bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch bool Initialize(const GLXFBConfig& fb_config); 106bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 1070f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) base::Callback<bool(void)> make_context_current_; 1080f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 109bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch Display* x_display_; 110bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 111bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // Output id for the client. 112bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch int32 picture_buffer_id_; 113bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch uint32 texture_id_; 114bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 115bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch gfx::Size size_; 116bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 11758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Pixmaps bound to this texture. 118bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch Pixmap x_pixmap_; 119bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch GLXPixmap glx_pixmap_; 120bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 121bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch DISALLOW_COPY_AND_ASSIGN(TFPPicture); 122bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}; 123bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 124bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochVaapiVideoDecodeAccelerator::TFPPicture::TFPPicture( 125bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch const base::Callback<bool(void)>& make_context_current, 126bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch Display* x_display, 127bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch int32 picture_buffer_id, 128bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch uint32 texture_id, 129bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch gfx::Size size) 130bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch : make_context_current_(make_context_current), 1310f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) x_display_(x_display), 132bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch picture_buffer_id_(picture_buffer_id), 1330f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) texture_id_(texture_id), 134bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch size_(size), 135bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch x_pixmap_(0), 136bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch glx_pixmap_(0) { 137bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch DCHECK(!make_context_current_.is_null()); 138bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}; 139bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 140bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochlinked_ptr<VaapiVideoDecodeAccelerator::TFPPicture> 141bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochVaapiVideoDecodeAccelerator::TFPPicture::Create( 14258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const base::Callback<bool(void)>& make_context_current, 143bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch const GLXFBConfig& fb_config, 144bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch Display* x_display, 145bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch int32 picture_buffer_id, 146bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch uint32 texture_id, 147bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch gfx::Size size) { 148bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 149bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch linked_ptr<TFPPicture> tfp_picture( 150bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch new TFPPicture(make_context_current, x_display, picture_buffer_id, 151bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch texture_id, size)); 152bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 153bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch if (!tfp_picture->Initialize(fb_config)) 154bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch tfp_picture.reset(); 155bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 156bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch return tfp_picture; 1570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)} 158bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 1590f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)bool VaapiVideoDecodeAccelerator::TFPPicture::Initialize( 160bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch const GLXFBConfig& fb_config) { 161bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch DCHECK(CalledOnValidThread()); 162bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch if (!make_context_current_.Run()) 163bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch return false; 164bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 165bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch XWindowAttributes win_attr; 166bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch int screen = DefaultScreen(x_display_); 167bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch XGetWindowAttributes(x_display_, RootWindow(x_display_, screen), &win_attr); 16858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) //TODO(posciak): pass the depth required by libva, not the RootWindow's depth 1690f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) x_pixmap_ = XCreatePixmap(x_display_, RootWindow(x_display_, screen), 1700f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) size_.width(), size_.height(), win_attr.depth); 1710f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) if (!x_pixmap_) { 1720f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) DVLOG(1) << "Failed creating an X Pixmap for TFP"; 1730f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) return false; 1740f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) } 1750f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 1760f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) static const int pixmap_attr[] = { 1770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, 1780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT, 1790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) GL_NONE, 1800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) }; 1810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 1820f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) glx_pixmap_ = glXCreatePixmap(x_display_, fb_config, x_pixmap_, pixmap_attr); 1830f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) if (!glx_pixmap_) { 1840f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) // x_pixmap_ will be freed in the destructor. 1850f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) DVLOG(1) << "Failed creating a GLX Pixmap for TFP"; 1860f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) return false; 1870f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) } 1880f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 1890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) return true; 1900f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)} 1910f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 1920f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)VaapiVideoDecodeAccelerator::TFPPicture::~TFPPicture() { 1930f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) DCHECK(CalledOnValidThread()); 1940f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) // Unbind surface from texture and deallocate resources. 1950f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) if (glx_pixmap_ && make_context_current_.Run()) { 1960f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) glXReleaseTexImageEXT(x_display_, glx_pixmap_, GLX_FRONT_LEFT_EXT); 1970f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) glXDestroyPixmap(x_display_, glx_pixmap_); 1980f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) } 1990f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 2000f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) if (x_pixmap_) 2010f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) XFreePixmap(x_display_, x_pixmap_); 2020f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) XSync(x_display_, False); // Needed to work around buggy vdpau-driver. 2030f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)} 2040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 2050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)bool VaapiVideoDecodeAccelerator::TFPPicture::Bind() { 2060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) DCHECK(CalledOnValidThread()); 2070f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) DCHECK(x_pixmap_); 2080f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) DCHECK(glx_pixmap_); 2090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) if (!make_context_current_.Run()) 2100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) return false; 2110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 2120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, texture_id_); 2130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) glXBindTexImageEXT(x_display_, glx_pixmap_, GLX_FRONT_LEFT_EXT, NULL); 2140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 2150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) return true; 2160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)} 2170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 2180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)VaapiVideoDecodeAccelerator::TFPPicture* 2190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) VaapiVideoDecodeAccelerator::TFPPictureById(int32 picture_buffer_id) { 2200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) TFPPictures::iterator it = tfp_pictures_.find(picture_buffer_id); 2210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) if (it == tfp_pictures_.end()) { 2220f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) DVLOG(1) << "Picture id " << picture_buffer_id << " does not exist"; 2230f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) return NULL; 2240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) } 2250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 2260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) return it->second.get(); 2270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)} 2280f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 2290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator( 2300f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) Display* x_display, 2310f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) const base::Callback<bool(void)>& make_context_current) 2320f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) : x_display_(x_display), 2330f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) make_context_current_(make_context_current), 2340f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) state_(kUninitialized), 2350f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) input_ready_(&lock_), 2360f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) surfaces_available_(&lock_), 2370f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) message_loop_(base::MessageLoop::current()), 23858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) decoder_thread_("VaapiDecoderThread"), 23958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) num_frames_at_client_(0), 24058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) num_stream_bufs_at_decoder_(0), 24158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) finish_flush_pending_(false), 24258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) awaiting_va_surfaces_recycle_(false), 24358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) requested_num_pics_(0), 2440f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) weak_this_factory_(this) { 24558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) weak_this_ = weak_this_factory_.GetWeakPtr(); 2460f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) va_surface_release_cb_ = media::BindToCurrentLoop( 24758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::Bind(&VaapiVideoDecodeAccelerator::RecycleVASurfaceID, weak_this_)); 24858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 24958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 25058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)VaapiVideoDecodeAccelerator::~VaapiVideoDecodeAccelerator() { 25158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK_EQ(message_loop_, base::MessageLoop::current()); 25258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 25358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 25458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)class XFreeDeleter { 25558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) public: 25658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) void operator()(void* x) const { 2570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) ::XFree(x); 25858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 2590f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}; 26058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 26158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool VaapiVideoDecodeAccelerator::InitializeFBConfig() { 26258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const int fbconfig_attr[] = { 26358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, 26458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT, 26558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) GLX_BIND_TO_TEXTURE_RGB_EXT, GL_TRUE, 26658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) GLX_Y_INVERTED_EXT, GL_TRUE, 26758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) GL_NONE, 268bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch }; 269bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 2700f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) int num_fbconfigs; 2710f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) scoped_ptr<GLXFBConfig, XFreeDeleter> glx_fb_configs( 2720f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) glXChooseFBConfig(x_display_, DefaultScreen(x_display_), fbconfig_attr, 2730f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) &num_fbconfigs)); 274bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch if (!glx_fb_configs) 2750f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) return false; 2760f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) if (!num_fbconfigs) 2770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) return false; 278bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 2790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) fb_config_ = glx_fb_configs.get()[0]; 2800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) return true; 2810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)} 2820f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 2830f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)bool VaapiVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, 2840f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) Client* client) { 2850f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) DCHECK_EQ(message_loop_, base::MessageLoop::current()); 2860f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 2870f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); 2880f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) client_ = client_ptr_factory_->GetWeakPtr(); 2890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 2900f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) base::AutoLock auto_lock(lock_); 2910f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) DCHECK_EQ(state_, kUninitialized); 2920f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) DVLOG(2) << "Initializing VAVDA, profile: " << profile; 2930f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 2940f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) if (!make_context_current_.Run()) 295bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch return false; 296bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 297bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch if (!InitializeFBConfig()) { 298bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch DVLOG(1) << "Could not get a usable FBConfig"; 299bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch return false; 300bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch } 3010f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 302bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch vaapi_wrapper_ = VaapiWrapper::Create( 303bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch VaapiWrapper::kDecode, 304bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch profile, 305bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch x_display_, 306bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch base::Bind(&ReportToUMA, content::VaapiH264Decoder::VAAPI_ERROR)); 307bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 308bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch if (!vaapi_wrapper_.get()) { 309bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch DVLOG(1) << "Failed initializing VAAPI"; 310bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch return false; 311bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch } 312bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 313bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch decoder_.reset( 314bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch new VaapiH264Decoder( 3150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) vaapi_wrapper_.get(), 316bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch media::BindToCurrentLoop(base::Bind( 3170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) &VaapiVideoDecodeAccelerator::SurfaceReady, weak_this_)), 318bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch base::Bind(&ReportToUMA))); 319bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 320bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch CHECK(decoder_thread_.Start()); 321bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch decoder_thread_proxy_ = decoder_thread_.message_loop_proxy(); 322bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 323bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch state_ = kIdle; 324bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch return true; 325bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch} 326bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 327bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochvoid VaapiVideoDecodeAccelerator::SurfaceReady( 328bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch int32 input_id, 3290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) const scoped_refptr<VASurface>& va_surface) { 330bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch DCHECK_EQ(message_loop_, base::MessageLoop::current()); 3310f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) DCHECK(!awaiting_va_surfaces_recycle_); 332bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 333bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // Drop any requests to output if we are resetting or being destroyed. 334bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch if (state_ == kResetting || state_ == kDestroying) 335bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch return; 336bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 337bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch pending_output_cbs_.push( 338bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch base::Bind(&VaapiVideoDecodeAccelerator::OutputPicture, 339bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch weak_this_, va_surface, input_id)); 340bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 341 TryOutputSurface(); 342} 343 344void VaapiVideoDecodeAccelerator::OutputPicture( 345 const scoped_refptr<VASurface>& va_surface, 346 int32 input_id, 347 TFPPicture* tfp_picture) { 348 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 349 350 int32 output_id = tfp_picture->picture_buffer_id(); 351 352 TRACE_EVENT2("Video Decoder", "VAVDA::OutputSurface", 353 "input_id", input_id, 354 "output_id", output_id); 355 356 DVLOG(3) << "Outputting VASurface " << va_surface->id() 357 << " into pixmap bound to picture buffer id " << output_id; 358 359 RETURN_AND_NOTIFY_ON_FAILURE(tfp_picture->Bind(), 360 "Failed binding texture to pixmap", 361 PLATFORM_FAILURE, ); 362 363 RETURN_AND_NOTIFY_ON_FAILURE( 364 vaapi_wrapper_->PutSurfaceIntoPixmap(va_surface->id(), 365 tfp_picture->x_pixmap(), 366 tfp_picture->size()), 367 "Failed putting surface into pixmap", PLATFORM_FAILURE, ); 368 369 // Notify the client a picture is ready to be displayed. 370 ++num_frames_at_client_; 371 TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_); 372 DVLOG(4) << "Notifying output picture id " << output_id 373 << " for input "<< input_id << " is ready"; 374 // TODO(posciak): Use visible size from decoder here instead 375 // (crbug.com/402760). 376 if (client_) 377 client_->PictureReady( 378 media::Picture(output_id, input_id, gfx::Rect(tfp_picture->size()))); 379} 380 381void VaapiVideoDecodeAccelerator::TryOutputSurface() { 382 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 383 384 // Handle Destroy() arriving while pictures are queued for output. 385 if (!client_) 386 return; 387 388 if (pending_output_cbs_.empty() || output_buffers_.empty()) 389 return; 390 391 OutputCB output_cb = pending_output_cbs_.front(); 392 pending_output_cbs_.pop(); 393 394 TFPPicture* tfp_picture = TFPPictureById(output_buffers_.front()); 395 DCHECK(tfp_picture); 396 output_buffers_.pop(); 397 398 output_cb.Run(tfp_picture); 399 400 if (finish_flush_pending_ && pending_output_cbs_.empty()) 401 FinishFlush(); 402} 403 404void VaapiVideoDecodeAccelerator::MapAndQueueNewInputBuffer( 405 const media::BitstreamBuffer& bitstream_buffer) { 406 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 407 TRACE_EVENT1("Video Decoder", "MapAndQueueNewInputBuffer", "input_id", 408 bitstream_buffer.id()); 409 410 DVLOG(4) << "Mapping new input buffer id: " << bitstream_buffer.id() 411 << " size: " << (int)bitstream_buffer.size(); 412 413 scoped_ptr<base::SharedMemory> shm( 414 new base::SharedMemory(bitstream_buffer.handle(), true)); 415 RETURN_AND_NOTIFY_ON_FAILURE(shm->Map(bitstream_buffer.size()), 416 "Failed to map input buffer", UNREADABLE_INPUT,); 417 418 base::AutoLock auto_lock(lock_); 419 420 // Set up a new input buffer and queue it for later. 421 linked_ptr<InputBuffer> input_buffer(new InputBuffer()); 422 input_buffer->shm.reset(shm.release()); 423 input_buffer->id = bitstream_buffer.id(); 424 input_buffer->size = bitstream_buffer.size(); 425 426 ++num_stream_bufs_at_decoder_; 427 TRACE_COUNTER1("Video Decoder", "Stream buffers at decoder", 428 num_stream_bufs_at_decoder_); 429 430 input_buffers_.push(input_buffer); 431 input_ready_.Signal(); 432} 433 434bool VaapiVideoDecodeAccelerator::GetInputBuffer_Locked() { 435 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread()); 436 lock_.AssertAcquired(); 437 438 if (curr_input_buffer_.get()) 439 return true; 440 441 // Will only wait if it is expected that in current state new buffers will 442 // be queued from the client via Decode(). The state can change during wait. 443 while (input_buffers_.empty() && (state_ == kDecoding || state_ == kIdle)) { 444 input_ready_.Wait(); 445 } 446 447 // We could have got woken up in a different state or never got to sleep 448 // due to current state; check for that. 449 switch (state_) { 450 case kFlushing: 451 // Here we are only interested in finishing up decoding buffers that are 452 // already queued up. Otherwise will stop decoding. 453 if (input_buffers_.empty()) 454 return false; 455 // else fallthrough 456 case kDecoding: 457 case kIdle: 458 DCHECK(!input_buffers_.empty()); 459 460 curr_input_buffer_ = input_buffers_.front(); 461 input_buffers_.pop(); 462 463 DVLOG(4) << "New current bitstream buffer, id: " 464 << curr_input_buffer_->id 465 << " size: " << curr_input_buffer_->size; 466 467 decoder_->SetStream( 468 static_cast<uint8*>(curr_input_buffer_->shm->memory()), 469 curr_input_buffer_->size, curr_input_buffer_->id); 470 return true; 471 472 default: 473 // We got woken up due to being destroyed/reset, ignore any already 474 // queued inputs. 475 return false; 476 } 477} 478 479void VaapiVideoDecodeAccelerator::ReturnCurrInputBuffer_Locked() { 480 lock_.AssertAcquired(); 481 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread()); 482 DCHECK(curr_input_buffer_.get()); 483 484 int32 id = curr_input_buffer_->id; 485 curr_input_buffer_.reset(); 486 DVLOG(4) << "End of input buffer " << id; 487 message_loop_->PostTask(FROM_HERE, base::Bind( 488 &Client::NotifyEndOfBitstreamBuffer, client_, id)); 489 490 --num_stream_bufs_at_decoder_; 491 TRACE_COUNTER1("Video Decoder", "Stream buffers at decoder", 492 num_stream_bufs_at_decoder_); 493} 494 495bool VaapiVideoDecodeAccelerator::FeedDecoderWithOutputSurfaces_Locked() { 496 lock_.AssertAcquired(); 497 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread()); 498 499 while (available_va_surfaces_.empty() && 500 (state_ == kDecoding || state_ == kFlushing || state_ == kIdle)) { 501 surfaces_available_.Wait(); 502 } 503 504 if (state_ != kDecoding && state_ != kFlushing && state_ != kIdle) 505 return false; 506 507 while (!available_va_surfaces_.empty()) { 508 scoped_refptr<VASurface> va_surface( 509 new VASurface(available_va_surfaces_.front(), va_surface_release_cb_)); 510 available_va_surfaces_.pop_front(); 511 decoder_->ReuseSurface(va_surface); 512 } 513 514 return true; 515} 516 517void VaapiVideoDecodeAccelerator::DecodeTask() { 518 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread()); 519 TRACE_EVENT0("Video Decoder", "VAVDA::DecodeTask"); 520 base::AutoLock auto_lock(lock_); 521 522 if (state_ != kDecoding) 523 return; 524 525 // Main decode task. 526 DVLOG(4) << "Decode task"; 527 528 // Try to decode what stream data is (still) in the decoder until we run out 529 // of it. 530 while (GetInputBuffer_Locked()) { 531 DCHECK(curr_input_buffer_.get()); 532 533 VaapiH264Decoder::DecResult res; 534 { 535 // We are OK releasing the lock here, as decoder never calls our methods 536 // directly and we will reacquire the lock before looking at state again. 537 // This is the main decode function of the decoder and while keeping 538 // the lock for its duration would be fine, it would defeat the purpose 539 // of having a separate decoder thread. 540 base::AutoUnlock auto_unlock(lock_); 541 res = decoder_->Decode(); 542 } 543 544 switch (res) { 545 case VaapiH264Decoder::kAllocateNewSurfaces: 546 DVLOG(1) << "Decoder requesting a new set of surfaces"; 547 message_loop_->PostTask(FROM_HERE, base::Bind( 548 &VaapiVideoDecodeAccelerator::InitiateSurfaceSetChange, weak_this_, 549 decoder_->GetRequiredNumOfPictures(), 550 decoder_->GetPicSize())); 551 // We'll get rescheduled once ProvidePictureBuffers() finishes. 552 return; 553 554 case VaapiH264Decoder::kRanOutOfStreamData: 555 ReturnCurrInputBuffer_Locked(); 556 break; 557 558 case VaapiH264Decoder::kRanOutOfSurfaces: 559 // No more output buffers in the decoder, try getting more or go to 560 // sleep waiting for them. 561 if (!FeedDecoderWithOutputSurfaces_Locked()) 562 return; 563 564 break; 565 566 case VaapiH264Decoder::kDecodeError: 567 RETURN_AND_NOTIFY_ON_FAILURE(false, "Error decoding stream", 568 PLATFORM_FAILURE, ); 569 return; 570 } 571 } 572} 573 574void VaapiVideoDecodeAccelerator::InitiateSurfaceSetChange(size_t num_pics, 575 gfx::Size size) { 576 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 577 DCHECK(!awaiting_va_surfaces_recycle_); 578 579 // At this point decoder has stopped running and has already posted onto our 580 // loop any remaining output request callbacks, which executed before we got 581 // here. Some of them might have been pended though, because we might not 582 // have had enough TFPictures to output surfaces to. Initiate a wait cycle, 583 // which will wait for client to return enough PictureBuffers to us, so that 584 // we can finish all pending output callbacks, releasing associated surfaces. 585 DVLOG(1) << "Initiating surface set change"; 586 awaiting_va_surfaces_recycle_ = true; 587 588 requested_num_pics_ = num_pics; 589 requested_pic_size_ = size; 590 591 TryFinishSurfaceSetChange(); 592} 593 594void VaapiVideoDecodeAccelerator::TryFinishSurfaceSetChange() { 595 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 596 597 if (!awaiting_va_surfaces_recycle_) 598 return; 599 600 if (!pending_output_cbs_.empty() || 601 tfp_pictures_.size() != available_va_surfaces_.size()) { 602 // Either: 603 // 1. Not all pending pending output callbacks have been executed yet. 604 // Wait for the client to return enough pictures and retry later. 605 // 2. The above happened and all surface release callbacks have been posted 606 // as the result, but not all have executed yet. Post ourselves after them 607 // to let them release surfaces. 608 DVLOG(2) << "Awaiting pending output/surface release callbacks to finish"; 609 message_loop_->PostTask(FROM_HERE, base::Bind( 610 &VaapiVideoDecodeAccelerator::TryFinishSurfaceSetChange, weak_this_)); 611 return; 612 } 613 614 // All surfaces released, destroy them and dismiss all PictureBuffers. 615 awaiting_va_surfaces_recycle_ = false; 616 available_va_surfaces_.clear(); 617 vaapi_wrapper_->DestroySurfaces(); 618 619 for (TFPPictures::iterator iter = tfp_pictures_.begin(); 620 iter != tfp_pictures_.end(); ++iter) { 621 DVLOG(2) << "Dismissing picture id: " << iter->first; 622 if (client_) 623 client_->DismissPictureBuffer(iter->first); 624 } 625 tfp_pictures_.clear(); 626 627 // And ask for a new set as requested. 628 DVLOG(1) << "Requesting " << requested_num_pics_ << " pictures of size: " 629 << requested_pic_size_.ToString(); 630 631 message_loop_->PostTask(FROM_HERE, base::Bind( 632 &Client::ProvidePictureBuffers, client_, 633 requested_num_pics_, requested_pic_size_, GL_TEXTURE_2D)); 634} 635 636void VaapiVideoDecodeAccelerator::Decode( 637 const media::BitstreamBuffer& bitstream_buffer) { 638 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 639 640 TRACE_EVENT1("Video Decoder", "VAVDA::Decode", "Buffer id", 641 bitstream_buffer.id()); 642 643 // We got a new input buffer from the client, map it and queue for later use. 644 MapAndQueueNewInputBuffer(bitstream_buffer); 645 646 base::AutoLock auto_lock(lock_); 647 switch (state_) { 648 case kIdle: 649 state_ = kDecoding; 650 decoder_thread_proxy_->PostTask(FROM_HERE, base::Bind( 651 &VaapiVideoDecodeAccelerator::DecodeTask, 652 base::Unretained(this))); 653 break; 654 655 case kDecoding: 656 // Decoder already running, fallthrough. 657 case kResetting: 658 // When resetting, allow accumulating bitstream buffers, so that 659 // the client can queue after-seek-buffers while we are finishing with 660 // the before-seek one. 661 break; 662 663 default: 664 RETURN_AND_NOTIFY_ON_FAILURE(false, 665 "Decode request from client in invalid state: " << state_, 666 PLATFORM_FAILURE, ); 667 break; 668 } 669} 670 671void VaapiVideoDecodeAccelerator::RecycleVASurfaceID( 672 VASurfaceID va_surface_id) { 673 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 674 base::AutoLock auto_lock(lock_); 675 676 available_va_surfaces_.push_back(va_surface_id); 677 surfaces_available_.Signal(); 678} 679 680void VaapiVideoDecodeAccelerator::AssignPictureBuffers( 681 const std::vector<media::PictureBuffer>& buffers) { 682 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 683 684 base::AutoLock auto_lock(lock_); 685 DCHECK(tfp_pictures_.empty()); 686 687 while (!output_buffers_.empty()) 688 output_buffers_.pop(); 689 690 RETURN_AND_NOTIFY_ON_FAILURE( 691 buffers.size() == requested_num_pics_, 692 "Got an invalid number of picture buffers. (Got " << buffers.size() 693 << ", requested " << requested_num_pics_ << ")", INVALID_ARGUMENT, ); 694 DCHECK(requested_pic_size_ == buffers[0].size()); 695 696 std::vector<VASurfaceID> va_surface_ids; 697 RETURN_AND_NOTIFY_ON_FAILURE( 698 vaapi_wrapper_->CreateSurfaces(requested_pic_size_, 699 buffers.size(), 700 &va_surface_ids), 701 "Failed creating VA Surfaces", PLATFORM_FAILURE, ); 702 DCHECK_EQ(va_surface_ids.size(), buffers.size()); 703 704 for (size_t i = 0; i < buffers.size(); ++i) { 705 DVLOG(2) << "Assigning picture id: " << buffers[i].id() 706 << " to texture id: " << buffers[i].texture_id() 707 << " VASurfaceID: " << va_surface_ids[i]; 708 709 linked_ptr<TFPPicture> tfp_picture( 710 TFPPicture::Create(make_context_current_, fb_config_, x_display_, 711 buffers[i].id(), buffers[i].texture_id(), 712 requested_pic_size_)); 713 714 RETURN_AND_NOTIFY_ON_FAILURE( 715 tfp_picture.get(), "Failed assigning picture buffer to a texture.", 716 PLATFORM_FAILURE, ); 717 718 bool inserted = tfp_pictures_.insert(std::make_pair( 719 buffers[i].id(), tfp_picture)).second; 720 DCHECK(inserted); 721 722 output_buffers_.push(buffers[i].id()); 723 available_va_surfaces_.push_back(va_surface_ids[i]); 724 surfaces_available_.Signal(); 725 } 726 727 state_ = kDecoding; 728 decoder_thread_proxy_->PostTask(FROM_HERE, base::Bind( 729 &VaapiVideoDecodeAccelerator::DecodeTask, base::Unretained(this))); 730} 731 732void VaapiVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { 733 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 734 TRACE_EVENT1("Video Decoder", "VAVDA::ReusePictureBuffer", "Picture id", 735 picture_buffer_id); 736 737 --num_frames_at_client_; 738 TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_); 739 740 output_buffers_.push(picture_buffer_id); 741 TryOutputSurface(); 742} 743 744void VaapiVideoDecodeAccelerator::FlushTask() { 745 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread()); 746 DVLOG(1) << "Flush task"; 747 748 // First flush all the pictures that haven't been outputted, notifying the 749 // client to output them. 750 bool res = decoder_->Flush(); 751 RETURN_AND_NOTIFY_ON_FAILURE(res, "Failed flushing the decoder.", 752 PLATFORM_FAILURE, ); 753 754 // Put the decoder in idle state, ready to resume. 755 decoder_->Reset(); 756 757 message_loop_->PostTask(FROM_HERE, base::Bind( 758 &VaapiVideoDecodeAccelerator::FinishFlush, weak_this_)); 759} 760 761void VaapiVideoDecodeAccelerator::Flush() { 762 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 763 DVLOG(1) << "Got flush request"; 764 765 base::AutoLock auto_lock(lock_); 766 state_ = kFlushing; 767 // Queue a flush task after all existing decoding tasks to clean up. 768 decoder_thread_proxy_->PostTask(FROM_HERE, base::Bind( 769 &VaapiVideoDecodeAccelerator::FlushTask, base::Unretained(this))); 770 771 input_ready_.Signal(); 772 surfaces_available_.Signal(); 773} 774 775void VaapiVideoDecodeAccelerator::FinishFlush() { 776 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 777 778 finish_flush_pending_ = false; 779 780 base::AutoLock auto_lock(lock_); 781 if (state_ != kFlushing) { 782 DCHECK_EQ(state_, kDestroying); 783 return; // We could've gotten destroyed already. 784 } 785 786 // Still waiting for textures from client to finish outputting all pending 787 // frames. Try again later. 788 if (!pending_output_cbs_.empty()) { 789 finish_flush_pending_ = true; 790 return; 791 } 792 793 state_ = kIdle; 794 795 message_loop_->PostTask(FROM_HERE, base::Bind( 796 &Client::NotifyFlushDone, client_)); 797 798 DVLOG(1) << "Flush finished"; 799} 800 801void VaapiVideoDecodeAccelerator::ResetTask() { 802 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread()); 803 DVLOG(1) << "ResetTask"; 804 805 // All the decoding tasks from before the reset request from client are done 806 // by now, as this task was scheduled after them and client is expected not 807 // to call Decode() after Reset() and before NotifyResetDone. 808 decoder_->Reset(); 809 810 base::AutoLock auto_lock(lock_); 811 812 // Return current input buffer, if present. 813 if (curr_input_buffer_.get()) 814 ReturnCurrInputBuffer_Locked(); 815 816 // And let client know that we are done with reset. 817 message_loop_->PostTask(FROM_HERE, base::Bind( 818 &VaapiVideoDecodeAccelerator::FinishReset, weak_this_)); 819} 820 821void VaapiVideoDecodeAccelerator::Reset() { 822 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 823 DVLOG(1) << "Got reset request"; 824 825 // This will make any new decode tasks exit early. 826 base::AutoLock auto_lock(lock_); 827 state_ = kResetting; 828 finish_flush_pending_ = false; 829 830 // Drop all remaining input buffers, if present. 831 while (!input_buffers_.empty()) { 832 message_loop_->PostTask(FROM_HERE, base::Bind( 833 &Client::NotifyEndOfBitstreamBuffer, client_, 834 input_buffers_.front()->id)); 835 input_buffers_.pop(); 836 } 837 838 decoder_thread_proxy_->PostTask(FROM_HERE, base::Bind( 839 &VaapiVideoDecodeAccelerator::ResetTask, base::Unretained(this))); 840 841 input_ready_.Signal(); 842 surfaces_available_.Signal(); 843} 844 845void VaapiVideoDecodeAccelerator::FinishReset() { 846 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 847 DVLOG(1) << "FinishReset"; 848 base::AutoLock auto_lock(lock_); 849 850 if (state_ != kResetting) { 851 DCHECK(state_ == kDestroying || state_ == kUninitialized) << state_; 852 return; // We could've gotten destroyed already. 853 } 854 855 // Drop pending outputs. 856 while (!pending_output_cbs_.empty()) 857 pending_output_cbs_.pop(); 858 859 if (awaiting_va_surfaces_recycle_) { 860 // Decoder requested a new surface set while we were waiting for it to 861 // finish the last DecodeTask, running at the time of Reset(). 862 // Let the surface set change finish first before resetting. 863 message_loop_->PostTask(FROM_HERE, base::Bind( 864 &VaapiVideoDecodeAccelerator::FinishReset, weak_this_)); 865 return; 866 } 867 868 num_stream_bufs_at_decoder_ = 0; 869 state_ = kIdle; 870 871 message_loop_->PostTask(FROM_HERE, base::Bind( 872 &Client::NotifyResetDone, client_)); 873 874 // The client might have given us new buffers via Decode() while we were 875 // resetting and might be waiting for our move, and not call Decode() anymore 876 // until we return something. Post a DecodeTask() so that we won't 877 // sleep forever waiting for Decode() in that case. Having two of them 878 // in the pipe is harmless, the additional one will return as soon as it sees 879 // that we are back in kDecoding state. 880 if (!input_buffers_.empty()) { 881 state_ = kDecoding; 882 decoder_thread_proxy_->PostTask(FROM_HERE, base::Bind( 883 &VaapiVideoDecodeAccelerator::DecodeTask, 884 base::Unretained(this))); 885 } 886 887 DVLOG(1) << "Reset finished"; 888} 889 890void VaapiVideoDecodeAccelerator::Cleanup() { 891 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 892 893 if (state_ == kUninitialized || state_ == kDestroying) 894 return; 895 896 DVLOG(1) << "Destroying VAVDA"; 897 base::AutoLock auto_lock(lock_); 898 state_ = kDestroying; 899 900 client_ptr_factory_.reset(); 901 weak_this_factory_.InvalidateWeakPtrs(); 902 903 // Signal all potential waiters on the decoder_thread_, let them early-exit, 904 // as we've just moved to the kDestroying state, and wait for all tasks 905 // to finish. 906 input_ready_.Signal(); 907 surfaces_available_.Signal(); 908 { 909 base::AutoUnlock auto_unlock(lock_); 910 decoder_thread_.Stop(); 911 } 912 913 state_ = kUninitialized; 914} 915 916void VaapiVideoDecodeAccelerator::Destroy() { 917 DCHECK_EQ(message_loop_, base::MessageLoop::current()); 918 Cleanup(); 919 delete this; 920} 921 922bool VaapiVideoDecodeAccelerator::CanDecodeOnIOThread() { 923 return false; 924} 925 926} // namespace content 927