vaapi_jpeg_decoder.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. // Copyright 2019 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. #include "media/gpu/vaapi/vaapi_jpeg_decoder.h"
  5. #include <string.h>
  6. #include <va/va.h>
  7. #include <iostream>
  8. #include <type_traits>
  9. #include "base/logging.h"
  10. #include "base/numerics/safe_conversions.h"
  11. #include "media/base/video_types.h"
  12. #include "media/gpu/macros.h"
  13. #include "media/gpu/vaapi/vaapi_utils.h"
  14. #include "media/gpu/vaapi/vaapi_wrapper.h"
  15. #include "media/parsers/jpeg_parser.h"
  16. #include "ui/gfx/geometry/size.h"
  17. namespace media {
  18. namespace {
  19. static void FillPictureParameters(
  20. const JpegFrameHeader& frame_header,
  21. VAPictureParameterBufferJPEGBaseline* pic_param) {
  22. pic_param->picture_width = frame_header.coded_width;
  23. pic_param->picture_height = frame_header.coded_height;
  24. pic_param->num_components = frame_header.num_components;
  25. for (int i = 0; i < pic_param->num_components; i++) {
  26. pic_param->components[i].component_id = frame_header.components[i].id;
  27. pic_param->components[i].h_sampling_factor =
  28. frame_header.components[i].horizontal_sampling_factor;
  29. pic_param->components[i].v_sampling_factor =
  30. frame_header.components[i].vertical_sampling_factor;
  31. pic_param->components[i].quantiser_table_selector =
  32. frame_header.components[i].quantization_table_selector;
  33. }
  34. }
  35. static void FillIQMatrix(const JpegQuantizationTable* q_table,
  36. VAIQMatrixBufferJPEGBaseline* iq_matrix) {
  37. static_assert(kJpegMaxQuantizationTableNum ==
  38. std::extent<decltype(iq_matrix->load_quantiser_table)>(),
  39. "max number of quantization table mismatched");
  40. static_assert(
  41. sizeof(iq_matrix->quantiser_table[0]) == sizeof(q_table[0].value),
  42. "number of quantization entries mismatched");
  43. for (size_t i = 0; i < kJpegMaxQuantizationTableNum; i++) {
  44. if (!q_table[i].valid)
  45. continue;
  46. iq_matrix->load_quantiser_table[i] = 1;
  47. for (size_t j = 0; j < std::size(q_table[i].value); j++)
  48. iq_matrix->quantiser_table[i][j] = q_table[i].value[j];
  49. }
  50. }
  51. static void FillHuffmanTable(const JpegHuffmanTable* dc_table,
  52. const JpegHuffmanTable* ac_table,
  53. VAHuffmanTableBufferJPEGBaseline* huffman_table) {
  54. // Use default huffman tables if not specified in header.
  55. bool has_huffman_table = false;
  56. for (size_t i = 0; i < kJpegMaxHuffmanTableNumBaseline; i++) {
  57. if (dc_table[i].valid || ac_table[i].valid) {
  58. has_huffman_table = true;
  59. break;
  60. }
  61. }
  62. if (!has_huffman_table) {
  63. dc_table = kDefaultDcTable;
  64. ac_table = kDefaultAcTable;
  65. }
  66. static_assert(kJpegMaxHuffmanTableNumBaseline ==
  67. std::extent<decltype(huffman_table->load_huffman_table)>(),
  68. "max number of huffman table mismatched");
  69. static_assert(sizeof(huffman_table->huffman_table[0].num_dc_codes) ==
  70. sizeof(dc_table[0].code_length),
  71. "size of huffman table code length mismatch");
  72. static_assert(sizeof(huffman_table->huffman_table[0].dc_values[0]) ==
  73. sizeof(dc_table[0].code_value[0]),
  74. "size of huffman table code value mismatch");
  75. for (size_t i = 0; i < kJpegMaxHuffmanTableNumBaseline; i++) {
  76. if (!dc_table[i].valid || !ac_table[i].valid)
  77. continue;
  78. huffman_table->load_huffman_table[i] = 1;
  79. memcpy(huffman_table->huffman_table[i].num_dc_codes,
  80. dc_table[i].code_length,
  81. sizeof(huffman_table->huffman_table[i].num_dc_codes));
  82. memcpy(huffman_table->huffman_table[i].dc_values, dc_table[i].code_value,
  83. sizeof(huffman_table->huffman_table[i].dc_values));
  84. memcpy(huffman_table->huffman_table[i].num_ac_codes,
  85. ac_table[i].code_length,
  86. sizeof(huffman_table->huffman_table[i].num_ac_codes));
  87. memcpy(huffman_table->huffman_table[i].ac_values, ac_table[i].code_value,
  88. sizeof(huffman_table->huffman_table[i].ac_values));
  89. }
  90. }
  91. static void FillSliceParameters(
  92. const JpegParseResult& parse_result,
  93. VASliceParameterBufferJPEGBaseline* slice_param) {
  94. slice_param->slice_data_size = parse_result.data_size;
  95. slice_param->slice_data_offset = 0;
  96. slice_param->slice_data_flag = VA_SLICE_DATA_FLAG_ALL;
  97. slice_param->slice_horizontal_position = 0;
  98. slice_param->slice_vertical_position = 0;
  99. slice_param->num_components = parse_result.scan.num_components;
  100. for (int i = 0; i < slice_param->num_components; i++) {
  101. slice_param->components[i].component_selector =
  102. parse_result.scan.components[i].component_selector;
  103. slice_param->components[i].dc_table_selector =
  104. parse_result.scan.components[i].dc_selector;
  105. slice_param->components[i].ac_table_selector =
  106. parse_result.scan.components[i].ac_selector;
  107. }
  108. slice_param->restart_interval = parse_result.restart_interval;
  109. // Cast to int to prevent overflow.
  110. int max_h_factor =
  111. parse_result.frame_header.components[0].horizontal_sampling_factor;
  112. int max_v_factor =
  113. parse_result.frame_header.components[0].vertical_sampling_factor;
  114. int mcu_cols = parse_result.frame_header.coded_width / (max_h_factor * 8);
  115. DCHECK_GT(mcu_cols, 0);
  116. int mcu_rows = parse_result.frame_header.coded_height / (max_v_factor * 8);
  117. DCHECK_GT(mcu_rows, 0);
  118. slice_param->num_mcus = mcu_rows * mcu_cols;
  119. }
  120. // VAAPI only supports a subset of JPEG profiles. This function determines
  121. // whether a given parsed JPEG result is supported or not.
  122. static bool IsVaapiSupportedJpeg(const JpegParseResult& jpeg) {
  123. // Make sure the JPEG's chroma subsampling format is supported.
  124. if (!VaapiWrapper::IsDecodingSupportedForInternalFormat(
  125. VAProfileJPEGBaseline, VaSurfaceFormatForJpeg(jpeg.frame_header))) {
  126. DLOG(ERROR) << "The JPEG's subsampling format is unsupported";
  127. return false;
  128. }
  129. // Validate the visible size.
  130. if (jpeg.frame_header.visible_width == 0u) {
  131. DLOG(ERROR) << "Visible width can't be zero";
  132. return false;
  133. }
  134. if (jpeg.frame_header.visible_height == 0u) {
  135. DLOG(ERROR) << "Visible height can't be zero";
  136. return false;
  137. }
  138. // Validate the coded size.
  139. gfx::Size min_jpeg_resolution;
  140. gfx::Size max_jpeg_resolution;
  141. if (!VaapiWrapper::GetSupportedResolutions(
  142. VAProfileJPEGBaseline, VaapiWrapper::CodecMode::kDecode,
  143. min_jpeg_resolution, max_jpeg_resolution)) {
  144. DLOG(ERROR) << "Could not get the minimum and maximum resolutions";
  145. return false;
  146. }
  147. const int actual_jpeg_coded_width =
  148. base::strict_cast<int>(jpeg.frame_header.coded_width);
  149. const int actual_jpeg_coded_height =
  150. base::strict_cast<int>(jpeg.frame_header.coded_height);
  151. if (actual_jpeg_coded_width < min_jpeg_resolution.width() ||
  152. actual_jpeg_coded_height < min_jpeg_resolution.height() ||
  153. actual_jpeg_coded_width > max_jpeg_resolution.width() ||
  154. actual_jpeg_coded_height > max_jpeg_resolution.height()) {
  155. DLOG(ERROR) << "VAAPI doesn't support size " << actual_jpeg_coded_width
  156. << "x" << actual_jpeg_coded_height << ": not in range "
  157. << min_jpeg_resolution.ToString() << " - "
  158. << max_jpeg_resolution.ToString();
  159. return false;
  160. }
  161. return true;
  162. }
  163. } // namespace
  164. unsigned int VaSurfaceFormatForJpeg(const JpegFrameHeader& frame_header) {
  165. if (frame_header.num_components != 3)
  166. return kInvalidVaRtFormat;
  167. const uint8_t y_h = frame_header.components[0].horizontal_sampling_factor;
  168. const uint8_t y_v = frame_header.components[0].vertical_sampling_factor;
  169. const uint8_t u_h = frame_header.components[1].horizontal_sampling_factor;
  170. const uint8_t u_v = frame_header.components[1].vertical_sampling_factor;
  171. const uint8_t v_h = frame_header.components[2].horizontal_sampling_factor;
  172. const uint8_t v_v = frame_header.components[2].vertical_sampling_factor;
  173. if (u_h != 1 || u_v != 1 || v_h != 1 || v_v != 1)
  174. return kInvalidVaRtFormat;
  175. if (y_h == 2 && y_v == 2)
  176. return VA_RT_FORMAT_YUV420;
  177. else if (y_h == 2 && y_v == 1)
  178. return VA_RT_FORMAT_YUV422;
  179. else if (y_h == 1 && y_v == 1)
  180. return VA_RT_FORMAT_YUV444;
  181. return kInvalidVaRtFormat;
  182. }
  183. VaapiJpegDecoder::VaapiJpegDecoder()
  184. : VaapiImageDecoder(VAProfileJPEGBaseline) {}
  185. VaapiJpegDecoder::~VaapiJpegDecoder() = default;
  186. VaapiImageDecodeStatus VaapiJpegDecoder::AllocateVASurfaceAndSubmitVABuffers(
  187. base::span<const uint8_t> encoded_image) {
  188. DCHECK(vaapi_wrapper_);
  189. // Parse the JPEG encoded data.
  190. JpegParseResult parse_result;
  191. if (!ParseJpegPicture(encoded_image.data(), encoded_image.size(),
  192. &parse_result)) {
  193. VLOGF(1) << "ParseJpegPicture failed";
  194. return VaapiImageDecodeStatus::kParseFailed;
  195. }
  196. // Figure out the right format for the VaSurface.
  197. const unsigned int picture_va_rt_format =
  198. VaSurfaceFormatForJpeg(parse_result.frame_header);
  199. if (picture_va_rt_format == kInvalidVaRtFormat) {
  200. VLOGF(1) << "Unsupported subsampling";
  201. return VaapiImageDecodeStatus::kUnsupportedSubsampling;
  202. }
  203. // Make sure this JPEG can be decoded.
  204. if (!IsVaapiSupportedJpeg(parse_result)) {
  205. VLOGF(1) << "The supplied JPEG is unsupported";
  206. return VaapiImageDecodeStatus::kUnsupportedImage;
  207. }
  208. // Prepare the surface for decoding.
  209. const gfx::Size new_visible_size(
  210. base::strict_cast<int>(parse_result.frame_header.visible_width),
  211. base::strict_cast<int>(parse_result.frame_header.visible_height));
  212. const gfx::Size new_coded_size(
  213. base::strict_cast<int>(parse_result.frame_header.coded_width),
  214. base::strict_cast<int>(parse_result.frame_header.coded_height));
  215. if (!MaybeCreateSurface(picture_va_rt_format, new_coded_size,
  216. new_visible_size)) {
  217. return VaapiImageDecodeStatus::kSurfaceCreationFailed;
  218. }
  219. // Submit input buffers.
  220. if (!SubmitBuffers(parse_result))
  221. return VaapiImageDecodeStatus::kSubmitVABuffersFailed;
  222. return VaapiImageDecodeStatus::kSuccess;
  223. }
  224. gpu::ImageDecodeAcceleratorType VaapiJpegDecoder::GetType() const {
  225. return gpu::ImageDecodeAcceleratorType::kJpeg;
  226. }
  227. SkYUVColorSpace VaapiJpegDecoder::GetYUVColorSpace() const {
  228. return SkYUVColorSpace::kJPEG_SkYUVColorSpace;
  229. }
  230. std::unique_ptr<ScopedVAImage> VaapiJpegDecoder::GetImage(
  231. uint32_t preferred_image_fourcc,
  232. VaapiImageDecodeStatus* status) {
  233. if (!scoped_va_context_and_surface_) {
  234. VLOGF(1) << "No decoded JPEG available";
  235. *status = VaapiImageDecodeStatus::kInvalidState;
  236. return nullptr;
  237. }
  238. DCHECK(scoped_va_context_and_surface_->IsValid());
  239. DCHECK(vaapi_wrapper_);
  240. uint32_t image_fourcc;
  241. if (!VaapiWrapper::GetJpegDecodeSuitableImageFourCC(
  242. scoped_va_context_and_surface_->format(), preferred_image_fourcc,
  243. &image_fourcc)) {
  244. VLOGF(1) << "Cannot determine the output FOURCC";
  245. *status = VaapiImageDecodeStatus::kCannotGetImage;
  246. return nullptr;
  247. }
  248. VAImageFormat image_format{.fourcc = image_fourcc};
  249. // In at least one driver, the VPP seems to have problems if we request a
  250. // VAImage with odd dimensions. Rather than debugging the issue in depth, we
  251. // disable support for odd dimensions since the VAImage path is only expected
  252. // to be used in camera captures (and we don't expect JPEGs with odd
  253. // dimensions in that path).
  254. if ((scoped_va_context_and_surface_->size().width() & 1) ||
  255. (scoped_va_context_and_surface_->size().height() & 1)) {
  256. VLOGF(1) << "Getting images with odd dimensions is not supported";
  257. *status = VaapiImageDecodeStatus::kCannotGetImage;
  258. NOTREACHED();
  259. return nullptr;
  260. }
  261. auto scoped_image = vaapi_wrapper_->CreateVaImage(
  262. scoped_va_context_and_surface_->id(), &image_format,
  263. scoped_va_context_and_surface_->size());
  264. if (!scoped_image) {
  265. VLOGF(1) << "Cannot get VAImage, FOURCC = "
  266. << FourccToString(image_format.fourcc);
  267. *status = VaapiImageDecodeStatus::kCannotGetImage;
  268. return nullptr;
  269. }
  270. *status = VaapiImageDecodeStatus::kSuccess;
  271. return scoped_image;
  272. }
  273. bool VaapiJpegDecoder::MaybeCreateSurface(unsigned int picture_va_rt_format,
  274. const gfx::Size& new_coded_size,
  275. const gfx::Size& new_visible_size) {
  276. DCHECK(!scoped_va_context_and_surface_ ||
  277. scoped_va_context_and_surface_->IsValid());
  278. if (scoped_va_context_and_surface_ &&
  279. new_visible_size == scoped_va_context_and_surface_->size() &&
  280. picture_va_rt_format == scoped_va_context_and_surface_->format()) {
  281. // No need to allocate a new surface. We can re-use the current one.
  282. return true;
  283. }
  284. scoped_va_context_and_surface_.reset();
  285. // We'll request a surface of |new_coded_size| from the VAAPI, but we will
  286. // keep track of the |new_visible_size| inside the ScopedVASurface so that
  287. // when we create a VAImage or export the surface as a NativePixmapDmaBuf, we
  288. // can report the size that clients should be using to read the contents.
  289. auto scoped_va_surfaces = vaapi_wrapper_->CreateContextAndScopedVASurfaces(
  290. picture_va_rt_format, new_coded_size,
  291. {VaapiWrapper::SurfaceUsageHint::kGeneric}, 1u, new_visible_size);
  292. if (scoped_va_surfaces.empty()) {
  293. VLOGF(1) << "CreateContextAndScopedVASurface() failed";
  294. return false;
  295. }
  296. scoped_va_context_and_surface_.reset(scoped_va_surfaces[0].release());
  297. DCHECK(scoped_va_context_and_surface_->IsValid());
  298. return true;
  299. }
  300. bool VaapiJpegDecoder::SubmitBuffers(const JpegParseResult& parse_result) {
  301. // Set picture parameters.
  302. VAPictureParameterBufferJPEGBaseline pic_param{};
  303. FillPictureParameters(parse_result.frame_header, &pic_param);
  304. // Set quantization table.
  305. VAIQMatrixBufferJPEGBaseline iq_matrix{};
  306. FillIQMatrix(parse_result.q_table, &iq_matrix);
  307. // Set huffman table.
  308. VAHuffmanTableBufferJPEGBaseline huffman_table{};
  309. FillHuffmanTable(parse_result.dc_table, parse_result.ac_table,
  310. &huffman_table);
  311. // Set slice parameters.
  312. VASliceParameterBufferJPEGBaseline slice_param{};
  313. FillSliceParameters(parse_result, &slice_param);
  314. return vaapi_wrapper_->SubmitBuffers(
  315. {{VAPictureParameterBufferType, sizeof(pic_param), &pic_param},
  316. {VAIQMatrixBufferType, sizeof(iq_matrix), &iq_matrix},
  317. {VAHuffmanTableBufferType, sizeof(huffman_table), &huffman_table},
  318. {VASliceParameterBufferType, sizeof(slice_param), &slice_param},
  319. {VASliceDataBufferType, parse_result.data_size,
  320. const_cast<char*>(parse_result.data)}});
  321. }
  322. } // namespace media