ogg
ogg copied to clipboard
Can't decode/encode without screwing the stream
package main
import (
"fmt"
"os"
"github.com/mccoyst/ogg"
)
func main() {
f, err := os.Open(os.Args[1])
if err != nil {
panic(err)
}
decoder := ogg.NewDecoder(f)
var encoder *ogg.Encoder
for {
page, err := decoder.Decode()
if err != nil {
fmt.Fprint(os.Stderr, err)
break
}
if encoder == nil {
encoder = ogg.NewEncoder(page.Serial, os.Stdout)
encoder.EncodeBOS(page.Granule, page.Packet)
} else {
encoder.Encode(page.Granule, page.Packet)
}
}
}
./copy a.ogg > b.ogg
This code decode a stream, encodes it to stdout.
ogginfo
works well with my original stream, but doesn't handle the output stream.
I tried something similar on my end and the only issue I found was with EOS. An ffmpeg-recorded .ogg file contains an EOS packet that also has data. This is lost due to the current API being exposed.
Using something like
func (w *Encoder) EncodeEOSPacket(granule int64, packet []byte) error {
return w.writePacket(EOS, granule, packet)
}
fixes the problem on my end
edit: NVM. This fixes the last EOS, but it looks like there are still errors somewhere in the packet writing logic.
As of today, I can confirm this issue still exists as I am trying something similar on my end (a copy logic), using the code listed below given filePath
, dupFilePath
pre-defined. After checking the binary generated, I am sure that there is a difference in many packets even though they have the same stats (page.Type, page.Granule, page.Serial, len(page.Packet)
). And if using ffprobe
, the generated file will show [opus @ 0x558cf915d580] Error parsing the packet header.
I have no idea why this copy logic won't work.
f, _:= os.Open(filePath)
defer f.Close()
w, _ := os.Create(dupFilePath)
defer w.Close()
decoder := ogg.NewDecoder(f)
encoder := ogg.NewEncoder(482915044, w)
for {
page, err := decoder.Decode()
fmt.Printf(
"page: type: %d, granule: %d, serial: %d, length: %d bytes\n",
page.Type, page.Granule, page.Serial, len(page.Packet))
if err != nil {
break
}
if page.Type == ogg.BOS {
encoder.EncodeBOS(page.Granule, page.Packet)
} else if page.Type == ogg.EOS {
if len(page.Packet) != 0 {
encoder.Encode(page.Granule, page.Packet)
}
encoder.EncodeEOS()
} else {
encoder.Encode(page.Granule, page.Packet)
}
}
Long story short: I figured out the root cause, and it was me misunderstanding the lacing values part of the spec. I should have a fix ready this week.
I believe I've solved the many problems. The downside is that I had to change the API so that the library can encode/decode pages that contain multiple packets. See otest.go
for an example — it's pretty much like the test programs posted to this issue, but uses the new methods.
Let me know if you find any files in the wild that break the new API. Thanks!
Keeping in mind that I've tested entirely via prog rock oggs from wikipedia, I haven't found a file that breaks yet, so I'm closing this. If anybody does ever find a file (vorbis or otherwise) that this can't handle, feel free to make a new ticket for the specific file (if possible).