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

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

Issue 9814001: Add VAVDA, the VAAPI Video Decode Accelerator for Intel CPUs. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 9 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "vaapi_h264_decoder.h"
6
7 #include <algorithm>
8 #include <dlfcn.h>
9
10 #include "base/bind.h"
11 #include "base/stl_util.h"
12 #include "third_party/libva/va/va.h"
13 #include "third_party/libva/va/va_x11.h"
14 #include "ui/gfx/gl/gl_bindings.h"
15
16 #define VA_SUCCESS_OR_ERROR(vares, err_msg) \
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 this name is confusing (why, yes, I'm sure we eith
Pawel Osciak 2012/03/21 18:40:35 Well, maybe I shouldn't have abbreviated it that m
Ami GONE FROM CHROMIUM 2012/03/22 17:01:36 I know; my problem with the name is that you're no
Pawel Osciak 2012/04/05 10:37:20 Done.
17 do { \
18 if ((vares) != VA_STATUS_SUCCESS) { \
19 DLOG(ERROR) << (err_msg); \
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 s/DLOG/DVLOG/ everywhere unless you have a reason
Pawel Osciak 2012/04/05 10:37:20 I thought this kind of failure was reason enough :
20 DLOG(ERROR) << "VA error: " << vaapi_vaErrorStr(vares); \
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 Can these be a single LOG?
Pawel Osciak 2012/04/05 10:37:20 Done.
21 } \
22 } while(0)
23
24 #define VA_SUCCESS_OR_RETURN(vares, err_msg, ret) \
25 do { \
26 if ((vares) != VA_STATUS_SUCCESS) { \
27 DLOG(ERROR) << (err_msg); \
28 DLOG(ERROR) << "VA error: " << vaapi_vaErrorStr(vares); \
29 return (ret); \
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 Don't most of these cases also want to set state_=
Pawel Osciak 2012/04/05 10:37:20 It will change state in higher layers, as this wil
30 } \
31 } while (0)
32
33 void *vaapi_handle = dlopen("libva.so", RTLD_NOW);
34 void *vaapi_x11_handle = dlopen("libva-x11.so", RTLD_NOW);
35 void *vaapi_glx_handle = dlopen("libva-glx.so", RTLD_NOW);
36
37 typedef VADisplay (*vaapiGetDisplayGLX)(Display *dpy);
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 Types need to be Capitalized (here and elsewhere)
Pawel Osciak 2012/04/05 10:37:20 Done.
38
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 remove the newlines between these typedefs?
Pawel Osciak 2012/04/05 10:37:20 Done.
39 typedef int (*vaapiDisplayIsValid)(VADisplay dpy);
40
41 typedef VAStatus (*vaapiInitialize)(VADisplay dpy,
42 int *major_version,
43 int *minor_version);
44
45 typedef VAStatus (*vaapiTerminate)(VADisplay dpy);
46
47 typedef VAStatus (*vaapiGetConfigAttributes)(VADisplay dpy,
48 VAProfile profile,
49 VAEntrypoint entrypoint,
50 VAConfigAttrib *attrib_list,
51 int num_attribs);
52
53 typedef VAStatus (*vaapiCreateConfig)(VADisplay dpy,
54 VAProfile profile,
55 VAEntrypoint entrypoint,
56 VAConfigAttrib *attrib_list,
57 int num_attribs,
58 VAConfigID *config_id);
59
60 typedef VAStatus (*vaapiDestroyConfig)(VADisplay dpy, VAConfigID config_id);
61
62 typedef VAStatus (*vaapiCreateSurfaces)(VADisplay dpy,
63 int width,
64 int height,
65 int format,
66 int num_surfaces,
67 VASurfaceID *surfaces);
68
69 typedef VAStatus (*vaapiDestroySurfaces)(VADisplay dpy,
70 VASurfaceID *surfaces,
71 int num_surfaces);
72
73 typedef VAStatus (*vaapiCreateContext)(VADisplay dpy,
74 VAConfigID config_id,
75 int picture_width,
76 int picture_height,
77 int flag,
78 VASurfaceID *render_targets,
79 int num_render_targets,
80 VAContextID *context);
81
82 typedef VAStatus (*vaapiDestroyContext)(VADisplay dpy, VAContextID context);
83
84 typedef VAStatus (*vaapiPutSurface)(VADisplay dpy,
85 VASurfaceID surface,
86 Drawable draw,
87 short srcx,
88 short srcy,
89 unsigned short srcw,
90 unsigned short srch,
91 short destx,
92 short desty,
93 unsigned short destw,
94 unsigned short desth,
95 VARectangle *cliprects,
96 unsigned int number_cliprects,
97 unsigned int flags);
98
99 typedef VAStatus (*vaapiSyncSurface)(VADisplay dpy, VASurfaceID render_target);
100
101 typedef VAStatus (*vaapiBeginPicture)(VADisplay dpy,
102 VAContextID context,
103 VASurfaceID render_target);
104
105 typedef VAStatus (*vaapiRenderPicture)(VADisplay dpy,
106 VAContextID context,
107 VABufferID *buffers,
108 int num_buffers);
109
110 typedef VAStatus (*vaapiEndPicture)(VADisplay dpy, VAContextID context);
111
112 typedef VAStatus (*vaapiCreateBuffer)(VADisplay dpy,
113 VAContextID context,
114 VABufferType type,
115 unsigned int size,
116 unsigned int num_elements,
117 void *data,
118 VABufferID *buf_id);
119
120 typedef const char* (*vaapiErrorStr)(VAStatus error_status);
121
122 vaapiGetDisplayGLX vaapi_vaGetDisplayGLX =
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 s/vaapi_vaGetDisplayGLX/VAAPI_GetDisplayGLX/ (and
Pawel Osciak 2012/04/05 10:37:20 I tried to keep the full vaapi function names in t
123 reinterpret_cast<vaapiGetDisplayGLX>(dlsym(vaapi_glx_handle,
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 does using a macro for this make sense?
Pawel Osciak 2012/04/05 10:37:20 Done.
124 "vaGetDisplayGLX"));
125
126 vaapiDisplayIsValid vaapi_vaDisplayIsValid =
127 reinterpret_cast<vaapiDisplayIsValid>(dlsym(vaapi_handle,
128 "vaDisplayIsValid"));
129
130 vaapiInitialize vaapi_vaInitialize =
131 reinterpret_cast<vaapiInitialize>(dlsym(vaapi_handle, "vaInitialize"));
132
133 vaapiTerminate vaapi_vaTerminate =
134 reinterpret_cast<vaapiTerminate>(dlsym(vaapi_handle, "vaTerminate"));
135
136 vaapiGetConfigAttributes vaapi_vaGetConfigAttributes =
137 reinterpret_cast<vaapiGetConfigAttributes>(dlsym(vaapi_handle,
138 "vaGetConfigAttributes"));
139
140 vaapiCreateConfig vaapi_vaCreateConfig =
141 reinterpret_cast<vaapiCreateConfig>(dlsym(vaapi_handle, "vaCreateConfig"));
142
143 vaapiDestroyConfig vaapi_vaDestroyConfig =
144 reinterpret_cast<vaapiDestroyConfig>(dlsym(vaapi_handle,
145 "vaDestroyConfig"));
146
147 vaapiCreateSurfaces vaapi_vaCreateSurfaces =
148 reinterpret_cast<vaapiCreateSurfaces>(dlsym(vaapi_handle,
149 "vaCreateSurfaces"));
150
151 vaapiDestroySurfaces vaapi_vaDestroySurfaces =
152 reinterpret_cast<vaapiDestroySurfaces>(dlsym(vaapi_handle,
153 "vaDestroySurfaces"));
154
155 vaapiCreateContext vaapi_vaCreateContext =
156 reinterpret_cast<vaapiCreateContext>(dlsym(vaapi_handle,
157 "vaCreateContext"));
158
159 vaapiDestroyContext vaapi_vaDestroyContext =
160 reinterpret_cast<vaapiDestroyContext>(dlsym(vaapi_handle,
161 "vaDestroyContext"));
162
163 vaapiPutSurface vaapi_vaPutSurface =
164 reinterpret_cast<vaapiPutSurface>(dlsym(vaapi_x11_handle, "vaPutSurface"));
165
166 vaapiSyncSurface vaapi_vaSyncSurface =
167 reinterpret_cast<vaapiSyncSurface>(dlsym(vaapi_x11_handle,
168 "vaSyncSurface"));
169
170 vaapiBeginPicture vaapi_vaBeginPicture =
171 reinterpret_cast<vaapiBeginPicture>(dlsym(vaapi_handle, "vaBeginPicture"));
172
173 vaapiRenderPicture vaapi_vaRenderPicture =
174 reinterpret_cast<vaapiRenderPicture>(dlsym(vaapi_handle,
175 "vaRenderPicture"));
176
177 vaapiEndPicture vaapi_vaEndPicture =
178 reinterpret_cast<vaapiEndPicture>(dlsym(vaapi_handle, "vaEndPicture"));
179
180 vaapiCreateBuffer vaapi_vaCreateBuffer =
181 reinterpret_cast<vaapiCreateBuffer>(dlsym(vaapi_handle, "vaCreateBuffer"));
182
183 vaapiErrorStr vaapi_vaErrorStr =
184 reinterpret_cast<vaapiErrorStr>(dlsym(vaapi_handle, "vaErrorStr"));
185
186 static bool AreVaapiFunctionPointersInitialized() {
187 return (vaapi_vaGetDisplayGLX
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 drop the parens?
Pawel Osciak 2012/04/05 10:37:20 Done.
188 && vaapi_vaDisplayIsValid
189 && vaapi_vaInitialize
190 && vaapi_vaTerminate
191 && vaapi_vaGetConfigAttributes
192 && vaapi_vaCreateConfig
193 && vaapi_vaDestroyConfig
194 && vaapi_vaCreateSurfaces
195 && vaapi_vaDestroySurfaces
196 && vaapi_vaCreateContext
197 && vaapi_vaDestroyContext
198 && vaapi_vaPutSurface
199 && vaapi_vaSyncSurface
200 && vaapi_vaBeginPicture
201 && vaapi_vaRenderPicture
202 && vaapi_vaEndPicture
203 && vaapi_vaCreateBuffer
204 && vaapi_vaErrorStr);
205 }
206
207 VaapiH264Decoder::VaapiH264Decoder() {
208 // Has to be before Reset() so it does not mark any surfaces as available.
209 num_assigned_vaapi_surfaces_ = 0;
210 Reset();
211 curr_sps_id_ = -1;
212 curr_pps_id_ = -1;
213 pic_width_ = -1;
214 pic_height_ = -1;
215 MaxFrameNum_ = 0;
216 MaxPicNum_ = 0;
217 MaxLongTermFrameIdx_ = 0;
218 MaxPicOrderCntLsb_ = 0;
219 state_ = kUninitialized;
220 }
221
222 VaapiH264Decoder::~VaapiH264Decoder() {
223 Destroy();
224 }
225
226 // This puts the decoder in state where it keeps stream data and is ready
227 // to resume playback from a random location in the stream, but drops all
228 // inputs and outputs and makes all surfaces available for use.
229 void VaapiH264Decoder::Reset() {
230 frame_decoded_ = false;
231
232 curr_pic_.reset();
233
234 frame_num_ = 0;
235 prev_frame_num_ = -1;
236
237 prev_ref_has_memmgmnt5_ = false;
238 prev_ref_TopFieldOrderCnt_ = -1;
239 prev_ref_PicOrderCntMsb_ = -1;
240 prev_ref_pic_order_cnt_lsb_ = -1;
241 prev_ref_field_ = H264Picture::FIELD_NONE;
242
243 pending_slice_bufs_ = std::queue<VABufferID>();
244 pending_va_bufs_ = std::queue<VABufferID>();
245
246 RefPicList0_.clear();
247 RefPicList1_.clear();
248
249 poc_to_decode_surfaces_.clear();
250
251 for (DecodeSurfaces::iterator iter = decode_surfaces_.begin();
252 iter != decode_surfaces_.end(); ++iter)
253 iter->second->available = true;
254 num_available_decode_surfaces_ = num_assigned_vaapi_surfaces_;
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 if you s/num_assigned_vaapi_surfaces_/decode_surfa
Pawel Osciak 2012/04/05 10:37:20 Yeah, good idea. Done.
255
256 dpb_.Clear();
257 parser_.Reset();
258
259 // Still initialized and ready to decode
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 this is a lie during the call from the ctor
Pawel Osciak 2012/03/21 18:40:35 But ctor changes it back... I was thinking of sepa
Ami GONE FROM CHROMIUM 2012/03/22 17:01:36 I think your instinct to avoid duplication was cor
Pawel Osciak 2012/04/05 10:37:20 Done.
260 state_ = kAfterReset;
261 }
262
263 void VaapiH264Decoder::Destroy() {
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 early-return if state_==kUninitialized ?
Pawel Osciak 2012/04/05 10:37:20 Done.
264 VAStatus va_status;
265
266 Reset();
267
268 switch (state_) {
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 Reset() just set state_; why is this switch necess
Pawel Osciak 2012/03/21 18:40:35 In case we call it without Reset()?
Ami GONE FROM CHROMIUM 2012/03/22 17:01:36 You unconditionally call Reset() two lines up, tho
Pawel Osciak 2012/04/05 10:37:20 Uh... not sure how it got there, thanks for spotti
269 case kDecoding:
270 case kAfterReset:
271 case kError:
272 DecodeSurface::Destroy();
273 DestroyVASurfaces();
274 // fallthrough
275 case kInitialized:
276 va_status = vaapi_vaDestroyConfig(va_display_, va_config_id_);
277 VA_SUCCESS_OR_ERROR(va_status, "vaDestroyConfig failed");
278 va_status = vaapi_vaTerminate(va_display_);
279 VA_SUCCESS_OR_ERROR(va_status, "vaTerminate failed");
280 // fallthrough
281 case kUninitialized:
282 break;
283
284 default:
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 better to drop default: and let the compiler yell
Pawel Osciak 2012/04/05 10:37:20 Done.
285 NOTREACHED();
286 }
287
288 state_ = kUninitialized;
289 }
290
291 bool VaapiH264Decoder::HasHWSupport() {
292 return AreVaapiFunctionPointersInitialized();
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 This doesn't check HW support, only presence of li
Pawel Osciak 2012/04/05 10:37:20 Done.
293 }
294
295 // Maps Profile enum values to VaProfile values.
296 bool VaapiH264Decoder::SetProfile(media::VideoCodecProfile profile) {
297 switch (profile) {
298 case media::H264PROFILE_BASELINE:
299 profile_ = VAProfileH264Baseline;
300 break;
301 case media::H264PROFILE_MAIN:
302 profile_ = VAProfileH264Main;
303 break;
304 case media::H264PROFILE_HIGH:
305 profile_ = VAProfileH264High;
306 break;
307 default:
308 DLOG(INFO) << "Unsupported profile: " << profile;
309 return false;
310 }
311
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 extra \n
Pawel Osciak 2012/04/05 10:37:20 Done.
312 return true;
313 }
314
315 // Has to be run in GLXContext thread
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 replace this comment (and others like it) with DCH
Pawel Osciak 2012/04/05 10:37:20 This is information for the caller, I don't know w
316 bool VaapiH264Decoder::Initialize(media::VideoCodecProfile profile,
317 Display* x_display,
318 GLXContext glx_context,
319 MessageLoop* msg_loop,
320 OutputPicCallbackPtr output_pic_callback,
321 void *arg) {
322 VAStatus va_res;
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 first use is at l.349; move this there.
Pawel Osciak 2012/04/05 10:37:20 Done.
323 DCHECK_EQ(state_, kUninitialized);
324
325 msg_loop_ = msg_loop;
326 output_pic_callback_ = output_pic_callback;
327 output_pic_callback_arg_ = arg;
328
329 x_display_ = x_display;
330 parent_glx_context_ = glx_context;
331
332 if (!SetProfile(profile)) {
333 DLOG(INFO) << "Unsupported profile";
334 return false;
335 }
336
337 if (!HasHWSupport()) {
338 DLOG(ERROR) << "Hardware not supported or could not load libva";
339 return false;
340 }
341
342 va_display_ = vaapi_vaGetDisplayGLX(x_display_);
343 if (!vaapi_vaDisplayIsValid(va_display_)) {
344 DLOG(ERROR) << "Could not get a valid VA display";
345 return false;
346 }
347
348 int major_version, minor_version;
349 va_res = vaapi_vaInitialize(va_display_, &major_version, &minor_version);
350 VA_SUCCESS_OR_RETURN(va_res, "vaInitialize failed", false);
351 DVLOG(1) << "VAAPI version: " << major_version << "." << minor_version;
352
353 VAConfigAttrib attrib;
354 attrib.type = VAConfigAttribRTFormat;
355
356 VAEntrypoint entrypoint = VAEntrypointVLD;
357 va_res = vaapi_vaGetConfigAttributes(va_display_, profile_, entrypoint,
358 &attrib, 1);
359 VA_SUCCESS_OR_RETURN(va_res, "vaGetConfigAttributes failed", false);
360
361 if (!(attrib.value & VA_RT_FORMAT_YUV420)) {
362 DLOG(INFO) << "YUV420 not supported";
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 s/DLOG/DVLOG/ s/INFO/ERROR/
Pawel Osciak 2012/04/05 10:37:20 My understanding was *VLOGs were associated with n
Ami GONE FROM CHROMIUM 2012/04/09 21:35:53 Sorry, my comment was cryptic. Indeed, *VLOG must
363 return false;
364 }
365
366 va_res = vaapi_vaCreateConfig(va_display_, profile_, entrypoint,
367 &attrib, 1, &va_config_id_);
368 VA_SUCCESS_OR_RETURN(va_res, "vaCreateConfig failed", false);
369
370 if (!DecodeSurface::Initialize(x_display_)) {
371 DLOG(ERROR) << "Could not get a usable FBConfig";
372 return false;
373 }
374
375 state_ = kInitialized;
376
377 return true;
378 }
379
380 VaapiH264Decoder::DecodeSurface::DecodeSurface()
381 : available(false)
382 {}
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 opening brace belongs on previous line
Pawel Osciak 2012/04/05 10:37:20 Done.
383
384 VaapiH264Decoder::DecodeSurface::~DecodeSurface() {
385 UnbindFromTexture();
386 }
387
388 // static
389 bool VaapiH264Decoder::DecodeSurface::Initialize(Display* x_display) {
390 const int fbconfig_attr[] = {
391 GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
392 GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
393 GLX_BIND_TO_TEXTURE_RGB_EXT, GL_TRUE,
394 GLX_Y_INVERTED_EXT, GL_TRUE,
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 what's this about?
Pawel Osciak 2012/04/05 10:37:20 Asking for a framebuffer config with origin at top
395 GL_NONE,
396 };
397
398 DCHECK(x_display);
399 x_display_ = x_display;
400
401 int num_fbconfigs;
402 GLXFBConfig* glx_fb_configs = glXChooseFBConfig(x_display_,
403 DefaultScreen(x_display_), fbconfig_attr, &num_fbconfigs);
404 if (!glx_fb_configs)
405 return false;
406
407 fb_config_.Get() = glx_fb_configs[0];
408
409 return true;
410 }
411
412 // static
413 void VaapiH264Decoder::DecodeSurface::Destroy() {
414 if (fb_config_.Get())
415 free(fb_config_.Get());
416 }
417
418
419 static int x11_error = 0;
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 Oh my. X11 error handling is tricky tricky busines
Pawel Osciak 2012/04/05 10:37:20 Well, I was restoring them after use ;)
420 static int (*old_error_handler)(Display *, XErrorEvent *);
421
422 static int X11ErrorHandler(Display *dpy, XErrorEvent *e) {
423 char buf[512];
424 LOG(ERROR) << "X11 error: " << (unsigned int)(e->error_code)
425 << " on display: " << dpy;
426 XGetErrorText(dpy, e->error_code, buf, 512);
427 LOG(ERROR) << "Error text: " << buf;
428 return 0;
429 }
430
431 static void TrapX11Errors() {
432 x11_error = 0;
433 old_error_handler = XSetErrorHandler(X11ErrorHandler);
434 }
435
436 static void UntrapX11Errors() {
437 XSetErrorHandler(old_error_handler);
438 }
439
440 // Must be run on the GLX thread.
441 bool VaapiH264Decoder::DecodeSurface::BindToTexture(int width, int height) {
442 TrapX11Errors();
443
444 glEnable(GL_TEXTURE_2D);
445 glBindTexture(GL_TEXTURE_2D, texture_id);
446 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
447 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
448
449 XWindowAttributes win_attr;
450 int screen = DefaultScreen(x_display_);
451 XGetWindowAttributes(x_display_, RootWindow(x_display_, screen), &win_attr);
452 x_pixmap = XCreatePixmap(x_display_, RootWindow(x_display_, screen),
453 width, height, win_attr.depth);
454 if (!x_pixmap) {
455 DLOG(ERROR) << "Failed creating an X Pixmap for TFP";
456 return false;
457 }
458
459 DCHECK(fb_config_.Get());
460
461 static const int pixmap_attr[] = {
462 GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
463 GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT,
464 GL_NONE,
465 };
466
467 glx_pixmap = glXCreatePixmap(x_display_, fb_config_.Get(), x_pixmap,
468 pixmap_attr);
469
470 glBindTexture(GL_TEXTURE_2D, texture_id);
471 glXBindTexImageEXT(x_display_, glx_pixmap, GLX_FRONT_LEFT_EXT, NULL);
472 // TODO posciak: verify whether needed
473 XSync(x_display_, False);
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 I don't think it's ok to have XSync's without docu
Pawel Osciak 2012/03/21 18:40:35 Yes, this will not be here in the final version, j
Pawel Osciak 2012/04/05 10:37:20 Done.
474
475 UntrapX11Errors();
476 return true;
477 }
478
479 // Must be run on the GLX thread.
480 void VaapiH264Decoder::DecodeSurface::UnbindFromTexture() {
481 TrapX11Errors();
482
483 glXReleaseTexImageEXT(x_display_, glx_pixmap, GLX_FRONT_LEFT_EXT);
484 // TODO posciak: verify whether needed
485 XSync(x_display_, False);
486 glXDestroyGLXPixmap(x_display_, glx_pixmap);
487 XFreePixmap(x_display_, x_pixmap);
488
489 UntrapX11Errors();
490 }
491
492 // Must be run on decoder thread
493 void VaapiH264Decoder::ReusePictureBuffer(int32 picture_buffer_id) {
494 DecodeSurfaces::iterator it = decode_surfaces_.find(picture_buffer_id);
495 if (it == decode_surfaces_.end()) {
496 DLOG(ERROR) << "Asked to reuse an invalid buffer";
497 return;
498 }
499
500 UnassignSurfaceFromPoC(it->second->poc);
501 }
502
503 // Must be run in GLXContext thread.
504 bool VaapiH264Decoder::AssignPictureBuffer(int32 picture_buffer_id,
505 uint32 texture_id) {
506 scoped_ptr<DecodeSurface> dec_surface(new DecodeSurface());
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 s/scoped/linked/
Pawel Osciak 2012/04/05 10:37:20 Done.
507
508 DCHECK_EQ(state_, kDecoding);
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 how can you be sure? What if an error occurred bu
Pawel Osciak 2012/03/21 18:40:35 There can be no threading here yet.
Ami GONE FROM CHROMIUM 2012/03/22 17:01:36 But a previously-failed APB() could have set error
Pawel Osciak 2012/04/05 10:37:20 Yes, I ignore it, but I don't see too much of a pr
509
510 if (num_assigned_vaapi_surfaces_ >= GetRequiredNumOfPictures()) {
511 DLOG(ERROR) << "Got more surfaces than required";
512 return false;
513 }
514
515 // This will not work if we start using VDA.DismissPicture()
516 dec_surface->va_surface_id = va_surface_ids_[num_assigned_vaapi_surfaces_++];
517 dec_surface->picture_buffer_id = picture_buffer_id;
518 dec_surface->texture_id = texture_id;
519
520 DVLOG(2) << "New picture assigned, texid: " << dec_surface->texture_id
521 << "va display: " << va_display_;
522
523 if (!dec_surface->BindToTexture(pic_width_, pic_height_)) {
524 DLOG(ERROR) << "Error binding VASurface to a texture";
525 return false;
526 }
527
528 dec_surface->available = true;
529 ++num_available_decode_surfaces_;
530
531 DVLOG(2) << "Pic buf id: " << dec_surface->picture_buffer_id
532 << " will use va surface " << dec_surface->va_surface_id
533 << ", texture id: " << dec_surface->texture_id;
534
535 bool inserted = decode_surfaces_.insert(std::make_pair(picture_buffer_id,
536 make_linked_ptr(dec_surface.release()))).second;
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 indent is wrong (and make_linked_ptr/release shoul
Pawel Osciak 2012/04/05 10:37:20 Done.
537 DCHECK(inserted);
538
539 return true;
540 }
541
542 bool VaapiH264Decoder::CreateVASurfaces() {
543 DCHECK_NE(pic_width_, -1);
544 DCHECK_NE(pic_height_, -1);
545 DCHECK_EQ(state_, kInitialized);
546
547 // Allocate VASurfaces in driver.
548 VAStatus va_res = vaapi_vaCreateSurfaces(va_display_, pic_width_,
549 pic_height_, VA_RT_FORMAT_YUV420,
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 indentation here and elsewhere is off. please mak
Pawel Osciak 2012/03/21 18:40:35 Chromium coding style says "do whatever seems most
Ami GONE FROM CHROMIUM 2012/03/22 17:01:36 Umm, yeah, no. ;) Your choices are blah(foo
Pawel Osciak 2012/04/05 10:37:20 Done.
550 GetRequiredNumOfPictures(), va_surface_ids_);
551 VA_SUCCESS_OR_RETURN(va_res, "vaCreateSurfaces failed", false);
552
553 // How many VA Surfaces are assigned/bound to output pictures.
554 num_assigned_vaapi_surfaces_ = 0;
555
556 // And create a context associated with them.
557 va_res = vaapi_vaCreateContext(va_display_, va_config_id_,
558 pic_width_, pic_height_, VA_PROGRESSIVE,
559 va_surface_ids_, GetRequiredNumOfPictures(),
560 &va_context_id_);
561 VA_SUCCESS_OR_RETURN(va_res, "vaCreateContext failed", false);
562
563 return true;
564 }
565
566 void VaapiH264Decoder::DestroyVASurfaces() {
567 VAStatus va_status;
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 please standardize on a single name for this throu
Pawel Osciak 2012/04/05 10:37:20 Done.
568 DCHECK(state_ == kDecoding || state_ == kError || state_ == kAfterReset);
569
570 decode_surfaces_.clear();
571
572 va_status = vaapi_vaDestroyContext(va_display_, va_context_id_);
573 VA_SUCCESS_OR_ERROR(va_status, "vaDestroyContext failed");
574
575 va_status = vaapi_vaDestroySurfaces(va_display_, va_surface_ids_,
576 GetRequiredNumOfPictures());
577 VA_SUCCESS_OR_ERROR(va_status, "vaDestroyContext failed");
578 }
579
580 void VaapiH264Decoder::FillVAPicture(VAPictureH264 *va_pic, H264Picture* pic) {
581 va_pic->picture_id =
582 poc_to_decode_surfaces_[pic->PicOrderCnt]->va_surface_id;
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 operator[] will add a NULL pointer if the index is
Pawel Osciak 2012/04/05 10:37:20 Done.
583 DCHECK(va_pic->picture_id);
584
585 va_pic->frame_idx = pic->frame_num;
586 va_pic->flags = 0;
587
588 switch (pic->field) {
589 case H264Picture::FIELD_NONE:
590 break;
591 case H264Picture::FIELD_TOP:
592 va_pic->flags |= VA_PICTURE_H264_TOP_FIELD;
593 break;
594 case H264Picture::FIELD_BOTTOM:
595 va_pic->flags |= VA_PICTURE_H264_BOTTOM_FIELD;
596 break;
597 default:
598 NOTREACHED();
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 drop default: clause.
Pawel Osciak 2012/04/05 10:37:20 Done.
599 }
600
601 if (pic->ref)
602 va_pic->flags |= pic->long_term ? VA_PICTURE_H264_LONG_TERM_REFERENCE
603 : VA_PICTURE_H264_SHORT_TERM_REFERENCE;
604
605 va_pic->TopFieldOrderCnt = pic->TopFieldOrderCnt;
606 va_pic->BottomFieldOrderCnt = pic->BottomFieldOrderCnt;
607 }
608
609 int VaapiH264Decoder::FillVARefFramesFromDPB(VAPictureH264 *va_pics) {
610 PicsVector::reverse_iterator rit;
611 int i;
612
613 // Return reference frames in reverse order of insertion
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 what's the reverse order about?
Pawel Osciak 2012/03/21 18:40:35 vaapi documentation is nonexistent, literally (wel
Ami GONE FROM CHROMIUM 2012/03/22 17:01:36 When you have code that even you don't understand
Pawel Osciak 2012/04/05 10:37:20 Done.
614 for (rit = dpb_.rbegin(), i = 0; rit != dpb_.rend() && i < 16; ++rit)
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 s/16/kSomething/
Pawel Osciak 2012/04/05 10:37:20 16 is actually hardcoded in libva.h... I should've
615 if ((*rit)->ref)
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 multi-line for bodies require braces. here & elsew
Pawel Osciak 2012/04/05 10:37:20 Done.
616 FillVAPicture(&va_pics[i++], *rit);
617
618 return i;
619 }
620
621 // Can only be called when all surfaces are already bound
622 // to textures (cannot be run at the same time as AssignPictureBuffer).
623 bool VaapiH264Decoder::AssignSurfaceToPoC(int poc) {
624 // Find a surface not currently holding data used for reference and/or
625 // to be displayed and mark it as used.
626 DecodeSurfaces::iterator iter = decode_surfaces_.begin();
627 for (; iter != decode_surfaces_.end(); ++iter) {
628 if (iter->second->available) {
629 iter->second->available = false;
630 --num_available_decode_surfaces_;
631 DCHECK_GE(num_available_decode_surfaces_, 0);
632 break;
633 }
634 }
635
636 if (iter == decode_surfaces_.end())
637 return false;
638
639 // Assign the current input_id to it, to be used when returning to client.
640 iter->second->input_id = curr_input_id_;
641 iter->second->poc = poc;
642 poc_to_decode_surfaces_[poc] = iter->second.get();
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 not worried about overwriting a previous value? (
Pawel Osciak 2012/03/21 18:40:35 Not that much, because I checked for ->available =
643 DVLOG(4) << "Will use surface "
644 << poc_to_decode_surfaces_[poc]->va_surface_id
645 << " for POC " << poc << " input ID: " << iter->second->input_id;
646
647 return true;
648 }
649
650 // Can only be called when all surfaces are already bound
651 // to textures (cannot be run at the same time as AssignPictureBuffer).
652 void VaapiH264Decoder::UnassignSurfaceFromPoC(int poc) {
653 POCToDecodeSurfaces::iterator it = poc_to_decode_surfaces_.find(poc);
654 /*DCHECK(it != poc_to_decode_surfaces_.end());*/
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 drop?
Pawel Osciak 2012/04/05 10:37:20 Done.
655
656 DVLOG(4) << "POC " << poc << "no longer using surface "
657 << it->second->va_surface_id;
658 it->second->available = true;
659 poc_to_decode_surfaces_.erase(it);
660
661 ++num_available_decode_surfaces_;
662 }
663
664 // Fill VAPictureH264 with default/neutral values.
665 static void InitVAPicture(VAPictureH264* va_pic) {
666 memset(va_pic, 0, sizeof(*va_pic));
667 va_pic->picture_id = 0xffffffff;
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 kuint32max? (but why set it to this?)
Pawel Osciak 2012/03/21 18:40:35 Again, not documented, but empirical from what oth
668 va_pic->flags = VA_PICTURE_H264_INVALID;
669 }
670
671 // Fill a VAPictureParameterBufferH264 to be later sent to the HW decoder.
672 bool VaapiH264Decoder::SendPPS() {
673 VAPictureParameterBufferH264 pic_param;
674 VABufferID pic_param_buf_id;
675
676 H264PPS* pps = parser_.GetPPS(curr_pps_id_);
677 DCHECK(pps);
678
679 H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id);
680 DCHECK(sps);
681
682 DCHECK(curr_pic_.get());
683
684 memset(&pic_param, 0, sizeof(VAPictureParameterBufferH264));
685
686 pic_param.picture_width_in_mbs_minus1 = sps->pic_width_in_mbs_minus1;
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 I'm weeping over here over the amount of text invo
Pawel Osciak 2012/03/21 18:40:35 I've been weeping too :( Unfortunately, some varia
Ami GONE FROM CHROMIUM 2012/03/22 17:01:36 Can the parser not populate as much as it can and
Pawel Osciak 2012/04/05 10:37:20 Done.
687 // This assumes non-interlaced video
688 pic_param.picture_height_in_mbs_minus1 = sps->pic_height_in_map_units_minus1;
689 pic_param.bit_depth_luma_minus8 = sps->bit_depth_luma_minus8;
690 pic_param.bit_depth_chroma_minus8 = sps->bit_depth_chroma_minus8;
691
692 pic_param.seq_fields.bits.chroma_format_idc = sps->chroma_format_idc;
693 pic_param.seq_fields.bits.residual_colour_transform_flag =
694 sps->separate_colour_plane_flag;
695 pic_param.seq_fields.bits.gaps_in_frame_num_value_allowed_flag =
696 sps->gaps_in_frame_num_value_allowed_flag;
697 pic_param.seq_fields.bits.frame_mbs_only_flag =
698 sps->frame_mbs_only_flag;
699 pic_param.seq_fields.bits.mb_adaptive_frame_field_flag =
700 sps->mb_adaptive_frame_field_flag;
701 pic_param.seq_fields.bits.direct_8x8_inference_flag =
702 sps->direct_8x8_inference_flag;
703 pic_param.seq_fields.bits.MinLumaBiPredSize8x8 =
704 (sps->level_idc >= 31);
705 pic_param.seq_fields.bits.log2_max_frame_num_minus4 =
706 sps->log2_max_frame_num_minus4;
707 pic_param.seq_fields.bits.pic_order_cnt_type =
708 sps->pic_order_cnt_type;
709 pic_param.seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 =
710 sps->log2_max_pic_order_cnt_lsb_minus4;
711 pic_param.seq_fields.bits.delta_pic_order_always_zero_flag =
712 sps->delta_pic_order_always_zero_flag;
713
714 pic_param.num_slice_groups_minus1 = pps->num_slice_groups_minus1;
715 pic_param.slice_group_map_type = 0;
716 pic_param.slice_group_change_rate_minus1 = 0;
717 pic_param.pic_init_qp_minus26 = pps->pic_init_qp_minus26;
718 pic_param.pic_init_qs_minus26 = pps->pic_init_qs_minus26;
719 pic_param.chroma_qp_index_offset = pps->chroma_qp_index_offset;
720 pic_param.second_chroma_qp_index_offset =
721 pps->second_chroma_qp_index_offset;
722
723 pic_param.pic_fields.bits.entropy_coding_mode_flag =
724 pps->entropy_coding_mode_flag;
725 pic_param.pic_fields.bits.weighted_pred_flag = pps->weighted_pred_flag;
726 pic_param.pic_fields.bits.weighted_bipred_idc = pps->weighted_bipred_idc;
727 pic_param.pic_fields.bits.transform_8x8_mode_flag =
728 pps->transform_8x8_mode_flag;
729
730 pic_param.pic_fields.bits.field_pic_flag = 0;
731 pic_param.pic_fields.bits.constrained_intra_pred_flag =
732 pps->constrained_intra_pred_flag;
733 pic_param.pic_fields.bits.pic_order_present_flag =
734 pps->bottom_field_pic_order_in_frame_present_flag;
735 pic_param.pic_fields.bits.deblocking_filter_control_present_flag =
736 pps->deblocking_filter_control_present_flag;
737 pic_param.pic_fields.bits.redundant_pic_cnt_present_flag =
738 pps->redundant_pic_cnt_present_flag;
739 pic_param.pic_fields.bits.reference_pic_flag = curr_pic_->ref;
740
741 pic_param.frame_num = curr_pic_->frame_num;
742
743 InitVAPicture(&pic_param.CurrPic);
744 FillVAPicture(&pic_param.CurrPic, curr_pic_.get());
745
746 // Init reference pictures' array.
747 for (int i = 0; i < 16; ++i)
748 InitVAPicture(&pic_param.ReferenceFrames[i]);
749
750 // And fill it with picture info from DPB.
751 FillVARefFramesFromDPB(pic_param.ReferenceFrames);
752
753 pic_param.num_ref_frames = sps->max_num_ref_frames;
754
755 // Allocate a buffer in driver for this parameter buffer and upload data.
756 VAStatus va_status = vaapi_vaCreateBuffer(va_display_, va_context_id_,
757 VAPictureParameterBufferType, sizeof(VAPictureParameterBufferH264),
758 1, &pic_param, &pic_param_buf_id);
759 VA_SUCCESS_OR_RETURN(va_status, "Failed to create a buffer for PPS", false);
760
761 // Queue its VA buffer ID to be committed on HW decode run.
762 pending_va_bufs_.push(pic_param_buf_id);
763
764 return true;
765 }
766
767 // Fill a VAIQMatrixBufferH264 to be later sent to the HW decoder.
768 bool VaapiH264Decoder::SendIQMatrix() {
769 VAIQMatrixBufferH264 iq_matrix_buf;
770 VABufferID iq_matrix_buf_id;
771 int i, j;
772
773 H264PPS* pps = parser_.GetPPS(curr_pps_id_);
774 DCHECK(pps);
775
776 memset(&iq_matrix_buf, 0, sizeof(VAIQMatrixBufferH264));
777
778 if (pps->pic_scaling_matrix_present_flag) {
779 for (i = 0; i < 6; ++i)
780 for (j = 0; j < 16; ++j)
781 iq_matrix_buf.ScalingList4x4[i][j] = pps->scaling_list4x4[i][j];
782
783 for (i = 0; i < 2; ++i)
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 I'm surprised by the '2' here and at l.793, expect
Pawel Osciak 2012/03/21 18:40:35 Yes, I was surprised with this asymmetry as well o
Ami GONE FROM CHROMIUM 2012/03/22 17:01:36 Are the other 4 rows left untouched??
Pawel Osciak 2012/04/05 10:37:20 VAIQMatrixBufferH264.ScalingList8x8 (the one in va
784 for (j = 0; j < 64; ++j)
785 iq_matrix_buf.ScalingList8x8[i][j] = pps->scaling_list8x8[i][j];
786 } else {
787 H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id);
788 DCHECK(sps);
789 for (i = 0; i < 6; ++i)
790 for (j = 0; j < 16; ++j)
791 iq_matrix_buf.ScalingList4x4[i][j] = sps->scaling_list4x4[i][j];
792
793 for (i = 0; i < 2; ++i)
794 for (j = 0; j < 64; ++j)
795 iq_matrix_buf.ScalingList8x8[i][j] = sps->scaling_list8x8[i][j];
796 }
797
798 // Allocate a buffer in driver for this parameter buffer and upload data.
799 VAStatus va_status = vaapi_vaCreateBuffer(va_display_, va_context_id_,
800 VAIQMatrixBufferType, sizeof(VAIQMatrixBufferH264), 1,
801 &iq_matrix_buf, &iq_matrix_buf_id);
802 VA_SUCCESS_OR_RETURN(va_status, "Failed to create a buffer for IQMatrix",
803 false);
804
805 // Queue its VA buffer ID to be committed on HW decode run.
806 pending_va_bufs_.push(iq_matrix_buf_id);
807
808 return true;
809 }
810
811 bool VaapiH264Decoder::SendVASliceParam(H264SliceHeader* slice_hdr) {
812 VASliceParameterBufferH264 slice_param;
813 VABufferID slice_param_buf_id;
814 VAStatus va_status;
815 int i;
816
817 H264PPS* pps = parser_.GetPPS(slice_hdr->pic_parameter_set_id);
818 DCHECK(pps);
819
820 H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id);
821 DCHECK(sps);
822
823 memset(&slice_param, 0, sizeof(VASliceParameterBufferH264));
824
825 slice_param.slice_data_size = slice_hdr->nalu_size;
826 slice_param.slice_data_offset = 0;
827 slice_param.slice_data_flag = VA_SLICE_DATA_FLAG_ALL;
828 slice_param.slice_data_bit_offset = slice_hdr->header_bit_size;
829
830 slice_param.first_mb_in_slice = slice_hdr->first_mb_in_slice;
831 slice_param.slice_type = slice_hdr->slice_type % 5;
832 slice_param.direct_spatial_mv_pred_flag =
833 slice_hdr->direct_spatial_mv_pred_flag;
834
835 // TODO posciak: make sure parser sets those even when override flags
836 // in slice header is off.
837 slice_param.num_ref_idx_l0_active_minus1 =
838 slice_hdr->num_ref_idx_l0_active_minus1;
839 slice_param.num_ref_idx_l1_active_minus1 =
840 slice_hdr->num_ref_idx_l1_active_minus1;
841 slice_param.cabac_init_idc = slice_hdr->cabac_init_idc;
842
843 slice_param.slice_qp_delta = slice_hdr->slice_qp_delta;
844 slice_param.disable_deblocking_filter_idc =
845 slice_hdr->disable_deblocking_filter_idc;
846
847 slice_param.slice_alpha_c0_offset_div2 =
848 slice_hdr->slice_alpha_c0_offset_div2;
849 slice_param.slice_beta_offset_div2 = slice_hdr->slice_beta_offset_div2;
850
851 if (((IsH264PSlice(slice_hdr) || IsH264SPSlice(slice_hdr))
852 && pps->weighted_pred_flag)
853 || (IsH264BSlice(slice_hdr) && pps->weighted_bipred_idc == 1)) {
854 slice_param.luma_log2_weight_denom = slice_hdr->luma_log2_weight_denom;
855 slice_param.chroma_log2_weight_denom = slice_hdr->chroma_log2_weight_denom;
856
857 slice_param.luma_weight_l0_flag = slice_hdr->luma_weight_l0_flag;
858 slice_param.luma_weight_l1_flag = slice_hdr->luma_weight_l1_flag;
859
860 slice_param.chroma_weight_l0_flag = slice_hdr->chroma_weight_l0_flag;
861 slice_param.chroma_weight_l1_flag = slice_hdr->chroma_weight_l1_flag;
862
863 for (i = 0; i <= slice_param.num_ref_idx_l0_active_minus1; ++i) {
864 slice_param.luma_weight_l0[i] =
865 slice_hdr->pred_weight_table_l0.luma_weight[i];
866 slice_param.luma_offset_l0[i] =
867 slice_hdr->pred_weight_table_l0.luma_offset[i];
868 }
869
870 for (i = 0; i <= slice_param.num_ref_idx_l0_active_minus1; ++i) {
871 slice_param.chroma_weight_l0[i][0] =
872 slice_hdr->pred_weight_table_l0.chroma_weight[i][0];
873 slice_param.chroma_weight_l0[i][1] =
874 slice_hdr->pred_weight_table_l0.chroma_weight[i][1];
875 slice_param.chroma_offset_l0[i][0] =
876 slice_hdr->pred_weight_table_l0.chroma_offset[i][0];
877 slice_param.chroma_offset_l0[i][1] =
878 slice_hdr->pred_weight_table_l0.chroma_offset[i][1];
879 }
880
881 if (IsH264BSlice(slice_hdr)) {
882 for (i = 0; i <= slice_param.num_ref_idx_l1_active_minus1; ++i) {
883 slice_param.luma_weight_l1[i] =
884 slice_hdr->pred_weight_table_l1.luma_weight[i];
885 slice_param.luma_offset_l1[i] =
886 slice_hdr->pred_weight_table_l1.luma_offset[i];
887 }
888
889 for (i = 0; i <= slice_param.num_ref_idx_l1_active_minus1; ++i) {
890 slice_param.chroma_weight_l1[i][0] =
891 slice_hdr->pred_weight_table_l1.chroma_weight[i][0];
892 slice_param.chroma_weight_l1[i][1] =
893 slice_hdr->pred_weight_table_l1.chroma_weight[i][1];
894 slice_param.chroma_offset_l1[i][0] =
895 slice_hdr->pred_weight_table_l1.chroma_offset[i][0];
896 slice_param.chroma_offset_l1[i][1] =
897 slice_hdr->pred_weight_table_l1.chroma_offset[i][1];
898 }
899 }
900 }
901
902 for (i = 0; i < 32; ++i) {
903 InitVAPicture(&slice_param.RefPicList0[i]);
904 InitVAPicture(&slice_param.RefPicList1[i]);
905 }
906
907 PicsVector::iterator it;
908 for (it = RefPicList0_.begin(), i = 0; it != RefPicList0_.end(); ++it, ++i)
909 FillVAPicture(&slice_param.RefPicList0[i], *it);
910
911 for (it = RefPicList1_.begin(), i = 0; it != RefPicList1_.end(); ++it, ++i)
912 FillVAPicture(&slice_param.RefPicList1[i], *it);
913
914 // Allocate a buffer in driver for this parameter buffer and upload data.
915 va_status = vaapi_vaCreateBuffer(va_display_, va_context_id_,
916 VASliceParameterBufferType, sizeof(VASliceParameterBufferH264),
917 1, &slice_param, &slice_param_buf_id);
918 VA_SUCCESS_OR_RETURN(va_status, "Failed creating a buffer for slice param",
919 false);
920
921 // Queue its VA buffer ID to be committed on HW decode run.
922 pending_slice_bufs_.push(slice_param_buf_id);
923
924 return true;
925 }
926
927 bool VaapiH264Decoder::SendSliceData(void* ptr, size_t size)
928 {
929 VABufferID slice_data_buf_id;
930 VAStatus va_status;
931
932 va_status = vaapi_vaCreateBuffer(va_display_, va_context_id_,
933 VASliceDataBufferType, size, 1, ptr, &slice_data_buf_id);
934 VA_SUCCESS_OR_RETURN(va_status, "Failed creating a buffer for slice data",
935 false);
936
937 pending_slice_bufs_.push(slice_data_buf_id);
938
939 return true;
940 }
941
942 bool VaapiH264Decoder::QueueSlice(H264SliceHeader* slice_hdr) {
943 DCHECK(curr_pic_.get());
944
945 if (!SendVASliceParam(slice_hdr))
946 return false;
947
948 if (!SendSliceData(slice_hdr->nalu_data, slice_hdr->nalu_size))
949 return false;
950
951 return true;
952 }
953
954 // TODO posciak: start using vaMapBuffer instead of vaCreateBuffer wherever
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 What's your plan here?
Pawel Osciak 2012/03/21 18:40:35 Small optimization that may save us a little bit,
955 // possible.
956
957 bool VaapiH264Decoder::DecodePicture() {
958 static const size_t kMaxVABuffers = 32;
959 VABufferID buffers[kMaxVABuffers];
960 VAStatus va_status;
961
962 DCHECK(!frame_decoded_);
963 DCHECK(curr_pic_.get());
964
965 DCHECK_LE(pending_va_bufs_.size(), kMaxVABuffers);
966 DCHECK_LE(pending_slice_bufs_.size(), kMaxVABuffers);
967
968 DVLOG(4) << "Pending VA bufs to commit: " << pending_va_bufs_.size();
969 DVLOG(4) << "Pending slice bufs to commit: " << pending_slice_bufs_.size();
970
971 // Find the surface associated with the picture to be decoded.
972 DCHECK(pending_slice_bufs_.size());
973 DecodeSurface* dec_surface = poc_to_decode_surfaces_[curr_pic_->PicOrderCnt];
974 DVLOG(4) << "Decoding POC " << curr_pic_->PicOrderCnt
975 << " into surface " << dec_surface->va_surface_id;
976
977 // Get ready to decode into surface.
978 va_status = vaapi_vaBeginPicture(va_display_, va_context_id_,
979 dec_surface->va_surface_id);
980 VA_SUCCESS_OR_RETURN(va_status, "vaBeginPicture failed", false);
981
982 // Put buffer IDs for pending parameter buffers into buffers[].
983 size_t num_buffers = pending_va_bufs_.size();
984 for (size_t i = 0; i < num_buffers && i < kMaxVABuffers; ++i) {
985 buffers[i] = pending_va_bufs_.front();
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 If 32 is a real limit, why not just maintain pendi
Pawel Osciak 2012/03/21 18:40:35 I had it that way originally actually. The problem
Ami GONE FROM CHROMIUM 2012/03/22 17:01:36 If that's the problem, I'm not seeing a solution :
Pawel Osciak 2012/04/05 10:37:20 To me it is simpler to have one queue variable I d
Ami GONE FROM CHROMIUM 2012/04/09 21:35:53 Would we both be happier if pending_{slice,va}_buf
986 pending_va_bufs_.pop();
987 }
988
989 // And send them to the HW decoder.
990 va_status = vaapi_vaRenderPicture(va_display_, va_context_id_, buffers,
991 num_buffers);
992 VA_SUCCESS_OR_RETURN(va_status, "vaRenderPicture for va_bufs failed", false);
993
994 DVLOG(4) << "Committed " << num_buffers << "VA buffers";
995
996 // Put buffer IDs for pending slice data buffers into buffers[].
997 num_buffers = pending_slice_bufs_.size();
998 for (size_t i = 0; i < num_buffers && i < kMaxVABuffers; ++i) {
999 buffers[i] = pending_slice_bufs_.front();
1000 pending_slice_bufs_.pop();
1001 }
1002
1003 // And send them to the Hw decoder.
1004 va_status = vaapi_vaRenderPicture(va_display_, va_context_id_, buffers,
1005 num_buffers);
1006 VA_SUCCESS_OR_RETURN(va_status, "vaRenderPicture fo slices failed", false);
1007
1008 DVLOG(4) << "Committed " << num_buffers << "slice buffers";
1009
1010 // Instruct HW decoder to start processing committed buffers (decode this
1011 // picture). This does not block until the end of decode.
1012 va_status = vaapi_vaEndPicture(va_display_, va_context_id_);
1013 VA_SUCCESS_OR_RETURN(va_status, "vaEndPicture failed", false);
1014
1015 // Used to notify clients that we had sufficient data to start decoding
1016 // a new frame.
1017 frame_decoded_ = true;
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 this var name and the comment preceding it are at
Pawel Osciak 2012/03/21 18:40:35 From our standpoint yes, because we committed all
Ami GONE FROM CHROMIUM 2012/03/22 17:01:36 Then s/frame_decoded_/frame_ready_at_hw_/
Pawel Osciak 2012/04/05 10:37:20 Done.
1018
1019 return true;
1020 }
1021
1022
1023 bool VaapiH264Decoder::InitCurrPicture(H264SliceHeader* slice_hdr) {
1024 DCHECK(curr_pic_.get());
1025
1026 memset(curr_pic_.get(), 0, sizeof(H264Picture));
1027
1028 curr_pic_->idr = slice_hdr->idr_pic_flag;
1029
1030 if (slice_hdr->field_pic_flag)
1031 curr_pic_->field = slice_hdr->bottom_field_flag ? H264Picture::FIELD_BOTTOM
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 multi-line then clause requires braces for then &
Pawel Osciak 2012/04/05 10:37:20 Done.
1032 : H264Picture::FIELD_TOP;
1033 else
1034 curr_pic_->field = H264Picture::FIELD_NONE;
1035
1036 curr_pic_->ref = slice_hdr->nal_ref_idc != 0;
1037 // Not correct if not a field.
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 not sure what this means.
Pawel Osciak 2012/03/21 18:40:35 The code here takes advantage of knowledge that it
Ami GONE FROM CHROMIUM 2012/03/22 17:01:36 I think these comments (about "field"s) could be c
Pawel Osciak 2012/04/05 10:37:20 Done.
1038 curr_pic_->frame_num = curr_pic_->PicNum = slice_hdr->frame_num;
1039
1040 if (!CalculatePicOrderCounts(slice_hdr))
1041 return false;
1042
1043 // Try to get an empty surface to decode this picture to.
1044 if (!AssignSurfaceToPoC(curr_pic_->PicOrderCnt)) {
1045 DLOG(INFO) << "Failed getting a free surface for a picture";
1046 return false;
1047 }
1048
1049 curr_pic_->long_term_reference_flag = slice_hdr->long_term_reference_flag;
1050 curr_pic_->adaptive_ref_pic_marking_mode_flag =
1051 slice_hdr->adaptive_ref_pic_marking_mode_flag;
1052
1053 // If the slice header indicates we will have to perform reference marking
1054 // process after this picture is decoded, store required data for that
1055 // purpose.
1056 if (slice_hdr->adaptive_ref_pic_marking_mode_flag) {
1057 DCHECK_EQ(sizeof(curr_pic_->ref_pic_marking),
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 This is a COMPILE_ASSERT that can go somewhere (no
Pawel Osciak 2012/03/21 18:40:35 But only in debug build, but you are right.
Ami GONE FROM CHROMIUM 2012/03/22 17:01:36 COMPILE_ASSERT should not be in only debug build.
Pawel Osciak 2012/04/05 10:37:20 Can't agree more. Done.
1058 sizeof(slice_hdr->ref_pic_marking));
1059 memcpy(curr_pic_->ref_pic_marking, slice_hdr->ref_pic_marking,
1060 sizeof(curr_pic_->ref_pic_marking));
1061 }
1062
1063 return true;
1064 }
1065
1066 bool VaapiH264Decoder::CalculatePicOrderCounts(H264SliceHeader* slice_hdr) {
1067 int prevPicOrderCntMsb, prevPicOrderCntLsb;
1068 int pic_order_cnt_lsb = slice_hdr->pic_order_cnt_lsb;
1069
1070 DCHECK_NE(curr_sps_id_, -1);
1071
1072 curr_pic_->pic_order_cnt_lsb = pic_order_cnt_lsb;
1073
1074 switch (parser_.GetSPS(curr_sps_id_)->pic_order_cnt_type) {
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 since only case 0 is handled it would be much clea
Pawel Osciak 2012/03/21 18:40:35 Probably... I would like to add this, but later on
Pawel Osciak 2012/04/05 10:37:20 Will need to find streams that actually use != 0,
1075 case 0:
1076 /* See spec 8.2.1.1 */
1077 if (slice_hdr->idr_pic_flag) {
1078 prevPicOrderCntMsb = prevPicOrderCntLsb = 0;
1079 } else {
1080 if (prev_ref_has_memmgmnt5_) {
1081 if (prev_ref_field_ != H264Picture::FIELD_BOTTOM) {
1082 prevPicOrderCntMsb = 0;
1083 prevPicOrderCntLsb = prev_ref_TopFieldOrderCnt_;
1084 } else {
1085 prevPicOrderCntMsb = 0;
1086 prevPicOrderCntLsb = 0;
1087 }
1088 } else {
1089 prevPicOrderCntMsb = prev_ref_PicOrderCntMsb_;
1090 prevPicOrderCntLsb = prev_ref_pic_order_cnt_lsb_;
1091 }
1092 }
1093
1094 DCHECK_NE(MaxPicOrderCntLsb_, 0);
1095 if ((pic_order_cnt_lsb < prevPicOrderCntLsb) &&
1096 (prevPicOrderCntLsb - pic_order_cnt_lsb >= MaxPicOrderCntLsb_ / 2)) {
1097 curr_pic_->PicOrderCntMsb = prevPicOrderCntMsb + MaxPicOrderCntLsb_;
1098 } else if ((pic_order_cnt_lsb > prevPicOrderCntLsb) &&
1099 (pic_order_cnt_lsb - prevPicOrderCntLsb > MaxPicOrderCntLsb_ / 2)) {
1100 curr_pic_->PicOrderCntMsb = prevPicOrderCntMsb - MaxPicOrderCntLsb_;
1101 } else {
1102 curr_pic_->PicOrderCntMsb = prevPicOrderCntMsb;
1103 }
1104
1105 if (curr_pic_->field != H264Picture::FIELD_BOTTOM)
1106 curr_pic_->TopFieldOrderCnt = curr_pic_->PicOrderCntMsb
1107 + pic_order_cnt_lsb;
1108
1109 if (curr_pic_->field != H264Picture::FIELD_TOP) {
1110 // TODO posciak: perhaps replace with pic->field?
1111 if (!slice_hdr->field_pic_flag)
1112 curr_pic_->BottomFieldOrderCnt = curr_pic_->TopFieldOrderCnt
1113 + slice_hdr->delta_pic_order_cnt_bottom;
1114 else
1115 curr_pic_->BottomFieldOrderCnt = curr_pic_->PicOrderCntMsb
1116 + pic_order_cnt_lsb;
1117 }
1118 break;
1119
1120 case 1:
1121 NOTIMPLEMENTED();
1122 return false;
1123 break;
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 break is unnecessary after return (here and elsewh
Pawel Osciak 2012/04/05 10:37:20 Done.
1124
1125 case 2:
1126 NOTIMPLEMENTED();
1127 return false;
1128 break;
1129
1130 default:
1131 NOTREACHED();
1132 }
1133
1134 switch (curr_pic_->field) {
1135 case H264Picture::FIELD_NONE:
1136 curr_pic_->PicOrderCnt = std::min(curr_pic_->TopFieldOrderCnt,
1137 curr_pic_->BottomFieldOrderCnt);
1138 break;
1139
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 extra newlines are unnecessary.
Pawel Osciak 2012/04/05 10:37:20 Done.
1140 case H264Picture::FIELD_TOP:
1141 curr_pic_->PicOrderCnt = curr_pic_->TopFieldOrderCnt;
1142 break;
1143
1144 case H264Picture::FIELD_BOTTOM:
1145 curr_pic_->PicOrderCnt = curr_pic_->BottomFieldOrderCnt;
1146 break;
1147
1148 default:
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 drop default clause
Pawel Osciak 2012/04/05 10:37:20 Done.
1149 NOTREACHED();
1150 }
1151
1152 return true;
1153 }
1154
1155 void VaapiH264Decoder::UpdatePicNums() {
1156 H264Picture* pic;
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 move to first use at l.1159.
Pawel Osciak 2012/04/05 10:37:20 Done.
1157
1158 for (PicsVector::iterator it = dpb_.begin(); it != dpb_.end(); ++it) {
1159 pic = *it;
1160 DCHECK(pic);
1161
1162 if (!pic->ref)
1163 continue;
1164
1165 // Below is not correct if a field.
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 unclear
Pawel Osciak 2012/03/21 18:40:35 This is one of the markers saying I'm cutting corn
1166 DCHECK_EQ(pic->field, H264Picture::FIELD_NONE);
1167 if (pic->long_term) {
1168 pic->LongTermPicNum = pic->LongTermFrameIdx;
1169 } else {
1170 if (pic->frame_num > frame_num_)
1171 pic->FrameNumWrap = pic->frame_num - MaxFrameNum_;
1172 else
1173 pic->FrameNumWrap = pic->frame_num;
1174
1175 pic->PicNum = pic->FrameNumWrap;
1176 }
1177 }
1178 }
1179
1180 void VaapiH264Decoder::ConstructReferencePicListsP(H264SliceHeader* slice_hdr) {
1181 // RefPicList0:
1182 // shortterm ref pics sorted by descending PicNum,
1183 // followed by long term ref pics by ascending LongTermPicNum.
1184
1185 DCHECK(RefPicList0_.empty() && RefPicList1_.empty());
1186 dpb_.GetShortTermRefPicsAppending(RefPicList0_);
1187 size_t num_short_refs = RefPicList0_.size();
1188 std::sort(RefPicList0_.begin(), RefPicList0_.end(),
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 This (and below) is an awful lot of std::sort()'in
Pawel Osciak 2012/03/21 18:40:35 Sorts are done on different comparators/different
Ami GONE FROM CHROMIUM 2012/03/22 17:01:36 My concern isn't about the run-time cost of sortin
Pawel Osciak 2012/04/05 10:37:20 It is required by spec, why would I be doing it ot
1189 H264Picture::PicNumDescCompare());
1190 dpb_.GetLongTermRefPicsAppending(RefPicList0_);
1191 std::sort(RefPicList0_.begin() + num_short_refs, RefPicList0_.end(),
1192 H264Picture::LongTermPicNumAscCompare());
1193
1194 //DCHECK((int)RefPicList0_.size() <=
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 drop
Pawel Osciak 2012/04/05 10:37:20 Done.
1195 //slice_hdr->num_ref_idx_l0_active_minus1 + 1);
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 drop
Pawel Osciak 2012/04/05 10:37:20 Done.
1196 RefPicList0_.resize(slice_hdr->num_ref_idx_l0_active_minus1 + 1);
1197 }
1198
1199 void VaapiH264Decoder::ConstructReferencePicListsB(H264SliceHeader* slice_hdr) {
Ami GONE FROM CHROMIUM 2012/03/22 17:01:36 The impl of this method is super-similar to Constr
Pawel Osciak 2012/04/05 10:37:20 The similarities are deceiving. I unified commenti
1200 PicsVector::iterator iter;
1201
1202 // RefPicList0 (8.2.4.2.3) [[1] [2] [3]], where:
1203 // [1] shortterm ref pics with POC < curr_pic's POC sorted by descending POC,
1204 // [2] shortterm ref pics with POC > curr_pic's POC by ascending POC,
1205 // [3] longterm ref pics by ascending LongTermPicNum.
1206
1207 DCHECK(RefPicList0_.empty() && RefPicList1_.empty());
1208 dpb_.GetShortTermRefPicsAppending(RefPicList0_);
1209 size_t num_short_refs = RefPicList0_.size();
1210
1211 // First sort ascending, this will put [1] in right place and finish [2].
1212 std::sort(RefPicList0_.begin(), RefPicList0_.end(),
1213 H264Picture::POCAscCompare());
1214
1215 // Find first with POC > curr_pic's POC to get first element in [2]...
1216 iter = std::upper_bound(RefPicList0_.begin(), RefPicList0_.end(),
1217 curr_pic_.get(), H264Picture::POCAscCompare());
1218
1219 // and sort [1] descending, thus finishing sequence [1] [2].
1220 std::sort(RefPicList0_.begin(), iter, H264Picture::POCDescCompare());
1221
1222 // Now add [3] and sort by ascending LongTermPicNum.
1223 dpb_.GetLongTermRefPicsAppending(RefPicList0_);
1224 std::sort(RefPicList0_.begin() + num_short_refs, RefPicList0_.end(),
1225 H264Picture::LongTermPicNumAscCompare());
1226
1227
1228 // RefPicList1 (8.2.4.2.4) [[1] [2] [3]], where:
1229 // [1] shortterm ref pics with POC > curr_pic's POC sorted by ascending POC,
1230 // [2] shortterm ref pics with POC < curr_pic's POC by descending POC,
1231 // [3] longterm ref pics by ascending LongTermPicNum.
1232
1233 dpb_.GetShortTermRefPicsAppending(RefPicList1_);
1234 num_short_refs = RefPicList1_.size();
1235
1236 // First sort by descending POC.
1237 std::sort(RefPicList1_.begin(), RefPicList1_.end(),
1238 H264Picture::POCDescCompare());
1239
1240 // Find first with POC < curr_pic's POC to get first element in [2]...
1241 iter = std::upper_bound(RefPicList1_.begin(), RefPicList1_.end(),
1242 curr_pic_.get(), H264Picture::POCDescCompare());
1243
1244 // and sort [1] ascending.
1245 std::sort(RefPicList1_.begin(), iter, H264Picture::POCAscCompare());
1246
1247 // Now add [3] and sort by ascending LongTermPicNum
1248 dpb_.GetShortTermRefPicsAppending(RefPicList1_);
1249 std::sort(RefPicList1_.begin() + num_short_refs, RefPicList1_.end(),
1250 H264Picture::LongTermPicNumAscCompare());
1251
1252 // If lists identical, swap first two entries in RefPicList1 (spec 8.2.4.2.3)
1253 if (RefPicList1_.size() > 1 &&
1254 std::equal(RefPicList0_.begin(), RefPicList0_.end(),
1255 RefPicList1_.begin()))
1256 std::swap(RefPicList1_[0], RefPicList1_[1]);
1257
1258 //DCHECK((int)RefPicList0_.size() <=
1259 //slice_hdr->num_ref_idx_l0_active_minus1 + 1);
1260 //DCHECK((int)RefPicList1_.size() <=
1261 //slice_hdr->num_ref_idx_l1_active_minus1 + 1);
1262
1263 // Per 8.2.4.2 it's possible for num_ref_idx_lX_active_minus1 to indicate
1264 // there should be more ref pics on list than we constructed.
1265 // Those superfluous ones should be treated as non-reference.
1266 RefPicList0_.resize(slice_hdr->num_ref_idx_l0_active_minus1 + 1);
1267 RefPicList1_.resize(slice_hdr->num_ref_idx_l1_active_minus1 + 1);
1268 }
1269
1270 // See 8.2.4
1271 int VaapiH264Decoder::PicNumF(H264Picture *pic) {
1272 if (!pic)
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 when can this happen?
Pawel Osciak 2012/04/05 10:37:20 Sometimes the stream may request more ref pics tha
1273 return -1;
1274
1275 if (!pic->long_term)
1276 return pic->PicNum;
1277 else
1278 return MaxPicNum_;
1279 }
1280
1281 // See 8.2.4
1282 int VaapiH264Decoder::LongTermPicNumF(H264Picture *pic) {
1283 if (H264Picture::IsLongTermRefPic()(pic))
1284 return pic->LongTermPicNum;
1285 else
1286 return 2 * (MaxLongTermFrameIdx_ + 1);
1287 }
1288
1289 bool VaapiH264Decoder::ModifyReferencePicList(H264SliceHeader *slice_hdr,
1290 int list) {
1291 int i;
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 Please declare variables at the latest possible ti
1292
1293 int refIdxLX = 0;
1294 int picNumLXNoWrap;
1295 int picNumLX;
1296 int picNumLXPred = curr_pic_->PicNum;
1297 int cIdx, nIdx;
1298 int num_ref_idx_lX_active_minus1;
1299
1300 PicsVector* RefPicListX;
1301 H264ModificationOfPicNum* list_mod;
1302
1303 // Set up pointers to proper list to be processed.
1304 if (list == 0) {
1305 if (!slice_hdr->ref_pic_list_modification_flag_l0)
1306 return true;
1307
1308 list_mod = slice_hdr->ref_list_l0_modifications;
1309 num_ref_idx_lX_active_minus1 = RefPicList0_.size() - 1;
1310
1311 RefPicListX = &RefPicList0_;
1312 } else {
1313 if (!slice_hdr->ref_pic_list_modification_flag_l1)
1314 return true;
1315
1316 list_mod = slice_hdr->ref_list_l1_modifications;
1317 num_ref_idx_lX_active_minus1 = RefPicList1_.size() - 1;
1318
1319 RefPicListX = &RefPicList1_;
1320 }
1321
1322 DCHECK_GT(num_ref_idx_lX_active_minus1, 0);
1323
1324 // Spec 8.2.4.3:
1325 // Reorder pictures on the list in a way specified in the stream.
1326 for (i = 0; i < H264SliceHeader::kRefListModSize; ++i) {
1327 switch (list_mod->modification_of_pic_nums_idc) {
1328 case 0:
1329 case 1:
1330 // Modify short reference picture position.
1331 if (list_mod->modification_of_pic_nums_idc == 0) {
1332 if (picNumLXPred - ((int)list_mod->abs_diff_pic_num_minus1 + 1)
1333 < 0)
1334 picNumLXNoWrap = picNumLXPred
1335 - ((int)list_mod->abs_diff_pic_num_minus1 + 1)
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 indent is wrong here & elsewhere operators belong
Pawel Osciak 2012/03/21 18:40:35 Yeah, I really can't make peace with this I guess
1336 + MaxPicNum_;
1337 else
1338 picNumLXNoWrap = picNumLXPred
1339 - ((int)list_mod->abs_diff_pic_num_minus1 + 1);
1340 } else {
1341 if (picNumLXPred + ((int)list_mod->abs_diff_pic_num_minus1 + 1)
1342 >= MaxPicNum_)
1343 picNumLXNoWrap = picNumLXPred
1344 + ((int)list_mod->abs_diff_pic_num_minus1 + 1)
1345 - MaxPicNum_;
1346 else
1347 picNumLXNoWrap = picNumLXPred
1348 + ((int)list_mod->abs_diff_pic_num_minus1 + 1);
1349 }
1350
1351 picNumLXPred = picNumLXNoWrap;
1352
1353 if (picNumLXNoWrap > curr_pic_->PicNum)
1354 picNumLX = picNumLXNoWrap - MaxPicNum_;
1355 else
1356 picNumLX = picNumLXNoWrap;
1357
1358 DCHECK_LT(num_ref_idx_lX_active_minus1 + 1,
1359 H264SliceHeader::kRefListModSize);
1360
1361 // Shift all pictures starting from refIdxLX one position to the right.
1362 for (cIdx = num_ref_idx_lX_active_minus1 + 1; cIdx > refIdxLX; --cIdx)
1363 (*RefPicListX)[cIdx] = (*RefPicListX)[cIdx - 1];
1364
1365 // Put picNumLX at refIdxLX.
1366 (*RefPicListX)[refIdxLX++] = dpb_.GetShortRefPicByPicNum(picNumLX);
1367 DCHECK((*RefPicListX)[refIdxLX - 1]);
1368
1369 // Now shift the pictures after its original position.
1370 nIdx = refIdxLX;
1371 for (cIdx = refIdxLX;
1372 cIdx <= num_ref_idx_lX_active_minus1 + 1; ++cIdx) {
1373 if (PicNumF((*RefPicListX)[cIdx]) != picNumLX)
1374 (*RefPicListX)[nIdx++] = (*RefPicListX)[cIdx];
1375 }
1376 break;
1377
1378 case 2:
1379 // Modify long term reference picture position.
1380 DCHECK_LT(num_ref_idx_lX_active_minus1 + 1,
1381 H264SliceHeader::kRefListModSize);
1382
1383 // Shift all pictures starting from refIdxLX to the right.
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 Can you try to extract common functionality into h
Pawel Osciak 2012/03/21 18:40:35 Well, again, this is intentional. This is exactly
Ami GONE FROM CHROMIUM 2012/03/22 17:01:36 "Optimized" is a red-herring; my concern is with c
Pawel Osciak 2012/04/05 10:37:20 Of course the code should be doing reasonable thin
1384 for (cIdx = num_ref_idx_lX_active_minus1 + 1; cIdx > refIdxLX; --cIdx)
1385 (*RefPicListX)[cIdx] = (*RefPicListX)[cIdx - 1];
1386
1387 // Put given LongTermPicNum at refIdxLX.
1388 (*RefPicListX)[refIdxLX++] =
1389 dpb_.GetLongRefPicByLongTermPicNum(list_mod->long_term_pic_num);
1390 DCHECK((*RefPicListX)[refIdxLX - 1]);
1391
1392 nIdx = refIdxLX;
1393
1394 // Now shift the pictures after its original position.
1395 for (cIdx = refIdxLX; cIdx <= num_ref_idx_lX_active_minus1 + 1; ++cIdx)
1396 if (LongTermPicNumF((*RefPicListX)[cIdx])
1397 != curr_pic_->LongTermPicNum)
1398 (*RefPicListX)[nIdx++] = (*RefPicListX)[cIdx];
1399 break;
1400
1401 case 3:
1402 // End of modification list.
1403 return true;
1404
1405 default:
1406 // May be recoverable.
1407 DLOG(INFO) << "Invalid modification_of_pic_nums_idc="
1408 << list_mod->modification_of_pic_nums_idc
1409 << " in position " << i;
1410 break;
1411 }
1412
1413 ++list_mod;
1414 }
1415
1416 return true;
1417 }
1418
1419 // Must be run in GLXContext thread.
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 Replace this comment with a DCHECK at the top of t
Pawel Osciak 2012/03/21 18:40:35 I didn't want to pollute this class with threading
Ami GONE FROM CHROMIUM 2012/03/22 17:01:36 I implied this elsewhere, but I don't think puttin
Pawel Osciak 2012/04/05 10:37:20 I just don't want to make it do any threading call
1420 bool VaapiH264Decoder::PutPicToTexture(int32 picture_buffer_id) {
1421 DecodeSurfaces::iterator it = decode_surfaces_.find(picture_buffer_id);
1422 if (it == decode_surfaces_.end()) {
1423 DLOG(ERROR) << "Asked to put an invalid buffer";
1424 return false;
1425 }
1426
1427 DVLOG(3) << "Will output from VASurface " << it->second->va_surface_id
1428 << " to texture id " << it->second->texture_id;
1429
1430 TrapX11Errors();
1431
1432 // Put the decoded data into XPixmap bound to the texture.
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 What is this doing? The comment reads to me like "
Pawel Osciak 2012/03/21 18:40:35 This is driver/platform-dependent and implemented
Ami GONE FROM CHROMIUM 2012/03/22 17:01:36 How could they *not* copy? This is the first time
Pawel Osciak 2012/04/05 10:37:20 This is possible. But whatever happens, this the k
1433 VAStatus va_status = vaapi_vaPutSurface(va_display_,
1434 it->second->va_surface_id, it->second->x_pixmap,
1435 0, 0, pic_width_, pic_height_,
1436 0, 0, pic_width_, pic_height_,
1437 NULL, 0, 0);
1438 VA_SUCCESS_OR_RETURN(va_status,
1439 "Failed putting decoded picture to texture", false);
1440 // TODO posciak: needed?
1441 XSync(x_display_, False);
1442
1443 // Wait for the data to be put into the buffer so it'd ready for output.
1444 va_status = vaapi_vaSyncSurface(va_display_, it->second->va_surface_id);
1445 VA_SUCCESS_OR_RETURN(va_status, "Failed syncing decoded picture", false);
1446
1447 UntrapX11Errors();
1448 return true;
1449 }
1450
1451 bool VaapiH264Decoder::OutputPic(H264Picture* pic) {
1452 DCHECK(poc_to_decode_surfaces_.find(pic->PicOrderCnt) !=
1453 poc_to_decode_surfaces_.end());
1454
1455 // Notify client that a picture is ready to be outputted. This does not
1456 // require the data to be synced with texture contents. Client must use
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 Why do it this way?
Pawel Osciak 2012/03/21 18:40:35 Because I want to postpone Sync until the last pos
1457 // PutPicToTexture() to ensure that.
1458 DecodeSurface* dec_surface = poc_to_decode_surfaces_[pic->PicOrderCnt];
1459 DCHECK(dec_surface);
1460
1461 DVLOG(4) << "Posting output task for input_id: " << dec_surface->input_id
1462 << "output_id: " << dec_surface->picture_buffer_id;
1463
1464 DCHECK(msg_loop_);
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 I thought you were going to PostTask to this msg l
Pawel Osciak 2012/03/21 18:40:35 I'm overgenerous with DCHECKs sometimes, but I hav
Ami GONE FROM CHROMIUM 2012/03/22 17:01:36 DCHECKs are indeed compiled out of release builds.
Pawel Osciak 2012/04/05 10:37:20 This DCHECK is actually a leftover from when this
1465 output_pic_callback_(output_pic_callback_arg_, dec_surface->input_id,
1466 dec_surface->picture_buffer_id);
1467 return true;
1468 }
1469
1470 bool VaapiH264Decoder::Flush() {
1471 PicsVector to_output;
1472 PicsVector::iterator it;
1473
1474 // Output all pictures that are waiting to be outputted.
1475 // Sort by POC before outputting
1476 dpb_.GetNotOutputtedPicsSortedByPOCAppending(to_output);
1477 for (it = to_output.begin(); it != to_output.end(); ++it) {
1478 if (!OutputPic(*it)) {
1479 DLOG(ERROR) << "Failed to output pic POC: " << (*it)->PicOrderCnt;
1480 return false;
1481 }
1482 }
1483
1484 // And clear DPB contents.
1485 dpb_.Clear();
1486
1487 return true;
1488 }
1489
1490 bool VaapiH264Decoder::StartNewFrame(H264SliceHeader* slice_hdr) {
1491 // TODO posciak: add handling of max_num_ref_frames per spec.
1492
1493 // If the new frame is an IDR, output what's left to output and clear DPB
1494 if (slice_hdr->idr_pic_flag) {
1495 // (unless we are explicitly instructed not to do so).
1496 if (!slice_hdr->no_output_of_prior_pics_flag) {
1497 // Output DPB contents.
1498 if (!Flush())
1499 return false;
1500 }
1501 dpb_.Clear();
1502 }
1503
1504 // curr_pic_ should have either been added to DPB or discarded when finishing
1505 // the last frame. DPB is responsible for releasing that memory once it's
1506 // not needed anymore.
1507 DCHECK(!curr_pic_.get());
1508 curr_pic_.reset(new H264Picture);
1509 CHECK(curr_pic_.get());
1510
1511 if (!InitCurrPicture(slice_hdr))
1512 return false;
1513
1514 DCHECK_GT(MaxFrameNum_, 0);
1515
1516 UpdatePicNums();
1517
1518 // Prepare reference picture lists if required (B and S/SP slices).
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 comment is conditional but next two lines aren't.
Pawel Osciak 2012/03/21 18:40:35 Yeah, it refers to the ifs below as well.
Ami GONE FROM CHROMIUM 2012/03/22 17:01:36 Then remove the newline at 1521.
Pawel Osciak 2012/04/05 10:37:20 Done.
1519 RefPicList0_.clear();
1520 RefPicList1_.clear();
1521
1522 if (IsH264PSlice(slice_hdr) || IsH264SPSlice(slice_hdr)) {
1523 DVLOG(4) << "================ P/SP slice, POC= " << curr_pic_->PicOrderCnt
1524 << " PicNum= " << curr_pic_->PicNum;
1525
1526 ConstructReferencePicListsP(slice_hdr);
1527 ModifyReferencePicList(slice_hdr, 0);
1528
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 lots of unnecessary \n's IMO
Pawel Osciak 2012/04/05 10:37:20 Done.
1529 } else if (IsH264BSlice(slice_hdr)) {
1530 DVLOG(4) << "================ B slice, POC= " << curr_pic_->PicOrderCnt
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 I think most/all of these DVLOGs in this CL should
Pawel Osciak 2012/04/05 10:37:20 Right, those ones can go easily.
1531 << " PicNum= " << curr_pic_->PicNum;
1532
1533 ConstructReferencePicListsB(slice_hdr);
1534 ModifyReferencePicList(slice_hdr, 0);
1535 ModifyReferencePicList(slice_hdr, 1);
1536
1537 } else {
1538 DVLOG(4) << "================ I slice, POC= " << curr_pic_->PicOrderCnt
1539 << " PicNum= " << curr_pic_->PicNum;
1540 }
1541
1542 // Send parameter buffers before each new picture, before the first slice.
1543 if (!SendPPS())
1544 return false;
1545
1546 if (!SendIQMatrix())
1547 return false;
1548
1549 if (!QueueSlice(slice_hdr))
1550 return false;
1551
1552 return true;
1553 }
1554
1555 struct MarkLongTermPicUnusedForRefIfOverMax
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 ditto my comment about explicit loops over algorit
Pawel Osciak 2012/04/05 10:37:20 Done.
1556 : public std::binary_function<H264Picture*, int, void> {
1557
1558 // Marks all long term pictures, for which their LongTermFrameIdx is
1559 // over given |max_long_term_frame_idx|, as unused.
1560 void operator()(H264Picture* pic, const int& max_long_term_frame_idx) const {
1561 DCHECK(pic->ref && pic->long_term);
1562 if (pic->LongTermFrameIdx > max_long_term_frame_idx)
1563 pic->ref = false;
1564 }
1565 };
1566
1567 struct MarkLongTermPicUnusedForRefByLongTermFrameIdx
1568 : public std::binary_function<H264Picture*, int, void> {
1569
1570 // Marks one long term frame picture, for which its LongTermFrameIdx is
1571 // over |long_term_frame_idx|.
1572 void operator()(H264Picture* pic, const int &long_term_frame_idx) const {
1573 DCHECK(pic->ref && pic->long_term);
1574 if (pic->LongTermFrameIdx == long_term_frame_idx)
1575 pic->ref = false;
1576 }
1577 };
1578
1579 bool VaapiH264Decoder::HandleMemoryManagementOps() {
1580 H264DecRefPicMarking *ref_pic_marking;
1581 int picNumX;
1582 H264Picture* to_mark;
1583
1584 // 8.2.5.4
1585 for (unsigned int i = 0; i < arraysize(curr_pic_->ref_pic_marking); ++i) {
1586 // Code below does not support field pictures.
1587 ref_pic_marking = &curr_pic_->ref_pic_marking[i];
1588
1589 switch (ref_pic_marking->memory_mgmnt_control_operation) {
1590 case 0:
1591 // Normal end of operations' specification.
1592 return true;
1593
1594 case 1:
1595 // Mark a short term reference picture as unused so it can be removed
1596 // if outputted.
1597 picNumX = curr_pic_->PicNum
1598 - (ref_pic_marking->difference_of_pic_nums_minus1 + 1);
1599 to_mark = dpb_.GetShortRefPicByPicNum(picNumX);
1600 if (to_mark) {
1601 to_mark->ref = false;
1602 } else {
1603 DLOG(ERROR) << "Invalid short ref pic num to unmark";
1604 return false;
1605 }
1606 break;
1607
1608 case 2:
1609 // Mark a long term reference picture as unused so it can be removed
1610 // if outputted.
1611 to_mark = dpb_.GetLongRefPicByLongTermPicNum(
1612 ref_pic_marking->long_term_pic_num);
1613 if (to_mark) {
1614 to_mark->ref = false;
1615 } else {
1616 DLOG(ERROR) << "Invalid long term ref pic num to unmark";
1617 return false;
1618 }
1619 break;
1620
1621 case 3:
1622 // Mark a short term reference picture as long term reference.
1623 picNumX = curr_pic_->PicNum
1624 - (ref_pic_marking->difference_of_pic_nums_minus1 + 1);
1625 to_mark = dpb_.GetShortRefPicByPicNum(picNumX);
1626 if (to_mark) {
1627 DCHECK(to_mark->ref && !to_mark->long_term);
1628 to_mark->long_term = true;
1629 to_mark->LongTermFrameIdx = ref_pic_marking->long_term_frame_idx;
1630 } else {
1631 DLOG(ERROR) << "Invalid short term ref pic num to mark as long ref";
1632 return false;
1633 }
1634 break;
1635
1636 case 4: {
1637 // Unmark all reference pictures with LongTermFrameIdx over new max.
1638 MaxLongTermFrameIdx_ = ref_pic_marking->max_long_term_frame_idx_plus1
1639 - 1;
1640 PicsVector long_terms;
1641 dpb_.GetLongTermRefPicsAppending(long_terms);
1642 for_each(long_terms.begin(), long_terms.end(),
1643 std::bind2nd(MarkLongTermPicUnusedForRefIfOverMax(),
1644 MaxLongTermFrameIdx_));
1645 break;
1646 }
1647
1648 case 5:
1649 // Unmark all reference pictures.
1650 dpb_.MarkAllUnusedForRef();
1651 MaxLongTermFrameIdx_ = -1;
1652 curr_pic_->mem_mgmt_5 = true;
1653 break;
1654
1655 case 6: {
1656 // Replace long term reference pictures with current picture.
1657 // First unmark if any existing with this LongTermFrameIdx...
1658 PicsVector long_terms;
1659 dpb_.GetLongTermRefPicsAppending(long_terms);
1660 for_each(long_terms.begin(), long_terms.end(),
1661 std::bind2nd(MarkLongTermPicUnusedForRefByLongTermFrameIdx(),
1662 ref_pic_marking->long_term_frame_idx));
1663
1664 // and mark the current one.
1665 curr_pic_->ref = true;
1666 curr_pic_->long_term = true;
1667 curr_pic_->LongTermFrameIdx = ref_pic_marking->long_term_frame_idx;
1668 break;
1669 }
1670
1671 default:
1672 // Would indicate a bug in parser.
1673 NOTREACHED();
1674 }
1675 }
1676
1677 return true;
1678 }
1679
1680 // This method ensures that DPB does not overflow, either by removing
1681 // reference pictures as specified in the stream, or using a sliding window
1682 // procedure to remove the oldest one.
1683 // It also performs marking and unmarking pictures as reference.
1684 // See spac 8.2.5.1.
1685 void VaapiH264Decoder::ReferencePictureMarking() {
1686 if (curr_pic_->idr) {
1687 // If current picture is an IDR, all reference pictures are unmarked.
1688 dpb_.MarkAllUnusedForRef();
1689
1690 if (curr_pic_->long_term_reference_flag) {
1691 curr_pic_->long_term = true;
1692 curr_pic_->LongTermFrameIdx = 0;
1693 MaxLongTermFrameIdx_ = 0;
1694 } else {
1695 curr_pic_->long_term = false;
1696 MaxLongTermFrameIdx_ = -1;
1697 }
1698 } else {
1699 if (!curr_pic_->adaptive_ref_pic_marking_mode_flag) {
1700 // If non-IDR, and the stream does not indicate what we should do to
1701 // ensure DPB doesn't overflow, discard oldest picture.
1702 // See spec 8.2.5.3.
1703 if (curr_pic_->field == H264Picture::FIELD_NONE) {
1704 DCHECK_LE(dpb_.CountRefPics(),
1705 std::max<int>(parser_.GetSPS(curr_sps_id_)->max_num_ref_frames,
1706 1));
1707 if (dpb_.CountRefPics() ==
1708 std::max<int>(parser_.GetSPS(curr_sps_id_)->max_num_ref_frames,
1709 1)) {
1710 // Max number of reference pics reached,
1711 // need to remove one of the short term ones.
1712 // Find smallest FrameNumWrap short reference picture and mark
1713 // it as unused.
1714 H264Picture* to_unmark = dpb_.GetLowestFrameNumWrapRefPic();
1715 if (to_unmark == NULL) {
1716 DLOG(ERROR) << "Couldn't find a short ref picture to unmark";
1717 return;
1718 }
1719 to_unmark->ref = false;
1720 }
1721 } else {
1722 // Shouldn't get here.
Ami GONE FROM CHROMIUM 2012/03/21 13:16:24 NOTIMPLEMENTED is LOG(ERROR). Can you replace som
Pawel Osciak 2012/04/05 10:37:20 The code couldn't have really gotten here, unless
Ami GONE FROM CHROMIUM 2012/04/09 21:35:53 NOTIMPLEMENTED is a placeholder for things that ne
1723 NOTIMPLEMENTED() << "Interlaced video not supported.";
1724 }
1725 } else {
1726 // Stream has instructions how to discard pictures from DPB and how
1727 // to mark/unmark existing reference pictures. Do it.
1728 // Spec 8.2.5.4.
1729 if (curr_pic_->field == H264Picture::FIELD_NONE) {
1730 HandleMemoryManagementOps();
1731 } else {
1732 // Shouldn't get here.
1733 NOTIMPLEMENTED() << "Interlaced video not supported.";
1734 }
1735 }
1736 }
1737 }
1738
1739 bool VaapiH264Decoder::FinishPicture() {
1740 DCHECK(curr_pic_.get());
1741
1742 // Finish processing previous picture.
1743 // Start by storing previous reference picture data for later use,
1744 // if picture being finished is a reference picture.
1745 if (curr_pic_->ref) {
1746 ReferencePictureMarking();
1747 prev_ref_has_memmgmnt5_ = curr_pic_->mem_mgmt_5;
1748 prev_ref_TopFieldOrderCnt_ = curr_pic_->TopFieldOrderCnt;
1749 prev_ref_PicOrderCntMsb_ = curr_pic_->PicOrderCntMsb;
1750 prev_ref_pic_order_cnt_lsb_ = curr_pic_->pic_order_cnt_lsb;
1751 prev_ref_field_ = curr_pic_->field;
1752 }
1753
1754 // Remove unused (for reference or later output) pictures from DPB.
1755 dpb_.RemoveUnused();
1756
1757 DVLOG(4) << "Finishing picture, DPB entries: " << dpb_.size()
1758 << " Num available dec surfaces: "
1759 << num_available_decode_surfaces_;
1760
1761 if (dpb_.IsFull()) {
1762 // DPB is full, we have to make space for the new picture.
1763 // Get all pictures that haven't been outputted yet.
1764 PicsVector not_outputted;
1765 dpb_.GetNotOutputtedPicsSortedByPOCAppending(not_outputted);
1766 PicsVector::iterator output_candidate = not_outputted.begin();
1767
1768 // Keep outputting pictures until we can either output the picture being
1769 // finished and discard it (if it is not a reference picture), or until
1770 // we can discard an older picture that was just waiting for output and
1771 // is not a reference picture, thus making space for the current one.
1772 while (dpb_.IsFull()) {
1773 // Maybe outputted enough to output current picture.
1774 if (!curr_pic_->ref && (output_candidate == not_outputted.end()
1775 || curr_pic_->PicOrderCnt < (*output_candidate)->PicOrderCnt)) {
1776 // curr_pic_ is not a reference picture and no preceding pictures are
1777 // waiting for output in DPB, so it can be outputted and discarded
1778 // without storing in DPB.
1779 if (!OutputPic(curr_pic_.get()))
1780 return false;
1781 goto no_store;
1782 }
1783
1784 // Couldn't output current picture, so try to output the lowest PoC
1785 // from DPB.
1786 if (output_candidate != not_outputted.end()) {
1787 if (!OutputPic(*output_candidate))
1788 return false;
1789
1790 // If outputted picture wasn't a reference picture, it can be removed.
1791 if (!(*output_candidate)->ref)
1792 dpb_.RemoveByPOC((*output_candidate)->PicOrderCnt);
1793 } else {
1794 // Couldn't output current pic and couldn't do anything
1795 // with existing pictures in DPB, so we can't make space.
1796 // This should not happen.
1797 DLOG(ERROR) << "Could not free up space in DPB!";
1798 return false;
1799 }
1800 }
1801 ++output_candidate;
1802 }
1803
1804 // Store current picture for later output and/or reference (ownership now
1805 // with the DPB).
1806 dpb_.StorePic(curr_pic_.release());
1807
1808 no_store:
1809 return true;
1810 }
1811
1812 bool VaapiH264Decoder::ProcessSPS(int sps_id) {
1813 int width, height;
1814 H264SPS* sps = parser_.GetSPS(sps_id);
1815 DCHECK(sps);
1816
1817 if (sps->frame_mbs_only_flag == 0) {
1818 // Fields/interlaced video not supported.
1819 DLOG(INFO) << "frame_mbs_only_flag != 1 not supported";
1820 return false;
1821 }
1822
1823 if (sps->gaps_in_frame_num_value_allowed_flag) {
1824 DLOG(INFO) << "Gaps in frame numbers not supported";
1825 return false;
1826 }
1827
1828 curr_sps_id_ = sps->seq_parameter_set_id;
1829
1830 // Calculate picture height/width (spec 7.4.2.1.1, 7.4.3).
1831 width = 16 * (sps->pic_width_in_mbs_minus1 + 1);
1832 height = 16 * (2 - sps->frame_mbs_only_flag)
1833 * (sps->pic_height_in_map_units_minus1 + 1);
1834
1835 if ((pic_width_ != -1 || pic_height_ != -1) &&
1836 (width != pic_width_ || height != pic_height_)) {
1837 DLOG(INFO) << "Picture size changed mid-stream";
1838 return false;
1839 }
1840
1841 pic_width_ = width;
1842 pic_height_ = height;
1843 DVLOG(1) << "New picture size: " << pic_width_ << "x" << pic_height_;
1844
1845 MaxPicOrderCntLsb_ = 1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4);
1846 MaxFrameNum_ = 1 << (sps->log2_max_frame_num_minus4 + 4);
1847
1848 return true;
1849 }
1850
1851 bool VaapiH264Decoder::ProcessPPS(int pps_id) {
1852 H264PPS* pps = parser_.GetPPS(pps_id);
1853 DCHECK(pps);
1854
1855 curr_pps_id_ = pps->pic_parameter_set_id;
1856
1857 return true;
1858 }
1859
1860 bool VaapiH264Decoder::FinishPrevFrameIfPresent() {
1861 // If we already have a frame waiting to be decoded, decode it and finish.
1862 if (curr_pic_ != NULL) {
1863 if (!DecodePicture())
1864 return false;
1865 return FinishPicture();
1866 }
1867
1868 return true;
1869 }
1870
1871 bool VaapiH264Decoder::ProcessSlice(H264SliceHeader* slice_hdr) {
1872 prev_frame_num_ = frame_num_;
1873 frame_num_ = slice_hdr->frame_num;
1874
1875 if (prev_frame_num_ > 0 && prev_frame_num_ < frame_num_ - 1) {
1876 DLOG(INFO) << "Gap in frame_num!";
1877 return false;
1878 }
1879
1880 if (slice_hdr->field_pic_flag == 0)
1881 MaxPicNum_ = MaxFrameNum_;
1882 else
1883 MaxPicNum_ = 2 * MaxFrameNum_;
1884
1885 // TODO posciak: switch to new picture detection per 7.4.1.2.4.
1886 if (curr_pic_ != NULL && slice_hdr->first_mb_in_slice != 0) {
1887 // This is just some more slice data of the current picture, so
1888 // just queue it and return.
1889 QueueSlice(slice_hdr);
1890 return true;
1891 } else {
1892 // A new frame, so first finish the previous one before processing it...
1893 if (!FinishPrevFrameIfPresent())
1894 return false;
1895
1896 // and then start a new one.
1897 return StartNewFrame(slice_hdr);
1898 }
1899 }
1900
1901 #define SET_ERROR_AND_RETURN() \
1902 do { \
1903 DLOG(ERROR) << "Error during decode"; \
1904 state_ = kError; \
1905 return VaapiH264Decoder::kDecError; \
1906 } while (0)
1907
1908 VaapiH264Decoder::DecResult VaapiH264Decoder::DecodeInitial(int32 input_id) {
1909 // Decode enough to get required picture size (i.e. until we find an SPS),
1910 // if we get any slice data, we are missing the beginning of the stream.
1911 H264NALU nalu;
1912 H264Parser::Result res;
1913
1914 DCHECK_NE(state_, kUninitialized);
1915
1916 curr_input_id_ = input_id;
1917
1918 while (1) {
1919 // Get next NALU looking for SPS or IDR if after reset.
1920 res = parser_.ParseNextNalu(&nalu);
1921 if (res == H264Parser::kEOStream) {
1922 DLOG(INFO) << "Could not find SPS before EOS";
1923 return kNeedMoreStreamData;
1924 } else if (res != H264Parser::kOk) {
1925 SET_ERROR_AND_RETURN();
1926 }
1927
1928 DVLOG(4) << " NALU found: " << (int)nalu.nal_unit_type;
1929
1930 switch (nalu.nal_unit_type) {
1931 case kH264NaluSPS:
1932 res = parser_.ParseSPS(&curr_sps_id_);
1933 if (res != H264Parser::kOk)
1934 SET_ERROR_AND_RETURN();
1935
1936 if (!ProcessSPS(curr_sps_id_))
1937 SET_ERROR_AND_RETURN();
1938
1939 // Just got information about the video size from SPS, so we can
1940 // now allocate surfaces and let the client now we are ready to
1941 // accept output buffers and decode.
1942 if (!CreateVASurfaces())
1943 SET_ERROR_AND_RETURN();
1944
1945 state_ = kDecoding;
1946 return kReadyToDecode;
1947
1948 case kH264NaluIDRSlice:
1949 // If after reset, should be able to recover from an IDR.
1950 if (state_ == kAfterReset) {
1951 H264SliceHeader slice_hdr;
1952
1953 res = parser_.ParseSliceHeader(&slice_hdr, &nalu);
1954 if (res != H264Parser::kOk)
1955 SET_ERROR_AND_RETURN();
1956
1957 if (!ProcessSlice(&slice_hdr))
1958 SET_ERROR_AND_RETURN();
1959
1960 state_ = kDecoding;
1961 return kReadyToDecode;
1962 } // else fallthrough
1963 case kH264NaluNonIDRSlice:
1964 case kH264NaluPPS:
1965 // Non-IDR slices cannot be used as resume points, as we may not
1966 // have all reference pictures that they may require.
1967 // fallthrough
1968 default:
1969 // Skip everything unless it's PPS or an IDR slice (if after reset).
1970 DVLOG(4) << "Skipping NALU";
1971 break;
1972 }
1973 }
1974 }
1975
1976 void VaapiH264Decoder::SetStream(uint8* ptr, size_t size) {
1977 DCHECK(ptr);
1978 DCHECK(size);
1979
1980 // Got new input stream data from the client.
1981 DVLOG(4) << "New input stream chunk at " << (void*) ptr
1982 << " size: " << size;
1983 parser_.SetStream(ptr, size);
1984 }
1985
1986 VaapiH264Decoder::DecResult VaapiH264Decoder::DecodeOneFrame(int32 input_id) {
1987 // Decode until one full frame is decoded or return it or until end
1988 // of stream (end of input data is reached).
1989 H264Parser::Result par_res;
1990 H264NALU nalu;
1991
1992 curr_input_id_ = input_id;
1993
1994 if (state_ != kDecoding) {
1995 DLOG(ERROR) << "Decoder not ready: error in stream or not initialized";
1996 return kDecError;
1997 } else if (num_available_decode_surfaces_ < 1) {
1998 DVLOG(4) << "No output surfaces available";
1999 return kNoOutputAvailable;
2000 }
2001
2002 // All of the actions below might result in decoding a picture from
2003 // previously parsed data, but we still have to handle/parse current input
2004 // first.
2005 // Note: this may drop some already decoded frames if there are errors
2006 // further in the stream, but we are OK with that.
2007 while (1) {
2008 par_res = parser_.ParseNextNalu(&nalu);
2009 if (par_res == H264Parser::kEOStream)
2010 return kNeedMoreStreamData;
2011 else if (par_res != H264Parser::kOk)
2012 SET_ERROR_AND_RETURN();
2013
2014 DVLOG(4) << "NALU found: " << (int)nalu.nal_unit_type;
2015
2016 switch (nalu.nal_unit_type) {
2017 case kH264NaluNonIDRSlice:
2018 case kH264NaluIDRSlice: {
2019 H264SliceHeader slice_hdr;
2020
2021 par_res = parser_.ParseSliceHeader(&slice_hdr, &nalu);
2022 if (par_res != H264Parser::kOk)
2023 SET_ERROR_AND_RETURN();
2024
2025 if (!ProcessSlice(&slice_hdr))
2026 SET_ERROR_AND_RETURN();
2027 break;
2028 }
2029
2030 case kH264NaluSPS:
2031 int sps_id;
2032
2033 if (!FinishPrevFrameIfPresent())
2034 SET_ERROR_AND_RETURN();
2035
2036 par_res = parser_.ParseSPS(&sps_id);
2037 if (par_res != H264Parser::kOk)
2038 SET_ERROR_AND_RETURN();
2039
2040 if (!ProcessSPS(sps_id))
2041 SET_ERROR_AND_RETURN();
2042 break;
2043
2044 case kH264NaluPPS:
2045 int pps_id;
2046
2047 if (!FinishPrevFrameIfPresent())
2048 SET_ERROR_AND_RETURN();
2049
2050 par_res = parser_.ParsePPS(&pps_id);
2051 if (par_res != H264Parser::kOk)
2052 SET_ERROR_AND_RETURN();
2053
2054 if (!ProcessPPS(pps_id))
2055 SET_ERROR_AND_RETURN();
2056 break;
2057
2058 default:
2059 // skip NALU
2060 break;
2061 }
2062
2063 // If the last action resulted in decoding a frame, possibly from older
2064 // data, return. Otherwise keep reading the stream.
2065 if (frame_decoded_) {
2066 frame_decoded_ = false;
2067 return kDecodedFrame;
2068 }
2069 }
2070 }
2071
2072 // static
2073 int VaapiH264Decoder::GetRequiredNumOfPictures() {
2074 return kNumReqPictures;
2075 }
2076
2077 base::LazyInstance<GLXFBConfig> VaapiH264Decoder::DecodeSurface::fb_config_ =
2078 LAZY_INSTANCE_INITIALIZER;
2079 Display* VaapiH264Decoder::DecodeSurface::x_display_;
2080
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698