fuchsia_video_decoder.cc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
  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/fuchsia/video/fuchsia_video_decoder.h"
  5. #include <vulkan/vulkan.h>
  6. #include "base/bind.h"
  7. #include "base/callback.h"
  8. #include "base/callback_helpers.h"
  9. #include "base/command_line.h"
  10. #include "base/fuchsia/fuchsia_logging.h"
  11. #include "base/fuchsia/process_context.h"
  12. #include "base/location.h"
  13. #include "base/logging.h"
  14. #include "base/memory/ref_counted.h"
  15. #include "base/memory/weak_ptr.h"
  16. #include "base/process/process_metrics.h"
  17. #include "base/threading/sequenced_task_runner_handle.h"
  18. #include "components/viz/common/gpu/raster_context_provider.h"
  19. #include "gpu/command_buffer/client/context_support.h"
  20. #include "gpu/command_buffer/client/shared_image_interface.h"
  21. #include "gpu/command_buffer/common/shared_image_usage.h"
  22. #include "gpu/ipc/common/gpu_memory_buffer_impl_native_pixmap.h"
  23. #include "media/base/bind_to_current_loop.h"
  24. #include "media/base/cdm_context.h"
  25. #include "media/base/media_switches.h"
  26. #include "media/base/video_aspect_ratio.h"
  27. #include "media/base/video_frame.h"
  28. #include "media/base/video_util.h"
  29. #include "media/fuchsia/cdm/fuchsia_cdm_context.h"
  30. #include "media/fuchsia/cdm/fuchsia_decryptor.h"
  31. #include "media/fuchsia/cdm/fuchsia_stream_decryptor.h"
  32. #include "media/fuchsia/common/decrypting_sysmem_buffer_stream.h"
  33. #include "media/fuchsia/common/passthrough_sysmem_buffer_stream.h"
  34. #include "media/fuchsia/common/stream_processor_helper.h"
  35. #include "media/fuchsia/mojom/fuchsia_media_resource_provider.mojom.h"
  36. #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
  37. #include "ui/gfx/buffer_types.h"
  38. #include "ui/gfx/client_native_pixmap_factory.h"
  39. #include "ui/ozone/public/client_native_pixmap_factory_ozone.h"
  40. namespace media {
  41. namespace {
  42. // Number of output buffers allocated "for camping". This value is passed to
  43. // sysmem to ensure that we get one output buffer for the frame currently
  44. // displayed on the screen.
  45. constexpr uint32_t kOutputBuffersForCamping = 1;
  46. // Maximum number of frames we expect to have queued up while playing video.
  47. // Higher values require more memory for output buffers. Lower values make it
  48. // more likely that renderer will stall because decoded frames are not available
  49. // on time.
  50. constexpr uint32_t kMaxUsedOutputBuffers = 5;
  51. // Use 2 buffers for decoder input. Allocating more than one buffers ensures
  52. // that when the decoder is done working on one packet it will have another one
  53. // waiting in the queue. Limiting number of buffers to 2 allows to minimize
  54. // required memory, without significant effect on performance.
  55. constexpr size_t kNumInputBuffers = 2;
  56. // Some codecs do not support splitting video frames across multiple input
  57. // buffers, so the buffers need to be large enough to fit all video frames. The
  58. // buffer size is calculated to fit 1080p I420 frame with MinCR=2 (per H264
  59. // spec), plus 128KiB for SEI/SPS/PPS. (note that the same size is used for all
  60. // codecs, not just H264).
  61. constexpr size_t kInputBufferSize = 1920 * 1080 * 3 / 2 / 2 + 128 * 1024;
  62. } // namespace
  63. // Helper used to hold mailboxes for the output textures. OutputMailbox may
  64. // outlive FuchsiaVideoDecoder if is referenced by a VideoFrame.
  65. class FuchsiaVideoDecoder::OutputMailbox {
  66. public:
  67. OutputMailbox(
  68. scoped_refptr<viz::RasterContextProvider> raster_context_provider,
  69. std::unique_ptr<gfx::GpuMemoryBuffer> gmb)
  70. : raster_context_provider_(raster_context_provider), weak_factory_(this) {
  71. uint32_t usage = gpu::SHARED_IMAGE_USAGE_DISPLAY |
  72. gpu::SHARED_IMAGE_USAGE_SCANOUT |
  73. gpu::SHARED_IMAGE_USAGE_VIDEO_DECODE;
  74. mailbox_ =
  75. raster_context_provider_->SharedImageInterface()->CreateSharedImage(
  76. gmb.get(), nullptr, gfx::ColorSpace(), kTopLeft_GrSurfaceOrigin,
  77. kPremul_SkAlphaType, usage);
  78. }
  79. OutputMailbox(const OutputMailbox&) = delete;
  80. OutputMailbox& operator=(const OutputMailbox&) = delete;
  81. ~OutputMailbox() {
  82. raster_context_provider_->SharedImageInterface()->DestroySharedImage(
  83. sync_token_, mailbox_);
  84. }
  85. const gpu::Mailbox& mailbox() { return mailbox_; }
  86. // Create a new video frame that wraps the mailbox. |reuse_callback| will be
  87. // called when the mailbox can be reused.
  88. scoped_refptr<VideoFrame> CreateFrame(VideoPixelFormat pixel_format,
  89. const gfx::Size& coded_size,
  90. const gfx::Rect& visible_rect,
  91. const gfx::Size& natural_size,
  92. base::TimeDelta timestamp,
  93. base::OnceClosure reuse_callback) {
  94. DCHECK(!is_used_);
  95. is_used_ = true;
  96. reuse_callback_ = std::move(reuse_callback);
  97. gpu::MailboxHolder mailboxes[VideoFrame::kMaxPlanes];
  98. mailboxes[0].mailbox = mailbox_;
  99. mailboxes[0].sync_token = raster_context_provider_->SharedImageInterface()
  100. ->GenUnverifiedSyncToken();
  101. auto frame = VideoFrame::WrapNativeTextures(
  102. pixel_format, mailboxes,
  103. BindToCurrentLoop(base::BindOnce(&OutputMailbox::OnFrameDestroyed,
  104. base::Unretained(this))),
  105. coded_size, visible_rect, natural_size, timestamp);
  106. // Request a fence we'll wait on before reusing the buffer.
  107. frame->metadata().read_lock_fences_enabled = true;
  108. return frame;
  109. }
  110. // Called by FuchsiaVideoDecoder when it no longer needs this mailbox.
  111. void Release() {
  112. if (is_used_) {
  113. // The mailbox is referenced by a VideoFrame. It will be deleted as soon
  114. // as the frame is destroyed.
  115. DCHECK(reuse_callback_);
  116. reuse_callback_ = base::OnceClosure();
  117. } else {
  118. delete this;
  119. }
  120. }
  121. private:
  122. void OnFrameDestroyed(const gpu::SyncToken& sync_token) {
  123. DCHECK(is_used_);
  124. is_used_ = false;
  125. sync_token_ = sync_token;
  126. if (!reuse_callback_) {
  127. // If the mailbox cannot be reused then we can just delete it.
  128. delete this;
  129. return;
  130. }
  131. raster_context_provider_->ContextSupport()->SignalSyncToken(
  132. sync_token_,
  133. BindToCurrentLoop(base::BindOnce(&OutputMailbox::OnSyncTokenSignaled,
  134. weak_factory_.GetWeakPtr())));
  135. }
  136. void OnSyncTokenSignaled() {
  137. sync_token_.Clear();
  138. std::move(reuse_callback_).Run();
  139. }
  140. const scoped_refptr<viz::RasterContextProvider> raster_context_provider_;
  141. gpu::Mailbox mailbox_;
  142. gpu::SyncToken sync_token_;
  143. // Set to true when the mailbox is referenced by a video frame.
  144. bool is_used_ = false;
  145. base::OnceClosure reuse_callback_;
  146. base::WeakPtrFactory<OutputMailbox> weak_factory_;
  147. };
  148. FuchsiaVideoDecoder::FuchsiaVideoDecoder(
  149. scoped_refptr<viz::RasterContextProvider> raster_context_provider,
  150. media::mojom::FuchsiaMediaResourceProvider* media_resource_provider)
  151. : raster_context_provider_(raster_context_provider),
  152. media_resource_provider_(media_resource_provider),
  153. use_overlays_for_video_(base::CommandLine::ForCurrentProcess()->HasSwitch(
  154. switches::kUseOverlaysForVideo)),
  155. sysmem_allocator_("CrFuchsiaVideoDecoder"),
  156. client_native_pixmap_factory_(
  157. ui::CreateClientNativePixmapFactoryOzone()) {
  158. DCHECK(raster_context_provider_);
  159. weak_this_ = weak_factory_.GetWeakPtr();
  160. }
  161. FuchsiaVideoDecoder::~FuchsiaVideoDecoder() {
  162. // Reset SysmemBufferStream to ensure it doesn't try to send new packets when
  163. // the |decoder_| is destroyed.
  164. sysmem_buffer_stream_.reset();
  165. decoder_.reset();
  166. // Release mailboxes used for output frames.
  167. ReleaseOutputBuffers();
  168. }
  169. bool FuchsiaVideoDecoder::IsPlatformDecoder() const {
  170. return true;
  171. }
  172. bool FuchsiaVideoDecoder::SupportsDecryption() const {
  173. return true;
  174. }
  175. VideoDecoderType FuchsiaVideoDecoder::GetDecoderType() const {
  176. return VideoDecoderType::kFuchsia;
  177. }
  178. void FuchsiaVideoDecoder::Initialize(const VideoDecoderConfig& config,
  179. bool low_delay,
  180. CdmContext* cdm_context,
  181. InitCB init_cb,
  182. const OutputCB& output_cb,
  183. const WaitingCB& waiting_cb) {
  184. DCHECK(output_cb);
  185. DCHECK(waiting_cb);
  186. DCHECK(decode_callbacks_.empty());
  187. auto done_callback = BindToCurrentLoop(std::move(init_cb));
  188. // There should be no pending decode request, so DropInputQueue() is not
  189. // expected to fail.
  190. bool result = DropInputQueue(DecoderStatus::Codes::kAborted);
  191. DCHECK(result);
  192. output_cb_ = output_cb;
  193. waiting_cb_ = waiting_cb;
  194. container_aspect_ratio_ = config.aspect_ratio();
  195. // Keep decoder and decryptor if the configuration hasn't changed.
  196. if (decoder_ && current_config_.codec() == config.codec() &&
  197. current_config_.is_encrypted() == config.is_encrypted()) {
  198. std::move(done_callback).Run(DecoderStatus::Codes::kOk);
  199. return;
  200. }
  201. sysmem_buffer_stream_.reset();
  202. decoder_.reset();
  203. // Initialize the stream.
  204. bool secure_mode = false;
  205. DecoderStatus status = InitializeSysmemBufferStream(
  206. config.is_encrypted(), cdm_context, &secure_mode);
  207. if (!status.is_ok()) {
  208. std::move(done_callback).Run(status);
  209. return;
  210. }
  211. // Reset output buffers since we won't be able to re-use them.
  212. ReleaseOutputBuffers();
  213. fuchsia::media::StreamProcessorPtr decoder;
  214. media_resource_provider_->CreateVideoDecoder(config.codec(), secure_mode,
  215. decoder.NewRequest());
  216. decoder_ = std::make_unique<StreamProcessorHelper>(std::move(decoder), this);
  217. current_config_ = config;
  218. std::move(done_callback).Run(DecoderStatus::Codes::kOk);
  219. }
  220. void FuchsiaVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
  221. DecodeCB decode_cb) {
  222. if (!decoder_) {
  223. // Post the callback to the current sequence as DecoderStream doesn't expect
  224. // Decode() to complete synchronously.
  225. base::SequencedTaskRunnerHandle::Get()->PostTask(
  226. FROM_HERE,
  227. base::BindOnce(std::move(decode_cb), DecoderStatus::Codes::kFailed));
  228. return;
  229. }
  230. decode_callbacks_.push_back(std::move(decode_cb));
  231. sysmem_buffer_stream_->EnqueueBuffer(std::move(buffer));
  232. }
  233. void FuchsiaVideoDecoder::Reset(base::OnceClosure closure) {
  234. DropInputQueue(DecoderStatus::Codes::kAborted);
  235. base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
  236. std::move(closure));
  237. }
  238. bool FuchsiaVideoDecoder::NeedsBitstreamConversion() const {
  239. return true;
  240. }
  241. bool FuchsiaVideoDecoder::CanReadWithoutStalling() const {
  242. return num_used_output_buffers_ < kMaxUsedOutputBuffers;
  243. }
  244. int FuchsiaVideoDecoder::GetMaxDecodeRequests() const {
  245. return max_decoder_requests_;
  246. }
  247. DecoderStatus FuchsiaVideoDecoder::InitializeSysmemBufferStream(
  248. bool is_encrypted,
  249. CdmContext* cdm_context,
  250. bool* out_secure_mode) {
  251. DCHECK(!sysmem_buffer_stream_);
  252. *out_secure_mode = false;
  253. // By default queue as many decode requests as the input buffers available
  254. // with one extra request to be able to send a new InputBuffer immediately.
  255. max_decoder_requests_ = kNumInputBuffers + 1;
  256. if (is_encrypted) {
  257. // Caller makes sure |cdm_context| is available if the stream is encrypted.
  258. if (!cdm_context) {
  259. DLOG(ERROR) << "No cdm context for encrypted stream.";
  260. return DecoderStatus::Codes::kUnsupportedEncryptionMode;
  261. }
  262. // Use FuchsiaStreamDecryptor with FuchsiaCdm (it doesn't support
  263. // media::Decryptor interface). Otherwise (e.g. for ClearKey CDM) use
  264. // DecryptingSysmemBufferStream.
  265. FuchsiaCdmContext* fuchsia_cdm = cdm_context->GetFuchsiaCdmContext();
  266. if (fuchsia_cdm) {
  267. *out_secure_mode = base::CommandLine::ForCurrentProcess()->HasSwitch(
  268. switches::kEnableProtectedVideoBuffers);
  269. sysmem_buffer_stream_ =
  270. fuchsia_cdm->CreateStreamDecryptor(*out_secure_mode);
  271. // For optimal performance allow more requests to fill the decryptor
  272. // queue.
  273. max_decoder_requests_ += FuchsiaStreamDecryptor::kInputBufferCount;
  274. } else {
  275. sysmem_buffer_stream_ = std::make_unique<DecryptingSysmemBufferStream>(
  276. &sysmem_allocator_, cdm_context, Decryptor::kVideo);
  277. }
  278. } else {
  279. sysmem_buffer_stream_ =
  280. std::make_unique<PassthroughSysmemBufferStream>(&sysmem_allocator_);
  281. }
  282. sysmem_buffer_stream_->Initialize(this, kInputBufferSize, kNumInputBuffers);
  283. return DecoderStatus::Codes::kOk;
  284. }
  285. void FuchsiaVideoDecoder::OnSysmemBufferStreamBufferCollectionToken(
  286. fuchsia::sysmem::BufferCollectionTokenPtr token) {
  287. DCHECK(decoder_);
  288. decoder_->SetInputBufferCollectionToken(std::move(token));
  289. }
  290. void FuchsiaVideoDecoder::OnSysmemBufferStreamOutputPacket(
  291. StreamProcessorHelper::IoPacket packet) {
  292. packet.AddOnDestroyClosure(
  293. base::BindOnce(&FuchsiaVideoDecoder::CallNextDecodeCallback,
  294. decode_callbacks_weak_factory_.GetWeakPtr()));
  295. decoder_->Process(std::move(packet));
  296. }
  297. void FuchsiaVideoDecoder::OnSysmemBufferStreamEndOfStream() {
  298. decoder_->ProcessEos();
  299. }
  300. void FuchsiaVideoDecoder::OnSysmemBufferStreamError() {
  301. OnError();
  302. }
  303. void FuchsiaVideoDecoder::OnSysmemBufferStreamNoKey() {
  304. waiting_cb_.Run(WaitingReason::kNoDecryptionKey);
  305. }
  306. void FuchsiaVideoDecoder::OnStreamProcessorAllocateOutputBuffers(
  307. const fuchsia::media::StreamBufferConstraints& output_constraints) {
  308. ReleaseOutputBuffers();
  309. output_buffer_collection_ = sysmem_allocator_.AllocateNewCollection();
  310. output_buffer_collection_->CreateSharedToken(
  311. base::BindOnce(&StreamProcessorHelper::CompleteOutputBuffersAllocation,
  312. base::Unretained(decoder_.get())),
  313. "codec");
  314. output_buffer_collection_->CreateSharedToken(
  315. base::BindOnce(&FuchsiaVideoDecoder::SetBufferCollectionTokenForGpu,
  316. base::Unretained(this)),
  317. "gpu");
  318. fuchsia::sysmem::BufferCollectionConstraints buffer_constraints;
  319. buffer_constraints.usage.none = fuchsia::sysmem::noneUsage;
  320. buffer_constraints.min_buffer_count_for_camping = kOutputBuffersForCamping;
  321. buffer_constraints.min_buffer_count_for_shared_slack =
  322. kMaxUsedOutputBuffers - kOutputBuffersForCamping;
  323. output_buffer_collection_->Initialize(std::move(buffer_constraints),
  324. "ChromiumVideoDecoderOutput");
  325. }
  326. void FuchsiaVideoDecoder::OnStreamProcessorEndOfStream() {
  327. // Decode() is not supposed to be called again after EOF.
  328. DCHECK_EQ(decode_callbacks_.size(), 1U);
  329. CallNextDecodeCallback();
  330. }
  331. void FuchsiaVideoDecoder::OnStreamProcessorOutputFormat(
  332. fuchsia::media::StreamOutputFormat output_format) {
  333. auto* format = output_format.mutable_format_details();
  334. if (!format->has_domain() || !format->domain().is_video() ||
  335. !format->domain().video().is_uncompressed()) {
  336. DLOG(ERROR) << "Received OnOutputFormat() with invalid format.";
  337. OnError();
  338. return;
  339. }
  340. output_format_ = std::move(format->mutable_domain()->video().uncompressed());
  341. }
  342. void FuchsiaVideoDecoder::OnStreamProcessorOutputPacket(
  343. StreamProcessorHelper::IoPacket output_packet) {
  344. fuchsia::sysmem::PixelFormatType sysmem_pixel_format =
  345. output_format_.image_format.pixel_format.type;
  346. VideoPixelFormat pixel_format;
  347. gfx::BufferFormat buffer_format;
  348. VkFormat vk_format;
  349. switch (sysmem_pixel_format) {
  350. case fuchsia::sysmem::PixelFormatType::NV12:
  351. pixel_format = PIXEL_FORMAT_NV12;
  352. buffer_format = gfx::BufferFormat::YUV_420_BIPLANAR;
  353. vk_format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
  354. break;
  355. case fuchsia::sysmem::PixelFormatType::I420:
  356. case fuchsia::sysmem::PixelFormatType::YV12:
  357. pixel_format = PIXEL_FORMAT_I420;
  358. buffer_format = gfx::BufferFormat::YVU_420;
  359. vk_format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
  360. break;
  361. default:
  362. DLOG(ERROR) << "Unsupported pixel format: "
  363. << static_cast<int>(sysmem_pixel_format);
  364. OnError();
  365. return;
  366. }
  367. size_t buffer_index = output_packet.buffer_index();
  368. if (buffer_index >= output_mailboxes_.size())
  369. output_mailboxes_.resize(buffer_index + 1, nullptr);
  370. auto coded_size = gfx::Size(output_format_.primary_width_pixels,
  371. output_format_.primary_height_pixels);
  372. if (!output_mailboxes_[buffer_index]) {
  373. gfx::GpuMemoryBufferHandle gmb_handle;
  374. gmb_handle.type = gfx::NATIVE_PIXMAP;
  375. gmb_handle.native_pixmap_handle.buffer_collection_id =
  376. output_buffer_collection_id_;
  377. gmb_handle.native_pixmap_handle.buffer_index = buffer_index;
  378. auto gmb = gpu::GpuMemoryBufferImplNativePixmap::CreateFromHandle(
  379. client_native_pixmap_factory_.get(), std::move(gmb_handle), coded_size,
  380. buffer_format, gfx::BufferUsage::GPU_READ,
  381. gpu::GpuMemoryBufferImpl::DestructionCallback());
  382. output_mailboxes_[buffer_index] =
  383. new OutputMailbox(raster_context_provider_, std::move(gmb));
  384. } else {
  385. raster_context_provider_->SharedImageInterface()->UpdateSharedImage(
  386. gpu::SyncToken(), output_mailboxes_[buffer_index]->mailbox());
  387. }
  388. auto display_rect = gfx::Rect(output_format_.primary_display_width_pixels,
  389. output_format_.primary_display_height_pixels);
  390. VideoAspectRatio aspect_ratio = container_aspect_ratio_;
  391. if (!aspect_ratio.IsValid() && output_format_.has_pixel_aspect_ratio) {
  392. aspect_ratio =
  393. VideoAspectRatio::PAR(output_format_.pixel_aspect_ratio_width,
  394. output_format_.pixel_aspect_ratio_height);
  395. }
  396. auto timestamp = output_packet.timestamp();
  397. // SendInputPacket() sets timestamp for all packets sent to the decoder, so we
  398. // expect to receive timestamp for all decoded frames. Missing timestamp
  399. // indicates a bug in the decoder implementation.
  400. if (timestamp == kNoTimestamp) {
  401. LOG(ERROR) << "Received frame without timestamp.";
  402. OnError();
  403. return;
  404. }
  405. num_used_output_buffers_++;
  406. auto frame = output_mailboxes_[buffer_index]->CreateFrame(
  407. pixel_format, coded_size, display_rect,
  408. aspect_ratio.GetNaturalSize(display_rect), timestamp,
  409. base::BindOnce(&FuchsiaVideoDecoder::ReleaseOutputPacket,
  410. base::Unretained(this), std::move(output_packet)));
  411. // Currently sysmem doesn't specify location of chroma samples relative to
  412. // luma (see fxbug.dev/13677). Assume they are cosited with luma. YCbCr info
  413. // here must match the values passed for the same buffer in
  414. // ui::SysmemBufferCollection::CreateVkImage() (see
  415. // ui/ozone/platform/scenic/sysmem_buffer_collection.cc). |format_features|
  416. // are resolved later in the GPU process before this info is passed to Skia.
  417. frame->set_ycbcr_info(gpu::VulkanYCbCrInfo(
  418. vk_format, /*external_format=*/0,
  419. VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709,
  420. VK_SAMPLER_YCBCR_RANGE_ITU_NARROW, VK_CHROMA_LOCATION_COSITED_EVEN,
  421. VK_CHROMA_LOCATION_COSITED_EVEN, /*format_features=*/0));
  422. // Mark the frame as power-efficient since (software decoders are used only in
  423. // tests).
  424. frame->metadata().power_efficient = true;
  425. // Allow this video frame to be promoted as an overlay, because it was
  426. // registered with an ImagePipe.
  427. frame->metadata().allow_overlay = use_overlays_for_video_;
  428. output_cb_.Run(std::move(frame));
  429. }
  430. void FuchsiaVideoDecoder::OnStreamProcessorNoKey() {
  431. // Decoder is not expected to produce NoKey() error.
  432. DLOG(ERROR) << "Video decoder failed with DECRYPTOR_NO_KEY expectedly";
  433. OnError();
  434. }
  435. void FuchsiaVideoDecoder::OnStreamProcessorError() {
  436. OnError();
  437. }
  438. void FuchsiaVideoDecoder::CallNextDecodeCallback() {
  439. DCHECK(!decode_callbacks_.empty());
  440. auto cb = std::move(decode_callbacks_.front());
  441. decode_callbacks_.pop_front();
  442. std::move(cb).Run(DecoderStatus::Codes::kOk);
  443. }
  444. bool FuchsiaVideoDecoder::DropInputQueue(DecoderStatus status) {
  445. // Invalidate callbacks for CallNextDecodeCallback(), so the callbacks are not
  446. // called when the |decoder_| is dropped below. The callbacks are called
  447. // explicitly later.
  448. decode_callbacks_weak_factory_.InvalidateWeakPtrs();
  449. if (decoder_) {
  450. decoder_->Reset();
  451. }
  452. if (sysmem_buffer_stream_) {
  453. sysmem_buffer_stream_->Reset();
  454. }
  455. auto weak_this = weak_this_;
  456. for (auto& cb : decode_callbacks_) {
  457. std::move(cb).Run(status);
  458. // DecodeCB may destroy |this|.
  459. if (!weak_this)
  460. return false;
  461. }
  462. decode_callbacks_.clear();
  463. return true;
  464. }
  465. void FuchsiaVideoDecoder::OnError() {
  466. sysmem_buffer_stream_.reset();
  467. decoder_.reset();
  468. ReleaseOutputBuffers();
  469. DropInputQueue(DecoderStatus::Codes::kFailed);
  470. }
  471. void FuchsiaVideoDecoder::SetBufferCollectionTokenForGpu(
  472. fuchsia::sysmem::BufferCollectionTokenPtr token) {
  473. // Register the new collection with the GPU process.
  474. DCHECK(!output_buffer_collection_id_);
  475. output_buffer_collection_id_ = gfx::SysmemBufferCollectionId::Create();
  476. raster_context_provider_->SharedImageInterface()
  477. ->RegisterSysmemBufferCollection(
  478. output_buffer_collection_id_, token.Unbind().TakeChannel(),
  479. gfx::BufferFormat::YUV_420_BIPLANAR, gfx::BufferUsage::GPU_READ,
  480. use_overlays_for_video_ /*register_with_image_pipe*/);
  481. // Exact number of buffers sysmem will allocate is unknown here.
  482. // |output_mailboxes_| is resized when we start receiving output frames.
  483. DCHECK(output_mailboxes_.empty());
  484. }
  485. void FuchsiaVideoDecoder::ReleaseOutputBuffers() {
  486. // Release the buffer collection.
  487. num_used_output_buffers_ = 0;
  488. if (output_buffer_collection_) {
  489. output_buffer_collection_.reset();
  490. }
  491. // Release all output mailboxes.
  492. for (OutputMailbox* mailbox : output_mailboxes_) {
  493. if (mailbox)
  494. mailbox->Release();
  495. }
  496. output_mailboxes_.clear();
  497. // Tell the GPU process to drop the buffer collection.
  498. if (output_buffer_collection_id_) {
  499. raster_context_provider_->SharedImageInterface()
  500. ->ReleaseSysmemBufferCollection(output_buffer_collection_id_);
  501. output_buffer_collection_id_ = {};
  502. }
  503. }
  504. void FuchsiaVideoDecoder::ReleaseOutputPacket(
  505. StreamProcessorHelper::IoPacket output_packet) {
  506. DCHECK_GT(num_used_output_buffers_, 0U);
  507. num_used_output_buffers_--;
  508. }
  509. } // namespace media