summaryrefslogtreecommitdiff
path: root/libmkv
diff options
context:
space:
mode:
Diffstat (limited to 'libmkv')
-rw-r--r--libmkv/EbmlBufferWriter.c60
-rw-r--r--libmkv/EbmlBufferWriter.h21
-rw-r--r--libmkv/EbmlIDs.h231
-rw-r--r--libmkv/EbmlWriter.c160
-rw-r--r--libmkv/EbmlWriter.h38
-rw-r--r--libmkv/Makefile25
-rw-r--r--libmkv/WebMElement.c220
-rw-r--r--libmkv/WebMElement.h35
-rw-r--r--libmkv/testlibmkv.c63
9 files changed, 853 insertions, 0 deletions
diff --git a/libmkv/EbmlBufferWriter.c b/libmkv/EbmlBufferWriter.c
new file mode 100644
index 000000000..d9b04a81a
--- /dev/null
+++ b/libmkv/EbmlBufferWriter.c
@@ -0,0 +1,60 @@
+//#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;
+
+ unsigned long cbWritten;
+ 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;
+}
+
diff --git a/libmkv/EbmlBufferWriter.h b/libmkv/EbmlBufferWriter.h
new file mode 100644
index 000000000..ba0a9b3ab
--- /dev/null
+++ b/libmkv/EbmlBufferWriter.h
@@ -0,0 +1,21 @@
+#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
diff --git a/libmkv/EbmlIDs.h b/libmkv/EbmlIDs.h
new file mode 100644
index 000000000..271990827
--- /dev/null
+++ b/libmkv/EbmlIDs.h
@@ -0,0 +1,231 @@
+// 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,
+ 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 \ No newline at end of file
diff --git a/libmkv/EbmlWriter.c b/libmkv/EbmlWriter.c
new file mode 100644
index 000000000..46d2dd84d
--- /dev/null
+++ b/libmkv/EbmlWriter.c
@@ -0,0 +1,160 @@
+// 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>
+
+
+void Ebml_WriteLen(EbmlGlobal *glob, long long val)
+{
+ //TODO check and make sure we are not > than 0x0100000000000000LLU
+ unsigned char size = 8; //size in bytes to output
+ unsigned long long minVal = 0x00000000000000ffLLU; //mask to compare for byte size
+
+ for (size = 1; size < 8; size ++)
+ {
+ if (val < minVal)
+ break;
+
+ minVal = (minVal << 7);
+ }
+
+ val |= (0x000000000000080LLU << ((size - 1) * 7));
+
+ Ebml_Serialize(glob, (void *) &val, size);
+}
+
+void Ebml_WriteString(EbmlGlobal *glob, const char *str)
+{
+ const size_t size_ = strlen(str);
+ const unsigned long long 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, 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 unsigned long long size = strlen;
+
+ Ebml_WriteLen(glob, size);
+ Ebml_Write(glob, wstr, size);
+}
+
+void Ebml_WriteID(EbmlGlobal *glob, unsigned long class_id)
+{
+ if (class_id >= 0x01000000)
+ Ebml_Serialize(glob, (void *)&class_id, 4);
+ else if (class_id >= 0x00010000)
+ Ebml_Serialize(glob, (void *)&class_id, 3);
+ else if (class_id >= 0x00000100)
+ Ebml_Serialize(glob, (void *)&class_id, 2);
+ else
+ Ebml_Serialize(glob, (void *)&class_id, 1);
+}
+void Ebml_SerializeUnsigned64(EbmlGlobal *glob, unsigned long class_id, UInt64 ui)
+{
+ unsigned char sizeSerialized = 8 | 0x80;
+ Ebml_WriteID(glob, class_id);
+ Ebml_Serialize(glob, &sizeSerialized, 1);
+ Ebml_Serialize(glob, &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;
+ Ebml_WriteID(glob, class_id);
+ unsigned long minVal;
+ 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, 1);
+ unsigned int _s = size;
+ Ebml_Serialize(glob, &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 & 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)
+{
+ Ebml_WriteID(glob, class_id);
+ unsigned char len = 0x88;
+ Ebml_Serialize(glob, &len, 1);
+ Ebml_Serialize(glob, &d, 8);
+}
+
+void Ebml_WriteSigned16(EbmlGlobal *glob, short val)
+{
+ signed long out = ((val & 0x003FFFFF) | 0x00200000) << 8;
+ Ebml_Serialize(glob, &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)
+{
+ unsigned char size = 4;
+ Ebml_WriteID(glob, class_id);
+ Ebml_WriteLen(glob, data_length);
+ Ebml_Write(glob, data, data_length);
+}
+
+void Ebml_WriteVoid(EbmlGlobal *glob, unsigned long vSize)
+{
+ Ebml_WriteID(glob, 0xEC);
+ unsigned char tmp = 0;
+ unsigned long i = 0;
+ Ebml_WriteLen(glob, vSize);
+
+ for (i = 0; i < vSize; i++)
+ {
+ Ebml_Write(glob, &tmp, 1);
+ }
+}
+
+//TODO Serialize Date
diff --git a/libmkv/EbmlWriter.h b/libmkv/EbmlWriter.h
new file mode 100644
index 000000000..e149f397e
--- /dev/null
+++ b/libmkv/EbmlWriter.h
@@ -0,0 +1,38 @@
+#ifndef EBMLWRITER_HPP
+#define EBMLWRITER_HPP
+
+// 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.
+
+
+//If you wish a different writer simply replace this
+//note: you must define write and serialize functions as well as your own EBML_GLOBAL
+#include <stddef.h>
+#include "EbmlBufferWriter.h"
+//These functions MUST be implemented
+void Ebml_Serialize(EbmlGlobal *glob, const void *, unsigned long);
+void Ebml_Write(EbmlGlobal *glob, const void *, unsigned long);
+/////
+
+
+void Ebml_WriteLen(EbmlGlobal *glob, long long 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 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
diff --git a/libmkv/Makefile b/libmkv/Makefile
new file mode 100644
index 000000000..b53377b21
--- /dev/null
+++ b/libmkv/Makefile
@@ -0,0 +1,25 @@
+#Variables
+CC=gcc
+LINKER=gcc
+FLAGS=
+
+
+#Build Targets
+EbmlWriter.o: EbmlWriter.c EbmlWriter.h
+ $(CC) $(FLAGS) -c EbmlWriter.c
+
+EbmlBufferWriter.o: EbmlBufferWriter.c EbmlBufferWriter.h
+ $(CC) $(FLAGS) -c EbmlBufferWriter.c
+
+MkvElement.o: MkvElement.c WebMElement.h
+ $(CC) $(FLAGS) -c MkvElement.c
+
+testlibmkv.o: testlibmkv.c
+ $(CC) $(FLAGS) -c testlibmkv.c
+
+testlibmkv: testlibmkv.o MkvElement.o EbmlBufferWriter.o EbmlWriter.o
+ $(LINKER) $(FLAGS) testlibmkv.o MkvElement.o EbmlBufferWriter.o EbmlWriter.o -o testlibmkv
+
+clean:
+ rm -rf *.o testlibmkv
+ \ No newline at end of file
diff --git a/libmkv/WebMElement.c b/libmkv/WebMElement.c
new file mode 100644
index 000000000..25a90249a
--- /dev/null
+++ b/libmkv/WebMElement.c
@@ -0,0 +1,220 @@
+// 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>
+
+#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, 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, 2);
+ unsigned char flags = 0x00 | (isKeyframe ? 0x80 : 0x00) | (lacingFlag << 1) | discardable;
+ Ebml_Write(glob, &flags, 1);
+ Ebml_Write(glob, data, dataLength);
+}
+
+static UInt64 generateTrackID(unsigned int trackNumber)
+{
+ UInt64 t = time(NULL) * trackNumber;
+ UInt64 r = rand();
+ r = r << 32;
+ r += rand();
+ UInt64 rval = t ^ r;
+ return rval;
+}
+
+void writeVideoTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
+ char *codecId, unsigned int pixelWidth, unsigned int pixelHeight,
+ double frameRate)
+{
+ EbmlLoc start;
+ Ebml_StartSubElement(glob, &start, TrackEntry);
+ Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
+ UInt64 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,
+ 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 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);
+}
+*/
diff --git a/libmkv/WebMElement.h b/libmkv/WebMElement.h
new file mode 100644
index 000000000..b4208f285
--- /dev/null
+++ b/libmkv/WebMElement.h
@@ -0,0 +1,35 @@
+// 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
+
+void writeSimpleBock(EbmlGlobal *ebml, unsigned char trackNumber, unsigned short timeCode,
+ int isKeyframe, unsigned char lacingFlag, int discardable,
+ unsigned char *data, unsigned long dataLength);
+
+
+// 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,
+ char *codecId, unsigned int pixelWidth, unsigned int pixelHeight,
+ double frameRate);
+void writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
+ 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 \ No newline at end of file
diff --git a/libmkv/testlibmkv.c b/libmkv/testlibmkv.c
new file mode 100644
index 000000000..7edfc4347
--- /dev/null
+++ b/libmkv/testlibmkv.c
@@ -0,0 +1,63 @@
+// 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