OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <dlfcn.h> | 5 #include <dlfcn.h> |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
11 #include "content/common/gpu/gl_scoped_binders.h" | 11 #include "content/common/gpu/gl_scoped_binders.h" |
12 #include "content/common/gpu/media/vaapi_h264_decoder.h" | 12 #include "content/common/gpu/media/vaapi_h264_decoder.h" |
13 #include "third_party/libva/va/va.h" | 13 #include "third_party/libva/va/va.h" |
14 #include "third_party/libva/va/va_x11.h" | 14 #include "third_party/libva/va/va_x11.h" |
15 #include "ui/gl/gl_bindings.h" | 15 #include "ui/gl/gl_bindings.h" |
16 | 16 |
17 #define VA_LOG_ON_ERROR(va_res, err_msg) \ | 17 #define VA_LOG_ON_ERROR(va_res, err_msg) \ |
18 do { \ | 18 do { \ |
19 if ((va_res) != VA_STATUS_SUCCESS) { \ | 19 if ((va_res) != VA_STATUS_SUCCESS) { \ |
20 DVLOG(1) << err_msg \ | 20 DVLOG(1) << err_msg \ |
21 << " VA error: " << VAAPI_ErrorStr(va_res); \ | 21 << " VA error: " << VAAPI_ErrorStr(va_res); \ |
22 } \ | 22 } \ |
23 } while(0) | 23 } while (0) |
24 | 24 |
25 #define VA_SUCCESS_OR_RETURN(va_res, err_msg, ret) \ | 25 #define VA_SUCCESS_OR_RETURN(va_res, err_msg, ret) \ |
26 do { \ | 26 do { \ |
27 if ((va_res) != VA_STATUS_SUCCESS) { \ | 27 if ((va_res) != VA_STATUS_SUCCESS) { \ |
28 DVLOG(1) << err_msg \ | 28 DVLOG(1) << err_msg \ |
29 << " VA error: " << VAAPI_ErrorStr(va_res); \ | 29 << " VA error: " << VAAPI_ErrorStr(va_res); \ |
30 return (ret); \ | 30 return (ret); \ |
31 } \ | 31 } \ |
32 } while (0) | 32 } while (0) |
33 | 33 |
34 #define VA_LOG_ERROR(va_res, err_msg) \ | |
35 do { \ | |
36 DVLOG(1) << err_msg \ | |
37 << " VA error: " << VAAPI_ErrorStr(va_res); \ | |
38 } while (0) | |
39 | |
34 namespace content { | 40 namespace content { |
35 | 41 |
36 void *vaapi_handle = dlopen("libva.so", RTLD_NOW); | 42 void *vaapi_handle = dlopen("libva.so", RTLD_NOW); |
37 void *vaapi_x11_handle = dlopen("libva-x11.so", RTLD_NOW); | 43 void *vaapi_x11_handle = dlopen("libva-x11.so", RTLD_NOW); |
38 | 44 |
39 typedef VADisplay (*VaapiGetDisplay)(Display *dpy); | 45 typedef VADisplay (*VaapiGetDisplay)(Display *dpy); |
40 typedef int (*VaapiDisplayIsValid)(VADisplay dpy); | 46 typedef int (*VaapiDisplayIsValid)(VADisplay dpy); |
41 typedef VAStatus (*VaapiInitialize)(VADisplay dpy, | 47 typedef VAStatus (*VaapiInitialize)(VADisplay dpy, |
42 int *major_version, | 48 int *major_version, |
43 int *minor_version); | 49 int *minor_version); |
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
364 frame_num_ = 0; | 370 frame_num_ = 0; |
365 prev_frame_num_ = -1; | 371 prev_frame_num_ = -1; |
366 prev_frame_num_offset_ = -1; | 372 prev_frame_num_offset_ = -1; |
367 | 373 |
368 prev_ref_has_memmgmnt5_ = false; | 374 prev_ref_has_memmgmnt5_ = false; |
369 prev_ref_top_field_order_cnt_ = -1; | 375 prev_ref_top_field_order_cnt_ = -1; |
370 prev_ref_pic_order_cnt_msb_ = -1; | 376 prev_ref_pic_order_cnt_msb_ = -1; |
371 prev_ref_pic_order_cnt_lsb_ = -1; | 377 prev_ref_pic_order_cnt_lsb_ = -1; |
372 prev_ref_field_ = H264Picture::FIELD_NONE; | 378 prev_ref_field_ = H264Picture::FIELD_NONE; |
373 | 379 |
380 // When called from the constructor, although va_display_ is invalid, | |
381 // |pending_slice_bufs_| and |pending_va_bufs_| are empty. | |
382 DestroyPendingBuffers(); | |
383 | |
374 pending_slice_bufs_ = std::queue<VABufferID>(); | 384 pending_slice_bufs_ = std::queue<VABufferID>(); |
375 pending_va_bufs_ = std::queue<VABufferID>(); | 385 pending_va_bufs_ = std::queue<VABufferID>(); |
376 | 386 |
377 ref_pic_list0_.clear(); | 387 ref_pic_list0_.clear(); |
378 ref_pic_list1_.clear(); | 388 ref_pic_list1_.clear(); |
379 | 389 |
380 for (POCToDecodeSurfaces::iterator it = poc_to_decode_surfaces_.begin(); | 390 for (POCToDecodeSurfaces::iterator it = poc_to_decode_surfaces_.begin(); |
381 it != poc_to_decode_surfaces_.end(); ) { | 391 it != poc_to_decode_surfaces_.end(); ) { |
382 int poc = it->second->poc(); | 392 int poc = it->second->poc(); |
383 // Must be incremented before UnassignSurfaceFromPoC as this call | 393 // Must be incremented before UnassignSurfaceFromPoC as this call |
(...skipping 25 matching lines...) Expand all Loading... | |
409 case kDecoding: | 419 case kDecoding: |
410 case kAfterReset: | 420 case kAfterReset: |
411 case kError: | 421 case kError: |
412 destroy_surfaces = true; | 422 destroy_surfaces = true; |
413 // fallthrough | 423 // fallthrough |
414 case kInitialized: | 424 case kInitialized: |
415 if (!make_context_current_.Run()) | 425 if (!make_context_current_.Run()) |
416 break; | 426 break; |
417 if (destroy_surfaces) | 427 if (destroy_surfaces) |
418 DestroyVASurfaces(); | 428 DestroyVASurfaces(); |
429 DestroyPendingBuffers(); | |
Pawel Osciak
2012/08/03 20:57:14
This should only be required in one of the three a
| |
419 va_res = VAAPI_DestroyConfig(va_display_, va_config_id_); | 430 va_res = VAAPI_DestroyConfig(va_display_, va_config_id_); |
420 VA_LOG_ON_ERROR(va_res, "vaDestroyConfig failed"); | 431 VA_LOG_ON_ERROR(va_res, "vaDestroyConfig failed"); |
421 va_res = VAAPI_Terminate(va_display_); | 432 va_res = VAAPI_Terminate(va_display_); |
422 VA_LOG_ON_ERROR(va_res, "vaTerminate failed"); | 433 VA_LOG_ON_ERROR(va_res, "vaTerminate failed"); |
423 // fallthrough | 434 // fallthrough |
424 case kUninitialized: | 435 case kUninitialized: |
425 break; | 436 break; |
426 } | 437 } |
427 | 438 |
428 state_ = kUninitialized; | 439 state_ = kUninitialized; |
429 } | 440 } |
430 | 441 |
431 // Maps Profile enum values to VaProfile values. | 442 // Maps Profile enum values to VaProfile values. |
432 bool VaapiH264Decoder::SetProfile(media::VideoCodecProfile profile) { | 443 bool VaapiH264Decoder::SetProfile(media::VideoCodecProfile profile) { |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
593 GetRequiredNumOfPictures(), | 604 GetRequiredNumOfPictures(), |
594 va_surface_ids_); | 605 va_surface_ids_); |
595 VA_SUCCESS_OR_RETURN(va_res, "vaCreateSurfaces failed", false); | 606 VA_SUCCESS_OR_RETURN(va_res, "vaCreateSurfaces failed", false); |
596 | 607 |
597 DCHECK(decode_surfaces_.empty()); | 608 DCHECK(decode_surfaces_.empty()); |
598 // And create a context associated with them. | 609 // And create a context associated with them. |
599 va_res = VAAPI_CreateContext(va_display_, va_config_id_, | 610 va_res = VAAPI_CreateContext(va_display_, va_config_id_, |
600 pic_width_, pic_height_, VA_PROGRESSIVE, | 611 pic_width_, pic_height_, VA_PROGRESSIVE, |
601 va_surface_ids_, GetRequiredNumOfPictures(), | 612 va_surface_ids_, GetRequiredNumOfPictures(), |
602 &va_context_id_); | 613 &va_context_id_); |
603 VA_SUCCESS_OR_RETURN(va_res, "vaCreateContext failed", false); | 614 |
615 if (va_res != VA_STATUS_SUCCESS) { | |
616 VAAPI_DestroySurfaces(va_display_, va_surface_ids_, | |
617 GetRequiredNumOfPictures()); | |
618 DVLOG(1) << "vaCreateContext failed" | |
619 << " VA error: " << VAAPI_ErrorStr(va_res); | |
620 return false; | |
621 } | |
604 | 622 |
605 return true; | 623 return true; |
606 } | 624 } |
607 | 625 |
608 void VaapiH264Decoder::DestroyVASurfaces() { | 626 void VaapiH264Decoder::DestroyVASurfaces() { |
609 DCHECK(state_ == kDecoding || state_ == kError || state_ == kAfterReset); | 627 DCHECK(state_ == kDecoding || state_ == kError || state_ == kAfterReset); |
610 decode_surfaces_.clear(); | 628 decode_surfaces_.clear(); |
611 | 629 |
612 VAStatus va_res = VAAPI_DestroyContext(va_display_, va_context_id_); | 630 VAStatus va_res = VAAPI_DestroyContext(va_display_, va_context_id_); |
613 VA_LOG_ON_ERROR(va_res, "vaDestroyContext failed"); | 631 VA_LOG_ON_ERROR(va_res, "vaDestroyContext failed"); |
614 | 632 |
615 va_res = VAAPI_DestroySurfaces(va_display_, va_surface_ids_, | 633 va_res = VAAPI_DestroySurfaces(va_display_, va_surface_ids_, |
616 GetRequiredNumOfPictures()); | 634 GetRequiredNumOfPictures()); |
617 VA_LOG_ON_ERROR(va_res, "vaDestroySurfaces failed"); | 635 VA_LOG_ON_ERROR(va_res, "vaDestroySurfaces failed"); |
618 } | 636 } |
619 | 637 |
638 void VaapiH264Decoder::DestroyPendingBuffers() { | |
639 while (!pending_slice_bufs_.empty()) { | |
640 VABufferID buffer = pending_slice_bufs_.front(); | |
641 VAStatus va_res = VAAPI_DestroyBuffer(va_display_, buffer); | |
642 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); | |
643 pending_slice_bufs_.pop(); | |
644 } | |
645 while (!pending_va_bufs_.empty()) { | |
646 VABufferID buffer = pending_va_bufs_.front(); | |
647 VAStatus va_res = VAAPI_DestroyBuffer(va_display_, buffer); | |
648 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); | |
649 pending_va_bufs_.pop(); | |
650 } | |
651 } | |
652 | |
620 // Fill |va_pic| with default/neutral values. | 653 // Fill |va_pic| with default/neutral values. |
621 static void InitVAPicture(VAPictureH264* va_pic) { | 654 static void InitVAPicture(VAPictureH264* va_pic) { |
622 memset(va_pic, 0, sizeof(*va_pic)); | 655 memset(va_pic, 0, sizeof(*va_pic)); |
623 va_pic->picture_id = VA_INVALID_ID; | 656 va_pic->picture_id = VA_INVALID_ID; |
624 va_pic->flags = VA_PICTURE_H264_INVALID; | 657 va_pic->flags = VA_PICTURE_H264_INVALID; |
625 } | 658 } |
626 | 659 |
627 void VaapiH264Decoder::FillVAPicture(VAPictureH264 *va_pic, H264Picture* pic) { | 660 void VaapiH264Decoder::FillVAPicture(VAPictureH264 *va_pic, H264Picture* pic) { |
628 POCToDecodeSurfaces::iterator iter = poc_to_decode_surfaces_.find( | 661 POCToDecodeSurfaces::iterator iter = poc_to_decode_surfaces_.find( |
629 pic->pic_order_cnt); | 662 pic->pic_order_cnt); |
(...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
988 | 1021 |
989 if (!SendVASliceParam(slice_hdr)) | 1022 if (!SendVASliceParam(slice_hdr)) |
990 return false; | 1023 return false; |
991 | 1024 |
992 if (!SendSliceData(slice_hdr->nalu_data, slice_hdr->nalu_size)) | 1025 if (!SendSliceData(slice_hdr->nalu_data, slice_hdr->nalu_size)) |
993 return false; | 1026 return false; |
994 | 1027 |
995 return true; | 1028 return true; |
996 } | 1029 } |
997 | 1030 |
1031 void VaapiH264Decoder::DestroyBuffers(VABufferID* va_buffers, | |
1032 size_t num_va_buffers) { | |
1033 for (size_t i = 0; i < num_va_buffers; ++i) { | |
1034 VAStatus va_res = VAAPI_DestroyBuffer(va_display_, va_buffers[i]); | |
1035 VA_LOG_ON_ERROR(va_res, "vaDestroyBuffer failed"); | |
1036 } | |
1037 } | |
1038 | |
998 // TODO(posciak) start using vaMapBuffer instead of vaCreateBuffer wherever | 1039 // TODO(posciak) start using vaMapBuffer instead of vaCreateBuffer wherever |
999 // possible. | 1040 // possible. |
1000 | 1041 |
1001 bool VaapiH264Decoder::DecodePicture() { | 1042 bool VaapiH264Decoder::DecodePicture() { |
1002 DCHECK(!frame_ready_at_hw_); | 1043 DCHECK(!frame_ready_at_hw_); |
1003 DCHECK(curr_pic_.get()); | 1044 DCHECK(curr_pic_.get()); |
1004 | 1045 |
1005 static const size_t kMaxVABuffers = 32; | 1046 static const size_t kMaxVABuffers = 32; |
1006 DCHECK_LE(pending_va_bufs_.size(), kMaxVABuffers); | 1047 DCHECK_LE(pending_va_bufs_.size(), kMaxVABuffers); |
1007 DCHECK_LE(pending_slice_bufs_.size(), kMaxVABuffers); | 1048 DCHECK_LE(pending_slice_bufs_.size(), kMaxVABuffers); |
1008 | 1049 |
1009 DVLOG(4) << "Pending VA bufs to commit: " << pending_va_bufs_.size(); | 1050 DVLOG(4) << "Pending VA bufs to commit: " << pending_va_bufs_.size(); |
1010 DVLOG(4) << "Pending slice bufs to commit: " << pending_slice_bufs_.size(); | 1051 DVLOG(4) << "Pending slice bufs to commit: " << pending_slice_bufs_.size(); |
1011 | 1052 |
1012 // Find the surface associated with the picture to be decoded. | 1053 // Find the surface associated with the picture to be decoded. |
1013 DCHECK(pending_slice_bufs_.size()); | 1054 DCHECK(pending_slice_bufs_.size()); |
1014 DecodeSurface* dec_surface = | 1055 DecodeSurface* dec_surface = |
1015 poc_to_decode_surfaces_[curr_pic_->pic_order_cnt]; | 1056 poc_to_decode_surfaces_[curr_pic_->pic_order_cnt]; |
1016 DVLOG(4) << "Decoding POC " << curr_pic_->pic_order_cnt | 1057 DVLOG(4) << "Decoding POC " << curr_pic_->pic_order_cnt |
1017 << " into surface " << dec_surface->va_surface_id(); | 1058 << " into surface " << dec_surface->va_surface_id(); |
1018 | 1059 |
1019 // Get ready to decode into surface. | 1060 // Get ready to decode into surface. |
1020 VAStatus va_res = VAAPI_BeginPicture(va_display_, va_context_id_, | 1061 VAStatus va_res = VAAPI_BeginPicture(va_display_, va_context_id_, |
1021 dec_surface->va_surface_id()); | 1062 dec_surface->va_surface_id()); |
1022 VA_SUCCESS_OR_RETURN(va_res, "vaBeginPicture failed", false); | 1063 VA_SUCCESS_OR_RETURN(va_res, "vaBeginPicture failed", false); |
1023 | 1064 |
1024 // Put buffer IDs for pending parameter buffers into buffers[]. | 1065 // Put buffer IDs for pending parameter buffers into va_buffers[]. |
1025 VABufferID buffers[kMaxVABuffers]; | 1066 VABufferID va_buffers[kMaxVABuffers]; |
1026 size_t num_buffers = pending_va_bufs_.size(); | 1067 size_t num_va_buffers = pending_va_bufs_.size(); |
1027 for (size_t i = 0; i < num_buffers && i < kMaxVABuffers; ++i) { | 1068 for (size_t i = 0; i < num_va_buffers && i < kMaxVABuffers; ++i) { |
1028 buffers[i] = pending_va_bufs_.front(); | 1069 va_buffers[i] = pending_va_bufs_.front(); |
1029 pending_va_bufs_.pop(); | 1070 pending_va_bufs_.pop(); |
1030 } | 1071 } |
1031 | 1072 |
1032 // And send them to the HW decoder. | 1073 // And send them to the HW decoder. |
1033 va_res = VAAPI_RenderPicture(va_display_, va_context_id_, buffers, | 1074 va_res = VAAPI_RenderPicture(va_display_, va_context_id_, va_buffers, |
1034 num_buffers); | 1075 num_va_buffers); |
1035 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for va_bufs failed", false); | 1076 if (va_res != VA_STATUS_SUCCESS) { |
1036 | 1077 DestroyBuffers(va_buffers, num_va_buffers); |
1037 DVLOG(4) << "Committed " << num_buffers << "VA buffers"; | 1078 VA_LOG_ERROR(va_res, "vaRenderPicture for va_bufs failed"); |
1038 | 1079 return false; |
1039 for (size_t i = 0; i < num_buffers; ++i) { | |
1040 va_res = VAAPI_DestroyBuffer(va_display_, buffers[i]); | |
1041 VA_SUCCESS_OR_RETURN(va_res, "vaDestroyBuffer for va_bufs failed", false); | |
1042 } | 1080 } |
1043 | 1081 |
1044 // Put buffer IDs for pending slice data buffers into buffers[]. | 1082 DVLOG(4) << "Committed " << num_va_buffers << "VA buffers"; |
1045 num_buffers = pending_slice_bufs_.size(); | 1083 |
1046 for (size_t i = 0; i < num_buffers && i < kMaxVABuffers; ++i) { | 1084 // Put buffer IDs for pending slice data buffers into slice_buffers[]. |
1047 buffers[i] = pending_slice_bufs_.front(); | 1085 VABufferID slice_buffers[kMaxVABuffers]; |
1086 size_t num_slice_buffers = pending_slice_bufs_.size(); | |
1087 for (size_t i = 0; i < num_slice_buffers && i < kMaxVABuffers; ++i) { | |
1088 slice_buffers[i] = pending_slice_bufs_.front(); | |
1048 pending_slice_bufs_.pop(); | 1089 pending_slice_bufs_.pop(); |
1049 } | 1090 } |
1050 | 1091 |
1051 // And send them to the Hw decoder. | 1092 // And send them to the Hw decoder. |
1052 va_res = VAAPI_RenderPicture(va_display_, va_context_id_, buffers, | 1093 va_res = VAAPI_RenderPicture(va_display_, va_context_id_, slice_buffers, |
1053 num_buffers); | 1094 num_slice_buffers); |
1054 VA_SUCCESS_OR_RETURN(va_res, "vaRenderPicture for slices failed", false); | 1095 if (va_res != VA_STATUS_SUCCESS) { |
1096 DestroyBuffers(va_buffers, num_va_buffers); | |
1097 DestroyBuffers(slice_buffers, num_slice_buffers); | |
1098 VA_LOG_ERROR(va_res, "vaRenderPicture for slices failed"); | |
1099 return false; | |
1100 } | |
1055 | 1101 |
1056 DVLOG(4) << "Committed " << num_buffers << "slice buffers"; | 1102 DVLOG(4) << "Committed " << num_slice_buffers << "slice buffers"; |
1057 | |
1058 for (size_t i = 0; i < num_buffers; ++i) { | |
1059 va_res = VAAPI_DestroyBuffer(va_display_, buffers[i]); | |
1060 VA_SUCCESS_OR_RETURN(va_res, "vaDestroyBuffer for slices failed", false); | |
1061 } | |
1062 | 1103 |
1063 // Instruct HW decoder to start processing committed buffers (decode this | 1104 // Instruct HW decoder to start processing committed buffers (decode this |
1064 // picture). This does not block until the end of decode. | 1105 // picture). This does not block until the end of decode. |
1065 va_res = VAAPI_EndPicture(va_display_, va_context_id_); | 1106 va_res = VAAPI_EndPicture(va_display_, va_context_id_); |
1066 VA_SUCCESS_OR_RETURN(va_res, "vaEndPicture failed", false); | 1107 VA_LOG_ON_ERROR(va_res, "vaEndPicture failed"); |
1108 | |
1109 // Now that EndPicture has passed we can destroy our buffers. | |
1110 DestroyBuffers(va_buffers, num_va_buffers); | |
1111 DestroyBuffers(slice_buffers, num_slice_buffers); | |
1067 | 1112 |
1068 // Used to notify clients that we had sufficient data to start decoding | 1113 // Used to notify clients that we had sufficient data to start decoding |
1069 // a new frame. | 1114 // a new frame. |
1070 frame_ready_at_hw_ = true; | 1115 frame_ready_at_hw_ = true; |
1071 return true; | 1116 return true; |
1072 } | 1117 } |
1073 | 1118 |
1074 | 1119 |
1075 bool VaapiH264Decoder::InitCurrPicture(H264SliceHeader* slice_hdr) { | 1120 bool VaapiH264Decoder::InitCurrPicture(H264SliceHeader* slice_hdr) { |
1076 DCHECK(curr_pic_.get()); | 1121 DCHECK(curr_pic_.get()); |
(...skipping 1015 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2092 } | 2137 } |
2093 } | 2138 } |
2094 } | 2139 } |
2095 | 2140 |
2096 // static | 2141 // static |
2097 size_t VaapiH264Decoder::GetRequiredNumOfPictures() { | 2142 size_t VaapiH264Decoder::GetRequiredNumOfPictures() { |
2098 return kNumReqPictures; | 2143 return kNumReqPictures; |
2099 } | 2144 } |
2100 | 2145 |
2101 } // namespace content | 2146 } // namespace content |
OLD | NEW |