首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 嵌入开发 > 驱动开发 >

S3C6410的MFC H264编码初始参数的设置解决办法

2012-03-26 
S3C6410的MFC H264编码初始参数的设置有谁用过S3C6410的MFC H264编码吗?编码器初始化的时候会有MFC_ENC_IN

S3C6410的MFC H264编码初始参数的设置
有谁用过S3C6410的MFC H264编码吗?编码器初始化的时候会有MFC_ENC_INIT_ARG 结构体的初始化参数设置,里面的参数in_bitrate是根据Y420输入视频码率吗?还有gopnum参数呢?希望用过的能指导下。

[解决办法]
从摄像头实时采集图像到H264编码输出文件的 Demo
前端:包括视频采集模块和视频压缩编码模块。 
实现思路:
视频采集模块使用V4L2 接口收集摄像头数据到缓冲区中,视频压缩模块调用MFC 驱动把YUV420 数据压缩编码,同时可以指定编码参数。
*/
#include <fcntl.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <linux/fb.h>
#include "mfc.h"
#include "MfcDrvParams.h"
#include "performance.h"
#define DEV_NAME "/dev/video12"
 
int main(int argc, char *argv[])
{
/*----------------------
//CamIF and OV9650 Config
------------------------*/

//打开camera 设备
 int cam_fp = -1;
 if( (cam_fp = open(DEV_NAME, O_RDWR)) < 0 )
 {
printf("Open Device failed.\n");
return -1;
 }

//V4L2 编程 
struct v4l2_capability cap;
int tmp = -1;
 if((tmp=ioctl(cam_fp, VIDIOC_QUERYCAP, &cap))<0) {
printf("VIDIOC_QUERYCAP error, ret=0x%x\n",tmp);
return -1;
 }
//选择输入/输出 
struct v4l2_input i;
// 枚举所有的输入
//To enumerate all inputs
 memset(&i, 0, sizeof(i));//initialize i.index=0;
/* while(tmp=ioctl(cam_fp, VIDIOC_ENUMINPUT, &i)>=0)//ref V4L2.pdf for VIDIOC_ENUMINPUT
{
printf("input i.name:%s; i.index :%d i.type = %s\n",i.name, i.index, i.type);
i.index++;
}
*/
//究竟应该选哪一个呢?
int index = 0;
i.index = index;//选择index
 if(ioctl(cam_fp, VIDIOC_S_INPUT, &index)<0) //select the specified video input
{
printf("VIDIOC_S_INPUT ERROR\n");
return -1;

/*
To select a video input applications store the number of the desired input in an integer and call the
VIDIOC_S_INPUT ioctl with a pointer to this integer. 
Side effects are possible. For example inputs may support different video standards, 
so the driver may implicitly switch the current standard. 
It is a good practice to select an input before querying or negotiating any other parameters.
Information about video inputs is available using the VIDIOC_ENUMINPUT ioctl.
*/
 if(ioctl(cam_fp, VIDIOC_S_OUTPUT, &index)<0) //select the specified video output
{
printf("VIDIOC_S_OUTPUT ERROR\n");
return -1;
}
//VIDIOC_S_OUTPUT 中的S代表SET, VIDIOC_G_OUTPUT中的G 代表GET 

//设置格式,注意必须设置输出为YUV420 格式 
struct v4l2_framebuffer fb;
 
 ioctl(cam_fp, VIDIOC_G_FBUF, &fb); //VIDIOC_G_FBUF Get frame buffer overlay parameters
printf("fb.capability = %d\n",fb.capability);
printf("fb.fmt.width=%d\n",fb.fmt.width);
printf("fb.fmt.height = %d\n", fb.fmt.height);
printf("initial fb.fmt.pixelformat = %d\n", fb.fmt.pixelformat);
#if 1
static int cap_width,cap_height;
cap_width=640; //LCD 240*320
cap_height=480; //摄像头初始化支持的是VGA640*480
fb.capability = cap.capabilities; 
fb.fmt.width = cap_width; 
fb.fmt.height = cap_height; 
#endif
fb.fmt.pixelformat = V4L2_PIX_FMT_YUV420; 
 ioctl(cam_fp, VIDIOC_S_FBUF, &fb); //VIDIOC_S_FBUF— Set frame buffer overlay parameters
printf("cofig to YUV420:fb.fmt.pixelformat = %d\n", fb.fmt.pixelformat);


int on = 1; 
 if(ioctl(cam_fp, VIDIOC_OVERLAY, &on)< 0 ) //0 to stop, 1 to start.
{
printf("VIDIOC_OVERLAY ERROR\n");
return -1; 
}
 /*VIDIOC_OVERLAY is part of the video overlay I/O method. 
 Applications call VIDIOC_OVERLAY to start or stop the overlay. 
 It takes a pointer to an integer which must be set to zero by the application to stop
overlay, to one to start.*/
#if 0
 //open() .YUV file to be saved.
int fpyuv = open("./capyuv.yuv",O_RDWR|O_CREAT|O_TRUNC);
if(fpyuv<=0)
{
 printf("Open file error\n");
 return -1;
}
#endif
//END of CAMIF &OV9650 Config

/*----------------------
//config MFC H.264 encoder.
------------------------*/
#define FPS
#ifdef FPS
//printf("hello FPS\n");
struct timeval start, stop;
unsigned int time = 0;
int frame_cnt = 0;
#endif
 //变量定义区
  
int mfc_fd, outyuv_fd;
char *addr_mfc, *in_addr;
int cnt = 0;
int frame_count;
int frame_size;
char *in_buf_mfc, *out_buf_mfc;
  
// arguments of ioctl
MFC_ENC_INIT_ARG enc_init;
MFC_ENC_EXE_ARG enc_exe;
MFC_GET_BUF_ADDR_ARG get_buf_addr;
// Open output yuv file.
//argv[] is temperally not used in these version of program.
#define H264_FILE_NAME "./h264_cam2mfc.h264"
outyuv_fd = open(H264_FILE_NAME, O_RDWR | O_CREAT | O_TRUNC, 0644);
if( outyuv_fd < 0 ) 
{
printf("output File Open ERROR\n");
return -1;
}
 //打开MFC 设备
 mfc_fd = open(MFC_DEV_NAME, O_RDWR);///dev/s3c-mfc O_RDWR|O_NDELAY 
 if(mfc_fd<0)
{
printf("MFC open error : %d\n", mfc_fd);
return -1;
}
 //mmap MFC: mapping shared in/out buffer between App and D/D
 addr_mfc = (char *) mmap(0, 
BUF_SIZE, 
PROT_READ | PROT_WRITE,
MAP_SHARED,
mfc_fd,
0
);
 if (addr_mfc == NULL) {
printf("MFC mmap failed\n");
return -1;
 }
 
// set encoding arguments
#if 0
 enc_init.in_width = atoi(argv[3]);
 enc_init.in_height = atoi(argv[4]);
 enc_init.in_frameRateRes = atoi(argv[5]);
 enc_init.in_frameRateDiv = 0;
 enc_init.in_bitrate = atoi(argv[6]);
 enc_init.in_gopNum = atoi(argv[7]);
#else
 enc_init.in_width = cap_width;
 enc_init.in_height = cap_height;
 enc_init.in_frameRateRes = 24;
 enc_init.in_frameRateDiv = 0;
 enc_init.in_bitrate = 1000;
 enc_init.in_gopNum = 1;
#endif
// set encoding arguments 
ioctl(mfc_fd, IOCTL_MFC_H264_ENC_INIT, &enc_init); 
frame_size = (enc_init.in_width * enc_init.in_height * 3) >> 1;//YUV420 
//also frame_size = (fb.fmt.width * fb.fmt.height* 3 / 2);//YUV420
 
 //得到MFC 输入缓冲区地址 
 
 get_buf_addr.in_usr_data = (int)addr_mfc; 
 
ioctl(mfc_fd, IOCTL_MFC_GET_FRAM_BUF_ADDR, &get_buf_addr); 
 
in_buf_mfc = (char *)get_buf_addr.out_buf_addr; 
 
 //得到MFC 输出缓冲区地址 
 
 get_buf_addr.in_usr_data = (int)addr_mfc; 
 
ioctl(mfc_fd, IOCTL_MFC_GET_LINE_BUF_ADDR, &get_buf_addr); 
 
out_buf_mfc = (char *)get_buf_addr.out_buf_addr;
  
// mapping input file to memory
in_addr = (char *)mmap(0, frame_size, PROT_READ, MAP_SHARED, cam_fp, 0);
if(in_addr == NULL) {
printf("cam input memory mapping failed\n");


return -1;
}
//-------------------------
frame_count=200;//capture some frame.
long int enc_FBuf_size = frame_count * enc_init.in_bitrate * 20;
long int actual_FSize=0;
char *enc_fbuf = (char*)malloc(enc_FBuf_size);
int out_stream_cnt = 0;//count for encoded output stream bytes.
if(!enc_fbuf)

 printf("Malloc enc_fbuf failed.\n");
 return -1;
}
 
char *read_buf = malloc(frame_size);printf("read_buf = 0x%X\n",read_buf);
if(!read_buf)

 printf("malloc read_buf ERROR\n");
 return -1;
}
#ifdef FPS
gettimeofday(&start, NULL);//计算从采集到编码输出frame_count 帧所需的时间
#endif

