x264编解码

一 编码:

    网上有很多相关文章,这里不多讲了;

 

二:解码(这里解码为bmp):

    关于生成的x264的解码,这里用ffmpeg(就是现在的libav):

   1:下载ffmpeg配置好相应VC环境(我用的是VC6);

   2:下载ffmpegtutorial,这里有学习ffmpeg的例程,我们可以直接用Tutorial02就可以;

   3:修改Tutorial02中的解码部分,将相应的数据改为bmp数据,可以参考下面文章:

《利用FFmpeg将视频文件生成bmp图像帧》(转载自网络)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>

#include "avformat.h"
#include "avcodec.h"
#include "swscale.h"


#pragma comment (lib, "avcodec.lib")
#pragma comment (lib, "avformat.lib")
#pragma comment (lib, "avutil.lib")
#pragma comment (lib, "swscale.lib")


#ifndef _WINGDI_
#define _WINGDI_

typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;

#endif

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] = "R:\\test";
_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;
AVCodec *pCodec;
AVFrame *pFrame, *pFrameRGB;
struct SwsContext *pSwsCtx;
const char *filename = "test.avi";
AVPacket packet;
int frameFinished;
int PictureSize;
uint8_t *buf;

av_register_all();

if ( av_open_input_file(&pFormatCtx, filename, NULL, 0, NULL) != 0 )
{
printf ("av open input file failed!\n");
exit (1);
}

if ( av_find_stream_info(pFormatCtx) < 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 == CODEC_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_open(pCodecCtx, pCodec)<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 = 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_video(pCodecCtx, pFrame, &frameFinished, packet.data, packet.size);

if(frameFinished)
{
//反转图像
//*(pFrame->data[0]) = pCodecCtx->width * (pCodecCtx->height-1);
//pFrame ->linesize[0] = -(pCodecCtx->height);
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);
}

sws_freeContext (pSwsCtx);
av_free (pFrame);
av_free (pFrameRGB);
avcodec_close (pCodecCtx);
av_close_input_file (pFormatCtx);

return 0;
}

 

 

总结:解码生成bmp图像是为了可以更好的显示图像,方便与MFC结合。

          x264和ffmpeg和VC结合最简单的方法就是,分别生成相关的dll然后MFC调用显示,

         当然可以在MFC中配置这两个工程的相关条件,切记:MFC中包含C的头文件,要extern "C" {},

         如:

        

extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>

#include <libsdl/SDL.h>
#include <libsdl/SDL_thread.h>
}

 下面给出 Tutorial02 与 MFC结合的代码:

 配置好相应的 文件路径,Lib库文件路径,dll文件路径(直接将bin目下的所有文件copy到当前工程中就可以了),以下是源码:


#define _SDL_config_win32_h //解决重定义冲突;

extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>

#include <libsdl/SDL.h>
#include <libsdl/SDL_thread.h>
}


#if defined __MINGW32__ || defined WIN32
#undef main /* Prevents SDL from overriding main() */
#endif

#include <stdio.h>
void CMfcffmpegDlg::OnButtonFFmpeg()
{
 // TODO: Add your control notification handler code here
 
  AVFormatContext *pFormatCtx;
  int             i, videoStream;
  AVCodecContext  *pCodecCtx;
  AVCodec         *pCodec;
  AVFrame         *pFrame;
  AVPacket        packet;
  int             frameFinished;
  float           aspect_ratio;

  SDL_Overlay     *bmp;
  SDL_Surface     *screen;
  SDL_Rect        rect;
  SDL_Event       event;

 AVPicture pict; 

 static int sws_flags = SWS_BICUBIC;
     struct SwsContext *img_convert_ctx;

 int  argc = 2;
  char * argv = "f:\\video.avi";
 
 
  // Register all formats and codecs
  av_register_all();
 
  if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
    fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
    exit(1);
  }

  // Open video file
  if(av_open_input_file(&pFormatCtx, argv, NULL, 0, NULL)!=0)
    return ; // Couldn't open file
 
  // Retrieve stream information
  if(av_find_stream_info(pFormatCtx)<0)
    return ; // Couldn't find stream information
 
  // Dump information about file onto standard error
  dump_format(pFormatCtx, 0, argv, 0);
 
  // Find the first video stream
  videoStream=-1;
  for(i=0; i<pFormatCtx->nb_streams; i++)
    if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO)
 {
      videoStream=i;
      break;
    }
  if(videoStream==-1)
    return ; // Didn't find a video stream
 
  // Get a pointer to the codec context for the video stream
  pCodecCtx=pFormatCtx->streams[videoStream]->codec;
 
  // Find the decoder for the video stream
  pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
  if(pCodec==NULL)
  {
    fprintf(stderr, "Unsupported codec!\n");
    return ; // Codec not found
  }
 
  // Open codec
  if(avcodec_open(pCodecCtx, pCodec)<0)
    return ; // Could not open codec
 
  // Allocate video frame
  pFrame=avcodec_alloc_frame();

  // Make a screen to put our video
