c++ 配置ffmpeg
本教程只针对windows64/32+vs2013环境配置
第一步 :配环境
1.打开ffmpeg官网中编译好的windows版本http://ffmpeg.zeranoe.com/builds/
64位windows系统和32位系统各有三个版本分别为Static版本,Share版本,Dev版本;
在这里建议无论是32位还是64位系统都直接配置32位的ffmpeg版本,除非你vs2013选择的是x64编译器。
将32位版本Share版本和Dev下载,解压。
在Dev里面主要是一些头文件和lib,在share版本里主要是dll文件。
2.打开vs2013,新建一个win32控制台程序。
选择项目-》属性-》c++目录,分别在包含目录和库目录中打开dev版本中的include和lib(指的是你解压dev保存的位置,在里面找到include和lib)
3项目-》属性-》链接器-》输入-》依赖项中填写
avcodec.lib
avformat.lib
avutil.lib
avdevice.lib
avfilter.lib
postproc.lib
swresample.lib
swscale.lib
保存即可。
第二步:视频解码,此处是一个完整的视频解码工程,从解码到存储,在vs2013上可以运行,如果编译不成功,可考虑是否是环境配错了。注意关闭防火墙。
// ConsoleApplication9.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <windows.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #pragma once #pragma warning(disable:4996) extern "C" { #include <libavcodec/avcodec.h> #include <libavdevice/avdevice.h> #include<libavfilter/avfilter.h> #include <libswscale/swscale.h> #include <libswresample/swresample.h> #include <libavformat/avformat.h> #include <libavutil/avutil.h> }; //定义BMP文件头 #ifndef _WINGDI_ #define _WINGDI_ typedef struct tagBITMAPFILEHEADER { WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER; typedef struct tagBITMAPINFOHEADER{ DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER; #endif //保存BMP文件的函数 void SaveAsBMP(AVFrame *pFrameRGB, int width, int height, int index, int bpp) { char buf[5] = { 0 }; //bmp头 BITMAPFILEHEADER bmpheader; BITMAPINFOHEADER bmpinfo; FILE *fp; char *filename = new char[255]; //文件存放路径,根据自己的修改 sprintf_s(filename, 255, "%s_%d.bmp", "D:\\", index); if ((fp = fopen(filename, "wb+")) == NULL) { printf("open file failed!\n"); return; } bmpheader.bfType = 0x4d42; bmpheader.bfReserved1 = 0; bmpheader.bfReserved2 = 0; bmpheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); bmpheader.bfSize = bmpheader.bfOffBits + width*height*bpp / 8; bmpinfo.biSize = sizeof(BITMAPINFOHEADER); bmpinfo.biWidth = width; bmpinfo.biHeight = height; bmpinfo.biPlanes = 1; bmpinfo.biBitCount = bpp; bmpinfo.biCompression = BI_RGB; bmpinfo.biSizeImage = (width*bpp + 31) / 32 * 4 * height; bmpinfo.biXPelsPerMeter = 100; bmpinfo.biYPelsPerMeter = 100; bmpinfo.biClrUsed = 0; bmpinfo.biClrImportant = 0; fwrite(&bmpheader, sizeof(bmpheader), 1, fp); fwrite(&bmpinfo, sizeof(bmpinfo), 1, fp); fwrite(pFrameRGB->data[0], width*height*bpp / 8, 1, fp); fclose(fp); } //主函数 int main(void) { unsigned int i = 0, videoStream = -1; AVCodecContext *pCodecCtx; AVFormatContext *pFormatCtx; AVCodec *pCodec; AVFrame *pFrame, *pFrameRGB; struct SwsContext *pSwsCtx; const char *filename = "E:\\123.avi";//rtsp://192.168.2.214:554/bs0 AVPacket packet; int frameFinished; int PictureSize; uint8_t *buf; //注册编解码器 av_register_all(); avformat_network_init(); pFormatCtx = avformat_alloc_context(); //打开视频文件 if (avformat_open_input(&pFormatCtx, filename, NULL, NULL) != 0) { printf("av open input file failed!\n"); exit(1); } //获取流信息 if (avformat_find_stream_info(pFormatCtx, NULL) < 0) { printf("av find stream info failed!\n"); exit(1); } //获取视频流 for (i = 0; i<pFormatCtx->nb_streams; i++) if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { videoStream = i; break; } if (videoStream == -1) { printf("find video stream failed!\n"); exit(1); } pCodecCtx = pFormatCtx->streams[videoStream]->codec; pCodec = avcodec_find_decoder(pCodecCtx->codec_id); if (pCodec == NULL) { printf("avcode find decoder failed!\n"); exit(1); } //打开解码器 if (avcodec_open2(pCodecCtx, pCodec, NULL)<0) { printf("avcode open failed!\n"); exit(1); } //为每帧图像分配内存 pFrame = av_frame_alloc(); pFrameRGB = av_frame_alloc(); if ((pFrame == NULL) || (pFrameRGB == NULL)) { printf("avcodec alloc frame failed!\n"); exit(1); } //获得帧图大小 PictureSize = avpicture_get_size(AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height); buf = (uint8_t*)av_malloc(PictureSize); if (buf == NULL) { printf("av malloc failed!\n"); exit(1); } avpicture_fill((AVPicture *)pFrameRGB, buf, AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height); //设置图像转换上下文 pSwsCtx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL); i = 0; while (av_read_frame(pFormatCtx, &packet) >= 0) { if (packet.stream_index == videoStream) { //真正解码 avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet); if (frameFinished) { //反转图像 ,否则生成的图像是上下调到的 pFrame->data[0] += pFrame->linesize[0] * (pCodecCtx->height - 1); pFrame->linesize[0] *= -1; pFrame->data[1] += pFrame->linesize[1] * (pCodecCtx->height / 2 - 1); pFrame->linesize[1] *= -1; pFrame->data[2] += pFrame->linesize[2] * (pCodecCtx->height / 2 - 1); pFrame->linesize[2] *= -1; //转换图像格式,将解压出来的YUV420P的图像转换为BRG24的图像 sws_scale(pSwsCtx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize); //保存为bmp图 SaveAsBMP(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i, 24); i++; } av_free_packet(&packet); } } sws_freeContext(pSwsCtx); av_free(pFrame); av_free(pFrameRGB); avcodec_close(pCodecCtx); avformat_close_input(&pFormatCtx); return 0; }
ffmpeg这样连接了后会花屏,解决方式如下(换成TCP连接方式):
AVDictionary* options = NULL; av_dict_set(&options, "rtsp_transport", "tcp", 0); if(avformat_open_input(&pFormatCtx,"rtsp://192.168.2.214:554/bs0",NULL,&options)!=0){ printf("Couldn't open input stream.\n"); return -1; }
这样连接了不会花屏,但是延时会越来越长