快捷方式

StreamingMediaDecoder

class torio.io.StreamingMediaDecoder(src: Union[str, Path, BinaryIO], format: Optional[str] = None, option: Optional[Dict[str, str]] = None, buffer_size: int = 4096)[來源]

逐塊獲取和解碼音訊/影片流。

有關此類的詳細用法,請參閱教程。

引數::
  • src (str, path-like, bytesfile-like object) –

    媒體源。如果為字串型別,則必須是 FFmpeg 可以處理的資源指示符。這包括檔案路徑、URL、裝置識別符號或濾波器表示式。支援的值取決於系統中找到的 FFmpeg。

    如果為 bytes 型別,則必須是連續記憶體中的編碼媒體資料。

    如果為類檔案物件,則必須支援簽名 read(size: int) -> bytesread 方法。此外,如果類檔案物件具有 seek 方法,則在解析媒體元資料時會使用該方法。這提高了編解碼器檢測的可靠性。seek 方法的簽名必須是 seek(offset: int, whence: int) -> int

    有關 readseek 方法的預期簽名和行為,請參閱以下內容。

  • format (strNone, 可選) –

    覆蓋輸入格式,或指定源音訊裝置。預設值:None (不覆蓋也不使用裝置輸入)。

    此引數用於兩種不同的用例。

    1. 覆蓋源格式。當輸入資料不包含頭部時,這很有用。

    2. 指定輸入源裝置。這允許從硬體裝置(如麥克風、攝像頭和螢幕)或虛擬裝置載入媒體流。

    注意

    此選項大致對應於 ffmpeg 命令的 -f 選項。有關可能的值,請參閱 ffmpeg 文件。

    https://ffmpeg.org/ffmpeg-formats.html#Demuxers

    請使用 get_demuxers() 列出當前環境中可用的解複用器。

    對於裝置訪問,可用值因硬體(音影片裝置)和軟體配置(ffmpeg 構建)而異。

    https://ffmpeg.org/ffmpeg-devices.html#Input-Devices

    請使用 get_input_devices() 列出當前環境中可用的輸入裝置。

  • option (從 str 到 str 的字典, 可選) –

    初始化格式上下文(開啟源)時傳遞的自定義選項。

    您可以使用此引數在輸入源傳遞給解碼器之前對其進行更改。

    預設值:None

  • buffer_size (int) –

    內部緩衝區大小(以位元組為單位)。僅當 src 是類檔案物件時使用。

    預設值:4096

屬性

default_audio_stream

property StreamingMediaDecoder.default_audio_stream

預設音訊流的索引。如果沒有音訊流,則為 None

型別::

Optional[int]

default_video_stream

property StreamingMediaDecoder.default_video_stream

預設影片流的索引。如果沒有影片流,則為 None

型別::

Optional[int]

num_out_streams

property StreamingMediaDecoder.num_out_streams

客戶端程式碼配置的輸出流數量。

型別::

int

num_src_streams

property StreamingMediaDecoder.num_src_streams

提供的媒體源中找到的流數量。

型別::

int

方法

add_audio_stream

StreamingMediaDecoder.add_audio_stream(frames_per_chunk: int, buffer_chunk_size: int = 3, *, stream_index: Optional[int] = None, decoder: Optional[str] = None, decoder_option: Optional[Dict[str, str]] = None, filter_desc: Optional[str] = None)[來源]

新增輸出音訊流

