Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(230)

Side by Side Diff: content/common/gpu/media/vaapi_video_decode_accelerator.cc

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

Powered by Google App Engine
This is Rietveld 408576698