0

最终目标是裁剪/剪切/修剪包含单个作品流的 Ogg 文件,我正在尝试从文件中检索和过滤 ogg 页面以及位于 startTimeMs 和 endTimeMs 的裁剪窗口之间的那些页面,我将它们附加到2 个 ogg 头,无需转码即可修剪作品

我已经到了可以访问 ogg 页面的阶段,但我对如何确定页面是否位于裁剪窗口中感到困惑

OggOpusStream oggOpusStream = OggOpusStream.from("audio/technology.opus");

// Get ID Header
IdHeader idHeader = oggOpusStream.getIdHeader();

// Get Comment Header
CommentHeader commentHeader = oggOpusStream.getCommentHeader();

while (true) {
    AudioDataPacket audioDataPacket = oggOpusStream.readAudioPacket();
    if (audioDataPacket == null) break;
    
    for (OpusPacket opusPacket : audioDataPacket.getOpusPackets()) {
    if(packetLiesWithinTrimRange(opusPacket )){ writeToOutput(opusPacket); }
    }
}
// Create an output stream
OutputStream outputStream = ...;

// Create a new Ogg page
OggPage oggPage = OggPage.empty();

// Set header fields by calling setX() method
oggPage.setSerialNum(100);


// Add a data packet to this page
oggPage.addDataPacket(audioDataPacket.dump());

// Call dump() method to dump the OggPage object to byte array binary 
byte[] binary = oggPage.dump();

// Write the binary to stream
outputStream.write(binary);

如果我能够完成此方法,它应该可以工作

private boolean packetLiesWithinTrimRange(OpusPacket packet){
   if(????????){ return true;}
  return false;
}

或者可能

private boolean pageLiesWithinTrimRange(OggPage page){
   if(????????){ return true;}
  return false;
}

任何 ogg/opus 帮助表示赞赏

https://github.com/leonfancy/oggus/issues/2

OggPage.java 与 private long granulePosition;

https://github.com/leonfancy/oggus/blob/master/src/main/java/org/chenliang/oggus/ogg/OggPage.java

Opus 音频编解码器的 Ogg 封装 https://datatracker.ietf.org/doc/html/rfc7845

4

1 回答 1

1

可以使用流的pre-skip和 first/initial granule position来计算音频页面的结束时间。可以使用上一页的结束时间获取页面的开始时间。请参阅下面的伪代码:

sampleRate = 48_000
streamPreskip = ...
streamGranulePosFirst = ...

isPageWithinTimeRange(page, prevPage, msStart, msEnd) {
  pageMsStart = getPageMsEnd(prevPage)
  pageMsEnd =   getPageMsEnd(page)

  return (pageMsStart >= msStart && pageMsEnd <= msEnd)
}

getPageMsEnd(page) {
  return (page.granulePos - streamGranulePosFirst - streamPreskip) / sampleRate
}
于 2021-11-28T22:11:02.760 回答