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 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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |