Trim opus file in ogg container
Can I use this library to Trim opus file in ogg container
I'm trying to avoid the large size ffmpeg lib and aiming for a small lib to trim/cut opus files in android
By any chance this library could help me?
It could help you, but not that straightway.
You should first read your audio as OggOpusStream
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()) {
// Do something with opusPacket
}
}
The create a new OutputStream, and encapsulate audioDataPacket into this OggPage and write to OutputStream.
// 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);
Thanks for detailed response I'll try to implement this
oggPage.setSerialNum(100); << Should 100 be fixed value or do i need to get it from somewhere?
Also how will I map start and end positions in for loop
long trimStartMs;
long trimEndMs;
...
for (OpusPacket opusPacket : audioDataPacket.getOpusPackets()) {
if(packetLiesWithinTrimRange(opusPacket )){ writeToOutput(opusPacket); }
}
...
private boolean packetLiesWithinTrimRange(OpusPacket packet){
if(????????){ return true;}
return false;
}
@leonfancy ??
Also looking into splitting an opus audio. The above ended up with a corrupt opus file in my scenario.
I had partial success, the file plays but in media players the duration will be shown of original audio and the position jumping to trimmed section
with dependency on https://github.com/leonfancy/oggus
import org.chenliang.oggus.ogg.OggPage;
import org.chenliang.oggus.ogg.OggStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class OpusFileUtil {
static long sampleRate = 48;
static long streamPreskip = -1;
static long streamGranulePosFirst;
public static void trim(long fromMs, long toMs, InputStream source, File result) throws IOException {
OggPage prevPage = null;
Log.oneLine("OGGPAGETRIM START ======================");
OutputStream outputStream = new FileOutputStream(result);
OggStream oggStream = OggStream.from(source);
outputStream.write(oggStream.readPage().dump()); //1st id page
outputStream.write(oggStream.readPage().dump()); //2nd comment page
outputStream.flush();
while (true) {
OggPage oggPage = oggStream.readPage();
if (oggPage == null) break;
long pageMsStart = prevPage == null ? 0 : getPageMsEnd(prevPage);
long pageMsEnd = getPageMsEnd(oggPage);
Log.oneLine("OGGPAGETRIM MS_START " + pageMsStart + "OGGPAGETRIM MS_END " + pageMsEnd);
if(pageMsStart > toMs){
break;
}
if (pageMsStart >= fromMs && pageMsEnd < toMs) {
Log.oneLine("OGGPAGETRIM " + oggPage.getGranulePosition() + " IN RANGE --------------------");
outputStream.write(oggPage.dump());
outputStream.flush();
}
if (prevPage == null) {
//this is first page
streamGranulePosFirst = oggPage.getGranulePosition();
}
prevPage = oggPage;
}
}
static long getPageMsEnd(OggPage page) {
return (page.getGranulePosition() - streamGranulePosFirst - streamPreskip) / sampleRate;
}
}
That was very helpful, thank you. In terms of the position misalignment, you might need to update the granule position of each page to have it fixed. I also noticed that the pageMsEnd of the second page (excluding the id/comment) is less than the pageMsStart. I was able to get around this by making the equation much simpler: page.getGranulePosition() / sampleRate although I am not certain about the accuracy of the timing yet.
Please post the solution for others if you made it work!