Something went wrong. Try again.
Reads and writes the Ogg container format in Zig: pages, packets, grouping and chaining, with a page layer that allocates nothing.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596// SPDX-FileCopyrightText: © 2026 Jeffrey C. Ollie <jeff@ocjtech.us>// SPDX-License-Identifier: MIT
//! zig-ogg -- reading and writing the Ogg container format, as specified by//! [RFC 3533](https://www.rfc-editor.org/rfc/rfc3533.html).//!//! Ogg is framing and nothing else. It takes packets from a codec, chops them//! into pages with a checksum and a position marker on each, and interleaves//! the pages of however many logical bitstreams share the file. It knows//! nothing about what the packets mean -- not even how long a second is -- and//! neither does this library: it moves packets in and out of pages and leaves//! every question about their contents to whoever wrote them.//!//! This is the library. It has no filesystem and no threads: a reader takes a//! `std.Io.Reader` and a writer takes a `std.Io.Writer`, so a caller with a//! file, a socket or a slice of memory supplies its own.//!//! # Reading//!//! ```zig//! const ogg = @import("ogg");//!//! var buffer: [ogg.Page.max_size]u8 = undefined;//! var d: ogg.Demuxer = .init(gpa, reader, &buffer, .{});//! defer d.deinit();//!//! while (try d.next()) |packet| {//! // packet.serial_number -- which logical bitstream//! // packet.data -- the bytes, valid until the next call//! // packet.first -- the identification packet, per ogg.codec//! }//! ```//!//! `Demuxer` is the whole of demultiplexing: concurrent streams and chained//! ones both come out as packets tagged with a serial number, because that is//! all either of them is. Below it, `PageReader` hands back one `Page` at a//! time for a caller that wants the framing rather than the contents, and//! `Page.parse` is the parser on its own, over bytes, with no I/O at all.//!//! # Writing//!//! ```zig//! var body: [ogg.Page.max_body_size]u8 = undefined;//! var w: ogg.StreamWriter = .init(writer, &body, .{ .serial_number = serial });//!//! try w.writePacket(identification_header, 0);//! for (packets) |packet| try w.writePacket(packet.bytes, packet.position);//! try w.finish();//! ```//!//! One `StreamWriter` is one logical bitstream. Two of them pointed at the same//! `std.Io.Writer` interleave into one physical bitstream, and one after another//! chains.//!//! # What allocates, and what does not//!//! **A page is bounded and a packet is not**, and that one fact decides the//! shape of everything here. A segment table holds at most 255 entries of at//! most 255 bytes, so no page exceeds `Page.max_size` = 65307 bytes however//! hostile the stream is: `Page`, `PageReader` and `StreamWriter` therefore//! allocate nothing at all and work out of one buffer the caller hands them. A//! packet, on the other hand, can be continued from page to page without end,//! so `Demuxer` -- the only part that reassembles one -- takes an allocator and//! a `max_packet_size` to refuse at.//!//! # What is where//!//! * `crc` -- the page checksum, which is not any of the catalogued CRC-32s.//! * `page` -- the page header, the segment table, and the packet fragments a//! page carries. Pure: bytes in, bytes out.//! * `reader` -- pages off a `std.Io.Reader`, and resynchronising after damage.//! * `writer` -- packets into pages, one logical bitstream at a time.//! * `demuxer` -- pages back into packets, any number of streams at once.//! * `codec` -- which codec a logical bitstream's first packet says it is.
const std = @import("std");
pub const crc = @import("crc.zig");pub const page = @import("page.zig");pub const reader = @import("reader.zig");pub const writer = @import("writer.zig");pub const demuxer = @import("demuxer.zig");pub const codec = @import("codec.zig");
pub const Page = page.Page;pub const HeaderType = page.HeaderType;pub const PageReader = reader.PageReader;pub const StreamWriter = writer.StreamWriter;pub const Demuxer = demuxer.Demuxer;pub const Packet = demuxer.Packet;pub const Codec = codec.Codec;
test { std.testing.refAllDecls(@This());}