上一篇写的是保存摄像头数据为YUYV格式的文件链接:http://blog.csdn.net/u011186256/article/details/79289989
本篇文件介绍 FFMPEG 编码YUYV 数据 为H264
1、Ubuntu安装x264与FFmpeg
root权限运行
./configure --enable-shared --disable-asm
下载last_stable_x264.tar.bz2
tar xzvf last_stable_x264.tar.bz2
make
make install
下载ffmpeg-2.8.6.tar.bz2
tar -jxvf ffmpeg-2.8.6.tar.bz2
./configure --enable-shared --disable-yasm --enable-libx264 --enable-gpl --prefix=/usr/local/
//--enable-shared // 编译共享库
//--disable-yasm //不使用yasm ,默认使用yasm配置会很麻烦,需要下载yasm
//--enable-libx264 //依赖x264
//--prefix=/usr/local //编译完成后输出我们要用的文件路径
make
make install
这样你安装好的相关库在/usr/local/lib 下了
相关包下载地址:http://download.csdn.net/download/u011186256/10246003
注意安装顺序与安装ffmpeg选择enable-libx264否则在ffmpeg编解码程序运行报错Cannot load libcuda.so.1
另外如果avcodec_open2返回错误代码-22说明你的编码器设置参数不对
代码参考http://blog.csdn.net/li_wen01/article/details/63264548
#include
#define __STDC_CONSTANT_MACROS
#include "libavutil/opt.h"
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
// #define ENCODE_YUV
#ifdef ENCODE_YUV
#define INPUT_FILE "mytest.yuv"
#define INPUT_WIDTH 640
#define INPUT_HEIGHT 480
#else
#define INPUT_FILE "mytest.yuyv"
#define INPUT_WIDTH 640
#define INPUT_HEIGHT 480
#endif
#define OUTPUT_FILE "ds.h264"
#define FRAMENUM 300
int flush_encoder(AVFormatContext *fmt_ctx,unsigned int stream_index){
int ret;
int got_frame;
AVPacket enc_pkt;
if (!(fmt_ctx->streams[stream_index]->codec->codec->capabilities &
CODEC_CAP_DELAY))
return 0;
while (1) {
enc_pkt.data = NULL;
enc_pkt.size = 0;
av_init_packet(&enc_pkt);
ret = avcodec_encode_video2 (fmt_ctx->streams[stream_index]->codec, &enc_pkt,
NULL, &got_frame);
av_frame_free(NULL);
if (ret < 0)
break;
if (!got_frame){
ret=0;
break;
}
printf("Flush Encoder: Succeed to encode 1 frame!\tsize:%5d\n",enc_pkt.size);
/* mux encoded frame */
ret = av_write_frame(fmt_ctx, &enc_pkt);
if (ret < 0)
break;
}
return ret;
}
int main(int argc, char* argv[])
{
AVFormatContext* pFormatCtx;
AVOutputFormat* fmt;
AVStream* video_st;
AVCodecContext* pCodecCtx;
AVCodec* pCodec;
AVPacket pkt;
uint8_t* picture_buf;
AVFrame* pFrame;
int picture_size;
int y_size;
int framecnt=0;
FILE *in_file ; //Input raw YUV data
int in_w=INPUT_WIDTH, in_h=INPUT_HEIGHT; //Input data's width and height
int framenum=FRAMENUM; //Frames to encode
const char* out_file = OUTPUT_FILE;
int i,j,k;
int num;
int index_y, index_u, index_v;
uint8_t *y_, *u_, *v_, *in;
int got_picture =0;
int ret;
#ifdef ENCODE_YUV
printf("ENCODE_YUV is open 111111111111111111111\n");
#else
printf("ENCODE_YUV is close 111111111111111111111\n");
#endif
printf("INPUT_FILE:%s\n",INPUT_FILE);
in_file = fopen(INPUT_FILE, "rb"); //Input raw YUV data
av_register_all();
//Method1.
pFormatCtx = avformat_alloc_context();
//Guess Format
fmt = av_guess_format(NULL, out_file, NULL);
pFormatCtx->oformat = fmt;
//Method 2.
/* 初始化输出码流的AVFormatContext */
//avformat_alloc_output_context2(&pFormatCtx, NULL, NULL, out_file);
//fmt = pFormatCtx->oformat;
//Open output URL
if (avio_open(&pFormatCtx->pb,out_file, AVIO_FLAG_READ_WRITE) < 0){
printf("Failed to open output file! \n");
return -1;
}
/* 创建输出码流的AVStream */
video_st = avformat_new_stream(pFormatCtx, 0);
//video_st->time_base.num = 1;
//video_st->time_base.den = 25;
if (video_st==NULL){
return -1;
}
//Param that must set
pCodecCtx = video_st->codec;
//pCodecCtx->codec_id =AV_CODEC_ID_HEVC;
pCodecCtx->codec_id = fmt->video_codec;
pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
#ifdef ENCODE_YUV
pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
#else
pCodecCtx->pix_fmt = AV_PIX_FMT_YUV422P;
#endif
pCodecCtx->width = in_w;
pCodecCtx->height = in_h;
pCodecCtx->bit_rate = 2000000;
pCodecCtx->gop_size=10;
pCodecCtx->time_base.num = 1;
pCodecCtx->time_base.den = 25;
//H264
pCodecCtx->me_range = 16;
pCodecCtx->max_qdiff = 4;
pCodecCtx->qcompress = 0.6;
pCodecCtx->qmin = 10;
pCodecCtx->qmax = 51;
//Optional Param
pCodecCtx->max_b_frames=3;
// Set Option
AVDictionary *param = 0;
//H.264
if(pCodecCtx->codec_id == AV_CODEC_ID_H264) {
av_dict_set(¶m, "preset", "slow", 0);
/* 这个可以让libav不缓存视频帧 */
av_dict_set(¶m, "tune", "zerolatency", 0);
// av_dict_set(¶m, "profile", "main", 0);
}
//Show some Information
av_dump_format(pFormatCtx, 0, out_file, 1);
/* 查找编码器 */
pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
if (!pCodec){
printf("Can not find encoder! \n");
return -1;
}
int rett = -1;
/* 打开编码器 */
if ((rett = avcodec_open2(pCodecCtx, pCodec,¶m)) < 0){
printf("Failed to open encoder!rett:%d \n",rett);
return -1;
}
pFrame = av_frame_alloc();
picture_size = avpicture_get_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
picture_buf = (uint8_t *)av_malloc(picture_size);
#ifdef ENCODE_YUV
avpicture_fill((AVPicture *)pFrame, picture_buf, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
#else
pFrame->format = pCodecCtx->pix_fmt;
pFrame->width = pCodecCtx->width;
pFrame->height = pCodecCtx->height;
av_image_alloc(pFrame->data, pFrame->linesize, pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, 32);
#endif
//Write File Header
/* 写文件头(对于某些没有文件头的封装格式,不需要此函数。比如说MPEG2TS) */
avformat_write_header(pFormatCtx,NULL);
/* Allocate the payload of a packet and initialize its fields with default values. */
av_new_packet(&pkt,picture_size);
y_size = pCodecCtx->width * pCodecCtx->height;
for (j=0; j< framenum; j++){
//Read raw YUV data
#ifdef ENCODE_YUV
if (fread(picture_buf, 1, y_size*3/2, in_file) <= 0){
#else
if (fread(picture_buf, 1, y_size*2, in_file) <= 0){
#endif
printf("Failed to read raw data! \n");
return -1;
}else if(feof(in_file)){
break;
}
#ifdef ENCODE_YUV
pFrame->data[0] = picture_buf; // Y
pFrame->data[1] = picture_buf + y_size; // U
pFrame->data[2] = picture_buf + y_size*5/4; // V
#else
num = y_size * 2 - 4;
index_y = 0;
index_u = 0;
index_v = 0;
y_ = pFrame->data[0];
u_ = pFrame->data[1];
v_ = pFrame->data[2];
in = picture_buf;
for(i = 0; i < num; i = i+4)
{
*(y_ + (index_y++)) = *(in + i);
*(u_ + (index_u++)) = *(in + i + 1);
*(y_ + (index_y++)) = *(in + i + 2);
*(v_ + (index_v++)) = *(in + i + 3);
}
#endif
//PTS
//pFrame->pts=i;
pFrame->pts=j*(video_st->time_base.den)/((video_st->time_base.num)*25);
//Encode
/* 编码一帧视频。即将AVFrame(存储YUV像素数据)编码为AVPacket(存储H.264等格式的码流数据) */
int ret = avcodec_encode_video2(pCodecCtx, &pkt,pFrame, &got_picture);
if(ret < 0){
printf("Failed to encode! \n");
return -1;
}
if (got_picture==1){
//printf("Succeed to encode frame: %5d\tsize:%5d\n",framecnt,pkt.size);
framecnt++;
pkt.stream_index = video_st->index;
/* 将编码后的视频码流写入文件 */
ret = av_write_frame(pFormatCtx, &pkt);
av_free_packet(&pkt);
}
}
//Flush Encoder
/* 输入的像素数据读取完成后调用此函数。用于输出编码器中剩余的AVPacket */
ret = flush_encoder(pFormatCtx,0);
if (ret < 0) {
printf("Flushing encoder failed\n");
return -1;
}
//Write file trailer
/* 写文件尾(对于某些没有文件头的封装格式,不需要此函数。比如说MPEG2TS) */
av_write_trailer(pFormatCtx);
//Clean
if (video_st){
avcodec_close(video_st->codec);
av_free(pFrame);
av_free(picture_buf);
}
avio_close(pFormatCtx->pb);
avformat_free_context(pFormatCtx);
fclose(in_file);
printf("close\n");
return 0;
}