ogg文件封閉格式簡介

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

ogg 數(shù)據(jù)結(jié)構(gòu)

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. 代表當(dāng)前流
ogg_packet This structure encapsulates the data and metadata for a single Ogg packet. 編碼時數(shù)據(jù)輸入的結(jié)構(gòu)包
ogg_sync_state Contains bitstream synchronization information.
image

以上ogg中最大的結(jié)構(gòu)為ogg流拉背,對比ogg的存儲結(jié)構(gòu)來說都是以ogg_page來進(jìn)行數(shù)據(jù)分頁焕济,但是對于用于來說是以ogg_packet來對數(shù)據(jù)進(jìn)行裝載和解析喇颁。

編碼相關(guān)

概覽

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代表結(jié)束包
  //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);
  }
}

解碼相關(guān)

基本方法

函數(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ù)輸入做準(zhǔn)備
ogg_sync_wrote Tells the synchronization layer how many bytes were written into the buffer. 同步已經(jīng)寫入了多少數(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信息,可進(jìn)行原始數(shù)據(jù)處理

創(chuàng)建與銷毀

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

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

處理結(jié)構(gòu)

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進(jìn)行解析

image
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末昵观,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子愉老,更是在濱河造成了極大的恐慌场绿,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嫉入,死亡現(xiàn)場離奇詭異焰盗,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)咒林,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進(jìn)店門熬拒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人垫竞,你說我怎么就攤上這事澎粟。” “怎么了欢瞪?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵活烙,是天一觀的道長。 經(jīng)常有香客問我遣鼓,道長啸盏,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任骑祟,我火速辦了婚禮回懦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘次企。我一直安慰自己怯晕,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布抒巢。 她就那樣靜靜地躺著贫贝,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蛉谜。 梳的紋絲不亂的頭發(fā)上稚晚,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天,我揣著相機(jī)與錄音型诚,去河邊找鬼客燕。 笑死,一個胖子當(dāng)著我的面吹牛狰贯,可吹牛的內(nèi)容都是我干的也搓。 我是一名探鬼主播赏廓,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼傍妒!你這毒婦竟也來了幔摸?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤颤练,失蹤者是張志新(化名)和其女友劉穎既忆,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嗦玖,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡患雇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了宇挫。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片苛吱。...
    茶點(diǎn)故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖器瘪,靈堂內(nèi)的尸體忽然破棺而出翠储,到底是詐尸還是另有隱情,我是刑警寧澤橡疼,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布彰亥,位于F島的核電站,受9級特大地震影響衰齐,放射性物質(zhì)發(fā)生泄漏任斋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一耻涛、第九天 我趴在偏房一處隱蔽的房頂上張望废酷。 院中可真熱鬧,春花似錦抹缕、人聲如沸澈蟆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽趴俘。三九已至,卻和暖如春奏赘,著一層夾襖步出監(jiān)牢的瞬間寥闪,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工磨淌, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留疲憋,地道東北人。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓梁只,卻偏偏與公主長得像缚柳,于是被迫代替她去往敵國和親埃脏。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評論 2 348