avpack

June 7, 2025 ยท View on GitHub

avpack is a fast C library that can pack and unpack data to/from the popular multimedia container formats.

avpack code is header-only (.h-only) and doesn't need to be built into .a/.so/.dll before use - you just include .h file and that's all.

avpack is used by phiola (https://github.com/stsaz/phiola) - a fast audio player/recorder/converter. avpack is the only library for reading and writing multimedia files that is suitable for the highly efficient file I/O implemented in phiola.

Contents:

Features

  • read/write meta tags, audio track info
  • read/write audio frames
  • convenient for asynchronous I/O model (no I/O callback functions)
PurposeInclude Files
Audio file formats:
.aac readaac-read.h
.ape readape-read.h
.avi readavi-read.h
.caf readcaf-read.h
.flac readflac-read.h
.mkv/.webm readmkv-read.h
.mp3 read/writemp3-read.h, mp3-write.h
.mp4/.m4a/.mov read/writemp4-read.h, mp4-write.h
.mpc readmpc-read.h
.ogg(FLAC) readflac-ogg-read.h
.ogg/.opus read/writeogg-read.h, ogg-write.h
.ts readts-read.h
.wav read/writewav-read.h, wav-write.h
.wv read/writewv-read.h
Audio streams:
ICY stream readicy.h
MPEG-1 stream readmpeg1-read.h
Playlists:
.cue readcue.h
.m3u read/writem3u.h
.pls readpls.h
MM Tags:
APETAG readapetag.h
ID3v1 & ID3v2 read/writeid3v1.h, id3v2.h
Vorbis tags read/writevorbistag.h
Graphics:
.bmp read/writebmp-read.h, bmp-write.h
.jpg readjpg-read.h
.png readpng-read.h

It doesn't contain code that reads or writes files - this is user's responsibility.

How to use

  1. Clone repos:

     git clone https://github.com/stsaz/ffbase
     git clone https://github.com/stsaz/avpack
    
  2. Set compiler flags in your build script:

     -IFFBASE_DIR -IAVPACK_DIR
    

where FFBASE_DIR is your ffbase/ directory, and AVPACK_DIR is your avpack/ directory.

  1. And then just use the necessary files, e.g.:

     #include <avpack/mp4-read.h>
     #include <avpack/mp4-write.h>
    

Audio File Format Reader

	#include <avpack/reader.h>

	static const struct avpkr_if *const avpk_formats[] = {
		&avpk_mp3,
		...
	};

	struct avpk_reader_conf ac = {
		.total_size = ...,
	};
	avpk_reader ar = {};
	if (avpk_open(&ar, avpk_reader_find("mp3", avpk_formats, FF_COUNT(avpk_formats)), &ac))
		goto fin;
	ffstr in = {};
	for (;;) {
		union avpk_read_result res = {};
		switch (avpk_read(&ar, &in, &res)) {
		case AVPK_HEADER:
			// read res.hdr
			break;

		case AVPK_META:
			// read res.tag
			break;

		case AVPK_DATA:
			// read res.frame
			break;

		case AVPK_SEEK:
			// seek to res.seek_offset
			// fallthrough
		case AVPK_MORE:
			in = ...;
			break;

		case AVPK_FIN:
			goto fin;

		case AVPK_WARNING:
			// read res.error
			break;
		case AVPK_ERROR:
			// read res.error
			goto fin;
		}
	}

fin:
	avpk_close(&ar);

Audio File Format Writer

	#include <avpack/writer.h>

	static const struct avpkw_if *const avpkw_formats[] = {
		&avpkw_mp3,
		...
	};

	avpk_writer aw = {};
	struct avpk_writer_conf ac = {
		.info = {
			.duration = ...,
			.sample_rate = ...,
			.sample_bits = ...,
			.channels = ...,
		},
	};
	if (avpk_create(&aw, avpk_writer_find("mp3", avpkw_formats, FF_COUNT(avpkw_formats)), &ac))
		exit(1);

	avpk_tag(&aw, MMTAG_VENDOR, FFSTR_Z(""), ...);
	avpk_tag(&aw, MMTAG_ARTIST, FFSTR_Z(""), ...);
	avpk_tag(&aw, MMTAG_TITLE, FFSTR_Z(""), ...);
	...

	struct avpk_frame in = {
		.len = ...,
		.ptr = ...,
	};
	unsigned flags = 0;
	for (;;) {
		union avpk_write_result res = {};
		int r = avpk_write(&aw, &in, flags, &res);
		switch (r) {
		case AVPK_DATA:
			// use res.packet
			break;

		case AVPK_SEEK:
			// seek to res.seek_offset
			continue;

		case AVPK_MORE:
			in = ...;
			flags = ...;
			break;

		case AVPK_FIN:
			goto fin;

		case AVPK_ERROR:
			// read res.error.message
			goto fin;
		}
	}

fin:
	avpk_writer_close(&aw);

Test

git clone https://github.com/stsaz/ffbase
git clone https://github.com/stsaz/avpack
cd avpack/test
make
./avpack-test all