2012-05-30 210 views
6

從ffmpeg中的編碼示例中瞭解了這一點。我可以在一定程度遵循音頻編碼作者的例子,但我發現自己昏昏沉沉看C代碼(我的塊號評論說幫我參考什麼我談論)...瞭解FFMPEG視頻編碼

static void video_encode_example(const char *filename) 
{ 
AVCodec *codec; 
AVCodecContext *c= NULL; 
int i, out_size, size, x, y, outbuf_size; 
FILE *f; 
AVFrame *picture; 
uint8_t *outbuf, *picture_buf;    //BLOCK ONE 
printf("Video encoding\n"); 

/* find the mpeg1 video encoder */ 
codec = avcodec_find_encoder(CODEC_ID_MPEG1VIDEO); 
if (!codec) { 
    fprintf(stderr, "codec not found\n"); 
    exit(1);        //BLOCK TWO 
} 

c= avcodec_alloc_context(); 
picture= avcodec_alloc_frame(); 
/* put sample parameters */ 
c->bit_rate = 400000; 
/* resolution must be a multiple of two */ 
c->width = 352; 
c->height = 288; 
/* frames per second */ 
c->time_base= (AVRational){1,25}; 
c->gop_size = 10; /* emit one intra frame every ten frames */ 
c->max_b_frames=1; 
c->pix_fmt = PIX_FMT_YUV420P;     //BLOCK THREE 

/* open it */ 
if (avcodec_open(c, codec) < 0) { 
    fprintf(stderr, "could not open codec\n"); 
    exit(1); 
} 
f = fopen(filename, "wb"); 
if (!f) { 
    fprintf(stderr, "could not open %s\n", filename); 
    exit(1); 
}            //BLOCK FOUR 

/* alloc image and output buffer */ 
outbuf_size = 100000; 
outbuf = malloc(outbuf_size); 
size = c->width * c->height; 
picture_buf = malloc((size * 3)/2); /* size for YUV 420 */ 
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;    //BLOCK FIVE 

/* encode 1 second of video */ 
for(i=0;i<25;i++) { 
    fflush(stdout); 
    /* prepare a dummy image */ 
    /* Y */ 
    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; 
     } 
    }           //BLOCK SIX 

    /* Cb and Cr */ 
    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; 
     } 
    }           //BLOCK SEVEN 

    /* encode the image */ 
    out_size = avcodec_encode_video(c, outbuf, outbuf_size, picture); 
    printf("encoding frame %3d (size=%5d)\n", i, out_size); 
    fwrite(outbuf, 1, out_size, f); 
}            //BLOCK EIGHT 

/* get the delayed frames */ 
for(; out_size; i++) { 
    fflush(stdout); 
    out_size = avcodec_encode_video(c, outbuf, outbuf_size, NULL); 
    printf("write frame %3d (size=%5d)\n", i, out_size); 
    fwrite(outbuf, 1, out_size, f); 
}            //BLOCK NINE 

/* add sequence end code to have a real mpeg file */ 
outbuf[0] = 0x00; 
outbuf[1] = 0x00; 
outbuf[2] = 0x01; 
outbuf[3] = 0xb7; 
fwrite(outbuf, 1, 4, f); 
fclose(f); 
free(picture_buf); 
free(outbuf); 
avcodec_close(c); 
av_free(c); 
av_free(picture); 
}           //BLOCK TEN 

這裏是我可以從作者代碼塊中逐塊得到...

塊1:初始化變量和指針。我在ffmpeg源代碼中找不到AVFrame結構,因此我不知道它的參考內容。

BLOCK TWO:如果沒有找到,請使用文件中的編解碼器。

塊三:設置示例視頻參數。唯一我沒有得到的是gop的大小。我閱讀了關於內部幀的內容,但我仍然不明白它們是什麼。

塊中有四個:打開寫文件...

BLOCK五:在這裏,他們真正開始失去我。部分原因可能是因爲我不確切知道AVFrame是什麼,但爲什麼他們只使用3/2的圖像大小?

BLOCK SIX & SEVEN:我不明白他們試圖用這個數學來完成什麼。

BLOCK八:它看起來像avcodec中的功能在這裏所做的一切工作,並不關心是暫時..

BLOCK九:由於這是25幀之外循環我認爲它得到的剩餘幀?

BLOCK TEN:關閉,免費MEM等..

我知道這是一大塊代碼與混淆,任何輸入將是有益的。我在工作中頭昏腦脹。先謝謝了。

+0

今天早上我花了很多時間看塊六和七當數學在多維數組上完成時,我必須說我就像我昨天離開工作時一樣卡住:( – SetSlapShot

+0

第六塊和第七塊有什麼神祕之處?/ *準備一個虛擬圖像* /'應該爲你提供所有你需要的信息,所做的一切就是生成一些像素數據,這些數據最終會隨着幀索引的變化而變化, – HonkyTonk

+0

投票關閉太寬泛,請關注每個問題的一個點。 –

回答

3

正如HonkyTonk已經回覆,評論拼出來:準備一個虛擬形象。我猜你可能會對產生虛擬圖像感到困惑,特別是如果您不熟悉YUV/YCbCr色彩空間。 Read the Wikipedia treatment for the basics

許多視頻編解碼器在YUV色彩空間中運行。對於只用於處理RGB的程序員來說,這經常令人困惑。執行摘要是,對於這種變化(YUV 4:2:0平面),圖像中的每個像素都獲得Y樣本(請注意,Y循環遍歷每個(x,y)對),而每個2x2像素四邊形共享一個U/Cb樣本和一個V/Cr樣本(注意塊7中的迭代超過寬度/ 2和高度/ 2)。

它看起來像生成的模式是某種梯度。如果你想產生一個已知的變化,將Y/Cb/Cr設置爲0,並且虛擬圖像將全部爲綠色。將Cb和Cr設置爲128,將Y設置爲255,得到白色框;將Y滑動到0以看到黑色;將Y設置爲中間的任意值,同時將Cb和Cr保持爲128,以便看到灰色陰影。

4

我分享我的理解[安靜的回覆遲!]

YUV420P:

YUV 420P或YCbCr,是替代RGB repersetation,它包含3個

平面,即Y(亮度分量)U(Y-CB)& V(Y型的Cr ) 組件。 [ans Y-Cb-Cr-Cg =

常數,我們不需要存儲Cg分量,因爲它通常可以被計算。] 就像RGB888一樣,需要3個字節的像素,YUV420需要1.5字節一個像素[@Find( 12比特用於什麼比例的比較)] 這裏P代表進步,這意味着幀是漸進的,意味着V跟隨U,U跟隨Y和YUV幀是一個字節數組,只是! 另一種是我的交叉處理,意味着UV平面數據以特定的方式在Y平面數據之間交錯[@Find(What manner)]