Android的多媒體框架OpenCore(PacketVideo)介紹

一部分 OpenCore概述:

  OpenCore的另外一個常用的稱呼是PacketVideo,它是Android的多媒體核心。事實上,PacketVideo是一家公司的名稱,而OpenCore是這套多媒體框架的軟件層的名稱。在Android的開發者中間,二者的含義基本相同。對比Android的其它程序庫,OpenCore的代碼非常龐大,它是一個基於C++的實現,定義了全功能的

操作系統移植層,各種基本的功能均被封裝成類的形式,各層次之間的接口多使用繼承等方式。

 

  OpenCore是一個多媒體的框架,從宏觀上來看,它主要包含了兩大方面的內容:

1)         PVPlayer:提供媒體播放器的功能,完成各種音頻(Audio)

視頻(Video)流的回放(Playback)功能

 

2)         PVAuthor:提供媒體流記錄的功能,完成各種音頻(Audio)、視頻(Video)流的以及靜態圖像捕獲功能

 

  PVPlayerPVAuthorSDK的形式提供給開發者,可以在這個SDK之上構建多種應用程序和服務。在移動終端中常常使用的多媒體應用程序,例如媒體播放器、照相機、錄像機、錄音機等等。

 

  爲了更好的組織整體的架構,OpenCore在軟件層次在宏觀上分成幾個層次: 

 

 

1)         OSCLOperating System Compatibility Library (操作系統兼容庫),包含了一些操作系統底層的操作,爲了更好地在不同操作系統移植。包含了基本數據類型、配置、字符串工具、IO、錯誤處理、線程等內 容,類似一個基礎的C++庫。

 

2)         PVMFPacketVideo Multimedia Framework (PV多媒體框架),在框架內實現一個文件解析(parser)和組成(composer)、編解碼的NODE,也可以繼承其通用的接口,在用戶層實現一些NODE

 

3)         PVPlayer EnginePVPlayer引擎。

 

4)         PVAuthor EnginePVAuthor引擎。

  事實上,OpenCore中包含的內容非常多:從播放的角度,PVPlayer的輸入的(Source)是文件或者

網絡媒體流,輸出(Sink)是音頻視頻的輸出設備,其基本功能包含了媒體流控制、文件解析、音頻視頻流的解碼(Decode)等方面的內容。除了從文件中播放 媒體文件之外,還包含了與網絡相關的RTSP(Real Time Stream Protocol, 實時流協議)。在媒體流記錄的方面,PVAuthor的輸入的(Source)是照相機、麥克風等設備,輸出(Sink)是各種文件, 包含了流的同步、音頻視頻流的編碼(Encode)以及文件的寫入等功能。

 

在使用OpenCoreSDK的時候,有可能需要在應用程序層實現一個適配器(Adaptor),然後在適配器之上實現具體的功能,對於PVMFNODE也可以基於通用的接口,在上層實現,以插件的形式使用。

 

第二部分 OpenCore的代碼結構

 

 

2.1 代碼結構

 

 

以開源Android的代碼爲例,OpenCore的代碼在以下目錄中:external/opencore/

 

這個目錄是OpenCore的根目錄,其中包含的子目錄如下所示:

 

1)         android:這裏面是一個上層的庫,它基於PVPlayerPVAuthorSDK實現了一個爲Android使用的PlayerAuthor

2)         baselibs:包含數據結構和線程

安全等內容的底層庫

 

3)         codecs_v2:這是一個內容較多的庫,主要包含編解碼的實現,以及一個OpenMAX的實現

 

4)         engines:包含PVPlayerPVAuthor引擎的實現

 

5)         extern_libs_v2:包含了khronosOpenMAX的頭文件

 

6)         fileformats:文件格式的解析(parser)工具

 

7)         nodes:提供一些PVMFNODE,主要是編解碼和文件解析方面的。

8)         oscl

操作系統兼容庫

 

9)         pvmi 輸入輸出控制的抽象接口

10)     protocols:主要是與

網絡相關的RTSPRTPHTTP等協議的相關內容

 

11)     pvcommonpvcommon庫文件的Android.mk文件,沒有源文件。

 

12)     pvplayerpvplayer庫文件的Android.mk文件,沒有源文件。

 

13)     pvauthorpvauthor庫文件的Android.mk文件,沒有源文件。

 

