offloading_video_decoder.h 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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. #ifndef MEDIA_FILTERS_OFFLOADING_VIDEO_DECODER_H_
  5. #define MEDIA_FILTERS_OFFLOADING_VIDEO_DECODER_H_
  6. #include "base/callback_forward.h"
  7. #include "base/memory/weak_ptr.h"
  8. #include "base/sequence_checker.h"
  9. #include "media/base/video_codecs.h"
  10. #include "media/base/video_decoder.h"
  11. #include "media/base/video_decoder_config.h"
  12. namespace base {
  13. class SequencedTaskRunner;
  14. } // namespace base
  15. namespace media {
  16. class CancellationHelper;
  17. // OffloadableVideoDecoder implementations must have synchronous execution of
  18. // Reset() and Decode() (true for all current software decoders); this allows
  19. // for serializing these operations on the offloading sequence. With
  20. // serializing, multiple Decode() events can be queued on the offload thread,
  21. // and Reset() does not need to wait for |reset_cb| to return.
  22. class MEDIA_EXPORT OffloadableVideoDecoder : public VideoDecoder {
  23. public:
  24. enum class OffloadState {
  25. kOffloaded, // Indicates the VideoDecoder is being used with
  26. // OffloadingVideoDecoder and that callbacks provided to
  27. // VideoDecoder methods should not be bound to the current
  28. // loop.
  29. kNormal, // Indicates the VideoDecoder is being used as a normal
  30. // VideoDecoder, meaning callbacks should always be asynchronous.
  31. };
  32. ~OffloadableVideoDecoder() override {}
  33. // Called by the OffloadingVideoDecoder when closing the decoder and switching
  34. // task runners. Will be called on the task runner that Initialize() was
  35. // called on. Upon completion of this method implementing decoders must be
  36. // ready to be Initialized() on another thread.
  37. virtual void Detach() = 0;
  38. };
  39. // Wrapper for OffloadableVideoDecoder implementations that runs the wrapped
  40. // decoder on a task pool other than the caller's thread.
  41. //
  42. // Offloading allows us to avoid blocking the media sequence for Decode() when
  43. // it's known that decoding may take a long time; e.g., high-resolution VP9
  44. // decodes may occasionally take upwards of > 100ms per frame, which is enough
  45. // to exhaust the audio buffer and lead to underflow in some circumstances.
  46. //
  47. // Offloading also allows better pipelining of Decode() calls. The normal decode
  48. // sequence is Decode(buffer) -> DecodeComplete() -> WaitFor(buffer)-> (repeat);
  49. // this sequence generally involves thread hops as well. When offloading we can
  50. // take advantage of the serialization of operations on the offloading sequence
  51. // to make this Decode(buffer) -> DecodeComplete() -> Decode(buffer) by queuing
  52. // the next Decode(buffer) before the previous one completes.
  53. //
  54. // I.e., we are no longer wasting cycles waiting for the recipient of the
  55. // decoded frame to acknowledge that receipt, request the next muxed buffer, and
  56. // then queue the next decode. Those operations now happen in parallel with the
  57. // decoding of the previous buffer on the offloading sequence. Improving the
  58. // total throughput that a decode can achieve.
  59. //
  60. // E.g., without parallel offloading, over 4000 frames, a 4K60 VP9 clip spent
  61. // ~11.7 seconds of aggregate time just waiting for frames. With parallel
  62. // offloading the same clip spent only ~3.4 seconds.
  63. //
  64. // Optionally decoders which are aware of the wrapping may choose to not rebind
  65. // callbacks to the offloaded thread since they will already be bound by the
  66. // OffloadingVideoDecoder; this simply avoids extra hops for completed tasks.
  67. class MEDIA_EXPORT OffloadingVideoDecoder : public VideoDecoder {
  68. public:
  69. // Offloads |decoder| for VideoDecoderConfigs provided to Initialize() using
  70. // |supported_codecs| with a coded width >= |min_offloading_width|.
  71. //
  72. // E.g. if a width of 1024 is specified, and VideoDecoderConfig has a coded
  73. // size of 1280x720 we will use offloading. Conversely if the width was
  74. // 640x480, we would not use offloading.
  75. OffloadingVideoDecoder(int min_offloading_width,
  76. std::vector<VideoCodec> supported_codecs,
  77. std::unique_ptr<OffloadableVideoDecoder> decoder);
  78. OffloadingVideoDecoder(const OffloadingVideoDecoder&) = delete;
  79. OffloadingVideoDecoder& operator=(const OffloadingVideoDecoder&) = delete;
  80. ~OffloadingVideoDecoder() override;
  81. // VideoDecoder implementation.
  82. VideoDecoderType GetDecoderType() const override;
  83. void Initialize(const VideoDecoderConfig& config,
  84. bool low_delay,
  85. CdmContext* cdm_context,
  86. InitCB init_cb,
  87. const OutputCB& output_cb,
  88. const WaitingCB& waiting_cb) override;
  89. void Decode(scoped_refptr<DecoderBuffer> buffer, DecodeCB decode_cb) override;
  90. void Reset(base::OnceClosure reset_cb) override;
  91. int GetMaxDecodeRequests() const override;
  92. private:
  93. // VideoDecoderConfigs given to Initialize() with a coded size that has width
  94. // greater than or equal to this value will be offloaded.
  95. const int min_offloading_width_;
  96. // Codecs supported for offloading.
  97. const std::vector<VideoCodec> supported_codecs_;
  98. // Indicates if Initialize() has been called.
  99. bool initialized_ = false;
  100. SEQUENCE_CHECKER(sequence_checker_);
  101. // A helper class for managing Decode() and Reset() calls to the offloaded
  102. // decoder; it owns the given OffloadableVideoDecoder and is always destructed
  103. // on |offload_task_runner_| when used.
  104. std::unique_ptr<CancellationHelper> helper_;
  105. // High resolution decodes may block the media thread for too long, in such
  106. // cases offload the decoding to a task pool.
  107. scoped_refptr<base::SequencedTaskRunner> offload_task_runner_;
  108. // NOTE: Weak pointers must be invalidated before all other member variables.
  109. base::WeakPtrFactory<OffloadingVideoDecoder> weak_factory_{this};
  110. };
  111. } // namespace media
  112. #endif // MEDIA_FILTERS_OFFLOADING_VIDEO_DECODER_H_