ffmpeg摄像头数据H264编码

yuyv(yuv422): 一行里的两个像素结合, 一个像素有(y, u), 另一个像素有(y, v). 还原rgb时两像素的数据需结合来使用.yuv420: 每两行的上下两个像素结合, 一行的两个像素只存(y, u, y), 下一行的两个像素只存(y, v, y)./////////////////////////////////////yuv444: y00u00v00 y01u01v01 y02u02v02 y03u03v03 y04u04v04 y05u05v05 y06u06v06 y07u07v07... y56u56v56 y57u57v57 y58u58v58 y59u59v59 y60u60v60 y61u61v61 y62u62v62 y63u63v63yuv444->yuv420: y00u00 y01 y02u02 y03 | y04u04 y05 y06u06 y07 y56v56 y57 y58v58 y59 | y60v60 y61 y62v62 y63yuv420->yuv444: y00u00v56 y01u00v56 y02u02v58 y03u02v58 .... y56u00v56 y57u00v56 y58u02v58 y59u02v58 ...像素数通常分成:打包(packed)格式和平面(planar)格式packed: 就是一个像素的YUV数据存放完后接着存放另一个像素的YUV数据 上面的yuv数据就是打包的.planar: 就是每个像素的yuv数据分成三个地方存放, y专存一个地方, u.., v... // 三个地方可以是三个不同的数组, 也可以是同一数组里的不同的位置 "yuv420p" 后面的p表示planar////////////////////////////////////////////yuv422 --> yuv420p yuv422: y00u00 y01v01 y02u02 y03v03 y04u04 y05v05 y06u06 y07v07 ... y56u56 y57v57 y58u58 y59v59 y60u60 y61v61 y62u62 y63v63 ... yuv420: y00u00 y01 y02u02 y03 | y04u04 y05 y06u06 y07 y56v57 y57 y58v59 y59 | y60v61 y61 y62v63 y63 yuv420p: y00 y01 y02 y03 y04 y05 y06 y07 ... y56 y57 y58 y59 y60 y61 y62 y63 u00 u02 u04 u06 ... v57 v59 v61 v63 ...////////////////////////////////转换函数:int yuv422_2_yuv420p(unsigned char *yuv422, unsigned char *y, unsigned char *u, unsigned char *v, int w, int h){ int i, j; unsigned char *yuv = yuv422; for (i = 0; i < h; i += 2) { for (j = 0; j < w; j += 2) // 第一行: y u y { *y++ = yuv[0]; // y0 *u++ = yuv[1]; // u0 *y++ = yuv[2]; // y1 //yuv[3]; // v1 yuv += 4; } for (j = 0; j < w; j += 2) // 第二行: y v y { *y++ = yuv[0]; //y0 // yuv[1] ; // u0 *y++ = yuv[2]; // y1 *v++ = yuv[3]; // v1 yuv += 4; } } return (w*h*3)>>1; //yuv420里每个像素占用1.5字节}//////////////yuv420p数据编码过程///////ffmpeg编码库只支持yuv420p的数据编码成视频格式#define __STDC_CONSTANT_MACROSextern "C" { #include <libavformat/avformat.h> #include <libavutil/opt.h> #include <libavcodec/avcodec.h> #include <libavutil/imgutils.h>};//初始化编解码,文件格式等库1. av_register_all();2. //找到想用的编码器 AVCodec *pCodec = avcodec_find_encoder(AV_CODEC_ID_H264); //AV_CODEC_ID_H2653. //分配一个描述编码器的配置信息对象 AVCodecContext *pCodecCtx = avcodec_alloc_context3(pCodec); //初始化编码的配置    pCodecCtx->bit_rate = 400000; //400K比特传输率/秒 pCodecCtx->width = 图像的宽度; pCodecCtx->height = 图像的高度; pCodecCtx->time_base.num=1; pCodecCtx->time_base.den=25;  // 1秒钟25帧图像 pCodecCtx->gop_size = 10; //多少帧图像里有一张关键帧 pCodecCtx->max_b_frames = 1; pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P; //数据的格式4. //根据指定的参数,打开编码器 avcodec_open2(pCodecCtx, pCodec, NULL) < 0)5. //准备一帧要编码前的图像数据的空间    AVFrame *pFrame = av_frame_alloc(); pFrame->format = pCodecCtx->pix_fmt; pFrame->width = pCodecCtx->width; pFrame->height = pCodecCtx->height; //再准备好存放yuv420p的数据缓冲区 av_image_alloc(pFrame->data, pFrame->linesize, pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, 16); 注意,yuv420p是平面 pFrame->data[0]装y数据 , pFrame->data[1]装u数据, pFrame->data[2]装v数据6. //编码: AVPacket pkt ; //用于存放编码后的数据 for (;;) { av_init_packet(&pkt); pkt.data = NULL; // packet data will be allocated by the encoder pkt.size = 0; //把yuv420p的数据放入pFrame->data[]数组里 pFrame->pts = i; //记录当前是第几帧的数据 ret = avcodec_encode_video2(pCodecCtx, &pkt, pFrame, &got_output); //编码 if (got_output) //一帧图像已编码完成, 需要输出保存 { pkt.data里存放已编码好的数据, pkt.size记录编码的数据大小 pkt.flags == AV_PKT_FLAG_KEY //用于判断当前编码出来的是否为关键帧 av_packet_unref(&pkt); } }7. //编码退出前需把编码器里还未完成一帧图像的数据进行处理 for (got_output = 1; got_output; i++) { ret = avcodec_encode_video2(pCodecCtx, &pkt, NULL, &got_output); if (got_output) { pkt.data里存放已编码好的数据, pkt.size记录编码的数据大小 pkt.flags == AV_PKT_FLAG_KEY //用于判断当前编码出来的是否为关键帧 av_packet_unref(&pkt); } } 8.// 退出编码的处理 avcodec_close(pCodecCtx); av_free(pCodecCtx); av_freep(&pFrame->data[0]); av_frame_free(&pFrame);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值