实现 V4L2视频采集与 FFMPEG 编码YUYV 数据 为H264(2)

上一篇写的是保存摄像头数据为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 <stdio.h>  
    #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;  
    }  



  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值