简介
最近我在将自己的久笔记本放在家里做小型的远程监控,在网络传输视频时需要用到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下载中心。没有积分的可以留言联系我给你直接发过去。
源码下载链接