天天看點

ffmpeg實作RGB封裝H264

最近想做ffmpeg的H264編碼,網上找了好久,多數都是跟這個一樣的http://blog.csdn.net/eightdegree/article/details/7425635,于是将其整理了下,下面貼出代碼

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

#include <stdio.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include<string.h>
#include<malloc.h>
//#include <SDL/SDL.h>
#pragma pack(1)

int main()
{
	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\n",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個位元組。
   BITMAPFILEHEADER *test=NULL;
    FILE *file[5];  
    char *szTxt[5];  
      
    int nWidth = 0;  
    int nHeight= 0;  
      
    int nDataLen=0;  
      
    int nLen;

    char csFileName[20];
    int fileI ; 
    for (fileI = 1; fileI <= 5; fileI ++)  
     {  
      sprintf(csFileName, "%d.bmp", fileI);
      printf("%s\n",csFileName);
      file[fileI - 1] = fopen(csFileName, "rb");
      
      	fseek(file[fileI-1],0,2);
      	nLen = ftell(file[fileI-1]);
      szTxt[fileI -1] = (char *)malloc(nLen);
      nLen = fread(szTxt[fileI-1],1,nLen,file[fileI-1]);
     
      
      fclose(file[fileI - 1]);  
      
     
     
      BITMAPFILEHEADER bmpFHeader;  
      BITMAPINFOHEADER bmpIHeader;
      
      test =  &bmpFHeader;
      memcpy(&bmpFHeader,szTxt[fileI -1],sizeof(BITMAPFILEHEADER));
      
      
      int nHeadLen = bmpFHeader.bfOffBits - sizeof(BITMAPFILEHEADER);
      
      memcpy(&bmpIHeader,szTxt[fileI - 1]+sizeof(BITMAPFILEHEADER),nHeadLen);  //nHeadLen
      
      nWidth = bmpIHeader.biWidth;
      nHeight = bmpIHeader.biHeight;
      
      szTxt[fileI - 1] += bmpFHeader.bfOffBits;  
      nDataLen = nLen-bmpFHeader.bfOffBits;  
     }  
    printf("file ok\n");
    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);  

      
    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("不能打開編碼庫");  
      
    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];  
      
    //圖象編碼  
    int outbuf_size=100000;  
    uint8_t * outbuf= (uint8_t*)malloc(outbuf_size);   
    int u_size = 0;  
    FILE *f=NULL;   
    const char * filename = "myData.h264";  
    f = fopen(filename, "wb");  
    if (!f)  
    {  
      printf( "could not open %s\n", filename);  
      exit(1);  
    }  
      
    //初始化SwsContext  
    SwsContext * 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 AVFrame  
    for (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 Frame  
      avpicture_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轉化為YUV  
      sws_scale(scxt,m_pRGBFrame->data,m_pRGBFrame->linesize,0,c->height,m_pYUVFrame->data,m_pYUVFrame->linesize);  
        
      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);  
      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); 
} 
           

程式可以跑,但是會報錯, 找不到X264編碼器,我已經裝了X264,并且重新編譯ffmpeg./configure --enable-libx264

不知道為什麼還是找不到X264編碼器,希望高手指點。