GStreamer SDK 1.0 Build Via Cerbero

本文編寫(xiě)時(shí)基于GStreamer v1.11.0版,文中提及所有目錄結(jié)構(gòu)、文件、模塊等信息也均以v1.11.0為標(biāo)準(zhǔn)。后續(xù)如GStreamer官方SDK有做較大變動(dòng),請(qǐng)自行適配。

1. GStreamer Introduction

GStreamer是一個(gè)基于流水線的多媒體框架,其內(nèi)部基于GObject,以C語(yǔ)言寫(xiě)成(參見(jiàn)Wikipedia)。GStreamer采用基于plugin和pipeline的體系機(jī)構(gòu),框架中所有的功能模塊都是可插拔的plugins,可以很方便地安裝到任意pipeline上。

1.1 GStreamer 環(huán)境

通常,在運(yùn)行基于GStreamer開(kāi)發(fā)的程序前,需要配置開(kāi)發(fā)平臺(tái)所需環(huán)境,建議直接下載已編譯的安裝包,實(shí)在有特定需求(如裁剪、特定庫(kù)支持)時(shí),再考慮手動(dòng)編譯SDK。

GStreamer最新版本(1.11.0)中支持的系統(tǒng)具體如下:

  • Linux
    大部分Linux發(fā)行版均已提供GStreamer package,但部分發(fā)行版由于法律原因等會(huì)對(duì)GStreamer plugins進(jìn)一步切割,因此可能不會(huì)包含gst-plugins-bad、gst-plugins-ugly及gst-libav pacakges

  • OpenBSD
    不同架構(gòu)的package都有支持

  • Windows
    提供相應(yīng)版本MSI安裝器,SDK共提供三種文件,分別為:

    • Runtime:運(yùn)行GStreamer程序必需的文件,可能會(huì)隨程序一同發(fā)布
    • Development:開(kāi)發(fā)GStreamer程序額外所需的文件
    • Merge Modules:為GStreamer程序部署SDK所需的額外文件
  • Mac OS X
    提供相應(yīng)的框架

  • Android
    提供可被集成入Android NDK的GStreamer Binaries

  • IOS
    提供可被集成入XCode的GStreamer Binaries

  • Source

1.2 GStreamer內(nèi)部模塊

依據(jù)plugins功能及實(shí)現(xiàn)算法性能的不同,GStreamer將其分為如下模塊:

2. Cerbero編譯系統(tǒng)

Cerbero是一個(gè)服務(wù)于開(kāi)源項(xiàng)目的多平臺(tái)編譯系統(tǒng),它為不同體系、發(fā)行版的平臺(tái)編譯并創(chuàng)建本地化package。

2.1 Cerbero基礎(chǔ)環(huán)境搭建

雖然Cerbero已經(jīng)為各個(gè)平臺(tái)提供了bootstrap(啟動(dòng)引導(dǎo)項(xiàng)),但仍需要一些基礎(chǔ)環(huán)境來(lái)支持bootstrap。

由于Cerbero使用Python2.x(>= 2.6)開(kāi)發(fā)編譯腳本,因此不論是什么平臺(tái)都必須安裝Python,本教程中安裝版本為v2.7。除此之外,各平臺(tái)所需依賴(lài)項(xiàng)各有不同。具體如下:

2.1.1 OSX

在OSX上你需要安裝如下軟件:

Note:
此次實(shí)際編譯并未涉及OSX平臺(tái),因此IOS及OSX相關(guān)部分編譯并未測(cè)試,如需編譯SDK,可參照教程中通用部分或根據(jù)github自行完成。

2.1.2 Linux(以Ubuntu為例)

測(cè)試環(huán)境為Ubuntu 14.04,其他版本或發(fā)行版僅供參考。需確認(rèn)如下軟件是否安裝:

  • Git
    如當(dāng)前環(huán)境中沒(méi)有g(shù)it工具,請(qǐng)先手動(dòng)安裝完成。


    安裝完成后,配置git信息。

      git config --global user.email "xxxx@xxx.com"
      git config --global user.name "xxxx"
    
  • Python 2.x
    確認(rèn)所使用的發(fā)行版中python版本>= 2.6且已添加python的argparse模塊(Python2.7已默認(rèn)支持)。


