日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

FFPLAY的原理(二)

發(fā)布時(shí)間:2023/12/18 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 FFPLAY的原理(二) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

關(guān)于包Packets的注釋

從技術(shù)上講一個(gè)包可以包含部分或者其它的數(shù)據(jù),但是ffmpeg的解釋器保證了我們得到的包Packets包含的要么是完整的要么是多種完整的幀。

現(xiàn)在我們需要做的是讓SaveFrame函數(shù)能把RGB信息定稿到一個(gè)PPM格式的文件中。我們將生成一個(gè)簡(jiǎn)單的PPM格式文件,請(qǐng)相信,它是可以工作的。

void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame) {

FILE *pFile;

char szFilename[32];

int y;

// Open file

sprintf(szFilename, "frame%d.ppm", iFrame);

pFile=fopen(szFilename, "wb");

if(pFile==NULL)

return;

// Write header

fprintf(pFile, "P6/n%d %d/n255/n", width, height);

// Write pixel data

for(y=0; y<height; y++)

fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);

// Close file

fclose(pFile);

}

我們做了一些標(biāo)準(zhǔn)的文件打開(kāi)動(dòng)作,然后寫(xiě)入RGB數(shù)據(jù)。我們一次向文件寫(xiě)入一行數(shù)據(jù)。PPM格式文件的是一種包含一長(zhǎng)串的RGB數(shù)據(jù)的文件。如果你了解 HTML色彩表示的方式,那么它就類(lèi)似于把每個(gè)像素的顏色頭對(duì)頭的展開(kāi),就像#ff0000#ff0000....就表示了了個(gè)紅色的屏幕。(它被保存成二進(jìn)制方式并且沒(méi)有分隔符,但是你自己是知道如何分隔的)。文件的頭部表示了圖像的寬度和高度以及最大的RGB值的大小。

現(xiàn)在,回顧我們的main()函數(shù)。一旦我們開(kāi)始讀取完視頻流,我們必需清理一切:

// Free the RGB image

av_free(buffer);

av_free(pFrameRGB);

// Free the YUV frame

av_free(pFrame);

// Close the codec

avcodec_close(pCodecCtx);

// Close the video file

av_close_input_file(pFormatCtx);

return 0;

你會(huì)注意到我們使用av_free來(lái)釋放我們使用avcode_alloc_fram和av_malloc來(lái)分配的內(nèi)存。

上面的就是代碼!下面,我們將使用Linux或者其它類(lèi)似的平臺(tái),你將運(yùn)行:

gcc -o tutorial01 tutorial01.c -lavutil -lavformat -lavcodec -lz -lavutil -lm

如果你使用的是老版本的ffmpeg,你可以去掉-lavutil參數(shù):

gcc -o tutorial01 tutorial01.c -lavutil -lavformat -lavcodec -lz -lm

大多數(shù)的圖像處理函數(shù)可以打開(kāi)PPM文件。可以使用一些電影文件來(lái)進(jìn)行測(cè)試。

輸出到屏幕

SDL和視頻

為了在屏幕上顯示,我們將使用SDL.SDL是Simple Direct Layer的縮寫(xiě)。它是一個(gè)出色的多媒體庫(kù),適用于多平臺(tái),并且被用在許多工程中。你可以從它的官方網(wǎng)站的網(wǎng)址 http://www.libsdl.org/ 上來(lái)得到這個(gè)庫(kù)的源代碼或者如果有可能的話你可以直接下載開(kāi)發(fā)包到你的操作系統(tǒng)中。按照這個(gè)指導(dǎo),你將需要編譯這個(gè)庫(kù)。(剩下的幾個(gè)指導(dǎo)中也是一樣)

