1
votes

With an ultimate aim to crop/cut/trim the Ogg file containing a single opus stream, I'm trying to retrieve and filter ogg pages form the file and those which sit between the crop window of startTimeMs and endTimeMs I'll append them to the 2 ogg heads resulting in trimmed opus without transcoding

I have reached a stage where I have access to the ogg pages but I'm confused on how to determine if the page lies in crop window or not

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);

It should work if I would be able to complete this method

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

or maybe

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

Any ogg/opus help is appreciated

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

OggPage.java with private long granulePosition;

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

Ogg Encapsulation for the Opus Audio Codec https://datatracker.ietf.org/doc/html/rfc7845

1

1 Answers

0
votes

An audio page's end time can be calculated with using the stream's pre-skip and first/initial granule position. The page's start time can be obtained using the previous page's end time. See pseudocode below:

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
}