1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2005 x264 project
6 * Authors: Mike Matsnev
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
30 #define RESERVED_SEEKHEAD 0x100
31 /* 256 bytes should be enough room for our Seek entries. */
32 #define RESERVED_CHAPTERS 0x1000
33 /* 4096 bytes, hopefully enough for Chapters. */
35 int mk_seekFile(mk_Writer
*w
, uint64_t pos
)
37 if (fseek(w
->fp
, pos
, SEEK_SET
))
48 char *mk_laceXiph(uint64_t *sizes
, uint8_t num_frames
,
49 uint64_t *output_size
)
53 uint64_t alloc_size
= num_frames
* 6; /* Complete guess. It gets realloc'd
54 * below if we need more space, though.
56 char *laced
= calloc(alloc_size
, sizeof(*laced
));
60 laced
[offset
++] = num_frames
;
61 for (i
= 0; i
< num_frames
; i
++) {
62 for (j
= sizes
[i
]; j
>= 255; j
-= 255) {
63 laced
[offset
++] = 255;
64 if (offset
+ 1 >= alloc_size
) {
65 int avg_sz
= offset
/ (i
- 1); /* Compute approximate average bytes/frame */
66 alloc_size
+= avg_sz
* (num_frames
- i
);
67 /* Sum average so far and number of frames left
70 if ((laced
= realloc(laced
, alloc_size
)) == NULL
)
77 if (output_size
!= NULL
)
78 *output_size
= offset
;
83 mk_Writer
*mk_createWriter(const char *filename
, int64_t timescale
,
86 mk_Writer
*w
= calloc(1, sizeof(*w
));
92 w
->root
= mk_createContext(w
, NULL
, 0);
93 if (w
->root
== NULL
) {
99 if ((w
->cues
= mk_createContext(w
, w
->root
, MATROSKA_ID_CUES
)) == NULL
)
101 mk_destroyContexts(w
);
106 /* Clusters SeekHead */
107 if ((w
->cluster
.seekhead
= mk_createContext(w
, w
->root
, MATROSKA_ID_SEEKHEAD
)) == NULL
)
109 mk_destroyContexts(w
);
114 w
->fp
= fopen(filename
, "wb");
116 mk_destroyContexts(w
);
121 gettimeofday( &tv
, NULL
);
122 srandom(tv
.tv_sec
^ tv
.tv_usec
);
124 w
->timescale
= timescale
;
125 w
->vlc_compat
= vlc_compat
;
130 int mk_writeHeader(mk_Writer
*w
, const char *writingApp
)
138 md5_starts(&w
->segment_md5
); /* Initalize MD5 */
140 CHECK(mk_writeEbmlHeader(w
, "matroska", MATROSKA_VERSION
, MATROSKA_VERSION
));
143 if ((c
= mk_createContext(w
, w
->root
, MATROSKA_ID_SEGMENT
)) == NULL
)
145 CHECK(mk_flushContextID(c
));
146 w
->segment_ptr
= c
->d_cur
;
147 CHECK(mk_closeContext(c
, &w
->segment_ptr
));
150 CHECK(mk_writeVoid(w
->root
, RESERVED_SEEKHEAD
)); /* Reserved space for SeekHead */
151 CHECK(mk_writeVoid(w
->root
, RESERVED_CHAPTERS
)); /* Reserved space for Chapters */
153 w
->seek_data
.seekhead
= 0x80000000;
154 CHECK(mk_writeSeekHead(w
, &w
->seekhead_ptr
));
155 w
->seek_data
.seekhead
= 0;
158 if ((c
= mk_createContext(w
, w
->root
, MATROSKA_ID_INFO
)) == NULL
) /* SegmentInfo */
160 w
->seek_data
.segmentinfo
= w
->root
->d_cur
- w
->segment_ptr
;
161 /* Reserve space for a SegmentUID (16 bytes + 1 byte longer EBML ID), to be written it later. */
162 CHECK(mk_writeVoid(c
, 16 + 1));
163 CHECK(mk_writeStr(c
, MATROSKA_ID_MUXINGAPP
, PACKAGE_STRING
)); /* MuxingApp */
164 CHECK(mk_writeStr(c
, MATROSKA_ID_WRITINGAPP
, writingApp
)); /* WritingApp */
165 CHECK(mk_writeUInt(c
, MATROSKA_ID_TIMECODESCALE
, w
->timescale
)); /* TimecodeScale */
166 CHECK(mk_writeFloat(c
, MATROSKA_ID_DURATION
, 0)); /* Duration */
167 w
->duration_ptr
= c
->d_cur
- 4;
168 CHECK(mk_closeContext(c
, &offset
));
169 w
->duration_ptr
+= offset
;
170 w
->segmentuid_ptr
= offset
;
172 w
->seek_data
.tracks
= w
->root
->d_cur
- w
->segment_ptr
;
175 CHECK(mk_closeContext(w
->tracks
, 0));
177 CHECK(mk_flushContextData(w
->root
));
180 w
->def_duration
= w
->tracks_arr
[0]->default_duration
;
184 static int mk_closeCluster(mk_Writer
*w
)
186 if (w
->cluster
.context
== NULL
)
189 CHECK(mk_closeContext(w
->cluster
.context
, 0));
190 w
->cluster
.context
= NULL
;
191 CHECK(mk_flushContextData(w
->root
));
196 int mk_flushFrame(mk_Writer
*w
, mk_Track
*track
)
199 int64_t delta
, ref
= 0;
200 unsigned fsize
, bgsize
;
201 uint8_t flags
, c_delta
[2];
205 uint64_t block_duration
= 0;
207 if (!track
->in_frame
)
210 delta
= track
->frame
.timecode
/ w
->timescale
- w
->cluster
.tc_scaled
;
211 block_duration
= track
->frame
.duration
/ w
->timescale
;
212 /* If switch rapidly back-and-forth between tracks with drastically different timecodes
213 * this causes a new cluster to be written each time a switch is made. This causes
214 * unnecessary overhead.
217 if (delta
> 20000ll || delta
< -20000ll)
218 CHECK(mk_closeCluster(w
));
220 if (w
->cluster
.context
== NULL
) {
221 w
->cluster
.tc_scaled
= track
->frame
.timecode
/ w
->timescale
;
223 w
->cluster
.context
= mk_createContext(w
, w
->root
, MATROSKA_ID_CLUSTER
);
224 if (w
->cluster
.context
== NULL
)
227 w
->cluster
.pointer
= w
->f_pos
- w
->segment_ptr
;
229 /* Cluster SeekEntry */
230 CHECK(mk_writeSeek(w
, w
->cluster
.seekhead
, MATROSKA_ID_CLUSTER
,
231 w
->cluster
.pointer
));
233 /* Cluster Timecode */
234 CHECK(mk_writeUInt(w
->cluster
.context
, MATROSKA_ID_CLUSTERTIMECODE
, w
->cluster
.tc_scaled
));
237 w
->cluster
.block_count
= 0;
240 /* Calculate the encoded lacing sizes. */
241 switch (track
->frame
.lacing
) {
243 laced
= mk_laceXiph(track
->frame
.lacing_sizes
,
244 track
->frame
.lacing_num_frames
, &length
);
249 /* Add one below for the frame count. */
250 length
+= mk_ebmlSizeSize(track
->frame
.lacing_sizes
[0]) + 1;
251 for (i
= 1; i
< track
->frame
.lacing_num_frames
; i
++) {
252 u_size
= llabs(track
->frame
.lacing_sizes
[i
] -
253 track
->frame
.lacing_sizes
[i
- 1]);
254 /* Shift by one so we get the right size for a signed number. */
255 length
+= mk_ebmlSizeSize((u_size
) << 1);
259 case MK_LACING_FIXED
:
261 laced
= calloc(1, sizeof(*laced
));
262 laced
[0] = track
->frame
.lacing_num_frames
;
270 fsize
= track
->frame
.data
? track
->frame
.data
->d_cur
: 0;
271 bgsize
= fsize
+ 4 + mk_ebmlSizeSize(fsize
+ 4 + length
) + 1 + length
;
272 if (!track
->frame
.keyframe
) {
273 ref
= track
->prev_frame_tc_scaled
- w
->cluster
.tc_scaled
- delta
;
274 bgsize
+= 1 + 1 + mk_ebmlSIntSize(ref
);
276 if (block_duration
> 0) /* BlockDuration */
278 bgsize
+= 1 + 1 + mk_ebmlUIntSize(block_duration
);
281 CHECK(mk_writeID(w
->cluster
.context
, MATROSKA_ID_BLOCKGROUP
)); /* BlockGroup */
282 CHECK(mk_writeSize(w
->cluster
.context
, bgsize
));
283 CHECK(mk_writeID(w
->cluster
.context
, MATROSKA_ID_BLOCK
)); /* Block */
284 CHECK(mk_writeSize(w
->cluster
.context
, fsize
+ 4 + length
)); /* BlockSize */
285 CHECK(mk_writeSize(w
->cluster
.context
, track
->track_id
)); /* track number */
287 w
->cluster
.block_count
++;
289 c_delta
[0] = delta
>> 8;
291 /* Timecode relative to Cluster. */
292 CHECK(mk_appendContextData(w
->cluster
.context
, c_delta
, 2));
294 /* flags = ( track->frame.keyframe << 8 ) | track->frame.lacing; */
295 flags
= track
->frame
.lacing
<< 1; /* Flags: Bit 5-6 describe what type of lacing to use. */
296 CHECK(mk_appendContextData(w
->cluster
.context
, &flags
, 1));
297 if (track
->frame
.lacing
) {
298 if (track
->frame
.lacing
== MK_LACING_EBML
) {
299 /* Number of frames in lace - 1 */
300 CHECK(mk_appendContextData(w
->cluster
.context
, &track
->frame
.lacing_num_frames
, 1));
301 /* Size of 1st frame. */
302 CHECK(mk_writeSize(w
->cluster
.context
, track
->frame
.lacing_sizes
[0]));
303 for (i
= 1; i
< track
->frame
.lacing_num_frames
; i
++) {
304 /* Size difference between previous size and this size. */
305 CHECK(mk_writeSSize(w
->cluster
.context
, track
->frame
.lacing_sizes
[i
] - track
->frame
.lacing_sizes
[i
- 1]));
307 } else if (length
> 0 && laced
!= NULL
) {
308 CHECK(mk_appendContextData(w
->cluster
.context
, laced
, length
));
314 if (track
->frame
.data
) {
315 CHECK(mk_appendContextData(w
->cluster
.context
, track
->frame
.data
->data
,
316 track
->frame
.data
->d_cur
));
317 track
->frame
.data
->d_cur
= 0;
319 if (!track
->frame
.keyframe
) /* ReferenceBlock */
320 CHECK(mk_writeSInt(w
->cluster
.context
, MATROSKA_ID_REFERENCEBLOCK
, ref
));
322 if (block_duration
> 0) /* BlockDuration */
323 CHECK(mk_writeUInt(w
->cluster
.context
, 0x9b, block_duration
));
325 /* This may get a little out of hand, but it seems sane enough for now. */
326 if (track
->frame
.keyframe
&& (track
->track_type
== MK_TRACK_VIDEO
)) {
327 /* if (track->frame.keyframe && (track->track_type & MK_TRACK_VIDEO) && ((track->prev_cue_pos + 3*CLSIZE) <= w->f_pos || track->frame.timecode == 0)) { */
329 if ((c
= mk_createContext(w
, w
->cues
, MATROSKA_ID_CUEPOINT
)) == NULL
)
332 CHECK(mk_writeUInt(c
, MATROSKA_ID_CUETIME
, (track
->frame
.timecode
/ w
->timescale
)));
334 /* CueTrackPositions */
335 if ((tp
= mk_createContext(w
, c
, MATROSKA_ID_CUETRACKPOSITIONS
)) == NULL
)
338 CHECK(mk_writeUInt(tp
, MATROSKA_ID_CUETRACK
, track
->track_id
));
339 /* CueClusterPosition */
340 CHECK(mk_writeUInt(tp
, MATROSKA_ID_CUECLUSTERPOSITION
, w
->cluster
.pointer
));
342 /* CHECK(mk_writeUInt(c, MATROSKA_ID_CUEBLOCKNUMBER, w->cluster.block_count)); */
343 CHECK(mk_closeContext(tp
, 0));
344 CHECK(mk_closeContext(c
, 0));
345 track
->prev_cue_pos
= w
->f_pos
;
349 track
->prev_frame_tc_scaled
= w
->cluster
.tc_scaled
+ delta
;
351 /* Write a new Cluster ~ every 5MB */
352 if (w
->cluster
.context
->d_cur
> 5 * CLSIZE
)
353 CHECK(mk_closeCluster(w
));
358 int mk_startFrame(mk_Writer
*w
, mk_Track
*track
)
360 if (mk_flushFrame(w
, track
) < 0)
364 track
->frame
.keyframe
= 0;
365 track
->frame
.lacing
= MK_LACING_NONE
;
366 track
->frame
.lacing_num_frames
= 0;
367 track
->frame
.lacing_sizes
= NULL
;
372 int mk_setFrameFlags(mk_Writer
*w
, mk_Track
*track
, int64_t timestamp
,
373 unsigned keyframe
, uint64_t duration
)
375 if (!track
->in_frame
)
378 track
->frame
.timecode
= timestamp
;
379 track
->frame
.keyframe
= keyframe
!= 0;
381 if (track
->max_frame_tc
< timestamp
)
382 track
->max_frame_tc
= timestamp
;
385 track
->frame
.duration
= duration
;
390 int mk_setFrameLacing(mk_Writer
*w
, mk_Track
*track
,
391 mk_LacingType lacing
, uint8_t num_frames
,
394 if (!track
->in_frame
)
396 track
->frame
.lacing_sizes
= calloc(num_frames
, sizeof(*sizes
));
398 track
->frame
.lacing
= lacing
;
399 track
->frame
.lacing_num_frames
= num_frames
;
400 memcpy(track
->frame
.lacing_sizes
, sizes
,
401 num_frames
* sizeof(*sizes
));
406 int mk_addFrameData(mk_Writer
*w
, mk_Track
*track
, const void *data
,
409 if (!track
->in_frame
)
412 if (track
->frame
.data
== NULL
) {
413 if ((track
->frame
.data
= mk_createContext(w
, NULL
, 0)) == NULL
)
417 md5_update(&w
->segment_md5
, (unsigned char *) data
, size
);
419 return mk_appendContextData(track
->frame
.data
, data
, size
);
422 int mk_writeSeek(mk_Writer
*w
, mk_Context
*c
, unsigned seek_id
,
427 if ((s
= mk_createContext(w
, c
, MATROSKA_ID_SEEKENTRY
)) == NULL
) /* Seek */
429 CHECK(mk_writeUInt(s
, MATROSKA_ID_SEEKID
, seek_id
)); /* SeekID */
430 CHECK(mk_writeUInt(s
, MATROSKA_ID_SEEKPOSITION
, seek_pos
)); /* SeekPosition */
431 CHECK(mk_closeContext(s
, 0));
436 /* The offset of the SeekHead is returned in pointer. */
437 int mk_writeSeekHead(mk_Writer
*w
, int64_t *pointer
)
440 int64_t seekhead_ptr
;
443 if ((c
= mk_createContext(w
, w
->root
, MATROSKA_ID_SEEKHEAD
)) == NULL
)
446 seekhead_ptr
= w
->f_pos
;
447 if (w
->seek_data
.seekhead
)
448 CHECK(mk_writeSeek(w
, c
, MATROSKA_ID_SEEKHEAD
, w
->seek_data
.seekhead
));
449 if (w
->seek_data
.segmentinfo
)
450 CHECK(mk_writeSeek(w
, c
, MATROSKA_ID_INFO
, w
->seek_data
.segmentinfo
));
451 if (w
->seek_data
.tracks
)
452 CHECK(mk_writeSeek(w
, c
, MATROSKA_ID_TRACKS
, w
->seek_data
.tracks
));
453 if (w
->seek_data
.cues
)
454 CHECK(mk_writeSeek(w
, c
, MATROSKA_ID_CUES
, w
->seek_data
.cues
));
455 if (w
->seek_data
.attachments
)
456 CHECK(mk_writeSeek(w
, c
, MATROSKA_ID_ATTACHMENTS
, w
->seek_data
.attachments
));
457 if (w
->seek_data
.chapters
)
458 CHECK(mk_writeSeek(w
, c
, MATROSKA_ID_CHAPTERS
, w
->seek_data
.chapters
));
459 if (w
->seek_data
.tags
)
460 CHECK(mk_writeSeek(w
, c
, MATROSKA_ID_TAGS
, w
->seek_data
.tags
));
461 CHECK(mk_closeContext(c
, 0));
464 *pointer
= seekhead_ptr
;
469 int mk_close(mk_Writer
*w
)
473 int64_t max_frame_tc
= w
->tracks_arr
[0]->max_frame_tc
;
474 uint64_t segment_size
= 0;
475 unsigned char c_size
[8];
476 unsigned char segment_uid
[16];
478 md5_finish(&w
->segment_md5
, segment_uid
);
480 for (i
= w
->num_tracks
- 1; i
>= 0; i
--) {
481 tk
= w
->tracks_arr
[i
];
482 w
->tracks_arr
[i
] = NULL
;
484 if (mk_flushFrame(w
, tk
) < 0)
490 if (mk_closeCluster(w
) < 0)
493 w
->seek_data
.cues
= w
->f_pos
- w
->segment_ptr
;
494 if (mk_closeContext(w
->cues
, 0) < 0)
496 if (mk_flushContextData(w
->root
) < 0)
499 if (w
->cluster
.seekhead
) {
500 w
->seek_data
.seekhead
= w
->f_pos
- w
->segment_ptr
;
501 if (mk_closeContext(w
->cluster
.seekhead
, 0) < 0)
503 if (mk_flushContextData(w
->root
) < 0)
507 if (w
->attachments
!= NULL
) {
508 w
->seek_data
.attachments
= w
->f_pos
- w
->segment_ptr
;
509 mk_writeAttachments(w
);
510 if (mk_flushContextData(w
->root
) < 0)
514 if (w
->tags
!= NULL
) {
515 w
->seek_data
.tags
= w
->f_pos
- w
->segment_ptr
;
517 if (mk_flushContextData(w
->root
) < 0)
521 if (w
->chapters
!= NULL
) {
523 if (mk_flushContextData(w
->root
) < 0)
525 if (mk_seekFile(w
, w
->segment_ptr
+ RESERVED_SEEKHEAD
+ 3) < 0)
528 w
->seek_data
.chapters
= w
->f_pos
- w
->segment_ptr
;
530 if (mk_flushContextData(w
->root
) < 0)
533 if (mk_writeVoid(w
->root
, (RESERVED_CHAPTERS
- (w
->f_pos
- w
->segment_ptr
- RESERVED_SEEKHEAD
- 3))) < 0)
535 if (mk_flushContextData(w
->root
) < 0)
540 if (w
->wrote_header
) {
542 if (mk_seekFile(w
, w
->segment_ptr
) < 0)
546 if (mk_writeSeekHead(w
, &w
->seek_data
.seekhead
) < 0)
548 w
->seek_data
.seekhead
-= w
->segment_ptr
;
551 if (mk_flushContextData(w
->root
) < 0)
553 if (mk_writeVoid(w
->root
, (RESERVED_SEEKHEAD
- (w
->f_pos
- w
->segment_ptr
))) < 0)
557 if (mk_flushContextData(w
->root
) < 0)
560 if (!w
->vlc_compat
) {
561 int i
= w
->seek_data
.segmentinfo
;
562 w
->seek_data
.segmentinfo
= 0;
563 w
->seek_data
.tracks
= 0;
564 w
->seek_data
.cues
= 0;
565 w
->seek_data
.chapters
= 0;
566 w
->seek_data
.attachments
= 0;
567 w
->seek_data
.tags
= 0;
568 if (mk_seekFile(w
, w
->segment_ptr
) < 0)
570 if (mk_writeSeekHead(w
, NULL
) < 0 || mk_flushContextData(w
->root
) < 0)
572 // The conditional below is easier to understand, but incorrect
573 // because f_pos is unsigned and causes the lhs to be evaluated
574 // as an unsigned quantity.
575 // if (((i + w->segment_ptr) - w->f_pos - 2) > 1)
576 if ((i
+ w
->segment_ptr
) > (w
->f_pos
+ 3))
577 if (mk_writeVoid(w
->root
, (i
+ w
->segment_ptr
) - w
->f_pos
- 2) < 0
578 || mk_flushContextData(w
->root
) < 0)
582 if (mk_seekFile(w
, w
->duration_ptr
) < 0)
584 if (mk_writeFloatRaw(w
->root
,
585 (float) ((double) (max_frame_tc
+ w
->def_duration
) /
587 || mk_flushContextData(w
->root
) < 0)
589 if (mk_seekFile(w
, w
->segment_ptr
- 8) < 0)
591 segment_size
= w
->f_eof
- w
->segment_ptr
;
592 for (i
= 7; i
> 0; --i
)
593 c_size
[i
] = segment_size
>> (8 * (7 - i
));
595 if (mk_appendContextData(w
->root
, &c_size
, 8) < 0 ||
596 mk_flushContextData(w
->root
) < 0)
598 if (mk_seekFile(w
, w
->segmentuid_ptr
) < 0)
600 if (mk_writeBin(w
->root
, MATROSKA_ID_SEGMENTUID
, segment_uid
,
601 sizeof(segment_uid
)) < 0 ||
602 mk_flushContextData(w
->root
) < 0)
606 if (mk_closeContext(w
->root
, 0) < 0)
608 mk_destroyContexts(w
);