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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

如何基于FFMPEG和SDL写一个少于1000行代码的视频播放器

發(fā)布時間:2023/12/18 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何基于FFMPEG和SDL写一个少于1000行代码的视频播放器 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

?

?

http://blog.csdn.net/eplaylity/archive/2008/12/05/3454431.aspx

http://www.cnblogs.com/konyel/tag/SDL+Guide+%E4%B8%AD%E6%96%87%E8%AF%91%E7%89%88/

ffmpeg文檔http://blog.sina.com.cn/s/blog_46dc65a90100a91b.html

http://dranger.com/ffmpeg/ffmpeg.html

VLC核心

功能部份:

VLC媒體播放器的核心是libvlc ,它提供了界面,應用處理功能,如播放列表管理,音頻和視頻解碼和輸出,線程系統(tǒng)。所有l(wèi)ibvlc源文件設在的/src目錄及其子目錄:

# config/ :從命令行和配置文件加載配置,提供功能模塊的讀取和寫入配置
# control/: 提供動作控制功能,如播放/暫停,音量管理,全屏,日志等。
# extras/: 大多是平臺的特殊代碼
# modules/: 模塊管理
# network/: 提供網(wǎng)絡接口(socket管理,網(wǎng)絡錯誤等)
# osd/: 顯示屏幕上的操作
# test/: libvlc測試模塊
# text/: 字符集
# interface/ : 提供代碼中可以調(diào)用的接口中,如按鍵后硬件作出反應。
# playlist/: 管理播放功能,如停止,播放,下一首,隨機播放等
# input/: 建立并讀取一個輸入流,并且分離其中的音頻和視頻,然后把分離好的音頻流和視頻流發(fā)送給解碼器.
# video_output/ : 初始化視頻播放器,把從解碼器得到的視頻畫面轉(zhuǎn)化格式(從YUV 轉(zhuǎn)為 RGB)然后播放它們
# audio_output/ : 初始化音頻混合器,即設置正確的同步頻率,并對從解碼器傳來的音頻流重新取樣
# stream_output/: 輸出音頻流和視頻流到網(wǎng)絡
# misc/: libvlc使用的其他部分功能 ,如線程系統(tǒng),消息隊列, CPU的檢測,對象查找系統(tǒng),或平臺的特定代碼。

模塊部份:

VLC媒體播放器的模塊部份,在/modules的子目錄下(詳細說明可以參考其下的List文件),這些模塊只在程序載入它們時有效.每一個模塊,可提供不同的功能,它們會適合的特定文件或某一特定的環(huán)境.此外,audio_output/video_output/interface 模塊都寫成了可跨平臺的代碼,方便支持新的平臺(如beos或服務Mac OS X ) 。

插件模塊可以在 src/modules.c 和 include/vlc_modules*.h 提供函數(shù)中,動態(tài)加載和卸載

LibVLC可以將模塊直接插入到應用程序中,例如不支持動態(tài)加載代碼的操作系統(tǒng).模塊靜態(tài)插入到應用程序叫內(nèi)建.


VLC框架分析

1.vlc.c 只是入口程序

2.Libvlc.c 是各個模塊的結(jié)合點,這要是對接口編程

  • Vlc_Create(): 兩個重要的數(shù)據(jù)結(jié)構(gòu):libvlc_t & vlc_t , 所有的參數(shù)傳遞都在這里面
  • Vlc_Init(): 初始化參數(shù), module_bank
  • Vlc_AddInf(): 添加module

3./src/misc/configure.c 命令行參數(shù)和參數(shù)文件分析
參數(shù)文件是~/.vnc/vlcrc。其中可以設置log文件的位置

4./include/ 所有頭文件的集合

5./src/interface/Interface.h 所有module的集合

6./src/misc/Modules.c
其中module_t * __module_Need( vlc_object_t *p_this, const char *psz_capability,
const char *psz_name, vlc_bool_t b_strict ) 方法是尋找合適的interface
如果找到合適的,就調(diào)用AllocatePlugin()動態(tài)的分配一個。

7.how to link to different modules without OOP

?

?

vlc網(wǎng)絡數(shù)據(jù)流接收處理過程分析

