ogg文件封閉格式簡介

核心參考 xiph官網(wǎng)

ogg 數(shù)據(jù)結構

datatype purpose
ogg_page This structure encapsulates data into one ogg bitstream page. 編碼時page的信息在此輸出
ogg_stream_state This structure contains current encode/decode data for a logical bitstream. 代表當前流
ogg_packet This structure encapsulates the data and metadata for a single Ogg packet. 編碼時數(shù)據(jù)輸入的結構包
ogg_sync_state Contains bitstream synchronization information.
image

以上ogg中最大的結構為ogg流,對比ogg的存儲結構來說都是以ogg_page來進行數(shù)據(jù)分頁,但是對于用于來說是以ogg_packet來對數(shù)據(jù)進行裝載和解析。

編碼相關

概覽

When encoding, the encoding engine will output raw packets which must be placed into an Ogg bitstream. Raw packets are inserted into the stream, and an ogg_page is output when enough packets have been written to create a full page. The pages output are pointers to buffered packet segments, and can then be written out and saved as an ogg stream. There are a couple of basic steps: Use the encoding engine to produce a raw packet of data. Call ogg_stream_packetin to submit a raw packet to the stream. Use ogg_stream_pageout to output a page, if enough data has been submitted. Otherwise, continue submitting data.
意思就是原始數(shù)據(jù)要封裝在ogg_packet中通過ogg_stream_packetin方法寫入到ogg_stream_state中,如果包足夠通過ogg_stream_pageout方法將數(shù)據(jù)寫在ogg_page中

function purpose
ogg_stream_packetin Submits a raw packet to the streaming layer, so that it can be formed into a page.
ogg_stream_iovecin iovec version of ogg_stream_packetin() above.
ogg_stream_pageout Outputs a completed page if the stream contains enough packets to form a full page. 返回值非0代碼輸出成功
ogg_stream_pageout_fill Similar to ogg_stream_pageout(), but specifies a page spill threshold in bytes.
ogg_stream_flush Forces any remaining packets in the stream to be returned as a page of any size.
ogg_stream_flush_fill Similar to ogg_stream_flush(), but specifies a page spill threshold in bytes.

創(chuàng)建與銷毀

創(chuàng)建
ogg_stream_init(&stream_, 0 /* serial number */);
銷毀
ogg_stream_clear(&stream_);

編碼數(shù)據(jù)封裝

typedef struct {
  unsigned char *packet;//數(shù)據(jù)
  long  bytes;//數(shù)據(jù)大小
  long  b_o_s;//1代表開始包
  long  e_o_s;//1代表結束包
  //A number indicating the position of this packet in the decoded data. This is the last sample, frame or other unit of information ('granule') that can be completely decoded from this packet.
  ogg_int64_t  granulepos;
  ogg_int64_t  packetno;//Sequential number of this packet in the ogg bitstream.

} ogg_packet;

單流數(shù)據(jù)寫入

// Write the most recent buffer of Opus data into an Ogg packet.
  ogg_packet frame_packet;
  frame_packet.b_o_s = 0;
  frame_packet.e_o_s = flush ? 1 : 0;
  // According to
  // https://tools.ietf.org/html/draft-ietf-codec-oggopus-14#section-4 the
  // granule position should include all samples up to the last packet completed
  // on the page, so we need to update granule_position_ before assigning it to
  // the packet.  If we're closing the stream, we don't assume that the last
  // packet includes a full frame.
  if (flush) {
    granule_position_ += (elements_in_pcm_frame_ / num_channels_);
  } else {
    granule_position_ += frame_size_;
  }
  frame_packet.granulepos = granule_position_;
  frame_packet.packetno = packet_count_;
  frame_packet.packet = opus_frame_bytes;
  frame_packet.bytes = opus_bytes_length;
  // Add the data packet into the stream.
  packet_count_++;
  ogg_stream_packetin(&stream_, &frame_packet);

獲取輸出數(shù)據(jù)

void OggOpusEncoder::AppendOggStateToBuffer(std::vector<unsigned char>* buffer,
                                            bool flush_ogg_stream) {
  int (*write_fun)(ogg_stream_state*, ogg_page*) =
      flush_ogg_stream ? &ogg_stream_flush : &ogg_stream_pageout;
  while (write_fun(&stream_, &page_) != 0) {
    const int initial_size = buffer->size();
    buffer->resize(buffer->size() + page_.header_len + page_.body_len);
    memcpy(buffer->data() + initial_size, page_.header, page_.header_len);
    memcpy(buffer->data() + initial_size + page_.header_len, page_.body,
           page_.body_len);
  }
}

解碼相關

基本方法

函數(shù) 用途
ogg_sync_pageseek Finds the borders of pages and resynchronizes the stream. -n means that we skipped n bytes within the bitstream.0 means that the page isn't ready and we need more data, or than an internal error occurred. No bytes have been skipped. n means that the page was synced at the current location, with a page length of n bytes.
ogg_sync_buffer Exposes a buffer from the synchronization layer in order to read data. 返回緩沖區(qū)引入,為下一步數(shù)據(jù)輸入做準備
ogg_sync_wrote Tells the synchronization layer how many bytes were written into the buffer. 同步已經寫入了多少數(shù)據(jù)
ogg_stream_pagein Submits a complete page to the stream layer. 把page的信息提交到流處理層
ogg_stream_packetout Outputs a packet to the codec-specific decoding engine. 取出packet信息,可進行原始數(shù)據(jù)處理

創(chuàng)建與銷毀

創(chuàng)建
ogg_sync_state ogsync; ogg_sync_init(&ogsync);
銷毀
ogg_sync_clear

遍歷處理數(shù)據(jù)

處理結構

ogg_sync_init(&ogsync);
while(get_next_page(file, &ogsync, &page, &written)) {
    ...
    p->process_page(p, &page);
    ...
    
}
ogg_sync_clear(&ogsync)

寫數(shù)據(jù)到同步器

while((ret = ogg_sync_pageseek(ogsync, page)) <= 0) {
    if(ret < 0) {
        /* unsynced, we jump over bytes to a possible capture - we don't need to read more just yet */
        oi_warn(_("WARNING: Hole in data (%d bytes) found at approximate offset %" I64FORMAT " bytes. Corrupted Ogg.\n"), -ret, *written);
        continue;
    }

    /* zero return, we didn't have enough data to find a whole page, read */
    buffer = ogg_sync_buffer(ogsync, CHUNK);
    bytes = fread(buffer, 1, CHUNK, f);
    if(bytes <= 0) {
        ogg_sync_wrote(ogsync, 0);
        return 0;
    }
    ogg_sync_wrote(ogsync, bytes);
    *written += bytes;
}

文件頭處理示例

//初始化流
ogg_stream_init(&stream->os, serial);
//ogg_stream_init
ogg_stream_pagein(&stream->os, page);
res = ogg_stream_packetout(&stream->os, &packet);
if(res <= 0) {
    oi_warn(_("WARNING: Invalid header page, no packet found\n"));
    null_start(stream);
}
else if(packet.bytes >= 19 && memcmp(packet.packet, "OpusHead", 8)==0)
...

/* re-init, ready for processing */
ogg_stream_clear(&stream->os);
ogg_stream_init(&stream->os, serial);
//此處是為了下次重新解析頭

音頻數(shù)據(jù)解析

音頻數(shù)據(jù)的解析根據(jù)ogg格式也是每個page進行解析

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

友情鏈接更多精彩內容