Merge branch 'cue_fixes'
[libmkv.git] / src / matroska.c
blob78a7f1999044cebc5a63c45a1baf0a171413b4a3
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 "libmkv.h"
25 #include "matroska.h"
26 #include "config.h"
28 int mk_writeVoid(mk_Context *c, uint64_t length) {
29 char *c_void = calloc(length, sizeof(char));
31 CHECK(mk_writeID(c, 0xec));
32 CHECK(mk_writeSize(c, length));
33 CHECK(mk_appendContextData(c, c_void, length));
34 free(c_void);
35 return 0;
38 char *mk_laceXiph(uint64_t *sizes, uint8_t num_frames, uint64_t *output_size) {
39 unsigned i, j;
40 uint64_t offset = 0;
41 uint64_t alloc_size = num_frames * 6; // Complete guess. We'll realloc if we need more space, though.
42 char *laced = calloc(alloc_size, sizeof(char));
43 if (laced == NULL)
44 return NULL;
46 laced[offset++] = num_frames;
47 for (i = 0; i < num_frames; i++)
49 for (j = sizes[i]; j >= 255 ; j -= 255)
51 laced[offset++] = 255;
52 if (offset + 1 >= alloc_size) {
53 int avg_sz = offset / (i - 1); // Compute approximate average bytes/frame
54 alloc_size += avg_sz * (num_frames - i); // Add our average + number of frames left to size
55 if ((laced = realloc(laced, alloc_size)) == NULL)
56 return NULL;
59 laced[offset++] = j;
62 if (output_size != NULL)
63 *output_size = offset;
65 return laced;
68 mk_Writer *mk_createWriter(const char *filename, int64_t timescale, uint8_t vlc_compat) {
69 mk_Writer *w = calloc(1, sizeof(*w));
70 if (w == NULL)
71 return NULL;
73 w->root = mk_createContext(w, NULL, 0);
74 if (w->root == NULL) {
75 free(w);
76 return NULL;
79 if ((w->cues = mk_createContext(w, w->root, 0x1c53bb6b)) == NULL) // Cues
81 mk_destroyContexts(w);
82 free(w);
83 return NULL;
86 w->fp = fopen(filename, "wb");
87 if (w->fp == NULL) {
88 mk_destroyContexts(w);
89 free(w);
90 return NULL;
93 w->timescale = timescale;
94 w->vlc_compat = vlc_compat;
96 return w;
99 int mk_writeHeader(mk_Writer *w, const char *writingApp) {
100 mk_Context *c;
102 if (w->wrote_header)
103 return -1;
105 if ((c = mk_createContext(w, w->root, 0x1a45dfa3)) == NULL) // EBML
106 return -1;
107 CHECK(mk_writeUInt(c, 0x4286, 1)); // EBMLVersion
108 CHECK(mk_writeUInt(c, 0x42f7, 1)); // EBMLReadVersion
109 CHECK(mk_writeUInt(c, 0x42f2, 4)); // EBMLMaxIDLength
110 CHECK(mk_writeUInt(c, 0x42f3, 8)); // EBMLMaxSizeLength
111 CHECK(mk_writeStr(c, 0x4282, "matroska")); // DocType
112 CHECK(mk_writeUInt(c, 0x4287, 1)); // DocTypeVersion
113 CHECK(mk_writeUInt(c, 0x4285, 1)); // DocTypeReadversion
114 CHECK(mk_closeContext(c, 0));
116 if ((c = mk_createContext(w, w->root, 0x18538067)) == NULL) // Segment
117 return -1;
118 CHECK(mk_flushContextID(c));
119 w->segment_ptr = c->d_cur;
120 CHECK(mk_closeContext(c, &w->segment_ptr));
122 if (w->vlc_compat)
124 CHECK(mk_writeVoid(w->root, 0x100)); // 256 bytes should be enough room for our Seek entries.
125 CHECK(mk_writeVoid(w->root, 0x800)); // 2048 bytes for Chapters.
126 CHECK(mk_writeVoid(w->root, 0x1000)); // 4096 bytes for Cues.
127 } else
129 w->seek_data.seekhead = 0x80000000;
130 CHECK(mk_writeSeek(w, &w->seekhead_ptr));
131 w->seek_data.seekhead = 0;
134 if ((c = mk_createContext(w, w->root, 0x1549a966)) == NULL) // SegmentInfo
135 return -1;
136 w->seek_data.segmentinfo = w->root->d_cur - w->segment_ptr;
137 CHECK(mk_writeStr(c, 0x4d80, PACKAGE_STRING)); // MuxingApp
138 CHECK(mk_writeStr(c, 0x5741, writingApp)); // WritingApp
139 CHECK(mk_writeUInt(c, 0x2ad7b1, w->timescale)); // TimecodeScale
140 CHECK(mk_writeFloat(c, 0x4489, 0)); // Duration
141 w->duration_ptr = c->d_cur - 4;
142 CHECK(mk_closeContext(c, &w->duration_ptr));
144 w->seek_data.tracks = w->root->d_cur - w->segment_ptr;
146 if (w->tracks) {
147 CHECK(mk_closeContext(w->tracks, 0));
150 CHECK(mk_flushContextData(w->root));
152 w->wrote_header = 1;
153 w->def_duration = w->tracks_arr[0]->default_duration;
154 return 0;
157 static int mk_closeCluster(mk_Writer *w) {
158 if (w->cluster.context == NULL)
159 return 0;
160 w->cluster.count++;
161 CHECK(mk_closeContext(w->cluster.context, 0));
162 w->cluster.context = NULL;
163 CHECK(mk_flushContextData(w->root));
164 return 0;
167 int mk_flushFrame(mk_Writer *w, mk_Track *track) {
168 mk_Context *c;
169 int64_t delta, ref = 0;
170 unsigned fsize, bgsize;
171 uint8_t flags, c_delta_flags[2];
172 int i;
173 char *laced = NULL;
174 uint64_t length = 0;
176 if (!track->in_frame)
177 return 0;
179 delta = track->frame.timecode/w->timescale - w->cluster.tc_scaled;
180 if (delta > 32767ll || delta < -32768ll)
181 CHECK(mk_closeCluster(w));
183 if (w->cluster.context == NULL) {
184 w->cluster.tc_scaled = track->frame.timecode / w->timescale;
185 w->cluster.context = mk_createContext(w, w->root, 0x1f43b675); // Cluster
186 if (w->cluster.context == NULL)
187 return -1;
189 w->cluster.pointer = ftell(w->fp) - w->segment_ptr;
191 CHECK(mk_writeUInt(w->cluster.context, 0xe7, w->cluster.tc_scaled)); // Cluster Timecode
193 delta = 0;
194 w->cluster.block_count = 0;
197 fsize = track->frame.data ? track->frame.data->d_cur : 0;
198 bgsize = fsize + 4 + mk_ebmlSizeSize(fsize + 4) + 1;
199 if (!track->frame.keyframe) {
200 ref = track->prev_frame_tc_scaled - w->cluster.tc_scaled - delta;
201 bgsize += 1 + 1 + mk_ebmlSIntSize(ref);
204 CHECK(mk_writeID(w->cluster.context, 0xa0)); // BlockGroup
205 CHECK(mk_writeSize(w->cluster.context, bgsize));
206 CHECK(mk_writeID(w->cluster.context, 0xa1)); // Block
208 switch (track->frame.lacing) {
209 case MK_LACING_XIPH:
210 laced = mk_laceXiph(track->frame.lacing_sizes, track->frame.lacing_num_frames, &length);
211 break;
212 case MK_LACING_EBML:
213 length += mk_ebmlSizeSize(track->frame.lacing_sizes[0]) + 1;
214 for (i = 1; i < track->frame.lacing_num_frames; i++)
215 length += mk_ebmlSizeSize(track->frame.lacing_sizes[i] << 1);
216 break;
217 case MK_LACING_FIXED:
219 laced = calloc(1, sizeof(char));
220 laced[0] = track->frame.lacing_num_frames;
221 ++length;
223 break;
226 CHECK(mk_writeSize(w->cluster.context, fsize + 4 + length));
227 CHECK(mk_writeSize(w->cluster.context, track->track_id)); // track number
229 w->cluster.block_count++;
231 c_delta_flags[0] = delta >> 8;
232 c_delta_flags[1] = delta;
233 CHECK(mk_appendContextData(w->cluster.context, c_delta_flags, 2));
235 flags = ( track->frame.keyframe << 8 ) | track->frame.lacing;
236 CHECK(mk_appendContextData(w->cluster.context, &flags, 1));
237 if (track->frame.lacing) {
238 if (track->frame.lacing == MK_LACING_EBML) {
239 CHECK(mk_appendContextData(w->cluster.context, &track->frame.lacing_num_frames, 1));
240 CHECK(mk_writeSize(w->cluster.context, track->frame.lacing_sizes[0]));
241 for (i = 1; i < track->frame.lacing_num_frames; i++)
243 CHECK(mk_writeSSize(w->cluster.context, track->frame.lacing_sizes[i] - track->frame.lacing_sizes[i-1]));
245 } else if (length > 0 && laced != NULL) {
246 CHECK(mk_appendContextData(w->cluster.context, laced, length));
247 free(laced);
248 laced = NULL;
252 if (track->frame.data) {
253 CHECK(mk_appendContextData(w->cluster.context, track->frame.data->data, track->frame.data->d_cur));
254 track->frame.data->d_cur = 0;
256 if (!track->frame.keyframe)
257 CHECK(mk_writeSInt(w->cluster.context, 0xfb, ref)); // ReferenceBlock
259 if ((track->cue_flag || (track->track_type & MK_TRACK_VIDEO)) && track->frame.keyframe) {
260 for(i = 0; i < w->num_tracks; i++)
261 w->tracks_arr[i]->cue_flag = 1;
262 if (w->cue_point.timecode != track->frame.timecode) {
263 if (w->cue_point.context != NULL) {
264 CHECK(mk_closeContext(w->cue_point.context, 0));
265 w->cue_point.context = NULL;
268 if (w->cue_point.context == NULL) {
269 if ((w->cue_point.context = mk_createContext(w, w->cues, 0xbb)) == NULL) // CuePoint
270 return -1;
271 CHECK(mk_writeUInt(w->cue_point.context, 0xb3, track->frame.timecode)); // CueTime
272 w->cue_point.timecode = track->frame.timecode;
275 if ((c = mk_createContext(w, w->cue_point.context, 0xb7)) == NULL) // CueTrackPositions
276 return -1;
277 CHECK(mk_writeUInt(c, 0xf7, track->track_id)); // CueTrack
278 CHECK(mk_writeUInt(c, 0xf1, w->cluster.pointer)); // CueClusterPosition
279 // CHECK(mk_writeUInt(c, 0x5378, w->cluster.block_count)); // CueBlockNumber
280 CHECK(mk_closeContext(c, 0));
281 track->cue_flag = 0;
284 track->in_frame = 0;
285 track->prev_frame_tc_scaled = w->cluster.tc_scaled + delta;
287 if (w->cluster.context->d_cur > CLSIZE)
288 CHECK(mk_closeCluster(w));
290 return 0;
293 int mk_startFrame(mk_Writer *w, mk_Track *track) {
294 if (mk_flushFrame(w, track) < 0)
295 return -1;
297 track->in_frame = 1;
298 track->frame.keyframe = 0;
299 track->frame.lacing = MK_LACING_NONE;
300 track->frame.lacing_num_frames = 0;
301 track->frame.lacing_sizes = NULL;
303 return 0;
306 int mk_setFrameFlags(mk_Writer *w, mk_Track *track, int64_t timestamp, unsigned keyframe) {
307 if (!track->in_frame)
308 return -1;
310 track->frame.timecode = timestamp;
311 track->frame.keyframe = keyframe != 0;
313 if (track->max_frame_tc < timestamp)
314 track->max_frame_tc = timestamp;
316 return 0;
319 int mk_setFrameLacing(mk_Writer *w, mk_Track *track, uint8_t lacing, uint8_t num_frames, uint32_t sizes[]) {
320 if (!track->in_frame)
321 return -1;
322 track->frame.lacing_sizes = calloc(num_frames, sizeof(uint32_t));
324 track->frame.lacing = lacing;
325 track->frame.lacing_num_frames = num_frames;
326 memcpy(track->frame.lacing_sizes, sizes, num_frames);
328 return 0;
331 int mk_addFrameData(mk_Writer *w, mk_Track *track, const void *data, unsigned size) {
332 if (!track->in_frame)
333 return -1;
335 if (track->frame.data == NULL)
336 if ((track->frame.data = mk_createContext(w, NULL, 0)) == NULL)
337 return -1;
339 return mk_appendContextData(track->frame.data, data, size);
342 /* The offset of the SeekHead is returned in *pointer. */
343 int mk_writeSeek(mk_Writer *w, int64_t *pointer) {
344 mk_Context *c, *s;
345 int64_t seekhead_ptr;
347 if ((c = mk_createContext(w, w->root, 0x114d9b74)) == NULL) // SeekHead
348 return -1;
349 if (pointer != NULL)
350 seekhead_ptr = ftell(w->fp);
351 if (w->seek_data.seekhead) {
352 if ((s = mk_createContext(w, c, 0x4dbb)) == NULL) // Seek
353 return -1;
354 CHECK(mk_writeUInt(s, 0x53ab, 0x114d9b74)); // SeekID
355 CHECK(mk_writeUInt(s, 0x53ac, w->seek_data.seekhead)); // SeekPosition
356 CHECK(mk_closeContext(s, 0));
358 if (w->seek_data.segmentinfo) {
359 if ((s = mk_createContext(w, c, 0x4dbb)) == NULL) // Seek
360 return -1;
361 CHECK(mk_writeUInt(s, 0x53ab, 0x1549a966)); // SeekID
362 CHECK(mk_writeUInt(s, 0x53ac, w->seek_data.segmentinfo)); // SeekPosition
363 CHECK(mk_closeContext(s, 0));
365 if (w->seek_data.tracks) {
366 if ((s = mk_createContext(w, c, 0x4dbb)) == NULL) // Seek
367 return -1;
368 CHECK(mk_writeUInt(s, 0x53ab, 0x1654ae6b)); // SeekID
369 CHECK(mk_writeUInt(s, 0x53ac, w->seek_data.tracks)); // SeekPosition
370 CHECK(mk_closeContext(s, 0));
372 if (w->seek_data.cues) {
373 if ((s = mk_createContext(w, c, 0x4dbb)) == NULL) // Seek
374 return -1;
375 CHECK(mk_writeUInt(s, 0x53ab, 0x1c53bb6b)); // SeekID
376 CHECK(mk_writeUInt(s, 0x53ac, w->seek_data.cues)); // SeekPosition
377 CHECK(mk_closeContext(s, 0));
379 if (w->seek_data.attachments) {
380 if ((s = mk_createContext(w, c, 0x4dbb)) == NULL) // Seek
381 return -1;
382 CHECK(mk_writeUInt(s, 0x53ab, 0x1941a469)); // SeekID
383 CHECK(mk_writeUInt(s, 0x53ac, w->seek_data.attachments)); // SeekPosition
384 CHECK(mk_closeContext(s, 0));
386 if (w->seek_data.chapters) {
387 if ((s = mk_createContext(w, c, 0x4dbb)) == NULL) // Seek
388 return -1;
389 CHECK(mk_writeUInt(s, 0x53ab, 0x1043a770)); // SeekID
390 CHECK(mk_writeUInt(s, 0x53ac, w->seek_data.chapters)); // SeekPosition
391 CHECK(mk_closeContext(s, 0));
393 if (w->seek_data.tags) {
394 if ((s = mk_createContext(w, c, 0x4dbb)) == NULL) // Seek
395 return -1;
396 CHECK(mk_writeUInt(s, 0x53ab, 0x1254c367)); // SeekID
397 CHECK(mk_writeUInt(s, 0x53ac, w->seek_data.tags)); // SeekPosition
398 CHECK(mk_closeContext(s, 0));
400 CHECK(mk_closeContext(c, 0));
402 if (pointer != NULL)
403 *pointer = seekhead_ptr;
405 return 0;
408 int mk_close(mk_Writer *w) {
409 int i, ret = 0;
410 mk_Track *tk;
411 int64_t max_frame_tc = w->tracks_arr[0]->max_frame_tc;
413 for (i = w->num_tracks - 1; i >= 0; i--)
415 tk = w->tracks_arr[i];
416 w->tracks_arr[i] = NULL;
417 if (mk_flushFrame(w, tk) < 0)
418 ret = -1;
419 free(tk);
420 tk = NULL;
423 if (mk_closeCluster(w) < 0)
424 ret = -1;
426 if (w->chapters != NULL)
428 if (w->vlc_compat)
429 fseek(w->fp, w->segment_ptr + 0x103, SEEK_SET);
430 w->seek_data.chapters = ftell(w->fp) - w->segment_ptr;
431 mk_writeChapters(w);
432 if (w->vlc_compat) {
433 if (mk_flushContextData(w->root) < 0)
434 ret = -1;
435 if (mk_writeVoid(w->root, (0x800 - (ftell(w->fp) - w->segment_ptr))) < 0)
436 ret = -1;
438 if (mk_flushContextData(w->root) < 0)
439 ret = -1;
442 w->seek_data.cues = ftell(w->fp) - w->segment_ptr;
443 if (w->cue_point.context != NULL)
444 if (mk_closeContext(w->cue_point.context, 0) < 0)
445 ret = -1;
446 // if (w->vlc_compat)
447 // fseek(w->fp, w->segment_ptr + 259 + 2051, SEEK_SET);
448 if (mk_closeContext(w->cues, 0) < 0)
449 ret = -1;
450 if (w->vlc_compat) {
451 if (mk_flushContextData(w->root) < 0)
452 ret = -1;
453 if (mk_writeVoid(w->root, (0x1000 - (ftell(w->fp) - w->segment_ptr))) < 0)
454 ret = -1;
456 if (mk_flushContextData(w->root) < 0)
457 ret = -1;
459 if (w->wrote_header) {
460 if (w->vlc_compat)
461 fseek(w->fp, w->segment_ptr, SEEK_SET);
463 if (mk_writeSeek(w, &w->seek_data.seekhead) < 0)
464 ret = -1;
465 w->seek_data.seekhead -= w->segment_ptr;
467 if (w->vlc_compat)
469 if (mk_flushContextData(w->root) < 0)
470 ret = -1;
471 if (mk_writeVoid(w->root, (256 - (ftell(w->fp) - w->segment_ptr))) < 0)
472 ret = -1;
475 if (mk_flushContextData(w->root) < 0)
476 ret = -1;
478 if (!w->vlc_compat)
480 int i = w->seek_data.segmentinfo;
481 w->seek_data.segmentinfo = 0;
482 w->seek_data.tracks = 0;
483 w->seek_data.cues = 0;
484 w->seek_data.chapters = 0;
485 w->seek_data.attachments = 0;
486 w->seek_data.tags = 0;
487 fseek(w->fp, w->segment_ptr, SEEK_SET);
488 if (mk_writeSeek(w, NULL) < 0 ||
489 mk_flushContextData(w->root) < 0)
490 ret = -1;
491 if (((i + w->segment_ptr) - ftell(w->fp) - 2) > 1)
492 if (mk_writeVoid(w->root, (i + w->segment_ptr) - ftell(w->fp) - 2) < 0 ||
493 mk_flushContextData(w->root) < 0)
494 ret = -1;
497 fseek(w->fp, w->duration_ptr, SEEK_SET);
498 if (mk_writeFloatRaw(w->root, (float)((double)(max_frame_tc+w->def_duration) / w->timescale)) < 0 ||
499 mk_flushContextData(w->root) < 0)
500 ret = -1;
503 if (mk_closeContext(w->root, 0) < 0)
504 ret = -1;
505 mk_destroyContexts(w);
506 fclose(w->fp);
507 free(w->tracks_arr);
508 free(w);
510 return ret;