#if 1
while(frame_count--) 

//把摄像头的输出直接设为MFC 的输入可以节省一次内存操作。 
#if 1
//read from camera to MFC
read(cam_fp,read_buf,frame_size);
memcpy(in_buf_mfc,read_buf,frame_size);//GOOD.but WHY?
#elif 0
 read(cam_fp,in_buf_mfc,frame_size);//NOT GOOD.
#else
 memcpy(in_buf_mfc, in_addr, frame_size);//GOOD. but WHY?
#endif
//printf("before encode ret code : %d\n", enc_exe.ret_code);
// encoding
ioctl(mfc_fd, IOCTL_MFC_H264_ENC_EXE, &enc_exe);
//printf("Header size = %d\n", enc_exe.out_header_size); 
  
//if(enc_exe.ret_code != 0) {
// printf("after encode ret code : %d\n", enc_exe.ret_code);
//}
printf("frame_cnt = %d\n",frame_cnt);
frame_cnt++;
memcpy(enc_fbuf+out_stream_cnt,out_buf_mfc,enc_exe.out_encoded_size);
out_stream_cnt += enc_exe.out_encoded_size;//
actual_FSize += enc_exe.out_encoded_size;
//write(outyuv_fd, out_buf_mfc, enc_exe.out_encoded_size);//

} //END of While
#else
while(frame_count--)
{
read(cam_fp,read_buf,frame_size);
printf("frame_cnt = %d\n",frame_cnt);
frame_cnt++;
}
#endif
#ifdef FPS
gettimeofday(&stop, NULL);
time = measureTime(&start, &stop);
#endif
#ifdef FPS
 printf("Processing Time : %u, Frame Count : %d, FPS : %f\n",
time, 
frame_cnt, 
(float)frame_cnt*1000/time);
#endif
//write all the encoded data from enc_fbuf to file.
//printf("out_stream_cnt=%d, actual_FSize = %d\n",out_stream_cnt,actual_FSize);
write(outyuv_fd, enc_fbuf, out_stream_cnt);//Only one write outside the while.
munmap(in_addr, frame_size);
munmap(addr_mfc, BUF_SIZE);
 free(read_buf);
 free(enc_fbuf);
 close(mfc_fd);
 close(outyuv_fd);
 printf("fb.fmt.width=%d\n",fb.fmt.width);
 printf("fb.fmt.height = %d\n", fb.fmt.height);
// printf("initial fb.fmt.pixelformat = %d\n", fb.fmt.pixelformat);
 
 return 0;
}/////////////////////////end of main.

热点排行