OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 <algorithm> | 5 #include <algorithm> |
6 | 6 |
7 #include <CoreVideo/CoreVideo.h> | 7 #include <CoreVideo/CoreVideo.h> |
8 #include <OpenGL/CGLIOSurface.h> | 8 #include <OpenGL/CGLIOSurface.h> |
9 #include <OpenGL/gl.h> | 9 #include <OpenGL/gl.h> |
10 #include <stddef.h> | 10 #include <stddef.h> |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
67 // Maximum number of frames to queue for reordering before we stop asking for | 67 // Maximum number of frames to queue for reordering before we stop asking for |
68 // more. (NotifyEndOfBitstreamBuffer() is called when frames are moved into the | 68 // more. (NotifyEndOfBitstreamBuffer() is called when frames are moved into the |
69 // reorder queue.) | 69 // reorder queue.) |
70 static const int kMaxReorderQueueSize = 16; | 70 static const int kMaxReorderQueueSize = 16; |
71 | 71 |
72 // Build an |image_config| dictionary for VideoToolbox initialization. | 72 // Build an |image_config| dictionary for VideoToolbox initialization. |
73 static base::ScopedCFTypeRef<CFMutableDictionaryRef> | 73 static base::ScopedCFTypeRef<CFMutableDictionaryRef> |
74 BuildImageConfig(CMVideoDimensions coded_dimensions) { | 74 BuildImageConfig(CMVideoDimensions coded_dimensions) { |
75 base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config; | 75 base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config; |
76 | 76 |
77 // 4:2:2 is used over the native 4:2:0 because only 4:2:2 can be directly | 77 // Note that 4:2:0 textures cannot be used directly as RGBA in OpenGL, but are |
78 // bound to a texture by CGLTexImageIOSurface2D(). | 78 // lower power than 4:2:2 when composited directly by CoreAnimation. |
79 int32_t pixel_format = kCVPixelFormatType_422YpCbCr8; | 79 int32_t pixel_format = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; |
80 #define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i) | 80 #define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i) |
81 base::ScopedCFTypeRef<CFNumberRef> cf_pixel_format(CFINT(pixel_format)); | 81 base::ScopedCFTypeRef<CFNumberRef> cf_pixel_format(CFINT(pixel_format)); |
82 base::ScopedCFTypeRef<CFNumberRef> cf_width(CFINT(coded_dimensions.width)); | 82 base::ScopedCFTypeRef<CFNumberRef> cf_width(CFINT(coded_dimensions.width)); |
83 base::ScopedCFTypeRef<CFNumberRef> cf_height(CFINT(coded_dimensions.height)); | 83 base::ScopedCFTypeRef<CFNumberRef> cf_height(CFINT(coded_dimensions.height)); |
84 #undef CFINT | 84 #undef CFINT |
85 if (!cf_pixel_format.get() || !cf_width.get() || !cf_height.get()) | 85 if (!cf_pixel_format.get() || !cf_width.get() || !cf_height.get()) |
86 return image_config; | 86 return image_config; |
87 | 87 |
88 image_config.reset( | 88 image_config.reset(CFDictionaryCreateMutable( |
89 CFDictionaryCreateMutable( | 89 kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, |
90 kCFAllocatorDefault, | 90 &kCFTypeDictionaryValueCallBacks)); |
91 4, // capacity | |
92 &kCFTypeDictionaryKeyCallBacks, | |
93 &kCFTypeDictionaryValueCallBacks)); | |
94 if (!image_config.get()) | 91 if (!image_config.get()) |
95 return image_config; | 92 return image_config; |
96 | 93 |
97 CFDictionarySetValue(image_config, kCVPixelBufferPixelFormatTypeKey, | 94 CFDictionarySetValue(image_config, kCVPixelBufferPixelFormatTypeKey, |
98 cf_pixel_format); | 95 cf_pixel_format); |
99 CFDictionarySetValue(image_config, kCVPixelBufferWidthKey, cf_width); | 96 CFDictionarySetValue(image_config, kCVPixelBufferWidthKey, cf_width); |
100 CFDictionarySetValue(image_config, kCVPixelBufferHeightKey, cf_height); | 97 CFDictionarySetValue(image_config, kCVPixelBufferHeightKey, cf_height); |
101 CFDictionarySetValue(image_config, kCVPixelBufferOpenGLCompatibilityKey, | |
102 kCFBooleanTrue); | |
103 | 98 |
104 return image_config; | 99 return image_config; |
105 } | 100 } |
106 | 101 |
107 // Create a VTDecompressionSession using the provided |pps| and |sps|. If | 102 // Create a VTDecompressionSession using the provided |pps| and |sps|. If |
108 // |require_hardware| is true, the session must uses real hardware decoding | 103 // |require_hardware| is true, the session must uses real hardware decoding |
109 // (as opposed to software decoding inside of VideoToolbox) to be considered | 104 // (as opposed to software decoding inside of VideoToolbox) to be considered |
110 // successful. | 105 // successful. |
111 // | 106 // |
112 // TODO(sandersd): Merge with ConfigureDecoder(), as the code is very similar. | 107 // TODO(sandersd): Merge with ConfigureDecoder(), as the code is very similar. |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
281 if (lhs->pic_order_cnt != rhs->pic_order_cnt) | 276 if (lhs->pic_order_cnt != rhs->pic_order_cnt) |
282 return lhs->pic_order_cnt > rhs->pic_order_cnt; | 277 return lhs->pic_order_cnt > rhs->pic_order_cnt; |
283 // If |pic_order_cnt| is the same, fall back on using the bitstream order. | 278 // If |pic_order_cnt| is the same, fall back on using the bitstream order. |
284 // TODO(sandersd): Assign a sequence number in Decode() and use that instead. | 279 // TODO(sandersd): Assign a sequence number in Decode() and use that instead. |
285 // TODO(sandersd): Using the sequence number, ensure that frames older than | 280 // TODO(sandersd): Using the sequence number, ensure that frames older than |
286 // |kMaxReorderQueueSize| are ordered first, regardless of |pic_order_cnt|. | 281 // |kMaxReorderQueueSize| are ordered first, regardless of |pic_order_cnt|. |
287 return lhs->bitstream_id > rhs->bitstream_id; | 282 return lhs->bitstream_id > rhs->bitstream_id; |
288 } | 283 } |
289 | 284 |
290 VTVideoDecodeAccelerator::VTVideoDecodeAccelerator( | 285 VTVideoDecodeAccelerator::VTVideoDecodeAccelerator( |
291 const base::Callback<bool(void)>& make_context_current, | 286 const MakeContextCurrentCallback& make_context_current, |
292 const base::Callback<void(uint32_t, uint32_t, scoped_refptr<gl::GLImage>)>& | 287 const BindImageCallback& bind_image) |
293 bind_image) | |
294 : make_context_current_(make_context_current), | 288 : make_context_current_(make_context_current), |
295 bind_image_(bind_image), | 289 bind_image_(bind_image), |
296 client_(nullptr), | 290 client_(nullptr), |
297 state_(STATE_DECODING), | 291 state_(STATE_DECODING), |
298 format_(nullptr), | 292 format_(nullptr), |
299 session_(nullptr), | 293 session_(nullptr), |
300 last_sps_id_(-1), | 294 last_sps_id_(-1), |
301 last_pps_id_(-1), | 295 last_pps_id_(-1), |
302 config_changed_(false), | 296 config_changed_(false), |
303 missing_idr_logged_(false), | 297 missing_idr_logged_(false), |
(...skipping 723 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1027 PictureInfo* picture_info = picture_info_map_.find(picture_id)->second.get(); | 1021 PictureInfo* picture_info = picture_info_map_.find(picture_id)->second.get(); |
1028 DCHECK(!picture_info->cv_image); | 1022 DCHECK(!picture_info->cv_image); |
1029 DCHECK(!picture_info->gl_image); | 1023 DCHECK(!picture_info->gl_image); |
1030 | 1024 |
1031 if (!make_context_current_.Run()) { | 1025 if (!make_context_current_.Run()) { |
1032 DLOG(ERROR) << "Failed to make GL context current"; | 1026 DLOG(ERROR) << "Failed to make GL context current"; |
1033 NotifyError(PLATFORM_FAILURE, SFT_PLATFORM_ERROR); | 1027 NotifyError(PLATFORM_FAILURE, SFT_PLATFORM_ERROR); |
1034 return false; | 1028 return false; |
1035 } | 1029 } |
1036 | 1030 |
1037 IOSurfaceRef surface = CVPixelBufferGetIOSurface(frame.image.get()); | 1031 IOSurfaceRef io_surface = CVPixelBufferGetIOSurface(frame.image.get()); |
1038 if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGLCoreProfile) | 1032 |
1039 glEnable(GL_TEXTURE_RECTANGLE_ARB); | 1033 scoped_refptr<gl::GLImageIOSurface> gl_image( |
1040 gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_RECTANGLE_ARB, | 1034 new gl::GLImageIOSurface(frame.coded_size, GL_BGRA_EXT)); |
1041 picture_info->service_texture_id); | 1035 if (!gl_image->Initialize(io_surface, gfx::GenericSharedMemoryId(), |
1042 CGLContextObj cgl_context = | 1036 gfx::BufferFormat::YUV_420_BIPLANAR)) { |
1043 static_cast<CGLContextObj>(gfx::GLContext::GetCurrent()->GetHandle()); | 1037 NOTIFY_STATUS("Failed to initialize GLImageIOSurface", PLATFORM_FAILURE, |
1044 CGLError status = CGLTexImageIOSurface2D( | 1038 SFT_PLATFORM_ERROR); |
1045 cgl_context, // ctx | |
1046 GL_TEXTURE_RECTANGLE_ARB, // target | |
1047 GL_RGB, // internal_format | |
1048 frame.coded_size.width(), // width | |
1049 frame.coded_size.height(), // height | |
1050 GL_YCBCR_422_APPLE, // format | |
1051 GL_UNSIGNED_SHORT_8_8_APPLE, // type | |
1052 surface, // io_surface | |
1053 0); // plane | |
1054 if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGLCoreProfile) | |
1055 glDisable(GL_TEXTURE_RECTANGLE_ARB); | |
1056 if (status != kCGLNoError) { | |
1057 NOTIFY_STATUS("CGLTexImageIOSurface2D()", status, SFT_PLATFORM_ERROR); | |
1058 return false; | 1039 return false; |
1059 } | 1040 } |
1060 | 1041 |
1061 bool allow_overlay = false; | 1042 // Mark that the image is not bound for sampling. 4:2:0 images need to |
1062 scoped_refptr<gl::GLImageIOSurface> gl_image( | 1043 // undergo a separate copy to be displayed. |
1063 new gl::GLImageIOSurface(frame.coded_size, GL_BGRA_EXT)); | |
1064 if (gl_image->Initialize(surface, gfx::GenericSharedMemoryId(), | |
1065 gfx::BufferFormat::BGRA_8888)) { | |
1066 allow_overlay = true; | |
1067 } else { | |
1068 gl_image = nullptr; | |
1069 } | |
1070 bind_image_.Run(picture_info->client_texture_id, GL_TEXTURE_RECTANGLE_ARB, | 1044 bind_image_.Run(picture_info->client_texture_id, GL_TEXTURE_RECTANGLE_ARB, |
1071 gl_image); | 1045 gl_image, false); |
1072 | 1046 |
1073 // Assign the new image(s) to the the picture info. | 1047 // Assign the new image(s) to the the picture info. |
1074 picture_info->gl_image = gl_image; | 1048 picture_info->gl_image = gl_image; |
1075 picture_info->cv_image = frame.image; | 1049 picture_info->cv_image = frame.image; |
1076 available_picture_ids_.pop_back(); | 1050 available_picture_ids_.pop_back(); |
1077 | 1051 |
1078 // TODO(sandersd): Currently, the size got from | 1052 // TODO(sandersd): Currently, the size got from |
1079 // CMVideoFormatDescriptionGetDimensions is visible size. We pass it to | 1053 // CMVideoFormatDescriptionGetDimensions is visible size. We pass it to |
1080 // GpuVideoDecoder so that GpuVideoDecoder can use correct visible size in | 1054 // GpuVideoDecoder so that GpuVideoDecoder can use correct visible size in |
1081 // resolution changed. We should find the correct API to get the real | 1055 // resolution changed. We should find the correct API to get the real |
1082 // coded size and fix it. | 1056 // coded size and fix it. |
1083 client_->PictureReady(media::Picture(picture_id, frame.bitstream_id, | 1057 client_->PictureReady(media::Picture(picture_id, frame.bitstream_id, |
1084 gfx::Rect(frame.coded_size), | 1058 gfx::Rect(frame.coded_size), true)); |
1085 allow_overlay)); | |
1086 return true; | 1059 return true; |
1087 } | 1060 } |
1088 | 1061 |
1089 void VTVideoDecodeAccelerator::NotifyError( | 1062 void VTVideoDecodeAccelerator::NotifyError( |
1090 Error vda_error_type, | 1063 Error vda_error_type, |
1091 VTVDASessionFailureType session_failure_type) { | 1064 VTVDASessionFailureType session_failure_type) { |
1092 DCHECK_LT(session_failure_type, SFT_MAX + 1); | 1065 DCHECK_LT(session_failure_type, SFT_MAX + 1); |
1093 if (!gpu_thread_checker_.CalledOnValidThread()) { | 1066 if (!gpu_thread_checker_.CalledOnValidThread()) { |
1094 gpu_task_runner_->PostTask(FROM_HERE, base::Bind( | 1067 gpu_task_runner_->PostTask(FROM_HERE, base::Bind( |
1095 &VTVideoDecodeAccelerator::NotifyError, weak_this_, vda_error_type, | 1068 &VTVideoDecodeAccelerator::NotifyError, weak_this_, vda_error_type, |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1157 SupportedProfile profile; | 1130 SupportedProfile profile; |
1158 profile.profile = supported_profile; | 1131 profile.profile = supported_profile; |
1159 profile.min_resolution.SetSize(16, 16); | 1132 profile.min_resolution.SetSize(16, 16); |
1160 profile.max_resolution.SetSize(4096, 2160); | 1133 profile.max_resolution.SetSize(4096, 2160); |
1161 profiles.push_back(profile); | 1134 profiles.push_back(profile); |
1162 } | 1135 } |
1163 return profiles; | 1136 return profiles; |
1164 } | 1137 } |
1165 | 1138 |
1166 } // namespace content | 1139 } // namespace content |
OLD | NEW |