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

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

Powered by Google App Engine
This is Rietveld 408576698