【问题标题】:How can I read OPUS packets one by one from ogg/opus file如何从 ogg/opus 文件中一一读取 OPUS 数据包
【发布时间】:2021-02-05 07:12:49
【问题描述】:

我需要从 ogg/opus 文件中一一读取 OPUS 数据包,并以 OPUS 格式进一步发送它们,因此无需解码。我正在查看opusfile lib,但 API 和示例相当复杂,并且更专注于解码文件并获得结果 PCM。有没有办法用这个库实现我想要的,以及如何实现?如果没有,我还有什么其他选择?

【问题讨论】:

    标签: codec ogg opus


    【解决方案1】:

    libogg 可用于解析 Ogg Opus 文件的“页面”,然后可以从这些页面中提取作品“数据包”。请注意,数据包可能跨越页面,但我个人在测试opusenc 创建的文件时没有遇到过这种情况。您也可以手动解析页面(参见Splitting an Ogg Opus File stream

    我建议先阅读 Opus 文件规范 (RFC 7845) 的基础知识,以了解文件结构。 https://opus-codec.org/docs/

    【讨论】:

      【解决方案2】:

      我想我有点晚了。我有非常相似的用例,我想从 ogg opus 文件中提取 opus 数据包。我找到了这个答案

      https://stackoverflow.com/a/26285277/10110652

      以下代码将帮助您在 while 循环内的 'nextPacket' byteArray 中获取 opus 数据包(未解码为 pcm)

      File audioFile = null; 
          try {
              audioFile = new File("xyz.ogg"); //input ogg opus file
              oggFile = new FileStream(new RandomAccessFile(audioFile, "r"));
      
              for (LogicalOggStream stream : (Collection<LogicalOggStream>) oggFile.getLogicalStreams()) {
                  byte[] nextPacket = stream.getNextOggPacket();
                  while (nextPacket != null) {
                          //nextPacket here contains opus packet
                          //do what ever you want to do with this packet
                       
                      nextPacket = stream.getNextOggPacket();
                  }
              }
      
          } catch (EndOfOggStreamException e) {
              System.out.println("End of File");
              //file usually get over by raising this exception while execution getNextOggPacket()
          }
      

      同样的程序可以用来提取 ogg 容器中的 vorbis 编码数据包,即 ogg vorbis 文件。

      编码愉快!!!

      【讨论】:

        【解决方案3】:

        您可以使用libogg 来访问 Opus 数据包。不幸的是,它并不比opusfile 简单得多。在 C-ish 伪代码中,一般流程是:

        readPage(ogg_sync_state* syncState, ogg_page* page, file) {
          while ((ogg_sync_pageout(syncState, page) != 1) && file is good) {
            buffer = ogg_sync_buffer(syncState, yourMaxReadSize);
            bytesActuallyRead = read(file, buffer, yourMaxReadSize);
            ogg_sync_wrote(syncState, bytesActuallyReadFromFile); //tell the syncState how many bytes were actually read
          } //now we have a page, or the file is done
        }
        
        read() {
          ogg_sync_state oggSyncState;
          ogg_stream_state oggStreamState;
          ogg_page oggPage;
          ogg_packet oggPacket;
        
          open file;
        
          while (file is good) {
            readPage(&oggSyncState, &oggPage);
            if (ogg_page_bos(&oggPage)) {
              sn = ogg_page_serialno(&oggPage); //you can remember this serial number and check it on every page for robustness
              ogg_stream_init(&oggStreamState, sn);
            } 
            ogg_stream_pagein(&oggStreamState, &oggPage);
            while (ogg_stream_packetout(&oggStreamState, &oggPacket) != 0) {
              //check if it's a header packet, skip if so.
              //See https://tools.ietf.org/html/rfc7845.html#section-5 to see how to identify a header packet
              //Else it must be data
              do something with the buffer oggPacket.packet with size oggPacket.bytes
            }
            readPage(&oggSyncState, &oggPage, file);
            ogg_stream_pagein(&oggStreamState, &oggPage_);
          }
        }
        

        readPage 从文件中拉取一堆字节(yourMaxReadSize)到oggSyncState 结构中,然后逐页提取。在read中,数据包是从页面中一一提取出来的。

        【讨论】:

        • 感谢您的回答,我在考虑libogg,但希望有更简单的方法,使用opusfile,代码更少
        猜你喜欢
        • 2023-03-26
        • 2013-09-19
        • 2020-02-05
        • 2019-03-23
        • 2021-01-14
        • 2015-11-16
        • 2016-11-06
        • 1970-01-01
        • 2021-09-02
        相关资源
        最近更新 更多