采用FFmpeg解帧,并保存为JPG、BMP格式文件

最近了解了一下ffmpeg方面的内容,针对ffmpeg解帧,并保存图片的方法,找了个很好用的,就先记下了。内容出处:https://xiva.iteye.com/blog/1993599

首先下载ffmpeg的开发包以及依赖包,当然也可以下载源码。

http://ffmpeg.zeranoe.com/builds/

其次为了编码为JPEG格式的图片,需要下载Independent JPEG Group

http://www.ijg.org/files/jpegsr9.zip

下载IJG后,需要对源码进行编译,生成静态库,

本人是使用VS2010编译的,其中含有install.txt文件讲述了怎么讲make file文件转换为VS工程文件,使用下面命令可以做到:

NMAKE /f makefile.vc  setup-v10

其中会遇到windows环境变量中没有NMAKE 的问题,还有Win32.Mak找不到的问题。

1、找到nmake.exe配一下环境变量

2、在makefile.vc文件中找到Win32.Mak,将相应路径添加上,如:

!include <C:\Program Files\Microsoft SDKs\Windows\v7.0A\Include\Win32.Mak>

如果嫌Independent JPEG Group编译麻烦,我倒是有个编译好的:https://download.csdn.net/download/summer_9527/10937443(Vs2008)

https://download.csdn.net/download/summer_9527/11862213(VS2015)

而且这个玩意还能bmp图片转jpg格式,具体内容:https://blog.csdn.net/y601500359/article/details/80401958 没错,我就是大自然的搬运工

具体代码如下

#include <math.h>  
#include <windows.h>  
  
#include <libavutil/opt.h>  
#include <libavcodec/avcodec.h>  
#include <libavutil/channel_layout.h>  
#include <libavutil/common.h>  
#include <libavutil/imgutils.h>  
#include <libavutil/mathematics.h>  
#include <libavutil/samplefmt.h>  
#include <libavformat/avformat.h>  
#include <libswscale/swscale.h>  
  
#include <jpeglib.h>  
#include <setjmp.h>  
  
#define inline __inline  
#define snprintf _snprintf  
  
#define INBUF_SIZE 4096  
#define AUDIO_INBUF_SIZE 20480  
#define AUDIO_REFILL_THRESH 4096  
  
  
#pragma comment (lib, "Ws2_32.lib")    
#pragma comment (lib, "avcodec.lib")  
#pragma comment (lib, "avdevice.lib")  
#pragma comment (lib, "avfilter.lib")  
#pragma comment (lib, "avformat.lib")  
#pragma comment (lib, "avutil.lib")  
#pragma comment (lib, "swresample.lib")  
#pragma comment (lib, "swscale.lib")  
 #pragma comment(lib, "jpeg.lib")  
  
static void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame);  
  
static void yuv420p_save(AVFrame *pFrame, int width, int height, int iFrame);  
  
static void bmp_save(AVFrame *pFrame, int width, int height, int iFrame);  
  
static void saveFrame_jpg(uint8_t *pRGBBuffer, int iFrame, int width, int height);  
  