如出現(xiàn)正常安裝步驟報(bào)錯(cuò)時(shí),請(qǐng)嘗試先手動(dòng)sudo apt-get update && upgrade完善系統(tǒng)后重試。

2.1.3 Windows

Windows中環(huán)境配置較為復(fù)雜,編譯SDK通常也相對(duì)耗時(shí)較長(zhǎng),但由于其中Directshow Plugins需使用到Directshow base classes,仍依賴(lài)Microsoft編譯器和SDK完成編譯,所以也無(wú)法通過(guò)Linux系統(tǒng)完美跨平臺(tái)編譯。

同時(shí)Cerbero默認(rèn)使用Makefile進(jìn)行所有項(xiàng)目的編譯,類(lèi)似Unix,因此如需在Windows中正常編譯,必須首先配置Unix編譯環(huán)境。

具體需安裝項(xiàng)如下:

  • Python2.7 : Download
    切記只能安裝2.7版本,3.x版本并不支持

  • CMake : Download
    下載的x86版本可同樣支持x64版本編譯,安裝時(shí)勾選添加至環(huán)境變量。

  • Git : Download
    安裝過(guò)程中選擇“Checkout as-is, commit as-is"選項(xiàng),其他保持默認(rèn)


    安裝完成后,配置git信息。

      git config --global user.email "xxxx@xxx.com"
    git config --global user.name "xxxx"
    
  • Msys/MinGW : Download


    勾選"Basic Setup"所有項(xiàng)進(jìn)行安裝。

    此處選擇所有項(xiàng)為便捷做法,如有興趣,可嘗試去除如gcc-ada等項(xiàng),以最小化安裝

  • Wix 3.5 :Download
    Windows MSI打包工具,默認(rèn)安裝即可

  • Microsoft SDK 7.1 : Download
    安裝Win7.1 SDK GRMSDKX_EN_DVD.7z(帶X),只有該包中存在amd64.msi,否則安裝時(shí)因找不到文件報(bào)錯(cuò)而安裝失敗。

    如安裝過(guò)程中報(bào)錯(cuò)不能安裝依賴(lài)于 .NET Framework 4的組件,則請(qǐng)下載.NET 4并安裝后重試。

  • Windows Driver Kit 7.1.0 : Download
    安裝GRMWDK_EN_7600_1.iso

安裝完上述項(xiàng)后,由于Cerbero必須在MinGW shell中運(yùn)行,因此必須為shell配置部分程序環(huán)境變量:

  • windows x86

      echo 'export PATH="$PATH:/c/Python27:/c/Program Files(x86)/Git/bin:/c/MinGW/bin/
    
  • windows x64

      echo 'export PATH="$PATH:/c/Python27:/c/Program Files/Git/bin:/c/MinGW/bin/"' > ~/.profile
    

Note:
如生成的“.profile”文件與shell不位于同一路徑下,請(qǐng)手動(dòng)拷貝至同一路徑下。并在shell中運(yùn)行python、git、cmake命令確認(rèn)已生效。

至此,Cerbero基礎(chǔ)環(huán)境已搭建完成。

2.2 Cerbero基礎(chǔ)編譯過(guò)程

此處以Windows平臺(tái)編譯為示例,Linux可參照進(jìn)行,步驟一致,唯一區(qū)別為打包后文件格式不同。

編譯之前,需在shell中運(yùn)行如下命令行進(jìn)行版本庫(kù)克隆:

git clone git://anongit.freedesktop.org/gstreamer/sdk/cerbero

clone成功后,目錄結(jié)構(gòu)(v1.11.0)如下圖所示:

此處最好將cerbero完整文件夾內(nèi)容拷貝值/home/usrxxx/下,以避免后面compile過(guò)程中出現(xiàn)完整路徑過(guò)長(zhǎng)而導(dǎo)致失敗問(wèn)題。具體可參造4.5小節(jié)內(nèi)容。

可以看到文件夾上有勾選標(biāo)號(hào)提示,這是ToriseGit的功能,Windows下平臺(tái)可以更加便捷直觀地查看git庫(kù)文件,在裁剪SDK時(shí)有較大幫助,建議安裝。當(dāng)然,不安裝也不影響后續(xù)操作。

