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;
    }

 

这样连接了不会花屏,但是延时会越来越长
posted @ 2015-09-25 10:08  QQ76211822  阅读(2848)  评论(0编辑  收藏  举报