Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/bind.h" | 5 #include "base/bind.h" |
| 6 #include "base/command_line.h" | |
| 7 #include "base/debug/trace_event.h" | 6 #include "base/debug/trace_event.h" |
| 8 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/metrics/histogram.h" | |
| 9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
| 10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| 11 #include "base/synchronization/waitable_event.h" | 11 #include "base/synchronization/waitable_event.h" |
| 12 #include "gpu/command_buffer/service/gpu_switches.h" | |
| 13 #include "content/public/common/content_switches.h" | |
| 14 #include "content/common/gpu/gpu_channel.h" | 12 #include "content/common/gpu/gpu_channel.h" |
| 15 #include "content/common/gpu/media/vaapi_video_decode_accelerator.h" | 13 #include "content/common/gpu/media/vaapi_video_decode_accelerator.h" |
| 16 #include "media/base/bind_to_loop.h" | 14 #include "media/base/bind_to_loop.h" |
| 17 #include "media/video/picture.h" | 15 #include "media/video/picture.h" |
| 18 #include "third_party/libva/va/va.h" | |
| 19 #include "ui/gl/gl_bindings.h" | 16 #include "ui/gl/gl_bindings.h" |
| 17 #include "ui/gl/scoped_binders.h" | |
| 18 | |
| 19 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.
| |
| 20 | |
| 21 static void ReportToUMA( | |
| 22 content::VaapiH264Decoder::VAVDAH264DecoderFailure failure) { | |
| 23 UMA_HISTOGRAM_ENUMERATION( | |
| 24 "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
| |
| 25 failure, | |
| 26 content::VaapiH264Decoder::VAVDA_H264_DECODER_FAILURES_MAX); | |
| 27 } | |
| 28 | |
| 29 } // namespace | |
| 20 | 30 |
| 21 namespace content { | 31 namespace content { |
| 22 | 32 |
| 23 #define RETURN_AND_NOTIFY_ON_FAILURE(result, log, error_code, ret) \ | 33 #define RETURN_AND_NOTIFY_ON_FAILURE(result, log, error_code, ret) \ |
| 24 do { \ | 34 do { \ |
| 25 if (!(result)) { \ | 35 if (!(result)) { \ |
| 26 DVLOG(1) << log; \ | 36 DVLOG(1) << log; \ |
| 27 NotifyError(error_code); \ | 37 NotifyError(error_code); \ |
| 28 return ret; \ | 38 return ret; \ |
| 29 } \ | 39 } \ |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 47 message_loop_->PostTask(FROM_HERE, base::Bind( | 57 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 48 &VaapiVideoDecodeAccelerator::Cleanup, weak_this_)); | 58 &VaapiVideoDecodeAccelerator::Cleanup, weak_this_)); |
| 49 | 59 |
| 50 DVLOG(1) << "Notifying of error " << error; | 60 DVLOG(1) << "Notifying of error " << error; |
| 51 if (client_) { | 61 if (client_) { |
| 52 client_->NotifyError(error); | 62 client_->NotifyError(error); |
| 53 client_ptr_factory_.InvalidateWeakPtrs(); | 63 client_ptr_factory_.InvalidateWeakPtrs(); |
| 54 } | 64 } |
| 55 } | 65 } |
| 56 | 66 |
| 67 class VaapiVideoDecodeAccelerator::TFPPicture { | |
| 68 public: | |
| 69 ~TFPPicture(); | |
| 70 | |
| 71 static linked_ptr<TFPPicture> Create( | |
| 72 const base::Callback<bool(void)>& make_context_current, | |
| 73 const GLXFBConfig& fb_config, | |
| 74 Display* x_display, | |
| 75 int32 picture_buffer_id, | |
| 76 uint32 texture_id, | |
| 77 int width, int height); | |
| 78 | |
| 79 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
| |
| 80 return picture_buffer_id_; | |
| 81 } | |
| 82 | |
| 83 uint32 texture_id() { | |
| 84 return texture_id_; | |
| 85 } | |
| 86 | |
| 87 int width() { | |
| 88 return width_; | |
| 89 } | |
| 90 | |
| 91 int height() { | |
| 92 return height_; | |
| 93 } | |
| 94 | |
| 95 int x_pixmap() { | |
| 96 return x_pixmap_; | |
| 97 } | |
| 98 | |
| 99 // Bind texture to pixmap. Needs to be called every frame. | |
| 100 bool Bind(); | |
| 101 | |
| 102 private: | |
| 103 TFPPicture(const base::Callback<bool(void)>& make_context_current, | |
| 104 Display* x_display, | |
| 105 int32 picture_buffer_id, | |
| 106 uint32 texture_id, | |
| 107 int width, int height); | |
| 108 | |
| 109 bool Initialize(const GLXFBConfig& fb_config); | |
| 110 | |
| 111 base::Callback<bool(void)> make_context_current_; | |
| 112 | |
| 113 // Output id for the client. | |
| 114 int32 picture_buffer_id_; | |
| 115 uint32 texture_id_; | |
| 116 | |
| 117 int width_; | |
| 118 int height_; | |
| 119 | |
| 120 Display* x_display_; | |
| 121 | |
| 122 // Pixmaps bound to this texture. | |
| 123 Pixmap x_pixmap_; | |
| 124 GLXPixmap glx_pixmap_; | |
| 125 | |
| 126 DISALLOW_COPY_AND_ASSIGN(TFPPicture); | |
| 127 }; | |
| 128 | |
| 129 VaapiVideoDecodeAccelerator::TFPPicture::TFPPicture( | |
| 130 const base::Callback<bool(void)>& make_context_current, | |
| 131 Display* x_display, | |
| 132 int32 picture_buffer_id, | |
| 133 uint32 texture_id, | |
| 134 int width, int height) | |
| 135 : make_context_current_(make_context_current), | |
| 136 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.
| |
| 137 texture_id_(texture_id), | |
| 138 width_(width), | |
| 139 height_(height), | |
| 140 x_display_(x_display), | |
| 141 x_pixmap_(0), | |
| 142 glx_pixmap_(0) { | |
| 143 DCHECK(!make_context_current_.is_null()); | |
| 144 }; | |
| 145 | |
| 146 linked_ptr<VaapiVideoDecodeAccelerator::TFPPicture> | |
| 147 VaapiVideoDecodeAccelerator::TFPPicture::Create( | |
| 148 const base::Callback<bool(void)>& make_context_current, | |
| 149 const GLXFBConfig& fb_config, | |
| 150 Display* x_display, | |
| 151 int32 picture_buffer_id, | |
| 152 uint32 texture_id, | |
| 153 int width, int height) { | |
| 154 | |
| 155 linked_ptr<TFPPicture> tfp_picture( | |
| 156 new TFPPicture(make_context_current, x_display, picture_buffer_id, | |
| 157 texture_id, width, height)); | |
| 158 | |
| 159 if (!tfp_picture->Initialize(fb_config)) | |
| 160 tfp_picture.reset(); | |
| 161 | |
| 162 return tfp_picture; | |
| 163 } | |
| 164 | |
| 165 bool VaapiVideoDecodeAccelerator::TFPPicture::Initialize( | |
| 166 const GLXFBConfig& fb_config) { | |
| 167 if (!make_context_current_.Run()) | |
| 168 return false; | |
| 169 | |
| 170 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
| 171 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
| 172 | |
| 173 XWindowAttributes win_attr; | |
| 174 int screen = DefaultScreen(x_display_); | |
| 175 XGetWindowAttributes(x_display_, RootWindow(x_display_, screen), &win_attr); | |
| 176 //TODO(posciak): pass the depth required by libva, not the RootWindow's depth | |
| 177 x_pixmap_ = XCreatePixmap(x_display_, RootWindow(x_display_, screen), | |
| 178 width_, height_, win_attr.depth); | |
| 179 if (!x_pixmap_) { | |
| 180 DVLOG(1) << "Failed creating an X Pixmap for TFP"; | |
| 181 return NULL; | |
| 182 } | |
| 183 | |
| 184 static const int pixmap_attr[] = { | |
| 185 GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, | |
| 186 GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT, | |
| 187 GL_NONE, | |
| 188 }; | |
| 189 | |
| 190 glx_pixmap_ = glXCreatePixmap(x_display_, fb_config, x_pixmap_, pixmap_attr); | |
| 191 if (!glx_pixmap_) { | |
| 192 // x_pixmap_ will be freed in the destructor. | |
| 193 DVLOG(1) << "Failed creating a GLX Pixmap for TFP"; | |
| 194 return NULL; | |
| 195 } | |
| 196 | |
| 197 return true; | |
| 198 } | |
| 199 | |
| 200 VaapiVideoDecodeAccelerator::TFPPicture::~TFPPicture() { | |
| 201 // Unbind surface from texture and deallocate resources. | |
| 202 if (glx_pixmap_ && make_context_current_.Run()) { | |
| 203 glXReleaseTexImageEXT(x_display_, glx_pixmap_, GLX_FRONT_LEFT_EXT); | |
| 204 glXDestroyPixmap(x_display_, glx_pixmap_); | |
| 205 } | |
| 206 | |
| 207 if (x_pixmap_) | |
| 208 XFreePixmap(x_display_, x_pixmap_); | |
| 209 XSync(x_display_, False); // Needed to work around buggy vdpau-driver. | |
| 210 } | |
| 211 | |
| 212 bool VaapiVideoDecodeAccelerator::TFPPicture::Bind() { | |
| 213 DCHECK(x_pixmap_); | |
| 214 DCHECK(glx_pixmap_); | |
| 215 | |
| 216 if (!make_context_current_.Run()) | |
| 217 return false; | |
| 218 | |
| 219 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
| |
| 220 glXBindTexImageEXT(x_display_, glx_pixmap_, GLX_FRONT_LEFT_EXT, NULL); | |
| 221 | |
| 222 return true; | |
| 223 } | |
| 224 | |
| 225 VaapiVideoDecodeAccelerator::TFPPicture* | |
| 226 VaapiVideoDecodeAccelerator::TFPPictureById(int32 picture_buffer_id) { | |
| 227 TFPPictures::iterator it = tfp_pictures_.find(picture_buffer_id); | |
| 228 if (it == tfp_pictures_.end()) { | |
| 229 DVLOG(1) << "Picture id " << picture_buffer_id << " does not exist"; | |
| 230 return NULL; | |
| 231 } | |
| 232 | |
| 233 return it->second.get(); | |
| 234 } | |
| 235 | |
| 57 VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator( | 236 VaapiVideoDecodeAccelerator::VaapiVideoDecodeAccelerator( |
| 58 Display* x_display, GLXContext glx_context, | 237 Display* x_display, GLXContext glx_context, |
| 59 Client* client, | 238 Client* client, |
| 60 const base::Callback<bool(void)>& make_context_current) | 239 const base::Callback<bool(void)>& make_context_current) |
| 61 : x_display_(x_display), | 240 : x_display_(x_display), |
| 62 glx_context_(glx_context), | 241 glx_context_(glx_context), |
| 63 make_context_current_(make_context_current), | 242 make_context_current_(make_context_current), |
| 64 state_(kUninitialized), | 243 state_(kUninitialized), |
| 65 input_ready_(&lock_), | 244 input_ready_(&lock_), |
| 66 output_ready_(&lock_), | 245 surfaces_available_(&lock_), |
| 67 message_loop_(base::MessageLoop::current()), | 246 message_loop_(base::MessageLoop::current()), |
| 68 weak_this_(base::AsWeakPtr(this)), | 247 weak_this_(base::AsWeakPtr(this)), |
| 69 client_ptr_factory_(client), | 248 client_ptr_factory_(client), |
| 70 client_(client_ptr_factory_.GetWeakPtr()), | 249 client_(client_ptr_factory_.GetWeakPtr()), |
| 71 decoder_thread_("VaapiDecoderThread"), | 250 decoder_thread_("VaapiDecoderThread"), |
| 72 num_frames_at_client_(0), | 251 num_frames_at_client_(0), |
| 73 num_stream_bufs_at_decoder_(0) { | 252 num_stream_bufs_at_decoder_(0) { |
| 74 DCHECK(client); | 253 DCHECK(client); |
| 75 static bool vaapi_functions_initialized = PostSandboxInitialization(); | |
| 76 RETURN_AND_NOTIFY_ON_FAILURE(vaapi_functions_initialized, | |
| 77 "Failed to initialize VAAPI libs", | |
| 78 PLATFORM_FAILURE, ); | |
| 79 } | 254 } |
| 80 | 255 |
| 81 VaapiVideoDecodeAccelerator::~VaapiVideoDecodeAccelerator() { | 256 VaapiVideoDecodeAccelerator::~VaapiVideoDecodeAccelerator() { |
| 82 DCHECK_EQ(message_loop_, base::MessageLoop::current()); | 257 DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
| 83 } | 258 } |
| 84 | 259 |
| 260 class ScopedPtrXFree { | |
| 261 public: | |
| 262 void operator()(void* x) const { | |
| 263 ::XFree(x); | |
| 264 } | |
| 265 }; | |
| 266 | |
| 267 bool VaapiVideoDecodeAccelerator::InitializeFBConfig() { | |
| 268 const int fbconfig_attr[] = { | |
| 269 GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, | |
| 270 GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT, | |
| 271 GLX_BIND_TO_TEXTURE_RGB_EXT, GL_TRUE, | |
| 272 GLX_Y_INVERTED_EXT, GL_TRUE, | |
| 273 GL_NONE, | |
| 274 }; | |
| 275 | |
| 276 int num_fbconfigs; | |
| 277 scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> glx_fb_configs( | |
| 278 glXChooseFBConfig(x_display_, DefaultScreen(x_display_), fbconfig_attr, | |
| 279 &num_fbconfigs)); | |
| 280 if (!glx_fb_configs) | |
| 281 return false; | |
| 282 if (!num_fbconfigs) | |
| 283 return false; | |
| 284 | |
| 285 fb_config_ = glx_fb_configs.get()[0]; | |
| 286 return true; | |
| 287 } | |
| 288 | |
| 85 bool VaapiVideoDecodeAccelerator::Initialize( | 289 bool VaapiVideoDecodeAccelerator::Initialize( |
| 86 media::VideoCodecProfile profile) { | 290 media::VideoCodecProfile profile) { |
| 87 DCHECK_EQ(message_loop_, base::MessageLoop::current()); | 291 DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
| 88 | 292 |
| 89 base::AutoLock auto_lock(lock_); | 293 base::AutoLock auto_lock(lock_); |
| 90 DCHECK_EQ(state_, kUninitialized); | 294 DCHECK_EQ(state_, kUninitialized); |
| 91 DVLOG(2) << "Initializing VAVDA, profile: " << profile; | 295 DVLOG(2) << "Initializing VAVDA, profile: " << profile; |
| 92 | 296 |
| 93 bool res = decoder_.Initialize( | 297 if (!make_context_current_.Run()) |
| 94 profile, x_display_, glx_context_, make_context_current_, | 298 return false; |
| 95 media::BindToLoop(message_loop_->message_loop_proxy(), base::Bind( | 299 |
| 96 &VaapiVideoDecodeAccelerator::NotifyPictureReady, weak_this_)), | 300 if (!InitializeFBConfig()) { |
| 97 media::BindToLoop(message_loop_->message_loop_proxy(), base::Bind( | 301 DVLOG(1) << "Could not get a usable FBConfig"; |
| 98 &VaapiVideoDecodeAccelerator::SubmitDecode, weak_this_))); | |
| 99 if (!res) { | |
| 100 DVLOG(1) << "Failed initializing decoder"; | |
| 101 return false; | 302 return false; |
| 102 } | 303 } |
| 103 | 304 |
| 305 vaapi_delegate_ = VaapiDelegate::Create( | |
| 306 profile, x_display_, | |
| 307 base::Bind(&ReportToUMA, content::VaapiH264Decoder::VAAPI_ERROR)); | |
| 308 | |
| 309 if (!vaapi_delegate_.get()) { | |
| 310 DVLOG(1) << "Failed initializing VAAPI"; | |
| 311 return false; | |
| 312 } | |
| 313 | |
| 314 decoder_.reset( | |
| 315 new VaapiH264Decoder( | |
| 316 vaapi_delegate_, | |
| 317 media::BindToLoop(message_loop_->message_loop_proxy(), base::Bind( | |
| 318 &VaapiVideoDecodeAccelerator::SurfaceReady, weak_this_)), | |
| 319 base::Bind(&ReportToUMA))); | |
| 320 | |
| 104 CHECK(decoder_thread_.Start()); | 321 CHECK(decoder_thread_.Start()); |
| 105 | 322 |
| 106 state_ = kInitialized; | 323 state_ = kInitialized; |
| 107 | 324 |
| 108 message_loop_->PostTask(FROM_HERE, base::Bind( | 325 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 109 &Client::NotifyInitializeDone, client_)); | 326 &Client::NotifyInitializeDone, client_)); |
| 110 return true; | 327 return true; |
| 111 } | 328 } |
| 112 | 329 |
| 113 void VaapiVideoDecodeAccelerator::SubmitDecode( | 330 void VaapiVideoDecodeAccelerator::SyncSurfaceToPicture( |
| 114 int32 output_id, | 331 VASurfaceID va_surface_id, |
| 115 scoped_ptr<std::queue<VABufferID> > va_bufs, | 332 TFPPicture* tfp_picture) { |
| 116 scoped_ptr<std::queue<VABufferID> > slice_bufs) { | |
| 117 DCHECK_EQ(message_loop_, base::MessageLoop::current()); | 333 DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
| 118 base::AutoLock auto_lock(lock_); | |
| 119 | 334 |
| 120 TRACE_EVENT1("Video Decoder", "VAVDA::Decode", "output_id", output_id); | 335 RETURN_AND_NOTIFY_ON_FAILURE(tfp_picture->Bind(), |
| 336 "Failed binding texture to pixmap", | |
| 337 PLATFORM_FAILURE, ); | |
| 338 | |
| 339 RETURN_AND_NOTIFY_ON_FAILURE( | |
| 340 vaapi_delegate_->PutSurfaceIntoPixmap(va_surface_id, | |
| 341 tfp_picture->x_pixmap(), | |
| 342 tfp_picture->width(), | |
| 343 tfp_picture->height()), | |
| 344 "Failed putting surface into pixmap", PLATFORM_FAILURE, ); | |
| 345 } | |
| 346 | |
| 347 void VaapiVideoDecodeAccelerator::SurfaceReady( | |
| 348 int32 input_id, | |
| 349 const scoped_refptr<VASurface>& va_surface) { | |
| 350 DCHECK_EQ(message_loop_, base::MessageLoop::current()); | |
| 351 | |
| 352 // Drop any requests to output if we are resetting. | |
| 353 if (state_ == kResetting || state_ == kDestroying) | |
| 354 return; | |
| 355 | |
| 356 pending_output_cbs_.push( | |
| 357 base::Bind(&VaapiVideoDecodeAccelerator::OutputPicture, | |
| 358 weak_this_, va_surface, input_id)); | |
| 359 | |
| 360 TryOutputSurface(); | |
| 361 } | |
| 362 | |
| 363 void VaapiVideoDecodeAccelerator::OutputPicture( | |
| 364 const scoped_refptr<VASurface>& va_surface, | |
| 365 int32 input_id, | |
| 366 TFPPicture* tfp_picture) { | |
| 367 DCHECK_EQ(message_loop_, base::MessageLoop::current()); | |
| 368 | |
| 369 int32 output_id = tfp_picture->picture_buffer_id(); | |
| 370 | |
| 371 TRACE_EVENT2("Video Decoder", "VAVDA::OutputSurface", | |
| 372 "input_id", input_id, | |
| 373 "output_id", output_id); | |
| 374 | |
| 375 DVLOG(3) << "Outputting VASurface " << va_surface->id() | |
| 376 << " into pixmap bound to picture buffer id " << output_id; | |
| 377 | |
| 378 SyncSurfaceToPicture(va_surface->id(), tfp_picture); | |
| 379 | |
| 380 // Notify the client a picture is ready to be displayed. | |
| 381 ++num_frames_at_client_; | |
| 382 TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_); | |
| 383 DVLOG(4) << "Notifying output picture id " << output_id | |
| 384 << " for input "<< input_id << " is ready"; | |
| 385 client_->PictureReady(media::Picture(output_id, input_id)); | |
| 386 } | |
| 387 | |
| 388 void VaapiVideoDecodeAccelerator::TryOutputSurface() { | |
| 389 DCHECK_EQ(message_loop_, base::MessageLoop::current()); | |
| 121 | 390 |
| 122 // Handle Destroy() arriving while pictures are queued for output. | 391 // Handle Destroy() arriving while pictures are queued for output. |
| 123 if (!client_) | 392 if (!client_) |
| 124 return; | 393 return; |
| 125 | 394 |
| 126 RETURN_AND_NOTIFY_ON_FAILURE( | 395 if (pending_output_cbs_.empty() || output_buffers_.empty()) |
| 127 decoder_.SubmitDecode(output_id, va_bufs.Pass(), slice_bufs.Pass()), | |
| 128 "Failed putting picture to texture", | |
| 129 PLATFORM_FAILURE, ); | |
| 130 } | |
| 131 | |
| 132 void VaapiVideoDecodeAccelerator::NotifyPictureReady(int32 input_id, | |
| 133 int32 output_id) { | |
| 134 DCHECK_EQ(message_loop_, base::MessageLoop::current()); | |
| 135 TRACE_EVENT2("Video Decoder", "VAVDA::NotifyPictureReady", | |
| 136 "input_id", input_id, "output_id", output_id); | |
| 137 | |
| 138 // Handle Destroy() arriving while pictures are queued for output. | |
| 139 if (!client_) | |
| 140 return; | 396 return; |
| 141 | 397 |
| 142 // Don't return any pictures that we might want to return during resetting | 398 OutputCB output_cb = pending_output_cbs_.front(); |
| 143 // as a consequence of finishing up the decode that was running during | 399 pending_output_cbs_.pop(); |
| 144 // Reset() call from the client. Reuse it instead. | |
| 145 { | |
| 146 base::AutoLock auto_lock(lock_); | |
| 147 if (state_ == kResetting) { | |
| 148 output_buffers_.push(output_id); | |
| 149 return; | |
| 150 } | |
| 151 } | |
| 152 | 400 |
| 153 ++num_frames_at_client_; | 401 TFPPicture* tfp_picture = TFPPictureById(output_buffers_.front()); |
| 154 TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_); | 402 DCHECK(tfp_picture); |
| 403 output_buffers_.pop(); | |
| 155 | 404 |
| 156 // Notify the client a picture is ready to be displayed. | 405 output_cb.Run(tfp_picture); |
| 157 DVLOG(4) << "Notifying output picture id " << output_id | |
| 158 << " for input "<< input_id << " is ready"; | |
| 159 client_->PictureReady(media::Picture(output_id, input_id)); | |
| 160 } | 406 } |
| 161 | 407 |
| 162 void VaapiVideoDecodeAccelerator::MapAndQueueNewInputBuffer( | 408 void VaapiVideoDecodeAccelerator::MapAndQueueNewInputBuffer( |
| 163 const media::BitstreamBuffer& bitstream_buffer) { | 409 const media::BitstreamBuffer& bitstream_buffer) { |
| 164 DCHECK_EQ(message_loop_, base::MessageLoop::current()); | 410 DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
| 165 TRACE_EVENT1("Video Decoder", "MapAndQueueNewInputBuffer", "input_id", | 411 TRACE_EVENT1("Video Decoder", "MapAndQueueNewInputBuffer", "input_id", |
| 166 bitstream_buffer.id()); | 412 bitstream_buffer.id()); |
| 167 | 413 |
| 168 DVLOG(4) << "Mapping new input buffer id: " << bitstream_buffer.id() | 414 DVLOG(4) << "Mapping new input buffer id: " << bitstream_buffer.id() |
| 169 << " size: " << (int)bitstream_buffer.size(); | 415 << " size: " << (int)bitstream_buffer.size(); |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 198 DCHECK(curr_input_buffer_.get()); | 444 DCHECK(curr_input_buffer_.get()); |
| 199 | 445 |
| 200 // Since multiple Decode()'s can be in flight at once, it's possible that a | 446 // Since multiple Decode()'s can be in flight at once, it's possible that a |
| 201 // Decode() that seemed like an initial one is actually later in the stream | 447 // Decode() that seemed like an initial one is actually later in the stream |
| 202 // and we're already kDecoding. Let the normal DecodeTask take over in that | 448 // and we're already kDecoding. Let the normal DecodeTask take over in that |
| 203 // case. | 449 // case. |
| 204 if (state_ != kInitialized && state_ != kIdle) | 450 if (state_ != kInitialized && state_ != kIdle) |
| 205 return; | 451 return; |
| 206 | 452 |
| 207 VaapiH264Decoder::DecResult res = | 453 VaapiH264Decoder::DecResult res = |
| 208 decoder_.DecodeInitial(curr_input_buffer_->id); | 454 decoder_->DecodeInitial(curr_input_buffer_->id); |
| 209 switch (res) { | 455 switch (res) { |
| 210 case VaapiH264Decoder::kReadyToDecode: | 456 case VaapiH264Decoder::kReadyToDecode: |
| 211 if (state_ == kInitialized) { | 457 if (state_ == kInitialized) { |
| 212 state_ = kPicturesRequested; | 458 state_ = kPicturesRequested; |
| 213 size_t num_pics = decoder_.GetRequiredNumOfPictures(); | 459 num_pics_ = decoder_->GetRequiredNumOfPictures(); |
| 214 gfx::Size size(decoder_.pic_width(), decoder_.pic_height()); | 460 pic_size_ = decoder_->GetPicSize(); |
| 215 DVLOG(1) << "Requesting " << num_pics << " pictures of size: " | 461 DVLOG(1) << "Requesting " << num_pics_ << " pictures of size: " |
| 216 << size.width() << "x" << size.height(); | 462 << pic_size_.width() << "x" << pic_size_.height(); |
| 217 message_loop_->PostTask(FROM_HERE, base::Bind( | 463 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 218 &Client::ProvidePictureBuffers, client_, | 464 &Client::ProvidePictureBuffers, client_, |
| 219 num_pics, size, GL_TEXTURE_2D)); | 465 num_pics_, pic_size_, GL_TEXTURE_2D)); |
| 220 } else { | 466 } else { |
| 221 DCHECK_EQ(state_, kIdle); | 467 DCHECK_EQ(state_, kIdle); |
| 222 state_ = kDecoding; | 468 state_ = kDecoding; |
| 223 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 469 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
| 224 &VaapiVideoDecodeAccelerator::DecodeTask, | 470 &VaapiVideoDecodeAccelerator::DecodeTask, |
| 225 base::Unretained(this))); | 471 base::Unretained(this))); |
| 226 } | 472 } |
| 227 return; | 473 return; |
| 228 | 474 |
| 229 case VaapiH264Decoder::kNeedMoreStreamData: | 475 case VaapiH264Decoder::kNeedMoreStreamData: |
| 230 ReturnCurrInputBuffer_Locked(); | 476 ReturnCurrInputBuffer_Locked(); |
| 231 break; | 477 break; |
| 232 | 478 |
| 233 case VaapiH264Decoder::kNoOutputAvailable: | 479 case VaapiH264Decoder::kNoOutputAvailable: |
| 234 if (state_ == kIdle) { | 480 if (state_ == kIdle) { |
| 235 // No more output buffers in the decoder, try getting more or go to | 481 // No more output buffers in the decoder, try getting more or go to |
| 236 // sleep waiting for them. | 482 // sleep waiting for them. |
| 237 GetOutputBuffers_Locked(); | 483 GetOutputSurfaces_Locked(); |
| 238 return; | 484 return; |
| 239 } | 485 } |
| 240 // else fallthrough | 486 // else fallthrough |
| 241 case VaapiH264Decoder::kDecodeError: | 487 case VaapiH264Decoder::kDecodeError: |
| 242 RETURN_AND_NOTIFY_ON_FAILURE(false, "Error in decoding", | 488 RETURN_AND_NOTIFY_ON_FAILURE(false, "Error in decoding", |
| 243 PLATFORM_FAILURE, ); | 489 PLATFORM_FAILURE, ); |
| 244 | 490 |
| 245 default: | 491 default: |
| 246 RETURN_AND_NOTIFY_ON_FAILURE(false, | 492 RETURN_AND_NOTIFY_ON_FAILURE(false, |
| 247 "Unexpected result from decoder: " << res, | 493 "Unexpected result from decoder: " << res, |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 278 case kIdle: | 524 case kIdle: |
| 279 DCHECK(!input_buffers_.empty()); | 525 DCHECK(!input_buffers_.empty()); |
| 280 | 526 |
| 281 curr_input_buffer_ = input_buffers_.front(); | 527 curr_input_buffer_ = input_buffers_.front(); |
| 282 input_buffers_.pop(); | 528 input_buffers_.pop(); |
| 283 | 529 |
| 284 DVLOG(4) << "New current bitstream buffer, id: " | 530 DVLOG(4) << "New current bitstream buffer, id: " |
| 285 << curr_input_buffer_->id | 531 << curr_input_buffer_->id |
| 286 << " size: " << curr_input_buffer_->size; | 532 << " size: " << curr_input_buffer_->size; |
| 287 | 533 |
| 288 decoder_.SetStream( | 534 decoder_->SetStream( |
| 289 static_cast<uint8*>(curr_input_buffer_->shm->memory()), | 535 static_cast<uint8*>(curr_input_buffer_->shm->memory()), |
| 290 curr_input_buffer_->size); | 536 curr_input_buffer_->size); |
| 291 return true; | 537 return true; |
| 292 | 538 |
| 293 default: | 539 default: |
| 294 // We got woken up due to being destroyed/reset, ignore any already | 540 // We got woken up due to being destroyed/reset, ignore any already |
| 295 // queued inputs. | 541 // queued inputs. |
| 296 return false; | 542 return false; |
| 297 } | 543 } |
| 298 } | 544 } |
| 299 | 545 |
| 300 void VaapiVideoDecodeAccelerator::ReturnCurrInputBuffer_Locked() { | 546 void VaapiVideoDecodeAccelerator::ReturnCurrInputBuffer_Locked() { |
| 301 lock_.AssertAcquired(); | 547 lock_.AssertAcquired(); |
| 302 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 548 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 303 DCHECK(curr_input_buffer_.get()); | 549 DCHECK(curr_input_buffer_.get()); |
| 304 | 550 |
| 305 int32 id = curr_input_buffer_->id; | 551 int32 id = curr_input_buffer_->id; |
| 306 curr_input_buffer_.reset(); | 552 curr_input_buffer_.reset(); |
| 307 DVLOG(4) << "End of input buffer " << id; | 553 DVLOG(4) << "End of input buffer " << id; |
| 308 message_loop_->PostTask(FROM_HERE, base::Bind( | 554 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 309 &Client::NotifyEndOfBitstreamBuffer, client_, id)); | 555 &Client::NotifyEndOfBitstreamBuffer, client_, id)); |
| 310 | 556 |
| 311 --num_stream_bufs_at_decoder_; | 557 --num_stream_bufs_at_decoder_; |
| 312 TRACE_COUNTER1("Video Decoder", "Stream buffers at decoder", | 558 TRACE_COUNTER1("Video Decoder", "Stream buffers at decoder", |
| 313 num_stream_bufs_at_decoder_); | 559 num_stream_bufs_at_decoder_); |
| 314 } | 560 } |
| 315 | 561 |
| 316 bool VaapiVideoDecodeAccelerator::GetOutputBuffers_Locked() { | 562 bool VaapiVideoDecodeAccelerator::GetOutputSurfaces_Locked() { |
| 317 lock_.AssertAcquired(); | 563 lock_.AssertAcquired(); |
| 318 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 564 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 319 | 565 |
| 320 while (output_buffers_.empty() && | 566 while (available_va_surfaces_.empty() && |
| 321 (state_ == kDecoding || state_ == kFlushing || state_ == kIdle)) { | 567 (state_ == kDecoding || state_ == kFlushing || state_ == kIdle)) { |
| 322 output_ready_.Wait(); | 568 surfaces_available_.Wait(); |
| 323 } | 569 } |
| 324 | 570 |
| 325 if (state_ != kDecoding && state_ != kFlushing && state_ != kIdle) | 571 if (state_ != kDecoding && state_ != kFlushing && state_ != kIdle) |
| 326 return false; | 572 return false; |
| 327 | 573 |
| 328 while (!output_buffers_.empty()) { | 574 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.
| |
| 329 decoder_.ReusePictureBuffer(output_buffers_.front()); | 575 media::BindToLoop(message_loop_->message_loop_proxy(), base::Bind( |
| 330 output_buffers_.pop(); | 576 &VaapiVideoDecodeAccelerator::RecycleVASurfaceID, weak_this_)); |
| 577 | |
| 578 while (!available_va_surfaces_.empty()) { | |
| 579 scoped_refptr<VASurface> va_surface( | |
| 580 new VASurface(available_va_surfaces_.front(), va_surface_relase_cb)); | |
| 581 available_va_surfaces_.pop_front(); | |
| 582 decoder_->ReuseSurface(va_surface); | |
| 331 } | 583 } |
| 332 | 584 |
| 333 return true; | 585 return true; |
| 334 } | 586 } |
| 335 | 587 |
| 336 void VaapiVideoDecodeAccelerator::DecodeTask() { | 588 void VaapiVideoDecodeAccelerator::DecodeTask() { |
| 337 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 589 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 338 TRACE_EVENT0("Video Decoder", "VAVDA::DecodeTask"); | 590 TRACE_EVENT0("Video Decoder", "VAVDA::DecodeTask"); |
| 339 base::AutoLock auto_lock(lock_); | 591 base::AutoLock auto_lock(lock_); |
| 340 | 592 |
| 341 // Main decode task. | 593 // Main decode task. |
| 342 DVLOG(4) << "Decode task"; | 594 DVLOG(4) << "Decode task"; |
| 343 | 595 |
| 344 // Try to decode what stream data is (still) in the decoder until we run out | 596 // Try to decode what stream data is (still) in the decoder until we run out |
| 345 // of it. | 597 // of it. |
| 346 while (GetInputBuffer_Locked()) { | 598 while (GetInputBuffer_Locked()) { |
| 347 DCHECK(curr_input_buffer_.get()); | 599 DCHECK(curr_input_buffer_.get()); |
| 348 | 600 |
| 349 VaapiH264Decoder::DecResult res; | 601 VaapiH264Decoder::DecResult res; |
| 350 res = decoder_.DecodeOneFrame(curr_input_buffer_->id); | 602 { |
| 603 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.
| |
| 604 res = decoder_->DecodeOneFrame(curr_input_buffer_->id); | |
| 605 } | |
| 351 | 606 |
| 352 switch (res) { | 607 switch (res) { |
| 353 case VaapiH264Decoder::kNeedMoreStreamData: | 608 case VaapiH264Decoder::kNeedMoreStreamData: |
| 354 ReturnCurrInputBuffer_Locked(); | 609 ReturnCurrInputBuffer_Locked(); |
| 355 break; | 610 break; |
| 356 | 611 |
| 357 case VaapiH264Decoder::kDecodedFrame: | |
| 358 // May still have more stream data, continue decoding. | |
| 359 break; | |
| 360 | |
| 361 case VaapiH264Decoder::kNoOutputAvailable: | 612 case VaapiH264Decoder::kNoOutputAvailable: |
| 362 // No more output buffers in the decoder, try getting more or go to | 613 // No more output buffers in the decoder, try getting more or go to |
| 363 // sleep waiting for them. | 614 // sleep waiting for them. |
| 364 if (!GetOutputBuffers_Locked()) | 615 if (!GetOutputSurfaces_Locked()) |
| 365 return; | 616 return; |
| 366 break; | 617 break; |
| 367 | 618 |
| 368 case VaapiH264Decoder::kDecodeError: | 619 case VaapiH264Decoder::kDecodeError: |
| 369 RETURN_AND_NOTIFY_ON_FAILURE(false, "Error decoding stream", | 620 RETURN_AND_NOTIFY_ON_FAILURE(false, "Error decoding stream", |
| 370 PLATFORM_FAILURE, ); | 621 PLATFORM_FAILURE, ); |
| 371 return; | 622 return; |
| 372 | 623 |
| 373 default: | 624 default: |
| 374 RETURN_AND_NOTIFY_ON_FAILURE( | 625 RETURN_AND_NOTIFY_ON_FAILURE( |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 416 break; | 667 break; |
| 417 | 668 |
| 418 default: | 669 default: |
| 419 RETURN_AND_NOTIFY_ON_FAILURE(false, | 670 RETURN_AND_NOTIFY_ON_FAILURE(false, |
| 420 "Decode request from client in invalid state: " << state_, | 671 "Decode request from client in invalid state: " << state_, |
| 421 PLATFORM_FAILURE, ); | 672 PLATFORM_FAILURE, ); |
| 422 return; | 673 return; |
| 423 } | 674 } |
| 424 } | 675 } |
| 425 | 676 |
| 677 void VaapiVideoDecodeAccelerator::RecycleVASurfaceID( | |
| 678 VASurfaceID va_surface_id) { | |
| 679 DCHECK_EQ(message_loop_, base::MessageLoop::current()); | |
| 680 | |
| 681 base::AutoLock auto_lock(lock_); | |
| 682 | |
| 683 available_va_surfaces_.push_back(va_surface_id); | |
| 684 surfaces_available_.Signal(); | |
| 685 } | |
| 686 | |
| 426 void VaapiVideoDecodeAccelerator::AssignPictureBuffers( | 687 void VaapiVideoDecodeAccelerator::AssignPictureBuffers( |
| 427 const std::vector<media::PictureBuffer>& buffers) { | 688 const std::vector<media::PictureBuffer>& buffers) { |
| 428 DCHECK_EQ(message_loop_, base::MessageLoop::current()); | 689 DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
| 429 | 690 |
| 430 base::AutoLock auto_lock(lock_); | 691 base::AutoLock auto_lock(lock_); |
| 431 DCHECK_EQ(state_, kPicturesRequested); | 692 DCHECK_EQ(state_, kPicturesRequested); |
| 432 size_t num_pics = decoder_.GetRequiredNumOfPictures(); | 693 DCHECK(tfp_pictures_.empty()); |
| 433 RETURN_AND_NOTIFY_ON_FAILURE((num_pics == buffers.size()), | 694 |
| 434 "Failed to provide requested picture buffers. (Got " << buffers.size() << | 695 RETURN_AND_NOTIFY_ON_FAILURE( |
| 435 ", requested " << num_pics << ")", INVALID_ARGUMENT,); | 696 buffers.size() == num_pics_, |
| 697 "Got an invalid number of picture buffers. (Got " << buffers.size() | |
| 698 << ", requested " << num_pics_ << ")", INVALID_ARGUMENT, ); | |
| 699 | |
| 700 std::vector<VASurfaceID> va_surface_ids; | |
| 701 RETURN_AND_NOTIFY_ON_FAILURE( | |
| 702 vaapi_delegate_->CreateSurfaces(pic_size_.width(), pic_size_.height(), | |
| 703 buffers.size(), | |
| 704 va_surface_ids), | |
| 705 "Failed creating VA Surfaces", PLATFORM_FAILURE, ); | |
| 706 DCHECK_EQ(va_surface_ids.size(), buffers.size()); | |
| 436 | 707 |
| 437 for (size_t i = 0; i < buffers.size(); ++i) { | 708 for (size_t i = 0; i < buffers.size(); ++i) { |
| 438 DVLOG(2) << "Assigning picture id " << buffers[i].id() | 709 DVLOG(2) << "Assigning picture id: " << buffers[i].id() |
| 439 << " to texture id " << buffers[i].texture_id(); | 710 << " to texture id: " << buffers[i].texture_id() |
| 711 << " VASurfaceID: " << va_surface_ids[i]; | |
| 440 | 712 |
| 441 bool res = decoder_.AssignPictureBuffer(buffers[i].id(), | 713 linked_ptr<TFPPicture> tfp_picture( |
| 442 buffers[i].texture_id()); | 714 TFPPicture::Create(make_context_current_, fb_config_, x_display_, |
| 715 buffers[i].id(), buffers[i].texture_id(), | |
| 716 pic_size_.width(), pic_size_.height())); | |
| 717 | |
| 443 RETURN_AND_NOTIFY_ON_FAILURE( | 718 RETURN_AND_NOTIFY_ON_FAILURE( |
| 444 res, "Failed assigning picture buffer id: " << buffers[i].id() << | 719 tfp_picture.get(), "Failed assigning picture buffer to a texture.", |
| 445 ", texture id: " << buffers[i].texture_id(), PLATFORM_FAILURE, ); | 720 PLATFORM_FAILURE, ); |
| 721 | |
| 722 bool inserted = tfp_pictures_.insert(std::make_pair( | |
| 723 buffers[i].id(), tfp_picture)).second; | |
| 724 DCHECK(inserted); | |
| 725 | |
| 726 output_buffers_.push(buffers[i].id()); | |
| 727 available_va_surfaces_.push_back(va_surface_ids[i]); | |
| 728 surfaces_available_.Signal(); | |
| 446 } | 729 } |
| 447 | 730 |
| 448 state_ = kDecoding; | 731 state_ = kDecoding; |
| 449 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 732 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
| 450 &VaapiVideoDecodeAccelerator::DecodeTask, base::Unretained(this))); | 733 &VaapiVideoDecodeAccelerator::DecodeTask, base::Unretained(this))); |
| 451 } | 734 } |
| 452 | 735 |
| 453 void VaapiVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { | 736 void VaapiVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id) { |
| 454 DCHECK_EQ(message_loop_, base::MessageLoop::current()); | 737 DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
| 455 TRACE_EVENT1("Video Decoder", "VAVDA::ReusePictureBuffer", "Picture id", | 738 TRACE_EVENT1("Video Decoder", "VAVDA::ReusePictureBuffer", "Picture id", |
| 456 picture_buffer_id); | 739 picture_buffer_id); |
| 457 | 740 |
| 458 --num_frames_at_client_; | 741 --num_frames_at_client_; |
| 459 TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_); | 742 TRACE_COUNTER1("Video Decoder", "Textures at client", num_frames_at_client_); |
| 460 | 743 |
| 461 base::AutoLock auto_lock(lock_); | |
| 462 output_buffers_.push(picture_buffer_id); | 744 output_buffers_.push(picture_buffer_id); |
| 463 output_ready_.Signal(); | 745 TryOutputSurface(); |
| 464 } | 746 } |
| 465 | 747 |
| 466 void VaapiVideoDecodeAccelerator::FlushTask() { | 748 void VaapiVideoDecodeAccelerator::FlushTask() { |
| 467 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 749 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 468 DVLOG(1) << "Flush task"; | 750 DVLOG(1) << "Flush task"; |
| 469 | 751 |
| 470 base::AutoLock auto_lock(lock_); | |
| 471 | |
| 472 // First flush all the pictures that haven't been outputted, notifying the | 752 // First flush all the pictures that haven't been outputted, notifying the |
| 473 // client to output them. | 753 // client to output them. |
| 474 bool res = decoder_.Flush(); | 754 bool res = decoder_->Flush(); |
| 475 RETURN_AND_NOTIFY_ON_FAILURE(res, "Failed flushing the decoder.", | 755 RETURN_AND_NOTIFY_ON_FAILURE(res, "Failed flushing the decoder.", |
| 476 PLATFORM_FAILURE, ); | 756 PLATFORM_FAILURE, ); |
| 477 | 757 |
| 478 // Put the decoder in idle state, ready to resume. | 758 // Put the decoder in idle state, ready to resume. |
| 479 decoder_.Reset(); | 759 decoder_->Reset(); |
| 480 | 760 |
| 481 message_loop_->PostTask(FROM_HERE, base::Bind( | 761 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 482 &VaapiVideoDecodeAccelerator::FinishFlush, weak_this_)); | 762 &VaapiVideoDecodeAccelerator::FinishFlush, weak_this_)); |
| 483 } | 763 } |
| 484 | 764 |
| 485 void VaapiVideoDecodeAccelerator::Flush() { | 765 void VaapiVideoDecodeAccelerator::Flush() { |
| 486 DCHECK_EQ(message_loop_, base::MessageLoop::current()); | 766 DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
| 487 DVLOG(1) << "Got flush request"; | 767 DVLOG(1) << "Got flush request"; |
| 488 | 768 |
| 489 base::AutoLock auto_lock(lock_); | 769 base::AutoLock auto_lock(lock_); |
| 490 state_ = kFlushing; | 770 state_ = kFlushing; |
| 491 // Queue a flush task after all existing decoding tasks to clean up. | 771 // Queue a flush task after all existing decoding tasks to clean up. |
| 492 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 772 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
| 493 &VaapiVideoDecodeAccelerator::FlushTask, base::Unretained(this))); | 773 &VaapiVideoDecodeAccelerator::FlushTask, base::Unretained(this))); |
| 494 | 774 |
| 495 input_ready_.Signal(); | 775 input_ready_.Signal(); |
| 496 output_ready_.Signal(); | 776 surfaces_available_.Signal(); |
| 497 } | 777 } |
| 498 | 778 |
| 499 void VaapiVideoDecodeAccelerator::FinishFlush() { | 779 void VaapiVideoDecodeAccelerator::FinishFlush() { |
| 500 DCHECK_EQ(message_loop_, base::MessageLoop::current()); | 780 DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
| 501 | 781 |
| 502 base::AutoLock auto_lock(lock_); | 782 base::AutoLock auto_lock(lock_); |
| 503 if (state_ != kFlushing) { | 783 if (state_ != kFlushing) { |
| 504 DCHECK_EQ(state_, kDestroying); | 784 DCHECK_EQ(state_, kDestroying); |
| 505 return; // We could've gotten destroyed already. | 785 return; // We could've gotten destroyed already. |
| 506 } | 786 } |
| 507 | 787 |
| 508 state_ = kIdle; | 788 state_ = kIdle; |
| 509 | 789 |
| 510 message_loop_->PostTask(FROM_HERE, base::Bind( | 790 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 511 &Client::NotifyFlushDone, client_)); | 791 &Client::NotifyFlushDone, client_)); |
| 512 | 792 |
| 513 DVLOG(1) << "Flush finished"; | 793 DVLOG(1) << "Flush finished"; |
| 514 } | 794 } |
| 515 | 795 |
| 516 void VaapiVideoDecodeAccelerator::ResetTask() { | 796 void VaapiVideoDecodeAccelerator::ResetTask() { |
| 517 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 797 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
| 518 | 798 |
| 519 base::AutoLock auto_lock(lock_); | |
| 520 | |
| 521 // All the decoding tasks from before the reset request from client are done | 799 // All the decoding tasks from before the reset request from client are done |
| 522 // by now, as this task was scheduled after them and client is expected not | 800 // by now, as this task was scheduled after them and client is expected not |
| 523 // to call Decode() after Reset() and before NotifyResetDone. | 801 // to call Decode() after Reset() and before NotifyResetDone. |
| 524 decoder_.Reset(); | 802 decoder_->Reset(); |
| 803 | |
| 804 base::AutoLock auto_lock(lock_); | |
| 525 | 805 |
| 526 // Return current input buffer, if present. | 806 // Return current input buffer, if present. |
| 527 if (curr_input_buffer_.get()) | 807 if (curr_input_buffer_.get()) |
| 528 ReturnCurrInputBuffer_Locked(); | 808 ReturnCurrInputBuffer_Locked(); |
| 529 | 809 |
| 530 // And let client know that we are done with reset. | 810 // And let client know that we are done with reset. |
| 531 message_loop_->PostTask(FROM_HERE, base::Bind( | 811 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 532 &VaapiVideoDecodeAccelerator::FinishReset, weak_this_)); | 812 &VaapiVideoDecodeAccelerator::FinishReset, weak_this_)); |
| 533 } | 813 } |
| 534 | 814 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 545 message_loop_->PostTask(FROM_HERE, base::Bind( | 825 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 546 &Client::NotifyEndOfBitstreamBuffer, client_, | 826 &Client::NotifyEndOfBitstreamBuffer, client_, |
| 547 input_buffers_.front()->id)); | 827 input_buffers_.front()->id)); |
| 548 input_buffers_.pop(); | 828 input_buffers_.pop(); |
| 549 } | 829 } |
| 550 | 830 |
| 551 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 831 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
| 552 &VaapiVideoDecodeAccelerator::ResetTask, base::Unretained(this))); | 832 &VaapiVideoDecodeAccelerator::ResetTask, base::Unretained(this))); |
| 553 | 833 |
| 554 input_ready_.Signal(); | 834 input_ready_.Signal(); |
| 555 output_ready_.Signal(); | 835 surfaces_available_.Signal(); |
| 556 } | 836 } |
| 557 | 837 |
| 558 void VaapiVideoDecodeAccelerator::FinishReset() { | 838 void VaapiVideoDecodeAccelerator::FinishReset() { |
| 559 DCHECK_EQ(message_loop_, base::MessageLoop::current()); | 839 DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
| 560 | 840 |
| 561 base::AutoLock auto_lock(lock_); | 841 base::AutoLock auto_lock(lock_); |
| 562 if (state_ != kResetting) { | 842 if (state_ != kResetting) { |
| 563 DCHECK(state_ == kDestroying || state_ == kUninitialized) << state_; | 843 DCHECK(state_ == kDestroying || state_ == kUninitialized) << state_; |
| 564 return; // We could've gotten destroyed already. | 844 return; // We could've gotten destroyed already. |
| 565 } | 845 } |
| 566 | 846 |
| 567 state_ = kIdle; | 847 state_ = kIdle; |
| 568 num_stream_bufs_at_decoder_ = 0; | 848 num_stream_bufs_at_decoder_ = 0; |
| 569 | 849 |
| 850 while(!pending_output_cbs_.empty()) | |
| 851 pending_output_cbs_.pop(); | |
| 852 | |
| 570 message_loop_->PostTask(FROM_HERE, base::Bind( | 853 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 571 &Client::NotifyResetDone, client_)); | 854 &Client::NotifyResetDone, client_)); |
| 572 | 855 |
| 573 // The client might have given us new buffers via Decode() while we were | 856 // The client might have given us new buffers via Decode() while we were |
| 574 // resetting and might be waiting for our move, and not call Decode() anymore | 857 // resetting and might be waiting for our move, and not call Decode() anymore |
| 575 // until we return something. Post an InitialDecodeTask() so that we won't | 858 // until we return something. Post an InitialDecodeTask() so that we won't |
| 576 // sleep forever waiting for Decode() in that case. Having two of them | 859 // sleep forever waiting for Decode() in that case. Having two of them |
| 577 // in the pipe is harmless, the additional one will return as soon as it sees | 860 // in the pipe is harmless, the additional one will return as soon as it sees |
| 578 // that we are back in kDecoding state. | 861 // that we are back in kDecoding state. |
| 579 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 862 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 595 | 878 |
| 596 client_ptr_factory_.InvalidateWeakPtrs(); | 879 client_ptr_factory_.InvalidateWeakPtrs(); |
| 597 | 880 |
| 598 { | 881 { |
| 599 base::AutoUnlock auto_unlock(lock_); | 882 base::AutoUnlock auto_unlock(lock_); |
| 600 // Post a dummy task to the decoder_thread_ to ensure it is drained. | 883 // Post a dummy task to the decoder_thread_ to ensure it is drained. |
| 601 base::WaitableEvent waiter(false, false); | 884 base::WaitableEvent waiter(false, false); |
| 602 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 885 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
| 603 &base::WaitableEvent::Signal, base::Unretained(&waiter))); | 886 &base::WaitableEvent::Signal, base::Unretained(&waiter))); |
| 604 input_ready_.Signal(); | 887 input_ready_.Signal(); |
| 605 output_ready_.Signal(); | 888 surfaces_available_.Signal(); |
| 606 waiter.Wait(); | 889 waiter.Wait(); |
| 607 decoder_thread_.Stop(); | 890 decoder_thread_.Stop(); |
| 608 } | 891 } |
| 609 | 892 |
| 610 decoder_.Destroy(); | |
| 611 state_ = kUninitialized; | 893 state_ = kUninitialized; |
| 612 } | 894 } |
| 613 | 895 |
| 614 void VaapiVideoDecodeAccelerator::Destroy() { | 896 void VaapiVideoDecodeAccelerator::Destroy() { |
| 615 DCHECK_EQ(message_loop_, base::MessageLoop::current()); | 897 DCHECK_EQ(message_loop_, base::MessageLoop::current()); |
| 616 Cleanup(); | 898 Cleanup(); |
| 617 delete this; | 899 delete this; |
| 618 } | 900 } |
| 619 | 901 |
| 620 // static | |
| 621 void VaapiVideoDecodeAccelerator::PreSandboxInitialization() { | |
| 622 VaapiH264Decoder::PreSandboxInitialization(); | |
| 623 } | |
| 624 | |
| 625 // static | |
| 626 bool VaapiVideoDecodeAccelerator::PostSandboxInitialization() { | |
| 627 return VaapiH264Decoder::PostSandboxInitialization(); | |
| 628 } | |
| 629 | |
| 630 } // namespace content | 902 } // namespace content |
| OLD | NEW |