/* * Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of NVIDIA CORPORATION nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "NvVideoEncoder.h" #include "NvLogging.h" #include #include #include #define ENCODER_DEV "/dev/nvhost-msenc" #define ENCODER_COMP_NAME "NVENC" #define CHECK_V4L2_RETURN(ret, str) \ if (ret < 0) { \ COMP_SYS_ERROR_MSG(str << ": failed"); \ return -1; \ } else { \ COMP_DEBUG_MSG(str << ": success"); \ return 0; \ } #define RETURN_ERROR_IF_FORMATS_SET() \ if (output_plane_pixfmt != 0 || capture_plane_pixfmt != 0) { \ COMP_ERROR_MSG("Should be called before setting plane formats") \ return -1; \ } #define RETURN_ERROR_IF_BUFFERS_REQUESTED() \ if (output_plane.getNumBuffers() != 0 && capture_plane.getNumBuffers() != 0) { \ COMP_ERROR_MSG("Should be called before requesting buffers on either plane") \ return -1; \ } #define RETURN_ERROR_IF_BUFFERS_NOT_REQUESTED() \ if (output_plane.getNumBuffers() == 0 || capture_plane.getNumBuffers() == 0) { \ COMP_ERROR_MSG("Should be called before requesting buffers on either plane") \ return -1; \ } #define RETURN_ERROR_IF_FORMATS_NOT_SET() \ if (output_plane_pixfmt == 0 || capture_plane_pixfmt == 0) { \ COMP_ERROR_MSG("Should be called after setting plane formats") \ return -1; \ } using namespace std; NvVideoEncoder::NvVideoEncoder(const char *name, int flags) :NvV4l2Element(name, ENCODER_DEV, flags, valid_fields) { } NvVideoEncoder * NvVideoEncoder::createVideoEncoder(const char *name, int flags) { NvVideoEncoder *enc = new NvVideoEncoder(name, flags); if (enc->isInError()) { delete enc; return NULL; } return enc; } NvVideoEncoder::~NvVideoEncoder() { } int NvVideoEncoder::setOutputPlaneFormat(uint32_t pixfmt, uint32_t width, uint32_t height) { struct v4l2_format format; uint32_t num_bufferplanes; NvBuffer::NvBufferPlaneFormat planefmts[MAX_PLANES]; if (pixfmt != V4L2_PIX_FMT_YUV420M && pixfmt != V4L2_PIX_FMT_P010M && pixfmt != V4L2_PIX_FMT_NV12M && pixfmt != V4L2_PIX_FMT_NV24M && pixfmt != V4L2_PIX_FMT_NV24_10LE && pixfmt != V4L2_PIX_FMT_YUV444M) { COMP_ERROR_MSG("Only YUV420M, NV24, NV24_10LE, YUV444, P010M and NV12M are supported"); return -1; } output_plane_pixfmt = pixfmt; NvBuffer::fill_buffer_plane_format(&num_bufferplanes, planefmts, width, height, pixfmt); output_plane.setBufferPlaneFormat(num_bufferplanes, planefmts); memset(&format, 0, sizeof(struct v4l2_format)); format.type = output_plane.getBufType(); format.fmt.pix_mp.width = width; format.fmt.pix_mp.height = height; format.fmt.pix_mp.pixelformat = pixfmt; format.fmt.pix_mp.num_planes = num_bufferplanes; return output_plane.setFormat(format); } int NvVideoEncoder::setCapturePlaneFormat(uint32_t pixfmt, uint32_t width, uint32_t height, uint32_t sizeimage) { struct v4l2_format format; memset(&format, 0, sizeof(struct v4l2_format)); format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; switch (pixfmt) { case V4L2_PIX_FMT_H264: case V4L2_PIX_FMT_H265: case V4L2_PIX_FMT_VP8: case V4L2_PIX_FMT_VP9: case V4L2_PIX_FMT_AV1: capture_plane_pixfmt = pixfmt; break; default: ERROR_MSG("Unknown supported pixel format for encoder " << pixfmt); return -1; } format.fmt.pix_mp.pixelformat = pixfmt; format.fmt.pix_mp.width = width; format.fmt.pix_mp.height = height; format.fmt.pix_mp.num_planes = 1; format.fmt.pix_mp.plane_fmt[0].sizeimage = sizeimage; return capture_plane.setFormat(format); } int NvVideoEncoder::setFrameRate(uint32_t framerate_num, uint32_t framerate_den) { struct v4l2_streamparm parms; RETURN_ERROR_IF_FORMATS_NOT_SET(); memset(&parms, 0, sizeof(parms)); parms.parm.output.timeperframe.numerator = framerate_den; parms.parm.output.timeperframe.denominator = framerate_num; CHECK_V4L2_RETURN(output_plane.setStreamParms(parms), "Setting framerate to " << framerate_num << "/" << framerate_den); } int NvVideoEncoder::setBitrate(uint32_t bitrate) { struct v4l2_ext_control control; struct v4l2_ext_controls ctrls; cout << capture_plane_pixfmt <