SDL庫(kù)中有許多種方式來(lái)在屏幕上繪制圖形,而且它有一個(gè)特殊的方式來(lái)在屏幕上顯示圖像――這種方式叫做YUV覆蓋。YUV(從技術(shù)上來(lái)講并不叫 YUV而是叫做YCbCr)是一種類(lèi)似于RGB方式的存儲(chǔ)原始圖像的格式。粗略的講,Y是亮度分量,U和V是色度分量。(這種格式比RGB復(fù)雜的多,因?yàn)楹芏嗟念伾畔⒈粊G棄了,而且你可以每2個(gè)Y有1個(gè)U和1個(gè)V)。SDL的YUV覆蓋使用一組原始的YUV數(shù)據(jù)并且在屏幕上顯示出他們。它可以允許4種不同的 YUV格式,但是其中的YV12是最快的一種。還有一個(gè)叫做YUV420P的YUV格式,它和YV12是一樣的,除了U和V分量的位置被調(diào)換了以外。 420意味著它以4:2:0的比例進(jìn)行了二次抽樣,基本上就意味著1個(gè)顏色分量對(duì)應(yīng)著4個(gè)亮度分量。所以它的色度信息只有原來(lái)的1/4。這是一種節(jié)省帶寬的好方式,因?yàn)槿搜鄹杏X(jué)不到這種變化。在名稱中的P表示這種格式是平面的――簡(jiǎn)單的說(shuō)就是Y,U和V分量分別在不同的數(shù)組中。FFMPEG可以把圖像格式轉(zhuǎn)換為YUV420P,但是現(xiàn)在很多視頻流的格式已經(jīng)是YUV420P的了或者可以被很容易的轉(zhuǎn)換成YUV420P格式。

于是,我們現(xiàn)在計(jì)劃把指導(dǎo)1中的SaveFrame()函數(shù)替換掉,讓它直接輸出我們的幀到屏幕上去。但一開(kāi)始我們必需要先看一下如何使用SDL庫(kù)。首先我們必需先包含SDL庫(kù)的頭文件并且初始化它。

#include <SDL.h>

#include <SDL_thread.h>

if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {

fprintf(stderr, "Could not initialize SDL - %s/n", SDL_GetError());

exit(1);

}

SDL_Init()函數(shù)告訴了SDL庫(kù),哪些特性我們將要用到。當(dāng)然SDL_GetError()是一個(gè)用來(lái)手工除錯(cuò)的函數(shù)。

創(chuàng)建一個(gè)顯示

現(xiàn)在我們需要在屏幕上的一個(gè)地方放上一些東西。在SDL中顯示圖像的基本區(qū)域叫做面surface。

SDL_Surface *screen;

screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, 0);

if(!screen) {

fprintf(stderr, "SDL: could not set video mode - exiting/n");

exit(1);

}

這就創(chuàng)建了一個(gè)給定高度和寬度的屏幕。下一個(gè)選項(xiàng)是屏幕的顏色深度――0表示使用和當(dāng)前一樣的深度。(這個(gè)在OS X系統(tǒng)上不能正常工作,原因請(qǐng)看源代碼)

現(xiàn)在我們?cè)谄聊簧蟻?lái)創(chuàng)建一個(gè)YUV覆蓋以便于我們輸入視頻上去:

SDL_Overlay *bmp;

bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height,

SDL_YV12_OVERLAY, screen);

正如前面我們所說(shuō)的,我們使用YV12來(lái)顯示圖像。

顯示圖像

前面那些都是很簡(jiǎn)單的。現(xiàn)在我們需要來(lái)顯示圖像。讓我們看一下是如何來(lái)處理完成后的幀的。我們將原來(lái)對(duì)RGB處理的方式,并且替換 SaveFrame() 為顯示到屏幕上的代碼。為了顯示到屏幕上,我們將先建立一個(gè)AVPicture結(jié)構(gòu)體并且設(shè)置其數(shù)據(jù)指針和行尺寸來(lái)為我們的YUV覆蓋服務(wù):

if(frameFinished) {

SDL_LockYUVOverlay(bmp);

AVPicture pict;

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];

// Convert the image into YUV format that SDL uses

img_convert(&pict, PIX_FMT_YUV420P,

(AVPicture *)pFrame, pCodecCtx->pix_fmt,

pCodecCtx->width, pCodecCtx->height);

