使用ffmpeg將BMP圖片編碼為x264視頻檔案,將H264視頻儲存為BMP圖片,
ffmpeg開源庫,實現將bmp格式的圖片編碼成x264檔案,並將編碼好的H264檔案解碼儲存為BMP檔案。 自己根據部落格的代碼,vs2010搭建的測試環境。資源下載 具體代碼:
#define _AFXDLL #include<afxwin.h> #ifdef __cplusplusextern "C" {#endif#include <libavcodec/avcodec.h>#include <libavformat/avformat.h>#include <libswscale/swscale.h>void main(){CFile file[5];BYTE *szTxt[5];int nWidth = 0;int nHeight= 0;int nDataLen=0;int nLen;CString csFileName;for (int fileI = 1; fileI <= 5; fileI ++){csFileName.Format("%d.bmp", fileI);file[fileI - 1].Open(csFileName,CFile::modeRead | CFile::typeBinary);nLen = file[fileI - 1].GetLength();szTxt[fileI -1] = new BYTE[nLen];file[fileI - 1].Read(szTxt[fileI - 1], nLen);file[fileI - 1].Close();//BMP bmi;//BITMAPINFO bmi;//int nHeadLen = sizeof(BMP);BITMAPFILEHEADER bmpFHeader;BITMAPINFOHEADER bmpIHeader;memcpy(&bmpFHeader,szTxt[fileI -1],sizeof(BITMAPFILEHEADER));int nHeadLen = bmpFHeader.bfOffBits - sizeof(BITMAPFILEHEADER);memcpy(&bmpIHeader,szTxt[fileI - 1]+sizeof(BITMAPFILEHEADER),nHeadLen);nWidth = bmpIHeader.biWidth;// 464;// bmi.bmpInfo.bmiHeader.biWidth;// ;nHeight = bmpIHeader.biHeight;//362;// bmi.bmpInfo.bmiHeader.biHeight;// ;szTxt[fileI - 1] += bmpFHeader.bfOffBits;nDataLen = nLen-bmpFHeader.bfOffBits;}getchar();av_register_all();avcodec_register_all();AVFrame *m_pRGBFrame = new AVFrame[1]; //RGB幀資料 AVFrame *m_pYUVFrame = new AVFrame[1];; //YUV幀資料AVCodecContext *c= NULL;AVCodecContext *in_c= NULL;AVCodec *pCodecH264; //編碼器uint8_t * yuv_buff;////尋找h264編碼器pCodecH264 = avcodec_find_encoder(CODEC_ID_H264);if(!pCodecH264){fprintf(stderr, "h264 codec not found\n");getchar();exit(1);}c= avcodec_alloc_context3(pCodecH264);c->bit_rate = 3000000;// put sample parameters c->width =nWidth;// c->height = nHeight;// // frames per second AVRational rate;rate.num = 1;rate.den = 25;c->time_base= rate;//(AVRational){1,25};c->gop_size = 10; // emit one intra frame every ten frames c->max_b_frames=1;c->thread_count = 1;c->pix_fmt = PIX_FMT_YUV420P;//PIX_FMT_RGB24;//av_opt_set(c->priv_data, /*"preset"*/"libvpx-1080p.ffpreset", /*"slow"*/NULL, 0);//開啟編碼器if(avcodec_open2(c,pCodecH264,NULL)<0){printf("avcodec_open2 failed\n");TRACE("不能開啟編碼庫");getchar();}int size = c->width * c->height;yuv_buff = (uint8_t *) malloc((size * 3) / 2); // size for YUV 420 //將rgb映像資料填充rgb幀uint8_t * rgb_buff = new uint8_t[nDataLen];//圖象編碼 outbuf_size太小會報錯,映像清晰度也會差int outbuf_size = 900000;uint8_t * outbuf= (uint8_t*)malloc(outbuf_size); int u_size = 0;FILE *f=NULL; char * filename = "myData.h264";f = fopen(filename, "wb");if (!f){TRACE( "could not open %s\n", filename);getchar();exit(1);}//初始化SwsContextSwsContext * scxt = sws_getContext(c->width,c->height,PIX_FMT_BGR24,c->width,c->height,PIX_FMT_YUV420P,SWS_POINT,NULL,NULL,NULL);AVPacket avpkt;//AVFrame *pTFrame=new AVFramefor (int i=0;i<250;++i){//AVFrame *m_pYUVFrame = new AVFrame[1];int index = (i / 25) % 5;memcpy(rgb_buff,szTxt[index],nDataLen);avpicture_fill((AVPicture*)m_pRGBFrame, (uint8_t*)rgb_buff, PIX_FMT_RGB24, nWidth, nHeight);//將YUV buffer 填充YUV Frameavpicture_fill((AVPicture*)m_pYUVFrame, (uint8_t*)yuv_buff, PIX_FMT_YUV420P, nWidth, nHeight);// 翻轉RGB映像m_pRGBFrame->data[0] += m_pRGBFrame->linesize[0] * (nHeight - 1);m_pRGBFrame->linesize[0] *= -1; m_pRGBFrame->data[1] += m_pRGBFrame->linesize[1] * (nHeight / 2 - 1);m_pRGBFrame->linesize[1] *= -1;m_pRGBFrame->data[2] += m_pRGBFrame->linesize[2] * (nHeight / 2 - 1);m_pRGBFrame->linesize[2] *= -1;//將RGB轉化為YUVsws_scale(scxt,m_pRGBFrame->data,m_pRGBFrame->linesize,0,c->height,m_pYUVFrame->data,m_pYUVFrame->linesize);static int got_packet_ptr = 0;av_init_packet(&avpkt);avpkt.data = outbuf;avpkt.size = outbuf_size;u_size = avcodec_encode_video2(c, &avpkt, m_pYUVFrame, &got_packet_ptr);m_pYUVFrame->pts++;if (u_size == 0){fwrite(avpkt.data, 1, avpkt.size, f);}}fclose(f); delete []m_pRGBFrame;delete []m_pYUVFrame;delete []rgb_buff;free(outbuf);avcodec_close(c);av_free(c);}#ifdef __cplusplus}#endif
完全按照部落格中的代碼測試發現會報下面的資訊,而且在播放過程中,畫面都是模糊的。修改了outbuff_size的大小解決了這個問題。
疑問:為什麼要迴圈250次?有知道麻煩解答下!
for (int i=0;i<250;++i)
將H264視頻儲存為BMP圖片,具體代碼如下:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <windows.h>#ifdef __cplusplusextern "C" {#endif#include <libavcodec/avcodec.h>#include <libavformat/avformat.h>#include <libswscale/swscale.h>void SaveAsBMP (AVFrame *pFrameRGB, int width, int height, int index, int bpp){char buf[5] = {0};BITMAPFILEHEADER bmpheader;BITMAPINFOHEADER bmpinfo;FILE *fp;char filename[20] = "";_itoa (index, buf, 10);strcat (filename, buf);strcat (filename, ".bmp");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 = NULL;AVCodec *pCodec;AVFrame *pFrame, *pFrameRGB;struct SwsContext *pSwsCtx;const char *filename = "myData.h264";AVPacket packet;int frameFinished;int PictureSize;uint8_t *buf;av_register_all();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 = avcodec_alloc_frame();pFrameRGB = avcodec_alloc_frame();if ( (pFrame == NULL)||(pFrameRGB == NULL) ){printf("avcodec alloc frame failed!\n");exit (1);}PictureSize = avpicture_get_size (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, PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height);pSwsCtx = sws_getContext (pCodecCtx->width,pCodecCtx->height,pCodecCtx->pix_fmt,pCodecCtx->width,pCodecCtx->height,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;sws_scale (pSwsCtx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);SaveAsBMP (pFrameRGB, pCodecCtx->width, pCodecCtx->height, i++, 24);} }av_free_packet(&packet);}while(1){ packet.data = NULL; packet.size = 0; 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;sws_scale (pSwsCtx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);SaveAsBMP (pFrameRGB, pCodecCtx->width, pCodecCtx->height, i++, 24);}else{break;}av_free_packet(&packet); } sws_freeContext (pSwsCtx);av_free (pFrame);av_free (pFrameRGB);avcodec_close (pCodecCtx);avformat_close_input (&pFormatCtx);return 0;}#ifdef __cplusplus}#endif
參考資料:http://blog.csdn.net/eightdegree/article/details/7425635#reply