可以看到根目錄下存在 setup.py文件,而實(shí)際上cerbero編譯工具使用前并不需要安裝,只需要直接運(yùn)行cerbero-uninstalled腳本及選項(xiàng)(可選)即可。

2.2.1 cerbero-uninstalled常用選項(xiàng)

編譯之前,先簡(jiǎn)單了解下cerbero-uninstalled的常用選項(xiàng):

./cerbero-uninstalled --help

其輸出內(nèi)容為:

usage: cerbero-uninstalled [-h] [-c CONFIG]
                           {add-recipe,rdeps,tag,genxcconfig,genlibfiles,check,list-packages,show-config,add-package,build,genvsprops,shell,run,cleanone,packageinfo,bundle-source,buildone,wipe,debug-packages,package,bootstrap,list,checkpackage,deps,gensdkshell,fetch-package,fetch}
                           ...

Build and package a set of modules to distribute them in a SDK

positional arguments:
  {add-recipe,rdeps,tag,genxcconfig,genlibfiles,check,list-packages,show-config,add-package,build,genvsprops,shell,run,cleanone,packageinfo,bundle-source,buildone,wipe,debug-packages,package,bootstrap,list,checkpackage,deps,gensdkshell,fetch-package,fetch}
                        sub-command help
    add-recipe          Adds a new recipe
    rdeps               List the reverse dependencies of a recipe
    tag                 Tag a git recipe or all git recipes using their
                        sdk-$version branch
    genxcconfig         Generate XCode config files to use the SDK from VS
    genlibfiles         Generate MSVC compatible library files (.lib)
    check               Run checks on a given recipe
    list-packages       List all the available packages
    show-config         Show configuration settings
    add-package         Adds a new package
    build               Build a recipe
    genvsprops          Generate Visual Studio property sheets to use the SDK
                        from VS
    shell               Starts a shell with the build environment
    run                 Runs a command in the cerbero shell
    cleanone            Clean a single recipe without its dependencies
    packageinfo         Print information about this package
    bundle-source       Bundle Source code of recipes and Cerbero
    buildone            Build or rebuild a single recipe without its
                        dependencies
    wipe                Wipes everything to restore the build system
    debug-packages      Outputs debug information about package, like
                        duplicates files or files that do not belong to any
                        package
    package             Creates a distribution package
    bootstrap           Bootstrap the build system installing all the
                        dependencies
    list                List all the available recipes
    checkpackage        Run checks on a given package
    deps                List the dependencies of a recipe
    gensdkshell         Create a script with the shell environment for the SDK
    fetch-package       Fetch the recipes sources from a package
    fetch               Fetch the recipes sources

optional arguments:
  -h, --help            show this help message and exit
  -c CONFIG, --config CONFIG
                        Configuration file used for the build

上面列出的命令實(shí)際上都定義于./cerbero/commands/路徑下,以相應(yīng)名稱(chēng)的python腳本文件形式存在,如:

雖然cerbero-uninstalled支持很多命令,但編譯相關(guān)的并不多,這里僅介紹如下常用選項(xiàng):

  • [-c CONFIG]
    cerbero-unistalled編譯時(shí),如未使用該選項(xiàng),則cerbero-unistalled使用默認(rèn)配置(等價(jià)于變量)進(jìn)行編譯;如指定cbc文件,則使用指定配置完成編譯。

    可選擇的CONFIG文件位于/config路徑下,如下圖所示:

  • list
    列出所有可選的recipes;recipe用于指定某個(gè)模塊的源、依賴(lài)項(xiàng)、編譯步驟、產(chǎn)出庫(kù)(動(dòng)態(tài)、靜態(tài))等編譯過(guò)程相關(guān)信息。

    可選擇的recipe文件位于/recipes目錄下,由于數(shù)量較多,截取部分如下圖所示:

  • list-packages
    列出所有可打包的packages;打包實(shí)質(zhì)上是將編譯過(guò)程中各模塊相關(guān)文件(頭文件、庫(kù)等),按照對(duì)應(yīng)的package文件內(nèi)容取出至指定路徑,壓縮并打包為對(duì)應(yīng)平臺(tái)文件。

    可選擇的package文件位于/packages路徑下,如下圖所示:

  • bootstrap
    下載并安裝當(dāng)前環(huán)境下編譯時(shí)所需工具

  • build
    編譯某個(gè)recipe,包括其依賴(lài)項(xiàng)

  • buildone
    編譯某個(gè)recipe,不包括其依賴(lài)項(xiàng)

  • cleanone
    清理某個(gè)recipe

  • package
    打包某個(gè)package,遞歸遍歷所有依賴(lài)項(xiàng)。

  • wipe
    清理之前build過(guò)程中產(chǎn)生的所有文件,慎用