引數::
  • frames_per_chunk (int) –

    作為一塊返回的幀數。如果在緩衝足夠的幀之前源流已耗盡,則按原樣返回該塊。

    提供 -1 將停用分塊,並且 pop_chunks() 方法將連線所有已緩衝的幀並返回。

  • buffer_chunk_size (int, 可選) –

    內部緩衝區大小。當緩衝的塊數超過此數量時,舊幀將被丟棄。例如,如果 frames_per_chunk 為 5 且 buffer_chunk_size 為 3,則早於 15 的幀將被丟棄。提供 -1 將停用此行為。

    預設值:3

  • stream_index (intNone, 可選) – 源音訊流索引。如果省略,則使用 default_audio_stream

  • decoder (strNone, 可選) –

    要使用的解碼器名稱。如果提供,則使用指定的解碼器而不是預設解碼器。

    要列出可用的解碼器,請對音訊使用 get_audio_decoders(),對影片使用 get_video_decoders()

    預設值:None

  • decoder_option (dictNone, 可選) –

    傳遞給解碼器的選項。從 str 到 str 的對映。(預設值:None

    要列出解碼器的選項,您可以使用 ffmpeg -h decoder=<DECODER> 命令。


    除了特定於解碼器的選項外,您還可以傳遞與多執行緒相關的選項。它們僅在解碼器支援時有效。如果兩者都未提供,StreamingMediaDecoder 預設為單執行緒。

    "threads": 執行緒數(字串)。提供值 "0" 將讓 FFmpeg 根據其啟發式方法決定。

    "thread_type": 要使用的多執行緒方法。有效值為 "frame""slice"。請注意,每個解碼器支援的方法集不同。如果未提供,則使用預設值。

    • "frame": 一次解碼多個幀。每個執行緒處理一個幀。這將增加每個執行緒的解碼延遲一個幀。

    • "slice": 一次解碼單個幀的多個部分。


  • filter_desc (strNone, 可選) – 濾波器描述。可用濾波器的列表可在 https://ffmpeg.org/ffmpeg-filters.html 找到。請注意,不支援複雜濾波器。

add_basic_audio_stream

StreamingMediaDecoder.add_basic_audio_stream(frames_per_chunk: int, buffer_chunk_size: int = 3, *, stream_index: Optional[int] = None, decoder: Optional[str] = None, decoder_option: Optional[Dict[str, str]] = None, format: Optional[str] = 'fltp', sample_rate: Optional[int] = None, num_channels: Optional[int] = None)[來源]

新增輸出音訊流

引數::
  • frames_per_chunk (int) –

    作為一塊返回的幀數。如果在緩衝足夠的幀之前源流已耗盡,則按原樣返回該塊。

    提供 -1 將停用分塊,並且 pop_chunks() 方法將連線所有已緩衝的幀並返回。

  • buffer_chunk_size (int, 可選) –

    內部緩衝區大小。當緩衝的塊數超過此數量時,舊幀將被丟棄。例如,如果 frames_per_chunk 為 5 且 buffer_chunk_size 為 3,則早於 15 的幀將被丟棄。提供 -1 將停用此行為。

    預設值:3

  • stream_index (intNone, 可選) – 源音訊流索引。如果省略,則使用 default_audio_stream

  • decoder (strNone, 可選) –

    要使用的解碼器名稱。如果提供,則使用指定的解碼器而不是預設解碼器。

    要列出可用的解碼器,請對音訊使用 get_audio_decoders(),對影片使用 get_video_decoders()

    預設值:None

  • decoder_option (dictNone, 可選) –

    傳遞給解碼器的選項。從 str 到 str 的對映。(預設值:None

    要列出解碼器的選項,您可以使用 ffmpeg -h decoder=<DECODER> 命令。


    除了特定於解碼器的選項外,您還可以傳遞與多執行緒相關的選項。它們僅在解碼器支援時有效。如果兩者都未提供,StreamingMediaDecoder 預設為單執行緒。

    "threads": 執行緒數(字串)。提供值 "0" 將讓 FFmpeg 根據其啟發式方法決定。

    "thread_type": 要使用的多執行緒方法。有效值為 "frame""slice"。請注意,每個解碼器支援的方法集不同。如果未提供,則使用預設值。

    • "frame": 一次解碼多個幀。每個執行緒處理一個幀。這將增加每個執行緒的解碼延遲一個幀。

    • "slice": 一次解碼單個幀的多個部分。


  • format (str, 可選) –

    輸出取樣格式(精度)。

    如果為 None,則輸出塊的 dtype 對應於源音訊的精度。

    否則,將轉換樣本,輸出 dtype 更改如下。

    • "u8p": 輸出為 torch.uint8 型別。

    • "s16p": 輸出為 torch.int16 型別。

    • "s32p": 輸出為 torch.int32 型別。

    • "s64p": 輸出為 torch.int64 型別。

    • "fltp": 輸出為 torch.float32 型別。

    • "dblp": 輸出為 torch.float64 型別。

    預設值:"fltp"

  • sample_rate (intNone, 可選) – 如果提供,則對音訊進行重取樣。

  • num_channels (int, 或 None, 可選) – 如果提供,則更改通道數。

add_basic_video_stream

StreamingMediaDecoder.add_basic_video_stream(frames_per_chunk: int, buffer_chunk_size: int = 3, *, stream_index: Optional[int] = None, decoder: Optional[str] = None, decoder_option: Optional[Dict[str, str]] = None, format: Optional[str] = 'rgb24', frame_rate: Optional[int] = None, width: Optional[int] = None, height: Optional[int] = None, hw_accel: Optional[str] = None)[來源]

新增輸出影片流

引數::
  • frames_per_chunk (int) –

    作為一塊返回的幀數。如果在緩衝足夠的幀之前源流已耗盡,則按原樣返回該塊。

    提供 -1 將停用分塊,並且 pop_chunks() 方法將連線所有已緩衝的幀並返回。

  • buffer_chunk_size (int, 可選) –

    內部緩衝區大小。當緩衝的塊數超過此數量時,舊幀將被丟棄。例如,如果 frames_per_chunk 為 5 且 buffer_chunk_size 為 3,則早於 15 的幀將被丟棄。提供 -1 將停用此行為。

    預設值:3

  • stream_index (intNone, 可選) – 源影片流索引。如果省略,則使用 default_video_stream

  • decoder (strNone, 可選) –

    要使用的解碼器名稱。如果提供,則使用指定的解碼器而不是預設解碼器。

    要列出可用的解碼器,請對音訊使用 get_audio_decoders(),對影片使用 get_video_decoders()

    預設值:None

  • decoder_option (dictNone, 可選) –

    傳遞給解碼器的選項。從 str 到 str 的對映。(預設值:None

    要列出解碼器的選項,您可以使用 ffmpeg -h decoder=<DECODER> 命令。


    除了特定於解碼器的選項外,您還可以傳遞與多執行緒相關的選項。它們僅在解碼器支援時有效。如果兩者都未提供,StreamingMediaDecoder 預設為單執行緒。

    "threads": 執行緒數(字串)。提供值 "0" 將讓 FFmpeg 根據其啟發式方法決定。

    "thread_type": 要使用的多執行緒方法。有效值為 "frame""slice"。請注意,每個解碼器支援的方法集不同。如果未提供,則使用預設值。

    • "frame": 一次解碼多個幀。每個執行緒處理一個幀。這將增加每個執行緒的解碼延遲一個幀。

    • "slice": 一次解碼單個幀的多個部分。


  • format (str, 可選) –

    更改影像通道的格式。有效值包括:

    • "rgb24": 8 位 * 3 通道 (R, G, B)

    • "bgr24": 8 位 * 3 通道 (B, G, R)

    • "yuv420p": 8 位 * 3 通道 (Y, U, V)

    • "gray": 8 位 * 1 通道

    預設值:"rgb24"

  • frame_rate (intNone, 可選) – 如果提供,則更改幀率。

  • width (intNone, 可選) – 如果提供,則更改影像寬度。單位:畫素。

  • height (intNone, 可選) – 如果提供,則更改影像高度。單位:畫素。

  • hw_accel (strNone, 可選) –

    啟用硬體加速。

    當影片在 CUDA 硬體上解碼時,例如 decoder=”h264_cuvid”,將 CUDA 裝置指示符傳遞給 hw_accel (即 hw_accel=”cuda:0”) 會使 StreamingMediaDecoder 將結果幀直接放置到指定的 CUDA 裝置上作為 CUDA tensor。

    如果 None,幀將被移至 CPU 記憶體。預設值: None

新增影片流

StreamingMediaDecoder.add_video_stream(frames_per_chunk: int, buffer_chunk_size: int = 3, *, stream_index: Optional[int] = None, decoder: Optional[str] = None, decoder_option: Optional[Dict[str, str]] = None, filter_desc: Optional[str] = None, hw_accel: Optional[str] = None)[source]

新增輸出影片流

引數::
  • frames_per_chunk (int) –

    作為一塊返回的幀數。如果在緩衝足夠的幀之前源流已耗盡,則按原樣返回該塊。

    提供 -1 將停用分塊,並且 pop_chunks() 方法將連線所有已緩衝的幀並返回。

  • buffer_chunk_size (int, 可選) –

    內部緩衝區大小。當緩衝的塊數超過此數量時,舊幀將被丟棄。例如,如果 frames_per_chunk 為 5 且 buffer_chunk_size 為 3,則早於 15 的幀將被丟棄。提供 -1 將停用此行為。

    預設值:3

  • stream_index (intNone, 可選) – 源影片流索引。如果省略,則使用 default_video_stream

  • decoder (strNone, 可選) –

    要使用的解碼器名稱。如果提供,則使用指定的解碼器而不是預設解碼器。

    要列出可用的解碼器,請對音訊使用 get_audio_decoders(),對影片使用 get_video_decoders()

    預設值:None

  • decoder_option (dictNone, 可選) –

    傳遞給解碼器的選項。從 str 到 str 的對映。(預設值:None

    要列出解碼器的選項,您可以使用 ffmpeg -h decoder=<DECODER> 命令。


    除了特定於解碼器的選項外,您還可以傳遞與多執行緒相關的選項。它們僅在解碼器支援時有效。如果兩者都未提供,StreamingMediaDecoder 預設為單執行緒。

    "threads": 執行緒數(字串)。提供值 "0" 將讓 FFmpeg 根據其啟發式方法決定。

    "thread_type": 要使用的多執行緒方法。有效值為 "frame""slice"。請注意,每個解碼器支援的方法集不同。如果未提供,則使用預設值。

    • "frame": 一次解碼多個幀。每個執行緒處理一個幀。這將增加每個執行緒的解碼延遲一個幀。

    • "slice": 一次解碼單個幀的多個部分。


  • hw_accel (strNone, 可選) –

    啟用硬體加速。

    當影片在 CUDA 硬體上解碼時,例如 decoder=”h264_cuvid”,將 CUDA 裝置指示符傳遞給 hw_accel (即 hw_accel=”cuda:0”) 會使 StreamingMediaDecoder 將結果幀直接放置到指定的 CUDA 裝置上作為 CUDA tensor。

    如果 None,幀將被移至 CPU 記憶體。預設值: None

  • filter_desc (strNone, 可選) – 濾波器描述。可用濾波器的列表可在 https://ffmpeg.org/ffmpeg-filters.html 找到。請注意,不支援複雜濾波器。

填充緩衝區

StreamingMediaDecoder.fill_buffer(timeout: Optional[float] = None, backoff: float = 10.0) int[source]

持續處理資料包,直到所有緩衝區至少包含一個塊。

引數::
返回值:

0 資料包已正確處理,並且緩衝區已準備好彈出一次。

1 流處理器已到達 EOF。所有輸出流處理器已重新整理待處理的幀。呼叫者應停止呼叫此方法。

返回型別:

int

獲取元資料

StreamingMediaDecoder.get_metadata() Dict[str, str][source]

獲取源媒體的元資料。

返回值:

dict

獲取輸出流資訊

StreamingMediaDecoder.get_out_stream_info(i: int) OutputStream[source]

獲取輸出流的元資料

引數::

i (int) – 流索引。

返回值:

OutputStreamTypes

關於輸出流的資訊。如果輸出流是音訊型別,則返回 OutputAudioStream。如果是影片型別,則返回 OutputVideoStream

獲取源流資訊

StreamingMediaDecoder.get_src_stream_info(i: int) InputStream[source]

獲取源流的元資料

引數::

i (int) – 流索引。

返回值:

關於源流的資訊。如果源流是音訊型別,則返回 SourceAudioStream。如果是影片型別,則返回 SourceVideoStream。否則返回 SourceStream 類。

返回型別:

InputStreamTypes

緩衝區是否準備就緒

StreamingMediaDecoder.is_buffer_ready() bool[source]

如果所有輸出流都至少填充了一個塊,則返回 true。

彈出塊

StreamingMediaDecoder.pop_chunks() Tuple[Optional[ChunkTensor]][source]

從所有輸出流緩衝區中彈出一個塊。

返回值:

緩衝區內容。如果緩衝區不包含任何幀,則返回 None

返回型別:

Tuple[Optional[ChunkTensor]]

處理所有資料包

StreamingMediaDecoder.process_all_packets()[source]

處理資料包直到到達 EOF。

處理資料包

StreamingMediaDecoder.process_packet(timeout: Optional[float] = None, backoff: float = 10.0) int[source]

讀取源媒體並處理一個數據包。

如果成功讀取一個數據包,則資料包中的資料將被解碼並傳遞給相應的輸出流處理器。

如果資料包屬於未連線到輸出流的源流,則資料將被丟棄。

當源到達 EOF 時,它將觸發所有輸出流處理器進入排空模式。所有輸出流處理器都會重新整理待處理的幀。

引數::
  • timeout (floatNone可選) –

    超時時長,單位毫秒。

    當因底層媒體資源暫時不可用而未能處理資料包時,此引數會改變重試行為。

    使用媒體裝置(如麥克風)時,有時底層緩衝區尚未準備好。在這種情況下呼叫此函式會導致系統報告 EAGAIN (資源暫時不可用)

    • >=0: 一直重試直到給定時間過去。

    • 0<: 永遠重試。

    • None : 不重試並立即引發異常。

    預設值:None

    注意

    僅當原因為資源不可用時,重試行為才適用。如果失敗原因為其他,則不觸發重試。

  • backoff (float可選) –

    重試前等待時間,單位毫秒。

    此選項僅當 timeout 有效時才生效。(不是 None

    timeout 有效時,此 backoff 控制函式在重試前應等待多久。預設值: 10.0

返回值:

0 資料包已正確處理。呼叫者可以繼續呼叫此函式以緩衝更多幀。

1 流處理器已到達 EOF。所有輸出流處理器已重新整理待處理的幀。呼叫者應停止呼叫此方法。

返回型別:

int

移除流

StreamingMediaDecoder.remove_stream(i: int)[source]

移除一個輸出流。

引數::

i (int) – 要移除的輸出流的索引。

定位

StreamingMediaDecoder.seek(timestamp: float, mode: str = 'precise')[source]

將流定位到給定時間戳 [秒]

引數::
  • timestamp (float) – 目標時間,單位秒。

  • mode (str) –

    控制定位方式。有效選項為;

    • ”key”: 定位到給定時間戳之前的最近關鍵幀。

    • ”any”: 定位到給定時間戳之前的任何幀(包括非關鍵幀)。

    • ”precise”: 首先定位到給定時間戳之前的最近關鍵幀,然後解碼幀直到到達最接近給定時間戳的幀。

    注意

    所有模式都會使解碼器的內部狀態失效並重置。使用“any”模式時,如果最終定位到非關鍵幀,解碼後的影像可能因缺少關鍵幀而無效。使用“precise”模式可以透過從之前的關鍵幀開始解碼來解決此問題,但這會比較慢。

stream

StreamingMediaDecoder.stream(timeout: Optional[float] = None, backoff: float = 10.0) Iterator[Tuple[Optional[ChunkTensor], ...]][source]

返回生成輸出張量的迭代器

引數::
返回值:

生成一個元組的迭代器,該元組包含客戶端程式碼定義的輸出流對應的塊。如果一個輸出流耗盡,則塊 Tensor 會被替換為 None。如果所有輸出流都耗盡,迭代器將停止。

返回型別:

Iterator[Tuple[Optional[ChunkTensor], …]]

支援結構

ChunkTensor

class torio.io._streaming_media_decoder.ChunkTensor[source]

解碼後的媒體幀及元資料。

此類的例項表示解碼後的影片/音訊幀及元資料,例項本身的行為類似於 Tensor

客戶端程式碼可以將此類的例項當作 Tensor 類傳遞,或者呼叫在 Tensor 類上定義的方法。

示例

>>> # Define input streams
>>> reader = StreamingMediaDecoder(...)
>>> reader.add_audio_stream(frames_per_chunk=4000, sample_rate=8000)
>>> reader.add_video_stream(frames_per_chunk=7, frame_rate=28)
>>> # Decode the streams and fetch frames
>>> reader.fill_buffer()
>>> audio_chunk, video_chunk = reader.pop_chunks()
>>> # Access metadata
>>> (audio_chunk.pts, video_chunks.pts)
(0.0, 0.0)
>>>
>>> # The second time the PTS is different
>>> reader.fill_buffer()
>>> audio_chunk, video_chunk = reader.pop_chunks()
>>> (audio_chunk.pts, video_chunks.pts)
(0.5, 0.25)
>>> # Call PyTorch ops on chunk
>>> audio_chunk.shape
torch.Size([4000, 2]
>>> power = torch.pow(video_chunk, 2)
>>>
>>> # the result is a plain torch.Tensor class
>>> type(power)
<class 'torch.Tensor'>
>>>
>>> # Metadata is not available on the result
>>> power.pts
AttributeError: 'Tensor' object has no attribute 'pts'
pts: float

塊中第一幀的演示時間戳。

單位: 秒。

SourceStream

class torio.io._streaming_media_decoder.SourceStream[source]

源流的元資料,由 get_src_stream_info() 返回。

此類用於表示媒體型別非 audiovideo 的流。

當源流是 audiovideo 型別時,將分別使用報告額外媒體特定屬性的 SourceAudioStreamSourceVideoStream

media_type: str

流的型別。為 "audio", "video", "data", "subtitle", "attachment" 和空字串之一。

注意

音訊和影片流是唯一支援作為輸出的流。

注意

靜態影像,如 PNG 和 JPEG 格式,被報告為影片。

codec: str

編解碼器的短名稱。如 "pcm_s16le""h264"

codec_long_name: str

編解碼器的詳細名稱。

如“PCM signed 16-bit little-endian”和“H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10”。

format: Optional[str]

媒體格式。如 "s16""yuv420p"

常見的音訊格式值為;

  • "u8", "u8p": 無符號 8 位無符號整數。

  • "s16", "s16p": 16 位有符號整數。

  • "s32", "s32p": 32 位有符號整數。

  • "flt", "fltp": 32 位浮點數。

注意

末尾的 p 表示格式是 planar。通道在記憶體中是分組存放而不是交錯存放的。

bit_rate: Optional[int]

流的位元率,單位位元/秒。這是基於流最初幾幀的估計值。對於容器格式和可變位元率,它可以為 0。

num_frames: Optional[int]

流中的幀數

bits_per_sample: Optional[int]

這是每個輸出取樣中有效位元的數量。對於壓縮格式,它可以為 0。

metadata: Dict[str, str]

附加到源流的元資料。

SourceAudioStream

class torio.io._streaming_media_decoder.SourceAudioStream[source]

音訊源流的元資料,由 get_src_stream_info() 返回。

此類用於表示音訊流。

除了 SourceStream 報告的屬性外,還會報告以下屬性。

sample_rate: float

音訊取樣率。

num_channels: int

通道數。

SourceVideoStream

class torio.io._streaming_media_decoder.SourceVideoStream[source]

影片源流的元資料,由 get_src_stream_info() 返回。

此類用於表示影片流。

除了 SourceStream 報告的屬性外,還會報告以下屬性。

width: int

影片幀的寬度,單位畫素。

height: int

影片幀的高度,單位畫素。

frame_rate: float

幀率。

OutputStream

class torio.io._streaming_media_decoder.OutputStream[source]

配置在 StreamingMediaDecoder 上的輸出流,由 get_out_stream_info() 返回。

source_index: int

此輸出流連線到的源流的索引。

filter_description: str

應用於源流的濾鏡圖描述。

media_type: str

流的型別。"audio""video"

format: str

媒體格式。如 "s16""yuv420p"

常見的音訊格式值為;

  • "u8", "u8p": 無符號 8 位無符號整數。

  • "s16", "s16p": 16 位有符號整數。

  • "s32", "s32p": 32 位有符號整數。

  • "flt", "fltp": 32 位浮點數。

注意

末尾的 p 表示格式是 planar。通道在記憶體中是分組存放而不是交錯存放的。

OutputAudioStream

class torio.io._streaming_media_decoder.OutputAudioStream[source]

關於使用 add_audio_stream()add_basic_audio_stream() 配置的音訊輸出流的資訊。

除了 OutputStream 報告的屬性外,還報告以下屬性。

sample_rate: float

音訊取樣率。

num_channels: int

通道數。

OutputVideoStream

class torio.io._streaming_media_decoder.OutputVideoStream[source]

關於使用 add_video_stream()add_basic_video_stream() 配置的影片輸出流的資訊。

除了 OutputStream 報告的屬性外,還報告以下屬性。

width: int

影片幀的寬度,單位畫素。

height: int

影片幀的高度,單位畫素。

frame_rate: float

幀率。

文件

訪問全面的 PyTorch 開發者文件

檢視文件

教程

獲取針對初學者和高階開發者的深度教程

檢視教程

資源

查詢開發資源並獲得問題解答

檢視資源