ffmpeg学习

来源:互联网 发布:淘宝美女店主 下海 编辑:程序博客网 时间:2024/06/05 17:57
ffmpeg_纯净版 是2.1.1版本


H264_cavlc.c
中ff_h264_decode_mb_cavlc函数


ff_h264_decode_mb_cavlc函数中
1054行
if(!IS_INTRA16x16(mb_type)){
1081行
if(cbp || IS_INTRA16x16(mb_type)){


581行(加入)
printf("123\n");


(加入)
FILE *tp_dct_rem=fopen("dct.txt","a+");
fprintf(tp_dct_rem,"123");


ffmpeg_非纯净版
Ffmpeg.c:static int output_packet(InputStream *ist, const AVPacket *pkt)


Avcodec.h (libavcodec):int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,...)


H264.c (libavcodec):static int decode_frame(AVCodecContext *avctx, void *data,...)


H264.c (libavcodec):static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size,int parse_extradata)


H264.c (libavcodec):static int execute_decode_slices(H264Context *h, int context_count)        ->  return decode_slice(avctx, &h);


H264.c (libavcodec):static int decode_slice(struct AVCodecContext *avctx, void *arg)        -> int ret = ff_h264_decode_mb_cavlc(h);


H264.c (libavcodec):            int ret = ff_h264_decode_mb_cavlc(h);
H264.c (libavcodec):                ret = ff_h264_decode_mb_cavlc(h);


H264_cavlc.c (libavcodec):  int ff_h264_decode_mb_cavlc(H264Context *h)                       ->decode_luma_residual();decode_residual();


decode_luma_residual()    ->decode_residual();


H264_cavlc.c (libavcodec):  static int decode_residual(H264Context *h, GetBitContext *gb, int16_t *block, int n, const uint8_t *scantable, const uint32_t *qmul, int max_coeff)


参考:
http://www.douban.com/note/228831821/
http://wenku.baidu.com/link?url=YLSrL9aTK5ATaMXe8fRTDahKqvbqC7QwZ6C15vMxGQ7ga2fGAEep3F1DBqD7IftCi-FFcG_fcfGN9MuplEo_mHWiOiu880zeyQQ6zsa-9wq


AVCodecContext:
    这是一个描述编解码器上下文的数据结构,包含了众多编解码器需要的参数信息


typedef struct AVStream:
该结构体描述一个媒体流


AVFormatContext
        这个结构体描述了一个媒体文件或媒体流的构成和基本信息
这是FFMpeg中最为基本的一个结构,是其他所有结构的根,是一个多媒体文件或流的根本抽象。


AVPacket定义在avcodec.h中
FFMPEG使用AVPacket来暂存解复用之后、解码之前的媒体数据(一个音/视频帧、一个字幕包等)及附加信息(解码时间戳、显示时间戳、时长等)。


AVFrame是定义在avcodec.h中的一个数据结构:
        typedef struct AVFrame {
            FF_COMMON_FRAME
        } AVFrame;


avcodec_decode_video2
        int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture, int *got_picture_ptr, AVPacket *avpkt);
        解码一个视频帧。got_picture_ptr指示是否有解码数据输出。
        输入数据在AVPacket结构中,输出数据在AVFrame结构中。


派生关系
AVFormatContext->AVStream->AVCodecContext->AVCodec
AVOutPutFormator,AVInPutFormat
AVFrame->AVPicture->AVPacket


Coded_block_pattern,即CBP,指亮度和色度分量的各小块的残差的编码方案。
所谓的残差方案包括:
(1)       所有残差(包括DC、AC)都编码。
(2)       只对DC系数编码。
(3)       所有残差(包括DC、AC)都不编码。
对于非帧内16*16的宏块类型:
CodedBlockPatternLuma = coded_block_pattern % 16
CodedBlockPatternChroma = coded_block_pattern / 16
对于帧内16*16的宏块类型,CodedBlockPatternLuma和CodedBlockPatternChroma 的值不是由本句法元素给出,而是通过mb_type得到的。


max_coeff: 
number of coefficients in the block


param n :
block index


coeff_token:句法元素
total_coeff:非零系数的数目
uint32_t:32位无符号整数
const uint32_t *qmul
const uint8_t *scantable


static VLC chroma_dc_coeff_token_vlc;
typedef struct VLC {
    int bits;
    VLC_TYPE (*table)[2]; ///< code, bits
    int table_size, table_allocated;
} VLC;
#define VLC_TYPE int16_t


#define CHROMA_DC_COEFF_TOKEN_VLC_BITS 8


以下面这个为主:
static av_always_inline int get_vlc2(GetBitContext *s, VLC_TYPE (*table)[2],int bits, int max_depth)
{
    int code;


    OPEN_READER(re, s);
    UPDATE_CACHE(re, s);


    GET_VLC(code, re, s, table, bits, max_depth);


    CLOSE_READER(re, s);


    return code;
}


#define get_vlc2(s, tab, bits, max) get_vlc_trace(s,          tab,        bits, max, __FILE__, __PRETTY_FUNCTION__, __LINE__)


total_coeff由coeff_token求得:
total_coeff= coeff_token>>2;


trailing_ones由coeff_token求得:
trailing_ones= coeff_token&3;


static inline unsigned int show_bits(GetBitContext *s, int n)
{
    register int tmp;
    OPEN_READER(re, s);
    av_assert2(n>0 && n<=25);
    UPDATE_CACHE(re, s);
    tmp = SHOW_UBITS(re, s, n);
    return tmp;
}
#ifdef BITSTREAM_READER_LE
#   define SHOW_UBITS(name, gb, num) zero_extend(name ## _cache, num)
#   define SHOW_SBITS(name, gb, num) sign_extend(name ## _cache, num)
#else
#   define SHOW_UBITS(name, gb, num) NEG_USR32(name ## _cache, num)
#   define SHOW_SBITS(name, gb, num) NEG_SSR32(name ## _cache, num)
#endif
static inline av_const unsigned zero_extend(unsigned val, unsigned bits)
{
    return (val << ((8 * sizeof(int)) - bits)) >> ((8 * sizeof(int)) - bits);
}


static inline void skip_bits(GetBitContext *s, int n)
{
    OPEN_READER(re, s);
    UPDATE_CACHE(re, s);
    LAST_SKIP_BITS(re, s, n);
    CLOSE_READER(re, s);
}
#define LAST_SKIP_BITS(name, gb, num) SKIP_COUNTER(name, gb, num)
#   define SKIP_COUNTER(name, gb, num) name ## _index += (num)


前3个幅值由i给出:
    level[0] = 1-((i&4)>>1);
    level[1] = 1-((i&2)   );
    level[2] = 1-((i&1)<<1);


zeros_left由get_vlc2()求出:
zeros_left = get_vlc2();


run_before由get_vlc2()求出:
run_before= get_vlc2();


level[]由level_code求出:
level[trailing_ones]= level_code;


int pixel_shift;    ///< 0 for 8-bit H264, 1 for high-bit-depth H264


#define LUMA_DC_BLOCK_INDEX   48


((type*)block)[*scantable] = level[0];
((type*)block)[*scantable]= level[i];


修改((type*)block)[*scantable]值,都是幅值。


*scantable最大多少?
最大为total_coeff
total_coeff由coeff_token求得:
total_coeff= coeff_token>>2;
coeff_token = get_vlc2();


usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...


服务器上ffmpeg/ffmpeg-最终版本 学习:
//初始化变量
    FILE *tp_dct_cjx;  
    int coeff[16];
    int column[16]={0,4,8,12,1,5,9,13,2,6,10,14,3,7,11,15};
    memset(coeff,0,sizeof(coeff));
    if((tp_dct_cjx=fopen("dct.txt","a+"))==NULL)
    {
     
        printf("can not open file\n");
    }


