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 <dlfcn.h> | |
6 | |
7 #include <algorithm> | 5 #include <algorithm> |
8 #include <limits> | 6 #include <limits> |
9 | 7 |
10 #include "base/bind.h" | 8 #include "base/bind.h" |
11 #include "base/bind_helpers.h" | 9 #include "base/bind_helpers.h" |
12 #include "base/metrics/histogram.h" | |
13 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
14 #include "content/common/gpu/media/vaapi_h264_decoder.h" | 11 #include "content/common/gpu/media/vaapi_h264_decoder.h" |
15 #include "third_party/libva/va/va.h" | |
16 #include "third_party/libva/va/va_x11.h" | |
17 #include "ui/gl/gl_bindings.h" | |
18 #include "ui/gl/scoped_binders.h" | |
19 | |
20 namespace { | |
21 | |
22 enum VAVDAH264DecoderFailure { | |
23 FRAME_MBS_ONLY_FLAG_NOT_ONE = 0, | |
24 GAPS_IN_FRAME_NUM = 1, | |
25 MID_STREAM_RESOLUTION_CHANGE = 2, | |
26 INTERLACED_STREAM = 3, | |
27 VAAPI_ERROR = 4, | |
28 VAVDA_H264_DECODER_FAILURES_MAX, | |
29 }; | |
30 | |
31 static void ReportToUMA(VAVDAH264DecoderFailure failure) { | |
32 UMA_HISTOGRAM_ENUMERATION("Media.VAVDAH264.DecoderFailure", | |
33 failure, | |
34 VAVDA_H264_DECODER_FAILURES_MAX); | |
35 } | |
36 | |
37 } // namespace | |
38 | |
39 #define LOG_VA_ERROR_AND_RECORD_UMA(va_res, err_msg) \ | |
40 do { \ | |
41 DVLOG(1) << err_msg \ | |
42 << " VA error: " << VAAPI_ErrorStr(va_res); \ | |
43 ReportToUMA(VAAPI_ERROR); \ | |
44 } while (0) | |
45 | |
46 #define VA_LOG_ON_ERROR(va_res, err_msg) \ | |
47 do { \ | |
48 if ((va_res) != VA_STATUS_SUCCESS) { \ | |
49 LOG_VA_ERROR_AND_RECORD_UMA(va_res, err_msg); \ | |
50 } \ | |
51 } while (0) | |
52 | |
53 #define VA_SUCCESS_OR_RETURN(va_res, err_msg, ret) \ | |
54 do { \ | |
55 if ((va_res) != VA_STATUS_SUCCESS) { \ | |
56 LOG_VA_ERROR_AND_RECORD_UMA(va_res, err_msg); \ | |
57 return (ret); \ | |
58 } \ | |
59 } while (0) | |
60 | 12 |
61 namespace content { | 13 namespace content { |
62 | 14 |
63 void *vaapi_handle = NULL; | 15 // Decode surface, used for decoding and reference. input_id comes from client |
64 void *vaapi_x11_handle = NULL; | 16 // and is associated with the surface that was produced as the result |
65 | 17 // of decoding a bitstream buffer with that id. |
66 typedef VADisplay (*VaapiGetDisplay)(Display *dpy); | |
67 typedef int (*VaapiDisplayIsValid)(VADisplay dpy); | |
68 typedef VAStatus (*VaapiInitialize)(VADisplay dpy, | |
69 int *major_version, | |
70 int *minor_version); | |
71 typedef VAStatus (*VaapiTerminate)(VADisplay dpy); | |
72 typedef VAStatus (*VaapiGetConfigAttributes)(VADisplay dpy, | |
73 VAProfile profile, | |
74 VAEntrypoint entrypoint, | |
75 VAConfigAttrib *attrib_list, | |
76 int num_attribs); | |
77 typedef VAStatus (*VaapiCreateConfig)(VADisplay dpy, | |
78 VAProfile profile, | |
79 VAEntrypoint entrypoint, | |
80 VAConfigAttrib *attrib_list, | |
81 int num_attribs, | |
82 VAConfigID *config_id); | |
83 typedef VAStatus (*VaapiDestroyConfig)(VADisplay dpy, VAConfigID config_id); | |
84 typedef VAStatus (*VaapiCreateSurfaces)(VADisplay dpy, | |
85 int width, | |
86 int height, | |
87 int format, | |
88 int num_surfaces, | |
89 VASurfaceID *surfaces); | |
90 typedef VAStatus (*VaapiDestroySurfaces)(VADisplay dpy, | |
91 VASurfaceID *surfaces, | |
92 int num_surfaces); | |
93 typedef VAStatus (*VaapiCreateContext)(VADisplay dpy, | |
94 VAConfigID config_id, | |
95 int picture_width, | |
96 int picture_height, | |
97 int flag, | |
98 VASurfaceID *render_targets, | |
99 int num_render_targets, | |
100 VAContextID *context); | |
101 typedef VAStatus (*VaapiDestroyContext)(VADisplay dpy, VAContextID context); | |
102 typedef VAStatus (*VaapiPutSurface)(VADisplay dpy, | |
103 VASurfaceID surface, | |
104 Drawable draw, | |
105 short srcx, | |
106 short srcy, | |
107 unsigned short srcw, | |
108 unsigned short srch, | |
109 short destx, | |
110 short desty, | |
111 unsigned short destw, | |
112 unsigned short desth, | |
113 VARectangle *cliprects, | |
114 unsigned int number_cliprects, | |
115 unsigned int flags); | |
116 typedef VAStatus (*VaapiSyncSurface)(VADisplay dpy, VASurfaceID render_target); | |
117 typedef VAStatus (*VaapiBeginPicture)(VADisplay dpy, | |
118 VAContextID context, | |
119 VASurfaceID render_target); | |
120 typedef VAStatus (*VaapiRenderPicture)(VADisplay dpy, | |
121 VAContextID context, | |
122 VABufferID *buffers, | |
123 int num_buffers); | |
124 typedef VAStatus (*VaapiEndPicture)(VADisplay dpy, VAContextID context); | |
125 typedef VAStatus (*VaapiCreateBuffer)(VADisplay dpy, | |
126 VAContextID context, | |
127 VABufferType type, | |
128 unsigned int size, | |
129 unsigned int num_elements, | |
130 void *data, | |
131 VABufferID *buf_id); | |
132 typedef VAStatus (*VaapiDestroyBuffer)(VADisplay dpy, VABufferID buffer_id); | |
133 typedef const char* (*VaapiErrorStr)(VAStatus error_status); | |
134 | |
135 #define VAAPI_SYM(name, handle) Vaapi##name VAAPI_##name = NULL | |
136 | |
137 VAAPI_SYM(GetDisplay, vaapi_x11_handle); | |
138 VAAPI_SYM(DisplayIsValid, vaapi_handle); | |
139 VAAPI_SYM(Initialize, vaapi_handle); | |
140 VAAPI_SYM(Terminate, vaapi_handle); | |
141 VAAPI_SYM(GetConfigAttributes, vaapi_handle); | |
142 VAAPI_SYM(CreateConfig, vaapi_handle); | |
143 VAAPI_SYM(DestroyConfig, vaapi_handle); | |
144 VAAPI_SYM(CreateSurfaces, vaapi_handle); | |
145 VAAPI_SYM(DestroySurfaces, vaapi_handle); | |
146 VAAPI_SYM(CreateContext, vaapi_handle); | |
147 VAAPI_SYM(DestroyContext, vaapi_handle); | |
148 VAAPI_SYM(PutSurface, vaapi_x11_handle); | |
149 VAAPI_SYM(SyncSurface, vaapi_x11_handle); | |
150 VAAPI_SYM(BeginPicture, vaapi_handle); | |
151 VAAPI_SYM(RenderPicture, vaapi_handle); | |
152 VAAPI_SYM(EndPicture, vaapi_handle); | |
153 VAAPI_SYM(CreateBuffer, vaapi_handle); | |
154 VAAPI_SYM(DestroyBuffer, vaapi_handle); | |
155 VAAPI_SYM(ErrorStr, vaapi_handle); | |
156 | |
157 // static | |
158 bool VaapiH264Decoder::pre_sandbox_init_done_ = false; | |
159 | |
160 class VaapiH264Decoder::DecodeSurface { | 18 class VaapiH264Decoder::DecodeSurface { |
161 public: | 19 public: |
162 DecodeSurface(const GLXFBConfig& fb_config, | 20 DecodeSurface(int poc, |
163 Display* x_display, | 21 int32 input_id, |
164 VADisplay va_display, | 22 const scoped_refptr<VASurface>& va_surface); |
165 const base::Callback<bool(void)>& make_context_current, | 23 DecodeSurface(int poc, const scoped_refptr<DecodeSurface>& dec_surface); |
166 VASurfaceID va_surface_id, | |
167 int32 picture_buffer_id, | |
168 uint32 texture_id, | |
169 int width, int height); | |
170 ~DecodeSurface(); | 24 ~DecodeSurface(); |
171 | 25 |
172 VASurfaceID va_surface_id() { | 26 int poc() { |
173 return va_surface_id_; | 27 return poc_; |
174 } | 28 } |
175 | 29 |
176 int32 picture_buffer_id() { | 30 scoped_refptr<VASurface> va_surface() { |
177 return picture_buffer_id_; | 31 return va_surface_; |
178 } | |
179 | |
180 uint32 texture_id() { | |
181 return texture_id_; | |
182 } | |
183 | |
184 bool available() { | |
185 return available_; | |
186 } | |
187 | |
188 bool used() { | |
189 return used_; | |
190 } | |
191 | |
192 void set_used(bool used) { | |
193 DCHECK(!available_); | |
194 used_ = used; | |
195 } | |
196 | |
197 bool at_client() { | |
198 return at_client_; | |
199 } | |
200 | |
201 void set_at_client(bool at_client) { | |
202 DCHECK(!available_); | |
203 at_client_ = at_client; | |
204 } | 32 } |
205 | 33 |
206 int32 input_id() { | 34 int32 input_id() { |
207 return input_id_; | 35 return input_id_; |
208 } | 36 } |
209 | 37 |
210 int poc() { | |
211 return poc_; | |
212 } | |
213 | |
214 // Associate the surface with |input_id| and |poc|, and make it unavailable | |
215 // (in use). | |
216 void Acquire(int32 input_id, int poc); | |
217 | |
218 // Make this surface available, ready to be reused. | |
219 void Release(); | |
220 | |
221 // Has to be called before output to sync texture contents. | |
222 // Returns true if successful. | |
223 bool Sync(); | |
224 | |
225 private: | 38 private: |
226 Display* x_display_; | 39 int poc_; |
227 VADisplay va_display_; | |
228 base::Callback<bool(void)> make_context_current_; | |
229 VASurfaceID va_surface_id_; | |
230 | |
231 // Client-provided ids. | |
232 int32 input_id_; | 40 int32 input_id_; |
233 int32 picture_buffer_id_; | 41 scoped_refptr<VASurface> va_surface_; |
234 uint32 texture_id_; | |
235 | |
236 int width_; | |
237 int height_; | |
238 | |
239 // Available for decoding (data no longer used for reference or displaying). | |
240 // TODO(posciak): this is almost surely not needed anymore. Rethink and | |
241 // remove if possible. | |
242 bool available_; | |
243 // Used for decoding. | |
244 bool used_; | |
245 // Whether the surface has been sent to client for display. | |
246 bool at_client_; | |
247 | |
248 // PicOrderCount | |
249 int poc_; | |
250 | |
251 // Pixmaps bound to this texture. | |
252 Pixmap x_pixmap_; | |
253 GLXPixmap glx_pixmap_; | |
254 | |
255 DISALLOW_COPY_AND_ASSIGN(DecodeSurface); | |
256 }; | 42 }; |
257 | 43 |
258 VaapiH264Decoder::DecodeSurface::DecodeSurface( | 44 VaapiH264Decoder::DecodeSurface::DecodeSurface( |
259 const GLXFBConfig& fb_config, | 45 int poc, |
260 Display* x_display, | 46 int32 input_id, |
261 VADisplay va_display, | 47 const scoped_refptr<VASurface>& va_surface) |
262 const base::Callback<bool(void)>& make_context_current, | 48 : poc_(poc), |
263 VASurfaceID va_surface_id, | 49 input_id_(input_id), |
264 int32 picture_buffer_id, | 50 va_surface_(va_surface) { |
265 uint32 texture_id, | 51 DCHECK(va_surface_.get()); |
266 int width, int height) | |
267 : x_display_(x_display), | |
268 va_display_(va_display), | |
269 make_context_current_(make_context_current), | |
270 va_surface_id_(va_surface_id), | |
271 input_id_(0), | |
272 picture_buffer_id_(picture_buffer_id), | |
273 texture_id_(texture_id), | |
274 width_(width), | |
275 height_(height), | |
276 available_(false), | |
277 used_(false), | |
278 at_client_(false), | |
279 poc_(0), | |
280 x_pixmap_(0), | |
281 glx_pixmap_(0) { | |
282 // Bind the surface to a texture of the given width and height, | |
283 // allocating pixmaps as needed. | |
284 if (!make_context_current_.Run()) | |
285 return; | |
286 | |
287 gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, texture_id_); | |
288 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
289 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
290 | |
291 XWindowAttributes win_attr; | |
292 int screen = DefaultScreen(x_display_); | |
293 XGetWindowAttributes(x_display_, RootWindow(x_display_, screen), &win_attr); | |
294 //TODO(posciak): pass the depth required by libva, not the RootWindow's depth | |
295 x_pixmap_ = XCreatePixmap(x_display_, RootWindow(x_display_, screen), | |
296 width_, height_, win_attr.depth); | |
297 if (!x_pixmap_) { | |
298 DVLOG(1) << "Failed creating an X Pixmap for TFP"; | |
299 return; | |
300 } | |
301 | |
302 static const int pixmap_attr[] = { | |
303 GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, | |
304 GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT, | |
305 GL_NONE, | |
306 }; | |
307 | |
308 glx_pixmap_ = glXCreatePixmap(x_display_, fb_config, x_pixmap_, pixmap_attr); | |
309 if (!glx_pixmap_) { | |
310 // x_pixmap_ will be freed in the destructor. | |
311 DVLOG(1) << "Failed creating a GLX Pixmap for TFP"; | |
312 return; | |
313 } | |
314 | |
315 glXBindTexImageEXT(x_display_, glx_pixmap_, GLX_FRONT_LEFT_EXT, NULL); | |
316 | |
317 available_ = true; | |
318 } | 52 } |
319 | 53 |
320 VaapiH264Decoder::DecodeSurface::~DecodeSurface() { | 54 VaapiH264Decoder::DecodeSurface::~DecodeSurface() { |
321 // Unbind surface from texture and deallocate resources. | |
322 if (glx_pixmap_ && make_context_current_.Run()) { | |
323 glXReleaseTexImageEXT(x_display_, glx_pixmap_, GLX_FRONT_LEFT_EXT); | |
324 glXDestroyPixmap(x_display_, glx_pixmap_); | |
325 } | |
326 | |
327 if (x_pixmap_) | |
328 XFreePixmap(x_display_, x_pixmap_); | |
329 XSync(x_display_, False); // Needed to work around buggy vdpau-driver. | |
330 } | 55 } |
331 | 56 |
332 void VaapiH264Decoder::DecodeSurface::Acquire(int32 input_id, int poc) { | 57 VaapiH264Decoder::VaapiH264Decoder( |
333 DCHECK_EQ(available_, true); | 58 VaapiWrapper* vaapi_wrapper, |
334 available_ = false; | 59 const OutputPicCB& output_pic_cb, |
335 at_client_ = false; | 60 const ReportErrorToUmaCB& report_error_to_uma_cb) |
336 used_ = true; | 61 : max_pic_order_cnt_lsb_(0), |
337 input_id_ = input_id; | 62 max_frame_num_(0), |
338 poc_ = poc; | 63 max_pic_num_(0), |
339 } | 64 max_long_term_frame_idx_(0), |
340 | 65 curr_sps_id_(-1), |
341 void VaapiH264Decoder::DecodeSurface::Release() { | 66 curr_pps_id_(-1), |
342 DCHECK_EQ(available_, false); | 67 vaapi_wrapper_(vaapi_wrapper), |
343 available_ = true; | 68 output_pic_cb_(output_pic_cb), |
344 used_ = false; | 69 report_error_to_uma_cb_(report_error_to_uma_cb) { |
345 at_client_ = false; | |
346 } | |
347 | |
348 bool VaapiH264Decoder::DecodeSurface::Sync() { | |
349 if (!make_context_current_.Run()) | |
350 return false; | |
351 | |
352 // Wait for the data to be put into the buffer so it'd ready for output. | |
353 VAStatus va_res = VAAPI_SyncSurface(va_display_, va_surface_id_); | |
354 VA_SUCCESS_OR_RETURN(va_res, "Failed syncing decoded picture", false); | |
355 | |
356 // Put the decoded data into XPixmap bound to the texture. | |
357 va_res = VAAPI_PutSurface(va_display_, | |
358 va_surface_id_, x_pixmap_, | |
359 0, 0, width_, height_, | |
360 0, 0, width_, height_, | |
361 NULL, 0, 0); | |
362 VA_SUCCESS_OR_RETURN(va_res, "Failed putting decoded picture to texture", | |
363 false); | |
364 | |
365 return true; | |
366 } | |
367 | |
368 VaapiH264Decoder::VaapiH264Decoder() { | |
369 Reset(); | 70 Reset(); |
370 curr_input_id_ = -1; | |
371 x_display_ = NULL; | |
372 fb_config_ = NULL; | |
373 va_display_ = NULL; | |
374 curr_sps_id_ = -1; | |
375 curr_pps_id_ = -1; | |
376 pic_width_ = -1; | |
377 pic_height_ = -1; | |
378 max_frame_num_ = 0; | |
379 max_pic_num_ = 0; | |
380 max_long_term_frame_idx_ = 0; | |
381 max_pic_order_cnt_lsb_ = 0; | |
382 state_ = kUninitialized; | |
383 num_available_decode_surfaces_ = 0; | |
384 va_context_created_ = false; | |
385 last_output_poc_ = 0; | |
386 } | 71 } |
387 | 72 |
388 VaapiH264Decoder::~VaapiH264Decoder() { | 73 VaapiH264Decoder::~VaapiH264Decoder() { |
389 Destroy(); | |
390 } | 74 } |
391 | 75 |
392 // This puts the decoder in state where it keeps stream data and is ready | |
393 // to resume playback from a random location in the stream, but drops all | |
394 // inputs and outputs and makes all surfaces available for use. | |
395 void VaapiH264Decoder::Reset() { | 76 void VaapiH264Decoder::Reset() { |
396 frame_ready_at_hw_ = false; | |
397 | |
398 curr_pic_.reset(); | 77 curr_pic_.reset(); |
399 | 78 |
| 79 curr_input_id_ = -1; |
400 frame_num_ = 0; | 80 frame_num_ = 0; |
401 prev_frame_num_ = -1; | 81 prev_frame_num_ = -1; |
402 prev_frame_num_offset_ = -1; | 82 prev_frame_num_offset_ = -1; |
403 | 83 |
404 prev_ref_has_memmgmnt5_ = false; | 84 prev_ref_has_memmgmnt5_ = false; |
405 prev_ref_top_field_order_cnt_ = -1; | 85 prev_ref_top_field_order_cnt_ = -1; |
406 prev_ref_pic_order_cnt_msb_ = -1; | 86 prev_ref_pic_order_cnt_msb_ = -1; |
407 prev_ref_pic_order_cnt_lsb_ = -1; | 87 prev_ref_pic_order_cnt_lsb_ = -1; |
408 prev_ref_field_ = H264Picture::FIELD_NONE; | 88 prev_ref_field_ = H264Picture::FIELD_NONE; |
409 | 89 |
410 // When called from the constructor, although va_display_ is invalid, | 90 vaapi_wrapper_->DestroyPendingBuffers(); |
411 // |pending_slice_bufs_| and |pending_va_bufs_| are empty. | |
412 DestroyPendingBuffers(); | |
413 | |
414 pending_slice_bufs_ = std::queue<VABufferID>(); | |
415 pending_va_bufs_ = std::queue<VABufferID>(); | |
416 | 91 |
417 ref_pic_list0_.clear(); | 92 ref_pic_list0_.clear(); |
418 ref_pic_list1_.clear(); | 93 ref_pic_list1_.clear(); |
419 | 94 |
420 for (POCToDecodeSurfaces::iterator it = poc_to_decode_surfaces_.begin(); | 95 for (DecSurfacesInUse::iterator it = decode_surfaces_in_use_.begin(); |
421 it != poc_to_decode_surfaces_.end(); ) { | 96 it != decode_surfaces_in_use_.end(); ) { |
422 int poc = it->second->poc(); | 97 int poc = it->second->poc(); |
423 // Must be incremented before UnassignSurfaceFromPoC as this call | 98 // Must be incremented before UnassignSurfaceFromPoC as this call |
424 // invalidates |it|. | 99 // invalidates |it|. |
425 ++it; | 100 ++it; |
426 UnassignSurfaceFromPoC(poc); | 101 UnassignSurfaceFromPoC(poc); |
427 } | 102 } |
428 DCHECK(poc_to_decode_surfaces_.empty()); | 103 DCHECK(decode_surfaces_in_use_.empty()); |
429 | 104 |
430 dpb_.Clear(); | 105 dpb_.Clear(); |
431 parser_.Reset(); | 106 parser_.Reset(); |
432 last_output_poc_ = 0; | 107 last_output_poc_ = 0; |
433 | 108 |
434 // Still initialized and ready to decode, unless called from constructor, | 109 state_ = kIdle; |
435 // which will change it back. | |
436 state_ = kAfterReset; | |
437 } | 110 } |
438 | 111 |
439 void VaapiH264Decoder::Destroy() { | 112 void VaapiH264Decoder::ReuseSurface( |
440 if (state_ == kUninitialized) | 113 const scoped_refptr<VASurface>& va_surface) { |
441 return; | 114 available_va_surfaces_.push_back(va_surface); |
442 | |
443 VAStatus va_res; | |
444 bool destroy_surfaces = false; | |
445 switch (state_) { | |
446 case kDecoding: | |
447 case kAfterReset: | |
448 case kError: | |
449 destroy_surfaces = true; | |
450 // fallthrough | |
451 case kInitialized: | |
452 if (!make_context_current_.Run()) | |
453 break; | |
454 if (destroy_surfaces) | |
455 DestroyVASurfaces(); | |
456 DestroyPendingBuffers(); | |
457 va_res = VAAPI_DestroyConfig(va_display_, va_config_id_); | |
458 VA_LOG_ON_ERROR(va_res, "vaDestroyConfig failed"); | |
459 va_res = VAAPI_Terminate(va_display_); | |
460 VA_LOG_ON_ERROR(va_res, "vaTerminate failed"); | |
461 // fallthrough | |
462 case kUninitialized: | |
463 break; | |
464 } | |
465 | |
466 state_ = kUninitialized; | |
467 } | |
468 | |
469 // Maps Profile enum values to VaProfile values. | |
470 bool VaapiH264Decoder::SetProfile(media::VideoCodecProfile profile) { | |
471 switch (profile) { | |
472 case media::H264PROFILE_BASELINE: | |
473 profile_ = VAProfileH264Baseline; | |
474 break; | |
475 case media::H264PROFILE_MAIN: | |
476 profile_ = VAProfileH264Main; | |
477 break; | |
478 case media::H264PROFILE_HIGH: | |
479 profile_ = VAProfileH264High; | |
480 break; | |
481 default: | |
482 return false; | |
483 } | |
484 return true; | |
485 } | |
486 | |
487 class ScopedPtrXFree { | |
488 public: | |
489 void operator()(void* x) const { | |
490 ::XFree(x); | |
491 } | |
492 }; | |
493 | |
494 bool VaapiH264Decoder::InitializeFBConfig() { | |
495 const int fbconfig_attr[] = { | |
496 GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, | |
497 GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT, | |
498 GLX_BIND_TO_TEXTURE_RGB_EXT, GL_TRUE, | |
499 GLX_Y_INVERTED_EXT, GL_TRUE, | |
500 GL_NONE, | |
501 }; | |
502 | |
503 int num_fbconfigs; | |
504 scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> glx_fb_configs( | |
505 glXChooseFBConfig(x_display_, DefaultScreen(x_display_), fbconfig_attr, | |
506 &num_fbconfigs)); | |
507 if (!glx_fb_configs) | |
508 return false; | |
509 if (!num_fbconfigs) | |
510 return false; | |
511 | |
512 fb_config_ = glx_fb_configs.get()[0]; | |
513 return true; | |
514 } | |
515 | |
516 bool VaapiH264Decoder::Initialize( | |
517 media::VideoCodecProfile profile, | |
518 Display* x_display, | |
519 GLXContext glx_context, | |
520 const base::Callback<bool(void)>& make_context_current, | |
521 const OutputPicCB& output_pic_cb, | |
522 const SubmitDecodeCB& submit_decode_cb) { | |
523 DCHECK_EQ(state_, kUninitialized); | |
524 | |
525 output_pic_cb_ = output_pic_cb; | |
526 submit_decode_cb_ = submit_decode_cb; | |
527 | |
528 x_display_ = x_display; | |
529 make_context_current_ = make_context_current; | |
530 | |
531 if (!make_context_current_.Run()) | |
532 return false; | |
533 | |
534 if (!SetProfile(profile)) { | |
535 DVLOG(1) << "Unsupported profile"; | |
536 return false; | |
537 } | |
538 | |
539 if (!InitializeFBConfig()) { | |
540 DVLOG(1) << "Could not get a usable FBConfig"; | |
541 return false; | |
542 } | |
543 | |
544 va_display_ = VAAPI_GetDisplay(x_display_); | |
545 if (!VAAPI_DisplayIsValid(va_display_)) { | |
546 DVLOG(1) << "Could not get a valid VA display"; | |
547 return false; | |
548 } | |
549 | |
550 int major_version, minor_version; | |
551 VAStatus va_res; | |
552 va_res = VAAPI_Initialize(va_display_, &major_version, &minor_version); | |
553 VA_SUCCESS_OR_RETURN(va_res, "vaInitialize failed", false); | |
554 DVLOG(1) << "VAAPI version: " << major_version << "." << minor_version; | |
555 | |
556 VAConfigAttrib attrib; | |
557 attrib.type = VAConfigAttribRTFormat; | |
558 | |
559 VAEntrypoint entrypoint = VAEntrypointVLD; | |
560 va_res = VAAPI_GetConfigAttributes(va_display_, profile_, entrypoint, | |
561 &attrib, 1); | |
562 VA_SUCCESS_OR_RETURN(va_res, "vaGetConfigAttributes failed", false); | |
563 | |
564 if (!(attrib.value & VA_RT_FORMAT_YUV420)) { | |
565 DVLOG(1) << "YUV420 not supported"; | |
566 return false; | |
567 } | |
568 | |
569 va_res = VAAPI_CreateConfig(va_display_, profile_, entrypoint, | |
570 &attrib, 1, &va_config_id_); | |
571 VA_SUCCESS_OR_RETURN(va_res, "vaCreateConfig failed", false); | |
572 | |
573 state_ = kInitialized; | |
574 return true; | |
575 } | |
576 | |
577 void VaapiH264Decoder::ReusePictureBuffer(int32 picture_buffer_id) { | |
578 DecodeSurfaces::iterator it = decode_surfaces_.find(picture_buffer_id); | |
579 if (it == decode_surfaces_.end()) { | |
580 DVLOG(1) << "Asked to reuse an invalid surface " | |
581 << picture_buffer_id; | |
582 return; | |
583 } | |
584 if (it->second->available()) { | |
585 DVLOG(1) << "Asked to reuse an already available surface " | |
586 << picture_buffer_id; | |
587 return; | |
588 } | |
589 | |
590 it->second->set_at_client(false); | |
591 if (!it->second->used()) { | |
592 it->second->Release(); | |
593 ++num_available_decode_surfaces_; | |
594 } | |
595 } | |
596 | |
597 bool VaapiH264Decoder::AssignPictureBuffer(int32 picture_buffer_id, | |
598 uint32 texture_id) { | |
599 DCHECK_EQ(state_, kDecoding); | |
600 | |
601 if (decode_surfaces_.size() >= GetRequiredNumOfPictures()) { | |
602 DVLOG(1) << "Got more surfaces than required"; | |
603 return false; | |
604 } | |
605 | |
606 // This will not work if we start using VDA.DismissPicture() | |
607 linked_ptr<DecodeSurface> dec_surface(new DecodeSurface( | |
608 fb_config_, x_display_, va_display_, make_context_current_, | |
609 va_surface_ids_[decode_surfaces_.size()], picture_buffer_id, texture_id, | |
610 pic_width_, pic_height_)); | |
611 if (!dec_surface->available()) { | |
612 DVLOG(1) << "Error creating a decoding surface (binding to texture?)"; | |
613 return false; | |
614 } | |
615 | |
616 DVLOG(2) << "New picture assigned, texture id: " << dec_surface->texture_id() | |
617 << " pic buf id: " << dec_surface->picture_buffer_id() | |
618 << " will use va surface " << dec_surface->va_surface_id(); | |
619 | |
620 bool inserted = decode_surfaces_.insert(std::make_pair(picture_buffer_id, | |
621 dec_surface)).second; | |
622 DCHECK(inserted); | |
623 ++num_available_decode_surfaces_; | |
624 | |
625 return true; | |
626 } | |
627 | |
628 bool VaapiH264Decoder::CreateVASurfaces() { | |
629 DCHECK_NE(pic_width_, -1); | |
630 DCHECK_NE(pic_height_, -1); | |
631 if (state_ == kAfterReset) | |
632 return true; | |
633 DCHECK_EQ(state_, kInitialized); | |
634 | |
635 // Allocate VASurfaces in driver. | |
636 VAStatus va_res = VAAPI_CreateSurfaces(va_display_, pic_width_, | |
637 pic_height_, VA_RT_FORMAT_YUV420, | |
638 GetRequiredNumOfPictures(), | |
639 va_surface_ids_); | |
640 VA_SUCCESS_OR_RETURN(va_res, "vaCreateSurfaces failed", false); | |
641 | |
642 DCHECK(decode_surfaces_.empty()); | |
643 // And create a context associated with them. | |
644 va_res = VAAPI_CreateContext(va_display_, va_config_id_, | |
645 pic_width_, pic_height_, VA_PROGRESSIVE, | |
646 va_surface_ids_, GetRequiredNumOfPictures(), | |
647 &va_context_id_); | |
648 | |
649 if (va_res != VA_STATUS_SUCCESS) { | |
650 DVLOG(1) << "Error creating a decoding surface (binding to texture?)"; | |
651 VAAPI_DestroySurfaces(va_display_, va_surface_ids_, | |
652 GetRequiredNumOfPictures()); | |
653 return false; | |
654 } | |
655 | |
656 va_context_created_ = true; | |
657 | |
658 return true; | |
659 } | |
660 | |
661 void VaapiH264Decoder::DestroyVASurfaces() { | |
662 DCHECK(state_ == kDecoding || state_ == kError || state_ == kAfterReset); | |
663 decode_surfaces_.clear(); | |
664 | |
665 // This can happen if we fail during DecodeInitial. | |
666 if (!va_context_created_) | |
667 return; | |
668 | |
669 VAStatus va_res = VAAPI_DestroyContext(va_display_, va_context_id_); | |
670 VA_LOG_ON_ERROR(va_res, "vaDestroyContext failed"); | |
671 | |
672 va_res = VAAPI_DestroySurfaces(va_display_, va_surface_ids_, | |
673 GetRequiredNumOfPictures()); | |
674 VA_LOG_ON_ERROR(va_res, "vaDestroySurfaces failed"); | |
675 | |
676 va_context_created_ = false; | |
677 } | |
678 | |
679 void VaapiH264Decoder::DestroyPendingBuffers() { | |
680 while (!pending_slice_bufs_.empty()) { | |
681 VABufferID buffer = pending_slice_bufs_.front(); | |
682 VAStatus va_res = VAAPI_DestroyBuffer(va_display_, buffer); | |
683 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); | |
684 pending_slice_bufs_.pop(); | |
685 } | |
686 while (!pending_va_bufs_.empty()) { | |
687 VABufferID buffer = pending_va_bufs_.front(); | |
688 VAStatus va_res = VAAPI_DestroyBuffer(va_display_, buffer); | |
689 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); | |
690 pending_va_bufs_.pop(); | |
691 } | |
692 } | 115 } |
693 | 116 |
694 // Fill |va_pic| with default/neutral values. | 117 // Fill |va_pic| with default/neutral values. |
695 static void InitVAPicture(VAPictureH264* va_pic) { | 118 static void InitVAPicture(VAPictureH264* va_pic) { |
696 memset(va_pic, 0, sizeof(*va_pic)); | 119 memset(va_pic, 0, sizeof(*va_pic)); |
697 va_pic->picture_id = VA_INVALID_ID; | 120 va_pic->picture_id = VA_INVALID_ID; |
698 va_pic->flags = VA_PICTURE_H264_INVALID; | 121 va_pic->flags = VA_PICTURE_H264_INVALID; |
699 } | 122 } |
700 | 123 |
701 void VaapiH264Decoder::FillVAPicture(VAPictureH264 *va_pic, H264Picture* pic) { | 124 void VaapiH264Decoder::FillVAPicture(VAPictureH264 *va_pic, H264Picture* pic) { |
702 DCHECK(pic); | 125 DCHECK(pic); |
703 POCToDecodeSurfaces::iterator iter = poc_to_decode_surfaces_.find( | 126 |
704 pic->pic_order_cnt); | 127 DecodeSurface* dec_surface = DecodeSurfaceByPoC(pic->pic_order_cnt); |
705 if (iter == poc_to_decode_surfaces_.end()) { | 128 if (!dec_surface) { |
706 DVLOG(1) << "Could not find surface with POC: " << pic->pic_order_cnt; | |
707 // Cannot provide a ref picture, will corrupt output, but may be able | 129 // Cannot provide a ref picture, will corrupt output, but may be able |
708 // to recover. | 130 // to recover. |
709 InitVAPicture(va_pic); | 131 InitVAPicture(va_pic); |
710 return; | 132 return; |
711 } | 133 } |
712 | 134 |
713 va_pic->picture_id = iter->second->va_surface_id(); | 135 va_pic->picture_id = dec_surface->va_surface()->id(); |
714 va_pic->frame_idx = pic->frame_num; | 136 va_pic->frame_idx = pic->frame_num; |
715 va_pic->flags = 0; | 137 va_pic->flags = 0; |
716 | 138 |
717 switch (pic->field) { | 139 switch (pic->field) { |
718 case H264Picture::FIELD_NONE: | 140 case H264Picture::FIELD_NONE: |
719 break; | 141 break; |
720 case H264Picture::FIELD_TOP: | 142 case H264Picture::FIELD_TOP: |
721 va_pic->flags |= VA_PICTURE_H264_TOP_FIELD; | 143 va_pic->flags |= VA_PICTURE_H264_TOP_FIELD; |
722 break; | 144 break; |
723 case H264Picture::FIELD_BOTTOM: | 145 case H264Picture::FIELD_BOTTOM: |
(...skipping 19 matching lines...) Expand all Loading... |
743 // Libva does not document this, but other implementations (e.g. mplayer) | 165 // Libva does not document this, but other implementations (e.g. mplayer) |
744 // do it this way as well. | 166 // do it this way as well. |
745 for (rit = dpb_.rbegin(), i = 0; rit != dpb_.rend() && i < num_pics; ++rit) { | 167 for (rit = dpb_.rbegin(), i = 0; rit != dpb_.rend() && i < num_pics; ++rit) { |
746 if ((*rit)->ref) | 168 if ((*rit)->ref) |
747 FillVAPicture(&va_pics[i++], *rit); | 169 FillVAPicture(&va_pics[i++], *rit); |
748 } | 170 } |
749 | 171 |
750 return i; | 172 return i; |
751 } | 173 } |
752 | 174 |
753 // Can only be called when all surfaces are already bound | 175 VaapiH264Decoder::DecodeSurface* VaapiH264Decoder::DecodeSurfaceByPoC(int poc) { |
754 // to textures (cannot be run at the same time as AssignPictureBuffer). | 176 DecSurfacesInUse::iterator iter = decode_surfaces_in_use_.find(poc); |
755 bool VaapiH264Decoder::AssignSurfaceToPoC(int poc) { | 177 if (iter == decode_surfaces_in_use_.end()) { |
756 DCHECK_GT(num_available_decode_surfaces_, 0) << decode_surfaces_.size(); | 178 DVLOG(1) << "Could not find surface assigned to POC: " << poc; |
757 | 179 return NULL; |
758 // Find a surface not currently holding data used for reference and/or | |
759 // to be displayed and mark it as used. | |
760 DecodeSurfaces::iterator iter = decode_surfaces_.begin(); | |
761 for (; iter != decode_surfaces_.end(); ++iter) { | |
762 if (!iter->second->available()) | |
763 continue; | |
764 | |
765 --num_available_decode_surfaces_; | |
766 DCHECK_GE(num_available_decode_surfaces_, 0); | |
767 | |
768 // Associate with input id and poc and mark as unavailable. | |
769 iter->second->Acquire(curr_input_id_, poc); | |
770 DVLOG(4) << "Will use surface " << iter->second->va_surface_id() | |
771 << " for POC " << iter->second->poc() | |
772 << " input ID: " << iter->second->input_id(); | |
773 bool inserted = poc_to_decode_surfaces_.insert(std::make_pair( | |
774 poc, iter->second.get())).second; | |
775 DCHECK(inserted); | |
776 return true; | |
777 } | 180 } |
778 | 181 |
779 // Could not find an available surface. | 182 return iter->second.get(); |
780 return false; | |
781 } | 183 } |
782 | 184 |
783 // Can only be called when all surfaces are already bound | 185 bool VaapiH264Decoder::AssignSurfaceToPoC(int32 input_id, int poc) { |
784 // to textures (cannot be run at the same time as AssignPictureBuffer). | 186 if (available_va_surfaces_.empty()) { |
| 187 DVLOG(1) << "No VA Surfaces available"; |
| 188 return false; |
| 189 } |
| 190 |
| 191 linked_ptr<DecodeSurface> dec_surface(new DecodeSurface( |
| 192 poc, input_id, available_va_surfaces_.back())); |
| 193 available_va_surfaces_.pop_back(); |
| 194 |
| 195 DVLOG(4) << "POC " << poc |
| 196 << " will use surface " << dec_surface->va_surface()->id(); |
| 197 |
| 198 bool inserted = decode_surfaces_in_use_.insert( |
| 199 std::make_pair(poc, dec_surface)).second; |
| 200 DCHECK(inserted); |
| 201 |
| 202 return true; |
| 203 } |
| 204 |
785 void VaapiH264Decoder::UnassignSurfaceFromPoC(int poc) { | 205 void VaapiH264Decoder::UnassignSurfaceFromPoC(int poc) { |
786 DecodeSurface* dec_surface; | 206 DecSurfacesInUse::iterator it = decode_surfaces_in_use_.find(poc); |
787 POCToDecodeSurfaces::iterator it = poc_to_decode_surfaces_.find(poc); | 207 if (it == decode_surfaces_in_use_.end()) { |
788 if (it == poc_to_decode_surfaces_.end()) { | |
789 DVLOG(1) << "Asked to unassign an unassigned POC " << poc; | 208 DVLOG(1) << "Asked to unassign an unassigned POC " << poc; |
790 return; | 209 return; |
791 } | 210 } |
792 dec_surface = it->second; | |
793 DVLOG(4) << "POC " << poc << " no longer using surface " | |
794 << dec_surface->va_surface_id(); | |
795 poc_to_decode_surfaces_.erase(it); | |
796 | 211 |
797 dec_surface->set_used(false); | 212 DVLOG(4) << "POC " << poc << " no longer using VA surface " |
798 if (!dec_surface->at_client()) { | 213 << it->second->va_surface()->id(); |
799 dec_surface->Release(); | 214 |
800 ++num_available_decode_surfaces_; | 215 decode_surfaces_in_use_.erase(it); |
801 } | |
802 } | 216 } |
803 | 217 |
804 // Fill a VAPictureParameterBufferH264 to be later sent to the HW decoder. | |
805 bool VaapiH264Decoder::SendPPS() { | 218 bool VaapiH264Decoder::SendPPS() { |
806 const H264PPS* pps = parser_.GetPPS(curr_pps_id_); | 219 const H264PPS* pps = parser_.GetPPS(curr_pps_id_); |
807 DCHECK(pps); | 220 DCHECK(pps); |
808 | 221 |
809 const H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id); | 222 const H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id); |
810 DCHECK(sps); | 223 DCHECK(sps); |
811 | 224 |
812 DCHECK(curr_pic_.get()); | 225 DCHECK(curr_pic_.get()); |
813 | 226 |
814 VAPictureParameterBufferH264 pic_param; | 227 VAPictureParameterBufferH264 pic_param; |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
877 // Init reference pictures' array. | 290 // Init reference pictures' array. |
878 for (int i = 0; i < 16; ++i) | 291 for (int i = 0; i < 16; ++i) |
879 InitVAPicture(&pic_param.ReferenceFrames[i]); | 292 InitVAPicture(&pic_param.ReferenceFrames[i]); |
880 | 293 |
881 // And fill it with picture info from DPB. | 294 // And fill it with picture info from DPB. |
882 FillVARefFramesFromDPB(pic_param.ReferenceFrames, | 295 FillVARefFramesFromDPB(pic_param.ReferenceFrames, |
883 arraysize(pic_param.ReferenceFrames)); | 296 arraysize(pic_param.ReferenceFrames)); |
884 | 297 |
885 pic_param.num_ref_frames = sps->max_num_ref_frames; | 298 pic_param.num_ref_frames = sps->max_num_ref_frames; |
886 | 299 |
887 // Allocate a buffer in driver for this parameter buffer and upload data. | 300 return vaapi_wrapper_->SubmitBuffer(VAPictureParameterBufferType, |
888 VABufferID pic_param_buf_id; | 301 sizeof(VAPictureParameterBufferH264), |
889 VAStatus va_res = VAAPI_CreateBuffer(va_display_, va_context_id_, | 302 &pic_param); |
890 VAPictureParameterBufferType, | |
891 sizeof(VAPictureParameterBufferH264), | |
892 1, &pic_param, &pic_param_buf_id); | |
893 VA_SUCCESS_OR_RETURN(va_res, "Failed to create a buffer for PPS", false); | |
894 | |
895 // Queue its VA buffer ID to be committed on HW decode run. | |
896 pending_va_bufs_.push(pic_param_buf_id); | |
897 | |
898 return true; | |
899 } | 303 } |
900 | 304 |
901 // Fill a VAIQMatrixBufferH264 to be later sent to the HW decoder. | |
902 bool VaapiH264Decoder::SendIQMatrix() { | 305 bool VaapiH264Decoder::SendIQMatrix() { |
903 const H264PPS* pps = parser_.GetPPS(curr_pps_id_); | 306 const H264PPS* pps = parser_.GetPPS(curr_pps_id_); |
904 DCHECK(pps); | 307 DCHECK(pps); |
905 | 308 |
906 VAIQMatrixBufferH264 iq_matrix_buf; | 309 VAIQMatrixBufferH264 iq_matrix_buf; |
907 memset(&iq_matrix_buf, 0, sizeof(VAIQMatrixBufferH264)); | 310 memset(&iq_matrix_buf, 0, sizeof(VAIQMatrixBufferH264)); |
908 | 311 |
909 if (pps->pic_scaling_matrix_present_flag) { | 312 if (pps->pic_scaling_matrix_present_flag) { |
910 for (int i = 0; i < 6; ++i) { | 313 for (int i = 0; i < 6; ++i) { |
911 for (int j = 0; j < 16; ++j) | 314 for (int j = 0; j < 16; ++j) |
(...skipping 11 matching lines...) Expand all Loading... |
923 for (int j = 0; j < 16; ++j) | 326 for (int j = 0; j < 16; ++j) |
924 iq_matrix_buf.ScalingList4x4[i][j] = sps->scaling_list4x4[i][j]; | 327 iq_matrix_buf.ScalingList4x4[i][j] = sps->scaling_list4x4[i][j]; |
925 } | 328 } |
926 | 329 |
927 for (int i = 0; i < 2; ++i) { | 330 for (int i = 0; i < 2; ++i) { |
928 for (int j = 0; j < 64; ++j) | 331 for (int j = 0; j < 64; ++j) |
929 iq_matrix_buf.ScalingList8x8[i][j] = sps->scaling_list8x8[i][j]; | 332 iq_matrix_buf.ScalingList8x8[i][j] = sps->scaling_list8x8[i][j]; |
930 } | 333 } |
931 } | 334 } |
932 | 335 |
933 // Allocate a buffer in driver for this parameter buffer and upload data. | 336 return vaapi_wrapper_->SubmitBuffer(VAIQMatrixBufferType, |
934 VABufferID iq_matrix_buf_id; | 337 sizeof(VAIQMatrixBufferH264), |
935 VAStatus va_res = VAAPI_CreateBuffer(va_display_, va_context_id_, | 338 &iq_matrix_buf); |
936 VAIQMatrixBufferType, | |
937 sizeof(VAIQMatrixBufferH264), 1, | |
938 &iq_matrix_buf, &iq_matrix_buf_id); | |
939 VA_SUCCESS_OR_RETURN(va_res, "Failed to create a buffer for IQMatrix", | |
940 false); | |
941 | |
942 // Queue its VA buffer ID to be committed on HW decode run. | |
943 pending_va_bufs_.push(iq_matrix_buf_id); | |
944 | |
945 return true; | |
946 } | 339 } |
947 | 340 |
948 bool VaapiH264Decoder::SendVASliceParam(H264SliceHeader* slice_hdr) { | 341 bool VaapiH264Decoder::SendVASliceParam(H264SliceHeader* slice_hdr) { |
949 const H264PPS* pps = parser_.GetPPS(slice_hdr->pic_parameter_set_id); | 342 const H264PPS* pps = parser_.GetPPS(slice_hdr->pic_parameter_set_id); |
950 DCHECK(pps); | 343 DCHECK(pps); |
951 | 344 |
952 const H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id); | 345 const H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id); |
953 DCHECK(sps); | 346 DCHECK(sps); |
954 | 347 |
955 VASliceParameterBufferH264 slice_param; | 348 VASliceParameterBufferH264 slice_param; |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1025 | 418 |
1026 int i; | 419 int i; |
1027 H264Picture::PtrVector::iterator it; | 420 H264Picture::PtrVector::iterator it; |
1028 for (it = ref_pic_list0_.begin(), i = 0; it != ref_pic_list0_.end() && *it; | 421 for (it = ref_pic_list0_.begin(), i = 0; it != ref_pic_list0_.end() && *it; |
1029 ++it, ++i) | 422 ++it, ++i) |
1030 FillVAPicture(&slice_param.RefPicList0[i], *it); | 423 FillVAPicture(&slice_param.RefPicList0[i], *it); |
1031 for (it = ref_pic_list1_.begin(), i = 0; it != ref_pic_list1_.end() && *it; | 424 for (it = ref_pic_list1_.begin(), i = 0; it != ref_pic_list1_.end() && *it; |
1032 ++it, ++i) | 425 ++it, ++i) |
1033 FillVAPicture(&slice_param.RefPicList1[i], *it); | 426 FillVAPicture(&slice_param.RefPicList1[i], *it); |
1034 | 427 |
1035 // Allocate a buffer in driver for this parameter buffer and upload data. | 428 return vaapi_wrapper_->SubmitBuffer(VASliceParameterBufferType, |
1036 VABufferID slice_param_buf_id; | 429 sizeof(VASliceParameterBufferH264), |
1037 VAStatus va_res = VAAPI_CreateBuffer(va_display_, va_context_id_, | 430 &slice_param); |
1038 VASliceParameterBufferType, | |
1039 sizeof(VASliceParameterBufferH264), | |
1040 1, &slice_param, &slice_param_buf_id); | |
1041 VA_SUCCESS_OR_RETURN(va_res, "Failed creating a buffer for slice param", | |
1042 false); | |
1043 | |
1044 // Queue its VA buffer ID to be committed on HW decode run. | |
1045 pending_slice_bufs_.push(slice_param_buf_id); | |
1046 | |
1047 return true; | |
1048 } | 431 } |
1049 | 432 |
1050 bool VaapiH264Decoder::SendSliceData(const uint8* ptr, size_t size) { | 433 bool VaapiH264Decoder::SendSliceData(const uint8* ptr, size_t size) { |
1051 // Can't help it, blame libva... | 434 // Can't help it, blame libva... |
1052 void* non_const_ptr = const_cast<uint8*>(ptr); | 435 void* non_const_ptr = const_cast<uint8*>(ptr); |
1053 | 436 return vaapi_wrapper_->SubmitBuffer(VASliceDataBufferType, size, |
1054 VABufferID slice_data_buf_id; | 437 non_const_ptr); |
1055 VAStatus va_res = VAAPI_CreateBuffer(va_display_, va_context_id_, | |
1056 VASliceDataBufferType, size, 1, | |
1057 non_const_ptr, &slice_data_buf_id); | |
1058 VA_SUCCESS_OR_RETURN(va_res, "Failed creating a buffer for slice data", | |
1059 false); | |
1060 | |
1061 pending_slice_bufs_.push(slice_data_buf_id); | |
1062 return true; | |
1063 } | 438 } |
1064 | 439 |
1065 bool VaapiH264Decoder::QueueSlice(H264SliceHeader* slice_hdr) { | 440 bool VaapiH264Decoder::QueueSlice(H264SliceHeader* slice_hdr) { |
1066 DCHECK(curr_pic_.get()); | 441 DCHECK(curr_pic_.get()); |
1067 | 442 |
1068 if (!SendVASliceParam(slice_hdr)) | 443 if (!SendVASliceParam(slice_hdr)) |
1069 return false; | 444 return false; |
1070 | 445 |
1071 if (!SendSliceData(slice_hdr->nalu_data, slice_hdr->nalu_size)) | 446 if (!SendSliceData(slice_hdr->nalu_data, slice_hdr->nalu_size)) |
1072 return false; | 447 return false; |
1073 | 448 |
1074 return true; | 449 return true; |
1075 } | 450 } |
1076 | 451 |
| 452 // TODO(posciak) start using vaMapBuffer instead of vaCreateBuffer wherever |
| 453 // possible. |
1077 bool VaapiH264Decoder::DecodePicture() { | 454 bool VaapiH264Decoder::DecodePicture() { |
1078 DCHECK(!frame_ready_at_hw_); | |
1079 DCHECK(curr_pic_.get()); | 455 DCHECK(curr_pic_.get()); |
1080 | 456 |
1081 // Find the surface associated with the picture to be decoded. | 457 DVLOG(4) << "Decoding POC " << curr_pic_->pic_order_cnt; |
1082 DecodeSurface* dec_surface = | 458 DecodeSurface* dec_surface = DecodeSurfaceByPoC(curr_pic_->pic_order_cnt); |
1083 poc_to_decode_surfaces_[curr_pic_->pic_order_cnt]; | 459 if (!dec_surface) { |
1084 DVLOG(4) << "Decoding POC " << curr_pic_->pic_order_cnt | 460 DVLOG(1) << "Asked to decode an invalid POC " << curr_pic_->pic_order_cnt; |
1085 << " into surface " << dec_surface->va_surface_id(); | 461 return false; |
| 462 } |
1086 | 463 |
1087 DVLOG(4) << "Pending VA bufs to commit: " << pending_va_bufs_.size(); | 464 if (!vaapi_wrapper_->DecodeAndDestroyPendingBuffers( |
1088 DVLOG(4) << "Pending slice bufs to commit: " << pending_slice_bufs_.size(); | 465 dec_surface->va_surface()->id())) { |
1089 | 466 DVLOG(1) << "Failed decoding picture"; |
1090 DCHECK(pending_slice_bufs_.size()); | 467 return false; |
1091 scoped_ptr<std::queue<VABufferID> > va_bufs(new std::queue<VABufferID>()); | 468 } |
1092 std::swap(*va_bufs, pending_va_bufs_); | |
1093 scoped_ptr<std::queue<VABufferID> > slice_bufs(new std::queue<VABufferID>()); | |
1094 std::swap(*slice_bufs, pending_slice_bufs_); | |
1095 | |
1096 // Fire up a parallel job on the GPU on the ChildThread to decode and put | |
1097 // the decoded/converted/scaled picture into the pixmap. | |
1098 // Callee will take care of freeing the buffer queues. | |
1099 submit_decode_cb_.Run( | |
1100 dec_surface->picture_buffer_id(), va_bufs.Pass(), slice_bufs.Pass()); | |
1101 | |
1102 // Used to notify clients that we had sufficient data to start decoding | |
1103 // a new frame. | |
1104 frame_ready_at_hw_ = true; | |
1105 | 469 |
1106 return true; | 470 return true; |
1107 } | 471 } |
1108 | 472 |
1109 void VaapiH264Decoder::DestroyBuffers(size_t num_va_buffers, | |
1110 const VABufferID* va_buffers) { | |
1111 for (size_t i = 0; i < num_va_buffers; ++i) { | |
1112 VAStatus va_res = VAAPI_DestroyBuffer(va_display_, va_buffers[i]); | |
1113 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); | |
1114 } | |
1115 } | |
1116 | 473 |
1117 // TODO(posciak) start using vaMapBuffer instead of vaCreateBuffer wherever | |
1118 // possible. | |
1119 bool VaapiH264Decoder::SubmitDecode( | |
1120 int32 picture_buffer_id, | |
1121 scoped_ptr<std::queue<VABufferID> > va_bufs, | |
1122 scoped_ptr<std::queue<VABufferID> > slice_bufs) { | |
1123 | |
1124 static const size_t kMaxVABuffers = 32; | |
1125 DCHECK_LE(va_bufs->size(), kMaxVABuffers); | |
1126 DCHECK_LE(slice_bufs->size(), kMaxVABuffers); | |
1127 | |
1128 DecodeSurfaces::iterator it = decode_surfaces_.find(picture_buffer_id); | |
1129 if (it == decode_surfaces_.end()) { | |
1130 DVLOG(1) << "Asked to put an invalid buffer"; | |
1131 return false; | |
1132 } | |
1133 | |
1134 // Get ready to decode into surface. | |
1135 VAStatus va_res = VAAPI_BeginPicture(va_display_, va_context_id_, | |
1136 it->second->va_surface_id()); | |
1137 VA_SUCCESS_OR_RETURN(va_res, "vaBeginPicture failed", false); | |
1138 | |
1139 // Put buffer IDs for pending parameter buffers into va_buffers[]. | |
1140 VABufferID va_buffers[kMaxVABuffers]; | |
1141 size_t num_va_buffers = va_bufs->size(); | |
1142 for (size_t i = 0; i < num_va_buffers && i < kMaxVABuffers; ++i) { | |
1143 va_buffers[i] = va_bufs->front(); | |
1144 va_bufs->pop(); | |
1145 } | |
1146 base::Closure va_buffers_callback = | |
1147 base::Bind(&VaapiH264Decoder::DestroyBuffers, base::Unretained(this), | |
1148 num_va_buffers, va_buffers); | |
1149 base::ScopedClosureRunner va_buffers_deleter(va_buffers_callback); | |
1150 | |
1151 // And send them to the HW decoder. | |
1152 va_res = VAAPI_RenderPicture(va_display_, va_context_id_, va_buffers, | |
1153 num_va_buffers); | |
1154 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for va_bufs failed", false); | |
1155 | |
1156 DVLOG(4) << "Committed " << num_va_buffers << "VA buffers"; | |
1157 | |
1158 // Put buffer IDs for pending slice data buffers into slice_buffers[]. | |
1159 VABufferID slice_buffers[kMaxVABuffers]; | |
1160 size_t num_slice_buffers = slice_bufs->size(); | |
1161 for (size_t i = 0; i < num_slice_buffers && i < kMaxVABuffers; ++i) { | |
1162 slice_buffers[i] = slice_bufs->front(); | |
1163 slice_bufs->pop(); | |
1164 } | |
1165 base::Closure va_slices_callback = | |
1166 base::Bind(&VaapiH264Decoder::DestroyBuffers, base::Unretained(this), | |
1167 num_slice_buffers, slice_buffers); | |
1168 base::ScopedClosureRunner slice_buffers_deleter(va_slices_callback); | |
1169 | |
1170 // And send them to the Hw decoder. | |
1171 va_res = VAAPI_RenderPicture(va_display_, va_context_id_, slice_buffers, | |
1172 num_slice_buffers); | |
1173 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for slices failed", false); | |
1174 | |
1175 DVLOG(4) << "Committed " << num_slice_buffers << "slice buffers"; | |
1176 | |
1177 // Instruct HW decoder to start processing committed buffers (decode this | |
1178 // picture). This does not block until the end of decode. | |
1179 va_res = VAAPI_EndPicture(va_display_, va_context_id_); | |
1180 VA_SUCCESS_OR_RETURN(va_res, "vaEndPicture failed", false); | |
1181 | |
1182 DVLOG(3) << "Will output from VASurface " << it->second->va_surface_id() | |
1183 << " to texture id " << it->second->texture_id(); | |
1184 | |
1185 return it->second->Sync(); | |
1186 } | |
1187 | |
1188 | |
1189 bool VaapiH264Decoder::InitCurrPicture(H264SliceHeader* slice_hdr) { | 474 bool VaapiH264Decoder::InitCurrPicture(H264SliceHeader* slice_hdr) { |
1190 DCHECK(curr_pic_.get()); | 475 DCHECK(curr_pic_.get()); |
1191 | 476 |
1192 memset(curr_pic_.get(), 0, sizeof(H264Picture)); | 477 memset(curr_pic_.get(), 0, sizeof(H264Picture)); |
1193 | 478 |
1194 curr_pic_->idr = slice_hdr->idr_pic_flag; | 479 curr_pic_->idr = slice_hdr->idr_pic_flag; |
1195 | 480 |
1196 if (slice_hdr->field_pic_flag) { | 481 if (slice_hdr->field_pic_flag) { |
1197 curr_pic_->field = slice_hdr->bottom_field_flag ? H264Picture::FIELD_BOTTOM | 482 curr_pic_->field = slice_hdr->bottom_field_flag ? H264Picture::FIELD_BOTTOM |
1198 : H264Picture::FIELD_TOP; | 483 : H264Picture::FIELD_TOP; |
1199 } else { | 484 } else { |
1200 curr_pic_->field = H264Picture::FIELD_NONE; | 485 curr_pic_->field = H264Picture::FIELD_NONE; |
1201 } | 486 } |
1202 | 487 |
1203 curr_pic_->ref = slice_hdr->nal_ref_idc != 0; | 488 curr_pic_->ref = slice_hdr->nal_ref_idc != 0; |
1204 // This assumes non-interlaced stream. | 489 // This assumes non-interlaced stream. |
1205 curr_pic_->frame_num = curr_pic_->pic_num = slice_hdr->frame_num; | 490 curr_pic_->frame_num = curr_pic_->pic_num = slice_hdr->frame_num; |
1206 | 491 |
1207 if (!CalculatePicOrderCounts(slice_hdr)) | 492 if (!CalculatePicOrderCounts(slice_hdr)) |
1208 return false; | 493 return false; |
1209 | 494 |
1210 // Try to get an empty surface to decode this picture to. | 495 // Try to get an empty surface to decode this picture to. |
1211 if (!AssignSurfaceToPoC(curr_pic_->pic_order_cnt)) { | 496 if (!AssignSurfaceToPoC(curr_input_id_, curr_pic_->pic_order_cnt)) { |
1212 DVLOG(1) << "Failed getting a free surface for a picture"; | 497 DVLOG(1) << "Failed getting a free surface for a picture"; |
1213 return false; | 498 return false; |
1214 } | 499 } |
1215 | 500 |
1216 curr_pic_->long_term_reference_flag = slice_hdr->long_term_reference_flag; | 501 curr_pic_->long_term_reference_flag = slice_hdr->long_term_reference_flag; |
1217 curr_pic_->adaptive_ref_pic_marking_mode_flag = | 502 curr_pic_->adaptive_ref_pic_marking_mode_flag = |
1218 slice_hdr->adaptive_ref_pic_marking_mode_flag; | 503 slice_hdr->adaptive_ref_pic_marking_mode_flag; |
1219 | 504 |
1220 // If the slice header indicates we will have to perform reference marking | 505 // If the slice header indicates we will have to perform reference marking |
1221 // process after this picture is decoded, store required data for that | 506 // process after this picture is decoded, store required data for that |
(...skipping 481 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1703 // temporarily made one element longer than the required final list. | 988 // temporarily made one element longer than the required final list. |
1704 // Resize the list back to its required size. | 989 // Resize the list back to its required size. |
1705 ref_pic_listx->resize(num_ref_idx_lX_active_minus1 + 1); | 990 ref_pic_listx->resize(num_ref_idx_lX_active_minus1 + 1); |
1706 | 991 |
1707 return true; | 992 return true; |
1708 } | 993 } |
1709 | 994 |
1710 bool VaapiH264Decoder::OutputPic(H264Picture* pic) { | 995 bool VaapiH264Decoder::OutputPic(H264Picture* pic) { |
1711 DCHECK(!pic->outputted); | 996 DCHECK(!pic->outputted); |
1712 pic->outputted = true; | 997 pic->outputted = true; |
1713 POCToDecodeSurfaces::iterator iter = poc_to_decode_surfaces_.find( | 998 last_output_poc_ = pic->pic_order_cnt; |
1714 pic->pic_order_cnt); | 999 |
1715 if (iter == poc_to_decode_surfaces_.end()) | 1000 DecodeSurface* dec_surface = DecodeSurfaceByPoC(pic->pic_order_cnt); |
| 1001 if (!dec_surface) |
1716 return false; | 1002 return false; |
1717 DecodeSurface* dec_surface = iter->second; | |
1718 | 1003 |
1719 dec_surface->set_at_client(true); | 1004 DCHECK_GE(dec_surface->input_id(), 0); |
1720 last_output_poc_ = pic->pic_order_cnt; | |
1721 // Notify the client that a picture can be output. | |
1722 DVLOG(4) << "Posting output task for POC: " << pic->pic_order_cnt | 1005 DVLOG(4) << "Posting output task for POC: " << pic->pic_order_cnt |
1723 << " input_id: " << dec_surface->input_id() | 1006 << " input_id: " << dec_surface->input_id(); |
1724 << "output_id: " << dec_surface->picture_buffer_id(); | 1007 output_pic_cb_.Run(dec_surface->input_id(), dec_surface->va_surface()); |
1725 output_pic_cb_.Run(dec_surface->input_id(), | |
1726 dec_surface->picture_buffer_id()); | |
1727 | 1008 |
1728 return true; | 1009 return true; |
1729 } | 1010 } |
1730 | 1011 |
1731 bool VaapiH264Decoder::Flush() { | 1012 void VaapiH264Decoder::ClearDPB() { |
| 1013 // Clear DPB contents, marking the pictures as unused first. |
| 1014 for (H264DPB::Pictures::iterator it = dpb_.begin(); it != dpb_.end(); ++it) |
| 1015 UnassignSurfaceFromPoC((*it)->pic_order_cnt); |
| 1016 |
| 1017 dpb_.Clear(); |
| 1018 last_output_poc_ = 0; |
| 1019 } |
| 1020 |
| 1021 bool VaapiH264Decoder::OutputAllRemainingPics() { |
1732 // Output all pictures that are waiting to be outputted. | 1022 // Output all pictures that are waiting to be outputted. |
1733 FinishPrevFrameIfPresent(); | 1023 FinishPrevFrameIfPresent(); |
1734 H264Picture::PtrVector to_output; | 1024 H264Picture::PtrVector to_output; |
1735 dpb_.GetNotOutputtedPicsAppending(to_output); | 1025 dpb_.GetNotOutputtedPicsAppending(to_output); |
1736 // Sort them by ascending POC to output in order. | 1026 // Sort them by ascending POC to output in order. |
1737 std::sort(to_output.begin(), to_output.end(), POCAscCompare()); | 1027 std::sort(to_output.begin(), to_output.end(), POCAscCompare()); |
1738 | 1028 |
1739 H264Picture::PtrVector::iterator it; | 1029 H264Picture::PtrVector::iterator it; |
1740 for (it = to_output.begin(); it != to_output.end(); ++it) { | 1030 for (it = to_output.begin(); it != to_output.end(); ++it) { |
1741 if (!OutputPic(*it)) { | 1031 if (!OutputPic(*it)) { |
1742 DVLOG(1) << "Failed to output pic POC: " << (*it)->pic_order_cnt; | 1032 DVLOG(1) << "Failed to output pic POC: " << (*it)->pic_order_cnt; |
1743 return false; | 1033 return false; |
1744 } | 1034 } |
1745 } | 1035 } |
1746 | 1036 |
1747 // And clear DPB contents, marking the pictures as unused first. | |
1748 // The surfaces will be released after they have been displayed and returned. | |
1749 for (H264DPB::Pictures::iterator it = dpb_.begin(); it != dpb_.end(); ++it) { | |
1750 UnassignSurfaceFromPoC((*it)->pic_order_cnt); | |
1751 } | |
1752 dpb_.Clear(); | |
1753 last_output_poc_ = 0; | |
1754 | |
1755 return true; | 1037 return true; |
1756 } | 1038 } |
1757 | 1039 |
| 1040 bool VaapiH264Decoder::Flush() { |
| 1041 if (!OutputAllRemainingPics()) |
| 1042 return false; |
| 1043 |
| 1044 ClearDPB(); |
| 1045 |
| 1046 DCHECK(decode_surfaces_in_use_.empty()); |
| 1047 return true; |
| 1048 } |
| 1049 |
1758 bool VaapiH264Decoder::StartNewFrame(H264SliceHeader* slice_hdr) { | 1050 bool VaapiH264Decoder::StartNewFrame(H264SliceHeader* slice_hdr) { |
1759 // TODO posciak: add handling of max_num_ref_frames per spec. | 1051 // TODO posciak: add handling of max_num_ref_frames per spec. |
1760 | 1052 |
1761 // If the new frame is an IDR, output what's left to output and clear DPB | 1053 // If the new frame is an IDR, output what's left to output and clear DPB |
1762 if (slice_hdr->idr_pic_flag) { | 1054 if (slice_hdr->idr_pic_flag) { |
1763 // (unless we are explicitly instructed not to do so). | 1055 // (unless we are explicitly instructed not to do so). |
1764 if (!slice_hdr->no_output_of_prior_pics_flag) { | 1056 if (!slice_hdr->no_output_of_prior_pics_flag) { |
1765 // Output DPB contents. | 1057 // Output DPB contents. |
1766 if (!Flush()) | 1058 if (!Flush()) |
1767 return false; | 1059 return false; |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1958 H264Picture* to_unmark = dpb_.GetLowestFrameNumWrapShortRefPic(); | 1250 H264Picture* to_unmark = dpb_.GetLowestFrameNumWrapShortRefPic(); |
1959 if (to_unmark == NULL) { | 1251 if (to_unmark == NULL) { |
1960 DVLOG(1) << "Couldn't find a short ref picture to unmark"; | 1252 DVLOG(1) << "Couldn't find a short ref picture to unmark"; |
1961 return; | 1253 return; |
1962 } | 1254 } |
1963 to_unmark->ref = false; | 1255 to_unmark->ref = false; |
1964 } | 1256 } |
1965 } else { | 1257 } else { |
1966 // Shouldn't get here. | 1258 // Shouldn't get here. |
1967 DVLOG(1) << "Interlaced video not supported."; | 1259 DVLOG(1) << "Interlaced video not supported."; |
1968 ReportToUMA(INTERLACED_STREAM); | 1260 report_error_to_uma_cb_.Run(INTERLACED_STREAM); |
1969 } | 1261 } |
1970 } else { | 1262 } else { |
1971 // Stream has instructions how to discard pictures from DPB and how | 1263 // Stream has instructions how to discard pictures from DPB and how |
1972 // to mark/unmark existing reference pictures. Do it. | 1264 // to mark/unmark existing reference pictures. Do it. |
1973 // Spec 8.2.5.4. | 1265 // Spec 8.2.5.4. |
1974 if (curr_pic_->field == H264Picture::FIELD_NONE) { | 1266 if (curr_pic_->field == H264Picture::FIELD_NONE) { |
1975 HandleMemoryManagementOps(); | 1267 HandleMemoryManagementOps(); |
1976 } else { | 1268 } else { |
1977 // Shouldn't get here. | 1269 // Shouldn't get here. |
1978 DVLOG(1) << "Interlaced video not supported."; | 1270 DVLOG(1) << "Interlaced video not supported."; |
1979 ReportToUMA(INTERLACED_STREAM); | 1271 report_error_to_uma_cb_.Run(INTERLACED_STREAM); |
1980 } | 1272 } |
1981 } | 1273 } |
1982 } | 1274 } |
1983 } | 1275 } |
1984 | 1276 |
1985 bool VaapiH264Decoder::FinishPicture() { | 1277 bool VaapiH264Decoder::FinishPicture() { |
1986 DCHECK(curr_pic_.get()); | 1278 DCHECK(curr_pic_.get()); |
1987 | 1279 |
1988 // Finish processing previous picture. | 1280 // Finish processing previous picture. |
1989 // Start by storing previous reference picture data for later use, | 1281 // Start by storing previous reference picture data for later use, |
1990 // if picture being finished is a reference picture. | 1282 // if picture being finished is a reference picture. |
1991 if (curr_pic_->ref) { | 1283 if (curr_pic_->ref) { |
1992 ReferencePictureMarking(); | 1284 ReferencePictureMarking(); |
1993 prev_ref_has_memmgmnt5_ = curr_pic_->mem_mgmt_5; | 1285 prev_ref_has_memmgmnt5_ = curr_pic_->mem_mgmt_5; |
1994 prev_ref_top_field_order_cnt_ = curr_pic_->top_field_order_cnt; | 1286 prev_ref_top_field_order_cnt_ = curr_pic_->top_field_order_cnt; |
1995 prev_ref_pic_order_cnt_msb_ = curr_pic_->pic_order_cnt_msb; | 1287 prev_ref_pic_order_cnt_msb_ = curr_pic_->pic_order_cnt_msb; |
1996 prev_ref_pic_order_cnt_lsb_ = curr_pic_->pic_order_cnt_lsb; | 1288 prev_ref_pic_order_cnt_lsb_ = curr_pic_->pic_order_cnt_lsb; |
1997 prev_ref_field_ = curr_pic_->field; | 1289 prev_ref_field_ = curr_pic_->field; |
1998 } | 1290 } |
1999 prev_has_memmgmnt5_ = curr_pic_->mem_mgmt_5; | 1291 prev_has_memmgmnt5_ = curr_pic_->mem_mgmt_5; |
2000 prev_frame_num_offset_ = curr_pic_->frame_num_offset; | 1292 prev_frame_num_offset_ = curr_pic_->frame_num_offset; |
2001 | 1293 |
2002 // Remove unused (for reference or later output) pictures from DPB, marking | 1294 // Remove unused (for reference or later output) pictures from DPB, marking |
2003 // them as such. | 1295 // them as such. |
2004 for (H264DPB::Pictures::iterator it = dpb_.begin(); it != dpb_.end(); ++it) { | 1296 for (H264DPB::Pictures::iterator it = dpb_.begin(); it != dpb_.end(); ++it) { |
2005 if ((*it)->outputted && !(*it)->ref) | 1297 if ((*it)->outputted && !(*it)->ref) |
2006 UnassignSurfaceFromPoC((*it)->pic_order_cnt); | 1298 UnassignSurfaceFromPoC((*it)->pic_order_cnt); |
2007 } | 1299 } |
2008 dpb_.RemoveUnused(); | 1300 dpb_.DeleteUnused(); |
2009 | 1301 |
2010 DVLOG(4) << "Finishing picture, DPB entries: " << dpb_.size() | 1302 DVLOG(4) << "Finishing picture, entries in DPB: " << dpb_.size(); |
2011 << " Num available dec surfaces: " | |
2012 << num_available_decode_surfaces_; | |
2013 | 1303 |
2014 // Whatever happens below, curr_pic_ will stop managing the pointer to the | 1304 // Whatever happens below, curr_pic_ will stop managing the pointer to the |
2015 // picture after this function returns. The ownership will either be | 1305 // picture after this function returns. The ownership will either be |
2016 // transferred to DPB, if the image is still needed (for output and/or | 1306 // transferred to DPB, if the image is still needed (for output and/or |
2017 // reference), or the memory will be released if we manage to output it here | 1307 // reference), or the memory will be released if we manage to output it here |
2018 // without having to store it for future reference. | 1308 // without having to store it for future reference. |
2019 scoped_ptr<H264Picture> pic(curr_pic_.release()); | 1309 scoped_ptr<H264Picture> pic(curr_pic_.release()); |
2020 | 1310 |
2021 // Get all pictures that haven't been outputted yet. | 1311 // Get all pictures that haven't been outputted yet. |
2022 H264Picture::PtrVector not_outputted; | 1312 H264Picture::PtrVector not_outputted; |
(...skipping 16 matching lines...) Expand all Loading... |
2039 (*output_candidate)->pic_order_cnt <= last_output_poc_ + 2; | 1329 (*output_candidate)->pic_order_cnt <= last_output_poc_ + 2; |
2040 ++output_candidate) { | 1330 ++output_candidate) { |
2041 DCHECK_GE((*output_candidate)->pic_order_cnt, last_output_poc_); | 1331 DCHECK_GE((*output_candidate)->pic_order_cnt, last_output_poc_); |
2042 if (!OutputPic(*output_candidate)) | 1332 if (!OutputPic(*output_candidate)) |
2043 return false; | 1333 return false; |
2044 | 1334 |
2045 if (!(*output_candidate)->ref) { | 1335 if (!(*output_candidate)->ref) { |
2046 // Current picture hasn't been inserted into DPB yet, so don't remove it | 1336 // Current picture hasn't been inserted into DPB yet, so don't remove it |
2047 // if we managed to output it immediately. | 1337 // if we managed to output it immediately. |
2048 if (*output_candidate != pic) | 1338 if (*output_candidate != pic) |
2049 dpb_.RemoveByPOC((*output_candidate)->pic_order_cnt); | 1339 dpb_.DeleteByPOC((*output_candidate)->pic_order_cnt); |
2050 // Mark as unused. | 1340 // Mark as unused. |
2051 UnassignSurfaceFromPoC((*output_candidate)->pic_order_cnt); | 1341 UnassignSurfaceFromPoC((*output_candidate)->pic_order_cnt); |
2052 } | 1342 } |
2053 } | 1343 } |
2054 | 1344 |
2055 // If we haven't managed to output the picture that we just decoded, or if | 1345 // If we haven't managed to output the picture that we just decoded, or if |
2056 // it's a reference picture, we have to store it in DPB. | 1346 // it's a reference picture, we have to store it in DPB. |
2057 if (!pic->outputted || pic->ref) { | 1347 if (!pic->outputted || pic->ref) { |
2058 if (dpb_.IsFull()) { | 1348 if (dpb_.IsFull()) { |
2059 // If we haven't managed to output anything to free up space in DPB | 1349 // If we haven't managed to output anything to free up space in DPB |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2092 return 0; | 1382 return 0; |
2093 } | 1383 } |
2094 } | 1384 } |
2095 | 1385 |
2096 bool VaapiH264Decoder::ProcessSPS(int sps_id) { | 1386 bool VaapiH264Decoder::ProcessSPS(int sps_id) { |
2097 const H264SPS* sps = parser_.GetSPS(sps_id); | 1387 const H264SPS* sps = parser_.GetSPS(sps_id); |
2098 DCHECK(sps); | 1388 DCHECK(sps); |
2099 | 1389 |
2100 if (sps->frame_mbs_only_flag == 0) { | 1390 if (sps->frame_mbs_only_flag == 0) { |
2101 DVLOG(1) << "frame_mbs_only_flag != 1 not supported"; | 1391 DVLOG(1) << "frame_mbs_only_flag != 1 not supported"; |
2102 ReportToUMA(FRAME_MBS_ONLY_FLAG_NOT_ONE); | 1392 report_error_to_uma_cb_.Run(FRAME_MBS_ONLY_FLAG_NOT_ONE); |
2103 return false; | 1393 return false; |
2104 } | 1394 } |
2105 | 1395 |
2106 if (sps->gaps_in_frame_num_value_allowed_flag) { | 1396 if (sps->gaps_in_frame_num_value_allowed_flag) { |
2107 DVLOG(1) << "Gaps in frame numbers not supported"; | 1397 DVLOG(1) << "Gaps in frame numbers not supported"; |
2108 ReportToUMA(GAPS_IN_FRAME_NUM); | 1398 report_error_to_uma_cb_.Run(GAPS_IN_FRAME_NUM); |
2109 return false; | 1399 return false; |
2110 } | 1400 } |
2111 | 1401 |
2112 curr_sps_id_ = sps->seq_parameter_set_id; | 1402 curr_sps_id_ = sps->seq_parameter_set_id; |
2113 | 1403 |
2114 // Calculate picture height/width in macroblocks and pixels | 1404 // Calculate picture height/width in macroblocks and pixels |
2115 // (spec 7.4.2.1.1, 7.4.3). | 1405 // (spec 7.4.2.1.1, 7.4.3). |
2116 int width_mb = sps->pic_width_in_mbs_minus1 + 1; | 1406 int width_mb = sps->pic_width_in_mbs_minus1 + 1; |
2117 int height_mb = (2 - sps->frame_mbs_only_flag) * | 1407 int height_mb = (2 - sps->frame_mbs_only_flag) * |
2118 (sps->pic_height_in_map_units_minus1 + 1); | 1408 (sps->pic_height_in_map_units_minus1 + 1); |
2119 | 1409 |
2120 int width = 16 * width_mb; | 1410 int width = 16 * width_mb; |
2121 int height = 16 * height_mb; | 1411 int height = 16 * height_mb; |
2122 | 1412 |
2123 DVLOG(1) << "New picture size: " << width << "x" << height; | 1413 DVLOG(1) << "New picture size: " << width << "x" << height; |
2124 if (width == 0 || height == 0) { | 1414 if (width == 0 || height == 0) { |
2125 DVLOG(1) << "Invalid picture size!"; | 1415 DVLOG(1) << "Invalid picture size!"; |
2126 return false; | 1416 return false; |
2127 } | 1417 } |
2128 | 1418 |
2129 if ((pic_width_ != -1 || pic_height_ != -1) && | 1419 if (!pic_size_.IsEmpty() && |
2130 (width != pic_width_ || height != pic_height_)) { | 1420 (width != pic_size_.width() || height != pic_size_.height())) { |
2131 DVLOG(1) << "Picture size changed mid-stream"; | 1421 DVLOG(1) << "Picture size changed mid-stream"; |
2132 ReportToUMA(MID_STREAM_RESOLUTION_CHANGE); | 1422 report_error_to_uma_cb_.Run(MID_STREAM_RESOLUTION_CHANGE); |
2133 return false; | 1423 return false; |
2134 } | 1424 } |
2135 | 1425 |
2136 pic_width_ = width; | 1426 pic_size_.SetSize(width, height); |
2137 pic_height_ = height; | |
2138 | 1427 |
2139 max_pic_order_cnt_lsb_ = 1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4); | 1428 max_pic_order_cnt_lsb_ = 1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4); |
2140 max_frame_num_ = 1 << (sps->log2_max_frame_num_minus4 + 4); | 1429 max_frame_num_ = 1 << (sps->log2_max_frame_num_minus4 + 4); |
2141 | 1430 |
2142 int level = sps->level_idc; | 1431 int level = sps->level_idc; |
2143 int max_dpb_mbs = LevelToMaxDpbMbs(level); | 1432 int max_dpb_mbs = LevelToMaxDpbMbs(level); |
2144 if (max_dpb_mbs == 0) | 1433 if (max_dpb_mbs == 0) |
2145 return false; | 1434 return false; |
2146 | 1435 |
2147 size_t max_dpb_size = std::min(max_dpb_mbs / (width_mb * height_mb), | 1436 size_t max_dpb_size = std::min(max_dpb_mbs / (width_mb * height_mb), |
(...skipping 24 matching lines...) Expand all Loading... |
2172 | 1461 |
2173 return true; | 1462 return true; |
2174 } | 1463 } |
2175 | 1464 |
2176 bool VaapiH264Decoder::ProcessSlice(H264SliceHeader* slice_hdr) { | 1465 bool VaapiH264Decoder::ProcessSlice(H264SliceHeader* slice_hdr) { |
2177 prev_frame_num_ = frame_num_; | 1466 prev_frame_num_ = frame_num_; |
2178 frame_num_ = slice_hdr->frame_num; | 1467 frame_num_ = slice_hdr->frame_num; |
2179 | 1468 |
2180 if (prev_frame_num_ > 0 && prev_frame_num_ < frame_num_ - 1) { | 1469 if (prev_frame_num_ > 0 && prev_frame_num_ < frame_num_ - 1) { |
2181 DVLOG(1) << "Gap in frame_num!"; | 1470 DVLOG(1) << "Gap in frame_num!"; |
2182 ReportToUMA(GAPS_IN_FRAME_NUM); | 1471 report_error_to_uma_cb_.Run(GAPS_IN_FRAME_NUM); |
2183 return false; | 1472 return false; |
2184 } | 1473 } |
2185 | 1474 |
2186 if (slice_hdr->field_pic_flag == 0) | 1475 if (slice_hdr->field_pic_flag == 0) |
2187 max_pic_num_ = max_frame_num_; | 1476 max_pic_num_ = max_frame_num_; |
2188 else | 1477 else |
2189 max_pic_num_ = 2 * max_frame_num_; | 1478 max_pic_num_ = 2 * max_frame_num_; |
2190 | 1479 |
2191 // TODO posciak: switch to new picture detection per 7.4.1.2.4. | 1480 // TODO posciak: switch to new picture detection per 7.4.1.2.4. |
2192 if (curr_pic_ != NULL && slice_hdr->first_mb_in_slice != 0) { | 1481 if (curr_pic_ != NULL && slice_hdr->first_mb_in_slice != 0) { |
(...skipping 17 matching lines...) Expand all Loading... |
2210 state_ = kError; \ | 1499 state_ = kError; \ |
2211 return VaapiH264Decoder::kDecodeError; \ | 1500 return VaapiH264Decoder::kDecodeError; \ |
2212 } while (0) | 1501 } while (0) |
2213 | 1502 |
2214 VaapiH264Decoder::DecResult VaapiH264Decoder::DecodeInitial(int32 input_id) { | 1503 VaapiH264Decoder::DecResult VaapiH264Decoder::DecodeInitial(int32 input_id) { |
2215 // Decode enough to get required picture size (i.e. until we find an SPS), | 1504 // Decode enough to get required picture size (i.e. until we find an SPS), |
2216 // if we get any slice data, we are missing the beginning of the stream. | 1505 // if we get any slice data, we are missing the beginning of the stream. |
2217 H264NALU nalu; | 1506 H264NALU nalu; |
2218 H264Parser::Result res; | 1507 H264Parser::Result res; |
2219 | 1508 |
2220 DCHECK_NE(state_, kUninitialized); | 1509 if (state_ == kDecoding) |
| 1510 return kReadyToDecode; |
2221 | 1511 |
2222 curr_input_id_ = input_id; | 1512 curr_input_id_ = input_id; |
2223 | 1513 |
2224 while (1) { | 1514 while (1) { |
2225 if (state_ == kAfterReset && num_available_decode_surfaces_ == 0) { | 1515 // If we've already decoded some of the stream (after reset), we may be able |
| 1516 // to go into decoding state not only starting at/resuming from an SPS, but |
| 1517 // also from other resume points, such as IDRs. In such a case we need an |
| 1518 // output surface in case we end up decoding a frame. Otherwise we just look |
| 1519 // for an SPS and don't need any outputs. |
| 1520 if (curr_sps_id_ != -1 && available_va_surfaces_.empty()) { |
2226 DVLOG(4) << "No output surfaces available"; | 1521 DVLOG(4) << "No output surfaces available"; |
2227 return kNoOutputAvailable; | 1522 return kNoOutputAvailable; |
2228 } | 1523 } |
2229 | 1524 |
2230 // Get next NALU looking for SPS or IDR if after reset. | 1525 // Get next NALU looking for SPS or IDR if after reset. |
2231 res = parser_.AdvanceToNextNALU(&nalu); | 1526 res = parser_.AdvanceToNextNALU(&nalu); |
2232 if (res == H264Parser::kEOStream) { | 1527 if (res == H264Parser::kEOStream) { |
2233 DVLOG(1) << "Could not find SPS before EOS"; | 1528 DVLOG(1) << "Could not find SPS before EOS"; |
2234 return kNeedMoreStreamData; | 1529 return kNeedMoreStreamData; |
2235 } else if (res != H264Parser::kOk) { | 1530 } else if (res != H264Parser::kOk) { |
2236 SET_ERROR_AND_RETURN(); | 1531 SET_ERROR_AND_RETURN(); |
2237 } | 1532 } |
2238 | 1533 |
2239 DVLOG(4) << " NALU found: " << static_cast<int>(nalu.nal_unit_type); | 1534 DVLOG(4) << " NALU found: " << static_cast<int>(nalu.nal_unit_type); |
2240 | 1535 |
2241 switch (nalu.nal_unit_type) { | 1536 switch (nalu.nal_unit_type) { |
2242 case H264NALU::kSPS: | 1537 case H264NALU::kSPS: |
2243 res = parser_.ParseSPS(&curr_sps_id_); | 1538 res = parser_.ParseSPS(&curr_sps_id_); |
2244 if (res != H264Parser::kOk) | 1539 if (res != H264Parser::kOk) |
2245 SET_ERROR_AND_RETURN(); | 1540 SET_ERROR_AND_RETURN(); |
2246 | 1541 |
2247 if (!ProcessSPS(curr_sps_id_)) | 1542 if (!ProcessSPS(curr_sps_id_)) |
2248 SET_ERROR_AND_RETURN(); | 1543 SET_ERROR_AND_RETURN(); |
2249 | 1544 |
2250 // Just got information about the video size from SPS, so we can | |
2251 // now allocate surfaces and let the client now we are ready to | |
2252 // accept output buffers and decode. | |
2253 if (!CreateVASurfaces()) | |
2254 SET_ERROR_AND_RETURN(); | |
2255 | |
2256 state_ = kDecoding; | 1545 state_ = kDecoding; |
2257 return kReadyToDecode; | 1546 return kReadyToDecode; |
2258 | 1547 |
2259 case H264NALU::kIDRSlice: | 1548 case H264NALU::kIDRSlice: |
2260 // If after reset, should be able to recover from an IDR. | 1549 // If after reset, should be able to recover from an IDR. |
2261 if (state_ == kAfterReset) { | 1550 // TODO(posciak): the IDR may require an SPS that we don't have |
| 1551 // available. For now we'd fail if that happens, but ideally we'd like |
| 1552 // to keep going until the next SPS in the stream. |
| 1553 if (curr_sps_id_ != -1) { |
2262 H264SliceHeader slice_hdr; | 1554 H264SliceHeader slice_hdr; |
2263 | 1555 |
2264 res = parser_.ParseSliceHeader(nalu, &slice_hdr); | 1556 res = parser_.ParseSliceHeader(nalu, &slice_hdr); |
2265 if (res != H264Parser::kOk) | 1557 if (res != H264Parser::kOk) |
2266 SET_ERROR_AND_RETURN(); | 1558 SET_ERROR_AND_RETURN(); |
2267 | 1559 |
2268 if (!ProcessSlice(&slice_hdr)) | 1560 if (!ProcessSlice(&slice_hdr)) |
2269 SET_ERROR_AND_RETURN(); | 1561 SET_ERROR_AND_RETURN(); |
2270 | 1562 |
2271 state_ = kDecoding; | 1563 state_ = kDecoding; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2306 DVLOG(1) << "Decoder not ready: error in stream or not initialized"; | 1598 DVLOG(1) << "Decoder not ready: error in stream or not initialized"; |
2307 return kDecodeError; | 1599 return kDecodeError; |
2308 } | 1600 } |
2309 | 1601 |
2310 // All of the actions below might result in decoding a picture from | 1602 // All of the actions below might result in decoding a picture from |
2311 // previously parsed data, but we still have to handle/parse current input | 1603 // previously parsed data, but we still have to handle/parse current input |
2312 // first. | 1604 // first. |
2313 // Note: this may drop some already decoded frames if there are errors | 1605 // Note: this may drop some already decoded frames if there are errors |
2314 // further in the stream, but we are OK with that. | 1606 // further in the stream, but we are OK with that. |
2315 while (1) { | 1607 while (1) { |
2316 if (num_available_decode_surfaces_ == 0) { | 1608 if (available_va_surfaces_.empty()) { |
2317 DVLOG(4) << "No output surfaces available"; | 1609 DVLOG(4) << "No output surfaces available"; |
2318 return kNoOutputAvailable; | 1610 return kNoOutputAvailable; |
2319 } | 1611 } |
| 1612 |
2320 par_res = parser_.AdvanceToNextNALU(&nalu); | 1613 par_res = parser_.AdvanceToNextNALU(&nalu); |
2321 if (par_res == H264Parser::kEOStream) | 1614 if (par_res == H264Parser::kEOStream) |
2322 return kNeedMoreStreamData; | 1615 return kNeedMoreStreamData; |
2323 else if (par_res != H264Parser::kOk) | 1616 else if (par_res != H264Parser::kOk) |
2324 SET_ERROR_AND_RETURN(); | 1617 SET_ERROR_AND_RETURN(); |
2325 | 1618 |
2326 DVLOG(4) << "NALU found: " << static_cast<int>(nalu.nal_unit_type); | 1619 DVLOG(4) << "NALU found: " << static_cast<int>(nalu.nal_unit_type); |
2327 | 1620 |
2328 switch (nalu.nal_unit_type) { | 1621 switch (nalu.nal_unit_type) { |
2329 case H264NALU::kNonIDRSlice: | 1622 case H264NALU::kNonIDRSlice: |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2364 SET_ERROR_AND_RETURN(); | 1657 SET_ERROR_AND_RETURN(); |
2365 | 1658 |
2366 if (!ProcessPPS(pps_id)) | 1659 if (!ProcessPPS(pps_id)) |
2367 SET_ERROR_AND_RETURN(); | 1660 SET_ERROR_AND_RETURN(); |
2368 break; | 1661 break; |
2369 | 1662 |
2370 default: | 1663 default: |
2371 // skip NALU | 1664 // skip NALU |
2372 break; | 1665 break; |
2373 } | 1666 } |
2374 | |
2375 // If the last action resulted in decoding a frame, possibly from older | |
2376 // data, return. Otherwise keep reading the stream. | |
2377 if (frame_ready_at_hw_) { | |
2378 frame_ready_at_hw_ = false; | |
2379 return kDecodedFrame; | |
2380 } | |
2381 } | 1667 } |
2382 } | 1668 } |
2383 | 1669 |
2384 size_t VaapiH264Decoder::GetRequiredNumOfPictures() { | 1670 size_t VaapiH264Decoder::GetRequiredNumOfPictures() { |
2385 return dpb_.max_num_pics() + kPicsInPipeline; | 1671 return dpb_.max_num_pics() + kPicsInPipeline; |
2386 } | 1672 } |
2387 | 1673 |
2388 // static | |
2389 void VaapiH264Decoder::PreSandboxInitialization() { | |
2390 DCHECK(!pre_sandbox_init_done_); | |
2391 vaapi_handle = dlopen("libva.so", RTLD_NOW); | |
2392 vaapi_x11_handle = dlopen("libva-x11.so", RTLD_NOW); | |
2393 pre_sandbox_init_done_ = vaapi_handle && vaapi_x11_handle; | |
2394 } | |
2395 | |
2396 // static | |
2397 bool VaapiH264Decoder::PostSandboxInitialization() { | |
2398 if (!pre_sandbox_init_done_) | |
2399 return false; | |
2400 #define VAAPI_DLSYM(name, handle) \ | |
2401 VAAPI_##name = reinterpret_cast<Vaapi##name>(dlsym((handle), "va"#name)) \ | |
2402 | |
2403 VAAPI_DLSYM(GetDisplay, vaapi_x11_handle); | |
2404 VAAPI_DLSYM(DisplayIsValid, vaapi_handle); | |
2405 VAAPI_DLSYM(Initialize, vaapi_handle); | |
2406 VAAPI_DLSYM(Terminate, vaapi_handle); | |
2407 VAAPI_DLSYM(GetConfigAttributes, vaapi_handle); | |
2408 VAAPI_DLSYM(CreateConfig, vaapi_handle); | |
2409 VAAPI_DLSYM(DestroyConfig, vaapi_handle); | |
2410 VAAPI_DLSYM(CreateSurfaces, vaapi_handle); | |
2411 VAAPI_DLSYM(DestroySurfaces, vaapi_handle); | |
2412 VAAPI_DLSYM(CreateContext, vaapi_handle); | |
2413 VAAPI_DLSYM(DestroyContext, vaapi_handle); | |
2414 VAAPI_DLSYM(PutSurface, vaapi_x11_handle); | |
2415 VAAPI_DLSYM(SyncSurface, vaapi_x11_handle); | |
2416 VAAPI_DLSYM(BeginPicture, vaapi_handle); | |
2417 VAAPI_DLSYM(RenderPicture, vaapi_handle); | |
2418 VAAPI_DLSYM(EndPicture, vaapi_handle); | |
2419 VAAPI_DLSYM(CreateBuffer, vaapi_handle); | |
2420 VAAPI_DLSYM(DestroyBuffer, vaapi_handle); | |
2421 VAAPI_DLSYM(ErrorStr, vaapi_handle); | |
2422 #undef VAAPI_DLSYM | |
2423 | |
2424 return VAAPI_GetDisplay && | |
2425 VAAPI_DisplayIsValid && | |
2426 VAAPI_Initialize && | |
2427 VAAPI_Terminate && | |
2428 VAAPI_GetConfigAttributes && | |
2429 VAAPI_CreateConfig && | |
2430 VAAPI_DestroyConfig && | |
2431 VAAPI_CreateSurfaces && | |
2432 VAAPI_DestroySurfaces && | |
2433 VAAPI_CreateContext && | |
2434 VAAPI_DestroyContext && | |
2435 VAAPI_PutSurface && | |
2436 VAAPI_SyncSurface && | |
2437 VAAPI_BeginPicture && | |
2438 VAAPI_RenderPicture && | |
2439 VAAPI_EndPicture && | |
2440 VAAPI_CreateBuffer && | |
2441 VAAPI_DestroyBuffer && | |
2442 VAAPI_ErrorStr; | |
2443 } | |
2444 | |
2445 } // namespace content | 1674 } // namespace content |
OLD | NEW |