mojo_mjpeg_decode_accelerator_service.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. // Copyright 2015 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 "components/chromeos_camera/mojo_mjpeg_decode_accelerator_service.h"
  5. #include <stdint.h>
  6. #include <memory>
  7. #include <utility>
  8. #include "base/bind.h"
  9. #include "base/callback_helpers.h"
  10. #include "base/files/platform_file.h"
  11. #include "base/files/scoped_file.h"
  12. #include "base/logging.h"
  13. #include "base/memory/ptr_util.h"
  14. #include "base/memory/unsafe_shared_memory_region.h"
  15. #include "base/numerics/safe_conversions.h"
  16. #include "base/threading/thread_task_runner_handle.h"
  17. #include "base/time/time.h"
  18. #include "base/trace_event/trace_event.h"
  19. #include "components/chromeos_camera/common/dmabuf.mojom.h"
  20. #include "components/chromeos_camera/dmabuf_utils.h"
  21. #include "media/base/bitstream_buffer.h"
  22. #include "media/base/video_frame.h"
  23. #include "mojo/public/cpp/bindings/self_owned_receiver.h"
  24. #include "mojo/public/cpp/system/platform_handle.h"
  25. #include "ui/gfx/geometry/rect.h"
  26. #include "ui/gfx/geometry/size.h"
  27. namespace {
  28. bool VerifyDecodeParams(const gfx::Size& coded_size,
  29. mojo::ScopedSharedBufferHandle* output_handle,
  30. uint32_t output_buffer_size) {
  31. const int kJpegMaxDimension = UINT16_MAX;
  32. if (coded_size.IsEmpty() || coded_size.width() > kJpegMaxDimension ||
  33. coded_size.height() > kJpegMaxDimension) {
  34. LOG(ERROR) << "invalid coded_size " << coded_size.ToString();
  35. return false;
  36. }
  37. if (!output_handle->is_valid()) {
  38. LOG(ERROR) << "invalid output_handle";
  39. return false;
  40. }
  41. uint32_t allocation_size =
  42. media::VideoFrame::AllocationSize(media::PIXEL_FORMAT_I420, coded_size);
  43. if (output_buffer_size < allocation_size) {
  44. DLOG(ERROR) << "output_buffer_size is too small: " << output_buffer_size
  45. << ". It needs: " << allocation_size;
  46. return false;
  47. }
  48. return true;
  49. }
  50. } // namespace
  51. namespace chromeos_camera {
  52. // static
  53. void MojoMjpegDecodeAcceleratorService::Create(
  54. mojo::PendingReceiver<chromeos_camera::mojom::MjpegDecodeAccelerator>
  55. receiver) {
  56. auto* jpeg_decoder = new MojoMjpegDecodeAcceleratorService();
  57. mojo::MakeSelfOwnedReceiver(base::WrapUnique(jpeg_decoder),
  58. std::move(receiver));
  59. }
  60. MojoMjpegDecodeAcceleratorService::MojoMjpegDecodeAcceleratorService()
  61. : accelerator_initialized_(false), weak_this_factory_(this) {}
  62. MojoMjpegDecodeAcceleratorService::~MojoMjpegDecodeAcceleratorService() {
  63. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  64. accelerator_.reset();
  65. }
  66. void MojoMjpegDecodeAcceleratorService::VideoFrameReady(
  67. int32_t bitstream_buffer_id) {
  68. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  69. NotifyDecodeStatus(
  70. bitstream_buffer_id,
  71. ::chromeos_camera::MjpegDecodeAccelerator::Error::NO_ERRORS);
  72. }
  73. void MojoMjpegDecodeAcceleratorService::NotifyError(
  74. int32_t bitstream_buffer_id,
  75. ::chromeos_camera::MjpegDecodeAccelerator::Error error) {
  76. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  77. NotifyDecodeStatus(bitstream_buffer_id, error);
  78. }
  79. void MojoMjpegDecodeAcceleratorService::InitializeInternal(
  80. std::vector<GpuMjpegDecodeAcceleratorFactory::CreateAcceleratorCB>
  81. remaining_accelerator_factory_functions,
  82. InitializeCallback init_cb) {
  83. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  84. if (remaining_accelerator_factory_functions.empty()) {
  85. DLOG(ERROR) << "All JPEG accelerators failed to initialize";
  86. std::move(init_cb).Run(false);
  87. return;
  88. }
  89. accelerator_ = std::move(remaining_accelerator_factory_functions.front())
  90. .Run(base::ThreadTaskRunnerHandle::Get());
  91. remaining_accelerator_factory_functions.erase(
  92. remaining_accelerator_factory_functions.begin());
  93. if (!accelerator_) {
  94. OnInitialize(std::move(remaining_accelerator_factory_functions),
  95. std::move(init_cb), /*last_initialize_result=*/false);
  96. return;
  97. }
  98. accelerator_->InitializeAsync(
  99. this, base::BindOnce(&MojoMjpegDecodeAcceleratorService::OnInitialize,
  100. weak_this_factory_.GetWeakPtr(),
  101. std::move(remaining_accelerator_factory_functions),
  102. std::move(init_cb)));
  103. }
  104. void MojoMjpegDecodeAcceleratorService::Initialize(
  105. InitializeCallback callback) {
  106. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  107. // When adding non-chromeos platforms, VideoCaptureGpuJpegDecoder::Initialize
  108. // needs to be updated.
  109. InitializeInternal(
  110. GpuMjpegDecodeAcceleratorFactory::GetAcceleratorFactories(),
  111. std::move(callback));
  112. }
  113. void MojoMjpegDecodeAcceleratorService::OnInitialize(
  114. std::vector<GpuMjpegDecodeAcceleratorFactory::CreateAcceleratorCB>
  115. remaining_accelerator_factory_functions,
  116. InitializeCallback init_cb,
  117. bool last_initialize_result) {
  118. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  119. if (last_initialize_result) {
  120. accelerator_initialized_ = true;
  121. std::move(init_cb).Run(true);
  122. return;
  123. }
  124. // Note that we can't call InitializeInternal() directly. The reason is that
  125. // InitializeInternal() may destroy |accelerator_| which could cause a
  126. // use-after-free if |accelerator_| needs to do more stuff after calling
  127. // OnInitialize().
  128. base::ThreadTaskRunnerHandle::Get()->PostTask(
  129. FROM_HERE,
  130. base::BindOnce(&MojoMjpegDecodeAcceleratorService::InitializeInternal,
  131. weak_this_factory_.GetWeakPtr(),
  132. std::move(remaining_accelerator_factory_functions),
  133. std::move(init_cb)));
  134. }
  135. void MojoMjpegDecodeAcceleratorService::Decode(
  136. media::BitstreamBuffer input_buffer,
  137. const gfx::Size& coded_size,
  138. mojo::ScopedSharedBufferHandle output_handle,
  139. uint32_t output_buffer_size,
  140. DecodeCallback callback) {
  141. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  142. TRACE_EVENT0("jpeg", "MojoMjpegDecodeAcceleratorService::Decode");
  143. DCHECK_EQ(mojo_cb_map_.count(input_buffer.id()), 0u);
  144. if (mojo_cb_map_.count(input_buffer.id()) != 0) {
  145. NotifyDecodeStatus(
  146. input_buffer.id(),
  147. ::chromeos_camera::MjpegDecodeAccelerator::Error::INVALID_ARGUMENT);
  148. return;
  149. }
  150. mojo_cb_map_[input_buffer.id()] =
  151. base::BindOnce(std::move(callback), input_buffer.id());
  152. if (!VerifyDecodeParams(coded_size, &output_handle, output_buffer_size)) {
  153. NotifyDecodeStatus(
  154. input_buffer.id(),
  155. ::chromeos_camera::MjpegDecodeAccelerator::Error::INVALID_ARGUMENT);
  156. return;
  157. }
  158. base::UnsafeSharedMemoryRegion output_region =
  159. mojo::UnwrapUnsafeSharedMemoryRegion(std::move(output_handle));
  160. DCHECK(output_region.IsValid());
  161. DCHECK_GE(output_region.GetSize(), output_buffer_size);
  162. base::WritableSharedMemoryMapping mapping =
  163. output_region.MapAt(0, output_buffer_size);
  164. if (!mapping.IsValid()) {
  165. LOG(ERROR) << "Could not map output shared memory for input buffer id "
  166. << input_buffer.id();
  167. NotifyDecodeStatus(
  168. input_buffer.id(),
  169. ::chromeos_camera::MjpegDecodeAccelerator::Error::PLATFORM_FAILURE);
  170. return;
  171. }
  172. uint8_t* shm_memory = mapping.GetMemoryAsSpan<uint8_t>().data();
  173. scoped_refptr<media::VideoFrame> frame = media::VideoFrame::WrapExternalData(
  174. media::PIXEL_FORMAT_I420, // format
  175. coded_size, // coded_size
  176. gfx::Rect(coded_size), // visible_rect
  177. coded_size, // natural_size
  178. shm_memory, // data
  179. output_buffer_size, // data_size
  180. base::TimeDelta()); // timestamp
  181. if (!frame.get()) {
  182. LOG(ERROR) << "Could not create VideoFrame for input buffer id "
  183. << input_buffer.id();
  184. NotifyDecodeStatus(
  185. input_buffer.id(),
  186. ::chromeos_camera::MjpegDecodeAccelerator::Error::PLATFORM_FAILURE);
  187. return;
  188. }
  189. frame->BackWithOwnedSharedMemory(std::move(output_region),
  190. std::move(mapping));
  191. if (!accelerator_initialized_) {
  192. NotifyDecodeStatus(
  193. input_buffer.id(),
  194. ::chromeos_camera::MjpegDecodeAccelerator::Error::PLATFORM_FAILURE);
  195. return;
  196. }
  197. DCHECK(accelerator_);
  198. accelerator_->Decode(std::move(input_buffer), frame);
  199. }
  200. void MojoMjpegDecodeAcceleratorService::DecodeWithDmaBuf(
  201. int32_t task_id,
  202. mojo::ScopedHandle src_dmabuf_fd,
  203. uint32_t src_size,
  204. uint32_t src_offset,
  205. mojom::DmaBufVideoFramePtr dst_frame,
  206. DecodeWithDmaBufCallback callback) {
  207. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  208. TRACE_EVENT0("jpeg", __FUNCTION__);
  209. if (src_size == 0) {
  210. LOG(ERROR) << "Input buffer size should be positive";
  211. std::move(callback).Run(
  212. ::chromeos_camera::MjpegDecodeAccelerator::Error::INVALID_ARGUMENT);
  213. return;
  214. }
  215. mojo::PlatformHandle src_handle =
  216. mojo::UnwrapPlatformHandle(std::move(src_dmabuf_fd));
  217. if (!src_handle.is_valid()) {
  218. LOG(ERROR) << "Invalid input DMA-buf FD";
  219. std::move(callback).Run(
  220. ::chromeos_camera::MjpegDecodeAccelerator::Error::INVALID_ARGUMENT);
  221. return;
  222. }
  223. const gfx::Size coded_size(base::checked_cast<int>(dst_frame->coded_width),
  224. base::checked_cast<int>(dst_frame->coded_height));
  225. scoped_refptr<media::VideoFrame> frame = ConstructVideoFrame(
  226. std::move(dst_frame->planes), dst_frame->format, coded_size);
  227. if (!frame) {
  228. LOG(ERROR) << "Failed to create video frame";
  229. std::move(callback).Run(
  230. ::chromeos_camera::MjpegDecodeAccelerator::Error::INVALID_ARGUMENT);
  231. return;
  232. }
  233. DCHECK_EQ(mojo_cb_map_.count(task_id), 0u);
  234. mojo_cb_map_[task_id] = std::move(callback);
  235. if (!accelerator_initialized_) {
  236. NotifyDecodeStatus(
  237. task_id,
  238. ::chromeos_camera::MjpegDecodeAccelerator::Error::PLATFORM_FAILURE);
  239. return;
  240. }
  241. DCHECK(accelerator_);
  242. accelerator_->Decode(task_id, src_handle.TakeFD(),
  243. base::strict_cast<size_t>(src_size),
  244. base::strict_cast<off_t>(src_offset), std::move(frame));
  245. }
  246. void MojoMjpegDecodeAcceleratorService::Uninitialize() {
  247. // TODO(c.padhi): see http://crbug.com/699255.
  248. NOTIMPLEMENTED();
  249. }
  250. void MojoMjpegDecodeAcceleratorService::NotifyDecodeStatus(
  251. int32_t bitstream_buffer_id,
  252. ::chromeos_camera::MjpegDecodeAccelerator::Error error) {
  253. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  254. auto iter = mojo_cb_map_.find(bitstream_buffer_id);
  255. DCHECK(iter != mojo_cb_map_.end());
  256. if (iter == mojo_cb_map_.end()) {
  257. // Silently ignoring abnormal case.
  258. return;
  259. }
  260. MojoCallback mojo_cb = std::move(iter->second);
  261. mojo_cb_map_.erase(iter);
  262. std::move(mojo_cb).Run(error);
  263. }
  264. } // namespace chromeos_camera