Import webmquicktime webm writer
Initial import of the libmkv directory from the webmquicktime[1]
project, at commit fedbda1.
[1]: git://review.webmproject.org/webmquicktime.git
commit fedbda18de899ff94855cb334de7e471036fbf1d
Change-Id: I1564a0ebfa72293fc296ee02178196530dfd90e4
This commit is contained in:
60
libmkv/EbmlBufferWriter.c
Normal file
60
libmkv/EbmlBufferWriter.c
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
21
libmkv/EbmlBufferWriter.h
Normal file
21
libmkv/EbmlBufferWriter.h
Normal file
@@ -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
|
||||
231
libmkv/EbmlIDs.h
Normal file
231
libmkv/EbmlIDs.h
Normal file
@@ -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
|
||||
160
libmkv/EbmlWriter.c
Normal file
160
libmkv/EbmlWriter.c
Normal file
@@ -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
|
||||
38
libmkv/EbmlWriter.h
Normal file
38
libmkv/EbmlWriter.h
Normal file
@@ -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
|
||||
25
libmkv/Makefile
Normal file
25
libmkv/Makefile
Normal file
@@ -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
|
||||
|
||||
220
libmkv/WebMElement.c
Normal file
220
libmkv/WebMElement.c
Normal file
@@ -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);
|
||||
}
|
||||
*/
|
||||
35
libmkv/WebMElement.h
Normal file
35
libmkv/WebMElement.h
Normal file
@@ -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
|
||||
63
libmkv/testlibmkv.c
Normal file
63
libmkv/testlibmkv.c
Normal file
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user