ffmpeg编译,解码 H264

转至:http://my.csdn.net/easymob/code/detail/15723

项目需要,要做PC端的解码器,解H264。
  
一直郁闷,终于今天搞定了。记录如下: 
  
1,找了两个网站: 
  
http://ffdshow-tryout.sourceforge.net/wiki/devel:building 这个,是k-lite的
  
http://ffmpeg.zeranoe.com/builds/ 这个,是windows平台编译ffmpeg的。此为关键
  
   
  
仔细阅读第二个网页。 
  
下载最新的库和代码。 
  
然后,代码中,有一个doc/examples/decoding_encoding.c。
  
这个文件,简明的介绍了如何解码。 
  
然后,将该文件中需要的部分,移植到VC中编译即可。
  
  
编译过程: 
错误一:无法打开包括文件:“inttypes.h”: No such file or directory
解决方法:删除之,并在其之前添加如下代码:
  
#if defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
#      define CONFIG_WIN32
#endif 
#if defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(EMULATE_INTTYPES)
#      define EMULATE_INTTYPES
#endif 
#ifndef EMULATE_INTTYPES
#     include <inttypes.h>
#else 
      typedefsigned char   int8_t; 
      typedefsigned shortint16_t; 
      typedefsigned int    int32_t; 
      typedefunsigned char   uint8_t; 
      typedefunsigned shortuint16_t; 
      typedefunsigned int    uint32_t; 
#     ifdef CONFIG_WIN32
          typedefsigned __int64    int64_t; 
          typedefunsigned __int64uint64_t; 
#     else /* other OS */
          typedefsigned longlong     int64_t; 
          typedefunsigned longlong uint64_t; 
#     endif /* other OS */
#endif /* EMULATE_INTTYPES */
  
错误二: error C3861: “UINT64_C”: 找不到标识符
解决方法:在common.h中添加如下代码:
  
#ifndef INT64_C
#define INT64_C(c) (c ## LL)
#define UINT64_C(c) (c ## ULL)
#endif 
   
  
修改的部分: 
  
1,解码器,改成CODEC_ID_H264
  
2,avpkt.size = fread(inbuf, 1, INBUF_SIZE, f);这个地方需要修改。要按它的帧来读。这部分期望的做法是什么还不清楚,但按原来的读法是不行的。
  
其它就没啥特别的了。 
  
   
  
把修改后的代码贴在这里: 
  
// decoder_ffmpeg.cpp : 定义控制台应用程序的入口点。
// 
  
#include "stdafx.h"
  
#ifdef __cplusplus
extern"C"{ 
#endif 
  
#include "libavutil/imgutils.h"
#include "libavutil/opt.h"
#include "libavcodec/avcodec.h"
#include "libavutil/mathematics.h"
#include "libavutil/samplefmt.h"
  
#ifdef __cplusplus
} 
#endif 
  
#define INBUF_SIZE (4096)
  
  
/* 
 * Video decoding example
 */
  
staticvoid pgm_save(unsignedchar *buf, int wrap, intxsize, int ysize, 
                     FILE*f) 
{ 
    inti; 
 //buf += 64;
    //fprintf(f,"P5n%d %dn%dn",xsize,ysize,255);
    for(i=0;i<ysize;i++)
        fwrite(buf + i * wrap,1,xsize,f);
} 
  
staticint _find_head(unsignedchar *buffer,int len) 
{ 
 inti; 
 intj; 
   
 for(i=512;i<len;i++) 
 {
     if(buffer[i] == 0 
       && buffer[i+1] == 0
       && buffer[i+2] == 0
       && buffer[i+3] == 1)
       break;
 }
 if(i == len) 
  return0; 
 if(i == 512) 
  return0; 
 returni; 
} 
#define FILE_READING_BUFFER (1*1024*1024)
staticvoid build_avpkt(AVPacket *avpkt,FILE *fp) 
{ 
#if 0 
     intlen; 
     staticunsigned charbuffer[INBUF_SIZE]; 
     len =fread(buffer, 1, INBUF_SIZE, fp);
     avpkt->data = buffer;
     avpkt->size = len;
#else 
     staticunsigned charbuffer[1*1024*1024]; 
     staticint readptr = 0; 
     staticint writeptr = 0; 
     intlen,toread; 
  
     intnexthead; 
  
     if(writeptr - readptr < 200 * 1024) 
     {
          memmove(buffer, &buffer[readptr], writeptr - readptr);
          writeptr -= readptr;
          readptr = 0;
          toread = FILE_READING_BUFFER - writeptr;
          len =fread(&buffer[writeptr], 1, toread, fp);
          writeptr += len;
     }
  
     nexthead = _find_head(&buffer[readptr], writeptr-readptr);
     if(nexthead == 0) 
     {
         printf("failed find next head...n");
         nexthead = writeptr - readptr;
     }
  
     avpkt->size = nexthead;
     avpkt->data = &buffer[readptr];
     readptr += nexthead;
#endif 
} 
  
