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 *****************************************************************************/
27 mk_Context
*mk_createContext(mk_Writer
*w
, mk_Context
*parent
,
34 w
->freelist
= w
->freelist
->next
;
36 c
= malloc(sizeof(*c
));
37 memset(c
, 0, sizeof(*c
));
47 if (c
->owner
->actlist
)
48 c
->owner
->actlist
->prev
= &c
->next
;
49 c
->next
= c
->owner
->actlist
;
50 c
->prev
= &c
->owner
->actlist
;
51 c
->owner
->actlist
= c
;
56 int mk_appendContextData(mk_Context
*c
, const void *data
, uint64_t size
)
58 uint64_t ns
= c
->d_cur
+ size
;
62 uint64_t dn
= c
->d_max
? c
->d_max
<< 1 : 16;
66 dp
= realloc(c
->data
, dn
);
74 memcpy((char *) c
->data
+ c
->d_cur
, data
, size
);
81 int mk_writeEbmlHeader(mk_Writer
*w
, const char *doctype
,
82 uint64_t doctype_version
,
83 uint64_t doctype_readversion
)
87 if ((c
= mk_createContext(w
, w
->root
, EBML_ID_HEADER
)) == NULL
) /* EBML */
89 CHECK(mk_writeUInt(c
, EBML_ID_EBMLVERSION
, EBML_VERSION
)); /* EBMLVersion */
90 CHECK(mk_writeUInt(c
, EBML_ID_EBMLREADVERSION
, EBML_VERSION
)); /* EBMLReadVersion */
91 CHECK(mk_writeUInt(c
, EBML_ID_EBMLMAXIDLENGTH
, 4)); /* EBMLMaxIDLength */
92 CHECK(mk_writeUInt(c
, EBML_ID_EBMLMAXSIZELENGTH
, 8)); /* EBMLMaxSizeLength */
93 CHECK(mk_writeStr(c
, EBML_ID_DOCTYPE
, doctype
)); /* DocType */
94 CHECK(mk_writeUInt(c
, EBML_ID_DOCTYPEVERSION
, doctype_version
)); /* DocTypeVersion */
95 /* DocTypeReadversion */
96 CHECK(mk_writeUInt(c
, EBML_ID_DOCTYPEREADVERSION
, doctype_readversion
));
97 CHECK(mk_closeContext(c
, 0));
102 int mk_writeID(mk_Context
*c
, unsigned id
)
104 unsigned char c_id
[4] = { id
>> 24, id
>> 16, id
>> 8, id
};
107 return mk_appendContextData(c
, c_id
, 4);
109 return mk_appendContextData(c
, c_id
+ 1, 3);
111 return mk_appendContextData(c
, c_id
+ 2, 2);
112 return mk_appendContextData(c
, c_id
+ 3, 1);
115 int mk_writeSize(mk_Context
*c
, uint64_t size
)
117 unsigned char c_size
[8] = { 0x01, size
>> 48, size
>> 40, size
>> 32,
118 size
>> 24, size
>> 16, size
>> 8, size
};
122 return mk_appendContextData(c
, c_size
+ 7, 1);
124 if (size
< 0x3fffll
) {
126 return mk_appendContextData(c
, c_size
+ 6, 2);
128 if (size
< 0x1fffffll
) {
130 return mk_appendContextData(c
, c_size
+ 5, 3);
132 if (size
< 0x0fffffffll
) {
134 return mk_appendContextData(c
, c_size
+ 4, 4);
136 if (size
< 0x07ffffffffll
) {
138 return mk_appendContextData(c
, c_size
+ 3, 5);
140 if (size
< 0x03ffffffffffll
) {
142 return mk_appendContextData(c
, c_size
+ 2, 6);
144 if (size
< 0x01ffffffffffffll
) {
146 return mk_appendContextData(c
, c_size
+ 1, 7);
148 return mk_appendContextData(c
, c_size
, 8);
151 int mk_writeSSize(mk_Context
*c
, int64_t size
)
153 uint64_t u_size
= (uint64_t) llabs(size
);
154 /* Need to shift by one below so ebmlSizeSize returns the correct size. */
155 unsigned size_size
= mk_ebmlSizeSize(u_size
<< 1);
168 size
+= 0x07ffffffll
;
171 size
+= 0x03ffffffffll
;
174 size
+= 0x01ffffffffffll
;
177 size
+= 0x00ffffffffffffll
;
179 default: /* Matroska currently doesn't support any int > 56-bit. */
183 return mk_writeSize(c
, size
);
186 int mk_flushContextID(mk_Context
*c
)
188 unsigned char size_undf
[8] = { 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
193 CHECK(mk_writeID(c
->parent
, c
->id
));
194 CHECK(mk_appendContextData(c
->parent
, &size_undf
, 8));
201 int mk_flushContextData(mk_Context
*c
)
203 mk_Writer
*w
= c
->owner
;
209 CHECK(mk_appendContextData(c
->parent
, c
->data
, c
->d_cur
));
211 if (fwrite(c
->data
, c
->d_cur
, 1, w
->fp
) != 1)
213 w
->f_pos
+= c
->d_cur
;
214 if (w
->f_pos
> w
->f_eof
)
223 int mk_closeContext(mk_Context
*c
, int64_t *off
)
226 CHECK(mk_writeID(c
->parent
, c
->id
));
227 CHECK(mk_writeSize(c
->parent
, c
->d_cur
));
230 if (c
->parent
&& off
!= NULL
)
231 *off
+= c
->parent
->d_cur
;
233 CHECK(mk_flushContextData(c
));
236 c
->next
->prev
= c
->prev
;
237 *(c
->prev
) = c
->next
;
238 c
->next
= c
->owner
->freelist
;
239 c
->owner
->freelist
= c
;
244 void mk_destroyContexts(mk_Writer
*w
)
246 mk_Context
*cur
, *next
;
248 for (cur
= w
->freelist
; cur
; cur
= next
) {
254 for (cur
= w
->actlist
; cur
; cur
= next
) {
260 w
->freelist
= w
->actlist
= w
->root
= NULL
;
263 int mk_writeStr(mk_Context
*c
, unsigned id
, const char *str
)
265 size_t len
= strlen(str
);
267 CHECK(mk_writeID(c
, id
));
268 CHECK(mk_writeSize(c
, len
));
269 CHECK(mk_appendContextData(c
, str
, len
));
273 int mk_writeBin(mk_Context
*c
, unsigned id
, const void *data
,
276 CHECK(mk_writeID(c
, id
));
277 CHECK(mk_writeSize(c
, size
));
278 CHECK(mk_appendContextData(c
, data
, size
));
282 int mk_writeUInt(mk_Context
*c
, unsigned id
, uint64_t ui
)
284 unsigned char c_ui
[8] = { ui
>> 56, ui
>> 48, ui
>> 40, ui
>> 32,
285 ui
>> 24, ui
>> 16, ui
>> 8, ui
};
288 CHECK(mk_writeID(c
, id
));
289 while (i
< 7 && c_ui
[i
] == 0)
291 CHECK(mk_writeSize(c
, 8 - i
));
292 CHECK(mk_appendContextData(c
, c_ui
+ i
, 8 - i
));
296 int mk_writeSInt(mk_Context
*c
, unsigned id
, int64_t si
)
298 unsigned char c_si
[8] = { si
>> 56, si
>> 48, si
>> 40, si
>> 32,
299 si
>> 24, si
>> 16, si
>> 8, si
};
302 CHECK(mk_writeID(c
, id
));
304 while (i
< 7 && c_si
[i
] == 0xff && c_si
[i
+ 1] & 0x80)
307 while (i
< 7 && c_si
[i
] == 0 && !(c_si
[i
+ 1] & 0x80))
310 CHECK(mk_writeSize(c
, 8 - i
));
311 CHECK(mk_appendContextData(c
, c_si
+ i
, 8 - i
));
315 int mk_writeFloatRaw(mk_Context
*c
, float f
)
321 unsigned char c_f
[4];
329 return mk_appendContextData(c
, c_f
, 4);
332 int mk_writeFloat(mk_Context
*c
, unsigned id
, float f
)
334 CHECK(mk_writeID(c
, id
));
335 CHECK(mk_writeSize(c
, 4));
336 CHECK(mk_writeFloatRaw(c
, f
));
340 int mk_writeVoid(mk_Context
*c
, uint64_t length
)
342 /* It would probably be faster to do this on the stack. */
343 char *c_void
= calloc(length
, sizeof(*c_void
));
345 CHECK(mk_writeID(c
, EBML_ID_VOID
));
346 CHECK(mk_writeSize(c
, length
));
347 CHECK(mk_appendContextData(c
, c_void
, length
));
353 unsigned mk_ebmlSizeSize(uint64_t s
)
361 if (s
< 0x0fffffffll
)
363 if (s
< 0x07ffffffffll
)
365 if (s
< 0x03ffffffffffll
)
367 if (s
< 0x01ffffffffffffll
)
372 unsigned mk_ebmlSIntSize(int64_t si
)
374 unsigned char c_si
[8] = { si
>> 56, si
>> 48, si
>> 40, si
>> 32,
375 si
>> 24, si
>> 16, si
>> 8, si
};
379 while (i
< 7 && c_si
[i
] == 0xff && c_si
[i
+ 1] & 0x80)
382 while (i
< 7 && c_si
[i
] == 0 && !(c_si
[i
+ 1] & 0x80))
389 unsigned mk_ebmlUIntSize(uint64_t ui
)
391 unsigned char c_ui
[8] = { ui
>> 56, ui
>> 48, ui
>> 40, ui
>> 32,
392 ui
>> 24, ui
>> 16, ui
>> 8, ui
};
395 while (i
< 7 && c_ui
[i
] == 0)