WebMElement.c revision b08e2e23eec181e9951df33cd704ac294c5407b6
1538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber// Copyright (c) 2010 The WebM project authors. All Rights Reserved.
2538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber//
3538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber// Use of this source code is governed by a BSD-style license
4538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber// that can be found in the LICENSE file in the root of the source
5538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber// tree. An additional intellectual property rights grant can be found
6538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber// in the file PATENTS.  All contributing project authors may
7538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber// be found in the AUTHORS file in the root of the source tree.
8538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
9538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
10538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber#include "EbmlBufferWriter.h"
11538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber#include "EbmlIDs.h"
12538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber#include "WebMElement.h"
13538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber#include <stdio.h>
14b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian#include "vpx/vpx_integer.h"
15538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
16538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber#define kVorbisPrivateMaxSize  4000
17538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
18ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuangvoid writeHeader(EbmlGlobal *glob) {
19ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  EbmlLoc start;
20ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_StartSubElement(glob, &start, EBML);
21ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_SerializeUnsigned(glob, EBMLVersion, 1);
22ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_SerializeUnsigned(glob, EBMLReadVersion, 1); // EBML Read Version
23ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_SerializeUnsigned(glob, EBMLMaxIDLength, 4); // EBML Max ID Length
24ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_SerializeUnsigned(glob, EBMLMaxSizeLength, 8); // EBML Max Size Length
25ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_SerializeString(glob, DocType, "webm"); // Doc Type
26ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_SerializeUnsigned(glob, DocTypeVersion, 2); // Doc Type Version
27ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_SerializeUnsigned(glob, DocTypeReadVersion, 2); // Doc Type Read Version
28ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_EndSubElement(glob, &start);
29538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber}
30538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
31538f6170b788de7408b06efc6613dc98579aa6a6Andreas Hubervoid writeSimpleBlock(EbmlGlobal *glob, unsigned char trackNumber, short timeCode,
32538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber                      int isKeyframe, unsigned char lacingFlag, int discardable,
33ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang                      unsigned char *data, unsigned long dataLength) {
34ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_WriteID(glob, SimpleBlock);
35ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  unsigned long blockLength = 4 + dataLength;
36ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  blockLength |= 0x10000000; // TODO check length < 0x0FFFFFFFF
37ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_Serialize(glob, &blockLength, sizeof(blockLength), 4);
38ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  trackNumber |= 0x80;  // TODO check track nubmer < 128
39ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_Write(glob, &trackNumber, 1);
40ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  // Ebml_WriteSigned16(glob, timeCode,2); //this is 3 bytes
41ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_Serialize(glob, &timeCode, sizeof(timeCode), 2);
42ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  unsigned char flags = 0x00 | (isKeyframe ? 0x80 : 0x00) | (lacingFlag << 1) | discardable;
43ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_Write(glob, &flags, 1);
44ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_Write(glob, data, dataLength);
45ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang}
46ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
47b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanianstatic uint64_t generateTrackID(unsigned int trackNumber) {
48b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  uint64_t t = time(NULL) * trackNumber;
49b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  uint64_t r = rand();
50ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  r = r << 32;
51ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  r +=  rand();
52b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  uint64_t rval = t ^ r;
53ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  return rval;
54538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber}
55538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
56b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanianvoid writeVideoTrack(EbmlGlobal *glob, unsigned int trackNumber,
57b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                     int flagLacing, const char *codecId,
58b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                     unsigned int pixelWidth, unsigned int pixelHeight,
59ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang                     double frameRate) {
60ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  EbmlLoc start;
61ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_StartSubElement(glob, &start, TrackEntry);
62ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
63b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  uint64_t trackID = generateTrackID(trackNumber);
64ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_SerializeUnsigned(glob, TrackUID, trackID);
65ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_SerializeString(glob, CodecName, "VP8");  // TODO shouldn't be fixed
66ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
67ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_SerializeUnsigned(glob, TrackType, 1); // video is always 1
68ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_SerializeString(glob, CodecID, codecId);
69ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  {
70ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    EbmlLoc videoStart;
71ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    Ebml_StartSubElement(glob, &videoStart, Video);
72ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth);
73ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight);
74ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    Ebml_SerializeFloat(glob, FrameRate, frameRate);
75ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    Ebml_EndSubElement(glob, &videoStart); // Video
76ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  }
77ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_EndSubElement(glob, &start); // Track Entry
78538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber}
79b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanianvoid writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber,
80b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                     int flagLacing, const char *codecId,
81b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                     double samplingFrequency, unsigned int channels,
82ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang                     unsigned char *private, unsigned long privateSize) {
83ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  EbmlLoc start;
84ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_StartSubElement(glob, &start, TrackEntry);
85ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
86b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  uint64_t trackID = generateTrackID(trackNumber);
87ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_SerializeUnsigned(glob, TrackUID, trackID);
88ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_SerializeUnsigned(glob, TrackType, 2); // audio is always 2
89ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  // I am using defaults for thesed required fields
90ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  /*  Ebml_SerializeUnsigned(glob, FlagEnabled, 1);
91ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      Ebml_SerializeUnsigned(glob, FlagDefault, 1);
92ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      Ebml_SerializeUnsigned(glob, FlagForced, 1);
93ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      Ebml_SerializeUnsigned(glob, FlagLacing, flagLacing);*/
94ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_SerializeString(glob, CodecID, codecId);
95ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_SerializeData(glob, CodecPrivate, private, privateSize);
96ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
97ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_SerializeString(glob, CodecName, "VORBIS");  // fixed for now
98ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  {
99ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    EbmlLoc AudioStart;
100ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    Ebml_StartSubElement(glob, &AudioStart, Audio);
101ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    Ebml_SerializeFloat(glob, SamplingFrequency, samplingFrequency);
102ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    Ebml_SerializeUnsigned(glob, Channels, channels);
103ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    Ebml_EndSubElement(glob, &AudioStart);
104ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  }
105ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_EndSubElement(glob, &start);
106ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang}
107ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuangvoid writeSegmentInformation(EbmlGlobal *ebml, EbmlLoc *startInfo, unsigned long timeCodeScale, double duration) {
108ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_StartSubElement(ebml, startInfo, Info);
109ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_SerializeUnsigned(ebml, TimecodeScale, timeCodeScale);
110ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_SerializeFloat(ebml, Segment_Duration, duration * 1000.0); // Currently fixed to using milliseconds
111ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_SerializeString(ebml, 0x4D80, "QTmuxingAppLibWebM-0.0.1");
112ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_SerializeString(ebml, 0x5741, "QTwritingAppLibWebM-0.0.1");
113ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  Ebml_EndSubElement(ebml, startInfo);
114538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber}
115538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
116538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber/*
117538f6170b788de7408b06efc6613dc98579aa6a6Andreas Hubervoid Mkv_InitializeSegment(Ebml& ebml_out, EbmlLoc& ebmlLoc)
118538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber{
119538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_StartSubElement(ebml_out, ebmlLoc, 0x18538067);
120538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber}
121538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
122538f6170b788de7408b06efc6613dc98579aa6a6Andreas Hubervoid Mkv_InitializeSeek(Ebml& ebml_out, EbmlLoc& ebmlLoc)
123538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber{
124538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_StartSubElement(ebml_out, ebmlLoc, 0x114d9b74);
125538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber}
126538f6170b788de7408b06efc6613dc98579aa6a6Andreas Hubervoid Mkv_WriteSeekInformation(Ebml& ebml_out, SeekStruct& seekInformation)
127538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber{
128538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    EbmlLoc ebmlLoc;
129538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_StartSubElement(ebml_out, ebmlLoc, 0x4dbb);
130538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeString(ebml_out, 0x53ab, seekInformation.SeekID);
131538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeUnsigned(ebml_out, 0x53ac, seekInformation.SeekPosition);
132538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_EndSubElement(ebml_out, ebmlLoc);
133538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber}
134538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
135538f6170b788de7408b06efc6613dc98579aa6a6Andreas Hubervoid Mkv_WriteSegmentInformation(Ebml& ebml_out, SegmentInformationStruct& segmentInformation)
136538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber{
137538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeUnsigned(ebml_out, 0x73a4, segmentInformation.segmentUID);
138538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    if (segmentInformation.filename != 0)
139538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        Ebml_SerializeString(ebml_out, 0x7384, segmentInformation.filename);
140538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeUnsigned(ebml_out, 0x2AD7B1, segmentInformation.TimecodeScale);
141538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeUnsigned(ebml_out, 0x4489, segmentInformation.Duration);
142ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    // TODO date
143538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeWString(ebml_out, 0x4D80, L"MKVMUX");
144538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeWString(ebml_out, 0x5741, segmentInformation.WritingApp);
145538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber}
146538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
147538f6170b788de7408b06efc6613dc98579aa6a6Andreas Hubervoid Mkv_InitializeTrack(Ebml& ebml_out, EbmlLoc& ebmlLoc)
148538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber{
149538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_StartSubElement(ebml_out, ebmlLoc, 0x1654AE6B);
150538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber}
151538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
152538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huberstatic void Mkv_WriteGenericTrackData(Ebml& ebml_out, TrackStruct& track)
153538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber{
154538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeUnsigned(ebml_out, 0xD7, track.TrackNumber);
155538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeUnsigned(ebml_out, 0x73C5, track.TrackUID);
156538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeUnsigned(ebml_out, 0x83, track.TrackType);
157538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeUnsigned(ebml_out, 0xB9, track.FlagEnabled ? 1 :0);
158538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeUnsigned(ebml_out, 0x88, track.FlagDefault ? 1 :0);
159538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeUnsigned(ebml_out, 0x55AA, track.FlagForced ? 1 :0);
160538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    if (track.Language != 0)
161538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        Ebml_SerializeString(ebml_out, 0x22B59C, track.Language);
162538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    if (track.CodecID != 0)
163538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        Ebml_SerializeString(ebml_out, 0x86, track.CodecID);
164538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    if (track.CodecPrivate != 0)
165538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        Ebml_SerializeData(ebml_out, 0x63A2, track.CodecPrivate, track.CodecPrivateLength);
166538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    if (track.CodecName != 0)
167538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        Ebml_SerializeWString(ebml_out, 0x258688, track.CodecName);
168538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber}
169538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
170538f6170b788de7408b06efc6613dc98579aa6a6Andreas Hubervoid Mkv_WriteVideoTrack(Ebml& ebml_out, TrackStruct & track, VideoTrackStruct& video)
171538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber{
172538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    EbmlLoc trackHeadLoc, videoHeadLoc;
173ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    Ebml_StartSubElement(ebml_out, trackHeadLoc, 0xAE);  // start Track
174538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Mkv_WriteGenericTrackData(ebml_out, track);
175ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    Ebml_StartSubElement(ebml_out, videoHeadLoc, 0xE0);  // start Video
176538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeUnsigned(ebml_out, 0x9A, video.FlagInterlaced ? 1 :0);
177538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeUnsigned(ebml_out, 0xB0, video.PixelWidth);
178538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeUnsigned(ebml_out, 0xBA, video.PixelHeight);
179538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeUnsigned(ebml_out, 0x54B0, video.PixelDisplayWidth);
180538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeUnsigned(ebml_out, 0x54BA, video.PixelDisplayHeight);
181538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeUnsigned(ebml_out, 0x54B2, video.displayUnit);
182538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeFloat(ebml_out, 0x2383E3, video.FrameRate);
183538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_EndSubElement(ebml_out, videoHeadLoc);
184538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_EndSubElement(ebml_out, trackHeadLoc);
185538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
186538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber}
187538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
188538f6170b788de7408b06efc6613dc98579aa6a6Andreas Hubervoid Mkv_WriteAudioTrack(Ebml& ebml_out, TrackStruct & track, AudioTrackStruct& video)
189538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber{
190538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    EbmlLoc trackHeadLoc, audioHeadLoc;
191538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_StartSubElement(ebml_out, trackHeadLoc, 0xAE);
192538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Mkv_WriteGenericTrackData(ebml_out, track);
193ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    Ebml_StartSubElement(ebml_out, audioHeadLoc, 0xE0);  // start Audio
194538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeFloat(ebml_out, 0xB5, video.SamplingFrequency);
195538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeUnsigned(ebml_out, 0x9F, video.Channels);
196538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeUnsigned(ebml_out, 0x6264, video.BitDepth);
197538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_EndSubElement(ebml_out, audioHeadLoc); // end audio
198538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_EndSubElement(ebml_out, trackHeadLoc);
199538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber}
200538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
201538f6170b788de7408b06efc6613dc98579aa6a6Andreas Hubervoid Mkv_WriteEbmlClusterHead(Ebml& ebml_out,  EbmlLoc& ebmlLoc, ClusterHeadStruct & clusterHead)
202538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber{
203538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_StartSubElement(ebml_out, ebmlLoc, 0x1F43B675);
204538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_SerializeUnsigned(ebml_out, 0x6264, clusterHead.TimeCode);
205538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber}
206538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
207538f6170b788de7408b06efc6613dc98579aa6a6Andreas Hubervoid Mkv_WriteSimpleBlockHead(Ebml& ebml_out,  EbmlLoc& ebmlLoc, SimpleBlockStruct& block)
208538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber{
209538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_StartSubElement(ebml_out, ebmlLoc, 0xA3);
210538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_Write1UInt(ebml_out, block.TrackNumber);
211538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_WriteSigned16(ebml_out,block.TimeCode);
212538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    unsigned char flags = 0x00 | (block.iskey ? 0x80:0x00) | (block.lacing << 1) | block.discardable;
213ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    Ebml_Write1UInt(ebml_out, flags);  // TODO this may be the wrong function
214538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_Serialize(ebml_out, block.data, block.dataLength);
215538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    Ebml_EndSubElement(ebml_out,ebmlLoc);
216538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber}
217538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber*/
218