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

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

Powered by Google App Engine
This is Rietveld 408576698