I帧转图片(BMP、PPM、JPG)



// 使用ffmpeg取得视频的首个I帧,并转换为图片// 图片格式可以为BMP、PPM、JPG

// 头文件CGetFirstIFrameToPic.h

#if !defined (_C_GET_FIRST_IFRAME_TO_PIC_H_)#define _C_GET_FIRST_IFRAME_TO_PIC_H_extern "C"{#include "libavcodec/avcodec.h"#include "libavformat/avformat.h"#include "libswscale/swscale.h"#include "jpeglib.h"}// 取得视频的首个I帧,并转换为图片// 图片格式可以为BMP、PPM、JPGclass CGetFirstIFrameToPic{public:CGetFirstIFrameToPic(){};virtual ~CGetFirstIFrameToPic(){};// 取得视频的首个I帧,并转换为图片virtual int GetFirstIFrameAndConvertToPic(char *pVideoFile, char *pPicFile);// 保存帧数据为BMP图片virtual int SaveFrameToBMP(char *pPicFile, uint8_t *pRGBBuffer, int nWidth, int nHeight, int nBitCount);// 保存帧数据为PPM图片virtual int SaveFrameToPPM(char *pPicFile, AVFrame *pFrame, int nWidth, int nHeight);// 保存帧数据为JPG图片virtual int SaveFrameToJPG(char *pPicFile, uint8_t *pRGBBuffer, int nWidth, int nHeight);};#endif //!defined(_C_GET_FIRST_IFRAME_TO_PIC_H_)

// 取得视频的首个I帧,并转换为图片

