vaapi_jpeg_encoder.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. // Copyright 2017 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_encoder.h"
  5. #include <array>
  6. #include <type_traits>
  7. #include <stddef.h>
  8. #include <string.h>
  9. #include "base/check_op.h"
  10. #include "base/cxx17_backports.h"
  11. #include "base/numerics/safe_conversions.h"
  12. #include "media/gpu/macros.h"
  13. #include "media/gpu/vaapi/vaapi_wrapper.h"
  14. #include "media/parsers/jpeg_parser.h"
  15. namespace media {
  16. namespace {
  17. void FillPictureParameters(const gfx::Size& input_size,
  18. int quality,
  19. VABufferID output_buffer_id,
  20. VAEncPictureParameterBufferJPEG* pic_param) {
  21. pic_param->picture_width = input_size.width();
  22. pic_param->picture_height = input_size.height();
  23. pic_param->num_components = 3;
  24. // Output buffer.
  25. pic_param->coded_buf = output_buffer_id;
  26. pic_param->quality = quality;
  27. // Profile = Baseline.
  28. pic_param->pic_flags.bits.profile = 0;
  29. // Sequential encoding.
  30. pic_param->pic_flags.bits.progressive = 0;
  31. // Uses Huffman coding.
  32. pic_param->pic_flags.bits.huffman = 1;
  33. // Input format is interleaved (YUV).
  34. pic_param->pic_flags.bits.interleaved = 0;
  35. // Non-differential Encoding.
  36. pic_param->pic_flags.bits.differential = 0;
  37. // Only 8 bit sample depth is currently supported.
  38. pic_param->sample_bit_depth = 8;
  39. pic_param->num_scan = 1;
  40. }
  41. void FillQMatrix(VAQMatrixBufferJPEG* q_matrix) {
  42. // Fill the raw, unscaled quantization tables for libva. The VAAPI driver is
  43. // responsible for scaling the quantization tables based on picture
  44. // parameter quality.
  45. const JpegQuantizationTable& luminance = kDefaultQuantTable[0];
  46. static_assert(std::extent<decltype(luminance.value)>() ==
  47. std::extent<decltype(q_matrix->lum_quantiser_matrix)>(),
  48. "Luminance quantization table size mismatch.");
  49. static_assert(std::size(kZigZag8x8) == std::size(luminance.value),
  50. "Luminance quantization table size mismatch.");
  51. q_matrix->load_lum_quantiser_matrix = 1;
  52. for (size_t i = 0; i < std::size(kZigZag8x8); i++) {
  53. q_matrix->lum_quantiser_matrix[i] = luminance.value[kZigZag8x8[i]];
  54. }
  55. const JpegQuantizationTable& chrominance = kDefaultQuantTable[1];
  56. static_assert(std::extent<decltype(chrominance.value)>() ==
  57. std::extent<decltype(q_matrix->chroma_quantiser_matrix)>(),
  58. "Chrominance quantization table size mismatch.");
  59. static_assert(std::size(kZigZag8x8) == std::size(chrominance.value),
  60. "Chrominance quantization table size mismatch.");
  61. q_matrix->load_chroma_quantiser_matrix = 1;
  62. for (size_t i = 0; i < std::size(kZigZag8x8); i++) {
  63. q_matrix->chroma_quantiser_matrix[i] = chrominance.value[kZigZag8x8[i]];
  64. }
  65. }
  66. void FillHuffmanTableParameters(
  67. VAHuffmanTableBufferJPEGBaseline* huff_table_param) {
  68. static_assert(std::size(kDefaultDcTable) == std::size(kDefaultAcTable),
  69. "DC table and AC table size mismatch.");
  70. static_assert(std::size(kDefaultDcTable) ==
  71. std::extent<decltype(huff_table_param->huffman_table)>(),
  72. "DC table and destination table size mismatch.");
  73. for (size_t i = 0; i < std::size(kDefaultDcTable); ++i) {
  74. const JpegHuffmanTable& dcTable = kDefaultDcTable[i];
  75. const JpegHuffmanTable& acTable = kDefaultAcTable[i];
  76. huff_table_param->load_huffman_table[i] = true;
  77. // Load DC Table.
  78. SafeArrayMemcpy(huff_table_param->huffman_table[i].num_dc_codes,
  79. dcTable.code_length);
  80. // |code_values| of JpegHuffmanTable needs to hold DC and AC code values
  81. // so it has different size than
  82. // |huff_table_param->huffman_table[i].dc_values|. Therefore we can't use
  83. // SafeArrayMemcpy() here.
  84. static_assert(
  85. std::extent<decltype(huff_table_param->huffman_table[i].dc_values)>() <=
  86. std::extent<decltype(dcTable.code_value)>(),
  87. "DC table code value array too small.");
  88. memcpy(huff_table_param->huffman_table[i].dc_values, &dcTable.code_value[0],
  89. sizeof(huff_table_param->huffman_table[i].dc_values));
  90. // Load AC Table.
  91. SafeArrayMemcpy(huff_table_param->huffman_table[i].num_ac_codes,
  92. acTable.code_length);
  93. SafeArrayMemcpy(huff_table_param->huffman_table[i].ac_values,
  94. acTable.code_value);
  95. memset(huff_table_param->huffman_table[i].pad, 0,
  96. sizeof(huff_table_param->huffman_table[i].pad));
  97. }
  98. }
  99. void FillSliceParameters(VAEncSliceParameterBufferJPEG* slice_param) {
  100. slice_param->restart_interval = 0;
  101. slice_param->num_components = 3;
  102. slice_param->components[0].component_selector = 1;
  103. slice_param->components[0].dc_table_selector = 0;
  104. slice_param->components[0].ac_table_selector = 0;
  105. slice_param->components[1].component_selector = 2;
  106. slice_param->components[1].dc_table_selector = 1;
  107. slice_param->components[1].ac_table_selector = 1;
  108. slice_param->components[2].component_selector = 3;
  109. slice_param->components[2].dc_table_selector = 1;
  110. slice_param->components[2].ac_table_selector = 1;
  111. }
  112. size_t FillJpegHeader(const gfx::Size& input_size,
  113. const uint8_t* exif_buffer,
  114. size_t exif_buffer_size,
  115. int quality,
  116. uint8_t* header,
  117. size_t* exif_offset) {
  118. unsigned int width = input_size.width();
  119. unsigned int height = input_size.height();
  120. size_t idx = 0;
  121. // Start Of Input.
  122. static const uint8_t kSOI[] = {0xFF, JPEG_SOI};
  123. memcpy(header, kSOI, sizeof(kSOI));
  124. idx += sizeof(kSOI);
  125. if (exif_buffer_size > 0) {
  126. // Application Segment for Exif data.
  127. uint16_t exif_segment_size = static_cast<uint16_t>(exif_buffer_size + 2);
  128. const uint8_t kAppSegment[] = {
  129. 0xFF, JPEG_APP1, static_cast<uint8_t>(exif_segment_size / 256),
  130. static_cast<uint8_t>(exif_segment_size % 256)};
  131. memcpy(header + idx, kAppSegment, sizeof(kAppSegment));
  132. idx += sizeof(kAppSegment);
  133. *exif_offset = idx;
  134. memcpy(header + idx, exif_buffer, exif_buffer_size);
  135. idx += exif_buffer_size;
  136. } else {
  137. // Application Segment - JFIF standard 1.01.
  138. static const uint8_t kAppSegment[] = {
  139. 0xFF, JPEG_APP0, 0x00,
  140. 0x10, // Segment length:16 (2-byte).
  141. 0x4A, // J
  142. 0x46, // F
  143. 0x49, // I
  144. 0x46, // F
  145. 0x00, // 0
  146. 0x01, // Major version.
  147. 0x01, // Minor version.
  148. 0x01, // Density units 0:no units, 1:pixels per inch,
  149. // 2: pixels per cm.
  150. 0x00,
  151. 0x48, // X density (2-byte).
  152. 0x00,
  153. 0x48, // Y density (2-byte).
  154. 0x00, // Thumbnail width.
  155. 0x00 // Thumbnail height.
  156. };
  157. memcpy(header + idx, kAppSegment, sizeof(kAppSegment));
  158. idx += sizeof(kAppSegment);
  159. }
  160. if (quality <= 0) {
  161. quality = 1;
  162. }
  163. // Normalize quality factor.
  164. // Unlike VAQMatrixBufferJPEG, we have to scale quantization table in JPEG
  165. // header by ourselves.
  166. uint32_t quality_normalized = base::saturated_cast<uint32_t>(
  167. (quality < 50) ? (5000 / quality) : (200 - (quality * 2)));
  168. // Quantization Tables.
  169. for (size_t i = 0; i < 2; ++i) {
  170. const uint8_t kQuantSegment[] = {
  171. 0xFF, JPEG_DQT, 0x00,
  172. 0x03 + kDctSize, // Segment length:67 (2-byte).
  173. static_cast<uint8_t>(i) // Precision (4-bit high) = 0,
  174. // Index (4-bit low) = i.
  175. };
  176. memcpy(header + idx, kQuantSegment, sizeof(kQuantSegment));
  177. idx += sizeof(kQuantSegment);
  178. const JpegQuantizationTable& quant_table = kDefaultQuantTable[i];
  179. for (size_t j = 0; j < kDctSize; ++j) {
  180. // The iHD media driver shifts the quantization values
  181. // by 50 while encoding. We should add 50 here to
  182. // ensure the correctness in the packed header that is
  183. // directly stuffed into the bitstream as JPEG headers.
  184. // GStreamer test cases show a psnr improvement in
  185. // Y plane (41.27 to 48.31) with this quirk.
  186. const static uint32_t shift =
  187. VaapiWrapper::GetImplementationType() == VAImplementation::kIntelIHD ? 50 : 0;
  188. uint32_t scaled_quant_value =
  189. (quant_table.value[kZigZag8x8[j]] * quality_normalized + shift) / 100;
  190. scaled_quant_value = base::clamp(scaled_quant_value, 1u, 255u);
  191. header[idx++] = static_cast<uint8_t>(scaled_quant_value);
  192. }
  193. }
  194. // Start of Frame - Baseline.
  195. const uint8_t kStartOfFrame[] = {
  196. 0xFF,
  197. JPEG_SOF0, // Baseline.
  198. 0x00,
  199. 0x11, // Segment length:17 (2-byte).
  200. 8, // Data precision.
  201. static_cast<uint8_t>((height >> 8) & 0xFF),
  202. static_cast<uint8_t>(height & 0xFF),
  203. static_cast<uint8_t>((width >> 8) & 0xFF),
  204. static_cast<uint8_t>(width & 0xFF),
  205. 0x03, // Number of Components.
  206. };
  207. memcpy(header + idx, kStartOfFrame, sizeof(kStartOfFrame));
  208. idx += sizeof(kStartOfFrame);
  209. for (uint8_t i = 0; i < 3; ++i) {
  210. // These are the values for U and V planes.
  211. uint8_t h_sample_factor = 1;
  212. uint8_t v_sample_factor = 1;
  213. uint8_t quant_table_number = 1;
  214. if (!i) {
  215. // These are the values for Y plane.
  216. h_sample_factor = 2;
  217. v_sample_factor = 2;
  218. quant_table_number = 0;
  219. }
  220. header[idx++] = i + 1;
  221. // Horizontal Sample Factor (4-bit high),
  222. // Vertical Sample Factor (4-bit low).
  223. header[idx++] = (h_sample_factor << 4) | v_sample_factor;
  224. header[idx++] = quant_table_number;
  225. }
  226. static const uint8_t kDcSegment[] = {
  227. 0xFF, JPEG_DHT, 0x00,
  228. 0x1F, // Segment length:31 (2-byte).
  229. };
  230. static const uint8_t kAcSegment[] = {
  231. 0xFF, JPEG_DHT, 0x00,
  232. 0xB5, // Segment length:181 (2-byte).
  233. };
  234. // Huffman Tables.
  235. for (size_t i = 0; i < 2; ++i) {
  236. // DC Table.
  237. memcpy(header + idx, kDcSegment, sizeof(kDcSegment));
  238. idx += sizeof(kDcSegment);
  239. // Type (4-bit high) = 0:DC, Index (4-bit low).
  240. header[idx++] = static_cast<uint8_t>(i);
  241. const JpegHuffmanTable& dcTable = kDefaultDcTable[i];
  242. for (size_t j = 0; j < kNumDcRunSizeBits; ++j)
  243. header[idx++] = dcTable.code_length[j];
  244. for (size_t j = 0; j < kNumDcCodeWordsHuffVal; ++j)
  245. header[idx++] = dcTable.code_value[j];
  246. // AC Table.
  247. memcpy(header + idx, kAcSegment, sizeof(kAcSegment));
  248. idx += sizeof(kAcSegment);
  249. // Type (4-bit high) = 1:AC, Index (4-bit low).
  250. header[idx++] = 0x10 | static_cast<uint8_t>(i);
  251. const JpegHuffmanTable& acTable = kDefaultAcTable[i];
  252. for (size_t j = 0; j < kNumAcRunSizeBits; ++j)
  253. header[idx++] = acTable.code_length[j];
  254. for (size_t j = 0; j < kNumAcCodeWordsHuffVal; ++j)
  255. header[idx++] = acTable.code_value[j];
  256. }
  257. // Start of Scan.
  258. static const uint8_t kStartOfScan[] = {
  259. 0xFF, JPEG_SOS, 0x00,
  260. 0x0C, // Segment Length:12 (2-byte).
  261. 0x03 // Number of components in scan.
  262. };
  263. memcpy(header + idx, kStartOfScan, sizeof(kStartOfScan));
  264. idx += sizeof(kStartOfScan);
  265. for (uint8_t i = 0; i < 3; ++i) {
  266. uint8_t dc_table_number = 1;
  267. uint8_t ac_table_number = 1;
  268. if (!i) {
  269. dc_table_number = 0;
  270. ac_table_number = 0;
  271. }
  272. header[idx++] = i + 1;
  273. // DC Table Selector (4-bit high), AC Table Selector (4-bit low).
  274. header[idx++] = (dc_table_number << 4) | ac_table_number;
  275. }
  276. header[idx++] = 0x00; // 0 for Baseline.
  277. header[idx++] = 0x3F; // 63 for Baseline.
  278. header[idx++] = 0x00; // 0 for Baseline.
  279. return idx << 3;
  280. }
  281. } // namespace
  282. VaapiJpegEncoder::VaapiJpegEncoder(scoped_refptr<VaapiWrapper> vaapi_wrapper)
  283. : vaapi_wrapper_(vaapi_wrapper),
  284. q_matrix_cached_(nullptr),
  285. huff_table_param_cached_(nullptr),
  286. slice_param_cached_(nullptr) {}
  287. VaapiJpegEncoder::~VaapiJpegEncoder() {}
  288. size_t VaapiJpegEncoder::GetMaxCodedBufferSize(const gfx::Size& size) {
  289. return size.GetArea() * 3 / 2 + kJpegDefaultHeaderSize;
  290. }
  291. bool VaapiJpegEncoder::Encode(const gfx::Size& input_size,
  292. const uint8_t* exif_buffer,
  293. size_t exif_buffer_size,
  294. int quality,
  295. VASurfaceID surface_id,
  296. VABufferID output_buffer_id,
  297. size_t* exif_offset) {
  298. DCHECK_NE(surface_id, VA_INVALID_SURFACE);
  299. if (input_size.width() > kMaxDimension ||
  300. input_size.height() > kMaxDimension) {
  301. return false;
  302. }
  303. // Set picture parameters.
  304. VAEncPictureParameterBufferJPEG pic_param;
  305. FillPictureParameters(input_size, quality, output_buffer_id, &pic_param);
  306. if (!q_matrix_cached_) {
  307. q_matrix_cached_.reset(new VAQMatrixBufferJPEG());
  308. FillQMatrix(q_matrix_cached_.get());
  309. }
  310. if (!huff_table_param_cached_) {
  311. huff_table_param_cached_.reset(new VAHuffmanTableBufferJPEGBaseline());
  312. FillHuffmanTableParameters(huff_table_param_cached_.get());
  313. }
  314. // Set slice parameters.
  315. if (!slice_param_cached_) {
  316. slice_param_cached_.reset(new VAEncSliceParameterBufferJPEG());
  317. FillSliceParameters(slice_param_cached_.get());
  318. }
  319. size_t jpeg_header_size =
  320. exif_buffer_size > 0
  321. ? kJpegDefaultHeaderSize + kJFIFApp1HeaderSize + exif_buffer_size
  322. : kJpegDefaultHeaderSize + kJFIFApp0Size;
  323. std::vector<uint8_t> jpeg_header(jpeg_header_size);
  324. const size_t length_in_bits =
  325. FillJpegHeader(input_size, exif_buffer, exif_buffer_size, quality,
  326. jpeg_header.data(), exif_offset);
  327. VAEncPackedHeaderParameterBuffer header_param;
  328. memset(&header_param, 0, sizeof(header_param));
  329. header_param.type = VAEncPackedHeaderRawData;
  330. header_param.bit_length = length_in_bits;
  331. header_param.has_emulation_bytes = 0;
  332. if (!vaapi_wrapper_->SubmitBuffers(
  333. {{VAEncPictureParameterBufferType, sizeof(pic_param), &pic_param},
  334. {VAQMatrixBufferType, sizeof(*q_matrix_cached_),
  335. q_matrix_cached_.get()},
  336. {VAHuffmanTableBufferType, sizeof(*huff_table_param_cached_),
  337. huff_table_param_cached_.get()},
  338. {VAEncSliceParameterBufferType, sizeof(*slice_param_cached_),
  339. slice_param_cached_.get()},
  340. {VAEncPackedHeaderParameterBufferType, sizeof(header_param),
  341. &header_param},
  342. {VAEncPackedHeaderDataBufferType, (length_in_bits + 7) / 8,
  343. jpeg_header.data()}})) {
  344. return false;
  345. }
  346. // Submit the |surface_id| which contains input YUV frame and begin encoding.
  347. return vaapi_wrapper_->ExecuteAndDestroyPendingBuffers(surface_id);
  348. }
  349. } // namespace media