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

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

Issue 14914009: VAVDA: Redesign stage 1. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <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" 10 #include "base/memory/ref_counted.h"
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 how is this not required by the .h?
Pawel Osciak 2013/05/21 22:32:35 vaapi_delegate.h included from there includes it.
13 #include "base/stl_util.h" 11 #include "base/stl_util.h"
14 #include "content/common/gpu/media/vaapi_h264_decoder.h" 12 #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 13
61 namespace content { 14 namespace content {
62 15
63 void *vaapi_handle = NULL; 16 // Decode surface, used for decoding and reference. input_id comes from client
64 void *vaapi_x11_handle = NULL; 17 // and is associated with the surface that was produced as the result
65 18 // 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 { 19 class VaapiH264Decoder::DecodeSurface {
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 Would this be better off as an almost-POD now that
Pawel Osciak 2013/05/21 22:32:35 Well, taking a quick peek into the vortex, there's
161 public: 20 public:
162 DecodeSurface(const GLXFBConfig& fb_config, 21 DecodeSurface(int poc,
163 Display* x_display, 22 int32 input_id,
164 VADisplay va_display, 23 const scoped_refptr<VASurface>& va_surface);
165 const base::Callback<bool(void)>& make_context_current, 24 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(); 25 ~DecodeSurface();
171 26
172 VASurfaceID va_surface_id() { 27 int poc() {
173 return va_surface_id_; 28 return poc_;
174 } 29 }
175 30
176 int32 picture_buffer_id() { 31 VASurfaceID va_surface_id() {
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 Is this really adding value compared with va_surfa
Pawel Osciak 2013/05/21 22:32:35 Avoid a second call? I bet you'll say this is not
Ami GONE FROM CHROMIUM 2013/05/22 23:59:47 lol
Pawel Osciak 2013/05/24 01:46:39 I take it as lol ok. Another reason: va_surface()
177 return picture_buffer_id_; 32 return va_surface_->id();
178 } 33 }
179 34
180 uint32 texture_id() { 35 scoped_refptr<VASurface> va_surface() {
181 return texture_id_; 36 return va_surface_;
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 } 37 }
205 38
206 int32 input_id() { 39 int32 input_id() {
207 return input_id_; 40 return input_id_;
208 } 41 }
209 42
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: 43 private:
226 Display* x_display_; 44 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_; 45 int32 input_id_;
233 int32 picture_buffer_id_; 46 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 }; 47 };
257 48
258 VaapiH264Decoder::DecodeSurface::DecodeSurface( 49 VaapiH264Decoder::DecodeSurface::DecodeSurface(
259 const GLXFBConfig& fb_config, 50 int poc,
260 Display* x_display, 51 int32 input_id,
261 VADisplay va_display, 52 const scoped_refptr<VASurface>& va_surface)
262 const base::Callback<bool(void)>& make_context_current, 53 : poc_(poc),
263 VASurfaceID va_surface_id, 54 input_id_(input_id),
264 int32 picture_buffer_id, 55 va_surface_(va_surface) {
265 uint32 texture_id, 56 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 } 57 }
319 58
320 VaapiH264Decoder::DecodeSurface::~DecodeSurface() { 59 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 } 60 }
331 61
332 void VaapiH264Decoder::DecodeSurface::Acquire(int32 input_id, int poc) { 62 VaapiH264Decoder::VaapiH264Decoder(
333 DCHECK_EQ(available_, true); 63 const scoped_refptr<VaapiDelegate>& vaapi_delegate,
334 available_ = false; 64 const OutputPicCB& output_pic_cb,
335 at_client_ = false; 65 const ReportErrorCB& report_error_cb)
336 used_ = true; 66 : vaapi_delegate_(vaapi_delegate),
337 input_id_ = input_id; 67 output_pic_cb_(output_pic_cb),
338 poc_ = poc; 68 report_error_cb_(report_error_cb) {
339 }
340
341 void VaapiH264Decoder::DecodeSurface::Release() {
342 DCHECK_EQ(available_, false);
343 available_ = true;
344 used_ = false;
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(); 69 Reset();
370 curr_input_id_ = -1; 70 curr_input_id_ = -1;
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 does this not belong inside Reset()?
Pawel Osciak 2013/05/21 22:32:35 Nice catch, thanks.
371 x_display_ = NULL;
372 fb_config_ = NULL;
373 va_display_ = NULL;
374 curr_sps_id_ = -1; 71 curr_sps_id_ = -1;
375 curr_pps_id_ = -1; 72 curr_pps_id_ = -1;
376 pic_width_ = -1; 73 pic_size_ = gfx::Size();
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 noop
Pawel Osciak 2013/05/21 22:32:35 Done.
377 pic_height_ = -1;
378 max_frame_num_ = 0; 74 max_frame_num_ = 0;
379 max_pic_num_ = 0; 75 max_pic_num_ = 0;
380 max_long_term_frame_idx_ = 0; 76 max_long_term_frame_idx_ = 0;
381 max_pic_order_cnt_lsb_ = 0; 77 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; 78 last_output_poc_ = 0;
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 any reason these initializers couldn't/shouldn't g
Pawel Osciak 2013/05/21 22:32:35 Done.
386 } 79 }
387 80
388 VaapiH264Decoder::~VaapiH264Decoder() { 81 VaapiH264Decoder::~VaapiH264Decoder() {
389 Destroy();
390 } 82 }
391 83
392 // This puts the decoder in state where it keeps stream data and is ready 84 // Reset drops all queued inputs and outputs, but keeps all accumulated decoding
393 // to resume playback from a random location in the stream, but drops all 85 // metadata and leaves the decoder in a state ready to resume playback from
394 // inputs and outputs and makes all surfaces available for use. 86 // a random location in the stream.
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 this is an API comment, not an impl comment?
Pawel Osciak 2013/05/21 22:32:35 Done.
395 void VaapiH264Decoder::Reset() { 87 void VaapiH264Decoder::Reset() {
396 frame_ready_at_hw_ = false;
397
398 curr_pic_.reset(); 88 curr_pic_.reset();
399 89
400 frame_num_ = 0; 90 frame_num_ = 0;
401 prev_frame_num_ = -1; 91 prev_frame_num_ = -1;
402 prev_frame_num_offset_ = -1; 92 prev_frame_num_offset_ = -1;
403 93
404 prev_ref_has_memmgmnt5_ = false; 94 prev_ref_has_memmgmnt5_ = false;
405 prev_ref_top_field_order_cnt_ = -1; 95 prev_ref_top_field_order_cnt_ = -1;
406 prev_ref_pic_order_cnt_msb_ = -1; 96 prev_ref_pic_order_cnt_msb_ = -1;
407 prev_ref_pic_order_cnt_lsb_ = -1; 97 prev_ref_pic_order_cnt_lsb_ = -1;
408 prev_ref_field_ = H264Picture::FIELD_NONE; 98 prev_ref_field_ = H264Picture::FIELD_NONE;
409 99
410 // When called from the constructor, although va_display_ is invalid, 100 vaapi_delegate_->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 101
417 ref_pic_list0_.clear(); 102 ref_pic_list0_.clear();
418 ref_pic_list1_.clear(); 103 ref_pic_list1_.clear();
419 104
420 for (POCToDecodeSurfaces::iterator it = poc_to_decode_surfaces_.begin(); 105 for (DecSurfacesInUse::iterator it = decode_surfaces_in_use_.begin();
421 it != poc_to_decode_surfaces_.end(); ) { 106 it != decode_surfaces_in_use_.end(); ) {
422 int poc = it->second->poc(); 107 int poc = it->second->poc();
423 // Must be incremented before UnassignSurfaceFromPoC as this call 108 // Must be incremented before UnassignSurfaceFromPoC as this call
424 // invalidates |it|. 109 // invalidates |it|.
425 ++it; 110 ++it;
426 UnassignSurfaceFromPoC(poc); 111 UnassignSurfaceFromPoC(poc);
427 } 112 }
428 DCHECK(poc_to_decode_surfaces_.empty()); 113 DCHECK(decode_surfaces_in_use_.empty());
429 114
430 dpb_.Clear(); 115 dpb_.Clear();
431 parser_.Reset(); 116 parser_.Reset();
432 last_output_poc_ = 0; 117 last_output_poc_ = 0;
433 118
434 // Still initialized and ready to decode, unless called from constructor, 119 state_ = kIdle;
435 // which will change it back.
436 state_ = kAfterReset;
437 } 120 }
438 121
439 void VaapiH264Decoder::Destroy() { 122 void VaapiH264Decoder::ReuseSurface(
440 if (state_ == kUninitialized) 123 const scoped_refptr<VASurface>& va_surface) {
441 return; 124 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 } 125 }
693 126
694 // Fill |va_pic| with default/neutral values. 127 // Fill |va_pic| with default/neutral values.
695 static void InitVAPicture(VAPictureH264* va_pic) { 128 static void InitVAPicture(VAPictureH264* va_pic) {
696 memset(va_pic, 0, sizeof(*va_pic)); 129 memset(va_pic, 0, sizeof(*va_pic));
697 va_pic->picture_id = VA_INVALID_ID; 130 va_pic->picture_id = VA_INVALID_ID;
698 va_pic->flags = VA_PICTURE_H264_INVALID; 131 va_pic->flags = VA_PICTURE_H264_INVALID;
699 } 132 }
700 133
701 void VaapiH264Decoder::FillVAPicture(VAPictureH264 *va_pic, H264Picture* pic) { 134 void VaapiH264Decoder::FillVAPicture(VAPictureH264 *va_pic, H264Picture* pic) {
702 DCHECK(pic); 135 DCHECK(pic);
703 POCToDecodeSurfaces::iterator iter = poc_to_decode_surfaces_.find( 136
704 pic->pic_order_cnt); 137 DecodeSurface* dec_surface = DecodeSurfaceByPoC(pic->pic_order_cnt);
705 if (iter == poc_to_decode_surfaces_.end()) { 138 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 139 // Cannot provide a ref picture, will corrupt output, but may be able
708 // to recover. 140 // to recover.
709 InitVAPicture(va_pic); 141 InitVAPicture(va_pic);
710 return; 142 return;
711 } 143 }
712 144
713 va_pic->picture_id = iter->second->va_surface_id(); 145 va_pic->picture_id = dec_surface->va_surface_id();
714 va_pic->frame_idx = pic->frame_num; 146 va_pic->frame_idx = pic->frame_num;
715 va_pic->flags = 0; 147 va_pic->flags = 0;
716 148
717 switch (pic->field) { 149 switch (pic->field) {
718 case H264Picture::FIELD_NONE: 150 case H264Picture::FIELD_NONE:
719 break; 151 break;
720 case H264Picture::FIELD_TOP: 152 case H264Picture::FIELD_TOP:
721 va_pic->flags |= VA_PICTURE_H264_TOP_FIELD; 153 va_pic->flags |= VA_PICTURE_H264_TOP_FIELD;
722 break; 154 break;
723 case H264Picture::FIELD_BOTTOM: 155 case H264Picture::FIELD_BOTTOM:
(...skipping 19 matching lines...) Expand all
743 // Libva does not document this, but other implementations (e.g. mplayer) 175 // Libva does not document this, but other implementations (e.g. mplayer)
744 // do it this way as well. 176 // do it this way as well.
745 for (rit = dpb_.rbegin(), i = 0; rit != dpb_.rend() && i < num_pics; ++rit) { 177 for (rit = dpb_.rbegin(), i = 0; rit != dpb_.rend() && i < num_pics; ++rit) {
746 if ((*rit)->ref) 178 if ((*rit)->ref)
747 FillVAPicture(&va_pics[i++], *rit); 179 FillVAPicture(&va_pics[i++], *rit);
748 } 180 }
749 181
750 return i; 182 return i;
751 } 183 }
752 184
753 // Can only be called when all surfaces are already bound 185 VaapiH264Decoder::DecodeSurface* VaapiH264Decoder::DecodeSurfaceByPoC(int poc) {
754 // to textures (cannot be run at the same time as AssignPictureBuffer). 186 DecSurfacesInUse::iterator iter = decode_surfaces_in_use_.find(poc);
755 bool VaapiH264Decoder::AssignSurfaceToPoC(int poc) { 187 if (iter == decode_surfaces_in_use_.end()) {
756 DCHECK_GT(num_available_decode_surfaces_, 0) << decode_surfaces_.size(); 188 DVLOG(1) << "Could not find surface assigned to POC: " << poc;
757 189 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 } 190 }
778 191
779 // Could not find an available surface. 192 return iter->second.get();
780 return false;
781 } 193 }
782 194
783 // Can only be called when all surfaces are already bound 195 bool VaapiH264Decoder::AssignSurfaceToPoC(int32 input_id, int poc) {
784 // to textures (cannot be run at the same time as AssignPictureBuffer). 196 if (available_va_surfaces_.empty()) {
197 DVLOG(1) << "No VA Surfaces available";
198 return false;
199 }
200
201 linked_ptr<DecodeSurface> dec_surface(new DecodeSurface(
202 poc, input_id, available_va_surfaces_.front()));
203 available_va_surfaces_.pop_front();
204
205 DVLOG(4) << "POC " << poc
206 << " will use surface " << dec_surface->va_surface_id();
207
208 bool inserted = decode_surfaces_in_use_.insert(
209 std::make_pair(poc, dec_surface)).second;
210 DCHECK(inserted);
211
212 return true;
213 }
214
785 void VaapiH264Decoder::UnassignSurfaceFromPoC(int poc) { 215 void VaapiH264Decoder::UnassignSurfaceFromPoC(int poc) {
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 IWBN for there to be an ascii (or .dot) diagram +
Pawel Osciak 2013/05/21 22:32:35 Done.
786 DecodeSurface* dec_surface; 216 DecSurfacesInUse::iterator it = decode_surfaces_in_use_.find(poc);
787 POCToDecodeSurfaces::iterator it = poc_to_decode_surfaces_.find(poc); 217 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; 218 DVLOG(1) << "Asked to unassign an unassigned POC " << poc;
790 return; 219 return;
791 } 220 }
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 221
797 dec_surface->set_used(false); 222 DVLOG(4) << "POC " << poc << " no longer using VA surface "
798 if (!dec_surface->at_client()) { 223 << it->second->va_surface_id();
799 dec_surface->Release(); 224
800 ++num_available_decode_surfaces_; 225 decode_surfaces_in_use_.erase(it);
801 }
802 } 226 }
803 227
804 // Fill a VAPictureParameterBufferH264 to be later sent to the HW decoder.
805 bool VaapiH264Decoder::SendPPS() { 228 bool VaapiH264Decoder::SendPPS() {
806 const H264PPS* pps = parser_.GetPPS(curr_pps_id_); 229 const H264PPS* pps = parser_.GetPPS(curr_pps_id_);
807 DCHECK(pps); 230 DCHECK(pps);
808 231
809 const H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id); 232 const H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id);
810 DCHECK(sps); 233 DCHECK(sps);
811 234
812 DCHECK(curr_pic_.get()); 235 DCHECK(curr_pic_.get());
813 236
814 VAPictureParameterBufferH264 pic_param; 237 VAPictureParameterBufferH264 pic_param;
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
877 // Init reference pictures' array. 300 // Init reference pictures' array.
878 for (int i = 0; i < 16; ++i) 301 for (int i = 0; i < 16; ++i)
879 InitVAPicture(&pic_param.ReferenceFrames[i]); 302 InitVAPicture(&pic_param.ReferenceFrames[i]);
880 303
881 // And fill it with picture info from DPB. 304 // And fill it with picture info from DPB.
882 FillVARefFramesFromDPB(pic_param.ReferenceFrames, 305 FillVARefFramesFromDPB(pic_param.ReferenceFrames,
883 arraysize(pic_param.ReferenceFrames)); 306 arraysize(pic_param.ReferenceFrames));
884 307
885 pic_param.num_ref_frames = sps->max_num_ref_frames; 308 pic_param.num_ref_frames = sps->max_num_ref_frames;
886 309
887 // Allocate a buffer in driver for this parameter buffer and upload data. 310 return vaapi_delegate_->SubmitBuffer(VAPictureParameterBufferType,
888 VABufferID pic_param_buf_id;
889 VAStatus va_res = VAAPI_CreateBuffer(va_display_, va_context_id_,
890 VAPictureParameterBufferType,
891 sizeof(VAPictureParameterBufferH264), 311 sizeof(VAPictureParameterBufferH264),
892 1, &pic_param, &pic_param_buf_id); 312 &pic_param);
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 } 313 }
900 314
901 // Fill a VAIQMatrixBufferH264 to be later sent to the HW decoder.
902 bool VaapiH264Decoder::SendIQMatrix() { 315 bool VaapiH264Decoder::SendIQMatrix() {
903 const H264PPS* pps = parser_.GetPPS(curr_pps_id_); 316 const H264PPS* pps = parser_.GetPPS(curr_pps_id_);
904 DCHECK(pps); 317 DCHECK(pps);
905 318
906 VAIQMatrixBufferH264 iq_matrix_buf; 319 VAIQMatrixBufferH264 iq_matrix_buf;
907 memset(&iq_matrix_buf, 0, sizeof(VAIQMatrixBufferH264)); 320 memset(&iq_matrix_buf, 0, sizeof(VAIQMatrixBufferH264));
908 321
909 if (pps->pic_scaling_matrix_present_flag) { 322 if (pps->pic_scaling_matrix_present_flag) {
910 for (int i = 0; i < 6; ++i) { 323 for (int i = 0; i < 6; ++i) {
911 for (int j = 0; j < 16; ++j) 324 for (int j = 0; j < 16; ++j)
(...skipping 11 matching lines...) Expand all
923 for (int j = 0; j < 16; ++j) 336 for (int j = 0; j < 16; ++j)
924 iq_matrix_buf.ScalingList4x4[i][j] = sps->scaling_list4x4[i][j]; 337 iq_matrix_buf.ScalingList4x4[i][j] = sps->scaling_list4x4[i][j];
925 } 338 }
926 339
927 for (int i = 0; i < 2; ++i) { 340 for (int i = 0; i < 2; ++i) {
928 for (int j = 0; j < 64; ++j) 341 for (int j = 0; j < 64; ++j)
929 iq_matrix_buf.ScalingList8x8[i][j] = sps->scaling_list8x8[i][j]; 342 iq_matrix_buf.ScalingList8x8[i][j] = sps->scaling_list8x8[i][j];
930 } 343 }
931 } 344 }
932 345
933 // Allocate a buffer in driver for this parameter buffer and upload data. 346 return vaapi_delegate_->SubmitBuffer(VAIQMatrixBufferType,
934 VABufferID iq_matrix_buf_id; 347 sizeof(VAIQMatrixBufferH264),
935 VAStatus va_res = VAAPI_CreateBuffer(va_display_, va_context_id_, 348 &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 } 349 }
947 350
948 bool VaapiH264Decoder::SendVASliceParam(H264SliceHeader* slice_hdr) { 351 bool VaapiH264Decoder::SendVASliceParam(H264SliceHeader* slice_hdr) {
949 const H264PPS* pps = parser_.GetPPS(slice_hdr->pic_parameter_set_id); 352 const H264PPS* pps = parser_.GetPPS(slice_hdr->pic_parameter_set_id);
950 DCHECK(pps); 353 DCHECK(pps);
951 354
952 const H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id); 355 const H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id);
953 DCHECK(sps); 356 DCHECK(sps);
954 357
955 VASliceParameterBufferH264 slice_param; 358 VASliceParameterBufferH264 slice_param;
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
1025 428
1026 int i; 429 int i;
1027 H264Picture::PtrVector::iterator it; 430 H264Picture::PtrVector::iterator it;
1028 for (it = ref_pic_list0_.begin(), i = 0; it != ref_pic_list0_.end() && *it; 431 for (it = ref_pic_list0_.begin(), i = 0; it != ref_pic_list0_.end() && *it;
1029 ++it, ++i) 432 ++it, ++i)
1030 FillVAPicture(&slice_param.RefPicList0[i], *it); 433 FillVAPicture(&slice_param.RefPicList0[i], *it);
1031 for (it = ref_pic_list1_.begin(), i = 0; it != ref_pic_list1_.end() && *it; 434 for (it = ref_pic_list1_.begin(), i = 0; it != ref_pic_list1_.end() && *it;
1032 ++it, ++i) 435 ++it, ++i)
1033 FillVAPicture(&slice_param.RefPicList1[i], *it); 436 FillVAPicture(&slice_param.RefPicList1[i], *it);
1034 437
1035 // Allocate a buffer in driver for this parameter buffer and upload data. 438 return vaapi_delegate_->SubmitBuffer(VASliceParameterBufferType,
1036 VABufferID slice_param_buf_id;
1037 VAStatus va_res = VAAPI_CreateBuffer(va_display_, va_context_id_,
1038 VASliceParameterBufferType,
1039 sizeof(VASliceParameterBufferH264), 439 sizeof(VASliceParameterBufferH264),
1040 1, &slice_param, &slice_param_buf_id); 440 &slice_param);
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 } 441 }
1049 442
1050 bool VaapiH264Decoder::SendSliceData(const uint8* ptr, size_t size) { 443 bool VaapiH264Decoder::SendSliceData(const uint8* ptr, size_t size) {
1051 // Can't help it, blame libva... 444 // Can't help it, blame libva...
1052 void* non_const_ptr = const_cast<uint8*>(ptr); 445 void* non_const_ptr = const_cast<uint8*>(ptr);
1053 446 return vaapi_delegate_->SubmitBuffer(VASliceDataBufferType, size,
1054 VABufferID slice_data_buf_id; 447 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 } 448 }
1064 449
1065 bool VaapiH264Decoder::QueueSlice(H264SliceHeader* slice_hdr) { 450 bool VaapiH264Decoder::QueueSlice(H264SliceHeader* slice_hdr) {
1066 DCHECK(curr_pic_.get()); 451 DCHECK(curr_pic_.get());
1067 452
1068 if (!SendVASliceParam(slice_hdr)) 453 if (!SendVASliceParam(slice_hdr))
1069 return false; 454 return false;
1070 455
1071 if (!SendSliceData(slice_hdr->nalu_data, slice_hdr->nalu_size)) 456 if (!SendSliceData(slice_hdr->nalu_data, slice_hdr->nalu_size))
1072 return false; 457 return false;
1073 458
1074 return true; 459 return true;
1075 } 460 }
1076 461
462 // TODO(posciak) start using vaMapBuffer instead of vaCreateBuffer wherever
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 comment trails off
Pawel Osciak 2013/05/21 22:32:35 Done.
1077 bool VaapiH264Decoder::DecodePicture() { 463 bool VaapiH264Decoder::DecodePicture() {
1078 DCHECK(!frame_ready_at_hw_);
1079 DCHECK(curr_pic_.get()); 464 DCHECK(curr_pic_.get());
1080 465
1081 // Find the surface associated with the picture to be decoded. 466 DVLOG(4) << "Decoding POC " << curr_pic_->pic_order_cnt;
1082 DecodeSurface* dec_surface = 467 DecodeSurface* dec_surface = DecodeSurfaceByPoC(curr_pic_->pic_order_cnt);
1083 poc_to_decode_surfaces_[curr_pic_->pic_order_cnt]; 468 if (!dec_surface) {
1084 DVLOG(4) << "Decoding POC " << curr_pic_->pic_order_cnt 469 DVLOG(1) << "Asked to decode an invalid POC " << curr_pic_->pic_order_cnt;
1085 << " into surface " << dec_surface->va_surface_id(); 470 return false;
471 }
1086 472
1087 DVLOG(4) << "Pending VA bufs to commit: " << pending_va_bufs_.size(); 473 if (!vaapi_delegate_->DecodeAndDestroyPendingBuffers(
1088 DVLOG(4) << "Pending slice bufs to commit: " << pending_slice_bufs_.size(); 474 dec_surface->va_surface_id())) {
1089 475 DVLOG(1) << "Failed decoding picture";
1090 DCHECK(pending_slice_bufs_.size()); 476 return false;
1091 scoped_ptr<std::queue<VABufferID> > va_bufs(new std::queue<VABufferID>()); 477 }
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 478
1106 return true; 479 return true;
1107 } 480 }
1108 481
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 482
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) { 483 bool VaapiH264Decoder::InitCurrPicture(H264SliceHeader* slice_hdr) {
1190 DCHECK(curr_pic_.get()); 484 DCHECK(curr_pic_.get());
1191 485
1192 memset(curr_pic_.get(), 0, sizeof(H264Picture)); 486 memset(curr_pic_.get(), 0, sizeof(H264Picture));
1193 487
1194 curr_pic_->idr = slice_hdr->idr_pic_flag; 488 curr_pic_->idr = slice_hdr->idr_pic_flag;
1195 489
1196 if (slice_hdr->field_pic_flag) { 490 if (slice_hdr->field_pic_flag) {
1197 curr_pic_->field = slice_hdr->bottom_field_flag ? H264Picture::FIELD_BOTTOM 491 curr_pic_->field = slice_hdr->bottom_field_flag ? H264Picture::FIELD_BOTTOM
1198 : H264Picture::FIELD_TOP; 492 : H264Picture::FIELD_TOP;
1199 } else { 493 } else {
1200 curr_pic_->field = H264Picture::FIELD_NONE; 494 curr_pic_->field = H264Picture::FIELD_NONE;
1201 } 495 }
1202 496
1203 curr_pic_->ref = slice_hdr->nal_ref_idc != 0; 497 curr_pic_->ref = slice_hdr->nal_ref_idc != 0;
1204 // This assumes non-interlaced stream. 498 // This assumes non-interlaced stream.
1205 curr_pic_->frame_num = curr_pic_->pic_num = slice_hdr->frame_num; 499 curr_pic_->frame_num = curr_pic_->pic_num = slice_hdr->frame_num;
1206 500
1207 if (!CalculatePicOrderCounts(slice_hdr)) 501 if (!CalculatePicOrderCounts(slice_hdr))
1208 return false; 502 return false;
1209 503
1210 // Try to get an empty surface to decode this picture to. 504 // Try to get an empty surface to decode this picture to.
1211 if (!AssignSurfaceToPoC(curr_pic_->pic_order_cnt)) { 505 if (!AssignSurfaceToPoC(curr_input_id_, curr_pic_->pic_order_cnt)) {
1212 DVLOG(1) << "Failed getting a free surface for a picture"; 506 DVLOG(1) << "Failed getting a free surface for a picture";
1213 return false; 507 return false;
1214 } 508 }
1215 509
1216 curr_pic_->long_term_reference_flag = slice_hdr->long_term_reference_flag; 510 curr_pic_->long_term_reference_flag = slice_hdr->long_term_reference_flag;
1217 curr_pic_->adaptive_ref_pic_marking_mode_flag = 511 curr_pic_->adaptive_ref_pic_marking_mode_flag =
1218 slice_hdr->adaptive_ref_pic_marking_mode_flag; 512 slice_hdr->adaptive_ref_pic_marking_mode_flag;
1219 513
1220 // If the slice header indicates we will have to perform reference marking 514 // If the slice header indicates we will have to perform reference marking
1221 // process after this picture is decoded, store required data for that 515 // process after this picture is decoded, store required data for that
(...skipping 479 matching lines...) Expand 10 before | Expand all | Expand 10 after
1701 995
1702 // Per NOTE 2 in 8.2.4.3.2, the ref_pic_listx size in the above loop is 996 // Per NOTE 2 in 8.2.4.3.2, the ref_pic_listx size in the above loop is
1703 // temporarily made one element longer than the required final list. 997 // temporarily made one element longer than the required final list.
1704 // Resize the list back to its required size. 998 // Resize the list back to its required size.
1705 ref_pic_listx->resize(num_ref_idx_lX_active_minus1 + 1); 999 ref_pic_listx->resize(num_ref_idx_lX_active_minus1 + 1);
1706 1000
1707 return true; 1001 return true;
1708 } 1002 }
1709 1003
1710 bool VaapiH264Decoder::OutputPic(H264Picture* pic) { 1004 bool VaapiH264Decoder::OutputPic(H264Picture* pic) {
1711 DCHECK(!pic->outputted); 1005 if (pic->outputted)
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 how can this happen?
Pawel Osciak 2013/05/21 22:32:35 Another visitor from the future, but a harmless on
Ami GONE FROM CHROMIUM 2013/05/22 23:59:47 That is a terrible logic. Head-scratchers should
Pawel Osciak 2013/05/24 01:46:39 Done.
1006 return true;
1007
1712 pic->outputted = true; 1008 pic->outputted = true;
1713 POCToDecodeSurfaces::iterator iter = poc_to_decode_surfaces_.find( 1009 last_output_poc_ = pic->pic_order_cnt;
1714 pic->pic_order_cnt); 1010
1715 if (iter == poc_to_decode_surfaces_.end()) 1011 DecodeSurface* dec_surface = DecodeSurfaceByPoC(pic->pic_order_cnt);
1012 if (!dec_surface)
1716 return false; 1013 return false;
1717 DecodeSurface* dec_surface = iter->second;
1718 1014
1719 dec_surface->set_at_client(true); 1015 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 1016 DVLOG(4) << "Posting output task for POC: " << pic->pic_order_cnt
1723 << " input_id: " << dec_surface->input_id() 1017 << " input_id: " << dec_surface->input_id();
1724 << "output_id: " << dec_surface->picture_buffer_id(); 1018 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 1019
1728 return true; 1020 return true;
1729 } 1021 }
1730 1022
1731 bool VaapiH264Decoder::Flush() { 1023 void VaapiH264Decoder::ClearDPB() {
1024 // Clear DPB contents, marking the pictures as unused first.
1025 for (H264DPB::Pictures::iterator it = dpb_.begin(); it != dpb_.end(); ++it)
1026 UnassignSurfaceFromPoC((*it)->pic_order_cnt);
1027
1028 dpb_.Clear();
1029 last_output_poc_ = 0;
1030 }
1031
1032 bool VaapiH264Decoder::OutputAllRemainingPics() {
1732 // Output all pictures that are waiting to be outputted. 1033 // Output all pictures that are waiting to be outputted.
1733 FinishPrevFrameIfPresent(); 1034 FinishPrevFrameIfPresent();
1734 H264Picture::PtrVector to_output; 1035 H264Picture::PtrVector to_output;
1735 dpb_.GetNotOutputtedPicsAppending(to_output); 1036 dpb_.GetNotOutputtedPicsAppending(to_output);
1736 // Sort them by ascending POC to output in order. 1037 // Sort them by ascending POC to output in order.
1737 std::sort(to_output.begin(), to_output.end(), POCAscCompare()); 1038 std::sort(to_output.begin(), to_output.end(), POCAscCompare());
1738 1039
1739 H264Picture::PtrVector::iterator it; 1040 H264Picture::PtrVector::iterator it;
1740 for (it = to_output.begin(); it != to_output.end(); ++it) { 1041 for (it = to_output.begin(); it != to_output.end(); ++it) {
1741 if (!OutputPic(*it)) { 1042 if (!OutputPic(*it)) {
1742 DVLOG(1) << "Failed to output pic POC: " << (*it)->pic_order_cnt; 1043 DVLOG(1) << "Failed to output pic POC: " << (*it)->pic_order_cnt;
1743 return false; 1044 return false;
1744 } 1045 }
1745 } 1046 }
1746 1047
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; 1048 return true;
1756 } 1049 }
1757 1050
1051 bool VaapiH264Decoder::Flush() {
1052 if (!OutputAllRemainingPics())
1053 return false;
1054
1055 ClearDPB();
Ami GONE FROM CHROMIUM 2013/05/17 23:19:15 Why not clear the DPB if outputting fails above?
Pawel Osciak 2013/05/21 22:32:35 No false return from anywhere will ever result in
1056
1057 DCHECK(decode_surfaces_in_use_.empty());
1058 return true;
1059 }
1060
1758 bool VaapiH264Decoder::StartNewFrame(H264SliceHeader* slice_hdr) { 1061 bool VaapiH264Decoder::StartNewFrame(H264SliceHeader* slice_hdr) {
1759 // TODO posciak: add handling of max_num_ref_frames per spec. 1062 // TODO posciak: add handling of max_num_ref_frames per spec.
1760 1063
1761 // If the new frame is an IDR, output what's left to output and clear DPB 1064 // If the new frame is an IDR, output what's left to output and clear DPB
1762 if (slice_hdr->idr_pic_flag) { 1065 if (slice_hdr->idr_pic_flag) {
1763 // (unless we are explicitly instructed not to do so). 1066 // (unless we are explicitly instructed not to do so).
1764 if (!slice_hdr->no_output_of_prior_pics_flag) { 1067 if (!slice_hdr->no_output_of_prior_pics_flag) {
1765 // Output DPB contents. 1068 // Output DPB contents.
1766 if (!Flush()) 1069 if (!Flush())
1767 return false; 1070 return false;
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
1958 H264Picture* to_unmark = dpb_.GetLowestFrameNumWrapShortRefPic(); 1261 H264Picture* to_unmark = dpb_.GetLowestFrameNumWrapShortRefPic();
1959 if (to_unmark == NULL) { 1262 if (to_unmark == NULL) {
1960 DVLOG(1) << "Couldn't find a short ref picture to unmark"; 1263 DVLOG(1) << "Couldn't find a short ref picture to unmark";
1961 return; 1264 return;
1962 } 1265 }
1963 to_unmark->ref = false; 1266 to_unmark->ref = false;
1964 } 1267 }
1965 } else { 1268 } else {
1966 // Shouldn't get here. 1269 // Shouldn't get here.
1967 DVLOG(1) << "Interlaced video not supported."; 1270 DVLOG(1) << "Interlaced video not supported.";
1968 ReportToUMA(INTERLACED_STREAM); 1271 report_error_cb_.Run(INTERLACED_STREAM);
1969 } 1272 }
1970 } else { 1273 } else {
1971 // Stream has instructions how to discard pictures from DPB and how 1274 // Stream has instructions how to discard pictures from DPB and how
1972 // to mark/unmark existing reference pictures. Do it. 1275 // to mark/unmark existing reference pictures. Do it.
1973 // Spec 8.2.5.4. 1276 // Spec 8.2.5.4.
1974 if (curr_pic_->field == H264Picture::FIELD_NONE) { 1277 if (curr_pic_->field == H264Picture::FIELD_NONE) {
1975 HandleMemoryManagementOps(); 1278 HandleMemoryManagementOps();
1976 } else { 1279 } else {
1977 // Shouldn't get here. 1280 // Shouldn't get here.
1978 DVLOG(1) << "Interlaced video not supported."; 1281 DVLOG(1) << "Interlaced video not supported.";
1979 ReportToUMA(INTERLACED_STREAM); 1282 report_error_cb_.Run(INTERLACED_STREAM);
1980 } 1283 }
1981 } 1284 }
1982 } 1285 }
1983 } 1286 }
1984 1287
1985 bool VaapiH264Decoder::FinishPicture() { 1288 bool VaapiH264Decoder::FinishPicture() {
1986 DCHECK(curr_pic_.get()); 1289 DCHECK(curr_pic_.get());
1987 1290
1988 // Finish processing previous picture. 1291 // Finish processing previous picture.
1989 // Start by storing previous reference picture data for later use, 1292 // Start by storing previous reference picture data for later use,
1990 // if picture being finished is a reference picture. 1293 // if picture being finished is a reference picture.
1991 if (curr_pic_->ref) { 1294 if (curr_pic_->ref) {
1992 ReferencePictureMarking(); 1295 ReferencePictureMarking();
1993 prev_ref_has_memmgmnt5_ = curr_pic_->mem_mgmt_5; 1296 prev_ref_has_memmgmnt5_ = curr_pic_->mem_mgmt_5;
1994 prev_ref_top_field_order_cnt_ = curr_pic_->top_field_order_cnt; 1297 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; 1298 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; 1299 prev_ref_pic_order_cnt_lsb_ = curr_pic_->pic_order_cnt_lsb;
1997 prev_ref_field_ = curr_pic_->field; 1300 prev_ref_field_ = curr_pic_->field;
1998 } 1301 }
1999 prev_has_memmgmnt5_ = curr_pic_->mem_mgmt_5; 1302 prev_has_memmgmnt5_ = curr_pic_->mem_mgmt_5;
2000 prev_frame_num_offset_ = curr_pic_->frame_num_offset; 1303 prev_frame_num_offset_ = curr_pic_->frame_num_offset;
2001 1304
2002 // Remove unused (for reference or later output) pictures from DPB, marking 1305 // Remove unused (for reference or later output) pictures from DPB, marking
2003 // them as such. 1306 // them as such.
2004 for (H264DPB::Pictures::iterator it = dpb_.begin(); it != dpb_.end(); ++it) { 1307 for (H264DPB::Pictures::iterator it = dpb_.begin(); it != dpb_.end(); ++it) {
2005 if ((*it)->outputted && !(*it)->ref) 1308 if ((*it)->outputted && !(*it)->ref)
2006 UnassignSurfaceFromPoC((*it)->pic_order_cnt); 1309 UnassignSurfaceFromPoC((*it)->pic_order_cnt);
2007 } 1310 }
2008 dpb_.RemoveUnused(); 1311 dpb_.DeleteUnused();
2009 1312
2010 DVLOG(4) << "Finishing picture, DPB entries: " << dpb_.size() 1313 DVLOG(4) << "Finishing picture, entries in DPB: " << dpb_.size();
2011 << " Num available dec surfaces: "
2012 << num_available_decode_surfaces_;
2013 1314
2014 // Whatever happens below, curr_pic_ will stop managing the pointer to the 1315 // Whatever happens below, curr_pic_ will stop managing the pointer to the
2015 // picture after this function returns. The ownership will either be 1316 // picture after this function returns. The ownership will either be
2016 // transferred to DPB, if the image is still needed (for output and/or 1317 // 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 1318 // reference), or the memory will be released if we manage to output it here
2018 // without having to store it for future reference. 1319 // without having to store it for future reference.
2019 scoped_ptr<H264Picture> pic(curr_pic_.release()); 1320 scoped_ptr<H264Picture> pic(curr_pic_.release());
2020 1321
2021 // Get all pictures that haven't been outputted yet. 1322 // Get all pictures that haven't been outputted yet.
2022 H264Picture::PtrVector not_outputted; 1323 H264Picture::PtrVector not_outputted;
(...skipping 16 matching lines...) Expand all
2039 (*output_candidate)->pic_order_cnt <= last_output_poc_ + 2; 1340 (*output_candidate)->pic_order_cnt <= last_output_poc_ + 2;
2040 ++output_candidate) { 1341 ++output_candidate) {
2041 DCHECK_GE((*output_candidate)->pic_order_cnt, last_output_poc_); 1342 DCHECK_GE((*output_candidate)->pic_order_cnt, last_output_poc_);
2042 if (!OutputPic(*output_candidate)) 1343 if (!OutputPic(*output_candidate))
2043 return false; 1344 return false;
2044 1345
2045 if (!(*output_candidate)->ref) { 1346 if (!(*output_candidate)->ref) {
2046 // Current picture hasn't been inserted into DPB yet, so don't remove it 1347 // Current picture hasn't been inserted into DPB yet, so don't remove it
2047 // if we managed to output it immediately. 1348 // if we managed to output it immediately.
2048 if (*output_candidate != pic) 1349 if (*output_candidate != pic)
2049 dpb_.RemoveByPOC((*output_candidate)->pic_order_cnt); 1350 dpb_.DeleteByPOC((*output_candidate)->pic_order_cnt);
2050 // Mark as unused. 1351 // Mark as unused.
2051 UnassignSurfaceFromPoC((*output_candidate)->pic_order_cnt); 1352 UnassignSurfaceFromPoC((*output_candidate)->pic_order_cnt);
2052 } 1353 }
2053 } 1354 }
2054 1355
2055 // If we haven't managed to output the picture that we just decoded, or if 1356 // 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. 1357 // it's a reference picture, we have to store it in DPB.
2057 if (!pic->outputted || pic->ref) { 1358 if (!pic->outputted || pic->ref) {
2058 if (dpb_.IsFull()) { 1359 if (dpb_.IsFull()) {
2059 // If we haven't managed to output anything to free up space in DPB 1360 // 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
2092 return 0; 1393 return 0;
2093 } 1394 }
2094 } 1395 }
2095 1396
2096 bool VaapiH264Decoder::ProcessSPS(int sps_id) { 1397 bool VaapiH264Decoder::ProcessSPS(int sps_id) {
2097 const H264SPS* sps = parser_.GetSPS(sps_id); 1398 const H264SPS* sps = parser_.GetSPS(sps_id);
2098 DCHECK(sps); 1399 DCHECK(sps);
2099 1400
2100 if (sps->frame_mbs_only_flag == 0) { 1401 if (sps->frame_mbs_only_flag == 0) {
2101 DVLOG(1) << "frame_mbs_only_flag != 1 not supported"; 1402 DVLOG(1) << "frame_mbs_only_flag != 1 not supported";
2102 ReportToUMA(FRAME_MBS_ONLY_FLAG_NOT_ONE); 1403 report_error_cb_.Run(FRAME_MBS_ONLY_FLAG_NOT_ONE);
2103 return false; 1404 return false;
2104 } 1405 }
2105 1406
2106 if (sps->gaps_in_frame_num_value_allowed_flag) { 1407 if (sps->gaps_in_frame_num_value_allowed_flag) {
2107 DVLOG(1) << "Gaps in frame numbers not supported"; 1408 DVLOG(1) << "Gaps in frame numbers not supported";
2108 ReportToUMA(GAPS_IN_FRAME_NUM); 1409 report_error_cb_.Run(GAPS_IN_FRAME_NUM);
2109 return false; 1410 return false;
2110 } 1411 }
2111 1412
2112 curr_sps_id_ = sps->seq_parameter_set_id; 1413 curr_sps_id_ = sps->seq_parameter_set_id;
2113 1414
2114 // Calculate picture height/width in macroblocks and pixels 1415 // Calculate picture height/width in macroblocks and pixels
2115 // (spec 7.4.2.1.1, 7.4.3). 1416 // (spec 7.4.2.1.1, 7.4.3).
2116 int width_mb = sps->pic_width_in_mbs_minus1 + 1; 1417 int width_mb = sps->pic_width_in_mbs_minus1 + 1;
2117 int height_mb = (2 - sps->frame_mbs_only_flag) * 1418 int height_mb = (2 - sps->frame_mbs_only_flag) *
2118 (sps->pic_height_in_map_units_minus1 + 1); 1419 (sps->pic_height_in_map_units_minus1 + 1);
2119 1420
2120 int width = 16 * width_mb; 1421 int width = 16 * width_mb;
2121 int height = 16 * height_mb; 1422 int height = 16 * height_mb;
2122 1423
2123 DVLOG(1) << "New picture size: " << width << "x" << height; 1424 DVLOG(1) << "New picture size: " << width << "x" << height;
2124 if (width == 0 || height == 0) { 1425 if (width == 0 || height == 0) {
2125 DVLOG(1) << "Invalid picture size!"; 1426 DVLOG(1) << "Invalid picture size!";
2126 return false; 1427 return false;
2127 } 1428 }
2128 1429
2129 if ((pic_width_ != -1 || pic_height_ != -1) && 1430 if (!pic_size_.IsEmpty() &&
2130 (width != pic_width_ || height != pic_height_)) { 1431 (width != pic_size_.width() || height != pic_size_.height())) {
2131 DVLOG(1) << "Picture size changed mid-stream"; 1432 DVLOG(1) << "Picture size changed mid-stream";
2132 ReportToUMA(MID_STREAM_RESOLUTION_CHANGE); 1433 report_error_cb_.Run(MID_STREAM_RESOLUTION_CHANGE);
2133 return false; 1434 return false;
2134 } 1435 }
2135 1436
2136 pic_width_ = width; 1437 pic_size_.SetSize(width, height);
2137 pic_height_ = height;
2138 1438
2139 max_pic_order_cnt_lsb_ = 1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4); 1439 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); 1440 max_frame_num_ = 1 << (sps->log2_max_frame_num_minus4 + 4);
2141 1441
2142 int level = sps->level_idc; 1442 int level = sps->level_idc;
2143 int max_dpb_mbs = LevelToMaxDpbMbs(level); 1443 int max_dpb_mbs = LevelToMaxDpbMbs(level);
2144 if (max_dpb_mbs == 0) 1444 if (max_dpb_mbs == 0)
2145 return false; 1445 return false;
2146 1446
2147 size_t max_dpb_size = std::min(max_dpb_mbs / (width_mb * height_mb), 1447 size_t max_dpb_size = std::min(max_dpb_mbs / (width_mb * height_mb),
(...skipping 24 matching lines...) Expand all
2172 1472
2173 return true; 1473 return true;
2174 } 1474 }
2175 1475
2176 bool VaapiH264Decoder::ProcessSlice(H264SliceHeader* slice_hdr) { 1476 bool VaapiH264Decoder::ProcessSlice(H264SliceHeader* slice_hdr) {
2177 prev_frame_num_ = frame_num_; 1477 prev_frame_num_ = frame_num_;
2178 frame_num_ = slice_hdr->frame_num; 1478 frame_num_ = slice_hdr->frame_num;
2179 1479
2180 if (prev_frame_num_ > 0 && prev_frame_num_ < frame_num_ - 1) { 1480 if (prev_frame_num_ > 0 && prev_frame_num_ < frame_num_ - 1) {
2181 DVLOG(1) << "Gap in frame_num!"; 1481 DVLOG(1) << "Gap in frame_num!";
2182 ReportToUMA(GAPS_IN_FRAME_NUM); 1482 report_error_cb_.Run(GAPS_IN_FRAME_NUM);
2183 return false; 1483 return false;
2184 } 1484 }
2185 1485
2186 if (slice_hdr->field_pic_flag == 0) 1486 if (slice_hdr->field_pic_flag == 0)
2187 max_pic_num_ = max_frame_num_; 1487 max_pic_num_ = max_frame_num_;
2188 else 1488 else
2189 max_pic_num_ = 2 * max_frame_num_; 1489 max_pic_num_ = 2 * max_frame_num_;
2190 1490
2191 // TODO posciak: switch to new picture detection per 7.4.1.2.4. 1491 // 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) { 1492 if (curr_pic_ != NULL && slice_hdr->first_mb_in_slice != 0) {
(...skipping 17 matching lines...) Expand all
2210 state_ = kError; \ 1510 state_ = kError; \
2211 return VaapiH264Decoder::kDecodeError; \ 1511 return VaapiH264Decoder::kDecodeError; \
2212 } while (0) 1512 } while (0)
2213 1513
2214 VaapiH264Decoder::DecResult VaapiH264Decoder::DecodeInitial(int32 input_id) { 1514 VaapiH264Decoder::DecResult VaapiH264Decoder::DecodeInitial(int32 input_id) {
2215 // Decode enough to get required picture size (i.e. until we find an SPS), 1515 // 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. 1516 // if we get any slice data, we are missing the beginning of the stream.
2217 H264NALU nalu; 1517 H264NALU nalu;
2218 H264Parser::Result res; 1518 H264Parser::Result res;
2219 1519
2220 DCHECK_NE(state_, kUninitialized); 1520 if (state_ == kDecoding)
1521 return kReadyToDecode;
2221 1522
2222 curr_input_id_ = input_id; 1523 curr_input_id_ = input_id;
2223 1524
2224 while (1) { 1525 while (1) {
2225 if (state_ == kAfterReset && num_available_decode_surfaces_ == 0) { 1526 // If we've already decoded some of the stream (after reset), we may be able
1527 // to go into decoding state not only starting at/resuming from an SPS, but
1528 // also from other resume points, such as IDRs. In such a case we need an
1529 // output surface in case we end up decoding a frame. Otherwise we just look
1530 // for an SPS and don't need any outputs.
1531 if (curr_sps_id_ != -1 && available_va_surfaces_.empty()) {
2226 DVLOG(4) << "No output surfaces available"; 1532 DVLOG(4) << "No output surfaces available";
2227 return kNoOutputAvailable; 1533 return kNoOutputAvailable;
2228 } 1534 }
2229 1535
2230 // Get next NALU looking for SPS or IDR if after reset. 1536 // Get next NALU looking for SPS or IDR if after reset.
2231 res = parser_.AdvanceToNextNALU(&nalu); 1537 res = parser_.AdvanceToNextNALU(&nalu);
2232 if (res == H264Parser::kEOStream) { 1538 if (res == H264Parser::kEOStream) {
2233 DVLOG(1) << "Could not find SPS before EOS"; 1539 DVLOG(1) << "Could not find SPS before EOS";
2234 return kNeedMoreStreamData; 1540 return kNeedMoreStreamData;
2235 } else if (res != H264Parser::kOk) { 1541 } else if (res != H264Parser::kOk) {
2236 SET_ERROR_AND_RETURN(); 1542 SET_ERROR_AND_RETURN();
2237 } 1543 }
2238 1544
2239 DVLOG(4) << " NALU found: " << static_cast<int>(nalu.nal_unit_type); 1545 DVLOG(4) << " NALU found: " << static_cast<int>(nalu.nal_unit_type);
2240 1546
2241 switch (nalu.nal_unit_type) { 1547 switch (nalu.nal_unit_type) {
2242 case H264NALU::kSPS: 1548 case H264NALU::kSPS:
2243 res = parser_.ParseSPS(&curr_sps_id_); 1549 res = parser_.ParseSPS(&curr_sps_id_);
2244 if (res != H264Parser::kOk) 1550 if (res != H264Parser::kOk)
2245 SET_ERROR_AND_RETURN(); 1551 SET_ERROR_AND_RETURN();
2246 1552
2247 if (!ProcessSPS(curr_sps_id_)) 1553 if (!ProcessSPS(curr_sps_id_))
2248 SET_ERROR_AND_RETURN(); 1554 SET_ERROR_AND_RETURN();
2249 1555
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; 1556 state_ = kDecoding;
2257 return kReadyToDecode; 1557 return kReadyToDecode;
2258 1558
2259 case H264NALU::kIDRSlice: 1559 case H264NALU::kIDRSlice:
2260 // If after reset, should be able to recover from an IDR. 1560 // If after reset, should be able to recover from an IDR.
2261 if (state_ == kAfterReset) { 1561 // TODO(posciak): the IDR may require an SPS that we don't have
1562 // available. For now we'd fail if that happens, but ideally we'd like
1563 // to keep going until the next SPS in the stream.
1564 if (curr_sps_id_ != -1) {
2262 H264SliceHeader slice_hdr; 1565 H264SliceHeader slice_hdr;
2263 1566
2264 res = parser_.ParseSliceHeader(nalu, &slice_hdr); 1567 res = parser_.ParseSliceHeader(nalu, &slice_hdr);
2265 if (res != H264Parser::kOk) 1568 if (res != H264Parser::kOk)
2266 SET_ERROR_AND_RETURN(); 1569 SET_ERROR_AND_RETURN();
2267 1570
2268 if (!ProcessSlice(&slice_hdr)) 1571 if (!ProcessSlice(&slice_hdr))
2269 SET_ERROR_AND_RETURN(); 1572 SET_ERROR_AND_RETURN();
2270 1573
2271 state_ = kDecoding; 1574 state_ = kDecoding;
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
2306 DVLOG(1) << "Decoder not ready: error in stream or not initialized"; 1609 DVLOG(1) << "Decoder not ready: error in stream or not initialized";
2307 return kDecodeError; 1610 return kDecodeError;
2308 } 1611 }
2309 1612
2310 // All of the actions below might result in decoding a picture from 1613 // 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 1614 // previously parsed data, but we still have to handle/parse current input
2312 // first. 1615 // first.
2313 // Note: this may drop some already decoded frames if there are errors 1616 // Note: this may drop some already decoded frames if there are errors
2314 // further in the stream, but we are OK with that. 1617 // further in the stream, but we are OK with that.
2315 while (1) { 1618 while (1) {
2316 if (num_available_decode_surfaces_ == 0) { 1619 if (available_va_surfaces_.empty()) {
2317 DVLOG(4) << "No output surfaces available"; 1620 DVLOG(4) << "No output surfaces available";
2318 return kNoOutputAvailable; 1621 return kNoOutputAvailable;
2319 } 1622 }
1623
2320 par_res = parser_.AdvanceToNextNALU(&nalu); 1624 par_res = parser_.AdvanceToNextNALU(&nalu);
2321 if (par_res == H264Parser::kEOStream) 1625 if (par_res == H264Parser::kEOStream)
2322 return kNeedMoreStreamData; 1626 return kNeedMoreStreamData;
2323 else if (par_res != H264Parser::kOk) 1627 else if (par_res != H264Parser::kOk)
2324 SET_ERROR_AND_RETURN(); 1628 SET_ERROR_AND_RETURN();
2325 1629
2326 DVLOG(4) << "NALU found: " << static_cast<int>(nalu.nal_unit_type); 1630 DVLOG(4) << "NALU found: " << static_cast<int>(nalu.nal_unit_type);
2327 1631
2328 switch (nalu.nal_unit_type) { 1632 switch (nalu.nal_unit_type) {
2329 case H264NALU::kNonIDRSlice: 1633 case H264NALU::kNonIDRSlice:
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
2364 SET_ERROR_AND_RETURN(); 1668 SET_ERROR_AND_RETURN();
2365 1669
2366 if (!ProcessPPS(pps_id)) 1670 if (!ProcessPPS(pps_id))
2367 SET_ERROR_AND_RETURN(); 1671 SET_ERROR_AND_RETURN();
2368 break; 1672 break;
2369 1673
2370 default: 1674 default:
2371 // skip NALU 1675 // skip NALU
2372 break; 1676 break;
2373 } 1677 }
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 } 1678 }
2382 } 1679 }
2383 1680
2384 size_t VaapiH264Decoder::GetRequiredNumOfPictures() { 1681 size_t VaapiH264Decoder::GetRequiredNumOfPictures() {
2385 return dpb_.max_num_pics() + kPicsInPipeline; 1682 return dpb_.max_num_pics() + kPicsInPipeline;
2386 } 1683 }
2387 1684
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 1685 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698