#include "stdafx.h"#include "CGetFirstIFrameToPic.h"// 取得视频的首个I帧,并转换为图片int CGetFirstIFrameToPic::GetFirstIFrameAndConvertToPic(char *pVideoFile, char *pPicFile){int nRet = 0;if((NULL == pVideoFile) || (NULL == pPicFile)){return -1;}// 注册所有的文件格式和编解码器的库av_register_all();AVFormatContext *pFormatCtxDec = NULL; // 视频流的格式内容// 读取文件的头部并且把信息保存到我们给的AVFormatContext结构nRet = avformat_open_input(&pFormatCtxDec, pVideoFile, NULL, NULL);if(nRet != 0){printf("Couldn’t open file %s.\n", pVideoFile);return -1;}// 检查在文件中的流的信息nRet = avformat_find_stream_info(pFormatCtxDec, NULL);if(nRet < 0){printf("Couldn’t find stream information.\n");return -1;}// 找到第一个视频流int nVideoStream = -1;for(unsigned int i = 0; i < pFormatCtxDec->nb_streams; i++) {if(pFormatCtxDec->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){nVideoStream = i;break;}}if(nVideoStream == -1){printf("Didn’t find a video stream.\n");return -1;}printf("nVideoStream:%d.\n", nVideoStream);// 流中关于编解码器的信息就是被我们叫做"codec context"(编解码器上下文)的东西。// 这里面包含了流中所使用的关于编解码器的所有信息,现在我们有了一个指向他的指针。// 但是我们必需要找到真正的编解码器并且打开它AVCodecContext *pCodecCtxDec = NULL; // 编解码器上下文// Get a pointer to the codec context for the video streampCodecCtxDec = pFormatCtxDec->streams[nVideoStream]->codec;AVCodec *pCodecDec = NULL; // Find the decoder for the video streampCodecDec = avcodec_find_decoder(pCodecCtxDec->codec_id);if(pCodecDec==NULL){printf("Codec not found.\n");return -1;}// Open codecnRet = avcodec_open2(pCodecCtxDec, pCodecDec, NULL);if(nRet < 0){printf("Could not open codec.\n");return -1;}AVFrame *pFrameDec = NULL;// Allocate video framepFrameDec = avcodec_alloc_frame();if(pFrameDec == NULL){printf("Allocate video frame error.\n");return -1;}// 因为我们准备输出保存24位RGB色的PPM文件,我们必需把帧的格式从原来的转换为RGB。// FFMPEG将为我们做这些转换。// 在大多数项目中(包括我们的这个)我们都想把原始的帧转换成一个特定的格式。// 让我们先为转换来申请一帧的内存AVFrame *pFrameRGB = NULL;// Allocate an AVFrame structurepFrameRGB = avcodec_alloc_frame();if(pFrameRGB == NULL){printf("Allocate an AVFrame structure error.\n");return -1;}// 即使我们申请了一帧的内存,当转换的时候,我们仍然需要一个地方来放置原始的数据。// 我们使用avpicture_get_size来获得我们需要的大小,然后手工申请内存空间:uint8_t *pBuffer;int numBytes;// Determine required buffer size and allocate buffer AV_PIX_FMT_RGB24numBytes = avpicture_get_size(AV_PIX_FMT_RGB24, pCodecCtxDec->width, pCodecCtxDec->height);pBuffer=(uint8_t *)av_malloc(numBytes * sizeof(uint8_t));// 现在我们使用avpicture_fill来把帧和我们新申请的内存来结合。// 关于AVPicture的结成:AVPicture结构体是AVFrame结构体的子集// ――AVFrame结构体的开始部分与AVPicture结构体是一样的。// Assign appropriate parts of buffer to image planes in pFrameRGB// Note that pFrameRGB is an AVFrame, but AVFrame is a superset of AVPictureavpicture_fill((AVPicture *)pFrameRGB, pBuffer, AV_PIX_FMT_RGB24, pCodecCtxDec->width, pCodecCtxDec->height);// 最后,我们已经准备好来从流中读取数据了。// 读取数据// 我们将要做的是通过读取包来读取整个视频流,,// 然后把它解码成帧,最好后转换格式并且保存。int frameFinished = 0;AVPacket packet;static struct SwsContext *img_convert_ctx;while(true) {av_init_packet(&packet);nRet = av_read_frame(pFormatCtxDec, &packet);if(nRet < 0){break;}// Is this a packet from the video stream?if(packet.stream_index == nVideoStream) {// Decode video framenRet = avcodec_decode_video2(pCodecCtxDec, pFrameDec, &frameFinished, &packet);// Did we get a video frame?if(frameFinished){// 关键帧if(pFrameDec->key_frame == 1){char szPicFile[256];// ————frame to bmp start————memset(szPicFile, 0, sizeof(szPicFile));strncpy(szPicFile, pPicFile, sizeof(szPicFile));strncat(szPicFile, ".bmp", sizeof(szPicFile));// Convert the image from its native format to RGBimg_convert_ctx = sws_getContext(pCodecCtxDec->width, pCodecCtxDec->height, pCodecCtxDec->pix_fmt,pCodecCtxDec->width, pCodecCtxDec->height,AV_PIX_FMT_RGB24, SWS_BILINEAR, NULL, NULL, NULL);sws_scale(img_convert_ctx, pFrameDec->data, pFrameDec->linesize, 0,pCodecCtxDec->height, pFrameRGB->data, pFrameRGB->linesize);SaveFrameToBMP(szPicFile, pFrameRGB->data[0],pCodecCtxDec->width, pCodecCtxDec->height, 24);sws_freeContext(img_convert_ctx);// ————frame to bmp end————// ————frame to ppm start————memset(szPicFile, 0, sizeof(szPicFile));strncpy(szPicFile, pPicFile, sizeof(szPicFile));strncat(szPicFile, ".ppm", sizeof(szPicFile));// Convert the image from its native format to RGBimg_convert_ctx = sws_getContext(pCodecCtxDec->width, pCodecCtxDec->height, pCodecCtxDec->pix_fmt,pCodecCtxDec->width, pCodecCtxDec->height,AV_PIX_FMT_RGB24, SWS_FAST_BILINEAR, NULL, NULL, NULL);sws_scale(img_convert_ctx, pFrameDec->data, pFrameDec->linesize, 0,pCodecCtxDec->height, pFrameRGB->data, pFrameRGB->linesize);SaveFrameToPPM(szPicFile, pFrameRGB,pCodecCtxDec->width, pCodecCtxDec->height);sws_freeContext(img_convert_ctx);// ————frame to ppm end————// ————frame to jpg start————memset(szPicFile, 0, sizeof(szPicFile));strncpy(szPicFile, pPicFile, sizeof(szPicFile));strncat(szPicFile, ".jpg", sizeof(szPicFile));// Convert the image from its native format to RGBimg_convert_ctx = sws_getContext(pCodecCtxDec->width, pCodecCtxDec->height, pCodecCtxDec->pix_fmt,pCodecCtxDec->width, pCodecCtxDec->height,AV_PIX_FMT_RGB24, SWS_FAST_BILINEAR, NULL, NULL, NULL);sws_scale(img_convert_ctx, pFrameDec->data, pFrameDec->linesize, 0,pCodecCtxDec->height, pFrameRGB->data, pFrameRGB->linesize);// Save the frame to diskSaveFrameToJPG(szPicFile, pFrameRGB->data[0],pCodecCtxDec->width, pCodecCtxDec->height);sws_freeContext(img_convert_ctx);// ————frame to jpg end————break;}}}// Free the packet that was allocated by av_read_frameav_free_packet(&packet);}av_free(pFrameRGB);av_free(pBuffer);av_free(pFrameDec);return 0;}青春不是年华,而是心境;青春不是桃面丹唇柔膝,

I帧转图片(BMP、PPM、JPG)

相关文章:

你感兴趣的文章:

标签云: