天天看點

FFMpeg中apiexample.c例子分析——編碼分析

apiexample.c例子教我們如何去利用ffmpeg庫中的api函數來自己編寫編解碼程式。

    (1)首先,main函數中一開始會去調用avcodec_init()函數,該函數的作用是初始化libavcodec,而我們在使用avcodec庫時,該函數必須被調用。

  (2)avcodec_register_all()函數,注冊所有的編解碼器(codecs),解析器(parsers)以及碼流過濾器(bitstream filters)。當然我們也可以使用個别的注冊函數來注冊我們所要支援的格式。

  (3)video_encode_example()函數用于視訊編碼,由圖可知,所有的編碼工作都在該函數内完成。

  (4)avcodec_find_encoder()函數用于查找一個與codec ID相比對的已注冊的編碼器。

  (5)avcodec_alloc_context()函數用于配置設定一個AVCodecContext并設定預設值,如果失敗傳回NULL,并可用av_free()進行釋放。

  (6)avcodec_alloc_frame()函數用于配置設定一個AVFrame并設定預設值,如果失敗傳回NULL,并可用av_free()進行釋放。

  (7)設定參數:

    設定采樣參數,即比特率。

    c->bit_rate = 400000;

    設定分辨率,必須是2的倍數。

    c->width = 352;

    c->height = 288;

    設定幀率。

    c->time_base = (AVRational){1,25}; 該幀率為25,其實timebase = 1/framerate,花括号内分别為分子和分母。

    設定GOP大小。

    c->gop_size = 10; 該值表示每10幀會插入一個I幀(intra frame)。

    設定B幀最大數。

    c->max_b_frames = 1; 該值表示在兩個非B幀之間,所允許插入的B幀的最大幀數。

    設定像素格式。

    c->pix_fmt = PIX_FMT_YUV420P; 該值将像素格式設定為YUV420P。

  (8)avcodec_open()函數用給定的AVCodec來初始化AVCodecContext。

  (9)接着是打開檔案,f = fopen( filename, “wb” );

    (10)配置設定圖像和輸出緩存。

    申請100KB左右的記憶體作為輸出緩存。

outbuf_size = 100000;

    outbuf = malloc( outbuf_size );

    根據幀的大小來确定YUV420所占記憶體大小,一個像素,RGB格式占用3個位元組,而YUV420格式隻占用兩個位元組。YUV420格式是指,每個像素都保留一個Y(亮度)分量,而在水準方向上,不是每行都取U和V分量,而是一行隻取U分量,則其接着一行就隻取V分量,以此重複,是以420不是指沒有V,而是指一行采樣隻取U,另一行采樣隻取V。在取U和V時,每兩個Y之間取一個U或V。但從4x4矩陣列來看,每4個矩陣點Y區域中,隻有一個U和V,是以它們的比值是4:1。是以對于一個像素,RGB需要8 * 3 = 24位,即占3個位元組;而YUV420P,8 + 8/4 + 8/4 = 12位,即占2個位元組,其中8指Y分量,8/4指U和V分量。

    size = c->width * c->height;

    picture_buf = malloc( (size * 3) / 2 );  

    picture->data[0] = picture_buf;

    picture->data[1] = picture->data[0] + size;

    picture->data[2] = picture->data[1] + size / 4;

    picture->linesize[0] = c->width;

    picture->linesize[1] = c->width / 2;

    picture->linesize[2] = c->width / 2;

    其中,data[0]存放Y,data[1]存放U,data[2]存放V【FixMe】。linesize[0]表示Y分量的寬度,linesize[1]表示U分量的寬度,linesize[2]表示V分量的寬度。

  (11)編碼一秒鐘的視訊,幀率為25,是以需要循環25次,每次編碼一幀。

  (11.1)準備一幅僞圖像,即自己自定義往裡面塞資料。

    for(y=0;y<c->height;y++){

                     for(x=0;x<c->width;x++){

                            picture->data[0][y*picture->linesize[0]+x]=x+y+i*3;

}

}

for(y=0;y<c->height/2;y++){

       for(x=0;x<c->width/2;x++){

              picture->data[1][y*picture->linesize[1]+x]=128+y+i*2;

              picture->data[2][y*picture->linesize[2]+x]=64+x+i*5;

}

}

  (11.2)avcodec_encode_video()從picture中編碼一幀視訊資料,并存入到outbuf中,而期間所使用的編碼器為c。

  (11.3)将編碼完的資料寫入到檔案裡。

  (12)對延時的幀資料進行編碼。因為像MPEG4中,I幀、P幀和B幀之間存在一定的延時【FixMe】。同樣是avcodec_encode_video(),然後寫入檔案。

  (13)添加結束代碼,使其成為一個真正的mpeg檔案。

    outbuf[0] = 0x00;

    outbuf[1] = 0x00;

    outbuf[2] = 0x01;

    outbuf[3] = 0xb7;

    fwrite( outbuf, 1, 4, f );

  這個結束代碼表示什麼???

  (14)釋放資源。

    fclose(f);

    free(picture_buf);

    free(outbuf);

    avcodec_close(c);

    av_free(c);

    av_free(picture);

上一篇: 什麼是VGA
下一篇: CIF,4CIF,QCIF,D1

繼續閱讀