Index: content/common/gpu/media/vaapi_video_decode_accelerator.cc |
diff --git a/content/common/gpu/media/vaapi_video_decode_accelerator.cc b/content/common/gpu/media/vaapi_video_decode_accelerator.cc |
index a401ef64ab3eef04fa67fc7660aaf0995859364d..719d199dc84b7224d2c3c4d8c2c3251c7edd577b 100644 |
--- a/content/common/gpu/media/vaapi_video_decode_accelerator.cc |
+++ b/content/common/gpu/media/vaapi_video_decode_accelerator.cc |
@@ -3,20 +3,30 @@ |
// found in the LICENSE file. |
#include "base/bind.h" |
-#include "base/command_line.h" |
#include "base/debug/trace_event.h" |
#include "base/logging.h" |
+#include "base/metrics/histogram.h" |
#include "base/stl_util.h" |
#include "base/string_util.h" |
#include "base/synchronization/waitable_event.h" |
-#include "gpu/command_buffer/service/gpu_switches.h" |
-#include "content/public/common/content_switches.h" |
#include "content/common/gpu/gpu_channel.h" |
#include "content/common/gpu/media/vaapi_video_decode_accelerator.h" |
#include "media/base/bind_to_loop.h" |
#include "media/video/picture.h" |
-#include "third_party/libva/va/va.h" |
#include "ui/gl/gl_bindings.h" |
+#include "ui/gl/scoped_binders.h" |
+ |
+namespace { |
Ami GONE FROM CHROMIUM
2013/05/17 23:19:15
pointless
Pawel Osciak
2013/05/21 22:32:35
Even if at some point a global ReportToUMA() surfa
Ami GONE FROM CHROMIUM
2013/05/22 23:59:47
Anything global in the future should be namespaced
Pawel Osciak
2013/05/24 01:46:39
Done.
|
+ |
+static void ReportToUMA( |
+ content::VaapiH264Decoder::VAVDAH264DecoderFailure failure) { |
+ UMA_HISTOGRAM_ENUMERATION( |
+ "Media.VAVDAH264.DecoderFailure", |
Ami GONE FROM CHROMIUM
2013/05/17 23:19:15
This is clearly a decoder thing, not a VAVDA thing
Pawel Osciak
2013/05/21 22:32:35
Yeah, I hate it too, but didn't see a better way t
|
+ failure, |
+ content::VaapiH264Decoder::VAVDA_H264_DECODER_FAILURES_MAX); |
+} |
+ |
+} // namespace |
namespace content { |
@@ -54,6 +64,175 @@ void VaapiVideoDecodeAccelerator::NotifyError(Error error) { |
} |
} |
+class VaapiVideoDecodeAccelerator::TFPPicture { |
+ public: |
+ ~TFPPicture(); |
+ |
+ static linked_ptr<TFPPicture> Create( |
+ const base::Callback<bool(void)>& make_context_current, |
+ const GLXFBConfig& fb_config, |
+ Display* x_display, |
+ int32 picture_buffer_id, |
+ uint32 texture_id, |
+ int width, int height); |
+ |
+ int32 picture_buffer_id() { |
Ami GONE FROM CHROMIUM
2013/05/17 23:19:15
Please rationalize order of ctor args, getters, an
Pawel Osciak
2013/05/21 22:32:35
Not really anything in particular, but getters are
|
+ return picture_buffer_id_; |
+ } |
+ |
+ uint32 texture_id() { |
+ return texture_id_; |
+ } |
+ |
+ int width() { |
+ return width_; |
+ } |
+ |
+ int height() { |
+ return height_; |
+ } |
+ |
+ int x_pixmap() { |
+ return x_pixmap_; |
+ } |
+ |
+ // Bind texture to pixmap. Needs to be called every frame. |
+ bool Bind(); |
+ |
+ private: |
+ TFPPicture(const base::Callback<bool(void)>& make_context_current, |
+ Display* x_display, |
+ int32 picture_buffer_id, |
+ uint32 texture_id, |
+ int width, int height); |
+ |
+ bool Initialize(const GLXFBConfig& fb_config); |
+ |
+ base::Callback<bool(void)> make_context_current_; |
+ |
+ // Output id for the client. |
+ int32 picture_buffer_id_; |
+ uint32 texture_id_; |
+ |
+ int width_; |
+ int height_; |
+ |
+ Display* x_display_; |
+ |
+ // Pixmaps bound to this texture. |
+ Pixmap x_pixmap_; |
+ GLXPixmap glx_pixmap_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(TFPPicture); |
+}; |
+ |
+VaapiVideoDecodeAccelerator::TFPPicture::TFPPicture( |
+ const base::Callback<bool(void)>& make_context_current, |
+ Display* x_display, |
+ int32 picture_buffer_id, |
+ uint32 texture_id, |
+ int width, int height) |
+ : make_context_current_(make_context_current), |
+ picture_buffer_id_(picture_buffer_id), |
Ami GONE FROM CHROMIUM
2013/05/17 23:19:15
indent here and below
Pawel Osciak
2013/05/21 22:32:35
Done.
|
+ texture_id_(texture_id), |
+ width_(width), |
+ height_(height), |
+ x_display_(x_display), |
+ x_pixmap_(0), |
+ glx_pixmap_(0) { |
+ DCHECK(!make_context_current_.is_null()); |
+}; |
+ |
+linked_ptr<VaapiVideoDecodeAccelerator::TFPPicture> |
+VaapiVideoDecodeAccelerator::TFPPicture::Create( |
+ const base::Callback<bool(void)>& make_context_current, |
+ const GLXFBConfig& fb_config, |
+ Display* x_display, |
+ int32 picture_buffer_id, |
+ uint32 texture_id, |
+ int width, int height) { |
+ |
+ linked_ptr<TFPPicture> tfp_picture( |
+ new TFPPicture(make_context_current, x_display, picture_buffer_id, |
+ texture_id, width, height)); |
+ |
+ if (!tfp_picture->Initialize(fb_config)) |
+ tfp_picture.reset(); |
+ |
+ return tfp_picture; |
+} |
+ |
+bool VaapiVideoDecodeAccelerator::TFPPicture::Initialize( |
+ const GLXFBConfig& fb_config) { |
+ if (!make_context_current_.Run()) |
+ return false; |
+ |
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
+ |
+ XWindowAttributes win_attr; |
+ int screen = DefaultScreen(x_display_); |
+ XGetWindowAttributes(x_display_, RootWindow(x_display_, screen), &win_attr); |
+ //TODO(posciak): pass the depth required by libva, not the RootWindow's depth |
+ x_pixmap_ = XCreatePixmap(x_display_, RootWindow(x_display_, screen), |
+ width_, height_, win_attr.depth); |
+ if (!x_pixmap_) { |
+ DVLOG(1) << "Failed creating an X Pixmap for TFP"; |
+ return NULL; |
+ } |
+ |
+ static const int pixmap_attr[] = { |
+ GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, |
+ GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT, |
+ GL_NONE, |
+ }; |
+ |
+ glx_pixmap_ = glXCreatePixmap(x_display_, fb_config, x_pixmap_, pixmap_attr); |
+ if (!glx_pixmap_) { |
+ // x_pixmap_ will be freed in the destructor. |
+ DVLOG(1) << "Failed creating a GLX Pixmap for TFP"; |
+ return NULL; |
+ } |
+ |
+ return true; |
+} |
+ |
+VaapiVideoDecodeAccelerator::TFPPicture::~TFPPicture() { |
+ // Unbind surface from texture and deallocate resources. |
+ if (glx_pixmap_ && make_context_current_.Run()) { |
+ glXReleaseTexImageEXT(x_display_, glx_pixmap_, GLX_FRONT_LEFT_EXT); |
+ glXDestroyPixmap(x_display_, glx_pixmap_); |
+ } |
+ |
+ if (x_pixmap_) |
+ XFreePixmap(x_display_, x_pixmap_); |
+ XSync(x_display_, False); // Needed to work around buggy vdpau-driver. |
+} |
+ |
+bool VaapiVideoDecodeAccelerator::TFPPicture::Bind() { |
+ DCHECK(x_pixmap_); |
+ DCHECK(glx_pixmap_); |
+ |
+ if (!make_context_current_.Run()) |
+ return false; |
+ |
+ gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, texture_id_); |
Ami GONE FROM CHROMIUM
2013/05/17 23:19:15
Is it really correct to have this be scoped to jus
Pawel Osciak
2013/05/21 22:32:35
No. This saves the texture that was bound (current
|
+ glXBindTexImageEXT(x_display_, glx_pixmap_, GLX_FRONT_LEFT_EXT, NULL); |
+ |
+ return true; |
+} |
+ |
+VaapiVideoDecodeAccelerator::TFPPicture* |
+ VaapiVideoDecodeAccelerator::TFPPictureById(int32 picture_buffer_id) { |
+ TFPPictures::iterator it = tfp_pictures_.find(picture_buffer_id); |
+ if (it == tfp_pictures_.end()) { |
+ DVLOG(1) << "Picture id " << picture_buffer_id << " does not exist"; |
+ return NULL; |
+ } |
+ |
+ return it->second.get(); |
+} |
+ |
VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator( |
Display* x_display, GLXContext glx_context, |
Client* client, |
@@ -63,7 +242,7 @@ VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator( |
make_context_current_(make_context_current), |
state_(kUninitialized), |
input_ready_(&lock_), |
- output_ready_(&lock_), |
+ surfaces_available_(&lock_), |
message_loop_(base::MessageLoop::current()), |
weak_this_(base::AsWeakPtr(this)), |
client_ptr_factory_(client), |
@@ -72,16 +251,41 @@ VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator( |
num_frames_at_client_(0), |
num_stream_bufs_at_decoder_(0) { |
DCHECK(client); |
- static bool vaapi_functions_initialized = PostSandboxInitialization(); |
- RETURN_AND_NOTIFY_ON_FAILURE(vaapi_functions_initialized, |
- "Failed to initialize VAAPI libs", |
- PLATFORM_FAILURE, ); |
} |
VaapiVideoDecodeAccelerator::~VaapiVideoDecodeAccelerator() { |
DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
} |
+class ScopedPtrXFree { |
+ public: |
+ void operator()(void* x) const { |
+ ::XFree(x); |
+ } |
+}; |
+ |
+bool VaapiVideoDecodeAccelerator::InitializeFBConfig() { |
+ const int fbconfig_attr[] = { |
+ GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, |
+ GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT, |
+ GLX_BIND_TO_TEXTURE_RGB_EXT, GL_TRUE, |
+ GLX_Y_INVERTED_EXT, GL_TRUE, |
+ GL_NONE, |
+ }; |
+ |
+ int num_fbconfigs; |
+ scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> glx_fb_configs( |
+ glXChooseFBConfig(x_display_, DefaultScreen(x_display_), fbconfig_attr, |
+ &num_fbconfigs)); |
+ if (!glx_fb_configs) |
+ return false; |
+ if (!num_fbconfigs) |
+ return false; |
+ |
+ fb_config_ = glx_fb_configs.get()[0]; |
+ return true; |
+} |
+ |
bool VaapiVideoDecodeAccelerator::Initialize( |
media::VideoCodecProfile profile) { |
DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
@@ -90,17 +294,30 @@ bool VaapiVideoDecodeAccelerator::Initialize( |
DCHECK_EQ(state_, kUninitialized); |
DVLOG(2) << "Initializing VAVDA, profile: " << profile; |
- bool res = decoder_.Initialize( |
- profile, x_display_, glx_context_, make_context_current_, |
- media::BindToLoop(message_loop_->message_loop_proxy(), base::Bind( |
- &VaapiVideoDecodeAccelerator::NotifyPictureReady, weak_this_)), |
- media::BindToLoop(message_loop_->message_loop_proxy(), base::Bind( |
- &VaapiVideoDecodeAccelerator::SubmitDecode, weak_this_))); |
- if (!res) { |
- DVLOG(1) << "Failed initializing decoder"; |
+ if (!make_context_current_.Run()) |
+ return false; |
+ |
+ if (!InitializeFBConfig()) { |
+ DVLOG(1) << "Could not get a usable FBConfig"; |
return false; |
} |
+ vaapi_delegate_ = VaapiDelegate::Create( |
+ profile, x_display_, |
+ base::Bind(&ReportToUMA, content::VaapiH264Decoder::VAAPI_ERROR)); |
+ |
+ if (!vaapi_delegate_.get()) { |
+ DVLOG(1) << "Failed initializing VAAPI"; |
+ return false; |
+ } |
+ |
+ decoder_.reset( |
+ new VaapiH264Decoder( |
+ vaapi_delegate_, |
+ media::BindToLoop(message_loop_->message_loop_proxy(), base::Bind( |
+ &VaapiVideoDecodeAccelerator::SurfaceReady, weak_this_)), |
+ base::Bind(&ReportToUMA))); |
+ |
CHECK(decoder_thread_.Start()); |
state_ = kInitialized; |
@@ -110,55 +327,84 @@ bool VaapiVideoDecodeAccelerator::Initialize( |
return true; |
} |
-void VaapiVideoDecodeAccelerator::SubmitDecode( |
- int32 output_id, |
- scoped_ptr<std::queue<VABufferID> > va_bufs, |
- scoped_ptr<std::queue<VABufferID> > slice_bufs) { |
+void VaapiVideoDecodeAccelerator::SyncSurfaceToPicture( |
+ VASurfaceID va_surface_id, |
+ TFPPicture* tfp_picture) { |
DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
- base::AutoLock auto_lock(lock_); |
- |
- TRACE_EVENT1("Video Decoder", "VAVDA::Decode", "output_id", output_id); |
- // Handle Destroy() arriving while pictures are queued for output. |
- if (!client_) |
- return; |
+ RETURN_AND_NOTIFY_ON_FAILURE(tfp_picture->Bind(), |
+ "Failed binding texture to pixmap", |
+ PLATFORM_FAILURE, ); |
RETURN_AND_NOTIFY_ON_FAILURE( |
- decoder_.SubmitDecode(output_id, va_bufs.Pass(), slice_bufs.Pass()), |
- "Failed putting picture to texture", |
- PLATFORM_FAILURE, ); |
+ vaapi_delegate_->PutSurfaceIntoPixmap(va_surface_id, |
+ tfp_picture->x_pixmap(), |
+ tfp_picture->width(), |
+ tfp_picture->height()), |
+ "Failed putting surface into pixmap", PLATFORM_FAILURE, ); |
} |
-void VaapiVideoDecodeAccelerator::NotifyPictureReady(int32 input_id, |
- int32 output_id) { |
+void VaapiVideoDecodeAccelerator::SurfaceReady( |
+ int32 input_id, |
+ const scoped_refptr<VASurface>& va_surface) { |
DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
- TRACE_EVENT2("Video Decoder", "VAVDA::NotifyPictureReady", |
- "input_id", input_id, "output_id", output_id); |
- // Handle Destroy() arriving while pictures are queued for output. |
- if (!client_) |
+ // Drop any requests to output if we are resetting. |
+ if (state_ == kResetting || state_ == kDestroying) |
return; |
- // Don't return any pictures that we might want to return during resetting |
- // as a consequence of finishing up the decode that was running during |
- // Reset() call from the client. Reuse it instead. |
- { |
- base::AutoLock auto_lock(lock_); |
- if (state_ == kResetting) { |
- output_buffers_.push(output_id); |
- return; |
- } |
- } |
+ pending_output_cbs_.push( |
+ base::Bind(&VaapiVideoDecodeAccelerator::OutputPicture, |
+ weak_this_, va_surface, input_id)); |
- ++num_frames_at_client_; |
- TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_); |
+ TryOutputSurface(); |
+} |
+ |
+void VaapiVideoDecodeAccelerator::OutputPicture( |
+ const scoped_refptr<VASurface>& va_surface, |
+ int32 input_id, |
+ TFPPicture* tfp_picture) { |
+ DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
+ |
+ int32 output_id = tfp_picture->picture_buffer_id(); |
+ |
+ TRACE_EVENT2("Video Decoder", "VAVDA::OutputSurface", |
+ "input_id", input_id, |
+ "output_id", output_id); |
+ |
+ DVLOG(3) << "Outputting VASurface " << va_surface->id() |
+ << " into pixmap bound to picture buffer id " << output_id; |
+ |
+ SyncSurfaceToPicture(va_surface->id(), tfp_picture); |
// Notify the client a picture is ready to be displayed. |
+ ++num_frames_at_client_; |
+ TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_); |
DVLOG(4) << "Notifying output picture id " << output_id |
<< " for input "<< input_id << " is ready"; |
client_->PictureReady(media::Picture(output_id, input_id)); |
} |
+void VaapiVideoDecodeAccelerator::TryOutputSurface() { |
+ DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
+ |
+ // Handle Destroy() arriving while pictures are queued for output. |
+ if (!client_) |
+ return; |
+ |
+ if (pending_output_cbs_.empty() || output_buffers_.empty()) |
+ return; |
+ |
+ OutputCB output_cb = pending_output_cbs_.front(); |
+ pending_output_cbs_.pop(); |
+ |
+ TFPPicture* tfp_picture = TFPPictureById(output_buffers_.front()); |
+ DCHECK(tfp_picture); |
+ output_buffers_.pop(); |
+ |
+ output_cb.Run(tfp_picture); |
+} |
+ |
void VaapiVideoDecodeAccelerator::MapAndQueueNewInputBuffer( |
const media::BitstreamBuffer& bitstream_buffer) { |
DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
@@ -205,18 +451,18 @@ void VaapiVideoDecodeAccelerator::InitialDecodeTask() { |
return; |
VaapiH264Decoder::DecResult res = |
- decoder_.DecodeInitial(curr_input_buffer_->id); |
+ decoder_->DecodeInitial(curr_input_buffer_->id); |
switch (res) { |
case VaapiH264Decoder::kReadyToDecode: |
if (state_ == kInitialized) { |
state_ = kPicturesRequested; |
- size_t num_pics = decoder_.GetRequiredNumOfPictures(); |
- gfx::Size size(decoder_.pic_width(), decoder_.pic_height()); |
- DVLOG(1) << "Requesting " << num_pics << " pictures of size: " |
- << size.width() << "x" << size.height(); |
+ num_pics_ = decoder_->GetRequiredNumOfPictures(); |
+ pic_size_ = decoder_->GetPicSize(); |
+ DVLOG(1) << "Requesting " << num_pics_ << " pictures of size: " |
+ << pic_size_.width() << "x" << pic_size_.height(); |
message_loop_->PostTask(FROM_HERE, base::Bind( |
&Client::ProvidePictureBuffers, client_, |
- num_pics, size, GL_TEXTURE_2D)); |
+ num_pics_, pic_size_, GL_TEXTURE_2D)); |
} else { |
DCHECK_EQ(state_, kIdle); |
state_ = kDecoding; |
@@ -234,7 +480,7 @@ void VaapiVideoDecodeAccelerator::InitialDecodeTask() { |
if (state_ == kIdle) { |
// No more output buffers in the decoder, try getting more or go to |
// sleep waiting for them. |
- GetOutputBuffers_Locked(); |
+ GetOutputSurfaces_Locked(); |
return; |
} |
// else fallthrough |
@@ -285,7 +531,7 @@ bool VaapiVideoDecodeAccelerator::GetInputBuffer_Locked() { |
<< curr_input_buffer_->id |
<< " size: " << curr_input_buffer_->size; |
- decoder_.SetStream( |
+ decoder_->SetStream( |
static_cast<uint8*>(curr_input_buffer_->shm->memory()), |
curr_input_buffer_->size); |
return true; |
@@ -313,21 +559,27 @@ void VaapiVideoDecodeAccelerator::ReturnCurrInputBuffer_Locked() { |
num_stream_bufs_at_decoder_); |
} |
-bool VaapiVideoDecodeAccelerator::GetOutputBuffers_Locked() { |
+bool VaapiVideoDecodeAccelerator::GetOutputSurfaces_Locked() { |
lock_.AssertAcquired(); |
DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
- while (output_buffers_.empty() && |
+ while (available_va_surfaces_.empty() && |
(state_ == kDecoding || state_ == kFlushing || state_ == kIdle)) { |
- output_ready_.Wait(); |
+ surfaces_available_.Wait(); |
} |
if (state_ != kDecoding && state_ != kFlushing && state_ != kIdle) |
return false; |
- while (!output_buffers_.empty()) { |
- decoder_.ReusePictureBuffer(output_buffers_.front()); |
- output_buffers_.pop(); |
+ VASurface::ReleaseCB va_surface_relase_cb = |
Ami GONE FROM CHROMIUM
2013/05/17 23:19:15
typo: va_surface_relase_cb
Pawel Osciak
2013/05/21 22:32:35
Done.
|
+ media::BindToLoop(message_loop_->message_loop_proxy(), base::Bind( |
+ &VaapiVideoDecodeAccelerator::RecycleVASurfaceID, weak_this_)); |
+ |
+ while (!available_va_surfaces_.empty()) { |
+ scoped_refptr<VASurface> va_surface( |
+ new VASurface(available_va_surfaces_.front(), va_surface_relase_cb)); |
+ available_va_surfaces_.pop_front(); |
+ decoder_->ReuseSurface(va_surface); |
} |
return true; |
@@ -347,21 +599,20 @@ void VaapiVideoDecodeAccelerator::DecodeTask() { |
DCHECK(curr_input_buffer_.get()); |
VaapiH264Decoder::DecResult res; |
- res = decoder_.DecodeOneFrame(curr_input_buffer_->id); |
+ { |
+ base::AutoUnlock auto_unlock(lock_); |
Ami GONE FROM CHROMIUM
2013/05/17 23:19:15
Comment about why and why safe.
Pawel Osciak
2013/05/21 22:32:35
Done.
|
+ res = decoder_->DecodeOneFrame(curr_input_buffer_->id); |
+ } |
switch (res) { |
case VaapiH264Decoder::kNeedMoreStreamData: |
ReturnCurrInputBuffer_Locked(); |
break; |
- case VaapiH264Decoder::kDecodedFrame: |
- // May still have more stream data, continue decoding. |
- break; |
- |
case VaapiH264Decoder::kNoOutputAvailable: |
// No more output buffers in the decoder, try getting more or go to |
// sleep waiting for them. |
- if (!GetOutputBuffers_Locked()) |
+ if (!GetOutputSurfaces_Locked()) |
return; |
break; |
@@ -423,26 +674,58 @@ void VaapiVideoDecodeAccelerator::Decode( |
} |
} |
+void VaapiVideoDecodeAccelerator::RecycleVASurfaceID( |
+ VASurfaceID va_surface_id) { |
+ DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
+ |
+ base::AutoLock auto_lock(lock_); |
+ |
+ available_va_surfaces_.push_back(va_surface_id); |
+ surfaces_available_.Signal(); |
+} |
+ |
void VaapiVideoDecodeAccelerator::AssignPictureBuffers( |
const std::vector<media::PictureBuffer>& buffers) { |
DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
base::AutoLock auto_lock(lock_); |
DCHECK_EQ(state_, kPicturesRequested); |
- size_t num_pics = decoder_.GetRequiredNumOfPictures(); |
- RETURN_AND_NOTIFY_ON_FAILURE((num_pics == buffers.size()), |
- "Failed to provide requested picture buffers. (Got " << buffers.size() << |
- ", requested " << num_pics << ")", INVALID_ARGUMENT,); |
+ DCHECK(tfp_pictures_.empty()); |
+ |
+ RETURN_AND_NOTIFY_ON_FAILURE( |
+ buffers.size() == num_pics_, |
+ "Got an invalid number of picture buffers. (Got " << buffers.size() |
+ << ", requested " << num_pics_ << ")", INVALID_ARGUMENT, ); |
+ |
+ std::vector<VASurfaceID> va_surface_ids; |
+ RETURN_AND_NOTIFY_ON_FAILURE( |
+ vaapi_delegate_->CreateSurfaces(pic_size_.width(), pic_size_.height(), |
+ buffers.size(), |
+ va_surface_ids), |
+ "Failed creating VA Surfaces", PLATFORM_FAILURE, ); |
+ DCHECK_EQ(va_surface_ids.size(), buffers.size()); |
for (size_t i = 0; i < buffers.size(); ++i) { |
- DVLOG(2) << "Assigning picture id " << buffers[i].id() |
- << " to texture id " << buffers[i].texture_id(); |
+ DVLOG(2) << "Assigning picture id: " << buffers[i].id() |
+ << " to texture id: " << buffers[i].texture_id() |
+ << " VASurfaceID: " << va_surface_ids[i]; |
+ |
+ linked_ptr<TFPPicture> tfp_picture( |
+ TFPPicture::Create(make_context_current_, fb_config_, x_display_, |
+ buffers[i].id(), buffers[i].texture_id(), |
+ pic_size_.width(), pic_size_.height())); |
- bool res = decoder_.AssignPictureBuffer(buffers[i].id(), |
- buffers[i].texture_id()); |
RETURN_AND_NOTIFY_ON_FAILURE( |
- res, "Failed assigning picture buffer id: " << buffers[i].id() << |
- ", texture id: " << buffers[i].texture_id(), PLATFORM_FAILURE, ); |
+ tfp_picture.get(), "Failed assigning picture buffer to a texture.", |
+ PLATFORM_FAILURE, ); |
+ |
+ bool inserted = tfp_pictures_.insert(std::make_pair( |
+ buffers[i].id(), tfp_picture)).second; |
+ DCHECK(inserted); |
+ |
+ output_buffers_.push(buffers[i].id()); |
+ available_va_surfaces_.push_back(va_surface_ids[i]); |
+ surfaces_available_.Signal(); |
} |
state_ = kDecoding; |
@@ -458,25 +741,22 @@ void VaapiVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { |
--num_frames_at_client_; |
TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_); |
- base::AutoLock auto_lock(lock_); |
output_buffers_.push(picture_buffer_id); |
- output_ready_.Signal(); |
+ TryOutputSurface(); |
} |
void VaapiVideoDecodeAccelerator::FlushTask() { |
DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
DVLOG(1) << "Flush task"; |
- base::AutoLock auto_lock(lock_); |
- |
// First flush all the pictures that haven't been outputted, notifying the |
// client to output them. |
- bool res = decoder_.Flush(); |
+ bool res = decoder_->Flush(); |
RETURN_AND_NOTIFY_ON_FAILURE(res, "Failed flushing the decoder.", |
PLATFORM_FAILURE, ); |
// Put the decoder in idle state, ready to resume. |
- decoder_.Reset(); |
+ decoder_->Reset(); |
message_loop_->PostTask(FROM_HERE, base::Bind( |
&VaapiVideoDecodeAccelerator::FinishFlush, weak_this_)); |
@@ -493,7 +773,7 @@ void VaapiVideoDecodeAccelerator::Flush() { |
&VaapiVideoDecodeAccelerator::FlushTask, base::Unretained(this))); |
input_ready_.Signal(); |
- output_ready_.Signal(); |
+ surfaces_available_.Signal(); |
} |
void VaapiVideoDecodeAccelerator::FinishFlush() { |
@@ -516,12 +796,12 @@ void VaapiVideoDecodeAccelerator::FinishFlush() { |
void VaapiVideoDecodeAccelerator::ResetTask() { |
DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
- base::AutoLock auto_lock(lock_); |
- |
// All the decoding tasks from before the reset request from client are done |
// by now, as this task was scheduled after them and client is expected not |
// to call Decode() after Reset() and before NotifyResetDone. |
- decoder_.Reset(); |
+ decoder_->Reset(); |
+ |
+ base::AutoLock auto_lock(lock_); |
// Return current input buffer, if present. |
if (curr_input_buffer_.get()) |
@@ -552,7 +832,7 @@ void VaapiVideoDecodeAccelerator::Reset() { |
&VaapiVideoDecodeAccelerator::ResetTask, base::Unretained(this))); |
input_ready_.Signal(); |
- output_ready_.Signal(); |
+ surfaces_available_.Signal(); |
} |
void VaapiVideoDecodeAccelerator::FinishReset() { |
@@ -567,6 +847,9 @@ void VaapiVideoDecodeAccelerator::FinishReset() { |
state_ = kIdle; |
num_stream_bufs_at_decoder_ = 0; |
+ while(!pending_output_cbs_.empty()) |
+ pending_output_cbs_.pop(); |
+ |
message_loop_->PostTask(FROM_HERE, base::Bind( |
&Client::NotifyResetDone, client_)); |
@@ -602,12 +885,11 @@ void VaapiVideoDecodeAccelerator::Cleanup() { |
decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
&base::WaitableEvent::Signal, base::Unretained(&waiter))); |
input_ready_.Signal(); |
- output_ready_.Signal(); |
+ surfaces_available_.Signal(); |
waiter.Wait(); |
decoder_thread_.Stop(); |
} |
- decoder_.Destroy(); |
state_ = kUninitialized; |
} |
@@ -617,14 +899,4 @@ void VaapiVideoDecodeAccelerator::Destroy() { |
delete this; |
} |
-// static |
-void VaapiVideoDecodeAccelerator::PreSandboxInitialization() { |
- VaapiH264Decoder::PreSandboxInitialization(); |
-} |
- |
-// static |
-bool VaapiVideoDecodeAccelerator::PostSandboxInitialization() { |
- return VaapiH264Decoder::PostSandboxInitialization(); |
-} |
- |
} // namespace content |