2.2.2 cerbero-uninstalled基礎(chǔ)編譯

本節(jié)內(nèi)容閱讀默認(rèn)前面章節(jié)所述環(huán)境均已安裝配置完善,繼續(xù)閱讀前,請(qǐng)確認(rèn)均已完備。

選擇只簡(jiǎn)單指定.cbc文件,而不修改配置文件(package、recipe、commands等)直接編譯,可能存在如下問(wèn)題:

  • 模塊依賴(lài)項(xiàng)多,打包操作內(nèi)部遍歷后整體所需編譯模塊較多,造成編譯耗時(shí)長(zhǎng)(虛擬機(jī)測(cè)試2天左右)
  • 部分特定模塊打包時(shí)并未勾選,造成安裝編譯后SDK無(wú)法提供相應(yīng)環(huán)境支持

如可接受上述問(wèn)題,則可按照如下步驟進(jìn)行基礎(chǔ)編譯:

./cerbero-uninstalled -c config/xxx.cbc bootstrap
./cerbero-uninstalled -c config/xxx.cbc package gstreamer-1.0

編譯成功后,將生成對(duì)應(yīng)平臺(tái)文件,如windows中msi,linux下tar.bz2文件等。

Note:
編譯過(guò)程中如出現(xiàn)錯(cuò)誤,可先跳轉(zhuǎn)至章節(jié) “4. 問(wèn)題-解決方法匯總”查看是否已有記錄。

3. Cerbero配置

Cerbero內(nèi)部使用了典型的oven-cookbook-recipe結(jié)構(gòu),結(jié)合其他功能命令、config等模塊構(gòu)建整個(gè)編譯系統(tǒng)。

Projects通過(guò)recipes文件(.recipe)來(lái)定義,文件中描述了需要編譯的項(xiàng)目信息,如name, version, license, sources和編譯方法。同時(shí),還提供了一些用于后續(xù)打包的文件。

Packages通過(guò)packages文件(.package)來(lái)定義,文件中描述了包信息,如name, version, license, maintainer和其他用于打包的內(nèi)容。一個(gè)包內(nèi)部包含了一系列recipes,安裝時(shí)將進(jìn)行展開(kāi)。

3.1 定制編譯步驟

如前所述,projects通過(guò)recipe文件來(lái)定義,build過(guò)程中會(huì)根據(jù)recipe內(nèi)容進(jìn)行編譯。編譯步驟實(shí)際上分為六步,分別為:

  • Fetch
  • Extract
  • Configure
  • Compile
  • Install
  • Post_install

第一次編譯時(shí),必須Fetch相關(guān)源以進(jìn)行后續(xù)步驟,但通常在編譯成功后,我們將不再希望所有模塊每次編譯時(shí)都自動(dòng)更新為最新版本(穩(wěn)定性不可控),此時(shí)可以將Fetch步驟去除,之后的build便會(huì)基于已有的源包進(jìn)行編譯。

./cerbero/build/recipe.py

3.2 指定模塊編譯版本

編譯時(shí),可能會(huì)出現(xiàn)某個(gè)模塊的最新或特定版本存在bug,此時(shí)可通過(guò)指定模塊編譯版本來(lái)解決。

3.2.1 SourceType.GIT

以libffi為例, 修改下圖中標(biāo)示處:


其中commit等可從已clone下來(lái)的git版本庫(kù)中獲取,需為對(duì)應(yīng)版本commit id。修改完成后,確認(rèn)是否有其他相關(guān)內(nèi)容需一并修改,此處需自行調(diào)整。

