免费爱碰视频在线观看,九九精品国产屋,欧美亚洲尤物久久精品,1024在线观看视频亚洲

      ffmpeg播放器實現(xiàn)詳解 – 框架搭建

      ffmpeg播放器實現(xiàn)詳解 - 框架搭建

      ffplay是ffmpeg源碼中一個自帶的開源播放器實例,同時支持本地視頻文件的播放以及在線流媒體播放,功能非常強(qiáng)大。

      FFplay: FFplay is a very simple and portable media player using the FFmpeg libraries and the SDL library. It is mostly used as a testbed for the various FFmpeg APIs

      ffplay中的代碼充分調(diào)用了ffmpeg中的函數(shù)庫,因此,想學(xué)習(xí)ffmpeg的使用,或基于ffmpeg開發(fā)一個自己的播放器,ffplay都是一個很好的切入點。 ffplay源碼編譯見[公眾號:斷點實驗室]的前述文章 [ffplay源碼編譯]。 由于ffmpeg本身的開發(fā)文檔比較少,且ffplay播放器源碼的實現(xiàn)相對復(fù)雜,除了基礎(chǔ)的ffmpeg組件調(diào)用外,還包含視頻幀的渲染、音頻幀的播放、音視頻同步策略及線程調(diào)度等問題。

      因此,這里我們以ffmpeg官網(wǎng)推薦的一個ffplay播放器簡化版本的開發(fā)例程為基礎(chǔ),在此基礎(chǔ)上循序漸進(jìn)由淺入深,最終探討實現(xiàn)一個視頻播放器的完整邏輯。

      ffplay播放器簡化版本開發(fā)例程可在ffmpeg官網(wǎng)[documentation]頁面的右下角找到,點擊An FFmpeg and SDL Tutorial即可打開找到對應(yīng)的源碼。

      這里對其中部分難以理解的代碼進(jìn)行了修改,并對幾乎所有代碼逐行注釋,方便大家理解

      1、項目編譯環(huán)境搭建

      這里仍以Ubuntu 16.04 LTS為基礎(chǔ)進(jìn)行講述,由于ffmpeg支持多個主流平臺,且api接口在各個平臺是一致的,因此其他平臺也可參照本文內(nèi)容,后續(xù)會將代碼移植到windows等其他平臺,方便大家調(diào)試。

      源碼的編譯除了ffmpeg環(huán)境外,還需要SDL-1.x版本的支持,用于提供視頻幀的渲染及音頻幀的播放。

      1.1 sdl庫編譯

      SDL(Simple DirectMedia Layer)是一個跨平臺的多媒體和游戲開發(fā)包,提供2D,音頻,事件驅(qū)動,多線程和定時器等服務(wù),它使用C語言寫成,提供了多種控制圖像、聲音、輸出的函數(shù),讓開發(fā)者只要用相同或是相似的代碼就可以開發(fā)出跨多個平臺(Linux、Windows、Mac OS X等)的應(yīng)用軟件。

      SDL: Simple DirectMedia Layer is a cross-platform development library designed to provide low level access to audio, keyboard, mouse, joystick, and graphics hardware via OpenGL and Direct3D. It is used by video playback software, emulators, and popular games including Valve’s award winning catalog and many Humble Bundle games.

      可通過下面的鏈接下載SDL-1.2.15源碼,注意,例程中依賴的SDL版本與ffplay中有所不同 https://www.libsdl.org/download-1.2.php

      下載完成后解壓進(jìn)入sdl源碼目錄,可通過下面的配置方法生成Makefile文件

      ./configure –prefix=/usr/local/3rdparty/sdl

      生成Makefile文件后,輸入make命令即可開始編譯過程,編譯完成后,執(zhí)行make install命令進(jìn)行安裝

      make make install

      安裝完成后,會在configure指定的目錄下找到sdl的目錄,由于sdl以庫文件的方式提供支持,因此在sdl/bin目錄下沒有對應(yīng)的可執(zhí)行文件。

      1.2 sdl環(huán)境變量配置

      sdl編譯完成后,還需要讓系統(tǒng)能夠找到對應(yīng)的安裝位置。打開/etc/profile配置文件,在該文件底部添加sdl的環(huán)境變量

      #SDL ENVIRONMENTexport C_INCLUDE_PATH=/usr/local/3rdparty/sdl/include/SDL:$C_INCLUDE_PATHexport LD_LIBRARY_PATH=/usr/local/3rdparty/sdl/lib:$LD_LIBRARY_PATHexport PKG_CONFIG_PATH=/usr/local/3rdparty/sdl/lib/pkgconfig:$PKG_CONFIG_PATH

      1.3 項目源碼編譯

      項目源碼可采用如下Makefile腳本進(jìn)行編譯

      tutorial01: tutorial01.c gcc -o tutorial01 -g3 tutorial01.c -I${FFMPEG_INCLUDE} -I${SDL_INCLUDE} -L${FFMPEG_LIB} -lavutil -lavformat -lavcodec -lswscale -lswresample -lz -lm `sdl-config –cflags –libs`clean: rm -rf tutorial01 rm -rf *.ppm

      執(zhí)行make命令開始編譯,編譯完成后,可在源碼目錄生成名為[tutorial01]的可執(zhí)行文件。

      1.4 驗證

      與ffplay的使用方法類似,執(zhí)行[tutorial01 url]命令,可以看到在源碼目錄生成的后綴名為.ppm的圖像

      ./tutorial01 rtmp://58.200.131.2:1935/livetv/hunantv

      ppm圖像在linux平臺下可直接打開,看到有ppm圖像生成,即可確定項目能夠正常工作,輸入Ctrl+C結(jié)束程序運行。

      ppm格式的圖像平時不太常用,大家沒有必要做深入研究,這里僅用于對編譯結(jié)果的驗證。

      PPM: A PPM file is a 24-bit color image formatted using a text format. It stores each pixel with a number from 0 to 65536, which specifies the color of the pixel. PPM files also store the image height and width, whitespace data, and the maximum color value. The portable pixmap format (PPM), the portable graymap format (PGM) and the portable bitmap format (PBM) are image file formats designed to be easily exchanged between platforms.

      領(lǐng)取C++音視頻開發(fā)學(xué)習(xí)資料:點擊 音視頻開發(fā)(資料文檔+視頻教程+面試題)(FFmpeg+WebRTC+RTMP+RTSP+HLS+RTP)

      2 源碼分析

      上述例程除了生成幾張圖片外,好像什么也做不了,似乎離一個功能完整的視頻播放器還有很遠(yuǎn)的距離。 盡管如此,例程依然包含了ffmpeg視頻開發(fā)用到的幾乎所有關(guān)鍵的api與數(shù)據(jù)結(jié)構(gòu)。后面的內(nèi)容會在此基礎(chǔ)上不斷的完善,直至實現(xiàn)一個完整的視頻播放器。

      2.1 流程

      下面給出例程的流程圖,流程非常簡單,所有代碼都運行在主線程中,流程涉及api及數(shù)據(jù)結(jié)構(gòu)的含義都在例程源碼中有詳細(xì)的注釋。

      2.2 源碼中涉及的api及組件

      由于篇幅的限制,這里先簡要介紹每個組件及api的含義,后續(xù)文章中會深入介紹每個組件及api的使用方法

      組件:

      • AVFormatContext 保存文件容器封裝信息及碼流參數(shù)的結(jié)構(gòu)體
      • AVCodecContext 解碼器上下文對象,解碼器依賴的相關(guān)環(huán)境、狀態(tài)、資源以及參數(shù)集的接口指針
      • AVCodec 保存編解碼器信息的結(jié)構(gòu)體,提供編碼與解碼的公共接口
      • AVPacket 負(fù)責(zé)保存壓縮編碼數(shù)據(jù)相關(guān)信息的結(jié)構(gòu)體,每幀圖像由一到多個packet包組成
      • AVFrame 保存音視頻解碼后的數(shù)據(jù),如狀態(tài)信息、編解碼器信息、宏塊類型表,QP表,運動矢量表等數(shù)據(jù)
      • SwsContext 描述轉(zhuǎn)換器參數(shù)的結(jié)構(gòu)體

      api :

      • av_register_all 注冊所有ffmpeg支持的多媒體格式及編解碼器
      • avformat_open_input 打開視頻文件,讀文件頭內(nèi)容,取得文件容器的封裝信息及碼流參數(shù)并存儲在pFormatCtx中
      • avformat_find_stream_info 取得文件中保存的碼流信息,并填充到pFormatCtx->stream 字段
      • avcodec_find_decoder 根據(jù)視頻流對應(yīng)的解碼器上下文查找對應(yīng)的解碼器,返回對應(yīng)的解碼器
      • avcodec_alloc_context3 復(fù)制編解碼器上下文對象,用于保存從視頻流中抽取的幀
      • avcodec_open2 打開解碼器
      • av_frame_alloc 為解碼后的視頻信息結(jié)構(gòu)體分配空間并完成初始化操作
      • av_read_frame 從文件中依次讀取每個圖像編碼數(shù)據(jù)包,并存儲在AVPacket數(shù)據(jù)結(jié)構(gòu)中
      • avcodec_decode_video2 解碼完整的一幀數(shù)據(jù),若一個packet無法解碼一個完整的視頻幀,則在ffmpeg后臺維護(hù)的緩存隊列會持續(xù)等待多個packet,直到能夠解碼出一個完整的視頻幀為止

      3 ffmpeg能幫我們做什么

      視頻開發(fā)涉及到多種視頻格式的編解碼,多種文件格式及傳輸協(xié)議的解封裝等操作,很難一下子全部掌握。 ffmpeg通過其封裝的api及組件,為我們屏蔽了不同視頻封裝格式及編碼格式的差異,以統(tǒng)一的api接口提供給開發(fā)者使用,開發(fā)者不需要了解每種編碼方式及封裝方式具體的技術(shù)細(xì)節(jié),只需要調(diào)用ffmpeg提供的api就可以完成解封裝和解碼的操作了。 至于視頻幀的渲染及音頻幀的播放,ffmpeg就無能為力了,因此需要借助類似sdl庫等其他組件完成,后面的章節(jié)會為大家介紹繼續(xù)介紹。

      4 源碼清單

      // tutorial01.c// Code based on a tutorial by Martin Bohme ([email protected])// Tested on Gentoo, CVS version 5/01/07 compiled with GCC 4.1.1// With updates from https://github.com/chelyaev/ffmpeg-tutorial// Updates tested on:// LAVC 54.59.100, LAVF 54.29.104, LSWS 2.1.101 // on GCC 4.7.2 in Debian February 2015//// Updates tested on:// Mac OS X 10.11.6// Apple LLVM version 8.0.0 (clang-800.0.38)//// A small sample program that shows how to use libavformat and libavcodec to read video from a file.//// Use//// $ gcc -o tutorial01 tutorial01.c -lavutil -lavformat -lavcodec -lswscale -lz -lm//// to build (assuming libavutil/libavformat/libavcodec/libswscale are correctly installed your system).//// Run using//// $ tutorial01 myvideofile.mpg//// to write the first five frames from “myvideofile.mpg” to disk in PPM format.// comment by [email protected]#include #include #include #include #include // compatibility with newer API#if LIBAVCODEC_VERSION_INT linesize[0], 1, width*3, pFile); } // Close file,關(guān)閉文件 fclose(pFile);}int main(int argc, char *argv[]) {/*————–參數(shù)定義————-*/ // Initalizing these to NULL prevents segfaults! AVFormatContext *pFormatCtx = NULL;//保存文件容器封裝信息及碼流參數(shù)的結(jié)構(gòu)體 AVCodecContext *pCodecCtxOrig = NULL;//解碼器上下文對象,解碼器依賴的相關(guān)環(huán)境、狀態(tài)、資源以及參數(shù)集的接口指針 AVCodecContext *pCodecCtx = NULL;//編碼器上下文對象,用于PPM文件輸出 AVCodec *pCodec = NULL;//保存編解碼器信息的結(jié)構(gòu)體,提供編碼與解碼的公共接口,可以看作是編碼器與解碼器的一個全局變量 AVPacket packet;//負(fù)責(zé)保存壓縮編碼數(shù)據(jù)相關(guān)信息的結(jié)構(gòu)體,每幀圖像由一到多個packet包組成 AVFrame *pFrame = NULL;//保存音視頻解碼后的數(shù)據(jù),如狀態(tài)信息、編解碼器信息、宏塊類型表,QP表,運動矢量表等數(shù)據(jù) AVFrame *pFrameRGB = NULL;//保存輸出24-bit RGB的PPM文件數(shù)據(jù) struct SwsContext *sws_ctx = NULL;//描述轉(zhuǎn)換器參數(shù)的結(jié)構(gòu)體 int numBytes;//RGB24格式數(shù)據(jù)長度 uint8_t *buffer = NULL;//解碼數(shù)據(jù)輸出緩存指針 int i,videoStream;//循環(huán)變量,視頻流類型標(biāo)號 int frameFinished;//解碼操作是否成功標(biāo)識/*————-參數(shù)初始化————*/ if (argcstream 字段 * check out & Retrieve the stream information in the file * then populate pFormatCtx->stream with the proper information * pFormatCtx->streams is just an array of pointers, of size pFormatCtx->nb_streams ———————–*/ if (avformat_find_stream_info(pFormatCtx, NULL) streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) {//若文件中包含有視頻流 videoStream = i;//用視頻流類型的標(biāo)號修改標(biāo)識,使之不為-1 break;//退出循環(huán) } } if (videoStream==-1) {//檢查文件中是否存在視頻流 return -1; // Didn’t find a video stream. } // Get a pointer to the codec context for the video stream,根據(jù)流類型標(biāo)號從pFormatCtx->streams中取得視頻流對應(yīng)的解碼器上下文 pCodecCtxOrig = pFormatCtx->streams[videoStream]->codec; /*———————– * Find the decoder for the video stream,根據(jù)視頻流對應(yīng)的解碼器上下文查找對應(yīng)的解碼器,返回對應(yīng)的解碼器(信息結(jié)構(gòu)體) * The stream’s information about the codec is in what we call the “codec context. * This contains all the information about the codec that the stream is using ———————–*/ pCodec = avcodec_find_decoder(pCodecCtxOrig->codec_id); if (pCodec == NULL) {//檢查解碼器是否匹配 fprintf(stderr, “Unsupported codec!”); return -1; // Codec not found. } // Copy context,復(fù)制編解碼器上下文對象,用于保存從視頻流中抽取的幀 pCodecCtx = avcodec_alloc_context3(pCodec);//創(chuàng)建AVCodecContext結(jié)構(gòu)體對象pCodecCtx if (avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0) {//復(fù)制編解碼器上下文對象 fprintf(stderr, “Couldn’t copy codec context”); return -1; // Error copying codec context. } // Open codec,打開解碼器 if (avcodec_open2(pCodecCtx, pCodec, NULL) width, pCodecCtx->height, 1); buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));//為轉(zhuǎn)換后的RGB24圖像配置緩存空間 // Assign appropriate parts of buffer to image planes in pFrameRGB Note that pFrameRGB is an AVFrame, but AVFrame is a superset of AVPicture // 為AVFrame對象安裝圖像緩存,將out_buffer緩存掛到pFrameYUV->data指針結(jié)構(gòu)上 av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, buffer, AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height, 1); // Initialize SWS context for software scaling,設(shè)置圖像轉(zhuǎn)換像素格式為AV_PIX_FMT_RGB24 sws_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_RGB24, SWS_BILINEAR, NULL, NULL, NULL);/*————–循環(huán)解碼————-*/ i = 0;// Read frames(2 packet) and save first five frames to disk, /*———————– * read in a packet and store it in the AVPacket struct * ffmpeg allocates the internal data for us,which is pointed to by packet.data * this is freed by the av_free_packet() ———————–*/ while (av_read_frame(pFormatCtx, &packet) >= 0) {//從視頻文件或網(wǎng)絡(luò)流媒體中依次讀取每個圖像編碼數(shù)據(jù)包,并存儲在AVPacket數(shù)據(jù)結(jié)構(gòu)中 // Is this a packet from the video stream,檢查數(shù)據(jù)包類型 if (packet.stream_index == videoStream) { /*———————– * Decode video frame,解碼完整的一幀數(shù)據(jù),并將frameFinished設(shè)置為true * 可能無法通過只解碼一個packet就獲得一個完整的視頻幀frame,可能需要讀取多個packet才行 * avcodec_decode_video2()會在解碼到完整的一幀時設(shè)置frameFinished為真 * Technically a packet can contain partial frames or other bits of data * ffmpeg’s parser ensures that the packets we get contain either complete or multiple frames * convert the packet to a frame for us and set frameFinisned for us when we have the next frame ———————–*/ avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet); // Did we get a video frame,檢查是否解碼出完整一幀圖像 if (frameFinished) { // Convert the image from its native format to RGB,//將解碼后的圖像轉(zhuǎn)換為RGB24格式 sws_scale(sws_ctx, (uint8_t const * const *) pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize); if (++i width, pCodecCtx->height, i); } } } // Free the packet that was allocated by av_read_frame,釋放AVPacket數(shù)據(jù)結(jié)構(gòu)中編碼數(shù)據(jù)指針 av_packet_unref(&packet); }/*————–參數(shù)撤銷————-*/ // Free the RGB image buffer av_free(buffer); av_frame_free(&pFrameRGB); // Free the YUV frame. av_frame_free(&pFrame); // Close the codecs. avcodec_close(pCodecCtx); avcodec_close(pCodecCtxOrig); // Close the video file. avformat_close_input(&pFormatCtx); return 0;}

      鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場,版權(quán)歸原作者所有,如有侵權(quán)請聯(lián)系管理員(admin#wlmqw.com)刪除。
      用戶投稿
      上一篇 2022年6月26日 06:29
      下一篇 2022年6月26日 06:29

      相關(guān)推薦

      • 抖音只說了封禁沒說時長(抖音封禁一般多長時間)

        最近是不是發(fā)現(xiàn)抖音監(jiān)管和封號的力度大了很多,我常能看到,有同學(xué)吐槽,為什么又被封了,我也沒有違規(guī)呀!! 那么今天,我就列出4大容易被封的原因,幫你避開90%的坑。學(xué)會了就點贊吧。 …

        2022年11月27日
      • 短視頻策劃內(nèi)容的3個要點(短視頻策劃內(nèi)容怎么做)

        短視頻在制作時,內(nèi)容框架非常重要。如果直奔主題,然后結(jié)束,聚卓告訴你,這樣的短視頻已經(jīng)過時了。現(xiàn)在的短視頻需要框架的,但不是任何框架,它需要一種易于理解和消化的框架。而且,現(xiàn)在大多…

        2022年11月27日
      • 存儲過程語法(sql server存儲過程語法)

        今天小編給各位分享存儲過程語法的知識,其中也會對sql server存儲過程語法進(jìn)行解釋,如果能碰巧解決你現(xiàn)在面臨的問題,別忘了關(guān)注本站,現(xiàn)在開始吧! oracle存儲過程基本語法…

        2022年11月26日
      • 計算機(jī)網(wǎng)絡(luò)技術(shù)論文(計算機(jī)網(wǎng)絡(luò)技術(shù)論文七千字)

        今天小編給各位分享計算機(jī)網(wǎng)絡(luò)技術(shù)論文的知識,其中也會對計算機(jī)網(wǎng)絡(luò)技術(shù)論文七千字進(jìn)行解釋,如果能碰巧解決你現(xiàn)在面臨的問題,別忘了關(guān)注本站,現(xiàn)在開始吧! 計算機(jī)網(wǎng)絡(luò)方面的論文3000字…

        2022年11月26日
      • 個人怎么做抖音帶貨(個人做抖音帶貨能賺錢嗎)

        抖音如今是大家很熟悉的短視頻平臺,不過現(xiàn)在的抖音卻不只是短視頻那么簡單,它的功能非常豐富,其中一個就是可以帶貨,相信很多小伙伴都有在抖音上買過東西,抖音如今的變現(xiàn)能力也是不容小覷的…

        2022年11月25日
      • 全民K歌升級新版本7.0之后,有哪些隱藏功能?

        作者:高百烈來源:知乎 這個功能,舊版并沒有,要升級到全新的全民K歌7.0版本才能發(fā)現(xiàn)。 作為朋友圈當(dāng)代K歌之王,我費了不少功夫才搶到內(nèi)測版本。有一說一,全民K歌的路子真的很野,新…

        2022年11月25日
      • “濛翔”搭檔展現(xiàn)不一樣的世界杯 中國移動咪咕多檔綜藝上線

        2022國際足聯(lián)卡塔爾世界杯如火如荼進(jìn)行中,王濛、黃健翔冬奧之后再聚首,作為咪咕嘉賓天團(tuán)的成員,不僅陪伴觀眾直擊現(xiàn)場,暢聊世界杯賽場內(nèi)外趣事,更攜手于11月26日、11月30日在咪…

        2022年11月25日
      • 直播帶貨詳細(xì)腳本(直播文案策劃怎么寫)

        短視頻運營策劃方案怎么寫?涉及哪幾個方面? 我在網(wǎng)上看到好多千篇一律的文章,關(guān)于【短視頻運營策劃方案】這一塊,基本都是在講賬號的內(nèi)容本身。 你內(nèi)容做得再好,卻不掌握算法的規(guī)律,能有…

        2022年11月25日
      • 2022世界杯免費直播平臺有哪些(2022世界杯免費直播平臺)

        世界杯近期的人氣超級火爆的,大家雖然不能去現(xiàn)場觀看卡塔爾世界杯比賽,不過國內(nèi)的球迷也都第一時間通過世界杯了解賽事情況。2022世界杯免費直播平臺有哪些?據(jù)悉本屆世界杯國內(nèi)的直播平臺…

        2022年11月24日
      • 咪咕世界杯怎么投屏到電視上(咪咕視頻世界杯會員是什么)

        最近關(guān)于2022年卡塔爾世界杯人氣超級火爆的,大家也都想要觀看世界杯的所有比賽直播,而咪咕視頻也可以觀看本屆世界杯。那么,咪咕世界杯怎么投屏到電視上?投屏到電視上門觀看世界杯體驗感…

        2022年11月24日

      聯(lián)系我們

      聯(lián)系郵箱:admin#wlmqw.com
      工作時間:周一至周五,10:30-18:30,節(jié)假日休息