#ifndef __DARWIN__
        screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, 0);
#else
        screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 24, 0);
#endif
  if(!screen) {
    fprintf(stderr, "SDL: could not set video mode - exiting\n");
    exit(1);
  }
 
  // Allocate a place to put our YUV image on that screen
  bmp = SDL_CreateYUVOverlay(pCodecCtx->width,
     pCodecCtx->height,
     SDL_YV12_OVERLAY,
     screen);


  // Read frames and save first five frames to disk
  i=0;
  while(av_read_frame(pFormatCtx, &packet)>=0)
  {
    // Is this a packet from the video stream?
    if(packet.stream_index==videoStream)
 {
      // Decode video frame
      avcodec_decode_video(pCodecCtx, pFrame, &frameFinished, packet.data, packet.size);     
     
      // Did we get a video frame?
      if(frameFinished)
   {
    SDL_LockYUVOverlay(bmp);
   
    pict.data[0] = bmp->pixels[0];
    pict.data[1] = bmp->pixels[2];
    pict.data[2] = bmp->pixels[1];
   
    pict.linesize[0] = bmp->pitches[0];
    pict.linesize[1] = bmp->pitches[2];
    pict.linesize[2] = bmp->pitches[1];

#if 0
 // Convert the image into YUV format that SDL uses
 img_convert(&pict, PIX_FMT_YUV420P,
                    (AVPicture *)pFrame, pCodecCtx->pix_fmt,
      pCodecCtx->width, pCodecCtx->height);
#else
  /*   img_convert(&pict, dst_pix_fmt,
        (AVPicture *)pFrame, is->video_st->codec->pix_fmt,
        is->video_st->codec->width, is->video_st->codec->height);
  */


       img_convert_ctx = sws_getContext( pCodecCtx->width,
           pCodecCtx->height,
                                            pCodecCtx->pix_fmt,
                                            pCodecCtx->width,
           pCodecCtx->height,
                                            PIX_FMT_YUV420P,
                                            sws_flags, NULL, NULL, NULL);

       sws_scale (img_convert_ctx, pFrame->data, pFrame->linesize,
           0, pCodecCtx->height,
           pict.data,pict.linesize);
       sws_freeContext(img_convert_ctx);
#endif
 SDL_UnlockYUVOverlay(bmp);
 
 rect.x = 0;
 rect.y = 0;
 rect.w = pCodecCtx->width;
 rect.h = pCodecCtx->height;
 SDL_DisplayYUVOverlay(bmp, &rect);
     
      }
    }
   
    // Free the packet that was allocated by av_read_frame
    av_free_packet(&packet);
    SDL_PollEvent(&event);
    switch(event.type) {
    case SDL_QUIT:
      SDL_Quit();
      exit(0);
      break;
    default:
      break;
    }
 //SDL_Delay(40);
  }
 
  // Free the YUV frame
  av_free(pFrame);
 
  // Close the codec
  avcodec_close(pCodecCtx);
 
  // Close the video file
  av_close_input_file(pFormatCtx);
 

}

 注:直接到ffmpeg网站下载x264解码VC工程源代码,最方便了;

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chinabinlang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值