clean后重新build,測(cè)試通過(guò)。

3.2.2 SourceType.TARBALL

此處以faad2為例,修改下圖中標(biāo)示處:


修改version、url地址,url地址需訪問(wèn)鏈接進(jìn)行手動(dòng)確認(rèn),方法通常為去除末端版本字段,如faad2-2.7.tar.bz后訪問(wèn)。其他獲取方法請(qǐng)自行研究。

3.2.3 SourceType.SVN

此處以Tremor為例,修改如下圖標(biāo)示處:

3.3 GStreamer SDK 裁剪

./cerbero-unistalled -c config/xxx.cbc package gstreamer-1.0

鍵入該命令行,可開(kāi)始gstreamer-1.0 SDKpackage動(dòng)作。

SDK實(shí)質(zhì)上是package所有recipe build后相關(guān)文件的產(chǎn)物,對(duì)應(yīng)編譯中參與的角色(總package、子package、模塊),裁剪也分為如下三種:

3.3.1 總package裁剪-.package

gstreamer-1.0 的package文件位于路徑 ./packages/gstreamer-1.0/下。

首先整體瀏覽下該package文件內(nèi)容:

# -*- Mode: Python -*- vi:si:et:sw=4:sts=4:ts=4:syntax=python
class SDKPackage(package.SDKPackage):
    name = "gstreamer-1.0"
    shortdesc = "GStreamer 1.0"
    longdesc = "GStreamer 1.0"
    title = "GStreamer 1.0"
    url = "http://gstreamer.freedesktop.org"
    version = '1.9.0.1'
    sdk_version = '1.0'
    codename = 'Congo'
    license = License.LGPL
    uuid = 'b1b4b712-0d09-4a34-8117-8a69b6deecc2'
    vendor = "GStreamer Project"
    org = "org.freedesktop.gstreamer"
    ignore_package_prefix = True
    packages =[
        # (name, required, selected)
        ('gstreamer-1.0-core', True, True),
        #('gstreamer-1.0-system', False, True),
        #('gstreamer-1.0-playback', False, True),
        ('gstreamer-1.0-codecs', False, True),
        ('gstreamer-1.0-effects', False, True),
        #('gstreamer-1.0-net', False, True),
        #('gstreamer-1.0-visualizers', False, True),
        #('gstreamer-1.0-codecs-gpl', False, False),
        ('gstreamer-1.0-codecs-restricted', False, True),
        #('gstreamer-1.0-net-restricted', False, False),
        #('gstreamer-1.0-dvd', False, False),
        #('gstreamer-1.0-libav', False, False),
        #('gstreamer-1.0-encoding', False, False),
        ('gstreamer-1.0-capture', False, False),
        #('gstreamer-1.0-editing', False, False),
        ('gstreamer-1.0-devtools', False, False),
    ]
    platform_packages = {
        Platform.WINDOWS: [
            ('vsintegration-1.0', True, False),
            ('gstreamer-1.0-vs-templates', True, False),
        ],
    }

    install_dir = {
        Platform.WINDOWS: 'gstreamer',
        Platform.LINUX: '/opt/gstreamer-1.0/',
        Platform.DARWIN: '/Library/Frameworks/GStreamer.framework/',
        Platform.IOS: '/Library/Developer/GStreamer/iPhone.sdk'
    }

    root_env_var = 'GSTREAMER_1_0_ROOT_%(arch)s'
    wix_upgrade_code = {
        PackageType.DEVEL: {
            Architecture.X86 : 'c0c6126d-1f4a-4577-9598-e900f594fd06',
            Architecture.X86_64: '49c4a3aa-249f-453c-b82e-ecd05fac0693',
        },
        PackageType.RUNTIME: {
            Architecture.X86 : 'ebe0c791-d84e-4f7e-a4eb-18012a0e319d',
            Architecture.X86_64: 'c20a66dc-b249-4e6d-a68a-d0f836b2b3cf',
        },
    }
    osx_framework_library = ('GStreamer', 'lib/GStreamer')
    ios_framework_library = ('GStreamer', 'lib/GStreamer')
    
    def prepare(self):
        if self.config.target_platform in [Platform.ANDROID, Platform.IOS]:
        p = ['gstreamer-1.0-dvd']
        self.packages = [ x for x in self.packages if x[0] not in p]
        if self.config.target_platform == Platform.IOS:
            self.resources_postinstall = 'post_install_ios'
            #self.user_resources = ['share/gst-sdk/tutorials/xcode iOS']

