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

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: Addressing previous CR + threading redesign 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 \
Ami GONE FROM CHROMIUM 2012/05/03 23:22:53 trailing space
Pawel Osciak 2012/05/06 17:49:19 Done (wasn't there).
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 Get(int32 input_id, int poc);
193
194 // Make this surface available, ready to be reused.
195 void Put();
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::Get(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::Put() {
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 ++it;
Ami GONE FROM CHROMIUM 2012/05/03 23:22:53 Comment this must be done before the UnassignSurfa
Pawel Osciak 2012/05/06 17:49:19 Done.
355 DecodeSurface *dec_surface = UnassignSurfaceFromPoC(poc);
356 if (dec_surface) {
357 dec_surface->Put();
358 ++num_available_decode_surfaces_;
Ami GONE FROM CHROMIUM 2012/05/03 23:22:53 IWBN if ++num_available_decode_surfaces_ could be
Pawel Osciak 2012/05/06 17:49:19 Yeah, I tried, but didn't see a way around this :(
359 }
360 }
361 DCHECK(poc_to_decode_surfaces_.empty());
362
363 dpb_.Clear();
364 parser_.Reset();
365
366 // Still initialized and ready to decode, unless called from constructor,
367 // which will change it back.
368 state_ = kAfterReset;
369 }
370
371 void VaapiH264Decoder::Destroy() {
372 VAStatus va_res;
373
374 if (state_ == kUninitialized)
375 return;
376
377 switch (state_) {
378 case kDecoding:
379 case kAfterReset:
380 case kError:
381 DestroyVASurfaces();
382 // fallthrough
383 case kInitialized:
384 va_res = VAAPI_DestroyConfig(va_display_, va_config_id_);
385 VA_LOG_ON_ERROR(va_res, "vaDestroyConfig failed");
386 va_res = VAAPI_Terminate(va_display_);
387 VA_LOG_ON_ERROR(va_res, "vaTerminate failed");
388 // fallthrough
389 case kUninitialized:
390 break;
391 }
392
393 state_ = kUninitialized;
394 }
395
396 // Maps Profile enum values to VaProfile values.
397 bool VaapiH264Decoder::SetProfile(media::VideoCodecProfile profile) {
398 switch (profile) {
399 case media::H264PROFILE_BASELINE:
400 profile_ = VAProfileH264Baseline;
401 break;
402 case media::H264PROFILE_MAIN:
403 profile_ = VAProfileH264Main;
404 break;
405 case media::H264PROFILE_HIGH:
406 profile_ = VAProfileH264High;
407 break;
408 default:
409 return false;
410 }
411 return true;
412 }
413
414 class ScopedPtrXFree {
415 public:
416 void operator()(void* x) const {
417 ::XFree(x);
418 }
419 };
420
421 bool VaapiH264Decoder::InitializeFBConfig() {
422 const int fbconfig_attr[] = {
423 GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
424 GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
425 GLX_BIND_TO_TEXTURE_RGB_EXT, GL_TRUE,
426 GLX_Y_INVERTED_EXT, GL_TRUE,
427 GL_NONE,
428 };
429
430 int num_fbconfigs;
431 scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> glx_fb_configs(
432 glXChooseFBConfig(x_display_, DefaultScreen(x_display_), fbconfig_attr,
433 &num_fbconfigs));
434 if (!glx_fb_configs.get())
435 return false;
436 if (!num_fbconfigs)
437 return false;
438
439 fb_config_ = glx_fb_configs.get()[0];
440 return true;
441 }
442
443 bool VaapiH264Decoder::Initialize(media::VideoCodecProfile profile,
444 Display* x_display,
445 GLXContext glx_context,
446 const OutputPicCB& output_pic_cb) {
447 DCHECK_EQ(state_, kUninitialized);
448
449 output_pic_cb_ = output_pic_cb;
450
451 x_display_ = x_display;
452 parent_glx_context_ = glx_context;
453
454 if (!SetProfile(profile)) {
455 DVLOG(1) << "Unsupported profile";
456 return false;
457 }
458
459 if (!AreVaapiFunctionPointersInitialized()) {
460 DVLOG(1) << "Could not load libva";
461 return false;
462 }
463
464 if (!InitializeFBConfig()) {
465 DVLOG(1) << "Could not get a usable FBConfig";
466 return false;
467 }
468
469 va_display_ = VAAPI_GetDisplayGLX(x_display_);
470 if (!VAAPI_DisplayIsValid(va_display_)) {
471 DVLOG(1) << "Could not get a valid VA display";
472 return false;
473 }
474
475 int major_version, minor_version;
476 VAStatus va_res;
477 va_res = VAAPI_Initialize(va_display_, &major_version, &minor_version);
478 VA_SUCCESS_OR_RETURN(va_res, "vaInitialize failed", false);
479 DVLOG(1) << "VAAPI version: " << major_version << "." << minor_version;
480
481 VAConfigAttrib attrib;
482 attrib.type = VAConfigAttribRTFormat;
483
484 VAEntrypoint entrypoint = VAEntrypointVLD;
485 va_res = VAAPI_GetConfigAttributes(va_display_, profile_, entrypoint,
486 &attrib, 1);
487 VA_SUCCESS_OR_RETURN(va_res, "vaGetConfigAttributes failed", false);
488
489 if (!(attrib.value & VA_RT_FORMAT_YUV420)) {
490 DVLOG(1) << "YUV420 not supported";
491 return false;
492 }
493
494 va_res = VAAPI_CreateConfig(va_display_, profile_, entrypoint,
495 &attrib, 1, &va_config_id_);
496 VA_SUCCESS_OR_RETURN(va_res, "vaCreateConfig failed", false);
497
498 state_ = kInitialized;
499 return true;
500 }
501
502 void VaapiH264Decoder::ReusePictureBuffer(int32 picture_buffer_id) {
503 DecodeSurfaces::iterator it = decode_surfaces_.find(picture_buffer_id);
504 if (it == decode_surfaces_.end() || it->second->available()) {
505 DVLOG(1) << "Asked to reuse an invalid/already available surface";
506 return;
507 }
508 it->second->Put();
509 ++num_available_decode_surfaces_;
510 }
511
512 bool VaapiH264Decoder::AssignPictureBuffer(int32 picture_buffer_id,
513 uint32 texture_id) {
514 DCHECK_EQ(state_, kDecoding);
515
516 if (decode_surfaces_.size() >= GetRequiredNumOfPictures()) {
517 DVLOG(1) << "Got more surfaces than required";
518 return false;
519 }
520
521 // This will not work if we start using VDA.DismissPicture()
522 linked_ptr<DecodeSurface> dec_surface(new DecodeSurface(
523 fb_config_, x_display_, va_display_,
524 va_surface_ids_[decode_surfaces_.size()], picture_buffer_id, texture_id,
525 pic_width_, pic_height_));
526 if (!dec_surface->available()) {
527 DVLOG(1) << "Error creating a decoding surface (binding to texture?)";
528 return false;
529 }
530
531 DVLOG(2) << "New picture assigned, texture id: " << dec_surface->texture_id()
532 << " pic buf id: " << dec_surface->picture_buffer_id()
533 << " will use va surface " << dec_surface->va_surface_id();
534
535 bool inserted = decode_surfaces_.insert(std::make_pair(picture_buffer_id,
536 dec_surface)).second;
537 DCHECK(inserted);
538 ++num_available_decode_surfaces_;
539
540 return true;
541 }
542
543 bool VaapiH264Decoder::CreateVASurfaces() {
544 DCHECK_NE(pic_width_, -1);
545 DCHECK_NE(pic_height_, -1);
546 DCHECK_EQ(state_, kInitialized);
547
548 // Allocate VASurfaces in driver.
549 VAStatus va_res = VAAPI_CreateSurfaces(va_display_, pic_width_,
550 pic_height_, VA_RT_FORMAT_YUV420,
551 GetRequiredNumOfPictures(),
552 va_surface_ids_);
553 VA_SUCCESS_OR_RETURN(va_res, "vaCreateSurfaces failed", false);
554
555 DCHECK(decode_surfaces_.empty());
556
557 // And create a context associated with them.
558 va_res = VAAPI_CreateContext(va_display_, va_config_id_,
559 pic_width_, pic_height_, VA_PROGRESSIVE,
560 va_surface_ids_, GetRequiredNumOfPictures(),
561 &va_context_id_);
562 VA_SUCCESS_OR_RETURN(va_res, "vaCreateContext failed", false);
563
564 return true;
565 }
566
567 void VaapiH264Decoder::DestroyVASurfaces() {
568 DCHECK(state_ == kDecoding || state_ == kError || state_ == kAfterReset);
569
570 decode_surfaces_.clear();
571
572 VAStatus va_res = VAAPI_DestroyContext(va_display_, va_context_id_);
573 VA_LOG_ON_ERROR(va_res, "vaDestroyContext failed");
574
575 va_res = VAAPI_DestroySurfaces(va_display_, va_surface_ids_,
576 GetRequiredNumOfPictures());
577 VA_LOG_ON_ERROR(va_res, "vaDestroySurfaces failed");
578 }
579
580 // Fill |va_pic| with default/neutral values.
581 static void InitVAPicture(VAPictureH264* va_pic) {
582 memset(va_pic, 0, sizeof(*va_pic));
583 va_pic->picture_id = VA_INVALID_ID;
584 va_pic->flags = VA_PICTURE_H264_INVALID;
585 }
586
587 void VaapiH264Decoder::FillVAPicture(VAPictureH264 *va_pic, H264Picture* pic) {
588 POCToDecodeSurfaces::iterator iter = poc_to_decode_surfaces_.find(
589 pic->pic_order_cnt);
590 if (iter == poc_to_decode_surfaces_.end()) {
591 DVLOG(1) << "Could not find surface with POC: " << pic->pic_order_cnt;
592 // Cannot provide a ref picture, will corrupt output, but may be able
593 // to recover.
594 InitVAPicture(va_pic);
595 return;
596 }
597
598 va_pic->picture_id = iter->second->va_surface_id();
599 va_pic->frame_idx = pic->frame_num;
600 va_pic->flags = 0;
601
602 switch (pic->field) {
603 case H264Picture::FIELD_NONE:
604 break;
605 case H264Picture::FIELD_TOP:
606 va_pic->flags |= VA_PICTURE_H264_TOP_FIELD;
607 break;
608 case H264Picture::FIELD_BOTTOM:
609 va_pic->flags |= VA_PICTURE_H264_BOTTOM_FIELD;
610 break;
611 }
612
613 if (pic->ref) {
614 va_pic->flags |= pic->long_term ? VA_PICTURE_H264_LONG_TERM_REFERENCE
615 : VA_PICTURE_H264_SHORT_TERM_REFERENCE;
616 }
617
618 va_pic->TopFieldOrderCnt = pic->top_field_order_cnt;
619 va_pic->BottomFieldOrderCnt = pic->bottom_field_order_cnt;
620 }
621
622 int VaapiH264Decoder::FillVARefFramesFromDPB(VAPictureH264 *va_pics,
623 int num_pics) {
624 H264DPB::Pictures::reverse_iterator rit;
625 int i;
626
627 // Return reference frames in reverse order of insertion.
628 // Libva does not document this, but other implementations (e.g. mplayer)
629 // do it this way as well.
630 for (rit = dpb_.rbegin(), i = 0; rit != dpb_.rend() && i < num_pics; ++rit) {
631 if ((*rit)->ref)
632 FillVAPicture(&va_pics[i++], *rit);
633 }
634
635 return i;
636 }
637
638 // Can only be called when all surfaces are already bound
639 // to textures (cannot be run at the same time as AssignPictureBuffer).
640 bool VaapiH264Decoder::AssignSurfaceToPoC(int poc) {
641 // Find a surface not currently holding data used for reference and/or
642 // to be displayed and mark it as used.
643 DecodeSurfaces::iterator iter = decode_surfaces_.begin();
644 for (; iter != decode_surfaces_.end(); ++iter) {
645 if (iter->second->available()) {
646 --num_available_decode_surfaces_;
647 DCHECK_GE(num_available_decode_surfaces_, 0);
648
649 // Associate with input id and poc and mark as unavailable.
650 iter->second->Get(curr_input_id_, poc);
651 DVLOG(4) << "Will use surface " << iter->second->va_surface_id()
652 << " for POC " << iter->second->poc()
653 << " input ID: " << iter->second->input_id();
654 bool inserted = poc_to_decode_surfaces_.insert(std::make_pair(poc,
655 iter->second.get())).second;
656 DCHECK(inserted);
657 return true;
658 }
659 }
660
661 // Could not find an available surface.
662 return false;
663 }
664
665 // Can only be called when all surfaces are already bound
666 // to textures (cannot be run at the same time as AssignPictureBuffer).
667 VaapiH264Decoder::DecodeSurface* VaapiH264Decoder::UnassignSurfaceFromPoC(
668 int poc) {
669 DecodeSurface* dec_surface;
670 POCToDecodeSurfaces::iterator it = poc_to_decode_surfaces_.find(poc);
671 if (it == poc_to_decode_surfaces_.end()) {
672 DVLOG(1) << "Asked to unassign an unassigned POC";
673 return NULL;
674 }
675 dec_surface = it->second;
676 DVLOG(4) << "POC " << poc << " no longer using surface "
677 << dec_surface->va_surface_id();
678 poc_to_decode_surfaces_.erase(it);
679 return dec_surface;
680 }
681
682 // Fill a VAPictureParameterBufferH264 to be later sent to the HW decoder.
683 bool VaapiH264Decoder::SendPPS() {
684 const H264PPS* pps = parser_.GetPPS(curr_pps_id_);
685 DCHECK(pps);
686
687 const H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id);
688 DCHECK(sps);
689
690 DCHECK(curr_pic_.get());
691
692 VAPictureParameterBufferH264 pic_param;
693 memset(&pic_param, 0, sizeof(VAPictureParameterBufferH264));
694
695 #define FROM_SPS_TO_PP(a) pic_param.a = sps->a;
696 #define FROM_SPS_TO_PP2(a, b) pic_param.b = sps->a;
697 FROM_SPS_TO_PP2(pic_width_in_mbs_minus1, picture_width_in_mbs_minus1);
698 // This assumes non-interlaced video
699 FROM_SPS_TO_PP2(pic_height_in_map_units_minus1,
700 picture_height_in_mbs_minus1);
701 FROM_SPS_TO_PP(bit_depth_luma_minus8);
702 FROM_SPS_TO_PP(bit_depth_chroma_minus8);
703 #undef FROM_SPS_TO_PP
704 #undef FROM_SPS_TO_PP2
705
706 #define FROM_SPS_TO_PP_SF(a) pic_param.seq_fields.bits.a = sps->a;
707 #define FROM_SPS_TO_PP_SF2(a, b) pic_param.seq_fields.bits.b = sps->a;
708 FROM_SPS_TO_PP_SF(chroma_format_idc);
709 FROM_SPS_TO_PP_SF2(separate_colour_plane_flag,
710 residual_colour_transform_flag);
711 FROM_SPS_TO_PP_SF(gaps_in_frame_num_value_allowed_flag);
712 FROM_SPS_TO_PP_SF(frame_mbs_only_flag);
713 FROM_SPS_TO_PP_SF(mb_adaptive_frame_field_flag);
714 FROM_SPS_TO_PP_SF(direct_8x8_inference_flag);
715 pic_param.seq_fields.bits.MinLumaBiPredSize8x8 = (sps->level_idc >= 31);
716 FROM_SPS_TO_PP_SF(log2_max_frame_num_minus4);
717 FROM_SPS_TO_PP_SF(pic_order_cnt_type);
718 FROM_SPS_TO_PP_SF(log2_max_pic_order_cnt_lsb_minus4);
719 FROM_SPS_TO_PP_SF(delta_pic_order_always_zero_flag);
720 #undef FROM_SPS_TO_PP_SF
721 #undef FROM_SPS_TO_PP_SF2
722
723 #define FROM_PPS_TO_PP(a) pic_param.a = pps->a;
724 FROM_PPS_TO_PP(num_slice_groups_minus1);
725 pic_param.slice_group_map_type = 0;
726 pic_param.slice_group_change_rate_minus1 = 0;
727 FROM_PPS_TO_PP(pic_init_qp_minus26);
728 FROM_PPS_TO_PP(pic_init_qs_minus26);
729 FROM_PPS_TO_PP(chroma_qp_index_offset);
730 FROM_PPS_TO_PP(second_chroma_qp_index_offset);
731 #undef FROM_PPS_TO_PP
732
733 #define FROM_PPS_TO_PP_PF(a) pic_param.pic_fields.bits.a = pps->a;
734 #define FROM_PPS_TO_PP_PF2(a, b) pic_param.pic_fields.bits.b = pps->a;
735 FROM_PPS_TO_PP_PF(entropy_coding_mode_flag);
736 FROM_PPS_TO_PP_PF(weighted_pred_flag);
737 FROM_PPS_TO_PP_PF(weighted_bipred_idc);
738 FROM_PPS_TO_PP_PF(transform_8x8_mode_flag);
739
740 pic_param.pic_fields.bits.field_pic_flag = 0;
741 FROM_PPS_TO_PP_PF(constrained_intra_pred_flag);
742 FROM_PPS_TO_PP_PF2(bottom_field_pic_order_in_frame_present_flag,
743 pic_order_present_flag);
744 FROM_PPS_TO_PP_PF(deblocking_filter_control_present_flag);
745 FROM_PPS_TO_PP_PF(redundant_pic_cnt_present_flag);
746 pic_param.pic_fields.bits.reference_pic_flag = curr_pic_->ref;
747 #undef FROM_PPS_TO_PP_PF
748 #undef FROM_PPS_TO_PP_PF2
749
750 pic_param.frame_num = curr_pic_->frame_num;
751
752 InitVAPicture(&pic_param.CurrPic);
753 FillVAPicture(&pic_param.CurrPic, curr_pic_.get());
754
755 // Init reference pictures' array.
756 for (int i = 0; i < 16; ++i)
757 InitVAPicture(&pic_param.ReferenceFrames[i]);
758
759 // And fill it with picture info from DPB.
760 FillVARefFramesFromDPB(pic_param.ReferenceFrames,
761 arraysize(pic_param.ReferenceFrames));
762
763 pic_param.num_ref_frames = sps->max_num_ref_frames;
764
765 // Allocate a buffer in driver for this parameter buffer and upload data.
766 VABufferID pic_param_buf_id;
767 VAStatus va_res = VAAPI_CreateBuffer(va_display_, va_context_id_,
768 VAPictureParameterBufferType,
769 sizeof(VAPictureParameterBufferH264),
770 1, &pic_param, &pic_param_buf_id);
771 VA_SUCCESS_OR_RETURN(va_res, "Failed to create a buffer for PPS", false);
772
773 // Queue its VA buffer ID to be committed on HW decode run.
774 pending_va_bufs_.push(pic_param_buf_id);
775
776 return true;
777 }
778
779 // Fill a VAIQMatrixBufferH264 to be later sent to the HW decoder.
780 bool VaapiH264Decoder::SendIQMatrix() {
781 const H264PPS* pps = parser_.GetPPS(curr_pps_id_);
782 DCHECK(pps);
783
784 VAIQMatrixBufferH264 iq_matrix_buf;
785 memset(&iq_matrix_buf, 0, sizeof(VAIQMatrixBufferH264));
786
787 if (pps->pic_scaling_matrix_present_flag) {
788 for (int i = 0; i < 6; ++i) {
789 for (int j = 0; j < 16; ++j)
790 iq_matrix_buf.ScalingList4x4[i][j] = pps->scaling_list4x4[i][j];
791 }
792
793 for (int i = 0; i < 2; ++i) {
794 for (int j = 0; j < 64; ++j)
795 iq_matrix_buf.ScalingList8x8[i][j] = pps->scaling_list8x8[i][j];
796 }
797 } else {
798 const H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id);
799 DCHECK(sps);
800 for (int i = 0; i < 6; ++i) {
801 for (int j = 0; j < 16; ++j)
802 iq_matrix_buf.ScalingList4x4[i][j] = sps->scaling_list4x4[i][j];
803 }
804
805 for (int i = 0; i < 2; ++i) {
806 for (int j = 0; j < 64; ++j)
807 iq_matrix_buf.ScalingList8x8[i][j] = sps->scaling_list8x8[i][j];
808 }
809 }
810
811 // Allocate a buffer in driver for this parameter buffer and upload data.
812 VABufferID iq_matrix_buf_id;
813 VAStatus va_res = VAAPI_CreateBuffer(va_display_, va_context_id_,
814 VAIQMatrixBufferType,
815 sizeof(VAIQMatrixBufferH264), 1,
816 &iq_matrix_buf, &iq_matrix_buf_id);
817 VA_SUCCESS_OR_RETURN(va_res, "Failed to create a buffer for IQMatrix",
818 false);
819
820 // Queue its VA buffer ID to be committed on HW decode run.
821 pending_va_bufs_.push(iq_matrix_buf_id);
822
823 return true;
824 }
825
826 bool VaapiH264Decoder::SendVASliceParam(H264SliceHeader* slice_hdr) {
827 const H264PPS* pps = parser_.GetPPS(slice_hdr->pic_parameter_set_id);
828 DCHECK(pps);
829
830 const H264SPS* sps = parser_.GetSPS(pps->seq_parameter_set_id);
831 DCHECK(sps);
832
833 VASliceParameterBufferH264 slice_param;
834 memset(&slice_param, 0, sizeof(VASliceParameterBufferH264));
835
836 slice_param.slice_data_size = slice_hdr->nalu_size;
837 slice_param.slice_data_offset = 0;
838 slice_param.slice_data_flag = VA_SLICE_DATA_FLAG_ALL;
839 slice_param.slice_data_bit_offset = slice_hdr->header_bit_size;
840
841 #define SHDRToSP(a) slice_param.a = slice_hdr->a;
842 SHDRToSP(first_mb_in_slice);
843 slice_param.slice_type = slice_hdr->slice_type % 5;
844 SHDRToSP(direct_spatial_mv_pred_flag);
845
846 // TODO posciak: make sure parser sets those even when override flags
847 // in slice header is off.
848 SHDRToSP(num_ref_idx_l0_active_minus1);
849 SHDRToSP(num_ref_idx_l1_active_minus1);
850 SHDRToSP(cabac_init_idc);
851 SHDRToSP(slice_qp_delta);
852 SHDRToSP(disable_deblocking_filter_idc);
853 SHDRToSP(slice_alpha_c0_offset_div2);
854 SHDRToSP(slice_beta_offset_div2);
855
856 if (((IsH264PSlice(slice_hdr) || IsH264SPSlice(slice_hdr))
857 && pps->weighted_pred_flag)
858 || (IsH264BSlice(slice_hdr) && pps->weighted_bipred_idc == 1)) {
859 SHDRToSP(luma_log2_weight_denom);
860 SHDRToSP(chroma_log2_weight_denom);
861
862 SHDRToSP(luma_weight_l0_flag);
863 SHDRToSP(luma_weight_l1_flag);
864
865 SHDRToSP(chroma_weight_l0_flag);
866 SHDRToSP(chroma_weight_l1_flag);
867
868 for (int i = 0; i <= slice_param.num_ref_idx_l0_active_minus1; ++i) {
869 slice_param.luma_weight_l0[i] =
870 slice_hdr->pred_weight_table_l0.luma_weight[i];
871 slice_param.luma_offset_l0[i] =
872 slice_hdr->pred_weight_table_l0.luma_offset[i];
873
874 for (int j = 0; j < 2; ++j) {
875 slice_param.chroma_weight_l0[i][j] =
876 slice_hdr->pred_weight_table_l0.chroma_weight[i][j];
877 slice_param.chroma_offset_l0[i][j] =
878 slice_hdr->pred_weight_table_l0.chroma_offset[i][j];
879 }
880 }
881
882 if (IsH264BSlice(slice_hdr)) {
883 for (int i = 0; i <= slice_param.num_ref_idx_l1_active_minus1; ++i) {
884 slice_param.luma_weight_l1[i] =
885 slice_hdr->pred_weight_table_l1.luma_weight[i];
886 slice_param.luma_offset_l1[i] =
887 slice_hdr->pred_weight_table_l1.luma_offset[i];
888
889 for (int j = 0; j < 2; ++j) {
890 slice_param.chroma_weight_l1[i][j] =
891 slice_hdr->pred_weight_table_l1.chroma_weight[i][j];
892 slice_param.chroma_offset_l1[i][j] =
893 slice_hdr->pred_weight_table_l1.chroma_offset[i][j];
894 }
895 }
896 }
897 }
898
899 for (int i = 0; i < 32; ++i) {
900 InitVAPicture(&slice_param.RefPicList0[i]);
901 InitVAPicture(&slice_param.RefPicList1[i]);
902 }
903
904 int i;
905 H264Picture::PtrVector::iterator it;
906 for (it = ref_pic_list0_.begin(), i = 0; it != ref_pic_list0_.end();
907 ++it, ++i)
908 FillVAPicture(&slice_param.RefPicList0[i], *it);
909 for (it = ref_pic_list1_.begin(), i = 0; it != ref_pic_list1_.end();
910 ++it, ++i)
911 FillVAPicture(&slice_param.RefPicList1[i], *it);
912
913 // Allocate a buffer in driver for this parameter buffer and upload data.
914 VABufferID slice_param_buf_id;
915 VAStatus va_res = VAAPI_CreateBuffer(va_display_, va_context_id_,
916 VASliceParameterBufferType,
917 sizeof(VASliceParameterBufferH264),
918 1, &slice_param, &slice_param_buf_id);
919 VA_SUCCESS_OR_RETURN(va_res, "Failed creating a buffer for slice param",
920 false);
921
922 // Queue its VA buffer ID to be committed on HW decode run.
923 pending_slice_bufs_.push(slice_param_buf_id);
924
925 return true;
926 }
927
928 bool VaapiH264Decoder::SendSliceData(const uint8* ptr, size_t size)
929 {
930 // Can't help it, blame libva...
931 void* non_const_ptr = const_cast<uint8*>(ptr);
932
933 VABufferID slice_data_buf_id;
934 VAStatus va_res = VAAPI_CreateBuffer(va_display_, va_context_id_,
935 VASliceDataBufferType, size, 1,
936 non_const_ptr, &slice_data_buf_id);
937 VA_SUCCESS_OR_RETURN(va_res, "Failed creating a buffer for slice data",
938 false);
939
940 pending_slice_bufs_.push(slice_data_buf_id);
941 return true;
942 }
943
944 bool VaapiH264Decoder::QueueSlice(H264SliceHeader* slice_hdr) {
945 DCHECK(curr_pic_.get());
946
947 if (!SendVASliceParam(slice_hdr))
948 return false;
949
950 if (!SendSliceData(slice_hdr->nalu_data, slice_hdr->nalu_size))
951 return false;
952
953 return true;
954 }
955
956 // TODO(posciak) start using vaMapBuffer instead of vaCreateBuffer wherever
957 // possible.
958
959 bool VaapiH264Decoder::DecodePicture() {
960 DCHECK(!frame_ready_at_hw_);
961 DCHECK(curr_pic_.get());
962
963 static const size_t kMaxVABuffers = 32;
964 DCHECK_LE(pending_va_bufs_.size(), kMaxVABuffers);
965 DCHECK_LE(pending_slice_bufs_.size(), kMaxVABuffers);
966
967 DVLOG(4) << "Pending VA bufs to commit: " << pending_va_bufs_.size();
968 DVLOG(4) << "Pending slice bufs to commit: " << pending_slice_bufs_.size();
969
970 // Find the surface associated with the picture to be decoded.
971 DCHECK(pending_slice_bufs_.size());
972 DecodeSurface* dec_surface =
973 poc_to_decode_surfaces_[curr_pic_->pic_order_cnt];
974 DVLOG(4) << "Decoding POC " << curr_pic_->pic_order_cnt
975 << " into surface " << dec_surface->va_surface_id();
976
977 // Get ready to decode into surface.
978 VAStatus va_res = VAAPI_BeginPicture(va_display_, va_context_id_,
979 dec_surface->va_surface_id());
980 VA_SUCCESS_OR_RETURN(va_res, "vaBeginPicture failed", false);
981
982 // Put buffer IDs for pending parameter buffers into buffers[].
983 VABufferID buffers[kMaxVABuffers];
984 size_t num_buffers = pending_va_bufs_.size();
985 for (size_t i = 0; i < num_buffers && i < kMaxVABuffers; ++i) {
986 buffers[i] = pending_va_bufs_.front();
987 pending_va_bufs_.pop();
988 }
989
990 // And send them to the HW decoder.
991 va_res = VAAPI_RenderPicture(va_display_, va_context_id_, buffers,
992 num_buffers);
993 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for va_bufs failed", false);
994
995 DVLOG(4) << "Committed " << num_buffers << "VA buffers";
996
997 // Put buffer IDs for pending slice data buffers into buffers[].
998 num_buffers = pending_slice_bufs_.size();
999 for (size_t i = 0; i < num_buffers && i < kMaxVABuffers; ++i) {
1000 buffers[i] = pending_slice_bufs_.front();
1001 pending_slice_bufs_.pop();
1002 }
1003
1004 // And send them to the Hw decoder.
1005 va_res = VAAPI_RenderPicture(va_display_, va_context_id_, buffers,
1006 num_buffers);
1007 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture fo slices failed", false);
1008
1009 DVLOG(4) << "Committed " << num_buffers << "slice buffers";
1010
1011 // Instruct HW decoder to start processing committed buffers (decode this
1012 // picture). This does not block until the end of decode.
1013 va_res = VAAPI_EndPicture(va_display_, va_context_id_);
1014 VA_SUCCESS_OR_RETURN(va_res, "vaEndPicture failed", false);
1015
1016 // Used to notify clients that we had sufficient data to start decoding
1017 // a new frame.
1018 frame_ready_at_hw_ = true;
1019 return true;
1020 }
1021
1022
1023 bool VaapiH264Decoder::InitCurrPicture(H264SliceHeader* slice_hdr) {
1024 DCHECK(curr_pic_.get());
1025
1026 memset(curr_pic_.get(), 0, sizeof(H264Picture));
1027
1028 curr_pic_->idr = slice_hdr->idr_pic_flag;
1029
1030 if (slice_hdr->field_pic_flag) {
1031 curr_pic_->field = slice_hdr->bottom_field_flag ? H264Picture::FIELD_BOTTOM
1032 : H264Picture::FIELD_TOP;
1033 } else {
1034 curr_pic_->field = H264Picture::FIELD_NONE;
1035 }
1036
1037 curr_pic_->ref = slice_hdr->nal_ref_idc != 0;
1038 // This assumes non-interlaced stream.
1039 curr_pic_->frame_num = curr_pic_->pic_num = slice_hdr->frame_num;
1040
1041 if (!CalculatePicOrderCounts(slice_hdr))
1042 return false;
1043
1044 // Try to get an empty surface to decode this picture to.
1045 if (!AssignSurfaceToPoC(curr_pic_->pic_order_cnt)) {
1046 DVLOG(1) << "Failed getting a free surface for a picture";
1047 return false;
1048 }
1049
1050 curr_pic_->long_term_reference_flag = slice_hdr->long_term_reference_flag;
1051 curr_pic_->adaptive_ref_pic_marking_mode_flag =
1052 slice_hdr->adaptive_ref_pic_marking_mode_flag;
1053
1054 // If the slice header indicates we will have to perform reference marking
1055 // process after this picture is decoded, store required data for that
1056 // purpose.
1057 if (slice_hdr->adaptive_ref_pic_marking_mode_flag) {
1058 COMPILE_ASSERT(sizeof(curr_pic_->ref_pic_marking) ==
1059 sizeof(slice_hdr->ref_pic_marking),
1060 ref_pic_marking_array_sizes_do_not_match);
1061 memcpy(curr_pic_->ref_pic_marking, slice_hdr->ref_pic_marking,
1062 sizeof(curr_pic_->ref_pic_marking));
1063 }
1064
1065 return true;
1066 }
1067
1068 bool VaapiH264Decoder::CalculatePicOrderCounts(H264SliceHeader* slice_hdr) {
1069 DCHECK_NE(curr_sps_id_, -1);
1070
1071 int pic_order_cnt_lsb = slice_hdr->pic_order_cnt_lsb;
1072 curr_pic_->pic_order_cnt_lsb = pic_order_cnt_lsb;
1073 if (parser_.GetSPS(curr_sps_id_)->pic_order_cnt_type != 0) {
1074 DVLOG(1) << "Unsupported pic_order_cnt_type";
1075 return false;
1076 }
1077
1078 // See spec 8.2.1.1.
1079 int prev_pic_order_cnt_msb, prev_pic_order_cnt_lsb;
1080 if (slice_hdr->idr_pic_flag) {
1081 prev_pic_order_cnt_msb = prev_pic_order_cnt_lsb = 0;
1082 } else {
1083 if (prev_ref_has_memmgmnt5_) {
1084 if (prev_ref_field_ != H264Picture::FIELD_BOTTOM) {
1085 prev_pic_order_cnt_msb = 0;
1086 prev_pic_order_cnt_lsb = prev_ref_top_field_order_cnt_;
1087 } else {
1088 prev_pic_order_cnt_msb = 0;
1089 prev_pic_order_cnt_lsb = 0;
1090 }
1091 } else {
1092 prev_pic_order_cnt_msb = prev_ref_pic_order_cnt_msb_;
1093 prev_pic_order_cnt_lsb = prev_ref_pic_order_cnt_lsb_;
1094 }
1095 }
1096
1097 DCHECK_NE(max_pic_order_cnt_lsb_, 0);
1098 if ((pic_order_cnt_lsb < prev_pic_order_cnt_lsb) &&
1099 (prev_pic_order_cnt_lsb - pic_order_cnt_lsb >=
1100 max_pic_order_cnt_lsb_ / 2)) {
1101 curr_pic_->pic_order_cnt_msb = prev_pic_order_cnt_msb +
1102 max_pic_order_cnt_lsb_;
1103 } else if ((pic_order_cnt_lsb > prev_pic_order_cnt_lsb) &&
1104 (pic_order_cnt_lsb - prev_pic_order_cnt_lsb >
1105 max_pic_order_cnt_lsb_ / 2)) {
1106 curr_pic_->pic_order_cnt_msb = prev_pic_order_cnt_msb -
1107 max_pic_order_cnt_lsb_;
1108 } else {
1109 curr_pic_->pic_order_cnt_msb = prev_pic_order_cnt_msb;
1110 }
1111
1112 if (curr_pic_->field != H264Picture::FIELD_BOTTOM) {
1113 curr_pic_->top_field_order_cnt = curr_pic_->pic_order_cnt_msb +
1114 pic_order_cnt_lsb;
1115 }
1116
1117 if (curr_pic_->field != H264Picture::FIELD_TOP) {
1118 // TODO posciak: perhaps replace with pic->field?
1119 if (!slice_hdr->field_pic_flag) {
1120 curr_pic_->bottom_field_order_cnt = curr_pic_->top_field_order_cnt +
1121 slice_hdr->delta_pic_order_cnt_bottom;
1122 } else {
1123 curr_pic_->bottom_field_order_cnt = curr_pic_->pic_order_cnt_msb +
1124 pic_order_cnt_lsb;
1125 }
1126 }
1127
1128 switch (curr_pic_->field) {
1129 case H264Picture::FIELD_NONE:
1130 curr_pic_->pic_order_cnt = std::min(curr_pic_->top_field_order_cnt,
1131 curr_pic_->bottom_field_order_cnt);
1132 break;
1133 case H264Picture::FIELD_TOP:
1134 curr_pic_->pic_order_cnt = curr_pic_->top_field_order_cnt;
1135 break;
1136 case H264Picture::FIELD_BOTTOM:
1137 curr_pic_->pic_order_cnt = curr_pic_->bottom_field_order_cnt;
1138 break;
1139 }
1140
1141 return true;
1142 }
1143
1144 void VaapiH264Decoder::UpdatePicNums() {
1145 for (H264DPB::Pictures::iterator it = dpb_.begin(); it != dpb_.end(); ++it) {
1146 H264Picture* pic = *it;
1147 DCHECK(pic);
1148 if (!pic->ref)
1149 continue;
1150
1151 // Below assumes non-interlaced stream.
1152 DCHECK_EQ(pic->field, H264Picture::FIELD_NONE);
1153 if (pic->long_term) {
1154 pic->long_term_pic_num = pic->long_term_frame_idx;
1155 } else {
1156 if (pic->frame_num > frame_num_)
1157 pic->frame_num_wrap = pic->frame_num - max_frame_num_;
1158 else
1159 pic->frame_num_wrap = pic->frame_num;
1160
1161 pic->pic_num = pic->frame_num_wrap;
1162 }
1163 }
1164 }
1165
1166 struct PicNumDescCompare {
1167 bool operator()(const H264Picture* a, const H264Picture* b) const {
1168 return a->pic_num > b->pic_num;
1169 }
1170 };
1171
1172 struct LongTermPicNumAscCompare {
1173 bool operator()(const H264Picture* a, const H264Picture* b) const {
1174 return a->long_term_pic_num < b->long_term_pic_num;
1175 }
1176 };
1177
1178 void VaapiH264Decoder::ConstructReferencePicListsP(H264SliceHeader* slice_hdr) {
1179 // RefPicList0 (8.2.4.2.1) [[1] [2]], where:
1180 // [1] shortterm ref pics sorted by descending pic_num,
1181 // [2] longterm ref pics by ascending long_term_pic_num.
1182 DCHECK(ref_pic_list0_.empty() && ref_pic_list1_.empty());
1183 // First get the short ref pics...
1184 dpb_.GetShortTermRefPicsAppending(ref_pic_list0_);
1185 size_t num_short_refs = ref_pic_list0_.size();
1186
1187 // and sort them to get [1].
1188 std::sort(ref_pic_list0_.begin(), ref_pic_list0_.end(), PicNumDescCompare());
1189
1190 // Now get long term pics and sort them by long_term_pic_num to get [2].
1191 dpb_.GetLongTermRefPicsAppending(ref_pic_list0_);
1192 std::sort(ref_pic_list0_.begin() + num_short_refs, ref_pic_list0_.end(),
1193 LongTermPicNumAscCompare());
1194
1195 // Cut off if we have more than requested in slice header.
1196 ref_pic_list0_.resize(slice_hdr->num_ref_idx_l0_active_minus1 + 1);
1197 }
1198
1199 struct POCAscCompare {
1200 bool operator()(const H264Picture* a, const H264Picture* b) const {
1201 return a->pic_order_cnt < b->pic_order_cnt;
1202 }
1203 };
1204
1205 struct POCDescCompare {
1206 bool operator()(const H264Picture* a, const H264Picture* b) const {
1207 return a->pic_order_cnt > b->pic_order_cnt;
1208 }
1209 };
1210
1211 void VaapiH264Decoder::ConstructReferencePicListsB(H264SliceHeader* slice_hdr) {
1212 // RefPicList0 (8.2.4.2.3) [[1] [2] [3]], where:
1213 // [1] shortterm ref pics with POC < curr_pic's POC sorted by descending POC,
1214 // [2] shortterm ref pics with POC > curr_pic's POC by ascending POC,
1215 // [3] longterm ref pics by ascending long_term_pic_num.
1216 DCHECK(ref_pic_list0_.empty() && ref_pic_list1_.empty());
1217 dpb_.GetShortTermRefPicsAppending(ref_pic_list0_);
1218 size_t num_short_refs = ref_pic_list0_.size();
1219
1220 // First sort ascending, this will put [1] in right place and finish [2].
1221 std::sort(ref_pic_list0_.begin(), ref_pic_list0_.end(), POCAscCompare());
1222
1223 // Find first with POC > curr_pic's POC to get first element in [2]...
1224 H264Picture::PtrVector::iterator iter;
1225 iter = std::upper_bound(ref_pic_list0_.begin(), ref_pic_list0_.end(),
1226 curr_pic_.get(), POCAscCompare());
1227
1228 // and sort [1] descending, thus finishing sequence [1] [2].
1229 std::sort(ref_pic_list0_.begin(), iter, POCDescCompare());
1230
1231 // Now add [3] and sort by ascending long_term_pic_num.
1232 dpb_.GetLongTermRefPicsAppending(ref_pic_list0_);
1233 std::sort(ref_pic_list0_.begin() + num_short_refs, ref_pic_list0_.end(),
1234 LongTermPicNumAscCompare());
1235
1236 // RefPicList1 (8.2.4.2.4) [[1] [2] [3]], where:
1237 // [1] shortterm ref pics with POC > curr_pic's POC sorted by ascending POC,
1238 // [2] shortterm ref pics with POC < curr_pic's POC by descending POC,
1239 // [3] longterm ref pics by ascending long_term_pic_num.
1240
1241 dpb_.GetShortTermRefPicsAppending(ref_pic_list1_);
1242 num_short_refs = ref_pic_list1_.size();
1243
1244 // First sort by descending POC.
1245 std::sort(ref_pic_list1_.begin(), ref_pic_list1_.end(), POCDescCompare());
1246
1247 // Find first with POC < curr_pic's POC to get first element in [2]...
1248 iter = std::upper_bound(ref_pic_list1_.begin(), ref_pic_list1_.end(),
1249 curr_pic_.get(), POCDescCompare());
1250
1251 // and sort [1] ascending.
1252 std::sort(ref_pic_list1_.begin(), iter, POCAscCompare());
1253
1254 // Now add [3] and sort by ascending long_term_pic_num
1255 dpb_.GetShortTermRefPicsAppending(ref_pic_list1_);
1256 std::sort(ref_pic_list1_.begin() + num_short_refs, ref_pic_list1_.end(),
1257 LongTermPicNumAscCompare());
1258
1259 // If lists identical, swap first two entries in RefPicList1 (spec 8.2.4.2.3)
1260 if (ref_pic_list1_.size() > 1 &&
1261 std::equal(ref_pic_list0_.begin(), ref_pic_list0_.end(),
1262 ref_pic_list1_.begin()))
1263 std::swap(ref_pic_list1_[0], ref_pic_list1_[1]);
1264
1265 // Per 8.2.4.2 it's possible for num_ref_idx_lX_active_minus1 to indicate
1266 // there should be more ref pics on list than we constructed.
1267 // Those superfluous ones should be treated as non-reference.
1268 ref_pic_list0_.resize(slice_hdr->num_ref_idx_l0_active_minus1 + 1);
1269 ref_pic_list1_.resize(slice_hdr->num_ref_idx_l1_active_minus1 + 1);
1270 }
1271
1272 // See 8.2.4
1273 int VaapiH264Decoder::PicNumF(H264Picture *pic) {
1274 if (!pic)
1275 return -1;
1276
1277 if (!pic->long_term)
1278 return pic->pic_num;
1279 else
1280 return max_pic_num_;
1281 }
1282
1283 // See 8.2.4
1284 int VaapiH264Decoder::LongTermPicNumF(H264Picture *pic) {
1285 if (pic->ref && pic->long_term)
1286 return pic->long_term_pic_num;
1287 else
1288 return 2 * (max_long_term_frame_idx_ + 1);
1289 }
1290
1291 // Shift elements on the |v| starting from |from| to |to|, inclusive,
1292 // one position to the right and insert pic at |from|.
1293 static void ShiftRightAndInsert(H264Picture::PtrVector& v,
1294 int from,
1295 int to,
1296 H264Picture* pic) {
1297 DCHECK(pic);
1298 for (int i = to + 1; i > from; --i)
1299 v[i] = v[i - 1];
1300
1301 v[from] = pic;
1302 }
1303
1304 bool VaapiH264Decoder::ModifyReferencePicList(H264SliceHeader *slice_hdr,
1305 int list) {
1306 int num_ref_idx_lX_active_minus1;
1307 H264Picture::PtrVector* ref_pic_listx;
1308 H264ModificationOfPicNum* list_mod;
1309
1310 // This can process either ref_pic_list0 or ref_pic_list1, depending on
1311 // the list argument. Set up pointers to proper list to be processed here.
1312 if (list == 0) {
1313 if (!slice_hdr->ref_pic_list_modification_flag_l0)
1314 return true;
1315
1316 list_mod = slice_hdr->ref_list_l0_modifications;
1317 num_ref_idx_lX_active_minus1 = ref_pic_list0_.size() - 1;
1318
1319 ref_pic_listx = &ref_pic_list0_;
1320 } else {
1321 if (!slice_hdr->ref_pic_list_modification_flag_l1)
1322 return true;
1323
1324 list_mod = slice_hdr->ref_list_l1_modifications;
1325 num_ref_idx_lX_active_minus1 = ref_pic_list1_.size() - 1;
1326
1327 ref_pic_listx = &ref_pic_list1_;
1328 }
1329
1330 DCHECK_GT(num_ref_idx_lX_active_minus1, 0);
1331
1332 // Spec 8.2.4.3:
1333 // Reorder pictures on the list in a way specified in the stream.
1334 int pic_num_lx_pred = curr_pic_->pic_num;
1335 int ref_idx_lx = 0;
1336 int pic_num_lx_no_wrap;
1337 int pic_num_lx;
1338 for (int i = 0; i < H264SliceHeader::kRefListModSize; ++i) {
1339 switch (list_mod->modification_of_pic_nums_idc) {
1340 case 0:
1341 case 1: {
Ami GONE FROM CHROMIUM 2012/05/03 23:22:53 If you don't like the fact that you had to add the
Pawel Osciak 2012/05/06 17:49:19 Yeah, didn't like the brace either. Done.
1342 // Modify short reference picture position.
1343 if (list_mod->modification_of_pic_nums_idc == 0) {
1344 // Subtract given value from predicted PicNum.
1345 pic_num_lx_no_wrap = pic_num_lx_pred -
1346 (static_cast<int>(list_mod->abs_diff_pic_num_minus1) + 1);
1347 // Wrap around max_pic_num_ if it becomes < 0 as result
1348 // of subtraction.
1349 if (pic_num_lx_no_wrap < 0)
1350 pic_num_lx_no_wrap += max_pic_num_;
1351 } else {
1352 // Add given value to predicted PicNum.
1353 pic_num_lx_no_wrap = pic_num_lx_pred +
1354 (static_cast<int>(list_mod->abs_diff_pic_num_minus1) + 1);
1355 // Wrap around max_pic_num_ if it becomes >= max_pic_num_ as result
1356 // of the addition.
1357 if (pic_num_lx_no_wrap >= max_pic_num_)
1358 pic_num_lx_no_wrap -= max_pic_num_;
1359 }
1360
1361 // For use in next iteration.
1362 pic_num_lx_pred = pic_num_lx_no_wrap;
1363
1364 if (pic_num_lx_no_wrap > curr_pic_->pic_num)
1365 pic_num_lx = pic_num_lx_no_wrap - max_pic_num_;
1366 else
1367 pic_num_lx = pic_num_lx_no_wrap;
1368
1369 DCHECK_LT(num_ref_idx_lX_active_minus1 + 1,
1370 H264SliceHeader::kRefListModSize);
1371 H264Picture *pic = dpb_.GetShortRefPicByPicNum(pic_num_lx);
1372 if (!pic) {
1373 DVLOG(1) << "Malformed stream, no pic num " << pic_num_lx;
1374 return false;
1375 }
1376 ShiftRightAndInsert(*ref_pic_listx, ref_idx_lx,
1377 num_ref_idx_lX_active_minus1, pic);
1378 ref_idx_lx++;
1379
1380 for (int src = ref_idx_lx, dst = ref_idx_lx;
1381 src <= num_ref_idx_lX_active_minus1 + 1; ++src) {
1382 if (PicNumF((*ref_pic_listx)[src]) != pic_num_lx)
1383 (*ref_pic_listx)[dst++] = (*ref_pic_listx)[src];
1384 }
1385 break;
1386 }
1387
1388 case 2: {
1389 // Modify long term reference picture position.
1390 DCHECK_LT(num_ref_idx_lX_active_minus1 + 1,
1391 H264SliceHeader::kRefListModSize);
1392 H264Picture *pic =
1393 dpb_.GetLongRefPicByLongTermPicNum(list_mod->long_term_pic_num);
1394 if (!pic) {
1395 DVLOG(1) << "Malformed stream, no pic num " << pic_num_lx;
1396 return false;
1397 }
1398 ShiftRightAndInsert(*ref_pic_listx, ref_idx_lx,
1399 num_ref_idx_lX_active_minus1, pic);
1400 ref_idx_lx++;
1401
1402 for (int src = ref_idx_lx, dst = ref_idx_lx;
1403 src <= num_ref_idx_lX_active_minus1 + 1; ++src) {
1404 if (LongTermPicNumF((*ref_pic_listx)[src])
1405 != static_cast<int>(list_mod->long_term_pic_num))
1406 (*ref_pic_listx)[dst++] = (*ref_pic_listx)[src];
1407 }
1408 break;
1409 }
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 (IsH264PSlice(slice_hdr) || IsH264SPSlice(slice_hdr)) {
1513 ConstructReferencePicListsP(slice_hdr);
1514 if (!ModifyReferencePicList(slice_hdr, 0))
1515 return false;
1516 } else if (IsH264BSlice(slice_hdr)) {
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::kH264NaluSPS:
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::kH264NaluIDRSlice:
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(&slice_hdr, &nalu);
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::kH264NaluNonIDRSlice:
1935 case H264NALU::kH264NaluPPS:
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::kH264NaluNonIDRSlice:
1989 case H264NALU::kH264NaluIDRSlice: {
1990 H264SliceHeader slice_hdr;
1991
1992 par_res = parser_.ParseSliceHeader(&slice_hdr, &nalu);
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::kH264NaluSPS:
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::kH264NaluPPS:
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