// Copyright 2014 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. // // This file defines the V4L2Device interface which is used by the // V4L2DecodeAccelerator class to delegate/pass the device specific // handling of any of the functionalities. // Note: ported from Chromium commit head: 2f13d62f0c0d // Note: the complete v4l2 device code is ported from Chromium, but some parts // have been removed: // - All V4L2 request functionality has been removed, as it required a newer // kernel version. // - void SetConfigStore() has been removed as it depends on a newer kernel // version. // - QueueDMABuf() from native pixmap planes has been removed, as // NativePixmapPlane have not been ported. // - GetVideoFrame() is removed as it depends on some helper functions that have // not been ported. // - GL-related functionality has been removed: canCreateEGLImageFrom(), // CreateEGLImage(), CreateGLImage() and GetTextureTarget() // - V4L2PixFmtToDrmFormat() has been removed, as DRM is not supported yet. #ifndef V4L2_DEVICE_H_ #define V4L2_DEVICE_H_ #include #include #include #include #include #include "base/containers/flat_map.h" #include "base/files/scoped_file.h" #include "base/memory/ref_counted.h" #include "fourcc.h" #include "size.h" #include "v4l2_device_poller.h" #include "video_codecs.h" #include "video_decode_accelerator.h" #include "video_encode_accelerator.h" #include "video_frame.h" #include "video_frame_layout.h" #include "video_pixel_format.h" // TODO(mojahsu): remove this once V4L2 headers are updated. #ifndef V4L2_PIX_FMT_JPEG_RAW #define V4L2_PIX_FMT_JPEG_RAW v4l2_fourcc('J', 'P', 'G', 'R') #endif #ifndef V4L2_CID_JPEG_LUMA_QUANTIZATION #define V4L2_CID_JPEG_LUMA_QUANTIZATION (V4L2_CID_JPEG_CLASS_BASE + 5) #endif #ifndef V4L2_CID_JPEG_CHROMA_QUANTIZATION #define V4L2_CID_JPEG_CHROMA_QUANTIZATION (V4L2_CID_JPEG_CLASS_BASE + 6) #endif // TODO(b/132589320): remove this once V4L2 header is updated. #ifndef V4L2_PIX_FMT_MM21 // MTK 8-bit block mode, two non-contiguous planes. #define V4L2_PIX_FMT_MM21 v4l2_fourcc('M', 'M', '2', '1') #endif namespace media { class V4L2Queue; class V4L2BufferRefBase; class V4L2BuffersList; class V4L2DecodeSurface; // Dummy V4L2RequestRef. The full request queue functionality could not be // ported as it requires a newer kernel header. class V4L2RequestRef {}; // Wrapper for the 'v4l2_ext_control' structure. struct V4L2ExtCtrl { V4L2ExtCtrl(uint32_t id); V4L2ExtCtrl(uint32_t id, int32_t val); struct v4l2_ext_control ctrl; }; // A unique reference to a buffer for clients to prepare and submit. // // Clients can prepare a buffer for queuing using the methods of this class, and // then either queue it using the Queue() method corresponding to the memory // type of the buffer, or drop the reference to make the buffer available again. class V4L2WritableBufferRef { public: V4L2WritableBufferRef(V4L2WritableBufferRef&& other); V4L2WritableBufferRef() = delete; V4L2WritableBufferRef& operator=(V4L2WritableBufferRef&& other); // Return the memory type of the buffer. Useful to e.g. decide which Queue() // method to use. enum v4l2_memory Memory() const; // Queue a MMAP buffer. // When requests are supported, a |request_ref| can be passed along this // the buffer to be submitted. // If successful, true is returned and the reference to the buffer is dropped // so this reference becomes invalid. // In case of error, false is returned and the buffer is returned to the free // list. bool QueueMMap(V4L2RequestRef* request_ref = nullptr) &&; // Queue a USERPTR buffer, assigning |ptrs| as pointer for each plane. // The size of |ptrs| must be equal to the number of planes of this buffer. // When requests are supported, a |request_ref| can be passed along this // the buffer to be submitted. // If successful, true is returned and the reference to the buffer is dropped // so this reference becomes invalid. // In case of error, false is returned and the buffer is returned to the free // list. bool QueueUserPtr(const std::vector& ptrs, V4L2RequestRef* request_ref = nullptr) &&; // Queue a DMABUF buffer, assigning |fds| as file descriptors for each plane. // It is allowed the number of |fds| might be greater than the number of // planes of this buffer. It happens when the v4l2 pixel format is single // planar. The fd of the first plane is only used in that case. // When requests are supported, a |request_ref| can be passed along this // the buffer to be submitted. // If successful, true is returned and the reference to the buffer is dropped // so this reference becomes invalid. // In case of error, false is returned and the buffer is returned to the free // list. bool QueueDMABuf(const std::vector& scoped_fds, V4L2RequestRef* request_ref = nullptr) &&; // Queue a DMABUF buffer, assigning |fds| as file descriptors for each plane. // It is allowed the number of |fds| might be greater than the number of // planes of this buffer. It happens when the v4l2 pixel format is single // planar. The fd of the first plane is only used in that case. // When requests are supported, a |request_ref| can be passed along this // the buffer to be submitted. // If successful, true is returned and the reference to the buffer is dropped // so this reference becomes invalid. // In case of error, false is returned and the buffer is returned to the free // list. bool QueueDMABuf(const std::vector& fds, V4L2RequestRef* request_ref = nullptr) &&; // Returns the number of planes in this buffer. size_t PlanesCount() const; // Returns the size of the requested |plane|, in bytes. size_t GetPlaneSize(const size_t plane) const; // Set the size of the requested |plane|, in bytes. It is only valid for // USERPTR and DMABUF buffers. When using MMAP buffer, this method triggers a // DCHECK and is a no-op for release builds. void SetPlaneSize(const size_t plane, const size_t size); // This method can only be used with MMAP buffers. // It will return a pointer to the data of the |plane|th plane. // In case of error (invalid plane index or mapping failed), a nullptr is // returned. void* GetPlaneMapping(const size_t plane); // Set the timestamp field for this buffer. void SetTimeStamp(const struct timeval& timestamp); // Return the previously-set timestamp field for this buffer. const struct timeval& GetTimeStamp() const; // Set the number of bytes used for |plane|. void SetPlaneBytesUsed(const size_t plane, const size_t bytes_used); // Returns the previously-set number of bytes used for |plane|. size_t GetPlaneBytesUsed(const size_t plane) const; // Set the data offset for |plane|, in bytes. void SetPlaneDataOffset(const size_t plane, const size_t data_offset); // Return the V4L2 buffer ID of the underlying buffer. // TODO(acourbot) This is used for legacy clients but should be ultimately // removed. See crbug/879971 size_t BufferId() const; ~V4L2WritableBufferRef(); private: // Do the actual queue operation once the v4l2_buffer structure is properly // filled. // When requests are supported, a |request_ref| can be passed along this // the buffer to be submitted. bool DoQueue(V4L2RequestRef* request_ref) &&; V4L2WritableBufferRef(const struct v4l2_buffer& v4l2_buffer, base::WeakPtr queue); friend class V4L2BufferRefFactory; std::unique_ptr buffer_data_; SEQUENCE_CHECKER(sequence_checker_); DISALLOW_COPY_AND_ASSIGN(V4L2WritableBufferRef); }; // A reference to a read-only, dequeued buffer. // // Clients use this class to query the buffer state and content, and are // guaranteed that the buffer will not be reused until all references are // destroyed. // All methods of this class must be called from the same sequence, but // instances of V4L2ReadableBuffer objects can be destroyed from any sequence. // They can even outlive the V4L2 buffers they originate from. This flexibility // is required because V4L2ReadableBufferRefs can be embedded into VideoFrames, // which are then passed to other threads and not necessarily destroyed before // the V4L2Queue buffers are freed. class V4L2ReadableBuffer : public base::RefCountedThreadSafe { public: // Returns whether the V4L2_BUF_FLAG_LAST flag is set for this buffer. bool IsLast() const; // Returns whether the V4L2_BUF_FLAG_KEYFRAME flag is set for this buffer. bool IsKeyframe() const; // Return the timestamp set by the driver on this buffer. struct timeval GetTimeStamp() const; // Returns the number of planes in this buffer. size_t PlanesCount() const; // Returns the number of bytes used for |plane|. size_t GetPlaneBytesUsed(size_t plane) const; // Returns the data offset for |plane|. size_t GetPlaneDataOffset(size_t plane) const; // This method can only be used with MMAP buffers. // It will return a pointer to the data of the |plane|th plane. // In case of error (invalid plane index or mapping failed), a nullptr is // returned. const void* GetPlaneMapping(const size_t plane) const; // Return the V4L2 buffer ID of the underlying buffer. // TODO(acourbot) This is used for legacy clients but should be ultimately // removed. See crbug/879971 size_t BufferId() const; private: friend class V4L2BufferRefFactory; friend class base::RefCountedThreadSafe; ~V4L2ReadableBuffer(); V4L2ReadableBuffer(const struct v4l2_buffer& v4l2_buffer, base::WeakPtr queue); std::unique_ptr buffer_data_; SEQUENCE_CHECKER(sequence_checker_); DISALLOW_COPY_AND_ASSIGN(V4L2ReadableBuffer); }; // Shortcut for naming consistency. using V4L2ReadableBufferRef = scoped_refptr; class V4L2Device; class V4L2Buffer; // Interface representing a specific queue of a |V4L2Device|. It provides free // and queued buffer management that is commonly required by clients. // // Buffers managed by this class undergo the following cycle: // 1) Allocated buffers are put into a free buffers pool, indicating that they // are used neither by the client nor the hardware. // 2) The client obtains a unique, writable reference to one of the free // buffers in order to set its content and other parameters. // 3) The client then queues the buffer obtained in 2), which invalidates its // reference. The buffer is now prepared to be processed by the hardware. // 4) Once the hardware is done with the buffer, it is ready to be dequeued by // the client. The client obtains a read-only, counted reference to the // buffer and can read its content and metadata, as well as making other // references to it. The buffer will not be reused until all the references // are dropped. Once this happens, the buffer goes back to the free list // described in 1). class V4L2Queue : public base::RefCountedThreadSafe { public: // Set |fourcc| as the current format on this queue. |size| corresponds to the // desired buffer's dimensions (i.e. width and height members of // v4l2_pix_format_mplane (if not applicable, pass Size()). // |buffer_size| is the desired size in bytes of the buffer for single-planar // formats (i.e. sizeimage of the first plane). It can be set to 0 if not // relevant for the desired format. // If the format could be set, then the |v4l2_format| reflecting the actual // format is returned. It is guaranteed to feature the specified |fourcc|, // but any other parameter (including |size| and |buffer_size| may have been // adjusted by the driver, so the caller must check their values. base::Optional SetFormat(uint32_t fourcc, const Size& size, size_t buffer_size) WARN_UNUSED_RESULT; // Allocate |count| buffers for the current format of this queue, with a // specific |memory| allocation, and returns the number of buffers allocated // or zero if an error occurred, or if references to any previously allocated // buffers are still held by any clients. // // The number of allocated buffers may be larger than the number requested, so // callers must always check the return value. // // Calling this method while buffers are still allocated results in an error. size_t AllocateBuffers(size_t count, enum v4l2_memory memory) WARN_UNUSED_RESULT; // Deallocate all buffers previously allocated by |AllocateBuffers|. Any // references to buffers previously allocated held by the client must be // released, or this call will fail. bool DeallocateBuffers(); // Returns the memory usage of v4l2 buffers owned by this V4L2Queue which are // mapped in user space memory. size_t GetMemoryUsage() const; // Returns |memory_|, memory type of last buffers allocated by this V4L2Queue. v4l2_memory GetMemoryType() const; // Return a reference to a free buffer for the caller to prepare and submit, // or nullopt if no buffer is currently free. // // If the caller discards the returned reference, the underlying buffer is // made available to clients again. base::Optional GetFreeBuffer(); base::Optional GetFreeBuffer( size_t requested_buffer_id); // Attempt to dequeue a buffer, and return a reference to it if one was // available. // // The first element of the returned pair will be false if an error occurred, // in which case the second element will be nullptr. If no error occurred, // then the first element will be true and the second element will contain a // reference to the dequeued buffer if one was available, or nullptr // otherwise. // Dequeued buffers will not be reused by the driver until all references to // them are dropped. std::pair DequeueBuffer(); // Returns true if this queue is currently streaming. bool IsStreaming() const; // If not currently streaming, starts streaming. Returns true if we started // streaming, or were already streaming, or false if we were not streaming // and an error occurred when attempting to start the stream. On failure, any // previously-queued buffers will be dequeued without processing and made // available to the client, while any buffers held by the client will remain // unchanged and their ownership will remain with the client. bool Streamon(); // If currently streaming, stops streaming. Also make all queued buffers // available to the client again regardless of the streaming state. // If an error occurred while attempting to stop streaming, then false is // returned and queued buffers are left untouched since the V4L2 queue may // still be using them. bool Streamoff(); // Returns the number of buffers currently allocated for this queue. size_t AllocatedBuffersCount() const; // Returns the number of currently free buffers on this queue. size_t FreeBuffersCount() const; // Returns the number of buffers currently queued on this queue. size_t QueuedBuffersCount() const; // Returns true if requests are supported by this queue. bool SupportsRequests(); private: ~V4L2Queue(); // Called when clients request a buffer to be queued. bool QueueBuffer(struct v4l2_buffer* v4l2_buffer); const enum v4l2_buf_type type_; enum v4l2_memory memory_ = V4L2_MEMORY_MMAP; bool is_streaming_ = false; // Set to true if the queue supports requests. bool supports_requests_ = false; size_t planes_count_ = 0; // Current format as set by SetFormat. base::Optional current_format_; std::vector> buffers_; // Buffers that are available for client to get and submit. // Buffers in this list are not referenced by anyone else than ourselves. scoped_refptr free_buffers_; // Buffers that have been queued by the client, and not dequeued yet. std::set queued_buffers_; scoped_refptr device_; // Callback to call in this queue's destructor. base::OnceClosure destroy_cb_; V4L2Queue(scoped_refptr dev, enum v4l2_buf_type type, base::OnceClosure destroy_cb); friend class V4L2QueueFactory; friend class V4L2BufferRefBase; friend class base::RefCountedThreadSafe; SEQUENCE_CHECKER(sequence_checker_); base::WeakPtrFactory weak_this_factory_; DISALLOW_COPY_AND_ASSIGN(V4L2Queue); }; class V4L2Device : public base::RefCountedThreadSafe { public: // Utility format conversion functions // If there is no corresponding single- or multi-planar format, returns 0. static uint32_t VideoCodecProfileToV4L2PixFmt(VideoCodecProfile profile, bool slice_based); static VideoCodecProfile V4L2ProfileToVideoCodecProfile(VideoCodec codec, uint32_t profile); std::vector V4L2PixFmtToVideoCodecProfiles( uint32_t pix_fmt, bool is_encoder); // Calculates the largest plane's allocation size requested by a V4L2 device. static Size AllocatedSizeFromV4L2Format(const struct v4l2_format& format); // Convert required H264 profile and level to V4L2 enums. static int32_t VideoCodecProfileToV4L2H264Profile(VideoCodecProfile profile); static int32_t H264LevelIdcToV4L2H264Level(uint8_t level_idc); // Converts v4l2_memory to a string. static const char* V4L2MemoryToString(const v4l2_memory memory); // Returns the printable name of a v4l2_buf_type. static const char* V4L2BufferTypeToString(const enum v4l2_buf_type buf_type); // Composes human readable string of v4l2_format. static std::string V4L2FormatToString(const struct v4l2_format& format); // Composes human readable string of v4l2_buffer. static std::string V4L2BufferToString(const struct v4l2_buffer& buffer); // Composes VideoFrameLayout based on v4l2_format. // If error occurs, it returns base::nullopt. static base::Optional V4L2FormatToVideoFrameLayout( const struct v4l2_format& format); // Returns number of planes of |pix_fmt|. static size_t GetNumPlanesOfV4L2PixFmt(uint32_t pix_fmt); enum class Type { kDecoder, kEncoder, kImageProcessor, kJpegDecoder, kJpegEncoder, }; // Create and initialize an appropriate V4L2Device instance for the current // platform, or return nullptr if not available. static scoped_refptr Create(); // Open a V4L2 device of |type| for use with |v4l2_pixfmt|. // Return true on success. // The device will be closed in the destructor. virtual bool Open(Type type, uint32_t v4l2_pixfmt) = 0; // Returns the V4L2Queue corresponding to the requested |type|, or nullptr // if the requested queue type is not supported. scoped_refptr GetQueue(enum v4l2_buf_type type); // Parameters and return value are the same as for the standard ioctl() system // call. virtual int Ioctl(int request, void* arg) = 0; // This method sleeps until either: // - SetDevicePollInterrupt() is called (on another thread), // - |poll_device| is true, and there is new data to be read from the device, // or an event from the device has arrived; in the latter case // |*event_pending| will be set to true. // Returns false on error, true otherwise. // This method should be called from a separate thread. virtual bool Poll(bool poll_device, bool* event_pending) = 0; // These methods are used to interrupt the thread sleeping on Poll() and force // it to return regardless of device state, which is usually when the client // is no longer interested in what happens with the device (on cleanup, // client state change, etc.). When SetDevicePollInterrupt() is called, Poll() // will return immediately, and any subsequent calls to it will also do so // until ClearDevicePollInterrupt() is called. virtual bool SetDevicePollInterrupt() = 0; virtual bool ClearDevicePollInterrupt() = 0; // Wrappers for standard mmap/munmap system calls. virtual void* Mmap(void* addr, unsigned int len, int prot, int flags, unsigned int offset) = 0; virtual void Munmap(void* addr, unsigned int len) = 0; // Return a vector of dmabuf file descriptors, exported for V4L2 buffer with // |index|, assuming the buffer contains |num_planes| V4L2 planes and is of // |type|. Return an empty vector on failure. // The caller is responsible for closing the file descriptors after use. virtual std::vector GetDmabufsForV4L2Buffer( int index, size_t num_planes, enum v4l2_buf_type type) = 0; // Returns the preferred V4L2 input formats for |type| or empty if none. virtual std::vector PreferredInputFormat(Type type) = 0; // NOTE: The below methods to query capabilities have a side effect of // closing the previously-open device, if any, and should not be called after // Open(). // TODO(posciak): fix this. // Get minimum and maximum resolution for fourcc |pixelformat| and store to // |min_resolution| and |max_resolution|. void GetSupportedResolution(uint32_t pixelformat, Size* min_resolution, Size* max_resolution); std::vector EnumerateSupportedPixelformats(v4l2_buf_type buf_type); // Return V4L2 pixelformats supported by the available image processor // devices for |buf_type|. virtual std::vector GetSupportedImageProcessorPixelformats( v4l2_buf_type buf_type) = 0; // Return supported profiles for decoder, including only profiles for given // fourcc |pixelformats|. virtual VideoDecodeAccelerator::SupportedProfiles GetSupportedDecodeProfiles( const size_t num_formats, const uint32_t pixelformats[]) = 0; // Return supported profiles for encoder. virtual VideoEncodeAccelerator::SupportedProfiles GetSupportedEncodeProfiles() = 0; // Return true if image processing is supported, false otherwise. virtual bool IsImageProcessingSupported() = 0; // Return true if JPEG codec is supported, false otherwise. virtual bool IsJpegDecodingSupported() = 0; virtual bool IsJpegEncodingSupported() = 0; // Start polling on this V4L2Device. |event_callback| will be posted to // the caller's sequence if a buffer is ready to be dequeued and/or a V4L2 // event has been posted. |error_callback| will be posted to the client's // sequence if a polling error has occurred. bool StartPolling(V4L2DevicePoller::EventCallback event_callback, base::RepeatingClosure error_callback); // Stop polling this V4L2Device if polling was active. No new events will // be posted after this method has returned. bool StopPolling(); // Schedule a polling event if polling is enabled. This method is intended // to be called from V4L2Queue, clients should not need to call it directly. void SchedulePoll(); // Check whether the V4L2 control with specified |ctrl_id| is supported. bool IsCtrlExposed(uint32_t ctrl_id); // Set the specified list of |ctrls| for the specified |ctrl_class|, returns // whether the operation succeeded. bool SetExtCtrls(uint32_t ctrl_class, std::vector ctrls); // Check whether the V4L2 command with specified |command_id| is supported. bool IsCommandSupported(uint32_t command_id); // Check whether the V4L2 device has the specified |capabilities|. bool HasCapabilities(uint32_t capabilities); protected: friend class base::RefCountedThreadSafe; V4L2Device(); virtual ~V4L2Device(); VideoDecodeAccelerator::SupportedProfiles EnumerateSupportedDecodeProfiles( const size_t num_formats, const uint32_t pixelformats[]); VideoEncodeAccelerator::SupportedProfiles EnumerateSupportedEncodeProfiles(); private: // Perform platform-specific initialization of the device instance. // Return true on success, false on error or if the particular implementation // is not available. virtual bool Initialize() = 0; // Associates a v4l2_buf_type to its queue. base::flat_map queues_; // Callback that is called upon a queue's destruction, to cleanup its pointer // in queues_. void OnQueueDestroyed(v4l2_buf_type buf_type); // Used if EnablePolling() is called to signal the user that an event // happened or a buffer is ready to be dequeued. std::unique_ptr device_poller_; // Indicates whether the request queue creation has been tried once. bool requests_queue_creation_called_ = false; SEQUENCE_CHECKER(client_sequence_checker_); }; } // namespace media #endif // V4L2_DEVICE_H_