SDL_UnlockYUVOverlay(bmp);

}

首先,我們鎖定這個(gè)覆蓋,因?yàn)槲覀儗⒁ジ膶?xiě)它。這是一個(gè)避免以后發(fā)生問(wèn)題的好習(xí)慣。正如前面所示的,這個(gè)AVPicture結(jié)構(gòu)體有一個(gè)數(shù)據(jù)指針指向一個(gè)有4個(gè)元素的指針數(shù)據(jù)。由于我們處理的是YUV420P,所以我們只需要3個(gè)通道即只要三組數(shù)據(jù)。其它的格式可能需要第四個(gè)指針來(lái)表示alpha通道或者其它參數(shù)。行尺寸正如它的名字表示的意義一樣。在YUV覆蓋中相同功能的結(jié)構(gòu)體是像素pixel和程度pitch。(程度pitch是在SDL里用來(lái)表示指定行數(shù)據(jù)寬度的值)。所以我們現(xiàn)在做的是讓我們的覆蓋中的pict.data中的三個(gè)指針有一個(gè)指向必要的空間的地址。類(lèi)似的,我們可以直接從覆蓋中得到行尺寸信息。像前面一樣我們使用img_convert來(lái)把格式轉(zhuǎn)換成PIX_FMT_YUV420P。

繪制圖像

但我們?nèi)匀恍枰嬖VSDL如何來(lái)實(shí)際顯示我們給的數(shù)據(jù)。我們也會(huì)傳遞一個(gè)表明電影位置、寬度、高度和縮放大小的矩形參數(shù)給SDL的函數(shù)。這樣,SDL為我們做縮放并且它可以通過(guò)顯卡的幫忙來(lái)進(jìn)行快速縮放。

SDL_Rect rect;

if(frameFinished) {

// Convert the image into YUV format that SDL uses

img_convert(&pict, PIX_FMT_YUV420P,

(AVPicture *)pFrame, pCodecCtx->pix_fmt,

pCodecCtx->width, pCodecCtx->height);

SDL_UnlockYUVOverlay(bmp);

rect.x = 0;

rect.y = 0;

rect.w = pCodecCtx->width;

rect.h = pCodecCtx->height;

SDL_DisplayYUVOverlay(bmp, &rect);

}

讓我們?cè)倩ㄒ稽c(diǎn)時(shí)間來(lái)看一下SDL的特性:它的事件驅(qū)動(dòng)系統(tǒng)。SDL被設(shè)置成當(dāng)你在SDL中點(diǎn)擊或者移動(dòng)鼠標(biāo)或者向它發(fā)送一個(gè)信號(hào)它都將產(chǎn)生一個(gè)事件的驅(qū)動(dòng)方式。如果你的程序想要處理用戶輸入的話,它就會(huì)檢測(cè)這些事件。你的程序也可以產(chǎn)生事件并且傳遞給SDL事件系統(tǒng)。當(dāng)使用SDL進(jìn)行多線程編程的時(shí)候,這相當(dāng)有用,這方面代碼我們可以在指導(dǎo)4中看到。在這個(gè)程序中,我們將在處理完包以后就立即輪詢事件。現(xiàn)在而言,我們將處理SDL_QUIT事件以便于我們退出:

SDL_Event event;

av_free_packet(&packet);

SDL_PollEvent(&event);

switch(event.type) {

case SDL_QUIT:

SDL_Quit();

exit(0);

break;

default:

break;

}

讓我們?nèi)サ襞f的冗余代碼,開(kāi)始編譯。如果你使用的是Linux或者其變體,使用SDL庫(kù)進(jìn)行編譯的最好方式為:

gcc -o tutorial02 tutorial02.c -lavutil -lavformat -lavcodec -lz -lm /

`sdl-config --cflags --libs`

這里的sdl-config命令會(huì)打印出用于gcc編譯的包含正確SDL庫(kù)的適當(dāng)參數(shù)。為了進(jìn)行編譯,在你自己的平臺(tái)你可能需要做的有點(diǎn)不同:請(qǐng)查閱一下SDL文檔中關(guān)于你的系統(tǒng)的那部分。一旦可以編譯,就馬上運(yùn)行它。

