Add a hack to set the first Cluster timecode to 0 if it isn't already.
[libmkv.git] / src / matroska.c
blob67f199f131317497f79630807f127bcf66b56bdb
1 /*****************************************************************************
2 * matroska.c:
3 *****************************************************************************
4 * Copyright (C) 2005 x264 project
5 * $Id: $
7 * Authors: Mike Matsnev
8 * Nathan Caldwell
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
24 #include "config.h"
25 #include "libmkv.h"
26 #include "matroska.h"
27 #include "md5.h"
29 int mk_seekFile(mk_Writer *w, uint64_t pos) {
30 if (fseek(w->fp, pos, SEEK_SET))
31 return -1;
33 w->f_pos = pos;
35 if (pos > w->f_eof)
36 w->f_eof = pos;
38 return 0;
41 char *mk_laceXiph(uint64_t *sizes, uint8_t num_frames, uint64_t *output_size) {
42 unsigned i, j;
43 uint64_t offset = 0;
44 uint64_t alloc_size = num_frames * 6; // Complete guess. We'll realloc if we need more space, though.
45 char *laced = calloc(alloc_size, sizeof(char));
46 if (laced == NULL)
47 return NULL;
49 laced[offset++] = num_frames;
50 for (i = 0; i < num_frames; i++)
52 for (j = sizes[i]; j >= 255 ; j -= 255)
54 laced[offset++] = 255;
55 if (offset + 1 >= alloc_size) {
56 int avg_sz = offset / (i - 1); // Compute approximate average bytes/frame
57 alloc_size += avg_sz * (num_frames - i); // Add our average + number of frames left to size
58 if ((laced = realloc(laced, alloc_size)) == NULL)
59 return NULL;
62 laced[offset++] = j;
65 if (output_size != NULL)
66 *output_size = offset;
68 return laced;
71 mk_Writer *mk_createWriter(const char *filename, int64_t timescale, uint8_t vlc_compat) {
72 mk_Writer *w = calloc(1, sizeof(*w));
73 if (w == NULL)
74 return NULL;
76 w->root = mk_createContext(w, NULL, 0);
77 if (w->root == NULL) {
78 free(w);
79 return NULL;
82 if ((w->cues = mk_createContext(w, w->root, 0x1c53bb6b)) == NULL) // Cues
84 mk_destroyContexts(w);
85 free(w);
86 return NULL;
89 if (vlc_compat) {
90 if ((w->cluster.seekhead = mk_createContext(w, w->root, 0x114d9b74)) == NULL) // SeekHead
92 mk_destroyContexts(w);
93 free(w);
94 return NULL;
98 w->fp = fopen(filename, "wb");
99 if (w->fp == NULL) {
100 mk_destroyContexts(w);
101 free(w);
102 return NULL;
105 w->timescale = timescale;
106 w->vlc_compat = vlc_compat;
108 return w;
111 int mk_writeHeader(mk_Writer *w, const char *writingApp) {
112 mk_Context *c;
113 int64_t offset = 0;
115 if (w->wrote_header)
116 return -1;
118 md5_starts(&w->segment_md5); /* Initalize MD5 */
120 if ((c = mk_createContext(w, w->root, 0x1a45dfa3)) == NULL) // EBML
121 return -1;
122 CHECK(mk_writeUInt(c, 0x4286, 1)); // EBMLVersion
123 CHECK(mk_writeUInt(c, 0x42f7, 1)); // EBMLReadVersion
124 CHECK(mk_writeUInt(c, 0x42f2, 4)); // EBMLMaxIDLength
125 CHECK(mk_writeUInt(c, 0x42f3, 8)); // EBMLMaxSizeLength
126 CHECK(mk_writeStr(c, 0x4282, "matroska")); // DocType
127 CHECK(mk_writeUInt(c, 0x4287, 1)); // DocTypeVersion
128 CHECK(mk_writeUInt(c, 0x4285, 1)); // DocTypeReadversion
129 CHECK(mk_closeContext(c, 0));
131 if ((c = mk_createContext(w, w->root, 0x18538067)) == NULL) // Segment
132 return -1;
133 CHECK(mk_flushContextID(c));
134 w->segment_ptr = c->d_cur;
135 CHECK(mk_closeContext(c, &w->segment_ptr));
137 if (w->vlc_compat) {
138 CHECK(mk_writeVoid(w->root, 0x100)); // 256 bytes should be enough room for our Seek entries.
139 CHECK(mk_writeVoid(w->root, 0x800)); // 2048 bytes for Chapters.
141 else {
142 w->seek_data.seekhead = 0x80000000;
143 CHECK(mk_writeSeekHead(w, &w->seekhead_ptr));
144 w->seek_data.seekhead = 0;
147 if ((c = mk_createContext(w, w->root, 0x1549a966)) == NULL) // SegmentInfo
148 return -1;
149 w->seek_data.segmentinfo = w->root->d_cur - w->segment_ptr;
150 CHECK(mk_writeVoid(c, 16)); /* Reserve space for a SegmentUID, we'll write the it later. */
151 CHECK(mk_writeStr(c, 0x4d80, PACKAGE_STRING)); // MuxingApp
152 CHECK(mk_writeStr(c, 0x5741, writingApp)); // WritingApp
153 CHECK(mk_writeUInt(c, 0x2ad7b1, w->timescale)); // TimecodeScale
154 CHECK(mk_writeFloat(c, 0x4489, 0)); // Duration
155 w->duration_ptr = c->d_cur - 4;
156 CHECK(mk_closeContext(c, &offset));
157 w->duration_ptr += offset;
158 w->segmentuid_ptr = offset;
160 w->seek_data.tracks = w->root->d_cur - w->segment_ptr;
162 if (w->tracks)
163 CHECK(mk_closeContext(w->tracks, 0));
165 CHECK(mk_flushContextData(w->root));
167 w->wrote_header = 1;
168 w->def_duration = w->tracks_arr[0]->default_duration;
169 return 0;
172 static int mk_closeCluster(mk_Writer *w) {
173 if (w->cluster.context == NULL)
174 return 0;
175 w->cluster.count++;
176 CHECK(mk_closeContext(w->cluster.context, 0));
177 w->cluster.context = NULL;
178 CHECK(mk_flushContextData(w->root));
179 return 0;
182 int mk_flushFrame(mk_Writer *w, mk_Track *track) {
183 mk_Context *c, *tp;
184 int64_t delta, ref = 0;
185 unsigned fsize, bgsize;
186 uint8_t flags, c_delta[2];
187 int i;
188 char *laced = NULL;
189 uint64_t length = 0;
191 if (!track->in_frame)
192 return 0;
194 delta = track->frame.timecode/w->timescale - w->cluster.tc_scaled;
195 if (delta > 2000ll || delta < -2000ll)
196 CHECK(mk_closeCluster(w));
198 if (w->cluster.context == NULL) {
199 w->cluster.tc_scaled = track->frame.timecode / w->timescale;
200 w->cluster.context = mk_createContext(w, w->root, 0x1f43b675); // Cluster
201 if (w->cluster.context == NULL)
202 return -1;
204 w->cluster.pointer = w->f_pos - w->segment_ptr;
207 * Dirty HACK: This is for HandBrake/VLC. The first timecode we get isnt't
208 * always 0, if not we set it to 0.
210 if (w->cluster.count == 0 && w->vlc_compat && track->frame.timecode != 0) {
211 w->cluster.tc_scaled = 0;
212 delta = track->frame.timecode/w->timescale;
213 } else {
214 delta = 0;
217 if (w->vlc_compat)
218 CHECK(mk_writeSeek(w, w->cluster.seekhead, 0x1f43b675, w->cluster.pointer));
220 CHECK(mk_writeUInt(w->cluster.context, 0xe7, w->cluster.tc_scaled)); // Cluster Timecode
222 w->cluster.block_count = 0;
225 /* Calculate the encoded lacing sizes. */
226 switch (track->frame.lacing) {
227 case MK_LACING_XIPH:
228 laced = mk_laceXiph(track->frame.lacing_sizes, track->frame.lacing_num_frames, &length);
229 break;
230 case MK_LACING_EBML:
232 uint64_t u_size = 0;
233 length += mk_ebmlSizeSize(track->frame.lacing_sizes[0]) + 1; // Add one for the frame count.
234 for (i = 1; i < track->frame.lacing_num_frames; i++)
236 u_size = llabs(track->frame.lacing_sizes[i] - track->frame.lacing_sizes[i-1]);
237 length += mk_ebmlSizeSize((u_size) << 1); // Shift by one so we get the right size for a signed number.
239 break;
241 case MK_LACING_FIXED:
243 laced = calloc(1, sizeof(char));
244 laced[0] = track->frame.lacing_num_frames;
245 ++length;
246 break;
250 fsize = track->frame.data ? track->frame.data->d_cur : 0;
251 bgsize = fsize + 4 + mk_ebmlSizeSize(fsize + 4 + length) + 1 + length;
252 if (!track->frame.keyframe) {
253 ref = track->prev_frame_tc_scaled - w->cluster.tc_scaled - delta;
254 bgsize += 1 + 1 + mk_ebmlSIntSize(ref);
257 CHECK(mk_writeID(w->cluster.context, 0xa0)); // BlockGroup
258 CHECK(mk_writeSize(w->cluster.context, bgsize));
259 CHECK(mk_writeID(w->cluster.context, 0xa1)); // Block
260 CHECK(mk_writeSize(w->cluster.context, fsize + 4 + length)); // Block size
261 CHECK(mk_writeSize(w->cluster.context, track->track_id)); // track number
263 w->cluster.block_count++;
265 c_delta[0] = delta >> 8;
266 c_delta[1] = delta;
267 CHECK(mk_appendContextData(w->cluster.context, c_delta, 2)); // Timecode relative to Cluster.
269 // flags = ( track->frame.keyframe << 8 ) | track->frame.lacing;
270 flags = track->frame.lacing << 1; // Flags: Bit 5-6 describe what type of lacing to use.
271 CHECK(mk_appendContextData(w->cluster.context, &flags, 1));
272 if (track->frame.lacing) {
273 if (track->frame.lacing == MK_LACING_EBML) {
274 CHECK(mk_appendContextData(w->cluster.context, &track->frame.lacing_num_frames, 1)); // Number of frames in lace-1
275 CHECK(mk_writeSize(w->cluster.context, track->frame.lacing_sizes[0])); // Size of 1st frame.
276 for (i = 1; i < track->frame.lacing_num_frames; i++)
278 CHECK(mk_writeSSize(w->cluster.context, track->frame.lacing_sizes[i] - track->frame.lacing_sizes[i-1])); // Size difference between previous size and this size.
280 } else if (length > 0 && laced != NULL) {
281 CHECK(mk_appendContextData(w->cluster.context, laced, length));
282 free(laced);
283 laced = NULL;
287 if (track->frame.data) {
288 CHECK(mk_appendContextData(w->cluster.context, track->frame.data->data, track->frame.data->d_cur));
289 track->frame.data->d_cur = 0;
291 if (!track->frame.keyframe)
292 CHECK(mk_writeSInt(w->cluster.context, 0xfb, ref)); // ReferenceBlock
294 if (track->frame.keyframe && (track->track_type & MK_TRACK_VIDEO) && ((track->prev_cue_pos + 3*CLSIZE) <= w->f_pos || track->frame.timecode == 0)) {
295 if ((c = mk_createContext(w, w->cues, 0xbb)) == NULL) // CuePoint
296 return -1;
297 CHECK(mk_writeUInt(c, 0xb3, track->frame.timecode)); // CueTime
299 if ((tp = mk_createContext(w, c, 0xb7)) == NULL) // CueTrackPositions
300 return -1;
301 CHECK(mk_writeUInt(tp, 0xf7, track->track_id)); // CueTrack
302 CHECK(mk_writeUInt(tp, 0xf1, w->cluster.pointer)); // CueClusterPosition
303 // CHECK(mk_writeUInt(c, 0x5378, w->cluster.block_count)); // CueBlockNumber
304 CHECK(mk_closeContext(tp, 0));
305 CHECK(mk_closeContext(c, 0));
306 track->prev_cue_pos = w->f_pos;
309 track->in_frame = 0;
310 track->prev_frame_tc_scaled = w->cluster.tc_scaled + delta;
312 if (w->cluster.context->d_cur > CLSIZE)
313 CHECK(mk_closeCluster(w));
315 return 0;
318 int mk_startFrame(mk_Writer *w, mk_Track *track) {
319 if (mk_flushFrame(w, track) < 0)
320 return -1;
322 track->in_frame = 1;
323 track->frame.keyframe = 0;
324 track->frame.lacing = MK_LACING_NONE;
325 track->frame.lacing_num_frames = 0;
326 track->frame.lacing_sizes = NULL;
328 return 0;
331 int mk_setFrameFlags(mk_Writer *w, mk_Track *track, int64_t timestamp, unsigned keyframe) {
332 if (!track->in_frame)
333 return -1;
335 track->frame.timecode = timestamp;
336 track->frame.keyframe = keyframe != 0;
338 if (track->max_frame_tc < timestamp)
339 track->max_frame_tc = timestamp;
341 return 0;
344 int mk_setFrameLacing(mk_Writer *w, mk_Track *track, uint8_t lacing, uint8_t num_frames, uint64_t sizes[]) {
345 if (!track->in_frame)
346 return -1;
347 track->frame.lacing_sizes = calloc(num_frames, sizeof(uint64_t));
349 track->frame.lacing = lacing;
350 track->frame.lacing_num_frames = num_frames;
351 memcpy(track->frame.lacing_sizes, sizes, num_frames * sizeof(uint64_t));
353 return 0;
356 int mk_addFrameData(mk_Writer *w, mk_Track *track, const void *data, unsigned size) {
357 if (!track->in_frame)
358 return -1;
360 if (track->frame.data == NULL)
361 if ((track->frame.data = mk_createContext(w, NULL, 0)) == NULL)
362 return -1;
364 md5_update(&w->segment_md5, (unsigned char *)data, size);
366 return mk_appendContextData(track->frame.data, data, size);
369 int mk_writeSeek(mk_Writer *w, mk_Context *c, unsigned seek_id, uint64_t seek_pos) {
370 mk_Context *s;
372 if ((s = mk_createContext(w, c, 0x4dbb)) == NULL) // Seek
373 return -1;
374 CHECK(mk_writeUInt(s, 0x53ab, seek_id)); // SeekID
375 CHECK(mk_writeUInt(s, 0x53ac, seek_pos)); // SeekPosition
376 CHECK(mk_closeContext(s, 0));
378 return 0;
381 /* The offset of the SeekHead is returned in *pointer. */
382 int mk_writeSeekHead(mk_Writer *w, int64_t *pointer) {
383 mk_Context *c;
384 int64_t seekhead_ptr;
386 if ((c = mk_createContext(w, w->root, 0x114d9b74)) == NULL) // SeekHead
387 return -1;
388 if (pointer != NULL)
389 seekhead_ptr = w->f_pos;
390 if (w->seek_data.seekhead)
391 CHECK(mk_writeSeek(w, c, 0x114d9b74, w->seek_data.seekhead));
392 if (w->seek_data.segmentinfo)
393 CHECK(mk_writeSeek(w, c, 0x1549a966, w->seek_data.segmentinfo));
394 if (w->seek_data.tracks)
395 CHECK(mk_writeSeek(w, c, 0x1654ae6b, w->seek_data.tracks));
396 if (w->seek_data.cues)
397 CHECK(mk_writeSeek(w, c, 0x1c53bb6b, w->seek_data.cues));
398 if (w->seek_data.attachments)
399 CHECK(mk_writeSeek(w, c, 0x1941a469, w->seek_data.attachments));
400 if (w->seek_data.chapters)
401 CHECK(mk_writeSeek(w, c, 0x1043a770, w->seek_data.chapters));
402 if (w->seek_data.tags)
403 CHECK(mk_writeSeek(w, c, 0x1254c367, w->seek_data.tags));
404 CHECK(mk_closeContext(c, 0));
406 if (pointer != NULL)
407 *pointer = seekhead_ptr;
409 return 0;
412 int mk_close(mk_Writer *w) {
413 int i, ret = 0;
414 mk_Track *tk;
415 int64_t max_frame_tc = w->tracks_arr[0]->max_frame_tc;
416 uint64_t segment_size = 0;
417 unsigned char c_size[8];
418 unsigned char segment_uid[16];
420 md5_finish(&w->segment_md5, segment_uid);
422 for (i = w->num_tracks - 1; i >= 0; i--)
424 tk = w->tracks_arr[i];
425 w->tracks_arr[i] = NULL;
426 --w->num_tracks;
427 if (mk_flushFrame(w, tk) < 0)
428 ret = -1;
429 free(tk);
430 tk = NULL;
433 if (mk_closeCluster(w) < 0)
434 ret = -1;
436 w->seek_data.cues = w->f_pos - w->segment_ptr;
437 if (mk_closeContext(w->cues, 0) < 0)
438 ret = -1;
439 if (mk_flushContextData(w->root) < 0)
440 ret = -1;
442 if (w->vlc_compat && w->cluster.seekhead) {
443 w->seek_data.seekhead = w->f_pos - w->segment_ptr;
444 if (mk_closeContext(w->cluster.seekhead, 0) < 0)
445 ret = -1;
446 if (mk_flushContextData(w->root) < 0)
447 ret = -1;
450 if (w->chapters != NULL)
452 if (w->vlc_compat) {
453 if (mk_flushContextData(w->root) < 0)
454 ret = -1;
455 if (mk_seekFile(w, w->segment_ptr + 0x100 + 3) < 0)
456 ret = -1;
458 w->seek_data.chapters = w->f_pos - w->segment_ptr;
459 mk_writeChapters(w);
460 if (mk_flushContextData(w->root) < 0)
461 ret = -1;
462 if (w->vlc_compat) {
463 if (mk_writeVoid(w->root, (0x800 - (w->f_pos - w->segment_ptr - 0x100 - 3))) < 0)
464 ret = -1;
465 if (mk_flushContextData(w->root) < 0)
466 ret = -1;
470 if (w->wrote_header) {
471 if (w->vlc_compat) {
472 if (mk_seekFile(w, w->segment_ptr) < 0)
473 ret = -1;
476 if (mk_writeSeekHead(w, &w->seek_data.seekhead) < 0)
477 ret = -1;
478 w->seek_data.seekhead -= w->segment_ptr;
480 if (w->vlc_compat)
482 if (mk_flushContextData(w->root) < 0)
483 ret = -1;
484 if (mk_writeVoid(w->root, (0x100 - (w->f_pos - w->segment_ptr))) < 0)
485 ret = -1;
488 if (mk_flushContextData(w->root) < 0)
489 ret = -1;
491 if (!w->vlc_compat)
493 int i = w->seek_data.segmentinfo;
494 w->seek_data.segmentinfo = 0;
495 w->seek_data.tracks = 0;
496 w->seek_data.cues = 0;
497 w->seek_data.chapters = 0;
498 w->seek_data.attachments = 0;
499 w->seek_data.tags = 0;
500 if (mk_seekFile(w, w->segment_ptr) < 0)
501 ret = -1;
502 if (mk_writeSeekHead(w, NULL) < 0 ||
503 mk_flushContextData(w->root) < 0)
504 ret = -1;
505 if (((i + w->segment_ptr) - w->f_pos - 2) > 1)
506 if (mk_writeVoid(w->root, (i + w->segment_ptr) - w->f_pos - 2) < 0 ||
507 mk_flushContextData(w->root) < 0)
508 ret = -1;
511 if (mk_seekFile(w, w->duration_ptr) < 0)
512 ret = -1;
513 if (mk_writeFloatRaw(w->root, (float)((double)(max_frame_tc+w->def_duration) / w->timescale)) < 0 ||
514 mk_flushContextData(w->root) < 0)
515 ret = -1;
516 if (mk_seekFile(w, w->segment_ptr - 8) < 0)
517 ret = -1;
518 segment_size = w->f_eof - w->segment_ptr;
519 for (i = 7; i > 0; --i)
520 c_size[i] = segment_size >> (8 * (7-i));
521 c_size[i] = 0x01;
522 if (mk_appendContextData(w->root, &c_size, 8) < 0 ||
523 mk_flushContextData(w->root) < 0)
524 ret = -1;
525 if (mk_seekFile(w, w->segmentuid_ptr) < 0)
526 ret = -1;
527 if (mk_writeBin(w->root, 0x73a4, segment_uid, sizeof(segment_uid)) < 0 ||
528 mk_flushContextData(w->root) < 0)
529 ret = -1;
532 if (mk_closeContext(w->root, 0) < 0)
533 ret = -1;
534 mk_destroyContexts(w);
535 fclose(w->fp);
536 free(w->tracks_arr);
537 free(w);
539 return ret;