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 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
|
// Copyright 2014 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_VIDEO_ENCODE_ACCELERATOR_H_
#define MEDIA_GPU_V4L2_V4L2_VIDEO_ENCODE_ACCELERATOR_H_
#include <linux/videodev2.h>
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <optional>
#include <vector>
#include "base/containers/circular_deque.h"
#include "base/containers/queue.h"
#include "base/files/scoped_file.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "gpu/command_buffer/client/shared_image_interface.h"
#include "gpu/ipc/service/command_buffer_stub.h"
#include "media/base/encoder_status.h"
#include "media/gpu/chromeos/image_processor.h"
#include "media/gpu/media_gpu_export.h"
#include "media/gpu/v4l2/v4l2_device.h"
#include "media/video/video_encode_accelerator.h"
#include "ui/gfx/geometry/size.h"
namespace base {
class SequencedTaskRunner;
} // namespace base
namespace media {
class BitstreamBuffer;
// This class handles video encode acceleration by interfacing with a V4L2
// device exposed by the codec hardware driver. The threading model of this
// class is the same as in the V4L2VideoDecodeAccelerator (from which class this
// was designed).
// This class may try to instantiate and use a ImageProcessor for input
// format conversion, if the input format requested via Initialize() is not
// accepted by the hardware codec.
class MEDIA_GPU_EXPORT V4L2VideoEncodeAccelerator
: public VideoEncodeAccelerator {
public:
explicit V4L2VideoEncodeAccelerator(scoped_refptr<V4L2Device> device);
V4L2VideoEncodeAccelerator(const V4L2VideoEncodeAccelerator&) = delete;
V4L2VideoEncodeAccelerator& operator=(const V4L2VideoEncodeAccelerator&) =
delete;
~V4L2VideoEncodeAccelerator() override;
// VideoEncodeAccelerator implementation.
VideoEncodeAccelerator::SupportedProfiles GetSupportedProfiles() override;
EncoderStatus Initialize(const Config& config,
Client* client,
std::unique_ptr<MediaLog> media_log) override;
void Encode(scoped_refptr<VideoFrame> frame, bool force_keyframe) override;
void UseOutputBitstreamBuffer(BitstreamBuffer buffer) override;
void RequestEncodingParametersChange(
const Bitrate& bitrate,
uint32_t framerate,
const std::optional<gfx::Size>& size) override;
void RequestEncodingParametersChange(
const VideoBitrateAllocation& bitrate_allocation,
uint32_t framerate,
const std::optional<gfx::Size>& size) override;
void Destroy() override;
void Flush(FlushCallback flush_callback) override;
bool IsFlushSupported() override;
void SetCommandBufferHelperCB(
base::RepeatingCallback<scoped_refptr<CommandBufferHelper>()>
get_command_buffer_helper_cb,
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner) override;
void SetSharedImageInterfaceForTesting(
scoped_refptr<gpu::SharedImageInterface> sii) override;
private:
// Auto-destroy reference for BitstreamBuffer, for tracking buffers passed to
// this instance.
struct BitstreamBufferRef;
// Record for codec input buffers.
struct InputRecord {
InputRecord();
InputRecord(const InputRecord&);
~InputRecord();
scoped_refptr<VideoFrame> frame;
// This is valid only if image processor is used. The buffer associated with
// this index can be reused in Dequeue().
std::optional<size_t> ip_output_buffer_index;
};
// Store all the information of input frame passed to Encode().
struct InputFrameInfo {
InputFrameInfo();
InputFrameInfo(scoped_refptr<VideoFrame> frame, bool force_keyframe);
InputFrameInfo(scoped_refptr<VideoFrame> frame,
bool force_keyframe,
size_t index);
InputFrameInfo(const InputFrameInfo&);
~InputFrameInfo();
scoped_refptr<VideoFrame> frame;
bool force_keyframe;
// This is valid only if image processor is used. This info needs to be
// propagated to InputRecord.
std::optional<size_t> ip_output_buffer_index;
};
enum {
// These are rather subjectively tuned.
kInputBufferCount = 2,
kOutputBufferCount = 2,
kImageProcBufferCount = 2,
};
// Internal state of the encoder.
enum State {
kUninitialized, // Initialize() not yet called.
kInitialized, // Initialize() returned true. The encoding is ready after
// InitializeTask() completes successfully.
kEncoding, // Encoding frames.
kFlushing, // Flushing frames.
kError, // Error in encoder state.
};
//
// Callbacks for the image processor, if one is used.
//
// Callback run by the image processor when a |frame| is ready for us to
// encode.
void FrameProcessed(bool force_keyframe,
base::TimeDelta timestamp,
size_t output_buffer_index,
scoped_refptr<VideoFrame> frame);
// Error callback for handling image processor errors.
void ImageProcessorError();
//
// Encoding tasks, to be run on encode_thread_.
//
void EncodeTask(scoped_refptr<VideoFrame> frame, bool force_keyframe);
// Add a BitstreamBuffer to the queue of buffers ready to be used for encoder
// output.
void UseOutputBitstreamBufferTask(BitstreamBuffer buffer);
// Device destruction task.
void DestroyTask();
// Try to output bitstream buffers.
void PumpBitstreamBuffers();
// Flush all the encoded frames. After all frames is flushed successfully or
// any error occurs, |flush_callback| will be called to notify client.
void FlushTask(FlushCallback flush_callback);
// Service I/O on the V4L2 devices. This task should only be scheduled from
// DevicePollTask().
void ServiceDeviceTask();
// Handle the device queues.
void Enqueue();
void Dequeue();
// Enqueue a buffer on the corresponding queue. Returns false on fatal error.
bool EnqueueInputRecord(V4L2WritableBufferRef input_buf);
bool EnqueueOutputRecord(V4L2WritableBufferRef output_buf);
// Attempt to start/stop device_poll_thread_.
bool StartDevicePoll();
bool StopDevicePoll();
//
// Device tasks, to be run on device_poll_thread_.
//
// The device task.
void DevicePollTask(bool poll_device);
//
// Safe from any thread.
//
// Set the encoder_state_ to kError and notify the client (if necessary).
void SetErrorState(EncoderStatus status);
//
// Other utility functions. Called on the |encoder_task_runner_|.
//
// Create image processor that will process |input_layout| +
// |input_visible_rect| to |output_layout|+|output_visible_rect|.
bool CreateImageProcessor(const VideoFrameLayout& input_layout,
const VideoPixelFormat output_format,
const gfx::Size& output_size,
const gfx::Rect& input_visible_rect,
const gfx::Rect& output_visible_rect);
// Process one video frame in |image_processor_input_queue_| by
// |image_processor_|.
void InputImageProcessorTask();
void MaybeFlushImageProcessor();
// Change encoding parameters.
void RequestEncodingParametersChangeTask(
const VideoBitrateAllocation& bitrate_allocation,
uint32_t framerate,
const std::optional<gfx::Size>& size);
// Do several initializations (e.g. set up format) on |encoder_task_runner_|.
void InitializeTask(const Config& config);
// Set up formats and initialize the device for them.
bool SetFormats(VideoPixelFormat input_format,
VideoCodecProfile output_profile);
// Reconfigure format of input buffers and image processor if the buffer
// represented by |frame| is different from one set in input buffers.
bool ReconfigureFormatIfNeeded(const VideoFrame& frame);
// Try to set up the device to the input format we were Initialized() with,
// or if the device doesn't support it, use one it can support, so that we
// can later instantiate an ImageProcessor to convert to it. Return
// std::nullopt if no format is supported, otherwise return v4l2_format
// adjusted by the driver.
std::optional<struct v4l2_format> NegotiateInputFormat(
VideoPixelFormat input_format,
const gfx::Size& frame_size);
// Apply the current crop parameters to the V4L2 device.
bool ApplyCrop();
// Set up the device to the output format requested in Initialize().
bool SetOutputFormat(VideoCodecProfile output_profile);
// Initialize device controls with |config| or default values.
bool InitControls(const Config& config);
// Initialize device controls with |config| or default values.
bool InitControlsH264(const Config& config);
// Initialize device controls with |config| or default values.
void InitControlsVP8(const Config& config);
// Create the buffers we need.
bool CreateInputBuffers();
bool CreateOutputBuffers();
// Destroy these buffers.
void DestroyInputBuffers();
void DestroyOutputBuffers();
// Allocates |count| video frames with |visible_size| for image processor's
// output buffers. Returns false if there's something wrong.
bool AllocateImageProcessorOutputBuffers(size_t count);
// Recycle output buffer of image processor with |output_buffer_index|.
void ReuseImageProcessorOutputBuffer(size_t output_buffer_index);
// Chrome specific metadata about the encoded frame.
BitstreamBufferMetadata GetMetadata(const uint8_t* data,
size_t data_size_bytes,
bool key_frame,
base::TimeDelta timestamp);
// Copy encoded stream data from an output V4L2 buffer at |bitstream_data|
// of size |bitstream_size| into a BitstreamBuffer referenced by |buffer_ref|,
// injecting stream headers if required. Return the size in bytes of the
// resulting stream in the destination buffer.
size_t CopyIntoOutputBuffer(const uint8_t* bitstream_data,
size_t bitstream_size,
std::unique_ptr<BitstreamBufferRef> buffer_ref);
// Initializes input_memory_type_.
bool InitInputMemoryType(const Config& config);
void OnSharedImageInterfaceAvailable(
scoped_refptr<gpu::SharedImageInterface> sii);
// Having too many encoder instances at once may cause us to run out of FDs
// and subsequently crash (crbug.com/1289465). To avoid that, we limit the
// maximum number of encoder instances that can exist at once.
// |num_instances_| tracks that number.
static constexpr int kMaxNumOfInstances = 10;
static base::AtomicRefCount num_instances_;
const bool can_use_encoder_;
std::string driver_name_;
// Our original calling task runner for the child sequence and its checker.
const scoped_refptr<base::SequencedTaskRunner> child_task_runner_;
SEQUENCE_CHECKER(child_sequence_checker_);
// A coded_size() of VideoFrame on VEA::Encode(). This is updated on the first
// time Encode() if the coded size is different from the expected one by VEA.
// For example, it happens in WebRTC simulcast case.
gfx::Size input_frame_size_;
// A natural_size() of VideoFrame on VEA::Encode(). This is updated on the
// first time Encode() always. The natural_size() of VideoFrames fed by
// VEA::Encode() must be the same as |input_natural_size_|.
gfx::Size input_natural_size_;
// Visible rectangle of VideoFrame to be fed to an encoder driver, in other
// words, a visible rectangle that output encoded bitstream buffers represent.
gfx::Rect encoder_input_visible_rect_;
// Layout of device accepted input VideoFrame.
std::optional<VideoFrameLayout> device_input_layout_;
// Stands for whether an input buffer is native graphic buffer.
bool native_input_mode_;
size_t output_buffer_byte_size_;
uint32_t output_format_fourcc_;
VideoBitrateAllocation current_bitrate_allocation_;
size_t current_framerate_;
// Encoder state, owned and operated by |encoder_task_runner_|.
State encoder_state_;
// For H264, for resilience, we prepend each IDR with SPS and PPS. Some
// devices support this via the V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR
// control. For devices that don't, we cache the latest SPS and PPS and inject
// them into the stream before every IDR.
bool inject_sps_and_pps_ = false;
// Cached SPS (without H.264 start code).
std::vector<uint8_t> cached_sps_;
// Cached PPS (without H.264 start code).
std::vector<uint8_t> cached_pps_;
// Size in bytes required to inject cached SPS and PPS, including H.264
// start codes.
size_t cached_h264_header_size_ = 0;
// Video frames ready to be encoded.
base::queue<InputFrameInfo> encoder_input_queue_;
// Encoder device.
scoped_refptr<V4L2Device> device_;
// Mapping of int index to input buffer record.
std::vector<InputRecord> input_buffer_map_;
v4l2_memory input_memory_type_;
scoped_refptr<V4L2Queue> input_queue_;
scoped_refptr<V4L2Queue> output_queue_;
// Bitstream buffers ready to be used to return encoded output, as a LIFO
// since we don't care about ordering.
std::vector<std::unique_ptr<BitstreamBufferRef>> bitstream_buffer_pool_;
// Queue of encoded bitstream V4L2 buffers. We enqueue the encoded buffers
// from V4L2 devices, and copy the data to the bitstream buffers passed from
// the client via UseOutputBitstreamBuffer().
base::circular_deque<V4L2ReadableBufferRef> output_buffer_queue_;
// The completion callback of the Flush() function.
FlushCallback flush_callback_;
// Indicates whether the V4L2 device supports flush.
// This is set in Initialize().
bool is_flush_supported_;
// Image processor, if one is in use.
std::unique_ptr<ImageProcessor> image_processor_;
// Video frames for image processor output / VideoEncodeAccelerator input.
// Only accessed on child thread.
std::vector<scoped_refptr<VideoFrame>> image_processor_output_buffers_;
// Indexes of free image processor output buffers. Only accessed on
// |child_task_runner_|.
std::vector<size_t> free_image_processor_output_buffer_indices_;
// Video frames ready to be processed. Only accessed on |child_task_runner_|.
base::queue<InputFrameInfo> image_processor_input_queue_;
// The number of frames that are being processed by |image_processor_|.
size_t num_frames_in_image_processor_ = 0;
// Indicates whether V4L2VideoEncodeAccelerator runs in L1T2 or not.
bool h264_l1t2_enabled_ = false;
const scoped_refptr<base::SequencedTaskRunner> encoder_task_runner_;
SEQUENCE_CHECKER(encoder_sequence_checker_);
// The device polling thread handles notifications of V4L2 device changes.
// TODO(sheu): replace this thread with an TYPE_IO encoder_thread_.
base::Thread device_poll_thread_;
// To expose client callbacks from VideoEncodeAccelerator.
// NOTE: all calls to these objects *MUST* be executed on
// |child_task_runner_|.
base::WeakPtr<Client> client_;
std::unique_ptr<base::WeakPtrFactory<Client>> client_ptr_factory_;
scoped_refptr<gpu::SharedImageInterface> sii_;
// WeakPtr<> pointing to |this| for use in posting tasks to
// |encoder_task_runner_|.
base::WeakPtr<V4L2VideoEncodeAccelerator> weak_this_;
base::WeakPtrFactory<V4L2VideoEncodeAccelerator> weak_this_factory_{this};
};
} // namespace media
#endif // MEDIA_GPU_V4L2_V4L2_VIDEO_ENCODE_ACCELERATOR_H_
|