14)     tools_v2:編譯工具以及一些可註冊的模塊。

 

  在external/opencore/目錄中還有2個文件,如下所示:

 

Android.mk:全局的編譯文件

 

pvplayer.conf:配置文件

 

  在external/opencore/的各個子文件夾中包含了衆多的Android.mk文件,它們之間還存在着遞歸的關係。例如根目錄下的Android.mk,就包含了如下的內容片斷:

 

include $(PV_TOP)/pvcommon/Android.mk

 

include $(PV_TOP)/pvplayer/Android.mk

 

include $(PV_TOP)/pvauthor/Android.mk

 

  這表示了要引用pvcommonpvplayerpvauthor等文件夾下面的Android.mk文件。

 

  external/opencore/的各個Android.mk文件可以按照排列組合進行使用,將幾個Android.mk內容合併在一個庫當中。

 

 

2.2 編譯結構

 

 

 

2.2.1. 庫的層次關係

 

 

Android的開源版本中編譯出來的內容,OpenCore編譯出來的各個庫如下所示:

 

1)         libopencoreauthor.soOpenCoreAuthor

 

2)         libopencorecommon.soOpenCore底層的公共庫

 

3)         libopencoredownloadreg.so :下載註冊庫

 

4)         libopencoredownload.so:下載功能實現庫

 

5)         libopencoremp4reg.soMP4註冊庫

 

6)         libopencoremp4.soMP4功能實現庫

 

7)         libopencorenet_support.so:網絡支持庫

 

8)         libopencoreplayer.soOpenCorePlayer

 

9)         libopencorertspreg.soRTSP註冊庫

 

10)     libopencorertsp.soRTSP功能實現庫

 

  這些庫的層次關係如下圖所示:


     OpenCore的各個庫之間具有如下的關係:

 

  libopencorecommon.so是所有的庫的依賴庫,提供了公共的功能;

 

  libopencoreplayer.solibopencoreauthor.so是兩個並立的庫,分別用於回放和記錄,而且這兩個庫是OpenCore對外的接口庫;

 

libopencorenet_support.so提供網絡支持的功能;

 

一些功能以插件(Plug-In)的方式放入Player中使用,每個功能使用兩個庫,一個實現具體功能,一個用於註冊。

 

 

2.2.2. libopencorecommon.so庫的結構

 

 

libopencorecommon.so是整個OpenCore的核心庫,它的編譯控制的文件的路徑爲pvcommon/Android.mk,這個文件使用遞歸的方式尋找子文件:

 

include $(BUILD_SHARED_LIBRARY)

 

include $(PV_TOP)//oscl/oscl/osclbase/Android.mk

 

include $(PV_TOP)//oscl/oscl/osclerror/Android.mk

 

include $(PV_TOP)//oscl/oscl/osclmemory/Android.mk

 

include $(PV_TOP)//oscl/oscl/osclutil/Android.mk

 

include $(PV_TOP)//oscl/pvlogger/Android.mk

 

include $(PV_TOP)//oscl/oscl/osclproc/Android.mk

 

include $(PV_TOP)//oscl/oscl/osclio/Android.mk

 

include $(PV_TOP)//oscl/oscl/osclregcli/Android.mk

 

include $(PV_TOP)//oscl/oscl/osclregserv/Android.mk

 

include $(PV_TOP)//oscl/unit_test/Android.mk

 

include $(PV_TOP)//oscl/oscl/oscllib/Android.mk

 

include $(PV_TOP)//pvmi/pvmf/Android.mk

 

include $(PV_TOP)//baselibs/pv_mime_utils/Android.mk

 

include $(PV_TOP)//nodes/pvfileoutputnode/Android.mk

 

include $(PV_TOP)//baselibs/media_data_structures/Android.mk

 

include $(PV_TOP)//baselibs/threadsafe_callback_ao/Android.mk

 

include $(PV_TOP)//codecs_v2/utilities/colorconvert/Android.mk

 

include $(PV_TOP)//codecs_v2/audio/gsm_amr/amr_nb/common/Android.mk

 

include $(PV_TOP)//codecs_v2/video/avc_h264/common/Android.mk

 

這些被包含的Android.mk文件真正指定需要編譯的文件,這些文件在Android.mk的目錄及其子目錄中。事實上,在libopencorecommon.so庫中包含了以下內容: 

 