int main(int argc, char **argv)  
{  
    AVFormatContext *pFormatCtx = NULL;  
    char            *fileName = "E:\\aa.rm";  
    int             i,videoStream;  
    AVCodecContext  *pCodecCtx;  
    AVCodec         *pCodec;  
    AVFrame         *pFrame;  
    AVFrame         *pFrameRGB;  
    int             numBytes;  
    uint8_t         *buffer;  
    AVPacket        packet;  
    int             frameFinished;  
    struct SwsContext *img_convert_ctx = NULL;  
  
    av_register_all();  
      
    if(avformat_open_input(&pFormatCtx, fileName, NULL, NULL)!=0)  
    {  
        printf("can not open");  
        return -1;  
    }  
  
    if(avformat_find_stream_info(pFormatCtx, NULL) < 0)  
    {  
        printf("can not find");  
        return -1;  
    }  
  
    av_dump_format(pFormatCtx, -1, fileName, 0);  
  
    videoStream = -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("not find videoStream");  
        return -1;  
    }  
  
    pCodecCtx = pFormatCtx->streams[videoStream]->codec;  
  
    pCodec = avcodec_find_decoder(pCodecCtx->codec_id);  
    if ( pCodec == NULL )  
    {  
        return -1;  
    }  
  
    if( avcodec_open2(pCodecCtx, pCodec, NULL) < 0 )  
    {  
        return -1;  
    }  
  
    pFrame = av_frame_alloc();  
    if( pFrame == NULL )  
    {  
        return -1;  
    }  
  
    pFrameRGB = av_frame_alloc();  
    if( pFrameRGB == NULL )  
    {  
        return -1;  
    }  
  
    numBytes = avpicture_get_size(PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height);  
  
    buffer = av_malloc(numBytes);  
  
    avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height);  
  
      
    img_convert_ctx = sws_getCachedContext(img_convert_ctx, pCodecCtx->width, pCodecCtx->height,  
        pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_RGB24, 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 )  
            {  
                  
                if (!img_convert_ctx )  
                {  
                    fprintf(stderr, "Cannot initialize sws conversion context\n");  
                    exit(1);  
                }  
  
                sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height,  
                    pFrameRGB->data, pFrameRGB->linesize);  
  
                if(i++<5)  
                {  
                    //SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);  
                    //yuv420p_save(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);  
                    //bmp_save(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);  
                    saveFrame_jpg(pFrameRGB->data[0], i, pCodecCtx->width, pCodecCtx->height);  
                      
                }  
            }  
        }  
        if(i > 5)  
        {  
            break;  
        }  
    }  
    av_free_packet(&packet);  
      
    av_free(buffer);  
    av_free(pFrame);  
    av_free(pFrameRGB);  
    avcodec_close(pCodecCtx);  
    avformat_close_input(&pFormatCtx);  
      
  
    return 0;  
}  
  
static void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame)  
{  
    FILE *pFile;  
    char szFilename[32];  
    int y;  
  
    sprintf(szFilename, "frame%d.jpg", iFrame);  
    pFile = fopen(szFilename, "wb");  
    if( !pFile )  
    {  
        return;  
    }  
  
    fprintf(pFile, "P6\n%d %d\n255\n", width, height);  
    for ( y=0; y<height; y++ )  
    {  
        fwrite(pFrame->data[0] + y * pFrame->linesize[0], 1, width * 3, pFile);  
    }  
  
    fclose(pFile);  
}  
  