從面的代碼中可以看出,裁剪過(guò)程中,只需要關(guān)注gstreamer-1.0.package文件的如下字段:

  • packages
  • platform_packages
    對(duì)于不需要的子package可以直接使用#注釋掉以裁剪。至于如何確認(rèn)是否需要,就要打開(kāi)各子package甚至更底層的模塊recipe文件進(jìn)行確認(rèn)。

gstreamer-1.0-codecs.package為例,如下圖所示:


實(shí)際上,子package文件中也只是在deps、files、files_devel、platform_files這些字段中粗略列出相關(guān)模塊和庫(kù),如需最終確認(rèn)是否存在依賴(lài)或裁剪的空間,需進(jìn)一步打開(kāi)所引入的模塊recipe文件。

gst-plugins-good-1.0為例,子package gstreamer-1.0-codecs.package中使用了其:plugins_codecs:plugins_codecs_devel兩項(xiàng)內(nèi)容,因此我們只關(guān)注gst-plugins-good-1.0.recipe文件中的這兩部分。

:plugins_codecs_devel字段不存在
此時(shí)可以清晰地看到,子package中引入模塊字段處其實(shí)是包含了模塊中對(duì)應(yīng)字段所有l(wèi)ib。如無(wú)需將這些lib打包到SDK中,則可在子package中移除對(duì)該字段的引入。

3.3.2 子package裁剪-.package

上節(jié)的裁剪是總package級(jí)別的,簡(jiǎn)單卻也也粗暴,只能以package為單位進(jìn)行裁剪,控制精度很低。實(shí)際上,為提高精度,可以對(duì)子package做進(jìn)一步的裁剪。

gstreamer-1.0-codecs.package為例,可做如下裁剪(具體裁剪內(nèi)容根據(jù)需求決定):

3.3.3 模塊裁剪-.recipe

上節(jié)的子package裁剪雖然已經(jīng)比總package級(jí)別裁剪精密很多,但某些時(shí)候,我們可能只需要在最終SDK中包含某子package所引入模塊字段中的一個(gè)lib,其他lib都可以去除,此時(shí)就需要進(jìn)行模塊級(jí)別的裁剪。

gst-plugins-good-1.0.recipe為例,可做如下裁剪示例(其他字段可參照進(jìn)行):


4. 問(wèn)題-解決方法匯總

4.1 Git信息未配置


解決辦法為根據(jù)提示配置信息:

git config --global user.email "xxxx@xxx.com"
git config --global user.name "xxxx"

4.2 Download certificate 驗(yàn)證


將參數(shù)check_cert=True修改為check_cert=False以關(guān)閉驗(yàn)證。

4.3 Console Unicode


The most secure solution is this one: Go to your Registry key HKEY_CURRENT_USER\Software\Microsoft\Command Processor and add String value Autorun = chcp 65001.

4.4 GPLed program for Windows NT/...


msgfmt是gettext中的一部分,使用gettext0.19.5中發(fā)現(xiàn)該系列程序運(yùn)行會(huì)出錯(cuò),而在gettext0.18.2中并未出現(xiàn)該問(wèn)題。目前采用的方法是恢復(fù)使用0.18.2系列msgfmt程序替代。
Download

4.5 webrtc-audio-processing compile error


查找到根本問(wèn)題為make過(guò)程中對(duì)應(yīng).o文件拼接后路徑過(guò)長(zhǎng)

需cebero文件夾內(nèi)容直接放置在home/usrxx/目錄下以減少完整路徑長(zhǎng)度。

4.6Ubuntu Android SDK libmad缺失

解決方法為去除對(duì)libmad項(xiàng)的依賴(lài),需修改文件有:

  • ./recipes/gst-plugins-ugly-1.0.recipe


  • ./recipes/gst-plugins-ugly-1.0-static.recipe


  • ./packages/gstreamer-1.0-codec-restricted.package


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容