vaapi_dmabuf_video_frame_mapper.cc 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. // Copyright 2018 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_dmabuf_video_frame_mapper.h"
  5. #include <sys/mman.h>
  6. #include "base/bind.h"
  7. #include "base/callback_helpers.h"
  8. #include "base/memory/ptr_util.h"
  9. #include "build/build_config.h"
  10. #include "media/base/color_plane_layout.h"
  11. #include "media/gpu/chromeos/platform_video_frame_utils.h"
  12. #include "media/gpu/macros.h"
  13. #include "media/gpu/vaapi/vaapi_utils.h"
  14. #include "media/gpu/vaapi/vaapi_wrapper.h"
  15. namespace media {
  16. namespace {
  17. constexpr VAImageFormat kImageFormatNV12{.fourcc = VA_FOURCC_NV12,
  18. .byte_order = VA_LSB_FIRST,
  19. .bits_per_pixel = 12};
  20. constexpr VAImageFormat kImageFormatP010{.fourcc = VA_FOURCC_P010,
  21. .byte_order = VA_LSB_FIRST,
  22. .bits_per_pixel = 16};
  23. void ConvertP010ToP016LE(const uint16_t* src,
  24. int src_stride,
  25. uint16_t* dst,
  26. int dst_stride,
  27. int width,
  28. int height) {
  29. // The P010 buffer layout is (meaningful 10bits:0) in two bytes like
  30. // ABCDEFGHIJ000000. However, libvpx's output is (0:meaningful 10bits) in two
  31. // bytes like 000000ABCDEFGHIJ. Although the P016LE buffer layout is
  32. // undefined, we locally define the layout as the same as libvpx's layout and
  33. // convert here for testing.
  34. for (int i = 0; i < height; i++) {
  35. for (int j = 0; j < width; j++) {
  36. constexpr int kShiftBits = 6;
  37. const uint16_t v = src[j];
  38. dst[j] = v >> kShiftBits;
  39. }
  40. src = reinterpret_cast<const uint16_t*>(
  41. reinterpret_cast<const uint8_t*>(src) + src_stride);
  42. dst = reinterpret_cast<uint16_t*>(reinterpret_cast<uint8_t*>(dst) +
  43. dst_stride);
  44. }
  45. }
  46. void DeallocateBuffers(std::unique_ptr<ScopedVAImage> va_image,
  47. scoped_refptr<const VideoFrame> /* video_frame */) {
  48. // The |video_frame| will be released here and it will be returned to pool if
  49. // client uses video frame pool.
  50. // Destructing ScopedVAImage releases its owned memory.
  51. DCHECK(va_image->IsValid());
  52. }
  53. scoped_refptr<VideoFrame> CreateMappedVideoFrame(
  54. scoped_refptr<const VideoFrame> src_video_frame,
  55. std::unique_ptr<ScopedVAImage> va_image) {
  56. DCHECK(va_image);
  57. // ScopedVAImage manages the resource of mapped data. That is, ScopedVAImage's
  58. // dtor releases the mapped resource.
  59. constexpr size_t kNumPlanes = 2u;
  60. DCHECK_EQ(VideoFrame::NumPlanes(src_video_frame->format()), kNumPlanes);
  61. if (va_image->image()->num_planes != kNumPlanes) {
  62. VLOGF(1) << "The number of planes of VAImage is not expected. "
  63. << "(expected: " << kNumPlanes
  64. << ", VAImage: " << va_image->image()->num_planes << ")";
  65. return nullptr;
  66. }
  67. // All the planes are stored in the same buffer, VAImage.va_buffer.
  68. std::vector<ColorPlaneLayout> planes(kNumPlanes);
  69. uint8_t* addrs[VideoFrame::kMaxPlanes] = {};
  70. for (size_t i = 0; i < kNumPlanes; i++) {
  71. planes[i].stride = va_image->image()->pitches[i];
  72. planes[i].offset = va_image->image()->offsets[i];
  73. addrs[i] = static_cast<uint8_t*>(va_image->va_buffer()->data()) +
  74. va_image->image()->offsets[i];
  75. }
  76. // The size of each plane is not given by VAImage. We compute the size to be
  77. // mapped from offset and the entire buffer size (data_size).
  78. for (size_t i = 0; i < kNumPlanes; i++) {
  79. if (i < kNumPlanes - 1)
  80. planes[i].size = planes[i + 1].offset - planes[i].offset;
  81. else
  82. planes[i].size = va_image->image()->data_size - planes[i].offset;
  83. }
  84. // Create new buffers and copy P010 buffers into because we should not modify
  85. // va_image->va_buffer->data().
  86. std::vector<std::unique_ptr<uint16_t[]>> p016le_buffers(kNumPlanes);
  87. if (src_video_frame->format() == PIXEL_FORMAT_P016LE) {
  88. for (size_t i = 0; i < kNumPlanes; i++) {
  89. const gfx::Size plane_dimensions_in_bytes = VideoFrame::PlaneSize(
  90. PIXEL_FORMAT_P016LE, i, src_video_frame->visible_rect().size());
  91. const gfx::Size plane_dimensions_in_16bit_words(
  92. plane_dimensions_in_bytes.width() / 2,
  93. plane_dimensions_in_bytes.height());
  94. p016le_buffers[i] = std::make_unique<uint16_t[]>(planes[i].size / 2);
  95. ConvertP010ToP016LE(reinterpret_cast<const uint16_t*>(addrs[i]),
  96. planes[i].stride, p016le_buffers[i].get(),
  97. planes[i].stride,
  98. plane_dimensions_in_16bit_words.width(),
  99. plane_dimensions_in_16bit_words.height());
  100. addrs[i] = reinterpret_cast<uint8_t*>(p016le_buffers[i].get());
  101. }
  102. }
  103. auto mapped_layout = VideoFrameLayout::CreateWithPlanes(
  104. src_video_frame->format(),
  105. gfx::Size(va_image->image()->width, va_image->image()->height),
  106. std::move(planes));
  107. if (!mapped_layout) {
  108. VLOGF(1) << "Failed to create VideoFrameLayout for VAImage";
  109. return nullptr;
  110. }
  111. auto video_frame = VideoFrame::WrapExternalYuvDataWithLayout(
  112. *mapped_layout, src_video_frame->visible_rect(),
  113. src_video_frame->visible_rect().size(), addrs[0], addrs[1], addrs[2],
  114. src_video_frame->timestamp());
  115. if (!video_frame)
  116. return nullptr;
  117. // The source video frame should not be released until the mapped
  118. // |video_frame| is destructed, because |video_frame| holds |va_image|.
  119. video_frame->AddDestructionObserver(base::BindOnce(
  120. DeallocateBuffers, std::move(va_image), std::move(src_video_frame)));
  121. for (auto&& buffer : p016le_buffers) {
  122. video_frame->AddDestructionObserver(
  123. base::BindOnce([](std::unique_ptr<uint16_t[]>) {}, std::move(buffer)));
  124. }
  125. return video_frame;
  126. }
  127. bool IsFormatSupported(VideoPixelFormat format) {
  128. return format == PIXEL_FORMAT_NV12 || format == PIXEL_FORMAT_P016LE;
  129. }
  130. } // namespace
  131. // static
  132. std::unique_ptr<VideoFrameMapper> VaapiDmaBufVideoFrameMapper::Create(
  133. VideoPixelFormat format) {
  134. if (!IsFormatSupported(format)) {
  135. VLOGF(1) << " Unsupported format: " << VideoPixelFormatToString(format);
  136. return nullptr;
  137. }
  138. auto video_frame_mapper =
  139. base::WrapUnique(new VaapiDmaBufVideoFrameMapper(format));
  140. if (!video_frame_mapper->vaapi_wrapper_)
  141. return nullptr;
  142. return video_frame_mapper;
  143. }
  144. VaapiDmaBufVideoFrameMapper::VaapiDmaBufVideoFrameMapper(
  145. VideoPixelFormat format)
  146. : VideoFrameMapper(format),
  147. vaapi_wrapper_(VaapiWrapper::Create(VaapiWrapper::kVideoProcess,
  148. VAProfileNone,
  149. EncryptionScheme::kUnencrypted,
  150. base::DoNothing())) {}
  151. VaapiDmaBufVideoFrameMapper::~VaapiDmaBufVideoFrameMapper() {}
  152. scoped_refptr<VideoFrame> VaapiDmaBufVideoFrameMapper::Map(
  153. scoped_refptr<const VideoFrame> video_frame,
  154. int permissions) const {
  155. DCHECK(vaapi_wrapper_);
  156. if (!video_frame) {
  157. LOG(ERROR) << "Video frame is nullptr";
  158. return nullptr;
  159. }
  160. if (!(permissions & PROT_READ && permissions & PROT_WRITE)) {
  161. LOG(ERROR) << "VAAPI DMA Buffer must be mapped read/write.";
  162. return nullptr;
  163. }
  164. if (!video_frame->HasDmaBufs())
  165. return nullptr;
  166. if (video_frame->format() != format_) {
  167. VLOGF(1) << "Unexpected format, got: "
  168. << VideoPixelFormatToString(video_frame->format())
  169. << ", expected: " << VideoPixelFormatToString(format_);
  170. return nullptr;
  171. }
  172. scoped_refptr<gfx::NativePixmap> pixmap =
  173. CreateNativePixmapDmaBuf(video_frame.get());
  174. if (!pixmap) {
  175. VLOGF(1) << "Failed to create NativePixmap from VideoFrame";
  176. return nullptr;
  177. }
  178. scoped_refptr<VASurface> va_surface =
  179. vaapi_wrapper_->CreateVASurfaceForPixmap(std::move(pixmap));
  180. if (!va_surface) {
  181. VLOGF(1) << "Failed to create VASurface";
  182. return nullptr;
  183. }
  184. // Map tiled NV12 or P010 buffer by CreateVaImage so that mapped buffers can
  185. // be accessed as non-tiled NV12 or P016LE buffer.
  186. VAImageFormat va_image_format = video_frame->format() == PIXEL_FORMAT_NV12
  187. ? kImageFormatNV12
  188. : kImageFormatP010;
  189. auto va_image = vaapi_wrapper_->CreateVaImage(
  190. va_surface->id(), &va_image_format, va_surface->size());
  191. if (!va_image || !va_image->IsValid()) {
  192. VLOGF(1) << "Failed in CreateVaImage.";
  193. return nullptr;
  194. }
  195. return CreateMappedVideoFrame(std::move(video_frame), std::move(va_image));
  196. }
  197. } // namespace media