staticvoid video_decode_example(constchar *outfilename, const char*filename) 
{ 
    AVCodec *codec;
    AVCodecContext *c= NULL;
    intframe, got_picture, len; 
    FILE*f, *fout; 
    AVFrame *picture;
    uint8_t inbuf[INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
    charbuf[1024]; 
    AVPacket avpkt;
    AVDictionary *opts;
  
    av_init_packet(&avpkt);
  
    /* set end of buffer to 0 (this ensures that no overreading happens for damaged mpeg streams) */
    memset(inbuf + INBUF_SIZE, 0, FF_INPUT_BUFFER_PADDING_SIZE);
  
    printf("Video decodingn");
    opts = NULL;
    //av_dict_set(&opts, "b", "2.5M", 0);
    /* find the mpeg1 video decoder */
    codec = avcodec_find_decoder(CODEC_ID_H264);
    if(!codec) { 
        fprintf(stderr,"codec not foundn");
        exit(1);
    }
  
    c = avcodec_alloc_context3(codec);
    picture= avcodec_alloc_frame();
  
    if(codec->capabilities&CODEC_CAP_TRUNCATED)
        c->flags|= CODEC_FLAG_TRUNCATED;/* we do not send complete frames */
  
    /* For some codecs, such as msmpeg4 and mpeg4, width and height
       MUST be initialized there because this information is not
       available in the bitstream. */
  
    /* open it */
    if(avcodec_open2(c, codec, NULL) < 0) { 
        fprintf(stderr,"could not open codecn");
        exit(1);
    }
  
   
    fout=fopen(outfilename,"wb");
    /* the codec gives us the frame size, in samples */
  
    f =fopen(filename,"rb"); 
    if(!f) { 
        fprintf(stderr,"could not open %sn", filename);
        exit(1);
    }
  
    frame = 0;
    for(;;) {
        //avpkt.size = fread(inbuf, 1, INBUF_SIZE, f);
        build_avpkt(&avpkt, f);
        if(avpkt.size == 0) 
            break;
  
        /* NOTE1: some codecs are stream based (mpegvideo, mpegaudio)
           and this is the only method to use them because you cannot
           know the compressed data size before analysing it.
  
           BUT some other codecs (msmpeg4, mpeg4) are inherently frame
           based, so you must call them with all the data for one
           frame exactly. You must also initialize 'width' and
           'height' before initializing them. */
  
        /* NOTE2: some codecs allow the raw parameters (frame size,
           sample rate) to be changed at any frame. We handle this, so
           you should also take care of it */
  
        /* here, we use a stream based decoder (mpeg1video), so we
           feed decoder and see if it could decode a frame */
        //avpkt.data = inbuf;
        while(avpkt.size > 0) { 
            len = avcodec_decode_video2(c, picture, &got_picture, &avpkt);
            if(len < 0) { 
                fprintf(stderr,"Error while decoding frame %dn", frame);
                break;
                //   exit(1);
            }
            if(got_picture) { 
                printf("saving frame %3dn", frame);
                fflush(stdout);
  
                /* the picture is allocated by the decoder. no need to
                   free it */
                sprintf(buf, outfilename, frame);
                pgm_save(picture->data[0], picture->linesize[0],
                         c->width, c->height, fout);
                pgm_save(picture->data[1], picture->linesize[1],
                         c->width/2, c->height/2, fout);
                pgm_save(picture->data[2], picture->linesize[2],
                         c->width/2, c->height/2, fout);
                frame++;
            }
            avpkt.size -= len;
            avpkt.data += len;
        }
    }
  
    /* some codecs, such as MPEG, transmit the I and P frame with a
       latency of one frame. You must do the following to have a
       chance to get the last frame of the video */
    avpkt.data = NULL;
    avpkt.size = 0;
    len = avcodec_decode_video2(c, picture, &got_picture, &avpkt);
    if(got_picture) { 
        printf("saving last frame %3dn", frame);
        fflush(stdout);
  
        /* the picture is allocated by the decoder. no need to
           free it */
        sprintf(buf, outfilename, frame);
        //pgm_save(picture->data[0], picture->linesize[0],
          //       c->width, c->height, fout);
                 pgm_save(picture->data[0], picture->linesize[0],c->width, c->height, fout);
    pgm_save(picture->data[1], picture->linesize[1],c->width/2, c->height/2, fout);
    pgm_save(picture->data[2], picture->linesize[2],c->width/2, c->height/2, fout);
  
  frame++;
    }
  
    fclose(f);
 fclose(fout);
  
    avcodec_close(c);
    av_free(c);
    av_free(picture);
    printf("n");
} 
  
  
int_tmain(int argc, _TCHAR* argv[]) 
{ 
     printf("hello worldn");
     avcodec_register_all();
     video_decode_example("d:\output.yuv","d:\record.h264");
     return0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值