简介

最近我在将自己的久笔记本放在家里做小型的远程监控,在网络传输视频时需要用到h264码流。然而我对h264只能说知道只知道它是一个视频编码格式,仅此而已。然后某度一下之后发现有开源的库可以直接使用。libx264就这样被我发现了。在其他博客中混迹了一段时间后发现,网上基本上是没有说使用libx264 将rgb24 数据格式转 h264的。基本上都是讲yuv420转的,说什么libx264只支持yuv420格式作为输入源,在这个我不想吐槽太多了。这篇博文主要是讲述如会将摄像头捕获回来的个图像数据转换为h264码流并保存到本地。然后可以用vlc查看。
当时我是看雷神的这篇博客踏入这神圣的殿堂的
雷霄骅 基于libx264(编码YUV为H.264)

本文框架

  • opencv 采集图像
  • libx264编码
  • vlc效果演示

opencv 采集图像

opencv 相信很多博友都应该知道。现在都可以说是烂大街了。现在我就直接使用它来作为我们采集图像的工具(可能有点大材小用了)。

// bolgLibx264.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <opencv/cv.h>
#include <opencv/highgui.h>
using namespace std;
using namespace cv;

#define WIDTH 640
#define HEIGHT 480

void testVideoCapture(void)
{
    VideoCapture cap(0);
    Mat frame;
    if (cap.isOpened() == false)
        cout << "can't not capture an usb camera from your computer!!!" << endl;
    while (true)
    {
        cap >> frame;
        if (frame.empty())
            continue;
        resize(frame, frame, Size(WIDTH, HEIGHT));
        imshow("frame", frame);
        waitKey(1);
    }
}
int _tmain(int argc, _TCHAR* argv[])
{
    testVideoCapture();
    return 0;
}

这里给出的代码片段只是简单的使用opencv 采集pc机中默认摄像头并显示图像,代码中的resize是缩放函数,我这里是将图像分辨率规定为640*480了。下面的是上边代码片段的运行效果:这里写图片描述


libx264编码

在上面的采集的基础上添加编码程序,至于怎么添加libx264 可以参考【雷霄骅博客】在简介中我已经给出了。我这里就不废话了。直接上代码。

// bolgLibx264.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <opencv/cv.h>
#include <opencv/highgui.h>

#if defined ( __cplusplus)
extern "C"
{
#include <stdint.h>
#include "x264.h"
};
#else
#include "x264.h"
#endif

using namespace std;
using namespace cv;

#define WIDTH 640
#define HEIGHT 480
#define VENC_FPS 30

typedef struct __X264_ENCODER__
{

    x264_t* m_pX264Handle;
    x264_param_t* m_pX264Param;

    x264_picture_t* m_pX264Pic_out;
    x264_picture_t* m_pX264Pic_in;
    x264_nal_t* m_pX264Nals;
    int m_x264iNal;
    FILE *m_x264Fp;
}X264Encoder;