1)         OSCL的所有內容

 

2)         Pvmf框架部分的內容(pvmi/pvmf/Android.mk

 

3)         基礎庫中的一些內容(baselibs

 

4)         編解碼的一些內容

 

5)         文件輸出的nodenodes/pvfileoutputnode/Android.mk

 

從庫的結構中可以看出,最終生成庫的結構與OpenCore的層次關係並非完全重合。libopencorecommon.so庫中就包含了底層的OSCL的內容、PVMF的框架以及Node和編解碼的工具。

 

 

2.2.3libopencoreplayer.so庫的結構

 

 

libopencoreplayer.so是用於播放的功能庫,它的編譯控制的文件的路徑爲pvplayer/Android.mk,它包含了以下的內容:

 

include $(BUILD_SHARED_LIBRARY)

 

include $(PV_TOP)//engines/player/Android.mk

 

include $(PV_TOP)//codecs_v2/audio/aac/dec/util/getactualaacconfig/Android.mk

 

include $(PV_TOP)//codecs_v2/video/avc_h264/dec/Android.mk

 

include $(PV_TOP)//codecs_v2/audio/aac/dec/Android.mk

 

include $(PV_TOP)//codecs_v2/audio/gsm_amr/amr_nb/dec/Android.mk

 

include $(PV_TOP)//codecs_v2/audio/gsm_amr/amr_wb/dec/Android.mk

 

include $(PV_TOP)//codecs_v2/audio/gsm_amr/common/dec/Android.mk

 

include $(PV_TOP)//codecs_v2/audio/mp3/dec/Android.mk

 

include $(PV_TOP)//codecs_v2/utilities/m4v_config_parser/Android.mk

 

include $(PV_TOP)//codecs_v2/utilities/pv_video_config_parser/Android.mk

 

include $(PV_TOP)//codecs_v2/omx/omx_common/Android.mk

 

include $(PV_TOP)//codecs_v2/omx/omx_queue/Android.mk

 

include $(PV_TOP)//codecs_v2/omx/omx_h264/Android.mk

 

include $(PV_TOP)//codecs_v2/omx/omx_aac/Android.mk

 

include $(PV_TOP)//codecs_v2/omx/omx_amr/Android.mk

 

include $(PV_TOP)//codecs_v2/omx/omx_mp3/Android.mk

 

include $(PV_TOP)//codecs_v2/omx/factories/omx_m4v_factory/Android.mk

 

include $(PV_TOP)//codecs_v2/omx/omx_proxy/Android.mk

 

include $(PV_TOP)//nodes/common/Android.mk

 

include $(PV_TOP)//pvmi/content_policy_manager/Android.mk

 

include $(PV_TOP)//pvmi/content_policy_manager/plugins/oma1/passthru/Android.mk

 

include $(PV_TOP)//pvmi/content_policy_manager/plugins/common/Android.mk

 

include $(PV_TOP)//pvmi/media_io/pvmiofileoutput/Android.mk

 

include $(PV_TOP)//fileformats/common/parser/Android.mk

 

include $(PV_TOP)//fileformats/id3parcom/Android.mk

 

include $(PV_TOP)//fileformats/rawgsmamr/parser/Android.mk

 

include $(PV_TOP)//fileformats/mp3/parser/Android.mk

 

include $(PV_TOP)//fileformats/mp4/parser/Android.mk

 

include $(PV_TOP)//fileformats/rawaac/parser/Android.mk

 

include $(PV_TOP)//fileformats/wav/parser/Android.mk

 

include $(PV_TOP)//nodes/pvaacffparsernode/Android.mk

 

include $(PV_TOP)//nodes/pvmp3ffparsernode/Android.mk

 

include $(PV_TOP)//nodes/pvamrffparsernode/Android.mk

 

include $(PV_TOP)//nodes/pvmediaoutputnode/Android.mk

 

include $(PV_TOP)//nodes/pvomxvideodecnode/Android.mk

 

include $(PV_TOP)//nodes/pvomxaudiodecnode/Android.mk

 

include $(PV_TOP)//nodes/pvwavffparsernode/Android.mk

 

include $(PV_TOP)//pvmi/recognizer/Android.mk

 

include $(PV_TOP)//pvmi/recognizer/plugins/pvamrffrecognizer/Android.mk

 

