c++ 配置ffmpeg
阅读原文时间:2023年07月08日阅读:3

本教程只针对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
#include
#include
#include
#pragma once
#pragma warning(disable:4996)

extern "C"
{
#include
#include
#include
#include
#include
#include
#include
};

//定义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[] = { };
//bmp头
BITMAPFILEHEADER bmpheader;
BITMAPINFOHEADER bmpinfo;
FILE *fp;
char *filename = new char[];
//文件存放路径,根据自己的修改
sprintf_s(filename, , "%s_%d.bmp", "D:\\", index);
if ((fp = fopen(filename, "wb+")) == NULL)
{
printf("open file failed!\n");
return;
}

bmpheader.bfType = 0x4d42;  
bmpheader.bfReserved1 = ;  
bmpheader.bfReserved2 = ;  
bmpheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);  
bmpheader.bfSize = bmpheader.bfOffBits + width\*height\*bpp / ;

bmpinfo.biSize = sizeof(BITMAPINFOHEADER);  
bmpinfo.biWidth = width;  
bmpinfo.biHeight = height;  
bmpinfo.biPlanes = ;  
bmpinfo.biBitCount = bpp;  
bmpinfo.biCompression = BI\_RGB;  
bmpinfo.biSizeImage = (width\*bpp + ) /  \*  \* height;  
bmpinfo.biXPelsPerMeter = ;  
bmpinfo.biYPelsPerMeter = ;  
bmpinfo.biClrUsed = ;  
bmpinfo.biClrImportant = ;

fwrite(&bmpheader, sizeof(bmpheader), , fp);  
fwrite(&bmpinfo, sizeof(bmpinfo), , fp);  
fwrite(pFrameRGB->data\[\], width\*height\*bpp / , , fp);

fclose(fp);  

}

//主函数
int main(void)
{
unsigned int i = , videoStream = -;
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) != )
{
printf("av open input file failed!\n");
exit();
}
//获取流信息
if (avformat_find_stream_info(pFormatCtx, NULL) < ) { printf("av find stream info failed!\n"); exit(); } //获取视频流 for (i = ; inb_streams; i++)
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoStream = i;
break;
}

if (videoStream == -)  
{  
    printf("find video stream failed!\\n");  
    exit();  
}

pCodecCtx = pFormatCtx->streams\[videoStream\]->codec;

pCodec = avcodec\_find\_decoder(pCodecCtx->codec\_id);

if (pCodec == NULL)  
{  
    printf("avcode find decoder failed!\\n");  
    exit();  
}  
//打开解码器  
if (avcodec\_open2(pCodecCtx, pCodec, NULL)<)  
{  
    printf("avcode open failed!\\n");  
    exit();  
}

//为每帧图像分配内存  
pFrame = av\_frame\_alloc();  
pFrameRGB = av\_frame\_alloc();

if ((pFrame == NULL) || (pFrameRGB == NULL))  
{  
    printf("avcodec alloc frame failed!\\n");  
    exit();  
}  
//获得帧图大小  
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();  
}  
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 = ;  
while (av\_read\_frame(pFormatCtx, &packet) >= )  
{  
    if (packet.stream\_index == videoStream)  
    {  
        //真正解码  
        avcodec\_decode\_video2(pCodecCtx, pFrame, &frameFinished, &packet);  
        if (frameFinished)  
        {  
            //反转图像 ,否则生成的图像是上下调到的  
            pFrame->data\[\] += pFrame->linesize\[\] \* (pCodecCtx->height - );  
            pFrame->linesize\[\] \*= -;  
            pFrame->data\[\] += pFrame->linesize\[\] \* (pCodecCtx->height /  - );  
            pFrame->linesize\[\] \*= -;  
            pFrame->data\[\] += pFrame->linesize\[\] \* (pCodecCtx->height /  - );  
            pFrame->linesize\[\] \*= -;  
            //转换图像格式,将解压出来的YUV420P的图像转换为BRG24的图像  
            sws\_scale(pSwsCtx, pFrame->data, pFrame->linesize, , pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);  
            //保存为bmp图  
            SaveAsBMP(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i, );  
            i++;  
        }  
        av\_free\_packet(&packet);  
    }  
}  
sws\_freeContext(pSwsCtx);  
av\_free(pFrame);  
av\_free(pFrameRGB);  
avcodec\_close(pCodecCtx);  
avformat\_close\_input(&pFormatCtx);

return ;  

}

ffmpeg这样连接了后会花屏,解决方式如下(换成TCP连接方式):

AVDictionary* options = NULL;
av_dict_set(&options, "rtsp_transport", "tcp", );
if(avformat_open_input(&pFormatCtx,"rtsp://192.168.2.214:554/bs0",NULL,&options)!=){
printf("Couldn't open input stream.\n");
return -;
}

这样连接了不会花屏,但是延时会越来越长