void initX264Encoder(X264Encoder &x264Encoder,char *filePath)
{
    x264Encoder.m_x264Fp = fopen(filePath, "wb");
    x264Encoder.m_pX264Param = (x264_param_t *)malloc(sizeof(x264_param_t));
    assert(x264Encoder.m_pX264Param);
    x264_param_default(x264Encoder.m_pX264Param);
    x264_param_default_preset(x264Encoder.m_pX264Param, "veryfast", "zerolatency");
    x264_param_apply_profile(x264Encoder.m_pX264Param, "baseline");
    x264Encoder.m_pX264Param->i_threads = X264_THREADS_AUTO;//X264_SYNC_LOOKAHEAD_AUTO; // 取空缓冲区继续使用不死锁的保证

    // 视频选项
    x264Encoder.m_pX264Param->i_width = WIDTH; // 要编码的图像宽度.
    x264Encoder.m_pX264Param->i_height = HEIGHT; // 要编码的图像高度

    // 帧率
    x264Encoder.m_pX264Param->b_vfr_input = 0;//0时只使用fps控制帧率
    int m_frameRate = VENC_FPS;
    x264Encoder.m_pX264Param->i_fps_num = m_frameRate; // 帧率分子
    x264Encoder.m_pX264Param->i_fps_den = 1; // 帧率分母
    x264Encoder.m_pX264Param->i_timebase_den = x264Encoder.m_pX264Param->i_fps_num;
    x264Encoder.m_pX264Param->i_timebase_num = x264Encoder.m_pX264Param->i_fps_den;
    x264Encoder.m_pX264Param->b_intra_refresh = 0;
    x264Encoder.m_pX264Param->b_annexb = 1;
    //m_pX264Param->b_repeat_headers = 0;
    x264Encoder.m_pX264Param->i_keyint_max = m_frameRate;

    x264Encoder.m_pX264Param->i_csp = X264_CSP_BGR;//X264_CSP_I420;// 
    x264Encoder.m_pX264Param->i_log_level = X264_LOG_INFO;//X264_LOG_DEBUG;

    x264Encoder.m_x264iNal = 0;
    x264Encoder.m_pX264Nals = NULL;
    x264Encoder.m_pX264Pic_in = (x264_picture_t *)malloc(sizeof(x264_picture_t));
    if (x264Encoder.m_pX264Pic_in == NULL)
        exit(1);
    else
        memset(x264Encoder.m_pX264Pic_in, 0, sizeof(x264_picture_t));
    //x264_picture_alloc(m_pX264Pic_in, X264_CSP_I420, m_pX264Param->i_width, m_pX264Param->i_height);
    x264_picture_alloc(x264Encoder.m_pX264Pic_in, X264_CSP_BGR, x264Encoder.m_pX264Param->i_width, x264Encoder.m_pX264Param->i_height);
    x264Encoder.m_pX264Pic_in->i_type = X264_TYPE_AUTO;

    x264Encoder.m_pX264Pic_out = (x264_picture_t *)malloc(sizeof(x264_picture_t));
    if (x264Encoder.m_pX264Pic_out == NULL)
        exit(1);
    else
        memset(x264Encoder.m_pX264Pic_out, 0, sizeof(x264_picture_t));
    x264_picture_init(x264Encoder.m_pX264Pic_out);
    x264Encoder.m_pX264Handle = x264_encoder_open(x264Encoder.m_pX264Param);
    assert(x264Encoder.m_pX264Handle);
}

void convertFrameToX264Img(x264_image_t *x264InImg,Mat &frame)
{
    //RGB方式
    int srcSize = frame.rows*frame.cols;
    x264InImg->plane[0] = frame.data;
    x264InImg->plane[1] = frame.data + srcSize;
    x264InImg->plane[2] = frame.data + srcSize;
}

void encoderImg(X264Encoder &x264Encoder,Mat &frame)
{
    //转换图像格式
    convertFrameToX264Img(&x264Encoder.m_pX264Pic_in->img,frame);


    x264Encoder.m_pX264Pic_in->i_pts++;
    int ret = x264_encoder_encode(x264Encoder.m_pX264Handle, &x264Encoder.m_pX264Nals, &x264Encoder.m_x264iNal, x264Encoder.m_pX264Pic_in, x264Encoder.m_pX264Pic_out);
    if (ret< 0){
        printf("Error.\n");
        return;
    }

    for (int i = 0; i < x264Encoder.m_x264iNal; ++i)
    {
        fwrite(x264Encoder.m_pX264Nals[i].p_payload, 1, x264Encoder.m_pX264Nals[i].i_payload, x264Encoder.m_x264Fp);
    }
}

void testVideoEncoder(void)
{
    X264Encoder x264Encoder;
    initX264Encoder(x264Encoder,"myCamera.h264");

    VideoCapture cap(0);
    Mat frame;
    if (cap.isOpened() == false)
        cout << "can't not capture an usb camera from your computer!!!" << endl;
    while (true)
    {
        cap >> frame;
        if (frame.empty())
            continue;
        resize(frame, frame, Size(WIDTH, HEIGHT));
        encoderImg(x264Encoder, frame);
        imshow("frame", frame);
        waitKey(30);
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    testVideoEncoder();
    return 0;
}

vlc演示

将代码产生的myCamera.h264 用vlc播放器打开即可播放
这里写图片描述

注:整个工程稍后上传至csdn下载中心。没有积分的可以留言联系我给你直接发过去。
源码下载链接

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