树莓派学习专题<14>:树莓派4B:从V4L2驱动直接获取h264码流

树莓派学习专题<14>:树莓派学习专题<14>:树莓派4B:从V4L2驱动直接获取h264码流

0. 项目代码

可以从下面获取到项目中的代码。
https://github.com/cdsmakc/h264_codec_base_rpi4b_rpi5_rv1106_visual_studio.git

1. 背景

之前的文章,记录了在树莓派4上,使用V4L2驱动获取YUV图像,然后通过x264编码。由于sensor本身并不能输出264码流,驱动本身也不负责编码,因此我一直以为从V4L2获取264码流是不可能的。但是在使用V4L2驱动罗列摄像头支持的数据格式时,却可以看到驱动能够输出264码流:

--Format descriptor --------------------------------------
-- 01. Planar YUV 4:2:0         (YU12)
-- 02. YUYV 4:2:2               (YUYV)
-- 03. 24-bit RGB 8-8-8         (RGB3)
-- 04. JFIF JPEG                (JPEG)
-- 05. H.264                    (H264)   --->此处
-- 06. Motion-JPEG              (MJPG)
-- 07. YVYU 4:2:2               (YVYU)
-- 08. VYUY 4:2:2               (VYUY)
-- 09. UYVY 4:2:2               (UYVY)
-- 10. Y/UV 4:2:0               (NV12)
-- 11. 24-bit BGR 8-8-8         (BGR3)
-- 12. Planar YVU 4:2:0         (YV12)
-- 13. Y/VU 4:2:0               (NV21)
-- 14. 32-bit XBGR 8-8-8-8      (RX24)
----------------------------------------------------------

也可以用V4L2-CTL工具查看输出支持的格式(注意:需要修改config.txt文件,参看之前的文章):

njl@raspberrypi:~ $ v4l2-ctl -d /dev/video0 --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
        Type: Video Capture

        [0]: 'YU12' (Planar YUV 4:2:0)
                Size: Stepwise 32x32 - 3280x2464 with step 2/2
        [1]: 'YUYV' (YUYV 4:2:2)
                Size: Stepwise 32x32 - 3280x2464 with step 2/2
        [2]: 'RGB3' (24-bit RGB 8-8-8)
                Size: Stepwise 32x32 - 3280x2464 with step 2/2
        [3]: 'JPEG' (JFIF JPEG, compressed)
                Size: Stepwise 32x32 - 3280x2464 with step 2/2
        [4]: 'H264' (H.264, compressed)
                Size: Stepwise 32x32 - 3280x2464 with step 2/2
        [5]: 'MJPG' (Motion-JPEG, compressed)
                Size: Stepwise 32x32 - 3280x2464 with step 2/2
        [6]: 'YVYU' (YVYU 4:2:2)
                Size: Stepwise 32x32 - 3280x2464 with step 2/2
        [7]: 'VYUY' (VYUY 4:2:2)
                Size: Stepwise 32x32 - 3280x2464 with step 2/2
        [8]: 'UYVY' (UYVY 4:2:2)
                Size: Stepwise 32x32 - 3280x2464 with step 2/2
        [9]: 'NV12' (Y/UV 4:2:0)
                Size: Stepwise 32x32 - 3280x2464 with step 2/2
        [10]: 'BGR3' (24-bit BGR 8-8-8)
                Size: Stepwise 32x32 - 3280x2464 with step 2/2
        [11]: 'YV12' (Planar YVU 4:2:0)
                Size: Stepwise 32x32 - 3280x2464 with step 2/2
        [12]: 'NV21' (Y/VU 4:2:0)
                Size: Stepwise 32x32 - 3280x2464 with step 2/2
        [13]: 'RX24' (32-bit XBGR 8-8-8-8)
                Size: Stepwise 32x32 - 3280x2464 with step 2/2

可以看到,摄像头即可以输出264码流也可以输出MJPEG码流。一上来没有注意到这点,后来看到树莓派论坛上的帖子才知道,树莓派官方已经将摄像头硬件设备、ISP和硬件编码器等做了封装,从而使得可以使用V4L2驱动从 /dev/video0 设备直接获取图像264码流。

2. 代码

使用V4L2获取摄像头的代码和之前的代码相同,只是输出格式需要改一下:

/* 设置输出格式 */
stFormat.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
stFormat.fmt.pix.width       = g_stRCEConfig.usWidth ;
stFormat.fmt.pix.height      = g_stRCEConfig.usHeight ;
stFormat.fmt.pix.pixelformat = (0 == g_stRCEConfig.uiHWEncoder) ? V4L2_PIX_FMT_YUV420 : V4L2_PIX_FMT_H264 ;

iRetVal = ioctl(g_stCAMWorkarea.iCameraFile, VIDIOC_S_FMT, &stFormat) ;

如果需要获取264码流,使用VIDIOC_S_FMT命令设置输出格式时,指定V4L2_PIX_FMT_H264即可。

此外,使用硬件编码时,树莓派4B可以输出到60fps;如果获取YUV420的图像,大约只能到47fps(只是获取图像,不考虑软编码的情况下)。另外,在默认情况下,硬件编码的264码流还是很大的,有时候接近10Mbps。这个也可以修改。这需要额外的命令来实现。

INT __RCE_CAM_SetRCParams(VOID)
{
    struct v4l2_ext_controls stExtCtrls ;
    struct v4l2_ext_control  stExtCtrl ;
    INT                      iRetVal ;

    memset(&stExtCtrls, 0, sizeof(stExtCtrls)) ;
    memset(&stExtCtrl, 0, sizeof(stExtCtrl)) ;

    stExtCtrl.id          = V4L2_CID_MPEG_VIDEO_BITRATE ;
    stExtCtrl.value       = g_stRCEConfig.uiHWBitrate ;
    stExtCtrl.size        = 0 ;
    stExtCtrls.controls   = &stExtCtrl ;
    stExtCtrls.count      = 1 ;
    stExtCtrls.ctrl_class = V4L2_CTRL_CLASS_MPEG ;

    iRetVal = ioctl(g_stCAMWorkarea.iCameraFile, VIDIOC_S_EXT_CTRLS, &stExtCtrls) ;

    if(-1 == iRetVal)
    {
        printf("File %s, func %s, line %d : ioctl VIDIOC_S_EXT_CTRLS error. ioctl : %s.\n", __FILE__, __func__, __LINE__, strerror(errno)) ;

        return -1 ;
    }

    return 0 ;
}

其中,g_stRCEConfig.uiHWBitrate即是码流目标值,以bps为单位。例如希望码流是3Mbps左右,则设置3000000。这个码流设置下去,也只是告知编码器按此目标工作,不代表输出就是这个码流。实际上,输出码流是变化的,只是均值尽量接近这个值而已。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值