static void yuv420p_save(AVFrame *pFrame, int width, int height, int iFrame)  
{  
    int i = 0;  
    FILE *pFile;  
    char szFilename[32];  
  
    int height_half = height / 2, width_half = width / 2;  
    int y_wrap = pFrame->linesize[0];  
    int u_wrap = pFrame->linesize[1];  
    int v_wrap = pFrame->linesize[2];  
  
    unsigned char *y_buf = pFrame->data[0];  
    unsigned char *u_buf = pFrame->data[1];  
    unsigned char *v_buf = pFrame->data[2];  
    sprintf(szFilename, "frame%d.jpg", iFrame);  
    pFile = fopen(szFilename, "wb");  
  
    //save y  
    for (i = 0; i < height; i++)  
        fwrite(y_buf + i * y_wrap, 1, width, pFile);  
    fprintf(stderr, "===>save Y success\n");  
  
    //save u  
    for (i = 0; i < height_half; i++)  
        fwrite(u_buf + i * u_wrap, 1, width_half, pFile);  
    fprintf(stderr, "===>save U success\n");  
  
    //save v  
    for (i = 0; i < height_half; i++)  
        fwrite(v_buf + i * v_wrap, 1, width_half, pFile);  
    fprintf(stderr, "===>save V success\n");  
  
    fflush(pFile);  
    fclose(pFile);  
}  
  
  
static void bmp_save(AVFrame *pFrame, int width, int height, int iFrame)  
{  
    BITMAPFILEHEADER bmpheader;  
    BITMAPINFO bmpinfo;  
    int y = 0;  
    FILE *pFile;  
    char szFilename[32];  
  
    unsigned char *y_buf = pFrame->data[0];  
    sprintf(szFilename, "frame%d.bmp", iFrame);  
    pFile = fopen(szFilename, "wb");  
  
    bmpheader.bfReserved1 = 0;  
    bmpheader.bfReserved2 = 0;  
    bmpheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);  
    bmpheader.bfSize = bmpheader.bfOffBits + width*height*24/8;  
  
    bmpinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);  
    bmpinfo.bmiHeader.biWidth = width;  
    bmpinfo.bmiHeader.biHeight = -height;  
    bmpinfo.bmiHeader.biPlanes = 1;  
    bmpinfo.bmiHeader.biBitCount = 24;  
    bmpinfo.bmiHeader.biCompression = BI_RGB;  
    bmpinfo.bmiHeader.biSizeImage = 0;  
    bmpinfo.bmiHeader.biXPelsPerMeter = 100;  
    bmpinfo.bmiHeader.biYPelsPerMeter = 100;  
    bmpinfo.bmiHeader.biClrUsed = 0;  
    bmpinfo.bmiHeader.biClrImportant = 0;  
  
    fwrite(&bmpheader, sizeof(BITMAPFILEHEADER), 1, pFile);  
    fwrite(&bmpinfo.bmiHeader, sizeof(BITMAPINFOHEADER), 1, pFile);  
  
    fwrite(pFrame->data[0], width*height*24/8, 1, pFile);  
  
    /*for(y=0; y<height; y++)  
    {  
        fwrite(pFrame->data[0] + y*pFrame->linesize[0], 1, width*3, pFile);  
    }*/  
  
    //fflush(pFile);  
    fclose(pFile);  
}  
  
static void saveFrame_jpg(uint8_t *pRGBBuffer, int iFrame, int width, int height)  
{  
  
    struct jpeg_compress_struct cinfo;  
  
    struct jpeg_error_mgr jerr;  
  
    char szFilename[1024];  
    int row_stride;  
  
    FILE *fp;  
  
    JSAMPROW row_pointer[1];   // 一行位图  
  
    cinfo.err = jpeg_std_error(&jerr);  
  
    jpeg_create_compress(&cinfo);  
  
      
    sprintf(szFilename, "test%d.jpg", iFrame);//图片名字为视频名+号码  
    fp = fopen(szFilename, "wb");  
      
    if(fp == NULL)  
            return;  
  
    jpeg_stdio_dest(&cinfo, fp);  
  
    cinfo.image_width = width;    // 为图的宽和高,单位为像素   
    cinfo.image_height = height;  
    cinfo.input_components = 3;   // 在此为1,表示灰度图, 如果是彩色位图,则为3   
    cinfo.in_color_space = JCS_RGB; //JCS_GRAYSCALE表示灰度图,JCS_RGB表示彩色图像  
  
    jpeg_set_defaults(&cinfo);   
    jpeg_set_quality (&cinfo, 80, 1);  
  
    jpeg_start_compress(&cinfo, TRUE);  
  
      
    row_stride = cinfo.image_width * 3;//每一行的字节数,如果不是索引图,此处需要乘以3  
  
    // 对每一行进行压缩  
    while (cinfo.next_scanline < cinfo.image_height) {  
        row_pointer[0] = &(pRGBBuffer[cinfo.next_scanline * row_stride]);  
        jpeg_write_scanlines(&cinfo, row_pointer, 1);  
    }  
  
    jpeg_finish_compress(&cinfo);  
    jpeg_destroy_compress(&cinfo);  
  
    fclose(fp);  
}  

 

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值