diff --git a/Makefile b/Makefile index 80c4992..9ebdbcf 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,5 @@ PROG = oxframe SRC = src/oxframe.c -NESTEGGS = src/nestegg.o src/halloc/src/halloc.o PREFIX ?= /usr/local BINDIR ?= ${DESTDIR}${PREFIX}/bin @@ -19,15 +18,13 @@ LINKFLAGS += `imlib2-config --libs` #LINKFLAGS += `pkg-config --libs oggplay` LINKFLAGS += -L/usr/local/lib /usr/local/lib/liboggplay.a LINKFLAGS += -loggz -lfishsound -ltheora -lvorbisenc -lvorbis -lm -logg -lkate -lpthread -LINKFLAGS += -lvpx +LINKFLAGS += -lvpx -lnestegg all: ${PROG} -src/nestegg.o: src/nestegg.h src/nestegg.c src/halloc/halloc.h -src/halloc/src/halloc.o: src/halloc/src/halloc.c src/halloc/halloc.h src/halloc/src/align.h src/halloc/src/hlist.h src/halloc/src/macros.h -${PROG}: ${SRC} ${NESTEGGS} - ${CC} -Wall -Wno-parentheses -O3 -fforce-addr -fomit-frame-pointer -finline-functions -funroll-loops ${CFLAGS} ${INCLUDEFLAGS} -o ${PROG} $< ${NESTEGGS} ${LINKFLAGS} +${PROG}: ${SRC} + ${CC} -Wall -Wno-parentheses -O3 -fforce-addr -fomit-frame-pointer -finline-functions -funroll-loops ${CFLAGS} ${INCLUDEFLAGS} -o ${PROG} $< ${LINKFLAGS} clean: -@rm -f ${PROG} *~ core *.core src/*.o src/halloc/src/*.o diff --git a/README b/README index d613f37..0c3e7dc 100644 --- a/README +++ b/README @@ -4,7 +4,9 @@ dependencies: liboggz git clone git://git.xiph.org/liboggz.git liboggplay git clone git://git.xiph.org/liboggplay.git libtheora apt-get install libtheora-dev - libvpx git clone git://review.webmproject.org/libvpx.git - - + libvpx get debs from + https://launchpad.net/~chromium-daily/+archive/ppa + or compile from + git clone git://review.webmproject.org/libvpx.git + libnestegg git clone http://github.com/kinetiknz/nestegg.git diff --git a/src/halloc/Makefile b/src/halloc/Makefile deleted file mode 100644 index d3df7d7..0000000 --- a/src/halloc/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -CFLAGS = -I. -ansi -Wall -pedantic - -LIBNAME = libhalloc.a -OBJS = src/halloc.o - -$(LIBNAME): $(OBJS) - ar rcs $(LIBNAME) $(OBJS) - -install: $(LIBNAME) - cp halloc.h /usr/include - cp $(LIBNAME) /usr/lib - -clean: - rm -f $(LIBNAME) $(OBJS) diff --git a/src/halloc/README b/src/halloc/README deleted file mode 100644 index 380fba2..0000000 --- a/src/halloc/README +++ /dev/null @@ -1,45 +0,0 @@ -halloc 1.2.1 -============ - - Hierarchical memory heap interface - an extension to standard - malloc/free interface that simplifies tasks of memory disposal - when allocated structures exhibit hierarchical properties. - - http://swapped.cc/halloc -= - To build libhalloc.a with GNU tools run - make - - To install in /usr/include and /usr/lib - make install - - To cleanup the build files - make clean -= - halloc-1.2.1 - * fixed a double-free bug in _set_allocator() as per - Matthew Gregan comments - - * switched to using NULL instead of 0 where applicable - - halloc-1.2.0 - * added missing include to halloc.c - - * improved standard compliance thanks to the feedback - received from Stan Tobias. Two things were fixed - - - - hblock_t structure no longer uses zero-sized 'data' - array, which happened to be common, but non-standard - extension; - - - secondly, added the code to test the behaviour of - realloc(ptr, 0). Standard allows it NOT to act as - free(), in which case halloc will use its own version - of allocator calling free() when neccessary. - - halloc-1.1.0 - * initial public release (rewrite of hhmalloc library) - -============================================================================= -Copyright (c) 2004-2010, Alex Pankratov (ap@swapped.cc). All rights reserved. - diff --git a/src/halloc/halloc.h b/src/halloc/halloc.h deleted file mode 100644 index 10af4e8..0000000 --- a/src/halloc/halloc.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2004-2010 Alex Pankratov. All rights reserved. - * - * Hierarchical memory allocator, 1.2.1 - * http://swapped.cc/halloc - */ - -/* - * The program is distributed under terms of BSD license. - * You can obtain the copy of the license by visiting: - * - * http://www.opensource.org/licenses/bsd-license.php - */ - -#ifndef _LIBP_HALLOC_H_ -#define _LIBP_HALLOC_H_ - -#include /* size_t */ - -/* - * Core API - */ -void * halloc (void * block, size_t len); -void hattach(void * block, void * parent); - -/* - * standard malloc/free api - */ -void * h_malloc (size_t len); -void * h_calloc (size_t n, size_t len); -void * h_realloc(void * p, size_t len); -void h_free (void * p); -char * h_strdup (const char * str); - -/* - * the underlying allocator - */ -typedef void * (* realloc_t)(void * ptr, size_t len); - -extern realloc_t halloc_allocator; - -#endif - diff --git a/src/halloc/src/align.h b/src/halloc/src/align.h deleted file mode 100644 index 4c6e183..0000000 --- a/src/halloc/src/align.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2004-2010 Alex Pankratov. All rights reserved. - * - * Hierarchical memory allocator, 1.2.1 - * http://swapped.cc/halloc - */ - -/* - * The program is distributed under terms of BSD license. - * You can obtain the copy of the license by visiting: - * - * http://www.opensource.org/licenses/bsd-license.php - */ - -#ifndef _LIBP_ALIGN_H_ -#define _LIBP_ALIGN_H_ - -/* - * a type with the most strict alignment requirements - */ -union max_align -{ - char c; - short s; - long l; - int i; - float f; - double d; - void * v; - void (*q)(void); -}; - -typedef union max_align max_align_t; - -#endif - diff --git a/src/halloc/src/halloc.c b/src/halloc/src/halloc.c deleted file mode 100644 index 5758fc0..0000000 --- a/src/halloc/src/halloc.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (c) 2004i-2010 Alex Pankratov. All rights reserved. - * - * Hierarchical memory allocator, 1.2.1 - * http://swapped.cc/halloc - */ - -/* - * The program is distributed under terms of BSD license. - * You can obtain the copy of the license by visiting: - * - * http://www.opensource.org/licenses/bsd-license.php - */ - -#include /* realloc */ -#include /* memset & co */ - -#include "halloc.h" -#include "align.h" -#include "hlist.h" - -/* - * block control header - */ -typedef struct hblock -{ -#ifndef NDEBUG -#define HH_MAGIC 0x20040518L - long magic; -#endif - hlist_item_t siblings; /* 2 pointers */ - hlist_head_t children; /* 1 pointer */ - max_align_t data[1]; /* not allocated, see below */ - -} hblock_t; - -#define sizeof_hblock offsetof(hblock_t, data) - -/* - * - */ -realloc_t halloc_allocator = NULL; - -#define allocator halloc_allocator - -/* - * static methods - */ -static void _set_allocator(void); -static void * _realloc(void * ptr, size_t n); - -static int _relate(hblock_t * b, hblock_t * p); -static void _free_children(hblock_t * p); - -/* - * Core API - */ -void * halloc(void * ptr, size_t len) -{ - hblock_t * p; - - /* set up default allocator */ - if (! allocator) - { - _set_allocator(); - assert(allocator); - } - - /* calloc */ - if (! ptr) - { - if (! len) - return NULL; - - p = allocator(0, len + sizeof_hblock); - if (! p) - return NULL; -#ifndef NDEBUG - p->magic = HH_MAGIC; -#endif - hlist_init(&p->children); - hlist_init_item(&p->siblings); - - return p->data; - } - - p = structof(ptr, hblock_t, data); - assert(p->magic == HH_MAGIC); - - /* realloc */ - if (len) - { - p = allocator(p, len + sizeof_hblock); - if (! p) - return NULL; - - hlist_relink(&p->siblings); - hlist_relink_head(&p->children); - - return p->data; - } - - /* free */ - _free_children(p); - hlist_del(&p->siblings); - allocator(p, 0); - - return NULL; -} - -void hattach(void * block, void * parent) -{ - hblock_t * b, * p; - - if (! block) - { - assert(! parent); - return; - } - - /* detach */ - b = structof(block, hblock_t, data); - assert(b->magic == HH_MAGIC); - - hlist_del(&b->siblings); - - if (! parent) - return; - - /* attach */ - p = structof(parent, hblock_t, data); - assert(p->magic == HH_MAGIC); - - /* sanity checks */ - assert(b != p); /* trivial */ - assert(! _relate(p, b)); /* heavy ! */ - - hlist_add(&p->children, &b->siblings); -} - -/* - * malloc/free api - */ -void * h_malloc(size_t len) -{ - return halloc(0, len); -} - -void * h_calloc(size_t n, size_t len) -{ - void * ptr = halloc(0, len*=n); - return ptr ? memset(ptr, 0, len) : NULL; -} - -void * h_realloc(void * ptr, size_t len) -{ - return halloc(ptr, len); -} - -void h_free(void * ptr) -{ - halloc(ptr, 0); -} - -char * h_strdup(const char * str) -{ - size_t len = strlen(str); - char * ptr = halloc(0, len + 1); - return ptr ? (ptr[len] = 0, memcpy(ptr, str, len)) : NULL; -} - -/* - * static stuff - */ -static void _set_allocator(void) -{ - void * p; - assert(! allocator); - - /* - * the purpose of the test below is to check the behaviour - * of realloc(ptr, 0), which is defined in the standard - * as an implementation-specific. if it returns zero, - * then it's equivalent to free(). it can however return - * non-zero, in which case it cannot be used for freeing - * memory blocks and we'll need to supply our own version - * - * Thanks to Stan Tobias for pointing this tricky part out. - */ - allocator = realloc; - if (! (p = malloc(1))) - /* hmm */ - return; - - if ((p = realloc(p, 0))) - { - /* realloc cannot be used as free() */ - allocator = _realloc; - free(p); - } -} - -static void * _realloc(void * ptr, size_t n) -{ - /* - * free'ing realloc() - */ - if (n) - return realloc(ptr, n); - free(ptr); - return NULL; -} - -static int _relate(hblock_t * b, hblock_t * p) -{ - hlist_item_t * i; - - if (!b || !p) - return 0; - - /* - * since there is no 'parent' pointer, which would've allowed - * O(log(n)) upward traversal, the check must use O(n) downward - * iteration of the entire hierarchy; and this can be VERY SLOW - */ - hlist_for_each(i, &p->children) - { - hblock_t * q = structof(i, hblock_t, siblings); - if (q == b || _relate(b, q)) - return 1; - } - return 0; -} - -static void _free_children(hblock_t * p) -{ - hlist_item_t * i, * tmp; - -#ifndef NDEBUG - /* - * this catches loops in hierarchy with almost zero - * overhead (compared to _relate() running time) - */ - assert(p && p->magic == HH_MAGIC); - p->magic = 0; -#endif - hlist_for_each_safe(i, tmp, &p->children) - { - hblock_t * q = structof(i, hblock_t, siblings); - _free_children(q); - allocator(q, 0); - } -} - diff --git a/src/halloc/src/hlist.h b/src/halloc/src/hlist.h deleted file mode 100644 index 2791f78..0000000 --- a/src/halloc/src/hlist.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2004-2010 Alex Pankratov. All rights reserved. - * - * Hierarchical memory allocator, 1.2.1 - * http://swapped.cc/halloc - */ - -/* - * The program is distributed under terms of BSD license. - * You can obtain the copy of the license by visiting: - * - * http://www.opensource.org/licenses/bsd-license.php - */ - -#ifndef _LIBP_HLIST_H_ -#define _LIBP_HLIST_H_ - -#include -#include "macros.h" /* static_inline */ - -/* - * weak double-linked list w/ tail sentinel - */ -typedef struct hlist_head hlist_head_t; -typedef struct hlist_item hlist_item_t; - -/* - * - */ -struct hlist_head -{ - hlist_item_t * next; -}; - -struct hlist_item -{ - hlist_item_t * next; - hlist_item_t ** prev; -}; - -/* - * shared tail sentinel - */ -struct hlist_item hlist_null; - -/* - * - */ -#define __hlist_init(h) { &hlist_null } -#define __hlist_init_item(i) { &hlist_null, &(i).next } - -static_inline void hlist_init(hlist_head_t * h); -static_inline void hlist_init_item(hlist_item_t * i); - -/* static_inline void hlist_purge(hlist_head_t * h); */ - -/* static_inline bool_t hlist_empty(const hlist_head_t * h); */ - -/* static_inline hlist_item_t * hlist_head(const hlist_head_t * h); */ - -/* static_inline hlist_item_t * hlist_next(const hlist_item_t * i); */ -/* static_inline hlist_item_t * hlist_prev(const hlist_item_t * i, - const hlist_head_t * h); */ - -static_inline void hlist_add(hlist_head_t * h, hlist_item_t * i); - -/* static_inline void hlist_add_prev(hlist_item_t * l, hlist_item_t * i); */ -/* static_inline void hlist_add_next(hlist_item_t * l, hlist_item_t * i); */ - -static_inline void hlist_del(hlist_item_t * i); - -static_inline void hlist_relink(hlist_item_t * i); -static_inline void hlist_relink_head(hlist_head_t * h); - -#define hlist_for_each(i, h) \ - for (i = (h)->next; i != &hlist_null; i = i->next) - -#define hlist_for_each_safe(i, tmp, h) \ - for (i = (h)->next, tmp = i->next; \ - i!= &hlist_null; \ - i = tmp, tmp = i->next) - -/* - * static - */ -static_inline void hlist_init(hlist_head_t * h) -{ - assert(h); - h->next = &hlist_null; -} - -static_inline void hlist_init_item(hlist_item_t * i) -{ - assert(i); - i->prev = &i->next; - i->next = &hlist_null; -} - -static_inline void hlist_add(hlist_head_t * h, hlist_item_t * i) -{ - hlist_item_t * next; - assert(h && i); - - next = i->next = h->next; - next->prev = &i->next; - h->next = i; - i->prev = &h->next; -} - -static_inline void hlist_del(hlist_item_t * i) -{ - hlist_item_t * next; - assert(i); - - next = i->next; - next->prev = i->prev; - *i->prev = next; - - hlist_init_item(i); -} - -static_inline void hlist_relink(hlist_item_t * i) -{ - assert(i); - *i->prev = i; - i->next->prev = &i->next; -} - -static_inline void hlist_relink_head(hlist_head_t * h) -{ - assert(h); - h->next->prev = &h->next; -} - -#endif - diff --git a/src/halloc/src/macros.h b/src/halloc/src/macros.h deleted file mode 100644 index c36b516..0000000 --- a/src/halloc/src/macros.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2004-2010 Alex Pankratov. All rights reserved. - * - * Hierarchical memory allocator, 1.2.1 - * http://swapped.cc/halloc - */ - -/* - * The program is distributed under terms of BSD license. - * You can obtain the copy of the license by visiting: - * - * http://www.opensource.org/licenses/bsd-license.php - */ - -#ifndef _LIBP_MACROS_H_ -#define _LIBP_MACROS_H_ - -#include /* offsetof */ - -/* - restore pointer to the structure by a pointer to its field - */ -#define structof(p,t,f) ((t*)(- offsetof(t,f) + (char*)(p))) - -/* - * redefine for the target compiler - */ -#ifdef _WIN32 -#define static_inline static __inline -#else -#define static_inline static __inline__ -#endif - - -#endif - diff --git a/src/nestegg.c b/src/nestegg.c deleted file mode 100644 index c6fd5dd..0000000 --- a/src/nestegg.c +++ /dev/null @@ -1,1947 +0,0 @@ -/* - * Copyright © 2010 Matthew Gregan - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include -#include -#include - -#include "halloc.h" -#include "nestegg.h" - -/* EBML Elements */ -#define ID_EBML 0x1a45dfa3 -#define ID_EBML_VERSION 0x4286 -#define ID_EBML_READ_VERSION 0x42f7 -#define ID_EBML_MAX_ID_LENGTH 0x42f2 -#define ID_EBML_MAX_SIZE_LENGTH 0x42f3 -#define ID_DOCTYPE 0x4282 -#define ID_DOCTYPE_VERSION 0x4287 -#define ID_DOCTYPE_READ_VERSION 0x4285 - -/* Global Elements */ -#define ID_VOID 0xec -#define ID_CRC32 0xbf - -/* WebMedia Elements */ -#define ID_SEGMENT 0x18538067 - -/* Seek Head Elements */ -#define ID_SEEK_HEAD 0x114d9b74 -#define ID_SEEK 0x4dbb -#define ID_SEEK_ID 0x53ab -#define ID_SEEK_POSITION 0x53ac - -/* Info Elements */ -#define ID_INFO 0x1549a966 -#define ID_TIMECODE_SCALE 0x2ad7b1 -#define ID_DURATION 0x4489 - -/* Cluster Elements */ -#define ID_CLUSTER 0x1f43b675 -#define ID_TIMECODE 0xe7 -#define ID_BLOCK_GROUP 0xa0 -#define ID_SIMPLE_BLOCK 0xa3 - -/* BlockGroup Elements */ -#define ID_BLOCK 0xa1 -#define ID_BLOCK_DURATION 0x9b -#define ID_REFERENCE_BLOCK 0xfb - -/* Tracks Elements */ -#define ID_TRACKS 0x1654ae6b -#define ID_TRACK_ENTRY 0xae -#define ID_TRACK_NUMBER 0xd7 -#define ID_TRACK_UID 0x73c5 -#define ID_TRACK_TYPE 0x83 -#define ID_FLAG_ENABLED 0xb9 -#define ID_FLAG_DEFAULT 0x88 -#define ID_FLAG_LACING 0x9c -#define ID_TRACK_TIMECODE_SCALE 0x23314f -#define ID_LANGUAGE 0x22b59c -#define ID_CODEC_ID 0x86 -#define ID_CODEC_PRIVATE 0x63a2 - -/* Video Elements */ -#define ID_VIDEO 0xe0 -#define ID_PIXEL_WIDTH 0xb0 -#define ID_PIXEL_HEIGHT 0xba -#define ID_PIXEL_CROP_BOTTOM 0x54aa -#define ID_PIXEL_CROP_TOP 0x54bb -#define ID_PIXEL_CROP_LEFT 0x54cc -#define ID_PIXEL_CROP_RIGHT 0x54dd -#define ID_DISPLAY_WIDTH 0x54b0 -#define ID_DISPLAY_HEIGHT 0x54ba - -/* Audio Elements */ -#define ID_AUDIO 0xe1 -#define ID_SAMPLING_FREQUENCY 0xb5 -#define ID_CHANNELS 0x9f -#define ID_BIT_DEPTH 0x6264 - -/* Cues Elements */ -#define ID_CUES 0x1c53bb6b -#define ID_CUE_POINT 0xbb -#define ID_CUE_TIME 0xb3 -#define ID_CUE_TRACK_POSITIONS 0xb7 -#define ID_CUE_TRACK 0xf7 -#define ID_CUE_CLUSTER_POSITION 0xf1 -#define ID_CUE_BLOCK_NUMBER 0x5378 - -/* EBML Types */ -enum ebml_type_enum { - TYPE_UNKNOWN, - TYPE_MASTER, - TYPE_UINT, - TYPE_FLOAT, - TYPE_INT, - TYPE_STRING, - TYPE_BINARY -}; - -#define LIMIT_STRING (1 << 20) -#define LIMIT_BINARY (1 << 24) -#define LIMIT_BLOCK (1 << 30) -#define LIMIT_FRAME (1 << 28) - -/* Field Flags */ -#define DESC_FLAG_NONE 0 -#define DESC_FLAG_MULTI (1 << 0) -#define DESC_FLAG_SUSPEND (1 << 1) -#define DESC_FLAG_OFFSET (1 << 2) - -/* Lacing Constants */ -#define LACING_NONE 0 -#define LACING_XIPH 1 -#define LACING_FIXED 2 -#define LACING_EBML 3 - -enum vint_mask { - MASK_NONE, - MASK_FIRST_BIT -}; - -struct ebml_binary { - unsigned char * data; - size_t length; -}; - -struct ebml_list_node { - struct ebml_list_node * next; - uint64_t id; - void * data; -}; - -struct ebml_list { - struct ebml_list_node * head; - struct ebml_list_node * tail; -}; - -struct ebml_type { - union ebml_value { - uint64_t u; - double f; - int64_t i; - char * s; - struct ebml_binary b; - } v; - enum ebml_type_enum type; - int read; -}; - -/* EBML Definitions */ -struct ebml { - struct ebml_type ebml_version; - struct ebml_type ebml_read_version; - struct ebml_type ebml_max_id_length; - struct ebml_type ebml_max_size_length; - struct ebml_type doctype; - struct ebml_type doctype_version; - struct ebml_type doctype_read_version; -}; - -/* Matroksa Definitions */ -struct seek { - struct ebml_type id; - struct ebml_type position; -}; - -struct seek_head { - struct ebml_list seek; -}; - -struct info { - struct ebml_type timecode_scale; - struct ebml_type duration; -}; - -struct block_group { - struct ebml_type duration; - struct ebml_type reference_block; -}; - -struct cluster { - struct ebml_type timecode; - struct ebml_list block_group; -}; - -struct video { - struct ebml_type pixel_width; - struct ebml_type pixel_height; - struct ebml_type pixel_crop_bottom; - struct ebml_type pixel_crop_top; - struct ebml_type pixel_crop_left; - struct ebml_type pixel_crop_right; - struct ebml_type display_width; - struct ebml_type display_height; -}; - -struct audio { - struct ebml_type sampling_frequency; - struct ebml_type channels; - struct ebml_type bit_depth; -}; - -struct track_entry { - struct ebml_type number; - struct ebml_type uid; - struct ebml_type type; - struct ebml_type flag_enabled; - struct ebml_type flag_default; - struct ebml_type flag_lacing; - struct ebml_type track_timecode_scale; - struct ebml_type language; - struct ebml_type codec_id; - struct ebml_type codec_private; - struct video video; - struct audio audio; -}; - -struct tracks { - struct ebml_list track_entry; -}; - -struct cue_track_positions { - struct ebml_type track; - struct ebml_type cluster_position; - struct ebml_type block_number; -}; - -struct cue_point { - struct ebml_type time; - struct ebml_list cue_track_positions; -}; - -struct cues { - struct ebml_list cue_point; -}; - -struct segment { - struct ebml_list seek_head; - struct info info; - struct ebml_list cluster; - struct tracks tracks; - struct cues cues; -}; - -/* Misc. */ -struct pool_ctx { - char dummy; -}; - -struct list_node { - struct list_node * previous; - struct ebml_element_desc * node; - unsigned char * data; -}; - -struct saved_state { - int64_t stream_offset; - struct list_node * ancestor; - uint64_t last_id; - uint64_t last_size; -}; - -struct frame { - unsigned char * data; - size_t length; - struct frame * next; -}; - -/* Public (opaque) Structures */ -struct nestegg { - nestegg_io * io; - nestegg_log log; - struct pool_ctx * alloc_pool; - uint64_t last_id; - uint64_t last_size; - struct list_node * ancestor; - struct ebml ebml; - struct segment segment; - int64_t segment_offset; - unsigned int track_count; -}; - -struct nestegg_packet { - uint64_t track; - uint64_t timecode; - struct frame * frame; -}; - -/* Element Descriptor */ -struct ebml_element_desc { - char const * name; - uint64_t id; - enum ebml_type_enum type; - size_t offset; - unsigned int flags; - struct ebml_element_desc * children; - size_t size; - size_t data_offset; -}; - -#define E_FIELD(ID, TYPE, STRUCT, FIELD) \ - { #ID, ID, TYPE, offsetof(STRUCT, FIELD), DESC_FLAG_NONE, NULL, 0, 0 } -#define E_MASTER(ID, TYPE, STRUCT, FIELD) \ - { #ID, ID, TYPE, offsetof(STRUCT, FIELD), DESC_FLAG_MULTI, FIELD ## _elements, \ - sizeof(struct FIELD), 0 } -#define E_SINGLE_MASTER_O(ID, TYPE, STRUCT, FIELD) \ - { #ID, ID, TYPE, offsetof(STRUCT, FIELD), DESC_FLAG_OFFSET, FIELD ## _elements, 0, \ - offsetof(STRUCT, FIELD ## _offset) } -#define E_SINGLE_MASTER(ID, TYPE, STRUCT, FIELD) \ - { #ID, ID, TYPE, offsetof(STRUCT, FIELD), DESC_FLAG_NONE, FIELD ## _elements, 0, 0 } -#define E_SUSPEND(ID, TYPE) \ - { #ID, ID, TYPE, 0, DESC_FLAG_SUSPEND, NULL, 0, 0 } -#define E_LAST \ - { NULL, 0, 0, 0, DESC_FLAG_NONE, NULL, 0, 0 } - -/* EBML Element Lists */ -static struct ebml_element_desc ebml_elements[] = { - E_FIELD(ID_EBML_VERSION, TYPE_UINT, struct ebml, ebml_version), - E_FIELD(ID_EBML_READ_VERSION, TYPE_UINT, struct ebml, ebml_read_version), - E_FIELD(ID_EBML_MAX_ID_LENGTH, TYPE_UINT, struct ebml, ebml_max_id_length), - E_FIELD(ID_EBML_MAX_SIZE_LENGTH, TYPE_UINT, struct ebml, ebml_max_size_length), - E_FIELD(ID_DOCTYPE, TYPE_STRING, struct ebml, doctype), - E_FIELD(ID_DOCTYPE_VERSION, TYPE_UINT, struct ebml, doctype_version), - E_FIELD(ID_DOCTYPE_READ_VERSION, TYPE_UINT, struct ebml, doctype_read_version), - E_LAST -}; - -/* WebMedia Element Lists */ -static struct ebml_element_desc seek_elements[] = { - E_FIELD(ID_SEEK_ID, TYPE_BINARY, struct seek, id), - E_FIELD(ID_SEEK_POSITION, TYPE_UINT, struct seek, position), - E_LAST -}; - -static struct ebml_element_desc seek_head_elements[] = { - E_MASTER(ID_SEEK, TYPE_MASTER, struct seek_head, seek), - E_LAST -}; - -static struct ebml_element_desc info_elements[] = { - E_FIELD(ID_TIMECODE_SCALE, TYPE_UINT, struct info, timecode_scale), - E_FIELD(ID_DURATION, TYPE_FLOAT, struct info, duration), - E_LAST -}; - -static struct ebml_element_desc block_group_elements[] = { - E_SUSPEND(ID_BLOCK, TYPE_BINARY), - E_FIELD(ID_BLOCK_DURATION, TYPE_UINT, struct block_group, duration), - E_FIELD(ID_REFERENCE_BLOCK, TYPE_INT, struct block_group, reference_block), - E_LAST -}; - -static struct ebml_element_desc cluster_elements[] = { - E_FIELD(ID_TIMECODE, TYPE_UINT, struct cluster, timecode), - E_MASTER(ID_BLOCK_GROUP, TYPE_MASTER, struct cluster, block_group), - E_SUSPEND(ID_SIMPLE_BLOCK, TYPE_BINARY), - E_LAST -}; - -static struct ebml_element_desc video_elements[] = { - E_FIELD(ID_PIXEL_WIDTH, TYPE_UINT, struct video, pixel_width), - E_FIELD(ID_PIXEL_HEIGHT, TYPE_UINT, struct video, pixel_height), - E_FIELD(ID_PIXEL_CROP_BOTTOM, TYPE_UINT, struct video, pixel_crop_bottom), - E_FIELD(ID_PIXEL_CROP_TOP, TYPE_UINT, struct video, pixel_crop_top), - E_FIELD(ID_PIXEL_CROP_LEFT, TYPE_UINT, struct video, pixel_crop_left), - E_FIELD(ID_PIXEL_CROP_RIGHT, TYPE_UINT, struct video, pixel_crop_right), - E_FIELD(ID_DISPLAY_WIDTH, TYPE_UINT, struct video, display_width), - E_FIELD(ID_DISPLAY_HEIGHT, TYPE_UINT, struct video, display_height), - E_LAST -}; - -static struct ebml_element_desc audio_elements[] = { - E_FIELD(ID_SAMPLING_FREQUENCY, TYPE_FLOAT, struct audio, sampling_frequency), - E_FIELD(ID_CHANNELS, TYPE_UINT, struct audio, channels), - E_FIELD(ID_BIT_DEPTH, TYPE_UINT, struct audio, bit_depth), - E_LAST -}; - -static struct ebml_element_desc track_entry_elements[] = { - E_FIELD(ID_TRACK_NUMBER, TYPE_UINT, struct track_entry, number), - E_FIELD(ID_TRACK_UID, TYPE_UINT, struct track_entry, uid), - E_FIELD(ID_TRACK_TYPE, TYPE_UINT, struct track_entry, type), - E_FIELD(ID_FLAG_ENABLED, TYPE_UINT, struct track_entry, flag_enabled), - E_FIELD(ID_FLAG_DEFAULT, TYPE_UINT, struct track_entry, flag_default), - E_FIELD(ID_FLAG_LACING, TYPE_UINT, struct track_entry, flag_lacing), - E_FIELD(ID_TRACK_TIMECODE_SCALE, TYPE_FLOAT, struct track_entry, track_timecode_scale), - E_FIELD(ID_LANGUAGE, TYPE_STRING, struct track_entry, language), - E_FIELD(ID_CODEC_ID, TYPE_STRING, struct track_entry, codec_id), - E_FIELD(ID_CODEC_PRIVATE, TYPE_BINARY, struct track_entry, codec_private), - E_SINGLE_MASTER(ID_VIDEO, TYPE_MASTER, struct track_entry, video), - E_SINGLE_MASTER(ID_AUDIO, TYPE_MASTER, struct track_entry, audio), - E_LAST -}; - -static struct ebml_element_desc tracks_elements[] = { - E_MASTER(ID_TRACK_ENTRY, TYPE_MASTER, struct tracks, track_entry), - E_LAST -}; - -static struct ebml_element_desc cue_track_positions_elements[] = { - E_FIELD(ID_CUE_TRACK, TYPE_UINT, struct cue_track_positions, track), - E_FIELD(ID_CUE_CLUSTER_POSITION, TYPE_UINT, struct cue_track_positions, cluster_position), - E_FIELD(ID_CUE_BLOCK_NUMBER, TYPE_UINT, struct cue_track_positions, block_number), - E_LAST -}; - -static struct ebml_element_desc cue_point_elements[] = { - E_FIELD(ID_CUE_TIME, TYPE_UINT, struct cue_point, time), - E_MASTER(ID_CUE_TRACK_POSITIONS, TYPE_MASTER, struct cue_point, cue_track_positions), - E_LAST -}; - -static struct ebml_element_desc cues_elements[] = { - E_MASTER(ID_CUE_POINT, TYPE_MASTER, struct cues, cue_point), - E_LAST -}; - -static struct ebml_element_desc segment_elements[] = { - E_MASTER(ID_SEEK_HEAD, TYPE_MASTER, struct segment, seek_head), - E_SINGLE_MASTER(ID_INFO, TYPE_MASTER, struct segment, info), - E_MASTER(ID_CLUSTER, TYPE_MASTER, struct segment, cluster), - E_SINGLE_MASTER(ID_TRACKS, TYPE_MASTER, struct segment, tracks), - E_SINGLE_MASTER(ID_CUES, TYPE_MASTER, struct segment, cues), - E_LAST -}; - -static struct ebml_element_desc top_level_elements[] = { - E_SINGLE_MASTER(ID_EBML, TYPE_MASTER, nestegg, ebml), - E_SINGLE_MASTER_O(ID_SEGMENT, TYPE_MASTER, nestegg, segment), - E_LAST -}; - -#undef E_FIELD -#undef E_MASTER -#undef E_SINGLE_MASTER_O -#undef E_SINGLE_MASTER -#undef E_SUSPEND -#undef E_LAST - -static struct pool_ctx * -pool_init(void) -{ - struct pool_ctx * pool; - - pool = h_malloc(sizeof(*pool)); - if (!pool) - abort(); - return pool; -} - -static void -pool_destroy(struct pool_ctx * pool) -{ - h_free(pool); -} - -static void * -pool_alloc(size_t size, struct pool_ctx * pool) -{ - void * p; - - p = h_malloc(size); - if (!p) - abort(); - hattach(p, pool); - memset(p, 0, size); - return p; -} - -#if 0 -static void -pool_free(void * p) -{ - h_free(p); -} -#endif - -static void * -alloc(size_t size) -{ - void * p; - - p = calloc(1, size); - if (!p) - abort(); - return p; -} - -static int -io_read(nestegg_io * io, void * buffer, size_t length) -{ - return io->read(buffer, length, io->userdata); -} - -static int -io_seek(nestegg_io * io, int64_t offset, int whence) -{ - return io->seek(offset, whence, io->userdata); -} - -static int64_t -io_tell(nestegg_io * io) -{ - return io->tell(io->userdata); -} - -static int -bare_read_vint(nestegg_io * io, uint64_t * value, uint64_t * length, enum vint_mask maskflag) -{ - int r; - unsigned char b; - size_t maxlen = 8; - unsigned int count = 1, mask = 1 << 7; - - r = io_read(io, &b, 1); - if (r != 1) - return r; - - while (count < maxlen) { - if ((b & mask) != 0) - break; - mask >>= 1; - count += 1; - } - - if (length) - *length = count; - *value = b; - - if (maskflag == MASK_FIRST_BIT) { - *value = b & ~mask; - } - - while (--count) { - r = io_read(io, &b, 1); - if (r != 1) - return r; - *value <<= 8; - *value |= b; - } - - return 1; -} - -static int -read_id(nestegg_io * io, uint64_t * value, uint64_t * length) -{ - return bare_read_vint(io, value, length, MASK_NONE); -} - -static int -read_vint(nestegg_io * io, uint64_t * value, uint64_t * length) -{ - return bare_read_vint(io, value, length, MASK_FIRST_BIT); -} - -static int -read_svint(nestegg_io * io, int64_t * value, uint64_t * length) -{ - int r; - uint64_t uvalue; - uint64_t ulength; - int64_t svint_subtr[] = { - 0x3f, 0x1fff, - 0xfffff, 0x7ffffff, - 0x3ffffffffLL, 0x1ffffffffffLL, - 0xffffffffffffLL, 0x7fffffffffffffLL - }; - - r = bare_read_vint(io, &uvalue, &ulength, MASK_FIRST_BIT); - if (r != 1) - return r; - *value = uvalue - svint_subtr[ulength - 1]; - if (length) - *length = ulength; - return r; -} - -static int -read_uint(nestegg_io * io, uint64_t * val, uint64_t length) -{ - unsigned char b; - int r; - - if (length == 0 || length > 8) - return -1; - r = io_read(io, &b, 1); - if (r != 1) - return r; - *val = b; - while (--length) { - r = io_read(io, &b, 1); - if (r != 1) - return r; - *val <<= 8; - *val |= b; - } - return 1; -} - -static int -read_int(nestegg_io * io, int64_t * val, uint64_t length) -{ - int r; - uint64_t uval, base; - - r = read_uint(io, &uval, length); - if (r != 1) - return r; - - if (length < sizeof(int64_t)) { - base = 1; - base <<= length * 8 - 1; - if (uval >= base) { - base = 1; - base <<= length * 8; - } else { - base = 0; - } - *val = uval - base; - } else { - *val = (int64_t) uval; - } - - return 1; -} - -static int -read_float(nestegg_io * io, double * val, uint64_t length) -{ - union { - uint64_t u; - float f; - double d; - } value; - int r; - - /* length == 10 not implemented */ - if (length != 4 && length != 8) - return -1; - r = read_uint(io, &value.u, length); - if (r != 1) - return r; - if (length == 4) - *val = value.f; - else - *val = value.d; - return 1; -} - -static int -read_string(nestegg * ctx, char ** val, uint64_t length) -{ - char * str; - int r; - - if (length == 0 || length > LIMIT_STRING) - return -1; - str = pool_alloc(length + 1, ctx->alloc_pool); - r = io_read(ctx->io, (unsigned char *) str, length); - if (r != 1) - return r; - str[length] = '\0'; - *val = str; - return 1; -} - -static int -read_binary(nestegg * ctx, struct ebml_binary * val, uint64_t length) -{ - if (length == 0 || length > LIMIT_BINARY) - return -1; - val->data = pool_alloc(length, ctx->alloc_pool); - val->length = length; - return io_read(ctx->io, val->data, length); -} - -static int -get_uint(struct ebml_type type, uint64_t * value) -{ - if (!type.read) - return -1; - - assert(type.type == TYPE_UINT); - - *value = type.v.u; - - return 0; -} - -static int -get_float(struct ebml_type type, double * value) -{ - if (!type.read) - return -1; - - assert(type.type == TYPE_FLOAT); - - *value = type.v.f; - - return 0; -} - -#if 0 -static int -get_int(struct ebml_type type, int64_t * value) -{ - if (!type.read) - return -1; - - assert(type.type == TYPE_INT); - - *value = type.v.i; - - return 0; -} -#endif - -static int -get_string(struct ebml_type type, char ** value) -{ - if (!type.read) - return -1; - - assert(type.type == TYPE_STRING); - - *value = type.v.s; - - return 0; -} - -static int -get_binary(struct ebml_type type, struct ebml_binary * value) -{ - if (!type.read) - return -1; - - assert(type.type == TYPE_BINARY); - - *value = type.v.b; - - return 0; -} - -static int -is_ancestor_element(uint64_t id, struct list_node * ancestor) -{ - struct ebml_element_desc * element; - - for (; ancestor; ancestor = ancestor->previous) - for (element = ancestor->node; element->id; ++element) - if (element->id == id) - return 1; - - return 0; -} - -static struct ebml_element_desc * -find_element(uint64_t id, struct ebml_element_desc * elements) -{ - struct ebml_element_desc * element; - - for (element = elements; element->id; ++element) - if (element->id == id) - return element; - - return NULL; -} - -static void -ctx_push(nestegg * ctx, struct ebml_element_desc * ancestor, void * data) -{ - struct list_node * item; - - item = alloc(sizeof(*item)); - item->previous = ctx->ancestor; - item->node = ancestor; - item->data = data; - ctx->ancestor = item; -} - -static void -ctx_pop(nestegg * ctx) -{ - struct list_node * item; - - item = ctx->ancestor; - ctx->ancestor = item->previous; - free(item); -} - -static int -ctx_save(nestegg * ctx, struct saved_state * s) -{ - s->stream_offset = io_tell(ctx->io); - if (s->stream_offset < 0) - return -1; - s->ancestor = ctx->ancestor; - s->last_id = ctx->last_id; - s->last_size = ctx->last_size; - return 0; -} - -static int -ctx_restore(nestegg * ctx, struct saved_state * s) -{ - int r; - - r = io_seek(ctx->io, s->stream_offset, NESTEGG_SEEK_SET); - if (r != 0) - return -1; - ctx->ancestor = s->ancestor; - ctx->last_id = s->last_id; - ctx->last_size = s->last_size; - return 0; -} - -static int -peek_element(nestegg * ctx, uint64_t * id, uint64_t * size) -{ - int r; - - if (ctx->last_id && ctx->last_size) { - if (id) - *id = ctx->last_id; - if (size) - *size = ctx->last_size; - return 1; - } - - r = read_id(ctx->io, &ctx->last_id, NULL); - if (r != 1) - return r; - - r = read_vint(ctx->io, &ctx->last_size, NULL); - if (r != 1) - return r; - - if (id) - *id = ctx->last_id; - if (size) - *size = ctx->last_size; - - return 1; -} - -static int -read_element(nestegg * ctx, uint64_t * id, uint64_t * size) -{ - int r; - - r = peek_element(ctx, id, size); - if (r != 1) - return r; - - ctx->last_id = 0; - ctx->last_size = 0; - - return 1; -} - -static int -read_master(nestegg * ctx, struct ebml_element_desc * desc) -{ - struct ebml_list * list; - struct ebml_list_node * node, * oldtail; - - assert(desc->type == TYPE_MASTER && desc->flags & DESC_FLAG_MULTI); - - ctx->log(ctx, NESTEGG_LOG_DEBUG, "multi master element %llx (%s)", - desc->id, desc->name); - - list = (struct ebml_list *) (ctx->ancestor->data + desc->offset); - - node = pool_alloc(sizeof(*node), ctx->alloc_pool); - node->id = desc->id; - node->data = pool_alloc(desc->size, ctx->alloc_pool); - - oldtail = list->tail; - if (oldtail) - oldtail->next = node; - list->tail = node; - if (!list->head) - list->head = node; - - ctx->log(ctx, NESTEGG_LOG_DEBUG, " -> using data %p", node->data); - - ctx_push(ctx, desc->children, node->data); - - return 1; -} - -static int -read_single_master(nestegg * ctx, struct ebml_element_desc * desc) -{ - assert(desc->type == TYPE_MASTER && !(desc->flags & DESC_FLAG_MULTI)); - - ctx->log(ctx, NESTEGG_LOG_DEBUG, "single master element %llx (%s)", - desc->id, desc->name); - ctx->log(ctx, NESTEGG_LOG_DEBUG, " -> using data %p (%u)", - ctx->ancestor->data + desc->offset, desc->offset); - - ctx_push(ctx, desc->children, ctx->ancestor->data + desc->offset); - - return 1; -} - -static int -read_simple(nestegg * ctx, struct ebml_element_desc * desc, size_t length) -{ - struct ebml_type * storage; - int r; - - storage = (struct ebml_type *) (ctx->ancestor->data + desc->offset); - - if (storage->read) - return -1; - - storage->type = desc->type; - - ctx->log(ctx, NESTEGG_LOG_DEBUG, "element %llx (%s) -> %p (%u)", - desc->id, desc->name, storage, desc->offset); - - r = -1; - - switch (desc->type) { - case TYPE_UINT: - r = read_uint(ctx->io, &storage->v.u, length); - break; - case TYPE_FLOAT: - r = read_float(ctx->io, &storage->v.f, length); - break; - case TYPE_INT: - r = read_int(ctx->io, &storage->v.i, length); - break; - case TYPE_STRING: - r = read_string(ctx, &storage->v.s, length); - break; - case TYPE_BINARY: - r = read_binary(ctx, &storage->v.b, length); - break; - case TYPE_MASTER: - case TYPE_UNKNOWN: - assert(0); - break; - } - - if (r == 1) - storage->read = 1; - - return r; -} - -static int -parse(nestegg * ctx, struct ebml_element_desc * top_level) -{ - int r; - int64_t * data_offset; - uint64_t id, size; - struct ebml_element_desc * element; - - /* loop until we need to return: - - hit suspend point - - parse complete - - error occurred */ - - /* loop over elements at current level reading them if sublevel found, - push ctx onto stack and continue if sublevel ended, pop ctx off stack - and continue */ - - for (;;) { - r = peek_element(ctx, &id, &size); - if (r != 1) - break; - - element = find_element(id, ctx->ancestor->node); - if (element) { - if (element->flags & DESC_FLAG_SUSPEND) { - assert(element->type == TYPE_BINARY); - ctx->log(ctx, NESTEGG_LOG_DEBUG, "suspend parse at %llx", id); - r = 1; - break; - } - - r = read_element(ctx, &id, &size); - if (r != 1) - break; - - if (element->flags & DESC_FLAG_OFFSET) { - data_offset = (int64_t *) (ctx->ancestor->data + element->data_offset); - *data_offset = io_tell(ctx->io); - if (*data_offset < 0) - return -1; - } - - if (element->type == TYPE_MASTER) { - if (element->flags & DESC_FLAG_MULTI) { - r = read_master(ctx, element); - } else { - r = read_single_master(ctx, element); - } - continue; - } else { - r = read_simple(ctx, element, size); - } - } else if (is_ancestor_element(id, ctx->ancestor->previous)) { - ctx->log(ctx, NESTEGG_LOG_DEBUG, "parent element %llx", id); - if (top_level && ctx->ancestor->node == top_level) { - ctx->log(ctx, NESTEGG_LOG_DEBUG, "*** parse about to back up past top_level"); - r = 1; - break; - } - ctx_pop(ctx); - } else { - r = read_element(ctx, &id, &size); - if (r != 1) - break; - - if (id != ID_VOID && id != ID_CRC32) - ctx->log(ctx, NESTEGG_LOG_DEBUG, "unknown element %llx", id); - r = io_seek(ctx->io, size, NESTEGG_SEEK_CUR); - if (r != 0) - return -1; - } - } - - if (r != 1) { - while(ctx->ancestor) - ctx_pop(ctx); - } - - return r; -} - -static uint64_t -xiph_lace_value(unsigned char ** np) -{ - uint64_t lace; - uint64_t value; - unsigned char * p = *np; - - lace = *p++; - value = lace; - while (lace == 255) { - lace = *p++; - value += lace; - } - - *np = p; - - return value; -} - -static int -read_xiph_lace_value(nestegg_io * io, uint64_t * value, size_t * consumed) -{ - int r; - uint64_t lace; - - r = read_uint(io, &lace, 1); - if (r != 1) - return r; - *consumed += 1; - - *value = lace; - while (lace == 255) { - r = read_uint(io, &lace, 1); - if (r != 1) - return r; - *consumed += 1; - *value += lace; - } - - return 1; -} - -static int -read_xiph_lacing(nestegg_io * io, size_t block, size_t * read, uint64_t n, uint64_t * sizes) -{ - int r; - size_t i = 0; - uint64_t sum = 0; - - while (--n) { - r = read_xiph_lace_value(io, &sizes[i], read); - if (r != 1) - return r; - sum += sizes[i]; - i += 1; - } - - if (*read + sum > block) - return -1; - - /* last frame is the remainder of the block */ - sizes[i] = block - *read - sum; - return 1; -} - -static int -read_ebml_lacing(nestegg_io * io, size_t block, size_t * read, uint64_t n, uint64_t * sizes) -{ - int r; - uint64_t lace, sum, length; - int64_t slace; - size_t i = 0; - - r = read_vint(io, &lace, &length); - if (r != 1) - return r; - *read += length; - - sizes[i] = lace; - sum = sizes[i]; - - i += 1; - n -= 1; - - while (--n) { - r = read_svint(io, &slace, &length); - if (r != 1) - return r; - *read += length; - sizes[i] = sizes[i - 1] + slace; - sum += sizes[i]; - i += 1; - } - - if (*read + sum > block) - return -1; - - /* last frame is the remainder of the block */ - sizes[i] = block - *read - sum; - return 1; -} - -static uint64_t -get_timecode_scale(nestegg * ctx) -{ - uint64_t scale; - - if (get_uint(ctx->segment.info.timecode_scale, &scale) != 0) - scale = 1000000; - - return scale; -} - -static struct track_entry * -find_track_entry(nestegg * ctx, unsigned int track) -{ - struct ebml_list_node * node; - unsigned int tracks = 0; - - node = ctx->segment.tracks.track_entry.head; - while (node) { - assert(node->id == ID_TRACK_ENTRY); - if (track == tracks) { - return node->data; - } - tracks += 1; - node = node->next; - } - - return NULL; -} - -static int -read_block(nestegg * ctx, uint64_t block_id, uint64_t block_size, nestegg_packet ** data) -{ - int r; - int64_t timecode, abs_timecode; - nestegg_packet * pkt; - struct cluster * cluster; - struct frame * f, * last; - struct track_entry * entry; - double track_scale; - uint64_t track, length, frame_sizes[256], cluster_tc, flags, frames, tc_scale, total; - unsigned int i, lacing; - size_t consumed = 0; - - *data = NULL; - - if (block_size > LIMIT_BLOCK) - return -1; - - r = read_vint(ctx->io, &track, &length); - if (r != 1) - return r; - - if (track == 0 || track > ctx->track_count) - return -1; - - consumed += length; - - r = read_int(ctx->io, &timecode, 2); - if (r != 1) - return r; - - consumed += 2; - - r = read_uint(ctx->io, &flags, 1); - if (r != 1) - return r; - - consumed += 1; - - frames = 0; - - /* flags are different between block and simpleblock, but lacing is - encoded the same way */ - lacing = (flags & 0x6) >> 1; - - switch (lacing) { - case LACING_NONE: - frames = 1; - break; - case LACING_XIPH: - case LACING_FIXED: - case LACING_EBML: - r = read_uint(ctx->io, &frames, 1); - if (r != 1) - return r; - consumed += 1; - frames += 1; - } - - if (frames > 256) - return -1; - - switch (lacing) { - case LACING_NONE: - frame_sizes[0] = block_size - consumed; - break; - case LACING_XIPH: - if (frames == 1) - return -1; - r = read_xiph_lacing(ctx->io, block_size, &consumed, frames, frame_sizes); - if (r != 1) - return r; - break; - case LACING_FIXED: - if ((block_size - consumed) % frames) - return -1; - for (i = 0; i < frames; ++i) { - frame_sizes[i] = (block_size - consumed) / frames; - } - break; - case LACING_EBML: - if (frames == 1) - return -1; - r = read_ebml_lacing(ctx->io, block_size, &consumed, frames, frame_sizes); - if (r != 1) - return r; - break; - } - - /* sanity check unlaced frame sizes against total block size. */ - total = consumed; - for (i = 0; i < frames; ++i) { - total += frame_sizes[i]; - } - if (total > block_size) - return -1; - - entry = find_track_entry(ctx, track - 1); - if (!entry) - return -1; - - track_scale = 1.0; - get_float(entry->track_timecode_scale, &track_scale); - - tc_scale = get_timecode_scale(ctx); - - assert(ctx->segment.cluster.tail->id == ID_CLUSTER); - cluster = ctx->segment.cluster.tail->data; - if (get_uint(cluster->timecode, &cluster_tc) != 0) - return -1; - - abs_timecode = timecode + cluster_tc; - if (abs_timecode < 0) - return -1; - - pkt = alloc(sizeof(*pkt)); - pkt->track = track - 1; - pkt->timecode = abs_timecode * tc_scale * track_scale; - - ctx->log(ctx, NESTEGG_LOG_DEBUG, "%sblock t %lld pts %f f %llx frames: %llu", - block_id == ID_BLOCK ? "" : "simple", pkt->track, pkt->timecode / 1e9, flags, frames); - - last = NULL; - for (i = 0; i < frames; ++i) { - if (frame_sizes[i] > LIMIT_FRAME) { - nestegg_free_packet(pkt); - return -1; - } - f = alloc(sizeof(*f)); - f->data = alloc(frame_sizes[i]); - f->length = frame_sizes[i]; - r = io_read(ctx->io, f->data, frame_sizes[i]); - if (r != 1) { - free(f->data); - free(f); - nestegg_free_packet(pkt); - return -1; - } - - if (!last) { - pkt->frame = f; - } else { - last->next = f; - } - last = f; - } - - *data = pkt; - - return 1; -} - -static uint64_t -buf_read_id(unsigned char const * p, size_t length) -{ - uint64_t id = 0; - - while (length--) { - id <<= 8; - id |= *p++; - } - - return id; -} - -static struct seek * -find_seek_for_id(struct ebml_list_node * seek_head, uint64_t id) -{ - struct ebml_list * head; - struct ebml_list_node * seek; - struct ebml_binary binary_id; - struct seek * s; - - while (seek_head) { - assert(seek_head->id == ID_SEEK_HEAD); - head = seek_head->data; - seek = head->head; - - while (seek) { - assert(seek->id == ID_SEEK); - s = seek->data; - - if (get_binary(s->id, &binary_id) == 0 && - buf_read_id(binary_id.data, binary_id.length) == id) { - return s; - } - - seek = seek->next; - } - - seek_head = seek_head->next; - } - - return NULL; -} - -static struct cue_point * -find_cue_point_for_tstamp(struct ebml_list_node * cue_point, uint64_t scale, uint64_t tstamp) -{ - uint64_t time; - struct cue_point *c, * prev = NULL; - - while (cue_point) { - assert(cue_point->id == ID_CUE_POINT); - c = cue_point->data; - - if (!prev) - prev = c; - - if (get_uint(c->time, &time) == 0 && - (time * scale > tstamp)) - return prev; - - prev = cue_point->data; - cue_point = cue_point->next; - } - - return NULL; -} - -static int -is_suspend_element(uint64_t id) -{ - /* this could search the tree of elements for DESC_FLAG_SUSPEND */ - if (id == ID_SIMPLE_BLOCK || id == ID_BLOCK) - return 1; - return 0; -} - -static void -null_log_callback(nestegg * ctx, unsigned int severity, char const * fmt, ...) -{ - if (ctx && severity && fmt) - return; -} - -int -nestegg_init(nestegg ** context, nestegg_io io, nestegg_log callback) -{ - int r; - uint64_t id, version; - struct ebml_list_node * track; - char * doctype; - nestegg * ctx = NULL; - - if (!(io.read && io.seek && io.tell)) - return -1; - - ctx = alloc(sizeof(*ctx)); - - ctx->io = alloc(sizeof(*ctx->io)); - *ctx->io = io; - ctx->log = callback; - ctx->alloc_pool = pool_init(); - - if (!ctx->log) - ctx->log = null_log_callback; - - r = peek_element(ctx, &id, NULL); - if (r != 1) { - nestegg_destroy(ctx); - return -1; - } - - if (id != ID_EBML) { - nestegg_destroy(ctx); - return -1; - } - - ctx->log(ctx, NESTEGG_LOG_DEBUG, "ctx %p", ctx); - - ctx_push(ctx, top_level_elements, ctx); - - r = parse(ctx, NULL); - - if (r != 1) { - nestegg_destroy(ctx); - return -1; - } - - /* XXX youtube hack: accept webm and matroska for now */ - if (get_string(ctx->ebml.doctype, &doctype) == 0 && - (strcmp(doctype, "webm") == 0 || - strcmp(doctype, "matroska") == 0) && - get_uint(ctx->ebml.doctype_read_version, &version) == 0 && version <= 2 && - get_uint(ctx->ebml.ebml_read_version, &version) == 0 && version <= 1 && - !ctx->segment.tracks.track_entry.head) { - nestegg_destroy(ctx); - return -1; - } - - track = ctx->segment.tracks.track_entry.head; - ctx->track_count = 0; - - while (track) { - ctx->track_count += 1; - track = track->next; - } - - *context = ctx; - - return 0; -} - -void -nestegg_destroy(nestegg * ctx) -{ - while (ctx->ancestor) - ctx_pop(ctx); - pool_destroy(ctx->alloc_pool); - free(ctx->io); - free(ctx); -} - -int -nestegg_duration(nestegg * ctx, uint64_t * duration) -{ - uint64_t tc_scale; - double unscaled_duration; - - if (get_float(ctx->segment.info.duration, &unscaled_duration) != 0) - return -1; - - tc_scale = get_timecode_scale(ctx); - - *duration = (uint64_t) (unscaled_duration * tc_scale); - return 0; -} - -int -nestegg_track_count(nestegg * ctx, unsigned int * tracks) -{ - *tracks = ctx->track_count; - return 0; -} - -int -nestegg_track_seek(nestegg * ctx, unsigned int track, uint64_t tstamp) -{ - int r; - struct cue_point * cue_point; - struct cue_track_positions * pos; - struct saved_state state; - struct seek * found; - uint64_t seek_pos, tc_scale, t, id; - struct ebml_list_node * node = ctx->segment.cues.cue_point.head; - - /* If there are no cues loaded, check for cues element in the seek head - and load it. */ - if (!node) { - found = find_seek_for_id(ctx->segment.seek_head.head, ID_CUES); - if (!found) - return -1; - - if (get_uint(found->position, &seek_pos) != 0) - return -1; - - /* Save old parser state. */ - r = ctx_save(ctx, &state); - if (r != 0) - return -1; - - /* Seek and set up parser state for segment-level element (Cues). */ - r = io_seek(ctx->io, ctx->segment_offset + seek_pos, NESTEGG_SEEK_SET); - if (r != 0) - return -1; - ctx->last_id = 0; - ctx->last_size = 0; - - r = read_element(ctx, &id, NULL); - if (r != 1) - return -1; - - if (id != ID_CUES) - return -1; - - ctx->ancestor = NULL; - ctx_push(ctx, top_level_elements, ctx); - ctx_push(ctx, segment_elements, &ctx->segment); - ctx_push(ctx, cues_elements, &ctx->segment.cues); - /* parser will run until end of cues element. */ - ctx->log(ctx, NESTEGG_LOG_DEBUG, "seek: parsing cue elements"); - r = parse(ctx, cues_elements); - while (ctx->ancestor) - ctx_pop(ctx); - - /* Reset parser state to original state and seek back to old position. */ - r = ctx_restore(ctx, &state); - if (r != 0) - return -1; - } - - tc_scale = get_timecode_scale(ctx); - - cue_point = find_cue_point_for_tstamp(ctx->segment.cues.cue_point.head, tc_scale, tstamp); - if (!cue_point) - return -1; - - node = cue_point->cue_track_positions.head; - - seek_pos = 0; - - while (node) { - assert(node->id == ID_CUE_TRACK_POSITIONS); - pos = node->data; - if (get_uint(pos->track, &t) == 0 && t - 1 == track) { - if (get_uint(pos->cluster_position, &seek_pos) != 0) - return -1; - break; - } - node = node->next; - } - - /* Seek and set up parser state for segment-level element (Cluster). */ - r = io_seek(ctx->io, ctx->segment_offset + seek_pos, NESTEGG_SEEK_SET); - if (r != 0) - return -1; - ctx->last_id = 0; - ctx->last_size = 0; - - while (ctx->ancestor) - ctx_pop(ctx); - - ctx_push(ctx, top_level_elements, ctx); - ctx_push(ctx, segment_elements, &ctx->segment); - ctx->log(ctx, NESTEGG_LOG_DEBUG, "seek: parsing cluster elements"); - r = parse(ctx, NULL); - if (r != 1) - return -1; - - if (!is_suspend_element(ctx->last_id)) - return -1; - - return 0; -} - -int -nestegg_track_type(nestegg * ctx, unsigned int track) -{ - struct track_entry * entry; - uint64_t type; - - entry = find_track_entry(ctx, track); - if (!entry) - return -1; - - if (get_uint(entry->type, &type) != 0) - return -1; - - if (type & 0x1) - return NESTEGG_TRACK_VIDEO; - - if (type & 0x2) - return NESTEGG_TRACK_AUDIO; - - return -1; -} - -struct bitmapinfoheader { - int size; - int width; - int height; - short planes; - short bit_count; - unsigned int compression; - int size_image; - int x_pels_per_meter; - int y_pels_per_meter; - int clr_used; - int clr_important; -}; - -int -nestegg_track_codec_id(nestegg * ctx, unsigned int track) -{ - char * codec_id; - struct ebml_binary codec_private; - struct track_entry * entry; - - entry = find_track_entry(ctx, track); - if (!entry) - return -1; - - if (get_string(entry->codec_id, &codec_id) != 0) - return -1; - - if (strcmp(codec_id, "V_VP8") == 0) - return NESTEGG_CODEC_VP8; - - if (strcmp(codec_id, "A_VORBIS") == 0) - return NESTEGG_CODEC_VORBIS; - - /* XXX youtube hack: accept VFW codec id for now */ - if (strcmp(codec_id, "V_MS/VFW/FOURCC") == 0 && - get_binary(entry->codec_private, &codec_private) == 0 && - codec_private.length >= 40) { - struct bitmapinfoheader * bih = (struct bitmapinfoheader *) codec_private.data; - if (bih->compression == 0x30385056) - return NESTEGG_CODEC_VP8; - } - - return -1; -} - -int -nestegg_track_codec_data_count(nestegg * ctx, unsigned int track, - unsigned int * count) -{ - struct track_entry * entry; - struct ebml_binary codec_private; - unsigned char * p; - - *count = 0; - - entry = find_track_entry(ctx, track); - if (!entry) - return -1; - - if (nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_VORBIS) - return -1; - - if (get_binary(entry->codec_private, &codec_private) != 0) - return -1; - - if (codec_private.length < 1) - return -1; - - p = codec_private.data; - *count = *p + 1; - - if (*count > 3) - return -1; - - return 0; -} - -int -nestegg_track_codec_data(nestegg * ctx, unsigned int track, unsigned int item, - unsigned char ** data, size_t * length) -{ - struct track_entry * entry; - struct ebml_binary codec_private; - uint64_t sizes[3], total; - unsigned char * p; - unsigned int count, i; - - *data = NULL; - *length = 0; - - entry = find_track_entry(ctx, track); - if (!entry) - return -1; - - if (nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_VORBIS) - return -1; - - if (get_binary(entry->codec_private, &codec_private) != 0) - return -1; - - p = codec_private.data; - count = *p++ + 1; - - if (count > 3) - return -1; - - i = 0; - total = 0; - while (--count) { - sizes[i] = xiph_lace_value(&p); - total += sizes[i]; - i += 1; - } - sizes[i] = codec_private.length - total - (p - codec_private.data); - - for (i = 0; i < item; ++i) { - if (sizes[i] > LIMIT_FRAME) - return -1; - p += sizes[i]; - } - *data = p; - *length = sizes[item]; - - return 0; -} - -int -nestegg_track_video_params(nestegg * ctx, unsigned int track, - nestegg_video_params * params) -{ - struct track_entry * entry; - uint64_t value; - - memset(params, 0, sizeof(*params)); - - entry = find_track_entry(ctx, track); - if (!entry) - return -1; - - if (nestegg_track_type(ctx, track) != NESTEGG_TRACK_VIDEO) - return -1; - - if (get_uint(entry->video.pixel_width, &value) != 0) - return -1; - params->width = value; - - if (get_uint(entry->video.pixel_height, &value) != 0) - return -1; - params->height = value; - - value = 0; - get_uint(entry->video.pixel_crop_bottom, &value); - params->crop_bottom = value; - - value = 0; - get_uint(entry->video.pixel_crop_top, &value); - params->crop_top = value; - - value = 0; - get_uint(entry->video.pixel_crop_left, &value); - params->crop_left = value; - - value = 0; - get_uint(entry->video.pixel_crop_right, &value); - params->crop_right = value; - - value = params->width; - get_uint(entry->video.display_width, &value); - params->display_width = value; - - value = params->height; - get_uint(entry->video.display_height, &value); - params->display_height = value; - - return 0; -} - -int -nestegg_track_audio_params(nestegg * ctx, unsigned int track, - nestegg_audio_params * params) -{ - struct track_entry * entry; - uint64_t value; - - memset(params, 0, sizeof(*params)); - - entry = find_track_entry(ctx, track); - if (!entry) - return -1; - - if (nestegg_track_type(ctx, track) != NESTEGG_TRACK_AUDIO) - return -1; - - params->rate = 8000; - get_float(entry->audio.sampling_frequency, ¶ms->rate); - - value = 1; - get_uint(entry->audio.channels, &value); - params->channels = value; - - value = 16; - get_uint(entry->audio.bit_depth, &value); - params->depth = value; - - return 0; -} - -int -nestegg_read_packet(nestegg * ctx, nestegg_packet ** pkt) -{ - int r; - uint64_t id, size; - - *pkt = NULL; - - for (;;) { - r = peek_element(ctx, &id, &size); - if (r != 1) { - return r; - } - - /* any suspend fields must be handled here */ - if (is_suspend_element(id)) { - r = read_element(ctx, &id, &size); - if (r != 1) { - return r; - } - - /* the only suspend fields are blocks and simple blocks, which we - handle directly. */ - r = read_block(ctx, id, size, pkt); - return r; - } - - r = parse(ctx, NULL); - if (r != 1) - return r; - } - - return 1; -} - -void -nestegg_free_packet(nestegg_packet * pkt) -{ - struct frame * frame; - - while (pkt->frame) { - frame = pkt->frame; - pkt->frame = frame->next; - free(frame->data); - free(frame); - } - - free(pkt); -} - -int -nestegg_packet_track(nestegg_packet * pkt, unsigned int * track) -{ - *track = pkt->track; - return 0; -} - -int -nestegg_packet_tstamp(nestegg_packet * pkt, uint64_t * tstamp) -{ - *tstamp = pkt->timecode; - return 0; -} - -int -nestegg_packet_count(nestegg_packet * pkt, unsigned int * count) -{ - struct frame * f = pkt->frame; - - *count = 0; - - while (f) { - *count += 1; - f = f->next; - } - - return 0; -} - -int -nestegg_packet_data(nestegg_packet * pkt, unsigned int item, - unsigned char ** data, size_t * length) -{ - struct frame * f = pkt->frame; - unsigned int count = 0; - - *data = NULL; - *length = 0; - - while (f) { - if (count == item) { - *data = f->data; - *length = f->length; - return 0; - } - count += 1; - f = f->next; - } - - return -1; -} diff --git a/src/nestegg.h b/src/nestegg.h deleted file mode 100644 index 53e2147..0000000 --- a/src/nestegg.h +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright © 2010 Matthew Gregan - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#ifndef NESTEGG_671cac2a_365d_ed69_d7a3_4491d3538d79 -#define NESTEGG_671cac2a_365d_ed69_d7a3_4491d3538d79 - -#ifdef _WIN32 -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#else -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/** @mainpage - - @section intro Introduction - - This is the documentation fot the libnestegg C API. - libnestegg is a demultiplexing library for Matroska and WebMedia media files. - - @section example Example code - - @code - nestegg * demux_ctx; - nestegg_init(&demux_ctx, io, NULL); - - nestegg_packet * pkt; - while ((r = nestegg_read_packet(demux_ctx, &pkt)) > 0) { - unsigned int track; - - nestegg_packet_track(pkt, &track); - - // This example decodes the first track only. - if (track == 0) { - unsigned int chunk, chunks; - - nestegg_packet_count(pkt, &chunks); - - // Decode each chunk of data. - for (chunk = 0; chunk < chunks; ++chunk) { - unsigned char * data; - size_t data_size; - - nestegg_packet_data(pkt, chunk, &data, &data_size); - - example_codec_decode(codec_ctx, data, data_size); - } - } - - nestegg_free_packet(pkt); - } - - nestegg_destroy(demux_ctx); - @endcode -*/ - - -/** @file - The libnestegg C API. */ - -#define NESTEGG_TRACK_VIDEO 0 /**< Track is of type video. */ -#define NESTEGG_TRACK_AUDIO 1 /**< Track is of type audio. */ - -#define NESTEGG_CODEC_VP8 0 /**< Track uses Google On2 VP8 codec. */ -#define NESTEGG_CODEC_VORBIS 1 /**< Track uses Xiph Vorbis codec. */ - -#define NESTEGG_SEEK_SET 0 /**< Seek offset relative to beginning of stream. */ -#define NESTEGG_SEEK_CUR 1 /**< Seek offset relative to current position in stream. */ -#define NESTEGG_SEEK_END 2 /**< Seek offset relative to end of stream. */ - -#define NESTEGG_LOG_DEBUG 1 /**< Debug level log message. */ -#define NESTEGG_LOG_INFO 10 /**< Informational level log message. */ -#define NESTEGG_LOG_WARNING 100 /**< Warning level log message. */ -#define NESTEGG_LOG_ERROR 1000 /**< Error level log message. */ -#define NESTEGG_LOG_CRITICAL 10000 /**< Critical level log message. */ - -typedef struct nestegg nestegg; /**< Opaque handle referencing the stream state. */ -typedef struct nestegg_packet nestegg_packet; /**< Opaque handle referencing a packet of data. */ - -/** User supplied IO context. */ -typedef struct { - /** User supplied read callback. - @param buffer Buffer to read data into. - @param length Length of supplied buffer in bytes. - @param userptr The #userdata supplied by the user. - @retval 1 Read succeeded. - @retval 0 End of stream. - @retval -1 Error. */ - int (* read)(void * buffer, size_t length, void * userdata); - - /** User supplied seek callback. - @param offset Offset within the stream to seek to. - @param whence Seek direction. One of #NESTEGG_SEEK_SET, - #NESTEGG_SEEK_CUR, or #NESTEGG_SEEK_END. - @param userdata The #userdata supplied by the user. - @retval 0 Seek succeeded. - @retval -1 Error. */ - int (* seek)(int64_t offset, int whence, void * userdata); - - /** User supplied tell callback. - @param userdata The #userdata supplied by the user. - @returns Current position within the stream. - @retval -1 Error. */ - int64_t (* tell)(void * userdata); - - /** User supplied pointer to be passed to the IO callbacks. */ - void * userdata; -} nestegg_io; - -/** Parameters specific to a video track. */ -typedef struct { - unsigned int width; /**< Width of the video frame in pixels. */ - unsigned int height; /**< Height of the video frame in pixels. */ - unsigned int display_width; /**< Display width of the video frame in pixels. */ - unsigned int display_height; /**< Display height of the video frame in pixels. */ - unsigned int crop_bottom; /**< Pixels to crop from the bottom of the frame. */ - unsigned int crop_top; /**< Pixels to crop from the top of the frame. */ - unsigned int crop_left; /**< Pixels to crop from the left of the frame. */ - unsigned int crop_right; /**< Pixels to crop from the right of the frame. */ -} nestegg_video_params; - -/** Parameters specific to an audio track. */ -typedef struct { - double rate; /**< Sampling rate in Hz. */ - unsigned int channels; /**< Number of audio channels. */ - unsigned int depth; /**< Bits per sample. */ -} nestegg_audio_params; - -/** Logging callback function pointer. */ -typedef void (* nestegg_log)(nestegg * context, unsigned int severity, char const * format, ...); - -/** Initialize a nestegg context. During initialization the parser will - read forward in the stream processing all elements until the first - block of media is reached. All track metadata has been processed at this point. - @param context Storage for the new nestegg context. @see nestegg_destroy - @param io User supplied IO context. - @param callback Optional logging callback function pointer. May be NULL. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_init(nestegg ** context, nestegg_io io, nestegg_log callback); - -/** Destroy a nestegg context and free associated memory. - @param context #nestegg context to be freed. @see nestegg_init */ -void nestegg_destroy(nestegg * context); - -/** Query the duration of the media stream in nanoseconds. - @param context Stream context initialized by #nestegg_init. - @param duration Storage for the queried duration. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_duration(nestegg * context, uint64_t * duration); - -/** Query the number of tracks in the media stream. - @param context Stream context initialized by #nestegg_init. - @param tracks Storage for the queried track count. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_track_count(nestegg * context, unsigned int * tracks); - -/** Seek @a track to @a tstamp. Stream seek will terminate at the earliest - key point in the stream at or before @a tstamp. Other tracks in the - stream will output packets with unspecified but nearby timestamps. - @param context Stream context initialized by #nestegg_init. - @param track Zero based track number. - @param tstamp Absolute timestamp in nanoseconds. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_track_seek(nestegg * context, unsigned int track, uint64_t tstamp); - -/** Query the type specified by @a track. - @param context Stream context initialized by #nestegg_init. - @param track Zero based track number. - @retval #NESTEGG_TRACK_VIDEO Track type is video. - @retval #NESTEGG_TRACK_VIDEO Track type is audio. - @retval -1 Error. */ -int nestegg_track_type(nestegg * context, unsigned int track); - -/** Query the codec ID specified by @a track. - @param context Stream context initialized by #nestegg_init. - @param track Zero based track number. - @retval #NESTEGG_CODEC_VP8 Track codec is VP8. - @retval #NESTEGG_CODEC_VORBIS Track codec is Vorbis. - @retval -1 Error. */ -int nestegg_track_codec_id(nestegg * context, unsigned int track); - -/** Query the number of codec initialization chunks for @a track. Each - chunk of data should be passed to the codec initialization functions in - the order returned. - @param context Stream context initialized by #nestegg_init. - @param track Zero based track number. - @param count Storage for the queried chunk count. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_track_codec_data_count(nestegg * context, unsigned int track, - unsigned int * count); - -/** Get a pointer to chunk number @a item of codec initialization data for - @a track. - @param context Stream context initialized by #nestegg_init. - @param track Zero based track number. - @param item Zero based chunk item number. - @param data Storage for the queried data pointer. - The data is owned by the #nestegg context. - @param length Storage for the queried data size. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_track_codec_data(nestegg * context, unsigned int track, unsigned int item, - unsigned char ** data, size_t * length); - -/** Query the video parameters specified by @a track. - @param context Stream context initialized by #nestegg_init. - @param track Zero based track number. - @param params Storage for the queried video parameters. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_track_video_params(nestegg * context, unsigned int track, - nestegg_video_params * params); - -/** Query the audio parameters specified by @a track. - @param context Stream context initialized by #nestegg_init. - @param track Zero based track number. - @param params Storage for the queried audio parameters. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_track_audio_params(nestegg * context, unsigned int track, - nestegg_audio_params * params); - -/** Read a packet of media data. A packet consists of one or more chunks of - data associated with a single track. nestegg_read_packet should be - called in a loop while the return value is 1 to drive the stream parser - forward. @see nestegg_free_packet - @param context Context returned by #nestegg_init. - @param packet Storage for the returned nestegg_packet. - @retval 1 Additional packets may be read in subsequent calls. - @retval 0 End of stream. - @retval -1 Error. */ -int nestegg_read_packet(nestegg * context, nestegg_packet ** packet); - -/** Destroy a nestegg_packet and free associated memory. - @param packet #nestegg_packet to be freed. @see nestegg_read_packet */ -void nestegg_free_packet(nestegg_packet * packet); - -/** Query the track number of @a packet. - @param packet Packet initialized by #nestegg_read_packet. - @param track Storage for the queried zero based track index. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_packet_track(nestegg_packet * packet, unsigned int * track); - -/** Query the time stamp in nanoseconds of @a packet. - @param packet Packet initialized by #nestegg_read_packet. - @param tstamp Storage for the queried timestamp in nanoseconds. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_packet_tstamp(nestegg_packet * packet, uint64_t * tstamp); - -/** Query the number of data chunks contained in @a packet. - @param packet Packet initialized by #nestegg_read_packet. - @param count Storage for the queried timestamp in nanoseconds. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_packet_count(nestegg_packet * packet, unsigned int * count); - -/** Get a pointer to chunk number @a item of packet data. - @param packet Packet initialized by #nestegg_read_packet. - @param item Zero based chunk item number. - @param data Storage for the queried data pointer. - The data is owned by the #nestegg_packet packet. - @param length Storage for the queried data size. - @retval 0 Success. - @retval -1 Error. */ -int nestegg_packet_data(nestegg_packet * packet, unsigned int item, - unsigned char ** data, size_t * length); - -#ifdef __cplusplus -} -#endif - -#endif /* NESTEGG_671cac2a_365d_ed69_d7a3_4491d3538d79 */ diff --git a/src/oxframe.c b/src/oxframe.c index 8a17a55..33956a5 100644 --- a/src/oxframe.c +++ b/src/oxframe.c @@ -23,7 +23,7 @@ #include #include #include -#include "nestegg.h" +#include #define VPX_CODEC_DISABLE_COMPAT 1 #include "vpx/vpx_decoder.h"