?

網(wǎng)絡數(shù)據(jù)流接收處理分析

1、在input.c(src/input)文件中的主線程循環(huán)

????? Thread in charge of processing the network packets and demultiplexing

RunThread( input_thread_t *p_input )

{

????????? InitThread( p_input ) ;

…………………………………………………….

???? input_SelectES( p_input, p_input->stream.p_newly_selected_es );

???????????? …………………………………………………….

??? ??/* Read and demultiplex some data. */

??? i_count = p_input->pf_demux( p_input );

?

}

2、在下列函數(shù)中:

  • 分離出access , demux , name字符串 ;
  • 根據(jù)分離出的access 字符串通過module_Need函數(shù)找到acess 指針模塊;
  • 根據(jù)分離出的demux 字符串通過module_Need函數(shù)找到demux 指針模塊;
  • static int InitThread( input_thread_t * p_input )

    {

    ???? msg_Dbg( p_input, "access `%s', demux `%s', name `%s'",

    ???????????? p_input->psz_access, p_input->psz_demux, p_input->psz_name );

    ?

    ??? /* Find and open appropriate access module */

    ??? p_input->p_access = module_Need( p_input, "access",

    ???????????????????????????????????? p_input->psz_access, VLC_TRUE );

    …………………………………………………….

    while( !input_FillBuffer( p_input ) )

    …………………………………………………….

    ??? /* Find and open appropriate demux module */

    ??? p_input->p_demux =

    ??????? module_Need( p_input, "demux",

    ???????????????????? (p_input->psz_demux && *p_input->psz_demux) ?

    ???????????????????? p_input->psz_demux : "$demux",

    ???????????????????? (p_input->psz_demux && *p_input->psz_demux) ?

    ???????????????????? VLC_TRUE : VLC_FALSE );

    …………………………………………………….

    }

    3、在ps.c (module/demux/mpeg)文件中

    a.通過消息映射宏賦值啟動函數(shù)Activate;

    b.通過函數(shù)Activate賦值p_input->pf_demux = Demux;

    c. 通過函數(shù)module_Need( p_input, "mpeg-system", NULL, 0 ) 激活p_input->p_demux_data->mpeg.pf_read_ps( p_input, &p_data )函數(shù)(pf_read_ps);

    d.在InitThread函數(shù)中激活;

    ?

    ??????? static int Activate( vlc_object_t * p_this )

    {

    ????? /* Set the demux function */

    p_input->pf_demux = Demux;

    p_input->p_private = (void*)&p_demux->mpeg;

    ??? p_demux->p_module = module_Need( p_input, "mpeg-system", NULL, 0 );

    }

    4、在system.c (module/demux/mpeg)文件中

    ???????? 賦值解碼模塊mpeg_demux_t的成員函數(shù);

    ???? static int Activate ( vlc_object_t *p_this )

    {

    ??? static mpeg_demux_t mpeg_demux =

    ??????????????????? { NULL, ReadPS, ParsePS, DemuxPS, ReadTS, DemuxTS };

    ??? mpeg_demux.cur_scr_time = -1;

    ??? memcpy( p_this->p_private, &mpeg_demux, sizeof( mpeg_demux ) );

    ?

    ??? return VLC_SUCCESS;

    }

    并且申明函數(shù)static ssize_t ReadPS( input_thread_t * p_input, data_packet_t ** pp_data );

    ?

    5、在ps.c (module/demux/mpeg)文件中

    Demux( input_thread_t * p_input )

    {

    i_result = p_input->p_demux_data->mpeg.pf_read_ps( p_input, &p_data );

    ??? ??p_input->p_demux_data->mpeg.pf_demux_ps( p_input, p_data );

    }

    進行讀取數(shù)據(jù)和分離工作;

    6、在system.c (module/demux/mpeg)文件中

    數(shù)據(jù)走向圖如下

    ReadPS-> PEEK-> input_Peek(src/input/input_ext-plugins.c)-> input_FillBuffert 通過 i_ret = p_input->pf_read( p_input,

    ????????? ????????????????????(byte_t *)p_buf + sizeof(data_buffer_t)

    ?????????????????????????????? + i_remains,

    ????????????????????????????? p_input->i_bufsize );

    input_thread_t結(jié)構(gòu)的pf_read函數(shù)成員如果是為udp.c(modules/access)的RTPChoose函數(shù)

    則在開啟access(UDP 模塊)時通過module_need 激活;

    激活網(wǎng)絡讀數(shù)據(jù)模塊 RTPChoose(modules/access/ udp.c)->Read->net_Read(src/misc/net.c);

    ?

    7、在input_programs.c(src/input)文件中

    ???????? 運行解碼器對ES流解碼

    ?? int input_SelectES( input_thread_t * p_input, es_descriptor_t * p_es )

    {

    ????? p_es->p_dec = input_RunDecoder( p_input, p_es );

    ??

    }

    input_SelectES(src/input/input_programs.c->input_RunDecodersrc/input/input_dec.c->DecoderThread->DecoderDecode ->vout_DisplayPicture

    VLC程序宏及線程分析

    第一部分 變量及宏定義
    1.消息映射宏
    vlc_module_begin();
    …………………..
    vlc_module_end();
    2.結(jié)構(gòu)中包含函數(shù)
    struct input_thread_t
    {
    VLC_COMMON_MEMBERS

    /* Thread properties */
    vlc_bool_t b_eof;
    vlc_bool_t b_out_pace_control;

    /* Access module */
    module_t * p_access;
    ssize_t (* pf_read ) ( input_thread_t *, byte_t *, size_t );
    int (* pf_set_program )( input_thread_t *, pgrm_descriptor_t * );
    int (* pf_set_area )( input_thread_t *, input_area_t * );
    void (* pf_seek ) ( input_thread_t *, off_t );
    }
    3.宏與換行符妙用
    #define VLC_COMMON_MEMBERS /
    /** /name VLC_COMMON_MEMBERS /
    * these members are common for all vlc objects /
    */ /
    /**@{*/ /
    int i_object_id; /
    int i_object_type; /
    char *psz_object_type; /
    char *psz_object_name; /
    /
    /** Just a reminder so that people don't cast garbage */ /
    int be_sure_to_add_VLC_COMMON_MEMBERS_to_struct; /
    /**@}*/

    #define VLC_OBJECT( x ) /
    ((vlc_object_t *)(x))+
    0*(x)->be_sure_to_add_VLC_COMMON_MEMBERS_to_struct

    struct vlc_object_t
    {
    VLC_COMMON_MEMBERS
    };//定義一個結(jié)構(gòu)來使用宏定義的公共成員

    4.定義導出函數(shù)
    #ifndef __PLUGIN__
    # define VLC_EXPORT( type, name, args ) type name args
    #else
    # define VLC_EXPORT( type, name, args ) struct _u_n_u_s_e_d_
    extern module_symbols_t* p_symbols;
    #endif
    5.定義回調(diào)函數(shù)

    typedef int ( * vlc_callback_t ) ( vlc_object_t *, /* variable's object */
    char const *, /* variable name */
    vlc_value_t, /* old value */
    vlc_value_t, /* new value */

    void * ); /* callback data */

    6.函數(shù)作為參數(shù)的定義方式
    Int Fun(int n,int (*pf)(int ,int),char *pstr)
    { int j =10;
    pf(n,j);
    }

    7.回調(diào)函數(shù)的聲明
    必須聲明為global,或者static

    Int vlc_callback_t (int ,int)
    {。。。。。。。。。。。}

    8.回調(diào)函數(shù)的使用
    Fun(0, vlc_callback_t,”test”);

    9.函數(shù)表達式
    #define input_BuffersInit(a) __input_BuffersInit(VLC_OBJECT(a))
    void * __input_BuffersInit( vlc_object_t * );

    #define module_Need(a,b,c,d) __module_Need(VLC_OBJECT(a),b,c,d)
    VLC_EXPORT( module_t *, __module_Need, ( vlc_object_t *, const char *, const char *, vlc_bool_t ) );

    10.定義函數(shù)
    /* Dynamic array handling: realloc array, move data, increment position */
    #define INSERT_ELEM( p_ar, i_oldsize, i_pos, elem ) /
    do /
    { /
    if( i_oldsize ) /
    { /
    (p_ar) = realloc( p_ar, ((i_oldsize) + 1) * sizeof( *(p_ar) ) ); /
    } /
    else /
    { /
    (p_ar) = malloc( ((i_oldsize) + 1) * sizeof( *(p_ar) ) ); /
    } /
    if( (i_oldsize) - (i_pos) ) /
    { /
    memmove( (p_ar) + (i_pos) + 1, /
    (p_ar) + (i_pos), /
    ((i_oldsize) - (i_pos)) * sizeof( *(p_ar) ) ); /
    } /
    (p_ar)[i_pos] = elem; /
    (i_oldsize)++; /
    } /
    while( 0 )


    應用為:
    INSERT_ELEM( p_new->p_libvlc->pp_objects,
    p_new->p_libvlc->i_objects,
    p_new->p_libvlc->i_objects,
    p_new );


    11.改變地址的方式傳遞其值
    stream_t *input_StreamNew( input_thread_t *p_input )
    { stream_t *s = vlc_object_create( p_input, sizeof( stream_t ) );
    input_stream_sys_t *p_sys;
    if( s )
    {
    s->p_sys = malloc( sizeof( input_stream_sys_t ) );
    p_sys = (input_stream_sys_t*)s->p_sys;
    p_sys->p_input = p_input;
    }
    return s;//注解:s->p_sys改變了
    }

    第二部分 程序框架實現(xiàn)
    1. 播放列表文件src/playlist/playlist.c的線程
    playlist_t * __playlist_Create ( vlc_object_t *p_parent )函數(shù)中創(chuàng)建的線程,線程函數(shù)為
    static void RunThread ( playlist_t *p_playlist )
    線程思路分析:
    在RunThread里面執(zhí)行循環(huán),如果沒有任務執(zhí)行,則適當?shù)难舆t,如果接到p_playlist->i_status != PLAYLIST_STOPPED的條件,則調(diào)用PlayItem( p_playlist )函數(shù),在PlayItem( p_playlist )函數(shù)中從新創(chuàng)建輸入線程。

    通過void playlist_Command( playlist_t * p_playlist, playlist_command_t i_command,int i_arg )接收來自GUI界面的各種命令,然后設置p_playlist->i_status的狀態(tài),由該狀態(tài)改變該播放列表文件主循環(huán)線程的執(zhí)行。

    2. 輸入文件SRC/INPUT/INPUT.C的輸入線程
    input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
    input_item_t *p_item )函數(shù)中創(chuàng)建的線程,線程函數(shù)為
    static int RunThread( input_thread_t *p_input )
    線程思路分析:
    由 input_thread_t結(jié)構(gòu)的成員分析是接收文件流還是網(wǎng)絡流,如果是文件流,則調(diào)用file module 的讀函數(shù)(pf_read)和打開函數(shù)(--).如果是network 則打開network module 的打開函數(shù)和讀函數(shù)(pf_read)。
    在 RunThread線程函數(shù)中接收數(shù)據(jù)和調(diào)用demux 或者decode etc處理。
    一旦產(chǎn)生新的輸入,則在播放列表線程中會首先結(jié)束該輸入線程,然后從新創(chuàng)建新的輸入線程。

    3. 視頻輸出文件src/video_output/ video_output.c的線程
    vout_thread_t * __vout_Create( vlc_object_t *p_parent,
    unsigned int i_width, unsigned int i_height,
    vlc_fourcc_t i_chroma, unsigned int i_aspect )函數(shù)中創(chuàng)建的線程,線程函數(shù)為
    static void RunThread( vout_thread_t *p_vout)
    線程思路分析:
    在RunThread里面執(zhí)行循環(huán),任務是顯示視頻。

    4. 在modules/gui/wxwindows/wxwindows.cpp中的GUI線程
    static void Run( intf_thread_t *p_intf ) 函數(shù)中創(chuàng)建的線程,線程函數(shù)為
    static void Init( intf_thread_t *p_intf )

    線程思路分析:
    在Init( intf_thread_t *p_intf )里面執(zhí)行循環(huán),創(chuàng)建新的GUI實例。Instance-》OnInit()(CreateDialogsProvider)-》DialogsProvider為運行的對話框。

    接收網(wǎng)絡文件的步驟
    OnOpenNet( wxCommandEvent& event )打開網(wǎng)絡文件的步驟。打開OpenDialog對話框,點擊Ok后調(diào)用OpenDialog::OnOk( wxCommandEvent& WXUNUSED(event) )函數(shù),調(diào)用playlist_Command函數(shù)改變播放列表線程的狀態(tài)。

    激活線程分析:
    在wxwindow.cpp中的消息映射中 set_callbacks( OpenDialogs, Close ); 則設置了module_t->pf_activate= OpenDialogs函數(shù),
    在module.c 的__module_Need( vlc_object_t *p_this, const char *psz_capability,
    const char *psz_name, vlc_bool_t b_strict )
    函數(shù)中用到了pf_activate激活GUI對話框;
    在video_output.c 的static void RunThread( vout_thread_t *p_vout)線程中,也用到了pf_activate激活GUI對話框;


    5. 開始所有module 的精髓
    消息映射宏
    vlc_module_begin();
    set_callbacks( NetOpen, NULL );
    vlc_module_end();
    然后設置模塊結(jié)構(gòu)的成員函數(shù)為:
    #define set_callbacks( activate, deactivate ) /
    p_submodule->pf_activate = activate; /
    p_submodule->pf_deactivate = deactivate

    在__module_Need函數(shù)中啟動pf_activate 激活相應的module。

    ?

    ?

    對VLC源代碼閱讀的計劃是從其程序的框架開始,先對其主要的文件進行整理: 1.include/main.h 文件: access to all program variables,主要定義了2個結(jié)構(gòu)體:libvlc_t,vlc_t。 ???????? a. struct libvlc_t 根據(jù)程序注釋:該結(jié)構(gòu)體只有一個實例,在main函數(shù)中被分配,而且只能在main中訪問。它用來存儲一些只能初始化一次的數(shù)據(jù),比如說cpu容量或者global lock. ????????? b. struct vlc_t?? 注釋稱:This structure is a LibVLC instance ???????? libvlc_t,vlc_t在VLC_COMMON_MEMBERS宏中出現(xiàn),分別定義了 libvlc_t *?? p_libvlc; vlc_t *?? p_vlc; 對象,注釋稱為 root of the evil,可見其結(jié)構(gòu)體的重要性.所有的參數(shù)傳遞都在這里面(具體尚不清楚)。 2.include/Vlc_common.h 文件:common definitions,Collection of useful common types and macros definitions,通用類型和宏定義的集合 ???????? 主要作用是為了將不同的操作系統(tǒng)中的變量定義統(tǒng)一起來,比如說根據(jù)將unit_8來統(tǒng)一代表unsiged char類型. ??????? 該文件中還定義了VLC_COMMON_MEMBERS宏,該宏中包括了所有VLC基本對象的通用成員變量:these members are common for all vlc objects。 ??????? 定義導出函數(shù)
    #ifndef __PLUGIN__
    #?? define VLC_EXPORT( type, name, args ) type name args
    #else
    #?? define VLC_EXPORT( type, name, args ) struct _u_n_u_s_e_d_
    extern module_symbols_t* p_symbols;
    #endif
    定義回調(diào)函數(shù)
    ????? typedef int ( * vlc_callback_t ) ( vlc_object_t *,????? /* variable's object */
    char const *,??????????? /* variable name */
    vlc_value_t,???????????? /* old value */
    vlc_value_t,??????????? /* new value */
    ????????????????????????????????????????????????? void * ); ??????????????? /* callback data */?????????? 3.include/vlc_objects.h 文件:vlc_object_t definition and manipulation methods,vlc_object_t的定義和處理函數(shù) ?????? struct vlc_object_t
    {
    VLC_COMMON_MEMBERS
    }; //定義一個結(jié)構(gòu)來使用宏定義的公共成員

    總結(jié)

    以上是生活随笔為你收集整理的如何基于FFMPEG和SDL写一个少于1000行代码的视频播放器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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