當(dāng)運(yùn)行這個(gè)程序的時(shí)候會(huì)發(fā)生什么呢?電影簡(jiǎn)直跑瘋了!實(shí)際上,我們只是以我們能從文件中解碼幀的最快速度顯示了所有的電影的幀。現(xiàn)在我們沒(méi)有任何代碼來(lái)計(jì)算出我們什么時(shí)候需要顯示電影的幀。最后(在指導(dǎo)5),我們將花足夠的時(shí)間來(lái)探討同步問(wèn)題。但一開(kāi)始我們會(huì)先忽略這個(gè),因?yàn)槲覀冇懈又匾氖虑橐幚?#xff1a;音頻!

總結(jié)

以上是生活随笔為你收集整理的FFPLAY的原理(二)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产美女无遮挡网站 | 欧美日韩一区二区三区四区 | 三日本三级少妇三级99 | 任你躁av一区二区三区 | 久久久av免费 | 国产欧美在线观看视频 | www.狠狠撸.com | 神马午夜不卡 | 青春草视频在线免费观看 | 欧美一区二区影院 | 99精品视频免费版的特色功能 | 寂寞午夜影院 | 精品国产a | 4438五月天 | 极品美妇后花庭翘臀娇吟小说 | h网址在线观看 | 日本一区二区免费高清视频 | 免费高清视频在线观看 | 中文字幕av影院 | 打开免费观看视频在线播放 | 国产精品福利一区二区三区 | 麻豆视频官网 | 鲁一鲁啪一啪 | 一区二区三区韩国 | 亚洲色图第1页 | 亚洲熟妇毛茸茸 | 国产精品无码免费播放 | 91成人看| 午夜黄色在线 | 久久久wwww| 殴美毛片| 91中文字幕在线播放 | 国产理伦 | 韩国三级在线看 | 精品视频一区二区三区四区 | 国产精品一区二区三区久久久 | 欧美bdsm调教视频 | 正在播放国产精品 | 色诱久久av | 亚洲综合三区 | 影音先锋婷婷 | 岛国av一区二区三区 | 伊人影院久久 | www.av免费| 国产精品麻豆欧美日韩ww | 成人黄色在线视频 | 爱爱视频免费网站 | 怡红院成人影院 | 久久99国产精品视频 | 手机在线中文字幕 | 中文久久久 | 青青视频免费 | 超碰.com | 久久3p | 日韩电影在线观看中文字幕 | 一级α片免费看刺激高潮视频 | 69xxxx日本| 在线视频自拍 | 成人无码av片在线观看 | 日韩精品免费播放 | 亚洲爱爱网站 | 乌克兰极品av女神 | 日本熟妇毛耸耸xxxxxx | 天天看天天色 | 国产九色sp调教91 | 91精品久久香蕉国产线看观看 | 亚洲一区二区三区在线 | 99国产超薄肉色丝袜交足 | 一级黄色片网址 | 操模特 | 宅男在线视频 | 成人福利在线免费观看 | 日韩一级二级 | 色妞色视频一区二区三区四区 | 久久露脸| se日韩 | 欧美日韩在线视频免费观看 | 亚洲综合成人网 | 日本三级大片 | 无码少妇精品一区二区免费动态 | 欧美美女性视频 | 国内9l自拍 | 国产91一区在线精品 | 亚洲综合色网 | 五月天精品| 少妇被粗大猛进进出出s小说 | 一级片在线免费观看 | jzzijzzij亚洲成熟少妇在线播放 狠狠躁日日躁夜夜躁2022麻豆 | 国产精品电影一区二区 | 成人自拍视频在线观看 | re久久| 成人久久久 | 天堂男人在线 | 午夜试看120秒 | 亚洲污污视频 | 久久人人爽人人 | 中文字幕在线免费观看 | www.99色| 97xxx |