include $(PV_TOP)//pvmi/recognizer/plugins/pvmp3ffrecognizer/Android.mk

 

include $(PV_TOP)//pvmi/recognizer/plugins/pvwavffrecognizer/Android.mk

 

include $(PV_TOP)//engines/common/Android.mk

 

include $(PV_TOP)//engines/adapters/player/framemetadatautility/Android.mk

 

include $(PV_TOP)//protocols/rtp_payload_parser/util/Android.mk

 

include $(PV_TOP)//android/Android.mk

 

include $(PV_TOP)//android/drm/oma1/Android.mk

 

include $(PV_TOP)//tools_v2/build/modules/linux_rtsp/core/Android.mk

 

include $(PV_TOP)//tools_v2/build/modules/linux_rtsp/node_registry/Android.mk

 

include $(PV_TOP)//tools_v2/build/modules/linux_net_support/core/Android.mk

 

include $(PV_TOP)//tools_v2/build/modules/linux_download/core/Android.mk

 

include $(PV_TOP)//tools_v2/build/modules/linux_download/node_registry/Android.mk

 

include $(PV_TOP)//tools_v2/build/modules/linux_mp4/core/Android.mk

 

include $(PV_TOP)//tools_v2/build/modules/linux_mp4/node_registry/Android.mk

 

libopencoreplayer.so中包含了以下內容: 

 

1)         一些解碼工具

 

2)         文件的解析器(mp4

 

3)         解碼工具對應的Node

 

4)         player的引擎部分(engines/player/Android.mk

 

5)         Androidplayer適配器(android/Android.mk

 

6)         識別工具(pvmi/recognizer

 

7)         編解碼工具中的OpenMax部分(codecs_v2/omx)

 

8)         對應幾個插件Node的註冊

 

libopencoreplayer.so中的內容較多,其中主要爲各個文件解析器和解碼器,PVPlayer的核心功能在engines/player/Android.mk當中,而android/Android.mk的內容比較特殊,它是在PVPlayer之上構建的一個爲Android使用的播放器。

 

 

2.2.4libopencoreauthor.so庫的結構

 

 

libopencoreauthor.so是用於媒體流記錄的功能庫,它的編譯控制的文件的路徑爲pvauthor/Android.mk,它包含了以下的內容:

 

include $(BUILD_SHARED_LIBRARY)

 

include $(PV_TOP)//engines/author/Android.mk

 

include $(PV_TOP)//codecs_v2/video/m4v_h263/enc/Android.mk

 

include $(PV_TOP)//codecs_v2/audio/gsm_amr/amr_nb/enc/Android.mk

 

include $(PV_TOP)//codecs_v2/video/avc_h264/enc/Android.mk

 

include $(PV_TOP)//fileformats/mp4/composer/Android.mk

 

include $(PV_TOP)//nodes/pvamrencnode/Android.mk

 

include $(PV_TOP)//nodes/pvmp4ffcomposernode/Android.mk

 

include $(PV_TOP)//nodes/pvvideoencnode/Android.mk

 

include $(PV_TOP)//nodes/pvavcencnode/Android.mk

 

include $(PV_TOP)//nodes/pvmediainputnode/Android.mk

 

include $(PV_TOP)//android/author/Android.mk

 

libopencoreauthor.so中包含了以下內容: 

1)         一些編碼工具(

視頻H263H264,音頻流Amr

 

2)         文件的組成器(mp4

 

3)         編碼工具對應的Node

 

4)         表示媒體輸入的Nodenodes/pvmediainputnode/Android.m

 

