1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
|
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_GPU_V4L2_V4L2_STATEFUL_VIDEO_DECODER_H_
#define MEDIA_GPU_V4L2_V4L2_STATEFUL_VIDEO_DECODER_H_
#include <linux/videodev2.h>
#include "base/atomic_ref_count.h"
#include "base/containers/flat_map.h"
#include "base/containers/queue.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequence_checker.h"
#include "base/task/cancelable_task_tracker.h"
#include "media/base/supported_video_decoder_config.h"
#include "media/base/video_types.h"
#include "media/gpu/chromeos/video_decoder_pipeline.h"
#include "media/gpu/media_gpu_export.h"
namespace base {
class Location;
class SingleThreadTaskRunner;
} // namespace base
namespace media {
class H264FrameReassembler;
class H264Parser;
class V4L2FrameRateControl;
class V4L2Queue;
// V4L2StatefulVideoDecoder is an implementation of VideoDecoderMixin
// (an augmented media::VideoDecoder) for stateful V4L2 decoding drivers
// (e.g. those in ChromeOS Qualcomm devices, and Mediatek 8173). This API has
// changed along the kernel versions, but a given copy can be found in [1]
// (the most up-to-date is in [2]).
//
// This class operates on a single thread, where it is constructed and
// destroyed.
//
// [1]
// https://www.kernel.org/doc/html/v5.15/userspace-api/media/v4l/dev-decoder.html
// [2]
// https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/dev-decoder.html
class MEDIA_GPU_EXPORT V4L2StatefulVideoDecoder : public VideoDecoderMixin {
public:
static std::unique_ptr<VideoDecoderMixin> Create(
std::unique_ptr<MediaLog> media_log,
scoped_refptr<base::SequencedTaskRunner> task_runner,
base::WeakPtr<VideoDecoderMixin::Client> client);
// VideoDecoderMixin implementation, VideoDecoder part.
void Initialize(const VideoDecoderConfig& config,
bool low_delay,
CdmContext* cdm_context,
InitCB init_cb,
const PipelineOutputCB& output_cb,
const WaitingCB& waiting_cb) override;
void Decode(scoped_refptr<DecoderBuffer> buffer, DecodeCB decode_cb) override;
void Reset(base::OnceClosure reset_cb) override;
bool NeedsBitstreamConversion() const override;
bool CanReadWithoutStalling() const override;
int GetMaxDecodeRequests() const override;
VideoDecoderType GetDecoderType() const override;
bool IsPlatformDecoder() const override;
// VideoDecoderMixin implementation, specific part.
void ApplyResolutionChange() override;
size_t GetMaxOutputFramePoolSize() const override;
void SetDmaIncoherentV4L2(bool incoherent) override;
static int GetMaxNumDecoderInstancesForTesting() {
return GetMaxNumDecoderInstances();
}
private:
V4L2StatefulVideoDecoder(std::unique_ptr<MediaLog> media_log,
scoped_refptr<base::SequencedTaskRunner> task_runner,
base::WeakPtr<VideoDecoderMixin::Client> client);
~V4L2StatefulVideoDecoder() override;
// Tries to create, configure and fill |CAPTURE_queue_|. This method, which
// should be called after PollOnceForResolutionChangeEvent() has returned
// true, queries the native |CAPTURE_queue_| configuration and supported
// capabilities and negotiates the preferred configuration with our |client_|
// (via PickDecoderOutputFormat()). It then tries to configure, stream on,
// and fill in said |CAPTURE_queue_|. Returns false if any step goes wrong,
// in particular any ioctl() call.
bool InitializeCAPTUREQueue();
// Before |CAPTURE_queue_| is to be configured, we need to ask our |client_|
// (usually VideoDecoderPipeline) to PickDecoderOutputFormat(), for which we
// provide some candidates. This method enumerates such candidates, or returns
// an empty vector.
std::vector<ImageProcessor::PixelLayoutCandidate>
EnumeratePixelLayoutCandidates(const gfx::Size& coded_size);
// Estimates the number of buffers needed for the |CAPTURE_queue_| and for
// codec reference requirements.This function cannot fail (at least returns a
// default, conservative value).
size_t GetNumberOfReferenceFrames();
// Convenience method to PostTask a wait for a |CAPTURE_queue_| event with
// callbacks pointing to TryAndDequeueCAPTUREQueueBuffers() (for data
// available) and InitializeCAPTUREQueue() (for re/configuration events).
void RearmCAPTUREQueueMonitoring();
// Dequeues all the available |CAPTURE_queue_| buffers and sends their
// associated VideoFrames to |output_cb_|. If all goes well, it will
// RearmCAPTUREQueueMonitoring().
// TODO(mcasas): Currently we also TryAndEnqueueCAPTUREQueueBuffers(), is this
// a good spot for that?
void TryAndDequeueCAPTUREQueueBuffers();
// Tries to "enqueue" all available |CAPTURE_queue_| buffers in the driver's
// CAPTURE queue (V4L2Queues don't do that by default upon allocation).
void TryAndEnqueueCAPTUREQueueBuffers();
// Dequeues all the available |OUTPUT_queue_| buffers. This will effectively
// make those available for sending further encoded chunks to the driver.
// Returns false if any ioctl fails, true otherwise.
bool DrainOUTPUTQueue();
// Tries to "enqueue" all encoded chunks in |decoder_buffer_and_callbacks_|
// in |OUTPUT_queue_|, Run()nning their respective DecodeCBs. Returns false if
// any enqueueing operation's ioctl fails, true otherwise.
bool TryAndEnqueueOUTPUTQueueBuffers();
// Prints a VLOG with the state of |OUTPUT_queue| and |CAPTURE_queue_| for
// debugging, preceded with |from_here|s function name. Also TRACEs the
// queues' state.
void PrintAndTraceQueueStates(const base::Location& from_here);
// Returns true if this class has successfully Initialize()d.
bool IsInitialized() const;
// Pages with multiple decoder instances might run out of memory (e.g.
// b/170870476) or crash (e.g. crbug.com/1109312). this class method provides
// that number to prevent that erroneous behaviour during Initialize().
static int GetMaxNumDecoderInstances();
// Tracks the number of decoder instances globally in the process.
static base::AtomicRefCount num_decoder_instances_;
base::ScopedFD device_fd_ GUARDED_BY_CONTEXT(sequence_checker_);
// This |wake_event_| is used to interrupt a blocking poll() call, such as the
// one started by e.g. RearmCAPTUREQueueMonitoring().
base::ScopedFD wake_event_ GUARDED_BY_CONTEXT(sequence_checker_);
// VideoDecoderConfigs supported by the driver. Cached on first Initialize().
SupportedVideoDecoderConfigs supported_configs_
GUARDED_BY_CONTEXT(sequence_checker_);
// Bitstream information and other stuff collected during Initialize().
VideoDecoderConfig config_ GUARDED_BY_CONTEXT(sequence_checker_);
PipelineOutputCB output_cb_ GUARDED_BY_CONTEXT(sequence_checker_);
DecodeCB flush_cb_ GUARDED_BY_CONTEXT(sequence_checker_);
// Set to true when the driver identifies itself as a Mediatek 8173.
bool is_mtk8173_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
// Used only on V4L2_MEMORY_MMAP queues (e.g. Hana MT8173) to grab the visible
// rectangle upon |CAPTURE_queue_| configuration in InitializeCAPTUREQueue().
gfx::Rect visible_rect_;
// Map of enqueuing timecodes to system timestamp, for histogramming purposes.
base::flat_map<int64_t, base::TimeTicks> encoding_timestamps_;
// Holds pairs of encoded chunk (DecoderBuffer) and associated DecodeCB for
// decoding via TryAndEnqueueOUTPUTQueueBuffers().
base::queue<std::pair<scoped_refptr<DecoderBuffer>, DecodeCB>>
decoder_buffer_and_callbacks_;
// OUTPUT in V4L2 terminology is the queue holding encoded chunks of
// bitstream. CAPTURE is the queue holding decoded pictures. See e.g. [1].
// https://www.kernel.org/doc/html/v5.15/userspace-api/media/v4l/dev-decoder.html#glossary
scoped_refptr<V4L2Queue> OUTPUT_queue_ GUARDED_BY_CONTEXT(sequence_checker_);
scoped_refptr<V4L2Queue> CAPTURE_queue_ GUARDED_BY_CONTEXT(sequence_checker_);
// Some drivers, e.g. QC SC7180, require the client to inform the driver of
// the framerate (to tweak internal resources).
std::unique_ptr<V4L2FrameRateControl> framerate_control_;
// A sequenced TaskRunner to wait for events coming from |CAPTURE_queue_| or
// |wake_event_|.
scoped_refptr<base::SingleThreadTaskRunner> event_task_runner_;
// Used to (try to) cancel the Tasks sent by RearmCAPTUREQueueMonitoring(),
// and not serviced yet, when no longer needed.
base::CancelableTaskTracker cancelable_task_tracker_
GUARDED_BY_CONTEXT(sequence_checker_);
// Optional helper class to reassemble full H.264 frames out of NALUs.
std::unique_ptr<H264FrameReassembler> h264_frame_reassembler_
GUARDED_BY_CONTEXT(sequence_checker_);
// Pegged to the construction and main work thread. Notably, |task_runner| is
// not used.
SEQUENCE_CHECKER(sequence_checker_);
// Weak factories associated with the main thread (|sequence_checker|).
base::WeakPtrFactory<V4L2StatefulVideoDecoder> weak_ptr_factory_for_events_;
base::WeakPtrFactory<V4L2StatefulVideoDecoder>
weak_ptr_factory_for_CAPTURE_availability_;
};
} // namespace media
#endif // MEDIA_GPU_V4L2_V4L2_STATEFUL_VIDEO_DECODER_H_
|