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
media / gpu / v4l2 / v4l2_stateful_video_decoder.h [blame]
// 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_