5)         author的引擎部分(engines/author/Android.mk

 

6)         Androidauthor適配器(android/author/Android.mk

 

libopencoreauthor.so中主要爲各個文件編碼器和文件組成器,PVAuthor的核心功能在engines/author/Android.mk當中,而android/author/Android.mk是在PVAuthor之上構建的一個爲Android使用的媒體記錄器。

 

 

2.2.5.其他庫

 

 

另外的幾個庫的Android.mk文件的路徑如下所示:

 

網絡支持庫libopencorenet_support.so

 

tools_v2/build/modules/linux_net_support/core/Android.mk

 

MP4功能實現庫libopencoremp4.so和註冊庫libopencoremp4reg.so

 

tools_v2/build/modules/linux_mp4/core/Android.mk

 

tools_v2/build/modules/linux_mp4/node_registry/Android.mk

 

RTSP功能實現庫libopencorertsp.so和註冊庫libopencorertspreg.so

 

tools_v2/build/modules/linux_rtsp/core/Android.mk

 

tools_v2/build/modules/linux_rtsp/node_registry/Android.mk

 

下載功能實現庫libopencoredownload.so和註冊庫libopencoredownloadreg.so

 

tools_v2/build/modules/linux_download/core/Android.mk

 

tools_v2/build/modules/linux_download/node_registry/Android.mk

 

第三部分 OpenCore OSCL簡介 

OSCL,全稱爲Operating System Compatibility Library (

操作系統兼容庫),它包含了一些在不同操作系統中移植層的功能,其代碼結構如下所示:

 

oscl/oscl

 

|-- config             :配置的宏

 

|-- makefile

 

|-- makefile.pv

 

|-- osclbase         :包含基本類型、宏以及一些STL容器類似的功能

 

|-- osclerror        :錯誤處理的功能

 

|-- osclio             :文件IOSocket等功能

 

|-- oscllib            :動態庫接口等功能

|-- osclmemory

內存管理、自動指針等功能

 

|-- osclproc         :線程、多任務通訊等功能

 

|-- osclregcli        :註冊客戶端的功能

|-- osclregserv     :註冊

服務器的功能

 

`-- osclutil           :字符串等基本功能

 

oscl的目錄中,一般每一個目錄表示一個模塊。OSCL對應的功能是非常細緻的,幾乎對C語言中每一個細節的功能都進行封裝,並使用了C++的接口提供給上層使用。事實上,OperCore中的PVMFEngine部分都在使用OSCL,而整個OperCore的調用者也需要使用OSCL

 

OSCL的實現中,很多典型的C語言函數被進行了簡單的封裝,例如:osclutil中與數學相關的功能在oscl_math.inl中被定義成爲了內嵌(inline)的函數:

 

OSCL_COND_EXPORT_REF OSCL_INLINE double oscl_log(double value)

 

{

 

         return (double) log(value);

 

}

 

OSCL_COND_EXPORT_REF OSCL_INLINE double oscl_log10(double value)

 

{

 

         return (double) log10(value);

 

}

 

OSCL_COND_EXPORT_REF OSCL_INLINE double oscl_sqrt(double value)

 

{

 

         return (double) sqrt(value);

 

}

 

oscl_math.inl文件又被oscl_math.h所包含,因此其結果是oscl_log()等功能的使用等價於原始的log()等函數。

 

很多C語言標準庫的句柄都被定義成爲了C++類的形式,實現由一些繁瑣,但是複雜性都不是很高。以oscllib爲例,其代碼結構如下所示:

 

oscl/oscl/oscllib/

 

|-- Android.mk

 

|-- build

 

|   `-- make

 

|       `-- makefile

 

`-- src

 

    |-- oscl_library_common.h

 

    |-- oscl_library_list.cpp

 

    |-- oscl_library_list.h

 

    |-- oscl_shared_lib_interface.h

 

    |-- oscl_shared_library.cpp

 

    `-- oscl_shared_library.h

 

 oscl_shared_library.h是提供給上層使用的動態庫的接口功能,它定義的接口如下所示:

 

class OsclSharedLibrary

 

{

 

public:

 

        OSCL_IMPORT_REF OsclSharedLibrary();

 

        OSCL_IMPORT_REF OsclSharedLibrary(const OSCL_String& aPath);

 

        OSCL_IMPORT_REF ~OsclSharedLibrary();

 

        OSCL_IMPORT_REF OsclLibStatus LoadLib(const OSCL_String& aPath);

 

        OSCL_IMPORT_REF OsclLibStatus LoadLib();

 

        OSCL_IMPORT_REF void SetLibPath(const OSCL_String& aPath);

 

        OSCL_IMPORT_REF OsclLibStatus QueryInterface(const OsclUuid& aInterfaceId, OsclAny*& aInterfacePtr);

 

        OSCL_IMPORT_REF OsclLibStatus Close();

 

        OSCL_IMPORT_REF void AddRef();

 

        OSCL_IMPORT_REF void RemoveRef();

 

}

 

這些接口顯然都是與庫的加載有關係的,而在oscl_shared_library.cpp 中其具體的功能是使用dlopen()等函數來實現的。

 

第四部分 文件格式處理和編解碼部分簡介

 

在多媒體方面,文件格式的處理和編解碼(Codec)是很基礎的兩個方面的內容。多媒體應用的兩個方面是媒體的播放(PlayBack)和媒體的記錄(Recording)

在媒體的播放過程中,通常情況是從對媒體文件的播放,必要的兩個步驟爲文件的解析和媒體流的解碼。例如對於一個mp4的文件,其中可能包括AMRAAC的音頻流,H263MPEG4以及AVC(H264)

視頻流,這些流被封裝在3GP的包當中,媒體播放器要做的就是從文件中將這些流解析出來,然後對媒體流進行解碼,解碼後的數據纔可以播放。

 

在媒體的記錄過程中,通過涉及到視頻、音頻、圖像的捕獲功能。對於將視頻加音頻錄製成文件功能,其過程與播放剛好相反,首先從硬件設備得到視頻和音頻的媒體流,然後對其進行編碼,編碼號的流還需要被分層次寫入到文件之中,最終得到組成好的文件。

 

OpenCore有關文件格式處理和編解碼部分兩部分的內容,分別在目錄fileformatscodecs_v2當中。這兩部分都屬於基礎性的功能,不涉及具體的邏輯,因此它們被別的模塊調用來使用,例如:構建各種Node

 

 

4.1 文件格式的處理

 

 

由於同時涉及播放文件和記錄文件兩種功能,因此OpenCore中的文件格式處理有兩種類型,一種是parser(解析器),另一種是composer(組成器)

 

fileformats的目錄結構如下所示:fileformats

 

|-- avi

 

|   `-- parser

 

|-- common

 

|   `-- parser

 

|-- id3parcom

 

|   |-- Android.mk

 

|   |-- build

 

|   |-- include

 

|   `-- src

 

|-- mp3

 

|   `-- parser

 

|-- mp4

 

|   |-- composer

 

|   `-- parser

 

|-- rawaac

 

|   `-- parser

 

|-- rawgsmamr

 

|   `-- parser

 

`-- wav

 

    `-- parser

 

目錄包含各個子目錄中,它們對應的是不同的文件格式,例如mp3mp4wav等。

 

 

4.2 編解碼

 

 

        編解碼部分主要針對AudioVideocodecs_v2的目錄結構如下所示:

 

codecs_v2

 

|-- audio

 

|   |-- aac

 

|   |-- gsm_amr

 

|   |-- mp3

 

|   `-- sbc

 

|-- omx

 

|   |-- factories

 

|   |-- omx_aac

 

|   |-- omx_amr

 

|   |-- omx_common

 

|   |-- omx_h264

 

|   |-- omx_m4v

 

|   |-- omx_mp3

 

|   |-- omx_proxy

 

|   `-- omx_queue

 

|-- utilities

 

|   |-- colorconvert

 

|   |-- m4v_config_parser

 

|   `-- pv_video_config_parser

 

`-- video

 

    |-- avc_h264

 

    `-- m4v_h263

 

audio video目錄中,對應了針對各種流的子目錄,其中可能包含decenc兩個目錄,分別對應解碼和編碼。video目錄展開後的內容如下所示:

 

`-- video

 

    |-- avc_h264

 

    |   |-- common

 

    |   |-- dec

 

    |   |-- enc

 

    |   `-- patent_disclaimer.txt

 

    `-- m4v_h263

 

        |-- dec

 

        |-- enc

 

        `-- patent_disclaimer.txt

 

codecs_v2目錄的子目錄omx實現了一個khronos 

 

OpenMAX的功能。OpenMAX是一個多媒體應用程序的框架標準,由NVIDIA公司和Khronos2006年推出。OpenMAX IL 1.0(集成層)技術規格定義了媒體組件接口,以便在嵌入式器件的流媒體框架中快速集成加速式編解碼器。

OpenMAX的設計實現可以讓具有硬件編輯碼功能的平臺提供統一的接口和框架,在OpenMAX中可以直接使用硬件加速的進行編解碼乃至輸出的功能,對外保持統一的接口。但是在此處的OpenMAX則是一個純軟件的實現。

 

轉自: http://tech.it168.com/a2009/0331/270/000000270422.shtml

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章