//反量化之前取level[0]到coeff[]中
else{
    //printf("4'5'6'\n");
    if ((h->luma_flag==1)&&(!IS_8x8DCT(h->hua_mb_type)))
     { 
     coeff[column[*scantable]]=level[0];
      }


 ((int16_t*)block)[*scantable] = ((int)(level[0] * qmul[*scantable] + 32))>>6;


//反量化之前取level[i]到coeff[]中
if ((h->luma_flag==1)&&(!IS_8x8DCT(h->hua_mb_type)))
          {
                    coeff[column[*scantable]]=level[i];
          }
            ((int16_t*)block)[*scantable]= ((int)(level[i] * qmul[*scantable] + 32))>>6;


//反量化之前取level[i]到coeff[]中
if ((h->luma_flag==1)&&(!IS_8x8DCT(h->hua_mb_type)))
       { 
          coeff[column[*scantable]]=level[i];
       } 
            ((int16_t*)block)[*scantable]= ((int)(level[i] * qmul[*scantable] + 32))>>6;


//把coeff[]中值写入文件dct.txt
 if ((h->luma_flag)&&(!IS_8x8DCT(h->hua_mb_type)))
     {
       for(i=0;i<16;i++)
       {
        if(i%16==0)
         {
          fprintf(tp_dct_cjx,"\r\n");
         }
        fprintf(tp_dct_cjx,"%4d",coeff[i]);
       }
    }


//关闭文件
fclose(tp_dct_cjx);
    return 0;


//if条件h->luma_flag  和 !IS_8x8DCT(h->hua_mb_type)
int hua_mb_type;
int luma_flag;


//Search luma_flag
luma_flag Matches (10 in 3 files) ----
H264.h (libavcodec):int luma_flag;
H264_cavlc.c (libavcodec):    if ((h->luma_flag==1)&&(!IS_8x8DCT(h->hua_mb_type)))
H264_cavlc.c (libavcodec):           if ((h->luma_flag==1)&&(!IS_8x8DCT(h->hua_mb_type)))
H264_cavlc.c (libavcodec):      if ((h->luma_flag==1)&&(!IS_8x8DCT(h->hua_mb_type)))
H264_cavlc.c (libavcodec):     if ((h->luma_flag)&&(!IS_8x8DCT(h->hua_mb_type)))
H264_cavlc.c (libavcodec):h->luma_flag=1;
H264_cavlc.c (libavcodec):h->luma_flag=0;
H264_cavlc.c (libavcodec):h->luma_flag=0;
H264_cavlc.c (libavcodec):h->luma_flag=0;
Vaapi_vc1.c (libavcodec):    pic_param->range_mapping_fields.bits.luma_flag                  = v->range_mapy_flag;


//2个函数修改了h->luma_flag值
static av_always_inline int decode_luma_residual(H264Context *h, GetBitContext *gb, const uint8_t *scan, const uint8_t *scan8x8, int pixel_shift, int mb_type, int cbp, int p){
 int i4x4, i8x8;
    int qscale = p == 0 ? h->qscale : h->chroma_qp[p-1];
h->luma_flag=1;
...
h->luma_flag=0;
}


int ff_h264_decode_mb_cavlc(H264Context *h){
if(cbp&0x30){
h->luma_flag=0;            
            if(cbp&0x20){
h->luma_flag=0;


//Search hua_mb_type
- hua_mb_type Matches (8 in 2 files) ----
H264.h (libavcodec):int hua_mb_type;
H264_cavlc.c (libavcodec):    if ((h->luma_flag==1)&&(!IS_8x8DCT(h->hua_mb_type)))
H264_cavlc.c (libavcodec):           if ((h->luma_flag==1)&&(!IS_8x8DCT(h->hua_mb_type)))
H264_cavlc.c (libavcodec):      if ((h->luma_flag==1)&&(!IS_8x8DCT(h->hua_mb_type)))
H264_cavlc.c (libavcodec):     if ((h->luma_flag)&&(!IS_8x8DCT(h->hua_mb_type)))
H264_cavlc.c (libavcodec):h->hua_mb_type=mb_type;
H264_cavlc.c (libavcodec):h->hua_mb_type=mb_type;
H264_cavlc.c (libavcodec):h->hua_mb_type=mb_type;


//1个函数修改了h->luma_flag值
int ff_h264_decode_mb_cavlc(H264Context *h){


if(h->slice_type_nos == AV_PICTURE_TYPE_B){
        if(mb_type < 23){
            partition_count= b_mb_type_info[mb_type].partition_count;
            mb_type=         b_mb_type_info[mb_type].type;
h->hua_mb_type=mb_type;
        }else{
            mb_type -= 23;
            goto decode_intra_mb;
        }
    }else if(h->slice_type_nos == AV_PICTURE_TYPE_P){
        if(mb_type < 5){
            partition_count= p_mb_type_info[mb_type].partition_count;
            mb_type=         p_mb_type_info[mb_type].type;
h->hua_mb_type=mb_type;
        }else{
            mb_type -= 5;
            goto decode_intra_mb;
        }
     }else{
       av_assert2(h->slice_type_nos == AV_PICTURE_TYPE_I);
        if(h->slice_type == AV_PICTURE_TYPE_SI && mb_type)
            mb_type--;
decode_intra_mb:
        if(mb_type > 25){
            av_log(h->avctx, AV_LOG_ERROR, "mb_type %d in %c slice too large at %d %d\n", mb_type, av_get_picture_type_char(h->slice_type), h->mb_x, h->mb_y);
            return -1;
        }
        partition_count=0;
        cbp= i_mb_type_info[mb_type].cbp;
        h->intra16x16_pred_mode= i_mb_type_info[mb_type].pred_mode;
        mb_type= i_mb_type_info[mb_type].type;
h->hua_mb_type=mb_type;
    }


//if条件
if ((h->luma_flag==1)&&(!IS_8x8DCT(h->hua_mb_type))&&(IS_INTRA4x4(h->hua_mb_type))&&(h->slice_type_nos==AV_PICTURE_TYPE_I))


//i_mb_type_info
static const IMbInfo i_mb_type_info[26] = {
    { MB_TYPE_INTRA4x4,  -1,  -1 },
    { MB_TYPE_INTRA16x16, 2,   0 },
    { MB_TYPE_INTRA16x16, 1,   0 },
    { MB_TYPE_INTRA16x16, 0,   0 },
    { MB_TYPE_INTRA16x16, 3,   0 },
    { MB_TYPE_INTRA16x16, 2,  16 },
    { MB_TYPE_INTRA16x16, 1,  16 },
    { MB_TYPE_INTRA16x16, 0,  16 },
    { MB_TYPE_INTRA16x16, 3,  16 },
    { MB_TYPE_INTRA16x16, 2,  32 },
    { MB_TYPE_INTRA16x16, 1,  32 },
    { MB_TYPE_INTRA16x16, 0,  32 },
    { MB_TYPE_INTRA16x16, 3,  32 },
    { MB_TYPE_INTRA16x16, 2,  15 +  0 },
    { MB_TYPE_INTRA16x16, 1,  15 +  0 },
    { MB_TYPE_INTRA16x16, 0,  15 +  0 },
    { MB_TYPE_INTRA16x16, 3,  15 +  0 },
    { MB_TYPE_INTRA16x16, 2,  15 + 16 },
    { MB_TYPE_INTRA16x16, 1,  15 + 16 },
    { MB_TYPE_INTRA16x16, 0,  15 + 16 },
    { MB_TYPE_INTRA16x16, 3,  15 + 16 },
    { MB_TYPE_INTRA16x16, 2,  15 + 32 },
    { MB_TYPE_INTRA16x16, 1,  15 + 32 },
    { MB_TYPE_INTRA16x16, 0,  15 + 32 },
    { MB_TYPE_INTRA16x16, 3,  15 + 32 },
    { MB_TYPE_INTRA_PCM,  -1, -1 },
};
//IMbInfo结构体
typedef struct IMbInfo {
    uint16_t type;
    uint8_t pred_mode;
    uint8_t cbp;
} IMbInfo;
//PMbInfo结构体
typedef struct PMbInfo {
    uint16_t type;
    uint8_t partition_count;
} PMbInfo;
//p_mb_type_info
static const PMbInfo p_mb_type_info[5] = {
    { MB_TYPE_16x16 | MB_TYPE_P0L0,                               1 },
    { MB_TYPE_16x8  | MB_TYPE_P0L0 | MB_TYPE_P1L0,                2 },
    { MB_TYPE_8x16  | MB_TYPE_P0L0 | MB_TYPE_P1L0,                2 },
    { MB_TYPE_8x8   | MB_TYPE_P0L0 | MB_TYPE_P1L0,                4 },
    { MB_TYPE_8x8   | MB_TYPE_P0L0 | MB_TYPE_P1L0 | MB_TYPE_REF0, 4 },
};
//还有static const PMbInfo p_sub_mb_type_info[4] 
static const PMbInfo b_mb_type_info[23]
static const PMbInfo b_sub_mb_type_info[13] 
//Avcodec.h中
//所有宏块类型:
//The following defines may change, don't expect compatibility if you use them.
#define MB_TYPE_INTRA4x4   0x0001
#define MB_TYPE_INTRA16x16 0x0002 //FIXME H.264-specific
#define MB_TYPE_INTRA_PCM  0x0004 //FIXME H.264-specific
#define MB_TYPE_16x16      0x0008
#define MB_TYPE_16x8       0x0010
#define MB_TYPE_8x16       0x0020
#define MB_TYPE_8x8        0x0040
#define MB_TYPE_INTERLACED 0x0080
#define MB_TYPE_DIRECT2    0x0100 //FIXME
#define MB_TYPE_ACPRED     0x0200
#define MB_TYPE_GMC        0x0400
#define MB_TYPE_SKIP       0x0800
#define MB_TYPE_P0L0       0x1000
#define MB_TYPE_P1L0       0x2000
#define MB_TYPE_P0L1       0x4000
#define MB_TYPE_P1L1       0x8000
#define MB_TYPE_L0         (MB_TYPE_P0L0 | MB_TYPE_P1L0)
#define MB_TYPE_L1         (MB_TYPE_P0L1 | MB_TYPE_P1L1)
#define MB_TYPE_L0L1       (MB_TYPE_L0   | MB_TYPE_L1)
#define MB_TYPE_QUANT      0x00010000
#define MB_TYPE_CBP        0x00020000
//Note bits 24-31 are reserved for codec specific use (h264 ref0, mpeg1 0mv, ...)


//所以Slice类型
enum AVPictureType {
    AV_PICTURE_TYPE_NONE = 0, ///< Undefined
    AV_PICTURE_TYPE_I,     ///< Intra
    AV_PICTURE_TYPE_P,     ///< Predicted
    AV_PICTURE_TYPE_B,     ///< Bi-dir predicted
    AV_PICTURE_TYPE_S,     ///< S(GMC)-VOP MPEG4
    AV_PICTURE_TYPE_SI,    ///< Switching Intra
    AV_PICTURE_TYPE_SP,    ///< Switching Predicted
    AV_PICTURE_TYPE_BI,    ///< BI type
};
//例子h->slice_type_nos != AV_PICTURE_TYPE_I
IS_16X16(mb_type)
IS_16X8(mb_type)
IS_8X16(mb_type)
IS_INTRA16x16(mb_type)
IS_INTRA4x4(mb_type)
//判断宏块类型
#define MB_TYPE_INTRA MB_TYPE_INTRA4x4 //default mb_type if there is just one type
#define IS_INTRA4x4(a)   ((a)&MB_TYPE_INTRA4x4)
#define IS_INTRA16x16(a) ((a)&MB_TYPE_INTRA16x16)
#define IS_PCM(a)        ((a)&MB_TYPE_INTRA_PCM)
#define IS_INTRA(a)      ((a)&7)
#define IS_INTER(a)      ((a)&(MB_TYPE_16x16|MB_TYPE_16x8|MB_TYPE_8x16|MB_TYPE_8x8))
#define IS_SKIP(a)       ((a)&MB_TYPE_SKIP)
#define IS_INTRA_PCM(a)  ((a)&MB_TYPE_INTRA_PCM)
#define IS_INTERLACED(a) ((a)&MB_TYPE_INTERLACED)
#define IS_DIRECT(a)     ((a)&MB_TYPE_DIRECT2)
#define IS_GMC(a)        ((a)&MB_TYPE_GMC)
#define IS_16X16(a)      ((a)&MB_TYPE_16x16)
#define IS_16X8(a)       ((a)&MB_TYPE_16x8)
#define IS_8X16(a)       ((a)&MB_TYPE_8x16)
#define IS_8X8(a)        ((a)&MB_TYPE_8x8)
#define IS_SUB_8X8(a)    ((a)&MB_TYPE_16x16) //note reused
#define IS_SUB_8X4(a)    ((a)&MB_TYPE_16x8)  //note reused
#define IS_SUB_4X8(a)    ((a)&MB_TYPE_8x16)  //note reused
#define IS_SUB_4X4(a)    ((a)&MB_TYPE_8x8)   //note reused
#define IS_ACPRED(a)     ((a)&MB_TYPE_ACPRED)
#define IS_QUANT(a)      ((a)&MB_TYPE_QUANT)
#define IS_DIR(a, part, list) ((a) & (MB_TYPE_P0L0<<((part)+2*(list))))
#define USES_LIST(a, list) ((a) & ((MB_TYPE_P0L0|MB_TYPE_P1L0)<<(2*(list)))) ///< does this mb use listX, note does not work if subMBs
#define HAS_CBP(a)        ((a)&MB_TYPE_CBP)


//IS_8x8DCT解释
#define MB_TYPE_REF0       MB_TYPE_ACPRED // dirty but it fits in 16 bit
#define MB_TYPE_8x8DCT     0x01000000
#define IS_REF0(a)         ((a) & MB_TYPE_REF0)
#define IS_8x8DCT(a)       ((a) & MB_TYPE_8x8DCT)


enum chroma_format_e
{
    CHROMA_400 = 0,
    CHROMA_420 = 1,
    CHROMA_422 = 2,
    CHROMA_444 = 3,
};


经验:修改过后的ffmpeg运行x264编码整个视频之后生成的.264不行。
原因:x264编码时加一个条件 --no-8x8dct 就行。因为*scantable越界超过16 。
调试ffmpeg
./configure --extra-cflags=-g --disable-stripping


avcodec_open2在libavcodec/utils.c
0 0
原创粉丝点击