We use libwebm instead of libmkv and nestegg.
Change-Id: I339eae081061c2e3eb8b234f14ae1bc846f85011
+++ /dev/null
-// #include <strmif.h>
-#include "EbmlBufferWriter.h"
-#include "EbmlWriter.h"
-// #include <cassert>
-// #include <limits>
-// #include <malloc.h> //_alloca
-#include <stdlib.h>
-#include <wchar.h>
-#include <string.h>
-
-void Ebml_Write(EbmlGlobal *glob, const void *buffer_in, unsigned long len) {
- unsigned char *src = glob->buf;
- src += glob->offset;
- memcpy(src, buffer_in, len);
- glob->offset += len;
-}
-
-static void _Serialize(EbmlGlobal *glob, const unsigned char *p, const unsigned char *q) {
- while (q != p) {
- --q;
- memcpy(&(glob->buf[glob->offset]), q, 1);
- glob->offset++;
- }
-}
-
-void Ebml_Serialize(EbmlGlobal *glob, const void *buffer_in, unsigned long len) {
- // assert(buf);
-
- const unsigned char *const p = (const unsigned char *)(buffer_in);
- const unsigned char *const q = p + len;
-
- _Serialize(glob, p, q);
-}
-
-
-void Ebml_StartSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc, unsigned long class_id) {
- Ebml_WriteID(glob, class_id);
- ebmlLoc->offset = glob->offset;
- // todo this is always taking 8 bytes, this may need later optimization
- unsigned long long unknownLen = 0x01FFFFFFFFFFFFFFLLU;
- Ebml_Serialize(glob, (void *)&unknownLen, 8); // this is a key that says lenght unknown
-}
-
-void Ebml_EndSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc) {
- unsigned long long size = glob->offset - ebmlLoc->offset - 8;
- unsigned long long curOffset = glob->offset;
- glob->offset = ebmlLoc->offset;
- size |= 0x0100000000000000LLU;
- Ebml_Serialize(glob, &size, 8);
- glob->offset = curOffset;
-}
-
+++ /dev/null
-#ifndef EBMLBUFFERWRITER_HPP
-#define EBMLBUFFERWRITER_HPP
-
-typedef struct {
- unsigned long long offset;
-} EbmlLoc;
-
-typedef struct {
- unsigned char *buf;
- unsigned int length;
- unsigned int offset;
-} EbmlGlobal;
-
-
-void Ebml_StartSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc, unsigned long class_id);
-void Ebml_EndSubElement(EbmlGlobal *glob, EbmlLoc *ebmlLoc);
-
-
-#endif
+++ /dev/null
-/*
- * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-#ifndef MKV_DEFS_HPP
-#define MKV_DEFS_HPP 1
-
-/* Commenting out values not available in webm, but available in matroska */
-
-enum mkv {
- EBML = 0x1A45DFA3,
- EBMLVersion = 0x4286,
- EBMLReadVersion = 0x42F7,
- EBMLMaxIDLength = 0x42F2,
- EBMLMaxSizeLength = 0x42F3,
- DocType = 0x4282,
- DocTypeVersion = 0x4287,
- DocTypeReadVersion = 0x4285,
-/* CRC_32 = 0xBF, */
- Void = 0xEC,
- SignatureSlot = 0x1B538667,
- SignatureAlgo = 0x7E8A,
- SignatureHash = 0x7E9A,
- SignaturePublicKey = 0x7EA5,
- Signature = 0x7EB5,
- SignatureElements = 0x7E5B,
- SignatureElementList = 0x7E7B,
- SignedElement = 0x6532,
- /* segment */
- Segment = 0x18538067,
- /* Meta Seek Information */
- SeekHead = 0x114D9B74,
- Seek = 0x4DBB,
- SeekID = 0x53AB,
- SeekPosition = 0x53AC,
- /* Segment Information */
- Info = 0x1549A966,
-/* SegmentUID = 0x73A4, */
-/* SegmentFilename = 0x7384, */
-/* PrevUID = 0x3CB923, */
-/* PrevFilename = 0x3C83AB, */
-/* NextUID = 0x3EB923, */
-/* NextFilename = 0x3E83BB, */
-/* SegmentFamily = 0x4444, */
-/* ChapterTranslate = 0x6924, */
-/* ChapterTranslateEditionUID = 0x69FC, */
-/* ChapterTranslateCodec = 0x69BF, */
-/* ChapterTranslateID = 0x69A5, */
- TimecodeScale = 0x2AD7B1,
- Segment_Duration = 0x4489,
- DateUTC = 0x4461,
-/* Title = 0x7BA9, */
- MuxingApp = 0x4D80,
- WritingApp = 0x5741,
- /* Cluster */
- Cluster = 0x1F43B675,
- Timecode = 0xE7,
-/* SilentTracks = 0x5854, */
-/* SilentTrackNumber = 0x58D7, */
-/* Position = 0xA7, */
- PrevSize = 0xAB,
- BlockGroup = 0xA0,
- Block = 0xA1,
-/* BlockVirtual = 0xA2, */
- BlockAdditions = 0x75A1,
- BlockMore = 0xA6,
- BlockAddID = 0xEE,
- BlockAdditional = 0xA5,
- BlockDuration = 0x9B,
-/* ReferencePriority = 0xFA, */
- ReferenceBlock = 0xFB,
-/* ReferenceVirtual = 0xFD, */
-/* CodecState = 0xA4, */
-/* Slices = 0x8E, */
-/* TimeSlice = 0xE8, */
- LaceNumber = 0xCC,
-/* FrameNumber = 0xCD, */
-/* BlockAdditionID = 0xCB, */
-/* MkvDelay = 0xCE, */
-/* Cluster_Duration = 0xCF, */
- SimpleBlock = 0xA3,
-/* EncryptedBlock = 0xAF, */
- /* Track */
- Tracks = 0x1654AE6B,
- TrackEntry = 0xAE,
- TrackNumber = 0xD7,
- TrackUID = 0x73C5,
- TrackType = 0x83,
- FlagEnabled = 0xB9,
- FlagDefault = 0x88,
- FlagForced = 0x55AA,
- FlagLacing = 0x9C,
-/* MinCache = 0x6DE7, */
-/* MaxCache = 0x6DF8, */
- DefaultDuration = 0x23E383,
-/* TrackTimecodeScale = 0x23314F, */
-/* TrackOffset = 0x537F, */
- MaxBlockAdditionID = 0x55EE,
- Name = 0x536E,
- Language = 0x22B59C,
- CodecID = 0x86,
- CodecPrivate = 0x63A2,
- CodecName = 0x258688,
-/* AttachmentLink = 0x7446, */
-/* CodecSettings = 0x3A9697, */
-/* CodecInfoURL = 0x3B4040, */
-/* CodecDownloadURL = 0x26B240, */
-/* CodecDecodeAll = 0xAA, */
-/* TrackOverlay = 0x6FAB, */
-/* TrackTranslate = 0x6624, */
-/* TrackTranslateEditionUID = 0x66FC, */
-/* TrackTranslateCodec = 0x66BF, */
-/* TrackTranslateTrackID = 0x66A5, */
- /* video */
- Video = 0xE0,
- FlagInterlaced = 0x9A,
- StereoMode = 0x53B8,
- AlphaMode = 0x53C0,
- PixelWidth = 0xB0,
- PixelHeight = 0xBA,
- PixelCropBottom = 0x54AA,
- PixelCropTop = 0x54BB,
- PixelCropLeft = 0x54CC,
- PixelCropRight = 0x54DD,
- DisplayWidth = 0x54B0,
- DisplayHeight = 0x54BA,
- DisplayUnit = 0x54B2,
- AspectRatioType = 0x54B3,
-/* ColourSpace = 0x2EB524, */
-/* GammaValue = 0x2FB523, */
- FrameRate = 0x2383E3,
- /* end video */
- /* audio */
- Audio = 0xE1,
- SamplingFrequency = 0xB5,
- OutputSamplingFrequency = 0x78B5,
- Channels = 0x9F,
-/* ChannelPositions = 0x7D7B, */
- BitDepth = 0x6264,
- /* end audio */
- /* content encoding */
-/* ContentEncodings = 0x6d80, */
-/* ContentEncoding = 0x6240, */
-/* ContentEncodingOrder = 0x5031, */
-/* ContentEncodingScope = 0x5032, */
-/* ContentEncodingType = 0x5033, */
-/* ContentCompression = 0x5034, */
-/* ContentCompAlgo = 0x4254, */
-/* ContentCompSettings = 0x4255, */
-/* ContentEncryption = 0x5035, */
-/* ContentEncAlgo = 0x47e1, */
-/* ContentEncKeyID = 0x47e2, */
-/* ContentSignature = 0x47e3, */
-/* ContentSigKeyID = 0x47e4, */
-/* ContentSigAlgo = 0x47e5, */
-/* ContentSigHashAlgo = 0x47e6, */
- /* end content encoding */
- /* Cueing Data */
- Cues = 0x1C53BB6B,
- CuePoint = 0xBB,
- CueTime = 0xB3,
- CueTrackPositions = 0xB7,
- CueTrack = 0xF7,
- CueClusterPosition = 0xF1,
- CueBlockNumber = 0x5378
-/* CueCodecState = 0xEA, */
-/* CueReference = 0xDB, */
-/* CueRefTime = 0x96, */
-/* CueRefCluster = 0x97, */
-/* CueRefNumber = 0x535F, */
-/* CueRefCodecState = 0xEB, */
- /* Attachment */
-/* Attachments = 0x1941A469, */
-/* AttachedFile = 0x61A7, */
-/* FileDescription = 0x467E, */
-/* FileName = 0x466E, */
-/* FileMimeType = 0x4660, */
-/* FileData = 0x465C, */
-/* FileUID = 0x46AE, */
-/* FileReferral = 0x4675, */
- /* Chapters */
-/* Chapters = 0x1043A770, */
-/* EditionEntry = 0x45B9, */
-/* EditionUID = 0x45BC, */
-/* EditionFlagHidden = 0x45BD, */
-/* EditionFlagDefault = 0x45DB, */
-/* EditionFlagOrdered = 0x45DD, */
-/* ChapterAtom = 0xB6, */
-/* ChapterUID = 0x73C4, */
-/* ChapterTimeStart = 0x91, */
-/* ChapterTimeEnd = 0x92, */
-/* ChapterFlagHidden = 0x98, */
-/* ChapterFlagEnabled = 0x4598, */
-/* ChapterSegmentUID = 0x6E67, */
-/* ChapterSegmentEditionUID = 0x6EBC, */
-/* ChapterPhysicalEquiv = 0x63C3, */
-/* ChapterTrack = 0x8F, */
-/* ChapterTrackNumber = 0x89, */
-/* ChapterDisplay = 0x80, */
-/* ChapString = 0x85, */
-/* ChapLanguage = 0x437C, */
-/* ChapCountry = 0x437E, */
-/* ChapProcess = 0x6944, */
-/* ChapProcessCodecID = 0x6955, */
-/* ChapProcessPrivate = 0x450D, */
-/* ChapProcessCommand = 0x6911, */
-/* ChapProcessTime = 0x6922, */
-/* ChapProcessData = 0x6933, */
- /* Tagging */
-/* Tags = 0x1254C367, */
-/* Tag = 0x7373, */
-/* Targets = 0x63C0, */
-/* TargetTypeValue = 0x68CA, */
-/* TargetType = 0x63CA, */
-/* Tagging_TrackUID = 0x63C5, */
-/* Tagging_EditionUID = 0x63C9, */
-/* Tagging_ChapterUID = 0x63C4, */
-/* AttachmentUID = 0x63C6, */
-/* SimpleTag = 0x67C8, */
-/* TagName = 0x45A3, */
-/* TagLanguage = 0x447A, */
-/* TagDefault = 0x4484, */
-/* TagString = 0x4487, */
-/* TagBinary = 0x4485, */
-};
-#endif
+++ /dev/null
-/*
- * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-#include "EbmlWriter.h"
-#include <stdlib.h>
-#include <wchar.h>
-#include <string.h>
-#include <limits.h>
-#if defined(_MSC_VER)
-#define LITERALU64(n) n
-#else
-#define LITERALU64(n) n##LLU
-#endif
-
-void Ebml_WriteLen(EbmlGlobal *glob, int64_t val) {
- /* TODO check and make sure we are not > than 0x0100000000000000LLU */
- unsigned char size = 8; /* size in bytes to output */
-
- /* mask to compare for byte size */
- int64_t minVal = 0xff;
-
- for (size = 1; size < 8; size ++) {
- if (val < minVal)
- break;
-
- minVal = (minVal << 7);
- }
-
- val |= (((uint64_t)0x80) << ((size - 1) * 7));
-
- Ebml_Serialize(glob, (void *) &val, sizeof(val), size);
-}
-
-void Ebml_WriteString(EbmlGlobal *glob, const char *str) {
- const size_t size_ = strlen(str);
- const uint64_t size = size_;
- Ebml_WriteLen(glob, size);
- /* TODO: it's not clear from the spec whether the nul terminator
- * should be serialized too. For now we omit the null terminator.
- */
- Ebml_Write(glob, str, (unsigned long)size);
-}
-
-void Ebml_WriteUTF8(EbmlGlobal *glob, const wchar_t *wstr) {
- const size_t strlen = wcslen(wstr);
-
- /* TODO: it's not clear from the spec whether the nul terminator
- * should be serialized too. For now we include it.
- */
- const uint64_t size = strlen;
-
- Ebml_WriteLen(glob, size);
- Ebml_Write(glob, wstr, (unsigned long)size);
-}
-
-void Ebml_WriteID(EbmlGlobal *glob, unsigned long class_id) {
- int len;
-
- if (class_id >= 0x01000000)
- len = 4;
- else if (class_id >= 0x00010000)
- len = 3;
- else if (class_id >= 0x00000100)
- len = 2;
- else
- len = 1;
-
- Ebml_Serialize(glob, (void *)&class_id, sizeof(class_id), len);
-}
-
-void Ebml_SerializeUnsigned64(EbmlGlobal *glob, unsigned long class_id, uint64_t ui) {
- unsigned char sizeSerialized = 8 | 0x80;
- Ebml_WriteID(glob, class_id);
- Ebml_Serialize(glob, &sizeSerialized, sizeof(sizeSerialized), 1);
- Ebml_Serialize(glob, &ui, sizeof(ui), 8);
-}
-
-void Ebml_SerializeUnsigned(EbmlGlobal *glob, unsigned long class_id, unsigned long ui) {
- unsigned char size = 8; /* size in bytes to output */
- unsigned char sizeSerialized = 0;
- unsigned long minVal;
-
- Ebml_WriteID(glob, class_id);
- minVal = 0x7fLU; /* mask to compare for byte size */
-
- for (size = 1; size < 4; size ++) {
- if (ui < minVal) {
- break;
- }
-
- minVal <<= 7;
- }
-
- sizeSerialized = 0x80 | size;
- Ebml_Serialize(glob, &sizeSerialized, sizeof(sizeSerialized), 1);
- Ebml_Serialize(glob, &ui, sizeof(ui), size);
-}
-/* TODO: perhaps this is a poor name for this id serializer helper function */
-void Ebml_SerializeBinary(EbmlGlobal *glob, unsigned long class_id, unsigned long bin) {
- int size;
- for (size = 4; size > 1; size--) {
- if (bin & (unsigned int)0x000000ff << ((size - 1) * 8))
- break;
- }
- Ebml_WriteID(glob, class_id);
- Ebml_WriteLen(glob, size);
- Ebml_WriteID(glob, bin);
-}
-
-void Ebml_SerializeFloat(EbmlGlobal *glob, unsigned long class_id, double d) {
- unsigned char len = 0x88;
-
- Ebml_WriteID(glob, class_id);
- Ebml_Serialize(glob, &len, sizeof(len), 1);
- Ebml_Serialize(glob, &d, sizeof(d), 8);
-}
-
-void Ebml_WriteSigned16(EbmlGlobal *glob, short val) {
- signed long out = ((val & 0x003FFFFF) | 0x00200000) << 8;
- Ebml_Serialize(glob, &out, sizeof(out), 3);
-}
-
-void Ebml_SerializeString(EbmlGlobal *glob, unsigned long class_id, const char *s) {
- Ebml_WriteID(glob, class_id);
- Ebml_WriteString(glob, s);
-}
-
-void Ebml_SerializeUTF8(EbmlGlobal *glob, unsigned long class_id, wchar_t *s) {
- Ebml_WriteID(glob, class_id);
- Ebml_WriteUTF8(glob, s);
-}
-
-void Ebml_SerializeData(EbmlGlobal *glob, unsigned long class_id, unsigned char *data, unsigned long data_length) {
- Ebml_WriteID(glob, class_id);
- Ebml_WriteLen(glob, data_length);
- Ebml_Write(glob, data, data_length);
-}
-
-void Ebml_WriteVoid(EbmlGlobal *glob, unsigned long vSize) {
- unsigned char tmp = 0;
- unsigned long i = 0;
-
- Ebml_WriteID(glob, 0xEC);
- Ebml_WriteLen(glob, vSize);
-
- for (i = 0; i < vSize; i++) {
- Ebml_Write(glob, &tmp, 1);
- }
-}
-
-/* TODO Serialize Date */
+++ /dev/null
-/*
- * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-#ifndef EBMLWRITER_HPP
-#define EBMLWRITER_HPP
-#include <stddef.h>
-#include "vpx/vpx_integer.h"
-
-/* note: you must define write and serialize functions as well as your own
- * EBML_GLOBAL
- *
- * These functions MUST be implemented
- */
-
-typedef struct EbmlGlobal EbmlGlobal;
-void Ebml_Serialize(EbmlGlobal *glob, const void *, int, unsigned long);
-void Ebml_Write(EbmlGlobal *glob, const void *, unsigned long);
-
-/*****/
-
-void Ebml_WriteLen(EbmlGlobal *glob, int64_t val);
-void Ebml_WriteString(EbmlGlobal *glob, const char *str);
-void Ebml_WriteUTF8(EbmlGlobal *glob, const wchar_t *wstr);
-void Ebml_WriteID(EbmlGlobal *glob, unsigned long class_id);
-void Ebml_SerializeUnsigned64(EbmlGlobal *glob, unsigned long class_id, uint64_t ui);
-void Ebml_SerializeUnsigned(EbmlGlobal *glob, unsigned long class_id, unsigned long ui);
-void Ebml_SerializeBinary(EbmlGlobal *glob, unsigned long class_id, unsigned long ui);
-void Ebml_SerializeFloat(EbmlGlobal *glob, unsigned long class_id, double d);
-/* TODO make this more generic to signed */
-void Ebml_WriteSigned16(EbmlGlobal *glob, short val);
-void Ebml_SerializeString(EbmlGlobal *glob, unsigned long class_id, const char *s);
-void Ebml_SerializeUTF8(EbmlGlobal *glob, unsigned long class_id, wchar_t *s);
-void Ebml_SerializeData(EbmlGlobal *glob, unsigned long class_id, unsigned char *data, unsigned long data_length);
-void Ebml_WriteVoid(EbmlGlobal *glob, unsigned long vSize);
-/* TODO need date function */
-#endif
+++ /dev/null
-#Variables
-CC=gcc
-LINKER=gcc
-FLAGS=-g -Wall
-
-all: testlibmkv
-
-#Build Targets
-EbmlWriter.o: EbmlWriter.c EbmlWriter.h
- $(CC) $(FLAGS) -c EbmlWriter.c
-
-EbmlBufferWriter.o: EbmlBufferWriter.c EbmlBufferWriter.h
- $(CC) $(FLAGS) -c EbmlBufferWriter.c
-
-WebMElement.o: WebMElement.c WebMElement.h
- $(CC) $(FLAGS) -c WebMElement.c
-
-testlibmkv.o: testlibmkv.c
- $(CC) $(FLAGS) -c testlibmkv.c
-
-testlibmkv: testlibmkv.o WebMElement.o EbmlBufferWriter.o EbmlWriter.o
- $(LINKER) $(FLAGS) -o testlibmkv testlibmkv.o WebMElement.o EbmlBufferWriter.o EbmlWriter.o
-
-clean:
- rm -rf *.o testlibmkv
+++ /dev/null
-// Copyright (c) 2010 The WebM project authors. All Rights Reserved.
-//
-// Use of this source code is governed by a BSD-style license
-// that can be found in the LICENSE file in the root of the source
-// tree. An additional intellectual property rights grant can be found
-// in the file PATENTS. All contributing project authors may
-// be found in the AUTHORS file in the root of the source tree.
-
-
-#include "EbmlBufferWriter.h"
-#include "EbmlIDs.h"
-#include "WebMElement.h"
-#include <stdio.h>
-#include "vpx/vpx_integer.h"
-
-#define kVorbisPrivateMaxSize 4000
-
-void writeHeader(EbmlGlobal *glob) {
- EbmlLoc start;
- Ebml_StartSubElement(glob, &start, EBML);
- Ebml_SerializeUnsigned(glob, EBMLVersion, 1);
- Ebml_SerializeUnsigned(glob, EBMLReadVersion, 1); // EBML Read Version
- Ebml_SerializeUnsigned(glob, EBMLMaxIDLength, 4); // EBML Max ID Length
- Ebml_SerializeUnsigned(glob, EBMLMaxSizeLength, 8); // EBML Max Size Length
- Ebml_SerializeString(glob, DocType, "webm"); // Doc Type
- Ebml_SerializeUnsigned(glob, DocTypeVersion, 2); // Doc Type Version
- Ebml_SerializeUnsigned(glob, DocTypeReadVersion, 2); // Doc Type Read Version
- Ebml_EndSubElement(glob, &start);
-}
-
-void writeSimpleBlock(EbmlGlobal *glob, unsigned char trackNumber, short timeCode,
- int isKeyframe, unsigned char lacingFlag, int discardable,
- unsigned char *data, unsigned long dataLength) {
- Ebml_WriteID(glob, SimpleBlock);
- unsigned long blockLength = 4 + dataLength;
- blockLength |= 0x10000000; // TODO check length < 0x0FFFFFFFF
- Ebml_Serialize(glob, &blockLength, sizeof(blockLength), 4);
- trackNumber |= 0x80; // TODO check track nubmer < 128
- Ebml_Write(glob, &trackNumber, 1);
- // Ebml_WriteSigned16(glob, timeCode,2); //this is 3 bytes
- Ebml_Serialize(glob, &timeCode, sizeof(timeCode), 2);
- unsigned char flags = 0x00 | (isKeyframe ? 0x80 : 0x00) | (lacingFlag << 1) | discardable;
- Ebml_Write(glob, &flags, 1);
- Ebml_Write(glob, data, dataLength);
-}
-
-static uint64_t generateTrackID(unsigned int trackNumber) {
- uint64_t t = time(NULL) * trackNumber;
- uint64_t r = rand();
- r = r << 32;
- r += rand();
- uint64_t rval = t ^ r;
- return rval;
-}
-
-void writeVideoTrack(EbmlGlobal *glob, unsigned int trackNumber,
- int flagLacing, const char *codecId,
- unsigned int pixelWidth, unsigned int pixelHeight,
- double frameRate) {
- EbmlLoc start;
- Ebml_StartSubElement(glob, &start, TrackEntry);
- Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
- uint64_t trackID = generateTrackID(trackNumber);
- Ebml_SerializeUnsigned(glob, TrackUID, trackID);
- Ebml_SerializeString(glob, CodecName, "VP8"); // TODO shouldn't be fixed
-
- Ebml_SerializeUnsigned(glob, TrackType, 1); // video is always 1
- Ebml_SerializeString(glob, CodecID, codecId);
- {
- EbmlLoc videoStart;
- Ebml_StartSubElement(glob, &videoStart, Video);
- Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth);
- Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight);
- Ebml_SerializeFloat(glob, FrameRate, frameRate);
- Ebml_EndSubElement(glob, &videoStart); // Video
- }
- Ebml_EndSubElement(glob, &start); // Track Entry
-}
-void writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber,
- int flagLacing, const char *codecId,
- double samplingFrequency, unsigned int channels,
- unsigned char *private, unsigned long privateSize) {
- EbmlLoc start;
- Ebml_StartSubElement(glob, &start, TrackEntry);
- Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
- uint64_t trackID = generateTrackID(trackNumber);
- Ebml_SerializeUnsigned(glob, TrackUID, trackID);
- Ebml_SerializeUnsigned(glob, TrackType, 2); // audio is always 2
- // I am using defaults for thesed required fields
- /* Ebml_SerializeUnsigned(glob, FlagEnabled, 1);
- Ebml_SerializeUnsigned(glob, FlagDefault, 1);
- Ebml_SerializeUnsigned(glob, FlagForced, 1);
- Ebml_SerializeUnsigned(glob, FlagLacing, flagLacing);*/
- Ebml_SerializeString(glob, CodecID, codecId);
- Ebml_SerializeData(glob, CodecPrivate, private, privateSize);
-
- Ebml_SerializeString(glob, CodecName, "VORBIS"); // fixed for now
- {
- EbmlLoc AudioStart;
- Ebml_StartSubElement(glob, &AudioStart, Audio);
- Ebml_SerializeFloat(glob, SamplingFrequency, samplingFrequency);
- Ebml_SerializeUnsigned(glob, Channels, channels);
- Ebml_EndSubElement(glob, &AudioStart);
- }
- Ebml_EndSubElement(glob, &start);
-}
-void writeSegmentInformation(EbmlGlobal *ebml, EbmlLoc *startInfo, unsigned long timeCodeScale, double duration) {
- Ebml_StartSubElement(ebml, startInfo, Info);
- Ebml_SerializeUnsigned(ebml, TimecodeScale, timeCodeScale);
- Ebml_SerializeFloat(ebml, Segment_Duration, duration * 1000.0); // Currently fixed to using milliseconds
- Ebml_SerializeString(ebml, 0x4D80, "QTmuxingAppLibWebM-0.0.1");
- Ebml_SerializeString(ebml, 0x5741, "QTwritingAppLibWebM-0.0.1");
- Ebml_EndSubElement(ebml, startInfo);
-}
-
-/*
-void Mkv_InitializeSegment(Ebml& ebml_out, EbmlLoc& ebmlLoc)
-{
- Ebml_StartSubElement(ebml_out, ebmlLoc, 0x18538067);
-}
-
-void Mkv_InitializeSeek(Ebml& ebml_out, EbmlLoc& ebmlLoc)
-{
- Ebml_StartSubElement(ebml_out, ebmlLoc, 0x114d9b74);
-}
-void Mkv_WriteSeekInformation(Ebml& ebml_out, SeekStruct& seekInformation)
-{
- EbmlLoc ebmlLoc;
- Ebml_StartSubElement(ebml_out, ebmlLoc, 0x4dbb);
- Ebml_SerializeString(ebml_out, 0x53ab, seekInformation.SeekID);
- Ebml_SerializeUnsigned(ebml_out, 0x53ac, seekInformation.SeekPosition);
- Ebml_EndSubElement(ebml_out, ebmlLoc);
-}
-
-void Mkv_WriteSegmentInformation(Ebml& ebml_out, SegmentInformationStruct& segmentInformation)
-{
- Ebml_SerializeUnsigned(ebml_out, 0x73a4, segmentInformation.segmentUID);
- if (segmentInformation.filename != 0)
- Ebml_SerializeString(ebml_out, 0x7384, segmentInformation.filename);
- Ebml_SerializeUnsigned(ebml_out, 0x2AD7B1, segmentInformation.TimecodeScale);
- Ebml_SerializeUnsigned(ebml_out, 0x4489, segmentInformation.Duration);
- // TODO date
- Ebml_SerializeWString(ebml_out, 0x4D80, L"MKVMUX");
- Ebml_SerializeWString(ebml_out, 0x5741, segmentInformation.WritingApp);
-}
-
-void Mkv_InitializeTrack(Ebml& ebml_out, EbmlLoc& ebmlLoc)
-{
- Ebml_StartSubElement(ebml_out, ebmlLoc, 0x1654AE6B);
-}
-
-static void Mkv_WriteGenericTrackData(Ebml& ebml_out, TrackStruct& track)
-{
- Ebml_SerializeUnsigned(ebml_out, 0xD7, track.TrackNumber);
- Ebml_SerializeUnsigned(ebml_out, 0x73C5, track.TrackUID);
- Ebml_SerializeUnsigned(ebml_out, 0x83, track.TrackType);
- Ebml_SerializeUnsigned(ebml_out, 0xB9, track.FlagEnabled ? 1 :0);
- Ebml_SerializeUnsigned(ebml_out, 0x88, track.FlagDefault ? 1 :0);
- Ebml_SerializeUnsigned(ebml_out, 0x55AA, track.FlagForced ? 1 :0);
- if (track.Language != 0)
- Ebml_SerializeString(ebml_out, 0x22B59C, track.Language);
- if (track.CodecID != 0)
- Ebml_SerializeString(ebml_out, 0x86, track.CodecID);
- if (track.CodecPrivate != 0)
- Ebml_SerializeData(ebml_out, 0x63A2, track.CodecPrivate, track.CodecPrivateLength);
- if (track.CodecName != 0)
- Ebml_SerializeWString(ebml_out, 0x258688, track.CodecName);
-}
-
-void Mkv_WriteVideoTrack(Ebml& ebml_out, TrackStruct & track, VideoTrackStruct& video)
-{
- EbmlLoc trackHeadLoc, videoHeadLoc;
- Ebml_StartSubElement(ebml_out, trackHeadLoc, 0xAE); // start Track
- Mkv_WriteGenericTrackData(ebml_out, track);
- Ebml_StartSubElement(ebml_out, videoHeadLoc, 0xE0); // start Video
- Ebml_SerializeUnsigned(ebml_out, 0x9A, video.FlagInterlaced ? 1 :0);
- Ebml_SerializeUnsigned(ebml_out, 0xB0, video.PixelWidth);
- Ebml_SerializeUnsigned(ebml_out, 0xBA, video.PixelHeight);
- Ebml_SerializeUnsigned(ebml_out, 0x54B0, video.PixelDisplayWidth);
- Ebml_SerializeUnsigned(ebml_out, 0x54BA, video.PixelDisplayHeight);
- Ebml_SerializeUnsigned(ebml_out, 0x54B2, video.displayUnit);
- Ebml_SerializeFloat(ebml_out, 0x2383E3, video.FrameRate);
- Ebml_EndSubElement(ebml_out, videoHeadLoc);
- Ebml_EndSubElement(ebml_out, trackHeadLoc);
-
-}
-
-void Mkv_WriteAudioTrack(Ebml& ebml_out, TrackStruct & track, AudioTrackStruct& video)
-{
- EbmlLoc trackHeadLoc, audioHeadLoc;
- Ebml_StartSubElement(ebml_out, trackHeadLoc, 0xAE);
- Mkv_WriteGenericTrackData(ebml_out, track);
- Ebml_StartSubElement(ebml_out, audioHeadLoc, 0xE0); // start Audio
- Ebml_SerializeFloat(ebml_out, 0xB5, video.SamplingFrequency);
- Ebml_SerializeUnsigned(ebml_out, 0x9F, video.Channels);
- Ebml_SerializeUnsigned(ebml_out, 0x6264, video.BitDepth);
- Ebml_EndSubElement(ebml_out, audioHeadLoc); // end audio
- Ebml_EndSubElement(ebml_out, trackHeadLoc);
-}
-
-void Mkv_WriteEbmlClusterHead(Ebml& ebml_out, EbmlLoc& ebmlLoc, ClusterHeadStruct & clusterHead)
-{
- Ebml_StartSubElement(ebml_out, ebmlLoc, 0x1F43B675);
- Ebml_SerializeUnsigned(ebml_out, 0x6264, clusterHead.TimeCode);
-}
-
-void Mkv_WriteSimpleBlockHead(Ebml& ebml_out, EbmlLoc& ebmlLoc, SimpleBlockStruct& block)
-{
- Ebml_StartSubElement(ebml_out, ebmlLoc, 0xA3);
- Ebml_Write1UInt(ebml_out, block.TrackNumber);
- Ebml_WriteSigned16(ebml_out,block.TimeCode);
- unsigned char flags = 0x00 | (block.iskey ? 0x80:0x00) | (block.lacing << 1) | block.discardable;
- Ebml_Write1UInt(ebml_out, flags); // TODO this may be the wrong function
- Ebml_Serialize(ebml_out, block.data, block.dataLength);
- Ebml_EndSubElement(ebml_out,ebmlLoc);
-}
-*/
+++ /dev/null
-// Copyright (c) 2010 The WebM project authors. All Rights Reserved.
-//
-// Use of this source code is governed by a BSD-style license
-// that can be found in the LICENSE file in the root of the source
-// tree. An additional intellectual property rights grant can be found
-// in the file PATENTS. All contributing project authors may
-// be found in the AUTHORS file in the root of the source tree.
-
-
-#ifndef MKV_CONTEXT_HPP
-#define MKV_CONTEXT_HPP 1
-
-// these are helper functions
-void writeHeader(EbmlGlobal *ebml);
-void writeSegmentInformation(EbmlGlobal *ebml, EbmlLoc *startInfo,
- unsigned long timeCodeScale, double duration);
-// this function is a helper only, it assumes a lot of defaults
-void writeVideoTrack(EbmlGlobal *ebml, unsigned int trackNumber,
- int flagLacing, const char *codecId,
- unsigned int pixelWidth, unsigned int pixelHeight,
- double frameRate);
-void writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber,
- int flagLacing, const char *codecId,
- double samplingFrequency, unsigned int channels,
- unsigned char *private, unsigned long privateSize);
-
-void writeSimpleBlock(EbmlGlobal *ebml, unsigned char trackNumber,
- short timeCode, int isKeyframe,
- unsigned char lacingFlag, int discardable,
- unsigned char *data, unsigned long dataLength);
-
-#endif
+++ /dev/null
-// Copyright (c) 2010 The WebM project authors. All Rights Reserved.
-//
-// Use of this source code is governed by a BSD-style license
-// that can be found in the LICENSE file in the root of the source
-// tree. An additional intellectual property rights grant can be found
-// in the file PATENTS. All contributing project authors may
-// be found in the AUTHORS file in the root of the source tree.
-
-
-
-#include "EbmlIDs.h"
-#include "EbmlBufferWriter.h"
-#include "WebMElement.h"
-
-#include <stdio.h>
-int main(int argc, char *argv[]) {
- // init the datatype we're using for ebml output
- unsigned char data[8192];
- EbmlGlobal ebml;
- ebml.buf = data;
- ebml.offset = 0;
- ebml.length = 8192;
-
- writeHeader(&ebml);
- {
- EbmlLoc startSegment;
- Ebml_StartSubElement(&ebml, &startSegment, Segment); // segment
- {
- // segment info
- EbmlLoc startInfo;
- Ebml_StartSubElement(&ebml, &startInfo, Info);
- Ebml_SerializeString(&ebml, 0x4D80, "muxingAppLibMkv");
- Ebml_SerializeString(&ebml, 0x5741, "writingAppLibMkv");
- Ebml_EndSubElement(&ebml, &startInfo);
- }
-
- {
- EbmlLoc trackStart;
- Ebml_StartSubElement(&ebml, &trackStart, Tracks);
- writeVideoTrack(&ebml, 1, 1, "V_MS/VFW/FOURCC", 320, 240, 29.97);
- // writeAudioTrack(&ebml,2,1, "A_VORBIS", 32000, 1, NULL, 0);
- Ebml_EndSubElement(&ebml, &trackStart);
- }
-
- {
- EbmlLoc clusterStart;
- Ebml_StartSubElement(&ebml, &clusterStart, Cluster); // cluster
- Ebml_SerializeUnsigned(&ebml, Timecode, 0);
-
- unsigned char someData[4] = {1, 2, 3, 4};
- writeSimpleBlock(&ebml, 1, 0, 1, 0, 0, someData, 4);
- Ebml_EndSubElement(&ebml, &clusterStart);
- } // end cluster
- Ebml_EndSubElement(&ebml, &startSegment);
- }
-
- // dump ebml stuff to the file
- FILE *file_out = fopen("test.mkv", "wb");
- size_t bytesWritten = fwrite(data, 1, ebml.offset, file_out);
- fclose(file_out);
- return 0;
-}
\ No newline at end of file
+++ /dev/null
-diff --git a/nestegg/halloc/src/halloc.c b/nestegg/halloc/src/halloc.c
-index 5758fc0..837b3ff 100644
---- a/nestegg/halloc/src/halloc.c
-+++ b/nestegg/halloc/src/halloc.c
-@@ -15,7 +15,7 @@
- #include <stdlib.h> /* realloc */
- #include <string.h> /* memset & co */
-
--#include "halloc.h"
-+#include "third_party/nestegg/halloc/halloc.h"
- #include "align.h"
- #include "hlist.h"
-
-diff --git a/nestegg/include/nestegg/nestegg.h b/nestegg/include/nestegg/nestegg.h
-index ff13728..c18d1d3 100644
---- a/nestegg/include/nestegg/nestegg.h
-+++ b/nestegg/include/nestegg/nestegg.h
-@@ -7,7 +7,7 @@
- #if !defined(NESTEGG_671cac2a_365d_ed69_d7a3_4491d3538d79)
- #define NESTEGG_671cac2a_365d_ed69_d7a3_4491d3538d79
-
--#include <nestegg/nestegg-stdint.h>
-+#include "vpx/vpx_integer.h"
-
- #if defined(__cplusplus)
- extern "C" {
-diff --git a/nestegg/src/nestegg.c b/nestegg/src/nestegg.c
-index daf1eed..4fb10e7 100644
---- a/nestegg/src/nestegg.c
-+++ b/nestegg/src/nestegg.c
-@@ -8,8 +8,8 @@
- #include <stdlib.h>
- #include <string.h>
-
--#include "halloc.h"
--#include "nestegg/nestegg.h"
-+#include "third_party/nestegg/halloc/halloc.h"
-+#include "third_party/nestegg/include/nestegg/nestegg.h"
-
- /* EBML Elements */
- #define ID_EBML 0x1a45dfa3
+++ /dev/null
-diff --git a/nestegg/src/nestegg.c b/nestegg/src/nestegg.c
-index 4fb10e7..b6bc460 100644
---- a/nestegg/src/nestegg.c
-+++ b/nestegg/src/nestegg.c
-@@ -934,7 +934,7 @@ static int
- ne_read_simple(nestegg * ctx, struct ebml_element_desc * desc, size_t length)
- {
- struct ebml_type * storage;
-- int r;
-+ int r = 0;
-
- storage = (struct ebml_type *) (ctx->ancestor->data + desc->offset);
-
-@@ -968,7 +968,6 @@ ne_read_simple(nestegg * ctx, struct ebml_element_desc * desc, size_t length)
- case TYPE_MASTER:
- case TYPE_UNKNOWN:
- assert(0);
-- r = 0;
- break;
- }
-
+++ /dev/null
-Matthew Gregan <kinetik@flim.org>
-Steve Workman <sjhworkman@gmail.com>
-Paul Adenot <paul@paul.cx>
+++ /dev/null
-Build instructions for libnestegg
-=================================
-
-0. Change directory into the source directory.
-1. Run |autoreconf --install| to generate configure.
-2. Run |./configure| to configure the build.
-3. Run |make| to build.
-4. Run |make check| to run the test suite.
+++ /dev/null
-Copyright © 2010 Mozilla Foundation
-
-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.
+++ /dev/null
-See INSTALL for build instructions.
-
-Licensed under an ISC-style license. See LICENSE for details.
-
-The source under the halloc/ directory is licensed under a BSD license. See
-halloc/halloc.h for details.
+++ /dev/null
-URL: https://github.com/kinetiknz/nestegg.git
-Version: f46223191d8116a36bf299b5b9793fcb798417b1
-License: ISC-style
-License File: LICENSE
-
-Description:
-The source under the halloc/ directory is licensed under a BSD license. See
-halloc/halloc.h for details.
-
-Local Modifications:
-- delete unnecessary docs and build files
-- nestegg/0001-include-paths.diff
- include path modifications for the libvpx build system
-- 0002-ne_read_simple-uninitialized_variable.diff
- fixes:
-nestegg.c|975 col 6| warning: ‘r’ may be used uninitialized in this function [-Wuninitialized]
-- add ne_get_uint32 convenience function
-- fix track_number uint64->uint32 warnings
-- fix track_scale double->uint64 warning
-- nestegg_packet_track: fix uint64->uint32 warning
-- ne_read_(string|binary|block): normalize size_t usage
-- ne_parse: normalize size_t usage
-- quiet read related uint64->size_t warnings
-- ne_buffer_read: quiet uint64->size_t warning
+++ /dev/null
-- Document when read, seek, tell callbacks are used.
-- Add an automated testsuite.
-- Test (and fix, if necessary) support for unknown sizes.
-- Test (and fix, if necessary) support for large files.
-- Read past unknown elements rather than seeking.
-- Try to handle unknown elements with unknown sizes.
-- Formalize handling of default element values.
-- Try to resynchronize stream when read_block fails so that failure to parse
- a single block can be treated as non-fatal.
-- Make logging more useful to API users.
-- Avoid reparsing Cues and ignore any SeekHead at end of file.
-- Optionally build a Cue index as Clusters are parsed.
-- Support seeking without Cues.
-- Avoid building a list of Clusters as they are parsed and retain only the
- last one parsed.
-- Add an asynchronous error code to struct nestegg and ensure that API calls
- continue to fail safely one a fatal error has been returned.
-- Modify parser/data structures to provide a clean separation. Perhaps the
- parser should return a generic tree of nodes that a second pass uses to
- initialize the main data structures.
-- Use pool allocator for all allocations.
+++ /dev/null
-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 <string.h> 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.
-
+++ /dev/null
-/*
- * 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 <stddef.h> /* 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
-
+++ /dev/null
-/*
- * 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
-
+++ /dev/null
-/*
- * 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 <stdlib.h> /* realloc */
-#include <string.h> /* memset & co */
-
-#include "third_party/nestegg/halloc/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);
- }
-}
-
+++ /dev/null
-/*
- * 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 <assert.h>
-#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
-
+++ /dev/null
-/*
- * 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 <stddef.h> /* offsetof */
-
-/*
- restore pointer to the structure by a pointer to its field
- */
-#define structof(p,t,f) ((t*)(- (ptrdiff_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
-
+++ /dev/null
-/*
- * Copyright © 2010 Mozilla Foundation
- *
- * This program is made available under an ISC-style license. See the
- * accompanying file LICENSE for details.
- */
-#if !defined(NESTEGG_671cac2a_365d_ed69_d7a3_4491d3538d79)
-#define NESTEGG_671cac2a_365d_ed69_d7a3_4491d3538d79
-
-#include "vpx/vpx_integer.h"
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-/** @mainpage
-
- @section intro Introduction
-
- This is the documentation for the <tt>libnestegg</tt> C API.
- <tt>libnestegg</tt> is a demultiplexing library for <a
- href="http://www.webmproject.org/code/specs/container/">WebM</a>
- 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 <tt>libnestegg</tt> 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_CODEC_VP9 2 /**< Track uses Google On2 VP9 codec. */
-#define NESTEGG_CODEC_OPUS 3 /**< Track uses Xiph Opus codec. */
-
-#define NESTEGG_VIDEO_MONO 0 /**< Track is mono video. */
-#define NESTEGG_VIDEO_STEREO_LEFT_RIGHT 1 /**< Track is side-by-side stereo video. Left first. */
-#define NESTEGG_VIDEO_STEREO_BOTTOM_TOP 2 /**< Track is top-bottom stereo video. Right first. */
-#define NESTEGG_VIDEO_STEREO_TOP_BOTTOM 3 /**< Track is top-bottom stereo video. Left first. */
-#define NESTEGG_VIDEO_STEREO_RIGHT_LEFT 11 /**< Track is side-by-side stereo video. Right first. */
-
-#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 userdata 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 stereo_mode; /**< Video mode. One of #NESTEGG_VIDEO_MONO,
- #NESTEGG_VIDEO_STEREO_LEFT_RIGHT,
- #NESTEGG_VIDEO_STEREO_BOTTOM_TOP, or
- #NESTEGG_VIDEO_STEREO_TOP_BOTTOM. */
- 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. */
- uint64_t codec_delay; /**< Nanoseconds that must be discarded from the start. */
- uint64_t seek_preroll;/**< Nanoseconds that must be discarded after a seek. */
-} 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.
- @param max_offset Optional maximum offset to be read. Set -1 to ignore.
- @retval 0 Success.
- @retval -1 Error. */
-int nestegg_init(nestegg ** context, nestegg_io io, nestegg_log callback, int64_t max_offset);
-
-/** 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 tstamp scale of the media stream in nanoseconds.
- Timecodes presented by nestegg have been scaled by this value
- before presentation to the caller.
- @param context Stream context initialized by #nestegg_init.
- @param scale Storage for the queried scale factor.
- @retval 0 Success.
- @retval -1 Error. */
-int nestegg_tstamp_scale(nestegg * context, uint64_t * scale);
-
-/** 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);
-
-/** Query the start and end offset for a particular cluster.
- @param context Stream context initialized by #nestegg_init.
- @param cluster_num Zero-based cluster number; order they appear in cues.
- @param max_offset Optional maximum offset to be read. Set -1 to ignore.
- @param start_pos Starting offset of the cluster. -1 means non-existant.
- @param end_pos Starting offset of the cluster. -1 means non-existant or
- final cluster.
- @param tstamp Starting timestamp of the cluster.
- @retval 0 Success.
- @retval -1 Error. */
-int nestegg_get_cue_point(nestegg * context, unsigned int cluster_num,
- int64_t max_offset, int64_t * start_pos,
- int64_t * end_pos, uint64_t * tstamp);
-
-/** Seek to @a offset. Stream will seek directly to offset.
- Should be used to seek to the start of a resync point, i.e. cluster; the
- parser will not be able to understand other offsets.
- @param context Stream context initialized by #nestegg_init.
- @param offset Absolute offset in bytes.
- @retval 0 Success.
- @retval -1 Error. */
-int nestegg_offset_seek(nestegg * context, uint64_t offset);
-
-/** 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_AUDIO 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);
-
-/** Returns discard_padding for given packet
- @param packet Packet initialized by #nestegg_read_packet.
- @param discard_padding pointer to store discard padding in.
- @retval 0 Success.
- @retval -1 Error. */
-int nestegg_packet_discard_padding(nestegg_packet * packet,
- int64_t * discard_padding);
-
-/** Query the presence of cues.
- @param context Stream context initialized by #nestegg_init.
- @retval 0 The media has no cues.
- @retval 1 The media has cues. */
-int nestegg_has_cues(nestegg * context);
-
-/**
- * Try to determine if the buffer looks like the beginning of a WebM file.
- *
- * @param buffer A buffer containing the beginning of a media file.
- * @param length The size of the buffer.
- * @retval 0 The file is not a WebM file.
- * @retval 1 The file is a WebM file. */
-int nestegg_sniff(unsigned char const * buffer, size_t length);
-
-#if defined(__cplusplus)
-}
-#endif
-
-#endif /* NESTEGG_671cac2a_365d_ed69_d7a3_4491d3538d79 */
+++ /dev/null
-/*
- * Copyright © 2010 Mozilla Foundation
- *
- * This program is made available under an ISC-style license. See the
- * accompanying file LICENSE for details.
- */
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "third_party/nestegg/halloc/halloc.h"
-#include "third_party/nestegg/include/nestegg/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
-
-/* WebM 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
-#define ID_DISCARD_PADDING 0x75a2
-
-/* 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
-#define ID_CODEC_DELAY 0x56aa
-#define ID_SEEK_PREROLL 0x56bb
-
-/* Video Elements */
-#define ID_VIDEO 0xe0
-#define ID_STEREO_MODE 0x53b8
-#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)
-
-/* Block Header Flags */
-#define BLOCK_FLAGS_LACING 6
-
-/* Lacing Constants */
-#define LACING_NONE 0
-#define LACING_XIPH 1
-#define LACING_FIXED 2
-#define LACING_EBML 3
-
-/* Track Types */
-#define TRACK_TYPE_VIDEO 1
-#define TRACK_TYPE_AUDIO 2
-
-/* Track IDs */
-#define TRACK_ID_VP8 "V_VP8"
-#define TRACK_ID_VP9 "V_VP9"
-#define TRACK_ID_VORBIS "A_VORBIS"
-#define TRACK_ID_OPUS "A_OPUS"
-
-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 ebml_type discard_padding;
-};
-
-struct cluster {
- struct ebml_type timecode;
- struct ebml_list block_group;
-};
-
-struct video {
- struct ebml_type stereo_mode;
- 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 ebml_type codec_delay;
- struct ebml_type seek_preroll;
- 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;
- int last_valid;
-};
-
-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;
- int last_valid;
- 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;
- int64_t discard_padding;
-};
-
-/* 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, ne_ ## FIELD ## _elements, \
- sizeof(struct FIELD), 0 }
-#define E_SINGLE_MASTER_O(ID, TYPE, STRUCT, FIELD) \
- { #ID, ID, TYPE, offsetof(STRUCT, FIELD), DESC_FLAG_OFFSET, ne_ ## FIELD ## _elements, 0, \
- offsetof(STRUCT, FIELD ## _offset) }
-#define E_SINGLE_MASTER(ID, TYPE, STRUCT, FIELD) \
- { #ID, ID, TYPE, offsetof(STRUCT, FIELD), DESC_FLAG_NONE, ne_ ## 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 ne_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
-};
-
-/* WebM Element Lists */
-static struct ebml_element_desc ne_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 ne_seek_head_elements[] = {
- E_MASTER(ID_SEEK, TYPE_MASTER, struct seek_head, seek),
- E_LAST
-};
-
-static struct ebml_element_desc ne_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 ne_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_FIELD(ID_DISCARD_PADDING, TYPE_INT, struct block_group, discard_padding),
- E_LAST
-};
-
-static struct ebml_element_desc ne_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 ne_video_elements[] = {
- E_FIELD(ID_STEREO_MODE, TYPE_UINT, struct video, stereo_mode),
- 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 ne_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 ne_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_FIELD(ID_CODEC_DELAY, TYPE_UINT, struct track_entry, codec_delay),
- E_FIELD(ID_SEEK_PREROLL, TYPE_UINT, struct track_entry, seek_preroll),
- 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 ne_tracks_elements[] = {
- E_MASTER(ID_TRACK_ENTRY, TYPE_MASTER, struct tracks, track_entry),
- E_LAST
-};
-
-static struct ebml_element_desc ne_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 ne_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 ne_cues_elements[] = {
- E_MASTER(ID_CUE_POINT, TYPE_MASTER, struct cues, cue_point),
- E_LAST
-};
-
-static struct ebml_element_desc ne_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 ne_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 *
-ne_pool_init(void)
-{
- struct pool_ctx * pool;
-
- pool = h_malloc(sizeof(*pool));
- if (!pool)
- abort();
- return pool;
-}
-
-static void
-ne_pool_destroy(struct pool_ctx * pool)
-{
- h_free(pool);
-}
-
-static void *
-ne_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;
-}
-
-static void *
-ne_alloc(size_t size)
-{
- void * p;
-
- p = calloc(1, size);
- if (!p)
- abort();
- return p;
-}
-
-static int
-ne_io_read(nestegg_io * io, void * buffer, size_t length)
-{
- return io->read(buffer, length, io->userdata);
-}
-
-static int
-ne_io_seek(nestegg_io * io, int64_t offset, int whence)
-{
- return io->seek(offset, whence, io->userdata);
-}
-
-static int
-ne_io_read_skip(nestegg_io * io, size_t length)
-{
- size_t get;
- unsigned char buf[8192];
- int r = 1;
-
- while (length > 0) {
- get = length < sizeof(buf) ? length : sizeof(buf);
- r = ne_io_read(io, buf, get);
- if (r != 1)
- break;
- length -= get;
- }
-
- return r;
-}
-
-static int64_t
-ne_io_tell(nestegg_io * io)
-{
- return io->tell(io->userdata);
-}
-
-static int
-ne_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 = ne_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 = ne_io_read(io, &b, 1);
- if (r != 1)
- return r;
- *value <<= 8;
- *value |= b;
- }
-
- return 1;
-}
-
-static int
-ne_read_id(nestegg_io * io, uint64_t * value, uint64_t * length)
-{
- return ne_bare_read_vint(io, value, length, MASK_NONE);
-}
-
-static int
-ne_read_vint(nestegg_io * io, uint64_t * value, uint64_t * length)
-{
- return ne_bare_read_vint(io, value, length, MASK_FIRST_BIT);
-}
-
-static int
-ne_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 = ne_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
-ne_read_uint(nestegg_io * io, uint64_t * val, uint64_t length)
-{
- unsigned char b;
- int r;
-
- if (length == 0 || length > 8)
- return -1;
- r = ne_io_read(io, &b, 1);
- if (r != 1)
- return r;
- *val = b;
- while (--length) {
- r = ne_io_read(io, &b, 1);
- if (r != 1)
- return r;
- *val <<= 8;
- *val |= b;
- }
- return 1;
-}
-
-static int
-ne_read_int(nestegg_io * io, int64_t * val, uint64_t length)
-{
- int r;
- uint64_t uval, base;
-
- r = ne_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
-ne_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 = ne_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
-ne_read_string(nestegg * ctx, char ** val, uint64_t length)
-{
- char * str;
- int r;
- const size_t alloc_size = (size_t)length + 1;
-
- if (length == 0 || length > LIMIT_STRING)
- return -1;
- str = ne_pool_alloc(alloc_size, ctx->alloc_pool);
- r = ne_io_read(ctx->io, (unsigned char *) str, alloc_size - 1);
- if (r != 1)
- return r;
- str[alloc_size - 1] = '\0';
- *val = str;
- return 1;
-}
-
-static int
-ne_read_binary(nestegg * ctx, struct ebml_binary * val, uint64_t length)
-{
- if (length == 0 || length > LIMIT_BINARY)
- return -1;
- val->length = (size_t)length;
- val->data = ne_pool_alloc(val->length, ctx->alloc_pool);
- return ne_io_read(ctx->io, val->data, val->length);
-}
-
-static int
-ne_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
-ne_get_uint32(struct ebml_type type, unsigned int * value)
-{
- uint64_t v;
- if (ne_get_uint(type, &v))
- return -1;
-
- assert((unsigned int)v == v);
-
- *value = (unsigned int)v;
-
- return 0;
-}
-
-static int
-ne_get_float(struct ebml_type type, double * value)
-{
- if (!type.read)
- return -1;
-
- assert(type.type == TYPE_FLOAT);
-
- *value = type.v.f;
-
- return 0;
-}
-
-static int
-ne_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
-ne_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
-ne_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 *
-ne_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
-ne_ctx_push(nestegg * ctx, struct ebml_element_desc * ancestor, void * data)
-{
- struct list_node * item;
-
- item = ne_alloc(sizeof(*item));
- item->previous = ctx->ancestor;
- item->node = ancestor;
- item->data = data;
- ctx->ancestor = item;
-}
-
-static void
-ne_ctx_pop(nestegg * ctx)
-{
- struct list_node * item;
-
- item = ctx->ancestor;
- ctx->ancestor = item->previous;
- free(item);
-}
-
-static int
-ne_ctx_save(nestegg * ctx, struct saved_state * s)
-{
- s->stream_offset = ne_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;
- s->last_valid = ctx->last_valid;
- return 0;
-}
-
-static int
-ne_ctx_restore(nestegg * ctx, struct saved_state * s)
-{
- int r;
-
- r = ne_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;
- ctx->last_valid = s->last_valid;
- return 0;
-}
-
-static int
-ne_peek_element(nestegg * ctx, uint64_t * id, uint64_t * size)
-{
- int r;
-
- if (ctx->last_valid) {
- if (id)
- *id = ctx->last_id;
- if (size)
- *size = ctx->last_size;
- return 1;
- }
-
- r = ne_read_id(ctx->io, &ctx->last_id, NULL);
- if (r != 1)
- return r;
-
- r = ne_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;
-
- ctx->last_valid = 1;
-
- return 1;
-}
-
-static int
-ne_read_element(nestegg * ctx, uint64_t * id, uint64_t * size)
-{
- int r;
-
- r = ne_peek_element(ctx, id, size);
- if (r != 1)
- return r;
-
- ctx->last_valid = 0;
-
- return 1;
-}
-
-static void
-ne_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 = ne_pool_alloc(sizeof(*node), ctx->alloc_pool);
- node->id = desc->id;
- node->data = ne_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);
-
- ne_ctx_push(ctx, desc->children, node->data);
-}
-
-static void
-ne_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);
-
- ne_ctx_push(ctx, desc->children, ctx->ancestor->data + desc->offset);
-}
-
-static int
-ne_read_simple(nestegg * ctx, struct ebml_element_desc * desc, size_t length)
-{
- struct ebml_type * storage;
- int r = 0;
-
- storage = (struct ebml_type *) (ctx->ancestor->data + desc->offset);
-
- if (storage->read) {
- ctx->log(ctx, NESTEGG_LOG_DEBUG, "element %llx (%s) already read, skipping",
- desc->id, desc->name);
- return 0;
- }
-
- storage->type = desc->type;
-
- ctx->log(ctx, NESTEGG_LOG_DEBUG, "element %llx (%s) -> %p (%u)",
- desc->id, desc->name, storage, desc->offset);
-
- switch (desc->type) {
- case TYPE_UINT:
- r = ne_read_uint(ctx->io, &storage->v.u, length);
- break;
- case TYPE_FLOAT:
- r = ne_read_float(ctx->io, &storage->v.f, length);
- break;
- case TYPE_INT:
- r = ne_read_int(ctx->io, &storage->v.i, length);
- break;
- case TYPE_STRING:
- r = ne_read_string(ctx, &storage->v.s, length);
- break;
- case TYPE_BINARY:
- r = ne_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
-ne_parse(nestegg * ctx, struct ebml_element_desc * top_level, int64_t max_offset)
-{
- int r;
- int64_t * data_offset;
- uint64_t id, size, peeked_id;
- struct ebml_element_desc * element;
-
- if (!ctx->ancestor)
- return -1;
-
- for (;;) {
- if (max_offset > 0 && ne_io_tell(ctx->io) >= max_offset) {
- /* Reached end of offset allowed for parsing - return gracefully */
- r = 1;
- break;
- }
- r = ne_peek_element(ctx, &id, &size);
- if (r != 1)
- break;
- peeked_id = id;
-
- element = ne_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 = ne_read_element(ctx, &id, &size);
- if (r != 1)
- break;
- assert(id == peeked_id);
-
- if (element->flags & DESC_FLAG_OFFSET) {
- data_offset = (int64_t *) (ctx->ancestor->data + element->data_offset);
- *data_offset = ne_io_tell(ctx->io);
- if (*data_offset < 0) {
- r = -1;
- break;
- }
- }
-
- if (element->type == TYPE_MASTER) {
- if (element->flags & DESC_FLAG_MULTI)
- ne_read_master(ctx, element);
- else
- ne_read_single_master(ctx, element);
- continue;
- } else {
- r = ne_read_simple(ctx, element, (size_t)size);
- if (r < 0)
- break;
- }
- } else if (ne_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;
- }
- ne_ctx_pop(ctx);
- } else {
- r = ne_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 = ne_io_read_skip(ctx->io, (size_t)size);
- if (r != 1)
- break;
- }
- }
-
- if (r != 1)
- while (ctx->ancestor)
- ne_ctx_pop(ctx);
-
- return r;
-}
-
-static uint64_t
-ne_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
-ne_read_xiph_lace_value(nestegg_io * io, uint64_t * value, size_t * consumed)
-{
- int r;
- uint64_t lace;
-
- r = ne_read_uint(io, &lace, 1);
- if (r != 1)
- return r;
- *consumed += 1;
-
- *value = lace;
- while (lace == 255) {
- r = ne_read_uint(io, &lace, 1);
- if (r != 1)
- return r;
- *consumed += 1;
- *value += lace;
- }
-
- return 1;
-}
-
-static int
-ne_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 = ne_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
-ne_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 = ne_read_vint(io, &lace, &length);
- if (r != 1)
- return r;
- assert(length <= 8);
- *read += (size_t)length;
-
- sizes[i] = lace;
- sum = sizes[i];
-
- i += 1;
- n -= 1;
-
- while (--n) {
- r = ne_read_svint(io, &slace, &length);
- if (r != 1)
- return r;
- assert(length <= 8);
- *read += (size_t)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
-ne_get_timecode_scale(nestegg * ctx)
-{
- uint64_t scale;
-
- if (ne_get_uint(ctx->segment.info.timecode_scale, &scale) != 0)
- scale = 1000000;
-
- return scale;
-}
-
-static int
-ne_map_track_number_to_index(nestegg * ctx,
- unsigned int track_number,
- unsigned int * track_index)
-{
- struct ebml_list_node * node;
- struct track_entry * t_entry;
- uint64_t t_number = 0;
-
- if (!track_index)
- return -1;
- *track_index = 0;
-
- if (track_number == 0)
- return -1;
-
- node = ctx->segment.tracks.track_entry.head;
- while (node) {
- assert(node->id == ID_TRACK_ENTRY);
- t_entry = node->data;
- if (ne_get_uint(t_entry->number, &t_number) != 0)
- return -1;
- if (t_number == track_number)
- return 0;
- *track_index += 1;
- node = node->next;
- }
-
- return -1;
-}
-
-static struct track_entry *
-ne_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
-ne_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;
- const int track_scale = 1;
- uint64_t track_number, length, frame_sizes[256], cluster_tc, flags, frames, tc_scale, total;
- unsigned int i, lacing, track;
- size_t consumed = 0;
-
- *data = NULL;
-
- if (block_size > LIMIT_BLOCK)
- return -1;
-
- r = ne_read_vint(ctx->io, &track_number, &length);
- if (r != 1)
- return r;
-
- if (track_number == 0 || (unsigned int)track_number != track_number)
- return -1;
-
- assert(length <= 8);
- consumed += (size_t)length;
-
- r = ne_read_int(ctx->io, &timecode, 2);
- if (r != 1)
- return r;
-
- consumed += 2;
-
- r = ne_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 & BLOCK_FLAGS_LACING) >> 1;
-
- switch (lacing) {
- case LACING_NONE:
- frames = 1;
- break;
- case LACING_XIPH:
- case LACING_FIXED:
- case LACING_EBML:
- r = ne_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 = ne_read_xiph_lacing(ctx->io, (size_t)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 = ne_read_ebml_lacing(ctx->io, (size_t)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;
-
- if (ne_map_track_number_to_index(ctx, (unsigned int)track_number, &track) != 0)
- return -1;
-
- entry = ne_find_track_entry(ctx, track);
- if (!entry)
- return -1;
-
- tc_scale = ne_get_timecode_scale(ctx);
-
- assert(ctx->segment.cluster.tail->id == ID_CLUSTER);
- cluster = ctx->segment.cluster.tail->data;
- if (ne_get_uint(cluster->timecode, &cluster_tc) != 0)
- return -1;
-
- abs_timecode = timecode + cluster_tc;
- if (abs_timecode < 0)
- return -1;
-
- pkt = ne_alloc(sizeof(*pkt));
- pkt->track = track;
- 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 = ne_alloc(sizeof(*f));
- f->length = (size_t)frame_sizes[i];
- f->data = ne_alloc(f->length);
- r = ne_io_read(ctx->io, f->data, f->length);
- 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 int
-ne_read_discard_padding(nestegg * ctx, nestegg_packet * pkt)
-{
- int r;
- uint64_t id, size;
- struct ebml_element_desc * element;
- struct ebml_type * storage;
-
- r = ne_peek_element(ctx, &id, &size);
- if (r != 1)
- return r;
-
- if (id != ID_DISCARD_PADDING)
- return 1;
-
- element = ne_find_element(id, ctx->ancestor->node);
- if (!element)
- return 1;
-
- assert((size_t)size == size);
- r = ne_read_simple(ctx, element, (size_t)size);
- if (r != 1)
- return r;
- storage = (struct ebml_type *) (ctx->ancestor->data + element->offset);
- pkt->discard_padding = storage->v.i;
-
- return 1;
-}
-
-
-static uint64_t
-ne_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 *
-ne_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 (ne_get_binary(s->id, &binary_id) == 0 &&
- ne_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_track_positions *
-ne_find_cue_position_for_track(nestegg * ctx, struct ebml_list_node * node, unsigned int track)
-{
- struct cue_track_positions * pos = NULL;
- unsigned int track_number;
- unsigned int t;
-
- while (node) {
- assert(node->id == ID_CUE_TRACK_POSITIONS);
- pos = node->data;
- if (ne_get_uint32(pos->track, &track_number) != 0)
- return NULL;
-
- if (ne_map_track_number_to_index(ctx, track_number, &t) != 0)
- return NULL;
-
- if (t == track)
- return pos;
-
- node = node->next;
- }
-
- return NULL;
-}
-
-static struct cue_point *
-ne_find_cue_point_for_tstamp(nestegg * ctx, struct ebml_list_node * cue_point, unsigned int track, 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 (ne_get_uint(c->time, &time) == 0 && time * scale > tstamp)
- break;
-
- if (ne_find_cue_position_for_track(ctx, c->cue_track_positions.head, track) != NULL)
- prev = c;
-
- cue_point = cue_point->next;
- }
-
- return prev;
-}
-
-static int
-ne_is_suspend_element(uint64_t id)
-{
- if (id == ID_SIMPLE_BLOCK || id == ID_BLOCK)
- return 1;
- return 0;
-}
-
-static void
-ne_null_log_callback(nestegg * ctx, unsigned int severity, char const * fmt, ...)
-{
- if (ctx && severity && fmt)
- return;
-}
-
-static int
-ne_init_cue_points(nestegg * ctx, int64_t max_offset)
-{
- int r;
- struct ebml_list_node * node = ctx->segment.cues.cue_point.head;
- struct seek * found;
- uint64_t seek_pos, id;
- struct saved_state state;
-
- /* If there are no cues loaded, check for cues element in the seek head
- and load it. */
- if (!node) {
- found = ne_find_seek_for_id(ctx->segment.seek_head.head, ID_CUES);
- if (!found)
- return -1;
-
- if (ne_get_uint(found->position, &seek_pos) != 0)
- return -1;
-
- /* Save old parser state. */
- r = ne_ctx_save(ctx, &state);
- if (r != 0)
- return -1;
-
- /* Seek and set up parser state for segment-level element (Cues). */
- r = ne_io_seek(ctx->io, ctx->segment_offset + seek_pos, NESTEGG_SEEK_SET);
- if (r != 0)
- return -1;
- ctx->last_valid = 0;
-
- r = ne_read_element(ctx, &id, NULL);
- if (r != 1)
- return -1;
-
- if (id != ID_CUES)
- return -1;
-
- ctx->ancestor = NULL;
- ne_ctx_push(ctx, ne_top_level_elements, ctx);
- ne_ctx_push(ctx, ne_segment_elements, &ctx->segment);
- ne_ctx_push(ctx, ne_cues_elements, &ctx->segment.cues);
- /* parser will run until end of cues element. */
- ctx->log(ctx, NESTEGG_LOG_DEBUG, "seek: parsing cue elements");
- r = ne_parse(ctx, ne_cues_elements, max_offset);
- while (ctx->ancestor)
- ne_ctx_pop(ctx);
-
- /* Reset parser state to original state and seek back to old position. */
- if (ne_ctx_restore(ctx, &state) != 0)
- return -1;
-
- if (r < 0)
- return -1;
-
- node = ctx->segment.cues.cue_point.head;
- if (!node)
- return -1;
- }
-
- return 0;
-}
-
-/* Three functions that implement the nestegg_io interface, operating on a
- * sniff_buffer. */
-struct sniff_buffer {
- unsigned char const * buffer;
- size_t length;
- int64_t offset;
-};
-
-static int
-ne_buffer_read(void * buffer, size_t length, void * user_data)
-{
- struct sniff_buffer * sb = user_data;
-
- int rv = 1;
- size_t available = sb->length - (size_t)sb->offset;
-
- if (available < length)
- return 0;
-
- memcpy(buffer, sb->buffer + sb->offset, length);
- sb->offset += length;
-
- return rv;
-}
-
-static int
-ne_buffer_seek(int64_t offset, int whence, void * user_data)
-{
- struct sniff_buffer * sb = user_data;
- int64_t o = sb->offset;
-
- switch(whence) {
- case NESTEGG_SEEK_SET:
- o = offset;
- break;
- case NESTEGG_SEEK_CUR:
- o += offset;
- break;
- case NESTEGG_SEEK_END:
- o = sb->length + offset;
- break;
- }
-
- if (o < 0 || o > (int64_t) sb->length)
- return -1;
-
- sb->offset = o;
- return 0;
-}
-
-static int64_t
-ne_buffer_tell(void * user_data)
-{
- struct sniff_buffer * sb = user_data;
- return sb->offset;
-}
-
-static int
-ne_match_webm(nestegg_io io, int64_t max_offset)
-{
- int r;
- uint64_t id;
- char * doctype;
- nestegg * ctx;
-
- if (!(io.read && io.seek && io.tell))
- return -1;
-
- ctx = ne_alloc(sizeof(*ctx));
-
- ctx->io = ne_alloc(sizeof(*ctx->io));
- *ctx->io = io;
- ctx->alloc_pool = ne_pool_init();
- ctx->log = ne_null_log_callback;
-
- r = ne_peek_element(ctx, &id, NULL);
- if (r != 1) {
- nestegg_destroy(ctx);
- return 0;
- }
-
- if (id != ID_EBML) {
- nestegg_destroy(ctx);
- return 0;
- }
-
- ne_ctx_push(ctx, ne_top_level_elements, ctx);
-
- /* we don't check the return value of ne_parse, that might fail because
- * max_offset is not on a valid element end point. We only want to check
- * the EBML ID and that the doctype is "webm". */
- ne_parse(ctx, NULL, max_offset);
-
- if (ne_get_string(ctx->ebml.doctype, &doctype) != 0 ||
- strcmp(doctype, "webm") != 0) {
- nestegg_destroy(ctx);
- return 0;
- }
-
- nestegg_destroy(ctx);
-
- return 1;
-}
-
-int
-nestegg_init(nestegg ** context, nestegg_io io, nestegg_log callback, int64_t max_offset)
-{
- int r;
- uint64_t id, version, docversion;
- struct ebml_list_node * track;
- char * doctype;
- nestegg * ctx;
-
- if (!(io.read && io.seek && io.tell))
- return -1;
-
- ctx = ne_alloc(sizeof(*ctx));
-
- ctx->io = ne_alloc(sizeof(*ctx->io));
- *ctx->io = io;
- ctx->log = callback;
- ctx->alloc_pool = ne_pool_init();
-
- if (!ctx->log)
- ctx->log = ne_null_log_callback;
-
- r = ne_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);
-
- ne_ctx_push(ctx, ne_top_level_elements, ctx);
-
- r = ne_parse(ctx, NULL, max_offset);
-
- if (r != 1) {
- nestegg_destroy(ctx);
- return -1;
- }
-
- if (ne_get_uint(ctx->ebml.ebml_read_version, &version) != 0)
- version = 1;
- if (version != 1) {
- nestegg_destroy(ctx);
- return -1;
- }
-
- if (ne_get_string(ctx->ebml.doctype, &doctype) != 0)
- doctype = "matroska";
- if (strcmp(doctype, "webm") != 0) {
- nestegg_destroy(ctx);
- return -1;
- }
-
- if (ne_get_uint(ctx->ebml.doctype_read_version, &docversion) != 0)
- docversion = 1;
- if (docversion < 1 || docversion > 2) {
- nestegg_destroy(ctx);
- return -1;
- }
-
- if (!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)
- ne_ctx_pop(ctx);
- ne_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 (ne_get_float(ctx->segment.info.duration, &unscaled_duration) != 0)
- return -1;
-
- tc_scale = ne_get_timecode_scale(ctx);
-
- *duration = (uint64_t) (unscaled_duration * tc_scale);
- return 0;
-}
-
-int
-nestegg_tstamp_scale(nestegg * ctx, uint64_t * scale)
-{
- *scale = ne_get_timecode_scale(ctx);
- return 0;
-}
-
-int
-nestegg_track_count(nestegg * ctx, unsigned int * tracks)
-{
- *tracks = ctx->track_count;
- return 0;
-}
-
-int
-nestegg_get_cue_point(nestegg * ctx, unsigned int cluster_num, int64_t max_offset,
- int64_t * start_pos, int64_t * end_pos, uint64_t * tstamp)
-{
- int range_obtained = 0;
- unsigned int cluster_count = 0;
- struct cue_point * cue_point;
- struct cue_track_positions * pos;
- uint64_t seek_pos, track_number, tc_scale, time;
- struct ebml_list_node * cues_node = ctx->segment.cues.cue_point.head;
- struct ebml_list_node * cue_pos_node = NULL;
- unsigned int track = 0, track_count = 0, track_index;
-
- if (!start_pos || !end_pos || !tstamp)
- return -1;
-
- /* Initialise return values */
- *start_pos = -1;
- *end_pos = -1;
- *tstamp = 0;
-
- if (!cues_node) {
- ne_init_cue_points(ctx, max_offset);
- cues_node = ctx->segment.cues.cue_point.head;
- /* Verify cues have been added to context. */
- if (!cues_node)
- return -1;
- }
-
- nestegg_track_count(ctx, &track_count);
-
- tc_scale = ne_get_timecode_scale(ctx);
-
- while (cues_node && !range_obtained) {
- assert(cues_node->id == ID_CUE_POINT);
- cue_point = cues_node->data;
- cue_pos_node = cue_point->cue_track_positions.head;
- while (cue_pos_node) {
- assert(cue_pos_node->id == ID_CUE_TRACK_POSITIONS);
- pos = cue_pos_node->data;
- for (track = 0; track < track_count; track++) {
- if (ne_get_uint(pos->track, &track_number) != 0)
- return -1;
-
- if (ne_map_track_number_to_index(ctx, (unsigned int)track_number, &track_index) != 0)
- return -1;
-
- if (track_index == track) {
- if (ne_get_uint(pos->cluster_position, &seek_pos) != 0)
- return -1;
- if (cluster_count == cluster_num) {
- *start_pos = ctx->segment_offset+seek_pos;
- if (ne_get_uint(cue_point->time, &time) != 0)
- return -1;
- *tstamp = time * tc_scale;
- } else if (cluster_count == cluster_num+1) {
- *end_pos = (ctx->segment_offset+seek_pos)-1;
- range_obtained = 1;
- break;
- }
- cluster_count++;
- }
- }
- cue_pos_node = cue_pos_node->next;
- }
- cues_node = cues_node->next;
- }
-
- return 0;
-}
-
-int
-nestegg_offset_seek(nestegg * ctx, uint64_t offset)
-{
- int r;
-
- /* Seek and set up parser state for segment-level element (Cluster). */
- r = ne_io_seek(ctx->io, offset, NESTEGG_SEEK_SET);
- if (r != 0)
- return -1;
- ctx->last_valid = 0;
-
- while (ctx->ancestor)
- ne_ctx_pop(ctx);
-
- ne_ctx_push(ctx, ne_top_level_elements, ctx);
- ne_ctx_push(ctx, ne_segment_elements, &ctx->segment);
-
- 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;
- uint64_t seek_pos, tc_scale;
-
- /* If there are no cues loaded, check for cues element in the seek head
- and load it. */
- if (!ctx->segment.cues.cue_point.head) {
- r = ne_init_cue_points(ctx, -1);
- if (r != 0)
- return -1;
- }
-
- tc_scale = ne_get_timecode_scale(ctx);
-
- cue_point = ne_find_cue_point_for_tstamp(ctx, ctx->segment.cues.cue_point.head,
- track, tc_scale, tstamp);
- if (!cue_point)
- return -1;
-
- pos = ne_find_cue_position_for_track(ctx, cue_point->cue_track_positions.head, track);
- if (pos == NULL)
- return -1;
-
- if (ne_get_uint(pos->cluster_position, &seek_pos) != 0)
- return -1;
-
- /* Seek and set up parser state for segment-level element (Cluster). */
- r = nestegg_offset_seek(ctx, ctx->segment_offset + seek_pos);
- ctx->log(ctx, NESTEGG_LOG_DEBUG, "seek: parsing cluster elements");
- r = ne_parse(ctx, NULL, -1);
- if (r != 1)
- return -1;
-
- if (!ne_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 = ne_find_track_entry(ctx, track);
- if (!entry)
- return -1;
-
- if (ne_get_uint(entry->type, &type) != 0)
- return -1;
-
- if (type & TRACK_TYPE_VIDEO)
- return NESTEGG_TRACK_VIDEO;
-
- if (type & TRACK_TYPE_AUDIO)
- return NESTEGG_TRACK_AUDIO;
-
- return -1;
-}
-
-int
-nestegg_track_codec_id(nestegg * ctx, unsigned int track)
-{
- char * codec_id;
- struct track_entry * entry;
-
- entry = ne_find_track_entry(ctx, track);
- if (!entry)
- return -1;
-
- if (ne_get_string(entry->codec_id, &codec_id) != 0)
- return -1;
-
- if (strcmp(codec_id, TRACK_ID_VP8) == 0)
- return NESTEGG_CODEC_VP8;
-
- if (strcmp(codec_id, TRACK_ID_VP9) == 0)
- return NESTEGG_CODEC_VP9;
-
- if (strcmp(codec_id, TRACK_ID_VORBIS) == 0)
- return NESTEGG_CODEC_VORBIS;
-
- if (strcmp(codec_id, TRACK_ID_OPUS) == 0)
- return NESTEGG_CODEC_OPUS;
-
- 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 = ne_find_track_entry(ctx, track);
- if (!entry)
- return -1;
-
- if (nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_VORBIS)
- return -1;
-
- if (ne_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 = ne_find_track_entry(ctx, track);
- if (!entry)
- return -1;
-
- if (nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_VORBIS
- && nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_OPUS)
- return -1;
-
- if (ne_get_binary(entry->codec_private, &codec_private) != 0)
- return -1;
-
- if (nestegg_track_codec_id(ctx, track) == NESTEGG_CODEC_VORBIS) {
- p = codec_private.data;
- count = *p++ + 1;
-
- if (count > 3)
- return -1;
-
- i = 0;
- total = 0;
- while (--count) {
- sizes[i] = ne_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 = (size_t)sizes[item];
- } else {
- *data = codec_private.data;
- *length = codec_private.length;
- }
-
- return 0;
-}
-
-int
-nestegg_track_video_params(nestegg * ctx, unsigned int track,
- nestegg_video_params * params)
-{
- struct track_entry * entry;
- unsigned int value;
-
- memset(params, 0, sizeof(*params));
-
- entry = ne_find_track_entry(ctx, track);
- if (!entry)
- return -1;
-
- if (nestegg_track_type(ctx, track) != NESTEGG_TRACK_VIDEO)
- return -1;
-
- value = 0;
- ne_get_uint32(entry->video.stereo_mode, &value);
- if (value <= NESTEGG_VIDEO_STEREO_TOP_BOTTOM ||
- value == NESTEGG_VIDEO_STEREO_RIGHT_LEFT)
- params->stereo_mode = value;
-
- if (ne_get_uint32(entry->video.pixel_width, &value) != 0)
- return -1;
- params->width = value;
-
- if (ne_get_uint32(entry->video.pixel_height, &value) != 0)
- return -1;
- params->height = value;
-
- value = 0;
- ne_get_uint32(entry->video.pixel_crop_bottom, &value);
- params->crop_bottom = value;
-
- value = 0;
- ne_get_uint32(entry->video.pixel_crop_top, &value);
- params->crop_top = value;
-
- value = 0;
- ne_get_uint32(entry->video.pixel_crop_left, &value);
- params->crop_left = value;
-
- value = 0;
- ne_get_uint32(entry->video.pixel_crop_right, &value);
- params->crop_right = value;
-
- value = params->width;
- ne_get_uint32(entry->video.display_width, &value);
- params->display_width = value;
-
- value = params->height;
- ne_get_uint32(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;
- unsigned int value;
-
- memset(params, 0, sizeof(*params));
-
- entry = ne_find_track_entry(ctx, track);
- if (!entry)
- return -1;
-
- if (nestegg_track_type(ctx, track) != NESTEGG_TRACK_AUDIO)
- return -1;
-
- params->rate = 8000;
- ne_get_float(entry->audio.sampling_frequency, ¶ms->rate);
-
- value = 1;
- ne_get_uint32(entry->audio.channels, &value);
- params->channels = value;
-
- value = 16;
- ne_get_uint32(entry->audio.bit_depth, &value);
- params->depth = value;
-
- value = 0;
- ne_get_uint32(entry->codec_delay, &value);
- params->codec_delay = value;
-
- value = 0;
- ne_get_uint32(entry->seek_preroll, &value);
- params->seek_preroll = value;
-
- return 0;
-}
-
-int
-nestegg_read_packet(nestegg * ctx, nestegg_packet ** pkt)
-{
- int r;
- uint64_t id, size;
-
- *pkt = NULL;
-
- for (;;) {
- r = ne_peek_element(ctx, &id, &size);
- if (r != 1)
- return r;
-
- /* Any DESC_FLAG_SUSPEND fields must be handled here. */
- if (ne_is_suspend_element(id)) {
- r = ne_read_element(ctx, &id, &size);
- if (r != 1)
- return r;
-
- /* The only DESC_FLAG_SUSPEND fields are Blocks and SimpleBlocks, which we
- handle directly. */
- r = ne_read_block(ctx, id, size, pkt);
- if (r != 1)
- return r;
-
- r = ne_read_discard_padding(ctx, *pkt);
- if (r != 1)
- return r;
-
- return r;
- }
-
- r = ne_parse(ctx, NULL, -1);
- 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 = (unsigned int)pkt->track;
- return 0;
-}
-
-int
-nestegg_packet_tstamp(nestegg_packet * pkt, uint64_t * tstamp)
-{
- *tstamp = pkt->timecode;
- return 0;
-}
-
-int
-nestegg_packet_discard_padding(nestegg_packet * pkt, int64_t * discard_padding)
-{
- *discard_padding = pkt->discard_padding;
- 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;
-}
-
-int
-nestegg_has_cues(nestegg * ctx)
-{
- return ctx->segment.cues.cue_point.head ||
- ne_find_seek_for_id(ctx->segment.seek_head.head, ID_CUES);
-}
-
-int
-nestegg_sniff(unsigned char const * buffer, size_t length)
-{
- nestegg_io io;
- struct sniff_buffer user_data;
-
- user_data.buffer = buffer;
- user_data.length = length;
- user_data.offset = 0;
-
- io.read = ne_buffer_read;
- io.seek = ne_buffer_seek;
- io.tell = ne_buffer_tell;
- io.userdata = &user_data;
- return ne_match_webm(io, length);
-}
-
+++ /dev/null
-/*
- * Copyright © 2010 Mozilla Foundation
- *
- * This program is made available under an ISC-style license. See the
- * accompanying file LICENSE for details.
- */
-#include <assert.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include "nestegg/nestegg.h"
-
-#undef DEBUG
-#define SEEK_TEST
-
-static int
-stdio_read(void * p, size_t length, void * file)
-{
- size_t r;
- FILE * fp = file;
-
- r = fread(p, length, 1, fp);
- if (r == 0 && feof(fp))
- return 0;
- return r == 0 ? -1 : 1;
-}
-
-static int
-stdio_seek(int64_t offset, int whence, void * file)
-{
- FILE * fp = file;
- return fseek(fp, offset, whence);
-}
-
-static int64_t
-stdio_tell(void * fp)
-{
- return ftell(fp);
-}
-
-static void
-log_callback(nestegg * ctx, unsigned int severity, char const * fmt, ...)
-{
- va_list ap;
- char const * sev = NULL;
-
-#if !defined(DEBUG)
- if (severity < NESTEGG_LOG_WARNING)
- return;
-#endif
-
- switch (severity) {
- case NESTEGG_LOG_DEBUG:
- sev = "debug: ";
- break;
- case NESTEGG_LOG_WARNING:
- sev = "warning: ";
- break;
- case NESTEGG_LOG_CRITICAL:
- sev = "critical:";
- break;
- default:
- sev = "unknown: ";
- }
-
- fprintf(stderr, "%p %s ", (void *) ctx, sev);
-
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
-
- fprintf(stderr, "\n");
-}
-
-int
-main(int argc, char * argv[])
-{
- FILE * fp;
- int r, type;
- nestegg * ctx;
- nestegg_audio_params aparams;
- nestegg_packet * pkt;
- nestegg_video_params vparams;
- size_t length, size;
- uint64_t duration, tstamp, pkt_tstamp;
- unsigned char * codec_data, * ptr;
- unsigned int cnt, i, j, track, tracks, pkt_cnt, pkt_track;
- unsigned int data_items = 0;
- nestegg_io io = {
- stdio_read,
- stdio_seek,
- stdio_tell,
- NULL
- };
-
- if (argc != 2)
- return EXIT_FAILURE;
-
- fp = fopen(argv[1], "rb");
- if (!fp)
- return EXIT_FAILURE;
-
- io.userdata = fp;
-
- ctx = NULL;
- r = nestegg_init(&ctx, io, log_callback, -1);
- if (r != 0)
- return EXIT_FAILURE;
-
- nestegg_track_count(ctx, &tracks);
- nestegg_duration(ctx, &duration);
-#if defined(DEBUG)
- fprintf(stderr, "media has %u tracks and duration %fs\n", tracks, duration / 1e9);
-#endif
-
- for (i = 0; i < tracks; ++i) {
- type = nestegg_track_type(ctx, i);
-#if defined(DEBUG)
- fprintf(stderr, "track %u: type: %d codec: %d", i,
- type, nestegg_track_codec_id(ctx, i));
-#endif
- nestegg_track_codec_data_count(ctx, i, &data_items);
- for (j = 0; j < data_items; ++j) {
- nestegg_track_codec_data(ctx, i, j, &codec_data, &length);
-#if defined(DEBUG)
- fprintf(stderr, " (%p, %u)", codec_data, (unsigned int) length);
-#endif
- }
- if (type == NESTEGG_TRACK_VIDEO) {
- nestegg_track_video_params(ctx, i, &vparams);
-#if defined(DEBUG)
- fprintf(stderr, " video: %ux%u (d: %ux%u %ux%ux%ux%u)",
- vparams.width, vparams.height,
- vparams.display_width, vparams.display_height,
- vparams.crop_top, vparams.crop_left, vparams.crop_bottom, vparams.crop_right);
-#endif
- } else if (type == NESTEGG_TRACK_AUDIO) {
- nestegg_track_audio_params(ctx, i, &aparams);
-#if defined(DEBUG)
- fprintf(stderr, " audio: %.2fhz %u bit %u channels",
- aparams.rate, aparams.depth, aparams.channels);
-#endif
- }
-#if defined(DEBUG)
- fprintf(stderr, "\n");
-#endif
- }
-
-#if defined(SEEK_TEST)
-#if defined(DEBUG)
- fprintf(stderr, "seek to middle\n");
-#endif
- r = nestegg_track_seek(ctx, 0, duration / 2);
- if (r == 0) {
-#if defined(DEBUG)
- fprintf(stderr, "middle ");
-#endif
- r = nestegg_read_packet(ctx, &pkt);
- if (r == 1) {
- nestegg_packet_track(pkt, &track);
- nestegg_packet_count(pkt, &cnt);
- nestegg_packet_tstamp(pkt, &tstamp);
-#if defined(DEBUG)
- fprintf(stderr, "* t %u pts %f frames %u\n", track, tstamp / 1e9, cnt);
-#endif
- nestegg_free_packet(pkt);
- } else {
-#if defined(DEBUG)
- fprintf(stderr, "middle seek failed\n");
-#endif
- }
- }
-
-#if defined(DEBUG)
- fprintf(stderr, "seek to ~end\n");
-#endif
- r = nestegg_track_seek(ctx, 0, duration - (duration / 10));
- if (r == 0) {
-#if defined(DEBUG)
- fprintf(stderr, "end ");
-#endif
- r = nestegg_read_packet(ctx, &pkt);
- if (r == 1) {
- nestegg_packet_track(pkt, &track);
- nestegg_packet_count(pkt, &cnt);
- nestegg_packet_tstamp(pkt, &tstamp);
-#if defined(DEBUG)
- fprintf(stderr, "* t %u pts %f frames %u\n", track, tstamp / 1e9, cnt);
-#endif
- nestegg_free_packet(pkt);
- } else {
-#if defined(DEBUG)
- fprintf(stderr, "end seek failed\n");
-#endif
- }
- }
-
-#if defined(DEBUG)
- fprintf(stderr, "seek to ~start\n");
-#endif
- r = nestegg_track_seek(ctx, 0, duration / 10);
- if (r == 0) {
-#if defined(DEBUG)
- fprintf(stderr, "start ");
-#endif
- r = nestegg_read_packet(ctx, &pkt);
- if (r == 1) {
- nestegg_packet_track(pkt, &track);
- nestegg_packet_count(pkt, &cnt);
- nestegg_packet_tstamp(pkt, &tstamp);
-#if defined(DEBUG)
- fprintf(stderr, "* t %u pts %f frames %u\n", track, tstamp / 1e9, cnt);
-#endif
- nestegg_free_packet(pkt);
- } else {
-#if defined(DEBUG)
- fprintf(stderr, "start seek failed\n");
-#endif
- }
- }
-#endif
-
- while (nestegg_read_packet(ctx, &pkt) > 0) {
- nestegg_packet_track(pkt, &pkt_track);
- nestegg_packet_count(pkt, &pkt_cnt);
- nestegg_packet_tstamp(pkt, &pkt_tstamp);
-
-#if defined(DEBUG)
- fprintf(stderr, "t %u pts %f frames %u: ", pkt_track, pkt_tstamp / 1e9, pkt_cnt);
-#endif
-
- for (i = 0; i < pkt_cnt; ++i) {
- nestegg_packet_data(pkt, i, &ptr, &size);
-#if defined(DEBUG)
- fprintf(stderr, "%u ", (unsigned int) size);
-#endif
- }
-#if defined(DEBUG)
- fprintf(stderr, "\n");
-#endif
-
- nestegg_free_packet(pkt);
- }
-
- nestegg_destroy(ctx);
- fclose(fp);
-
- return EXIT_SUCCESS;
-}
for f in $(git diff HEAD^ --name-only -M90 --diff-filter=AM); do
case "$f" in
third_party/*) continue;;
- nestegg/*) continue;;
esac
vpx_style "$f"
done