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

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 "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_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)
Ami GONE FROM CHROMIUM 2012/05/07 16:38:05 op goes on previous line
Pawel Osciak 2012/05/07 17:58:00 Will I ever get used to this? ;) Sorry, done.
860 || (slice_hdr->IsBSlice() && pps->weighted_bipred_idc == 1)) {
Ami GONE FROM CHROMIUM 2012/05/07 16:38:05 ditto
Pawel Osciak 2012/05/07 17:58:00 Done.
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 goto no_store;
1749 }
1750
1751 // Couldn't output current picture, so try to output the lowest PoC
1752 // from DPB.
1753 if (output_candidate != not_outputted.end()) {
1754 if (!OutputPic(*output_candidate))
1755 return false;
1756
1757 // If outputted picture wasn't a reference picture, it can be removed.
1758 if (!(*output_candidate)->ref)
1759 dpb_.RemoveByPOC((*output_candidate)->pic_order_cnt);
1760 } else {
1761 // Couldn't output current pic and couldn't do anything
1762 // with existing pictures in DPB, so we can't make space.
1763 // This should not happen.
1764 DVLOG(1) << "Could not free up space in DPB!";
1765 return false;
1766 }
1767 }
1768 ++output_candidate;
1769 }
1770
1771 // Store current picture for later output and/or reference (ownership now
1772 // with the DPB).
1773 dpb_.StorePic(curr_pic_.release());
1774
1775 no_store:
1776 return true;
1777 }
1778
1779 bool VaapiH264Decoder::ProcessSPS(int sps_id) {
1780 const H264SPS* sps = parser_.GetSPS(sps_id);
1781 DCHECK(sps);
1782
1783 if (sps->frame_mbs_only_flag == 0) {
1784 // Fields/interlaced video not supported.
1785 DVLOG(1) << "frame_mbs_only_flag != 1 not supported";
1786 return false;
1787 }
1788
1789 if (sps->gaps_in_frame_num_value_allowed_flag) {
1790 DVLOG(1) << "Gaps in frame numbers not supported";
1791 return false;
1792 }
1793
1794 if (sps->pic_order_cnt_type != 0) {
1795 DVLOG(1) << "Unsupported pic_order_cnt_type";
1796 return false;
1797 }
1798
1799 curr_sps_id_ = sps->seq_parameter_set_id;
1800
1801 // Calculate picture height/width (spec 7.4.2.1.1, 7.4.3).
1802 int width = 16 * (sps->pic_width_in_mbs_minus1 + 1);
1803 int height = 16 * (2 - sps->frame_mbs_only_flag) *
1804 (sps->pic_height_in_map_units_minus1 + 1);
1805
1806 if ((pic_width_ != -1 || pic_height_ != -1) &&
1807 (width != pic_width_ || height != pic_height_)) {
1808 DVLOG(1) << "Picture size changed mid-stream";
1809 return false;
1810 }
1811
1812 pic_width_ = width;
1813 pic_height_ = height;
1814 DVLOG(1) << "New picture size: " << pic_width_ << "x" << pic_height_;
1815
1816 max_pic_order_cnt_lsb_ = 1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4);
1817 max_frame_num_ = 1 << (sps->log2_max_frame_num_minus4 + 4);
1818
1819 return true;
1820 }
1821
1822 bool VaapiH264Decoder::ProcessPPS(int pps_id) {
1823 const H264PPS* pps = parser_.GetPPS(pps_id);
1824 DCHECK(pps);
1825
1826 curr_pps_id_ = pps->pic_parameter_set_id;
1827
1828 return true;
1829 }
1830
1831 bool VaapiH264Decoder::FinishPrevFrameIfPresent() {
1832 // If we already have a frame waiting to be decoded, decode it and finish.
1833 if (curr_pic_ != NULL) {
1834 if (!DecodePicture())
1835 return false;
1836 return FinishPicture();
1837 }
1838
1839 return true;
1840 }
1841
1842 bool VaapiH264Decoder::ProcessSlice(H264SliceHeader* slice_hdr) {
1843 prev_frame_num_ = frame_num_;
1844 frame_num_ = slice_hdr->frame_num;
1845
1846 if (prev_frame_num_ > 0 && prev_frame_num_ < frame_num_ - 1) {
1847 DVLOG(1) << "Gap in frame_num!";
1848 return false;
1849 }
1850
1851 if (slice_hdr->field_pic_flag == 0)
1852 max_pic_num_ = max_frame_num_;
1853 else
1854 max_pic_num_ = 2 * max_frame_num_;
1855
1856 // TODO posciak: switch to new picture detection per 7.4.1.2.4.
1857 if (curr_pic_ != NULL && slice_hdr->first_mb_in_slice != 0) {
1858 // This is just some more slice data of the current picture, so
1859 // just queue it and return.
1860 QueueSlice(slice_hdr);
1861 return true;
1862 } else {
1863 // A new frame, so first finish the previous one before processing it...
1864 if (!FinishPrevFrameIfPresent())
1865 return false;
1866
1867 // and then start a new one.
1868 return StartNewFrame(slice_hdr);
1869 }
1870 }
1871
1872 #define SET_ERROR_AND_RETURN() \
1873 do { \
1874 DVLOG(1) << "Error during decode"; \
1875 state_ = kError; \
1876 return VaapiH264Decoder::kDecodeError; \
1877 } while (0)
1878
1879 VaapiH264Decoder::DecResult VaapiH264Decoder::DecodeInitial(int32 input_id) {
1880 // Decode enough to get required picture size (i.e. until we find an SPS),
1881 // if we get any slice data, we are missing the beginning of the stream.
1882 H264NALU nalu;
1883 H264Parser::Result res;
1884
1885 DCHECK_NE(state_, kUninitialized);
1886
1887 curr_input_id_ = input_id;
1888
1889 while (1) {
1890 // Get next NALU looking for SPS or IDR if after reset.
1891 res = parser_.AdvanceToNextNALU(&nalu);
1892 if (res == H264Parser::kEOStream) {
1893 DVLOG(1) << "Could not find SPS before EOS";
1894 return kNeedMoreStreamData;
1895 } else if (res != H264Parser::kOk) {
1896 SET_ERROR_AND_RETURN();
1897 }
1898
1899 DVLOG(4) << " NALU found: " << static_cast<int>(nalu.nal_unit_type);
1900
1901 switch (nalu.nal_unit_type) {
1902 case H264NALU::kSPS:
1903 res = parser_.ParseSPS(&curr_sps_id_);
1904 if (res != H264Parser::kOk)
1905 SET_ERROR_AND_RETURN();
1906
1907 if (!ProcessSPS(curr_sps_id_))
1908 SET_ERROR_AND_RETURN();
1909
1910 // Just got information about the video size from SPS, so we can
1911 // now allocate surfaces and let the client now we are ready to
1912 // accept output buffers and decode.
1913 if (!CreateVASurfaces())
1914 SET_ERROR_AND_RETURN();
1915
1916 state_ = kDecoding;
1917 return kReadyToDecode;
1918
1919 case H264NALU::kIDRSlice:
1920 // If after reset, should be able to recover from an IDR.
1921 if (state_ == kAfterReset) {
1922 H264SliceHeader slice_hdr;
1923
1924 res = parser_.ParseSliceHeader(&nalu, &slice_hdr);
1925 if (res != H264Parser::kOk)
1926 SET_ERROR_AND_RETURN();
1927
1928 if (!ProcessSlice(&slice_hdr))
1929 SET_ERROR_AND_RETURN();
1930
1931 state_ = kDecoding;
1932 return kReadyToDecode;
1933 } // else fallthrough
1934 case H264NALU::kNonIDRSlice:
1935 case H264NALU::kPPS:
1936 // Non-IDR slices cannot be used as resume points, as we may not
1937 // have all reference pictures that they may require.
1938 // fallthrough
1939 default:
1940 // Skip everything unless it's PPS or an IDR slice (if after reset).
1941 DVLOG(4) << "Skipping NALU";
1942 break;
1943 }
1944 }
1945 }
1946
1947 void VaapiH264Decoder::SetStream(uint8* ptr, size_t size) {
1948 DCHECK(ptr);
1949 DCHECK(size);
1950
1951 // Got new input stream data from the client.
1952 DVLOG(4) << "New input stream chunk at " << (void*) ptr
1953 << " size: " << size;
1954 parser_.SetStream(ptr, size);
1955 }
1956
1957 VaapiH264Decoder::DecResult VaapiH264Decoder::DecodeOneFrame(int32 input_id) {
1958 // Decode until one full frame is decoded or return it or until end
1959 // of stream (end of input data is reached).
1960 H264Parser::Result par_res;
1961 H264NALU nalu;
1962
1963 curr_input_id_ = input_id;
1964
1965 if (state_ != kDecoding) {
1966 DVLOG(1) << "Decoder not ready: error in stream or not initialized";
1967 return kDecodeError;
1968 } else if (num_available_decode_surfaces_ < 1) {
1969 DVLOG(4) << "No output surfaces available";
1970 return kNoOutputAvailable;
1971 }
1972
1973 // All of the actions below might result in decoding a picture from
1974 // previously parsed data, but we still have to handle/parse current input
1975 // first.
1976 // Note: this may drop some already decoded frames if there are errors
1977 // further in the stream, but we are OK with that.
1978 while (1) {
1979 par_res = parser_.AdvanceToNextNALU(&nalu);
1980 if (par_res == H264Parser::kEOStream)
1981 return kNeedMoreStreamData;
1982 else if (par_res != H264Parser::kOk)
1983 SET_ERROR_AND_RETURN();
1984
1985 DVLOG(4) << "NALU found: " << static_cast<int>(nalu.nal_unit_type);
1986
1987 switch (nalu.nal_unit_type) {
1988 case H264NALU::kNonIDRSlice:
1989 case H264NALU::kIDRSlice: {
1990 H264SliceHeader slice_hdr;
1991
1992 par_res = parser_.ParseSliceHeader(&nalu, &slice_hdr);
1993 if (par_res != H264Parser::kOk)
1994 SET_ERROR_AND_RETURN();
1995
1996 if (!ProcessSlice(&slice_hdr))
1997 SET_ERROR_AND_RETURN();
1998 break;
1999 }
2000
2001 case H264NALU::kSPS:
2002 int sps_id;
2003
2004 if (!FinishPrevFrameIfPresent())
2005 SET_ERROR_AND_RETURN();
2006
2007 par_res = parser_.ParseSPS(&sps_id);
2008 if (par_res != H264Parser::kOk)
2009 SET_ERROR_AND_RETURN();
2010
2011 if (!ProcessSPS(sps_id))
2012 SET_ERROR_AND_RETURN();
2013 break;
2014
2015 case H264NALU::kPPS:
2016 int pps_id;
2017
2018 if (!FinishPrevFrameIfPresent())
2019 SET_ERROR_AND_RETURN();
2020
2021 par_res = parser_.ParsePPS(&pps_id);
2022 if (par_res != H264Parser::kOk)
2023 SET_ERROR_AND_RETURN();
2024
2025 if (!ProcessPPS(pps_id))
2026 SET_ERROR_AND_RETURN();
2027 break;
2028
2029 default:
2030 // skip NALU
2031 break;
2032 }
2033
2034 // If the last action resulted in decoding a frame, possibly from older
2035 // data, return. Otherwise keep reading the stream.
2036 if (frame_ready_at_hw_) {
2037 frame_ready_at_hw_ = false;
2038 return kDecodedFrame;
2039 }
2040 }
2041 }
2042
2043 // static
2044 size_t VaapiH264Decoder::GetRequiredNumOfPictures() {
2045 return kNumReqPictures;
2046 }
2047
2048 } // namespace content
2049
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698