zoukankan      html  css  js  c++  java
  • 通过FFmpeg将多媒体文件解码后保存成Bmp图像(YUV420 RGB32)

    /* g++ -o test test.cpp -lavformat -lavcodec -lavutil -lz -lm -lpthread -lswscale */

    #include <string>
    #include <cassert>
    #include <iostream>
    #include <sstream>
    //#include <tchar.h>


    extern "C"
    {
    #ifndef INT64_C
    #define INT64_C(c) (c ## LL)
    #define UINT64_C(c) (c ## ULL)
    #endif
    #include <libavutil/avutil.h>
    #include <libavformat/avformat.h>
    #include <libswscale/swscale.h>
    #include <libavcodec/avcodec.h>
    #include <stdlib.h>
    #include <unistd.h>
    };
    //#pragma comment(lib, "avformat.lib")
    //#pragma comment(lib, "avutil.lib")
    //#pragma comment(lib, "avcodec.lib")
    //#pragma comment(lib, "swscale.lib")
    #pragma pack(1)
    #define BOOL int
    #define TRUE 1
    #define FALSE 0
    #define BI_RGB 0x0

    char *itoa(int num,char *str,int radix) {
    /* 索引表 */
    char index[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    unsigned unum; /* 中间变量 */
    int i=0,j,k;
    /* 确定unum的值 */
    if(radix==10&&num<0) /* 十进制负数 */
    {
    unum=(unsigned)-num;
    str[i++]='-';
    } else unum=(unsigned)num; /* 其他情况 */
    /* 逆序 */
    do {
    str[i++]=index[unum%(unsigned)radix];
    unum/=radix;
    }while(unum);
    str[i]='';
    /* 转换 */
    if(str[0]=='-') k=1; /* 十进制负数 */
    else k=0;
    char temp;
    for(j=k;j<=(i-k-1)/2;j++)
    {
    temp=str[j];
    str[j]=str[i-j-1];
    str[i-j-1]=temp;
    }
    return str;
    }

    static AVFrame *alloc_picture(enum PixelFormat pix_fmt, int width, int height);
    BOOL CreateBmp(const char *filename, uint8_t *pRGBBuffer, int width, int height, int bpp) ;
    int main(int argc, char* argv[])
    {
    int iResult = 0;
    //* 注册
    av_register_all();
    //* 文件名.
    //std::string strFile = "e:\高码\13587戈壁母亲片花__016.mpg";
    const char *strFile = "input.MP4";
    //* 打开文件
    AVFormatContext* pavFmtCxt = NULL;
    //iResult = av_open_input_file(&pavFmtCxt, strFile.c_str(), NULL, 0, NULL);
    iResult = avformat_open_input(&pavFmtCxt, strFile, NULL, NULL);
    assert(iResult == 0);

    iResult = avformat_find_stream_info(pavFmtCxt, NULL);
    assert(iResult >= 0);
    int iVidStrmID = -1;
    for (int i = 0; i < pavFmtCxt->nb_streams; ++i)
    {
    if (AVMEDIA_TYPE_VIDEO == pavFmtCxt->streams[i]->codec->codec_type)
    {
    iVidStrmID = i;
    }
    }
    assert(iVidStrmID != -1);

    //* 查找,打开解码器.
    AVCodec* pDecodec = avcodec_find_decoder(
    pavFmtCxt->streams[iVidStrmID]->codec->codec_id);
    iResult = avcodec_open2(pavFmtCxt
    ->streams[iVidStrmID]->codec, pDecodec, NULL);
    assert(iResult >= 0);

    av_dump_format(pavFmtCxt, iVidStrmID, strFile, 0);
    //* 读取文件,解码.
    AVFrame* pFrame = avcodec_alloc_frame();
    AVPacket pkt;
    av_init_packet(&pkt);
    //* Seek
    //av_seek_frame(pavFmtCxt, 0, 493, AVSEEK_FLAG_FRAME);
    while (av_read_frame(pavFmtCxt, &pkt)>= 0)
    {
    if (pkt.stream_index == iVidStrmID)
    {
    int iFinished = 0;
    AVCodecContext* pavCCxt = NULL;
    pavCCxt = pavFmtCxt->streams[iVidStrmID]->codec;
    int iDecoded = avcodec_decode_video2(pavCCxt, pFrame,
    &iFinished, &pkt);
    if (iDecoded > 0 && iFinished)
    {
    std::ostringstream ostrm;
    //* 解码成功.输出PTS,
    ostrm<<"pts_"
    <<pkt.pts//<<pavFmtCxt->streams[iVidStrmID]->pts_buffer[0]
    <<" ";
    //OutputDebugStringA(ostrm.str().c_str());

    int width, height;
    width = pavFmtCxt->streams[iVidStrmID]->codec->width;
    height = pavFmtCxt->streams[iVidStrmID]->codec->height;
    //* 将YUV420P转换成RGB32.
    SwsContext* pSwsCxt = sws_getContext(width,
    height,
    PIX_FMT_YUV420P,
    width,
    height,
    PIX_FMT_RGB32,
    SWS_BILINEAR, NULL, NULL, NULL);
    uint8_t *rgb_data = static_cast<uint8_t*>(av_malloc(width*height*4));
    uint8_t *rgb_src[3]= {rgb_data, NULL, NULL};
    int rgb_stride[3]={4*width, 0, 0};
    assert(pSwsCxt);
    iResult = sws_scale(pSwsCxt, pFrame->data, pFrame->linesize,
    0, height, rgb_src, rgb_stride);
    assert(iResult == height);

    /* {{ 测试代码,RGB32,YUV420之间的转换.
    //* 将RGB32转换为YUV420P
    AVFrame* pYUVFrm = alloc_picture(PIX_FMT_YUV420P, width, height);
    SwsContext* pSwsCxtYUV = sws_getContext(width, height, PIX_FMT_RGB32,
    width, height,
    PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);//* 注意Flag的值.
    iResult = sws_scale(pSwsCxtYUV, rgb_src, rgb_stride,
    0, height, pYUVFrm->data, pYUVFrm->linesize);
    assert(iResult == height);

    //* 再转换成RGB32
    ::memset(rgb_data, 0, width*height*4);
    iResult = sws_scale(pSwsCxt, pYUVFrm->data, pYUVFrm->linesize,
    0, height, rgb_src, rgb_stride);
    assert(iResult == height);
    //* }} */
    char sz[100];
    itoa(pkt.pts, sz, 10);
    CreateBmp(sz, rgb_data, width, height, 32);
    ::memset(rgb_data, 0, width*height*4);
    av_freep(&rgb_data);

    //* 注意SwsContext必须用这个函数释放.
    sws_freeContext(pSwsCxt);

    /* {{ 测试代码, 打开上面必须打开这里.否则会内存泄漏.
    sws_freeContext(pSwsCxtYUV);

    av_free(pYUVFrm->data[0]);
    av_free(pYUVFrm);
    pYUVFrm = NULL;
    //* }} */
    }
    else
    {
    //::OutputDebugStringA("解码失败");
    printf("解码失败");
    }
    }
    }
    return 0;
    }

    typedef struct tagBITMAPFILEHEADER
    {
    unsigned short bfType; //2 位图文件的类型,必须为“BM”
    unsigned long bfSize; //4 位图文件的大小,以字节为单位
    unsigned short bfReserved1; //2 位图文件保留字,必须为0
    unsigned short bfReserved2; //2 位图文件保留字,必须为0
    unsigned long bfOffBits; //4 位图数据的起始位置,以相对于位图文件头的偏移量表示,以字节为单位
    } BITMAPFILEHEADER;//该结构占据14个字节。
    // printf("%d ",sizeof(BITMAPFILEHEADER));

    typedef struct tagBITMAPINFOHEADER{
    unsigned long biSize; //4 本结构所占用字节数
    long biWidth; //4 位图的宽度,以像素为单位
    long biHeight; //4 位图的高度,以像素为单位
    unsigned short biPlanes; //2 目标设备的平面数不清,必须为1
    unsigned short biBitCount;//2 每个像素所需的位数,必须是1(双色), 4(16色),8(256色)或24(真彩色)之一
    unsigned long biCompression; //4 位图压缩类型,必须是 0(不压缩),1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
    unsigned long biSizeImage; //4 位图的大小,以字节为单位
    long biXPelsPerMeter; //4 位图水平分辨率,每米像素数
    long biYPelsPerMeter; //4 位图垂直分辨率,每米像素数
    unsigned long biClrUsed;//4 位图实际使用的颜色表中的颜色数
    unsigned long biClrImportant;//4 位图显示过程中重要的颜色数
    } BITMAPINFOHEADER;//该结构占据40个字节。

    BOOL CreateBmp(const char *filename, uint8_t *pRGBBuffer, int width, int height, int bpp)
    {
    BITMAPFILEHEADER bmpheader;
    BITMAPINFOHEADER bmpinfo;
    FILE *fp = NULL;

    fp = fopen(filename,"wb");
    if( fp == NULL )
    {
    return FALSE;
    }

    bmpheader.bfType = ('M' <<8)|'B';
    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 = 0 - height;
    bmpinfo.biPlanes = 1;
    bmpinfo.biBitCount = bpp;
    bmpinfo.biCompression = BI_RGB;
    bmpinfo.biSizeImage = 0;
    bmpinfo.biXPelsPerMeter = 100;
    bmpinfo.biYPelsPerMeter = 100;
    bmpinfo.biClrUsed = 0;
    bmpinfo.biClrImportant = 0;

    fwrite(&bmpheader,sizeof(BITMAPFILEHEADER),1,fp);
    fwrite(&bmpinfo,sizeof(BITMAPINFOHEADER),1,fp);
    fwrite(pRGBBuffer,width*height*bpp/8,1,fp);
    fclose(fp);
    fp = NULL;

    return TRUE;
    }

    static AVFrame *alloc_picture(enum PixelFormat pix_fmt, int width, int height)
    {
    AVFrame *picture;
    uint8_t *picture_buf;
    int size;

    picture = avcodec_alloc_frame();
    if (!picture)
    return NULL;
    size = avpicture_get_size(pix_fmt, width, height);
    picture_buf = (uint8_t*)av_malloc(size);
    if (!picture_buf) {
    av_free(picture);
    return NULL;
    }
    avpicture_fill((AVPicture *)picture, picture_buf,
    pix_fmt, width, height);
    return picture;
    }

  • 相关阅读:
    【codevs1515】 跳
    【bzoj1227】 SDOI2009—虔诚的墓主人
    【bzoj3505】 Cqoi2014—数三角形
    【bzoj1059】 ZJOI2007—矩阵游戏
    【poj2122】 Optimal Milking
    【poj2455】 Secret Milking Machine
    【poj3084】 Panic Room
    【poj2699】 The Maximum Number of Strong Kings
    【bzoj3218】 a + b Problem
    【bzoj3122】 Sdoi2013—随机数生成器
  • 原文地址:https://www.cnblogs.com/subo_peng/p/5517269.html
Copyright © 2011-2022 走看看