blob: acff2f6b27486682c626132f904a2418c0ecf3d9 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// 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_MJPEG_DECODE_ACCELERATOR_H_
#define MEDIA_GPU_V4L2_V4L2_MJPEG_DECODE_ACCELERATOR_H_
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <vector>
#include "base/containers/queue.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread.h"
#include "components/chromeos_camera/mjpeg_decode_accelerator.h"
#include "media/base/bitstream_buffer.h"
#include "media/base/unaligned_shared_memory.h"
#include "media/gpu/media_gpu_export.h"
#include "media/gpu/v4l2/v4l2_device.h"
namespace media {
class VideoFrame;
class MEDIA_GPU_EXPORT V4L2MjpegDecodeAccelerator
: public chromeos_camera::MjpegDecodeAccelerator {
public:
V4L2MjpegDecodeAccelerator(
const scoped_refptr<V4L2Device>& device,
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
~V4L2MjpegDecodeAccelerator() override;
// MjpegDecodeAccelerator implementation.
bool Initialize(
chromeos_camera::MjpegDecodeAccelerator::Client* client) override;
void Decode(BitstreamBuffer bitstream_buffer,
scoped_refptr<VideoFrame> video_frame) override;
bool IsSupported() override;
private:
// Record for input/output buffers.
struct BufferRecord {
BufferRecord();
~BufferRecord();
void* address[VIDEO_MAX_PLANES]; // mmap() address.
size_t length[VIDEO_MAX_PLANES]; // mmap() length.
// Set true during QBUF and DQBUF. |address| will be accessed by hardware.
bool at_device;
};
// Job record. Jobs are processed in a FIFO order. This is separate from
// BufferRecord of input, because a BufferRecord of input may be returned
// before we dequeue the corresponding output buffer. It can't always be
// associated with a BufferRecord of output immediately either, because at
// the time of submission we may not have one available (and don't need one
// to submit input to the device).
struct JobRecord {
JobRecord(BitstreamBuffer bitstream_buffer,
scoped_refptr<VideoFrame> video_frame);
~JobRecord();
// Input image buffer ID.
int32_t bitstream_buffer_id;
// Memory mapped from |bitstream_buffer|.
UnalignedSharedMemory shm;
// Offset used for shm.
off_t offset;
// Output frame buffer.
scoped_refptr<VideoFrame> out_frame;
};
void EnqueueInput();
void EnqueueOutput();
void Dequeue();
bool EnqueueInputRecord();
bool EnqueueOutputRecord();
bool CreateInputBuffers();
bool CreateOutputBuffers();
void DestroyInputBuffers();
void DestroyOutputBuffers();
// Convert |output_buffer| to |dst_frame|. The function supports the following
// formats:
// - All formats that libyuv::ConvertToI420 can handle.
// - V4L2_PIX_FMT_YUV_420M, V4L2_PIX_FMT_YUV_422M to I420, YV12, and NV12.
bool ConvertOutputImage(const BufferRecord& output_buffer,
scoped_refptr<VideoFrame> dst_frame);
// Return the number of input/output buffers enqueued to the device.
size_t InputBufferQueuedCount();
size_t OutputBufferQueuedCount();
// Return true if input buffer size is not enough.
bool ShouldRecreateInputBuffers();
// Destroy and create input buffers. Return false on error.
bool RecreateInputBuffers();
// Destroy and create output buffers. Return false on error.
bool RecreateOutputBuffers();
void VideoFrameReady(int32_t bitstream_buffer_id);
void NotifyError(int32_t bitstream_buffer_id, Error error);
void PostNotifyError(int32_t bitstream_buffer_id, Error error);
// Run on |decoder_thread_| to enqueue the coming frame.
void DecodeTask(std::unique_ptr<JobRecord> job_record);
// Run on |decoder_thread_| to dequeue last frame and enqueue next frame.
// This task is triggered by DevicePollTask. |event_pending| means that device
// has resolution change event or pixelformat change event.
void ServiceDeviceTask(bool event_pending);
// Dequeue source change event. Return false on error.
bool DequeueSourceChangeEvent();
// Start/Stop |device_poll_thread_|.
void StartDevicePoll();
bool StopDevicePoll();
// Run on |device_poll_thread_| to wait for device events.
void DevicePollTask();
// Run on |decoder_thread_| to destroy input and output buffers.
void DestroyTask();
// The number of input buffers and output buffers.
const size_t kBufferCount = 2;
// Coded size of output buffer.
gfx::Size output_buffer_coded_size_;
// Pixel format of output buffer.
uint32_t output_buffer_pixelformat_;
// Number of physical planes the output buffers have.
size_t output_buffer_num_planes_;
// Strides of the output buffers.
size_t output_strides_[VIDEO_MAX_PLANES];
// ChildThread's task runner.
scoped_refptr<base::SingleThreadTaskRunner> child_task_runner_;
// GPU IO task runner.
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
// The client of this class.
chromeos_camera::MjpegDecodeAccelerator::Client* client_;
// The V4L2Device this class is operating upon.
scoped_refptr<V4L2Device> device_;
// Thread to communicate with the device.
base::Thread decoder_thread_;
// Decode task runner.
scoped_refptr<base::SingleThreadTaskRunner> decoder_task_runner_;
// Thread used to poll the V4L2 for events only.
base::Thread device_poll_thread_;
// Device poll task runner.
scoped_refptr<base::SingleThreadTaskRunner> device_poll_task_runner_;
// All the below members except |weak_factory_| are accessed from
// |decoder_thread_| only (if it's running).
base::queue<std::unique_ptr<JobRecord>> input_jobs_;
base::queue<std::unique_ptr<JobRecord>> running_jobs_;
// Input queue state.
bool input_streamon_;
// Mapping of int index to an input buffer record.
std::vector<BufferRecord> input_buffer_map_;
// Indices of input buffers ready to use; LIFO since we don't care about
// ordering.
std::vector<int> free_input_buffers_;
// Output queue state.
bool output_streamon_;
// Mapping of int index to an output buffer record.
std::vector<BufferRecord> output_buffer_map_;
// Indices of output buffers ready to use; LIFO since we don't care about
// ordering.
std::vector<int> free_output_buffers_;
// Point to |this| for use in posting tasks from the decoder thread back to
// the ChildThread.
base::WeakPtr<V4L2MjpegDecodeAccelerator> weak_ptr_;
// Weak factory for producing weak pointers on the child thread.
base::WeakPtrFactory<V4L2MjpegDecodeAccelerator> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(V4L2MjpegDecodeAccelerator);
};
} // namespace media
#endif // MEDIA_GPU_V4L2_V4L2_MJPEG_DECODE_ACCELERATOR_H_