使用visual studio 2013 ,首先配置项目环境。下载ffmpeg:win64位:https://ffmpeg.zeranoe.com/builds/win64/。下载share与dev,版本须要一致。html
在本身工程项目的.sln文件路径下新建include与lib文件夹,将ffmpeg shared项目的bin目录下.dll拷贝到本身建立的lib中,将dev项目中的lib目录下.lib文件拷贝到本身建立的lib目录中,将dev项目中的include目录下的全部文件拷贝到本身建立的include中并将以下三个头文件拷入include中缓存
设置include与lib的引用ide
最后将须要用到的.dll文件拷贝到生成.exe的目录下,至此环境搭建完成。函数
详细编码流程以下:工具
1.首先解析、处理输入参数,如编码器的参数、图像的参数、输入输出文件;ui
2.创建整个FFMpeg编码器的各类组件工具,顺序依次为:avcodec_register_all -> avcodec_find_encoder ->avcodec_alloc_context3 -> avcodec_open2 -> av_frame_alloc -> av_image_alloc;编码
3.编码循环:av_init_packet -> avcodec_encode_video2(两次) -> av_packet_unrefspa
4.关闭编码器组件:avcodec_close,av_free,av_freep,av_frame_free.net
1:定义错误码头文件Error.h命令行
#ifndef _ERROR_H_ #define _ERROR_H_ #define IO_FILE_ERROR_OPEN_FAIL -1 #define FF_ERROR_INITIALIZATION_FAILED -10 #define FF_ERROR_ENCODING_FAILED -11 #endif
#include "stdio.h" #include "stdlib.h" #include "stdint.h" #include "Error.h" extern "C"{ #include "libavutil/imgutils.h" #include "libavutil/samplefmt.h" #include "libavformat/avformat.h" #include "libavutil/opt.h" } //文件输入路径 const char *inputFileName = NULL; //文件输出路径 const char *outPutFileName = NULL; //输入输出文件指针 FILE *pFin = NULL, *pFout = NULL; //输入的视频文件宽高 int frameWidth = 0, frameHeight = 0; //编码的比特率和编码帧数 int bitRate = 0, frameToCode = 0; //编码器对象 AVCodec *codec = NULL; //编码器对象的上下文环境 AVCodecContext *codecCtx = NULL; AVFrame *frame = NULL; AVPacket pkt; /** *从命令行中解析出命令行参数 */ static int parse_input_paramaters(int argc, char **argv){ inputFileName = argv[1]; outPutFileName = argv[2]; fopen_s(&pFin,inputFileName,"rb+"); if (!pFin){ return IO_FILE_ERROR_OPEN_FAIL; } fopen_s(&pFout, outPutFileName, "wb+"); if (!pFout){ return IO_FILE_ERROR_OPEN_FAIL; } frameWidth = atoi(argv[3]); frameHeight = atoi(argv[4]); bitRate = atoi(argv[5]); frameToCode = atoi(argv[6]); return 1; } /** *从命令行中解析出命令行参数 *YUV_420_P格式的数据 */ static int read_yuv_data(int color){ //color = 0; y份量 亮度份量 占4份 //color = 1; u份量 色度份量 占2份 //color = 2; v份量 色度份量 占2份 int color_width = color == 0 ? frameWidth : frameWidth / 2; int color_height = color == 0 ? frameHeight : frameHeight / 2; int color_size = color_width * color_height; int color_stride = frame->linesize[color]; //因为视频边缘可能有填充像素,因此frame的width与linesize可能不相等 if (color_width == color_stride){ //frame的width与linesize相等时像素数据是连续的 fread_s(frame->data[color], color_size, 1, color_size, pFin); } else { //frame的width与linesize不相等时候读取像素数据 for (int row_idx = 0; row_idx < color_height; row_idx++){ fread_s(frame->data[color] + row_idx * color_stride, color_width, 1, color_width, pFin); } } return color_size; } int main(int argc, char **argv){ int got_packet = 0; if (parse_input_paramaters(argc, argv) > 0){ printf("InputFile: %s\nOutPutFile: %s\nFile:Frame resolution: (%d x %d)\nBitrate: %d\nFrame num to code: %d\n" ,inputFileName,outPutFileName,frameWidth,frameHeight,bitRate,frameToCode); } else{ printf("Error:connamd line error\n"); return -1; } { //注册须要的ffmpeg编解码组件 avcodec_register_all(); //查找编解码器 codec = avcodec_find_encoder(AV_CODEC_ID_H264); if (!codec){ return FF_ERROR_INITIALIZATION_FAILED; } //分配AVCodecContext codecCtx = avcodec_alloc_context3(codec); if (!codecCtx){ return FF_ERROR_INITIALIZATION_FAILED; } //设置编码参数 codecCtx->width = frameWidth; codecCtx->height = frameHeight; codecCtx->bit_rate = bitRate; AVRational r = { 1, 25 }; codecCtx->time_base = r; codecCtx->gop_size = 12; codecCtx->max_b_frames = 1; codecCtx->pix_fmt = AV_PIX_FMT_YUV420P; //av_opt_set(codecCtx->priv_data,"preset","superfast",0); av_opt_set(codecCtx->priv_data, "tune", "zerolatency", 0); //打开编码器 if(avcodec_open2(codecCtx, codec, NULL) < 0){ return FF_ERROR_INITIALIZATION_FAILED; } //分配AVFrame以及像素存储空间 frame = av_frame_alloc(); if (!frame){ return FF_ERROR_INITIALIZATION_FAILED; } frame->width = codecCtx->width; frame->height = codecCtx->height; frame->format = codecCtx->pix_fmt; if (av_image_alloc(frame->data, frame->linesize, frame->width, frame->height, (AVPixelFormat)frame->format, 32) < 0){ return FF_ERROR_INITIALIZATION_FAILED; } } for (int frameIdx = 0; frameIdx < frameToCode; frameIdx++) { //初始化AVPacket av_init_packet(&pkt); pkt.data = NULL; pkt.size = 0; //读取像素数据到AVFrame中 read_yuv_data(0); read_yuv_data(1); read_yuv_data(2); //设置视频的显示时间戳 frame->pts = frameIdx; //开始编码 if (avcodec_encode_video2(codecCtx,&pkt,frame,&got_packet) < 0){ printf("Error: encoding failed!"); return FF_ERROR_ENCODING_FAILED; } //将编码后的数据写入输出文件中 if (got_packet){ printf("write packet of frame %d,size = %d\n",frameIdx,pkt.size); fwrite(pkt.data,1,pkt.size,pFout); av_packet_unref(&pkt); } } //在编码器中可能还有一些缓存数据须要进行编码 for (got_packet = 1; got_packet;) { //编码 if (avcodec_encode_video2(codecCtx, &pkt, NULL, &got_packet) < 0){ printf("Error: encoding failed!"); return FF_ERROR_ENCODING_FAILED; } if (got_packet){ printf("write cached packet,size = %d\n", pkt.size); fwrite(pkt.data, 1, pkt.size, pFout); av_packet_unref(&pkt); } } //收尾工做,清理内存 fclose(pFin); fclose(pFout); avcodec_close(codecCtx); av_free(codecCtx); av_freep(&frame->data[0]); av_frame_free(&frame); return 0; }
备注:博客内容来源于《FFMpeg视频开发与应用基础——使用FFMpeg工具与SDK》
视频地址:http://edu.csdn.net/course/detail/2515