uvc camera yuv422 planer格式编码h264测试例程
/*
最简单的基于X264的视频编码器
Simplest X264 Encoder
jiangyu
本程序可以YUV格式的像素数据编码为H.264码流,是最简单的
基于libx264的视频编码器
This software encode YUV data to H.264 bitstream.
It's the simplest encoder example based on libx264.
*/
include <stdio.h>
include <stdlib.h>
include "stdint.h"
if defined ( __cplusplus)
extern "C"
{
include "x264.h"
};
else
include "x264.h"
endif
int width=640;
int height=480;
int csp=X264_CSP_I422;
// nv12 转 yuv 并写入本地
#if 0
void nv12toYuv(uint8_t NV12, uint8_t I420,size_t pixelWidth,size_t pixelHeight,const char resultCString,const char resultCString2){
unsigned char ybuf = (unsigned char )malloc(pixelHeight pixelWidth);
unsigned char ubuf = (unsigned char )malloc((pixelHeight/2) (pixelWidth/2));
unsigned char vbuf = (unsigned char )malloc((pixelHeight/2) (pixelWidth/2));
unsigned char y = ybuf;
unsigned char u = ubuf;
unsigned char v = vbuf;
int len = (int)pixelHeight pixelWidth + pixelHeight pixelWidth / 2;
FILE fpyuv = fopen(resultCString, "wb");
for (int i = 0; i < len; i ++) {
if (i < (pixelWidth pixelHeight)) { //yyyyy
y = NV12;
y++;
}
else{//uvuvuv
if (i % 2 == 0) {//uuuuu
u = NV12;
u ++;
}else{//vvvvv
v = NV12;
v ++;
}
}
NV12 ++;
}
fwrite(ybuf, 1, pixelWidthpixelHeight, fpyuv);
fwrite(ubuf, 1, pixelWidthpixelHeight/4, fpyuv);
fwrite(vbuf, 1, pixelWidth*pixelHeight/4, fpyuv);
fclose(fpyuv);
free(ybuf);
free(ubuf);
free(vbuf);
}
endif
//未用到
int yuv422toyuv420(unsigned char out, const unsigned char in, unsigned int width, unsigned int height)
{
unsigned char y = out;
unsigned char u = out + widthheight;
unsigned char v = out + widthheight + widthheight/4;
unsigned int i,j;
unsigned int base_h;
unsigned int is_y = 1, is_u = 1;
unsigned int y_index = 0, u_index = 0, v_index = 0;
unsigned long yuv422_length = 2 width height;
//序列为YU YV YU YV,一个yuv422帧的长度 width height 2 个字节
//丢弃偶数行 u v
for(i=0; i<yuv422_length; i+=2){
(y+y_index) = (in+i);
y_index++;
}
for(i=0; i<height; i+=2){
base_h = iwidth2;
for(j=base_h+1; j<base_h+width2; j+=2){
if(is_u){
(u+u_index) = (in+j);
u_index++;
is_u = 0;
}
else{
(v+v_index) = *(in+j);
v_index++;
is_u = 1;
}
}
}
return 1;
}
int main(int argc, char* argv)
{
int ret;
int y_size;
int i,j,ii,len;
char tmpbuf = NULL;
FILE fp_src = fopen("./640x480.yuv", "rb");
FILE fp_dst = fopen("output.h264", "wb");
//Encode frame number
//if set 0, encode all frame
int frame_num=0;
int index_y, index_u, index_v;
int num;
int iNal = 0;
x264_nal_t pNals = NULL;
x264_t pHandle = NULL;
x264_picture_t pPic_in = (x264_picture_t)malloc(sizeof(x264_picture_t));//编码之前进行填充
x264_picture_t pPic_out = (x264_picture_t)malloc(sizeof(x264_picture_t));
x264_param_t pParam = (x264_param_t)malloc(sizeof(x264_param_t));
tmpbuf = (char )malloc(widthheight2sizeof(char)+1);
if(!tmpbuf)
{
printf("malloc");
}
//Check
if(fp_src==NULL||fp_dst==NULL){
printf("Error open files.\n");
return -1;
}
x264_param_default(pParam); //给参数结构体赋默认值
x264_param_default_preset(pParam, "fast" , "zerolatency" ); //设置preset和tune
char y = pPic_in->img.plane[0];
char u = pPic_in->img.plane[1];
char v = pPic_in->img.plane[2];
//修改部分参数
pParam->i_csp=csp;
pParam->i_width = width; // 宽度
pParam->i_height = height; // 高度
pParam->i_fps_num = 25; // 设置帧率(分子)
pParam->i_fps_den = 1; // 设置帧率时间1s(分母)
pParam->i_threads = X264_SYNC_LOOKAHEAD_AUTO;
pParam->i_keyint_max = 10; //在此间隔设置IDR关键帧
pParam->rc.i_bitrate = 1200; // 设置码率,在ABR(平均码率)模式下才生效,且必须在设置ABR前先设置bitrate
pParam->rc.i_rc_method = X264_RC_ABR; // 码率控制方法,CQP(恒定质量),CRF(恒定码率,缺省值23),ABR(平均码率)
/
//Param
pParam->i_log_level = X264_LOG_DEBUG;
pParam->i_frame_total = 0;
pParam->i_bframe = 5;
pParam->b_open_gop = 0;
pParam->i_bframe_pyramid = 0;
pParam->rc.i_qp_constant=0;
pParam->rc.i_qp_max=0;
pParam->rc.i_qp_min=0;
pParam->i_bframe_adaptive = X264_B_ADAPT_TRELLIS;
pParam->i_timebase_den = pParam->i_fps_num;
pParam->i_timebase_num = pParam->i_fps_den;
/
//set profile x264_profile_names[] = { "baseline", "main", "high", "high10", "high422", "high444", 0 };
if(csp == X264_CSP_I420)
x264_param_apply_profile(pParam, "baseline");
else if(csp == X264_CSP_I422)
x264_param_apply_profile(pParam, "high422");
//open encoder
pHandle = x264_encoder_open(pParam);
if(csp == X264_CSP_NV12){
pPic_in->img.i_stride[0] = pParam->i_width;
pPic_in->img.i_stride[1] = pParam->i_width;
pPic_in->img.i_stride[2] = 0;
pPic_in->img.i_csp = X264_CSP_NV12;
pPic_in->img.i_plane = 2;
} else if(csp == X264_CSP_I422)
{
pPic_in->img.i_csp = X264_CSP_I422;
pPic_in->img.i_plane = 3;
}else { // 其他暂认为都是YUV420格式
pPic_in->img.i_stride[0] = pParam->i_width;
pPic_in->img.i_stride[1] = pParam->i_width>>1;
pPic_in->img.i_stride[2] = pParam->i_width>>1;
pPic_in->img.i_csp = X264_CSP_I420;
pPic_in->img.i_plane = 3;
}
x264_picture_init(pPic_out);
x264_picture_alloc(pPic_in, csp, pParam->i_width, pParam->i_height);
ret = x264_encoder_headers(pHandle, &pNals, &iNal);
y_size = pParam->i_width pParam->i_height;
//detect frame number
if(frame_num==0){
fseek(fp_src,0,SEEK_END);
switch(csp){
case X264_CSP_I444:frame_num=ftell(fp_src)/(y_size3);break;
case X264_CSP_I422:frame_num=ftell(fp_src)/(y_size2);break;
case X264_CSP_I420:frame_num=ftell(fp_src)/(y_size3/2);break;
case X264_CSP_NV12:frame_num=ftell(fp_src)/(y_size3/2);break;
default:printf("Colorspace Not Support.\n");return -1;
}
fseek(fp_src,0,SEEK_SET);
}
printf("franme count :%d \n",frame_num);
//Loop to Encode
for( i=0;i<frame_num;i++){
switch(csp){
case X264_CSP_I420:{
fread(pPic_in->img.plane[0],y_size,1,fp_src); //Y
fread(pPic_in->img.plane[1],y_size/4,1,fp_src); //U
fread(pPic_in->img.plane[2],y_size/4,1,fp_src); //V
break;}
case X264_CSP_NV12:
printf("nv12 enc y\n");
fread(pPic_in->img.plane[0],y_size,1,fp_src); //Y
fread(pPic_in->img.plane[1],y_size/2,1,fp_src); //uv
printf("nv12 enc uv end\n");
break;
case X264_CSP_I422:
printf("i422 enc yuv start\n");
index_y = 0;
index_u = 0;
index_v = 0;
len =fread(tmpbuf,y_size2,1,fp_src);
printf("read len:%d %x %x\n",len,tmpbuf[0],tmpbuf[y_size2]);
num = width height 2 - 4 ;
for(ii=0; ii<num; ii=ii+4)
{
(pPic_in->img.plane[0]+index_y++) = tmpbuf[ii];
(pPic_in->img.plane[1] +index_u++) = tmpbuf[ii + 1];
(pPic_in->img.plane[0] +index_y++) = tmpbuf[ii + 2];
(pPic_in->img.plane[2] +index_v++) = tmpbuf[ii + 3];
}
break;
default:{
printf("Colorspace Not Support.\n");
return -1;}
}
pPic_in->i_pts = i;
ret = x264_encoder_encode(pHandle, &pNals, &iNal, pPic_in, pPic_out);
if (ret< 0){
printf("Error.\n");
return -1;
}
printf("Succeed encode frame: %5d\n",i);
for ( j = 0; j < iNal; ++j){
fwrite(pNals[j].p_payload, 1, pNals[j].i_payload, fp_dst);
}
}
i=0;
//flush encoder
/ while(1){
ret = x264_encoder_encode(pHandle, &pNals, &iNal, NULL, pPic_out);
if(ret==0){
break;
}
printf("Flush 1 frame.\n");
for (j = 0; j < iNal; ++j){
fwrite(pNals[j].p_payload, 1, pNals[j].i_payload, fp_dst);
}
i++;
}/
x264_picture_clean(pPic_in);
x264_encoder_close(pHandle);
pHandle = NULL;
free(pPic_in);
free(pPic_out);
free(pParam);
free(tmpbuf);
fclose(fp_src);
fclose(fp_dst);
return 0;
}
makefile
##### Make sure all is the first target.
all:
CXX ?= g++
CC ?= gcc
CFLAGS += -g -pthread -Wall
CFLAGS += -rdynamic -funwind-tables
CFLAGS += -I${SDKTARGETSYSROOT}/usr/include/linux-headers/usr/include
CFLAGS += -I./inc
CFLAGS += -I./usr/include
CFLAGS += -D__unused="__attribute__((__unused__))"
#LDFLAGS += -L./usr/lib/gpac
LDFLAGS += -lx264 -ldl
LDFLAGS += -L./usr/lib/
C_SRC=
C_SRC+=src/main.c
C_SRC+=src/osp.c
C_SRC+=src/osp_common.c
C_SRC+=src/osp_proc_data.c
C_SRC+=src/osp_syslog.c
C_SRC+=src/osp_timer.c
CXX_SRC=
OBJ=
DEP=
#LDFLAGS+= -lcamera
OBJ_CAM_SRV = src/main.o
TARGETS += camera-rtp-service
$(TARGETS): $(OBJ_CAM_SRV)
TARGET_OBJ += $(OBJ_CAM_SRV)
FILE_LIST := files.txt
COUNT := ./make/count.sh
MK := $(word 1,$(MAKEFILE_LIST))
ME := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
OBJ=$(CXX_SRC:.cpp=.o) $(C_SRC:.c=.o)
DEP=$(OBJ:.o=.d) $(TARGET_OBJ:.o=.d)
CXXFLAGS += -std=c++11 $(CFLAGS)
#include ./common.mk
.PHONY: all clean distclean
all: $(TARGETS)
clean:
rm -f $(TARGETS) $(FILE_LIST)
find . -name "*.o" -delete
find . -name "*.d" -delete
distclean:
rm -f $(TARGETS) $(FILE_LIST)
find . -name "*.o" -delete
find . -name "*.d" -delete
-include $(DEP)
%.o: %.c $(MK) $(ME)
@[ -f $(COUNT) ] && $(COUNT) $(FILE_LIST) $^ || true
@$(CC) -c $< -MM -MT $@ -MF $(@:.o=.d) $(CFLAGS) $(LIBQCAM_CFLAGS)
$(CC) -c $< $(CFLAGS) -o $@ $(LIBQCAM_CFLAGS)
%.o: %.cpp $(MK) $(ME)
@[ -f $(COUNT) ] && $(COUNT) $(FILE_LIST) $^ || true
@$(CXX) -c $< -MM -MT $@ -MF $(@:.o=.d) $(CXXFLAGS)
$(CXX) -c $< $(CXXFLAGS) -o $@
$(TARGETS): $(OBJ)
$(CXX) -o $@ $^ $(CXXFLAGS) $(LDFLAGS)
@[ -f $(COUNT) -a -n "$(FILES)" ] && $(COUNT) $(FILE_LIST) $(FILES) || true
@[ -f $(COUNT) ] && $(COUNT) $(FILE_LIST) || true
使用说明
本例程是基于uvc摄像头输出格式为yuv422 格式的并非 yuv2,所以3个planer.make file 中需要制定Linux的sdk路径。