comparison matroskaenc.c @ 2447:54f0053730cf libavformat

Write the Seek Head element
author conrad
date Wed, 05 Sep 2007 00:23:19 +0000
parents b2f9523ee424
children bc52328116ac
comparison
equal deleted inserted replaced
2446:b2f9523ee424 2447:54f0053730cf
22 #include "avformat.h" 22 #include "avformat.h"
23 #include "riff.h" 23 #include "riff.h"
24 #include "xiph.h" 24 #include "xiph.h"
25 #include "matroska.h" 25 #include "matroska.h"
26 26
27 typedef struct mkv_seekhead_entry {
28 unsigned int elementid;
29 uint64_t segmentpos;
30 } mkv_seekhead_entry;
31
32 typedef struct mkv_seekhead {
33 offset_t filepos;
34 offset_t segment_offset; // the file offset to the beginning of the segment
35 int reserved_size; // -1 if appending to file
36 int max_entries;
37 mkv_seekhead_entry *entries;
38 int num_entries;
39 } mkv_seekhead;
40
27 typedef struct MatroskaMuxContext { 41 typedef struct MatroskaMuxContext {
28 offset_t segment; 42 offset_t segment;
43 offset_t segment_offset;
29 offset_t cluster; 44 offset_t cluster;
30 uint64_t cluster_pts; 45 uint64_t cluster_pts;
31 offset_t duration_offset; 46 offset_t duration_offset;
32 uint64_t duration; 47 uint64_t duration;
48 mkv_seekhead *main_seekhead;
49 mkv_seekhead *cluster_seekhead;
33 } MatroskaMuxContext; 50 } MatroskaMuxContext;
34 51
35 static void put_ebml_id(ByteIOContext *pb, unsigned int id) 52 static void put_ebml_id(ByteIOContext *pb, unsigned int id)
36 { 53 {
37 if (id >= 0x3fffff) 54 if (id >= 0x3fffff)
39 if (id >= 0x7fff) 56 if (id >= 0x7fff)
40 put_byte(pb, id >> 16); 57 put_byte(pb, id >> 16);
41 if (id >= 0xff) 58 if (id >= 0xff)
42 put_byte(pb, id >> 8); 59 put_byte(pb, id >> 8);
43 put_byte(pb, id); 60 put_byte(pb, id);
61 }
62
63 static int ebml_id_size(unsigned int id)
64 {
65 if (id >= 0x3fffff)
66 return 4;
67 if (id >= 0x7fff)
68 return 3;
69 if (id >= 0xff)
70 return 2;
71 return 1;
44 } 72 }
45 73
46 // XXX: test this thoroughly and get rid of minbytes hack (currently needed to 74 // XXX: test this thoroughly and get rid of minbytes hack (currently needed to
47 // use up all of the space reserved in start_ebml_master) 75 // use up all of the space reserved in start_ebml_master)
48 static void put_ebml_size(ByteIOContext *pb, uint64_t size, int minbytes) 76 static void put_ebml_size(ByteIOContext *pb, uint64_t size, int minbytes)
126 url_fseek(pb, start - 8, SEEK_SET); 154 url_fseek(pb, start - 8, SEEK_SET);
127 put_ebml_size(pb, pos - start, 7); 155 put_ebml_size(pb, pos - start, 7);
128 url_fseek(pb, pos, SEEK_SET); 156 url_fseek(pb, pos, SEEK_SET);
129 } 157 }
130 158
159 // initializes a mkv_seekhead element to be ready to index level 1 matroska elements
160 // if numelements is greater than 0, it reserves enough space for that many elements
161 // at the current file position and writes the seekhead there, otherwise the seekhead
162 // will be appended to the file when end_mkv_seekhead() is called
163 static mkv_seekhead * mkv_start_seekhead(ByteIOContext *pb, offset_t segment_offset, int numelements)
164 {
165 mkv_seekhead *new_seekhead = av_mallocz(sizeof(mkv_seekhead));
166 if (new_seekhead == NULL)
167 return NULL;
168
169 new_seekhead->segment_offset = segment_offset;
170
171 if (numelements > 0) {
172 new_seekhead->filepos = url_ftell(pb);
173 // 21 bytes max for a seek entry, 10 bytes max for the SeekHead ID and size,
174 // and 3 bytes to guarantee that an EBML void element will fit afterwards
175 // XXX: 28 bytes right now because begin_ebml_master() reserves more than necessary
176 new_seekhead->reserved_size = numelements * 28 + 13;
177 new_seekhead->max_entries = numelements;
178 put_ebml_void(pb, new_seekhead->reserved_size);
179 }
180 return new_seekhead;
181 }
182
183 static int mkv_add_seekhead_entry(mkv_seekhead *seekhead, unsigned int elementid, uint64_t filepos)
184 {
185 mkv_seekhead_entry *entries = seekhead->entries;
186 int new_entry = seekhead->num_entries;
187
188 // don't store more elements than we reserved space for
189 if (seekhead->max_entries > 0 && seekhead->max_entries <= seekhead->num_entries)
190 return -1;
191
192 entries = av_realloc(entries, (seekhead->num_entries + 1) * sizeof(mkv_seekhead_entry));
193 if (entries == NULL)
194 return -1;
195
196 entries[new_entry].elementid = elementid;
197 entries[new_entry].segmentpos = filepos - seekhead->segment_offset;
198
199 seekhead->entries = entries;
200 seekhead->num_entries++;
201
202 return 0;
203 }
204
205 // returns the file offset where the seekhead was written and frees the seekhead
206 static offset_t mkv_write_seekhead(ByteIOContext *pb, mkv_seekhead *seekhead)
207 {
208 offset_t metaseek, seekentry, currentpos;
209 int i;
210
211 currentpos = url_ftell(pb);
212
213 if (seekhead->reserved_size > 0)
214 url_fseek(pb, seekhead->filepos, SEEK_SET);
215
216 metaseek = start_ebml_master(pb, MATROSKA_ID_SEEKHEAD);
217 for (i = 0; i < seekhead->num_entries; i++) {
218 mkv_seekhead_entry *entry = &seekhead->entries[i];
219
220 seekentry = start_ebml_master(pb, MATROSKA_ID_SEEKENTRY);
221
222 put_ebml_id(pb, MATROSKA_ID_SEEKID);
223 put_ebml_size(pb, ebml_id_size(entry->elementid), 0);
224 put_ebml_id(pb, entry->elementid);
225
226 put_ebml_uint(pb, MATROSKA_ID_SEEKPOSITION, entry->segmentpos);
227 end_ebml_master(pb, seekentry);
228 }
229 end_ebml_master(pb, metaseek);
230
231 if (seekhead->reserved_size > 0) {
232 uint64_t remaining = seekhead->filepos + seekhead->reserved_size - url_ftell(pb);
233 put_ebml_void(pb, remaining);
234 url_fseek(pb, currentpos, SEEK_SET);
235
236 currentpos = seekhead->filepos;
237 }
238 av_free(seekhead->entries);
239 av_free(seekhead);
240
241 return currentpos;
242 }
243
131 static int put_xiph_codecpriv(ByteIOContext *pb, AVCodecContext *codec) 244 static int put_xiph_codecpriv(ByteIOContext *pb, AVCodecContext *codec)
132 { 245 {
133 offset_t codecprivate; 246 offset_t codecprivate;
134 uint8_t *header_start[3]; 247 uint8_t *header_start[3];
135 int header_len[3]; 248 int header_len[3];
165 { 278 {
166 MatroskaMuxContext *mkv = s->priv_data; 279 MatroskaMuxContext *mkv = s->priv_data;
167 ByteIOContext *pb = &s->pb; 280 ByteIOContext *pb = &s->pb;
168 offset_t tracks; 281 offset_t tracks;
169 int i, j; 282 int i, j;
283
284 if (mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_TRACKS, url_ftell(pb)) < 0)
285 return -1;
170 286
171 tracks = start_ebml_master(pb, MATROSKA_ID_TRACKS); 287 tracks = start_ebml_master(pb, MATROSKA_ID_TRACKS);
172 for (i = 0; i < s->nb_streams; i++) { 288 for (i = 0; i < s->nb_streams; i++) {
173 AVStream *st = s->streams[i]; 289 AVStream *st = s->streams[i];
174 AVCodecContext *codec = st->codec; 290 AVCodecContext *codec = st->codec;
265 put_ebml_uint (pb, EBML_ID_DOCTYPEVERSION , 2); 381 put_ebml_uint (pb, EBML_ID_DOCTYPEVERSION , 2);
266 put_ebml_uint (pb, EBML_ID_DOCTYPEREADVERSION , 2); 382 put_ebml_uint (pb, EBML_ID_DOCTYPEREADVERSION , 2);
267 end_ebml_master(pb, ebml_header); 383 end_ebml_master(pb, ebml_header);
268 384
269 mkv->segment = start_ebml_master(pb, MATROSKA_ID_SEGMENT); 385 mkv->segment = start_ebml_master(pb, MATROSKA_ID_SEGMENT);
386 mkv->segment_offset = url_ftell(pb);
387
388 // we write 2 seek heads - one at the end of the file to point to each cluster, and
389 // one at the beginning to point to all other level one elements (including the seek
390 // head at the end of the file), which isn't more than 10 elements if we only write one
391 // of each other currently defined level 1 element
392 mkv->main_seekhead = mkv_start_seekhead(pb, mkv->segment_offset, 10);
393 mkv->cluster_seekhead = mkv_start_seekhead(pb, mkv->segment_offset, 0);
394
395 if (mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_INFO, url_ftell(pb)) < 0)
396 return -1;
270 397
271 segment_info = start_ebml_master(pb, MATROSKA_ID_INFO); 398 segment_info = start_ebml_master(pb, MATROSKA_ID_INFO);
272 put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, 1000000); 399 put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, 1000000);
273 if (strlen(s->title)) 400 if (strlen(s->title))
274 put_ebml_string(pb, MATROSKA_ID_TITLE, s->title); 401 put_ebml_string(pb, MATROSKA_ID_TITLE, s->title);
285 end_ebml_master(pb, segment_info); 412 end_ebml_master(pb, segment_info);
286 413
287 if (mkv_write_tracks(s) < 0) 414 if (mkv_write_tracks(s) < 0)
288 return -1; 415 return -1;
289 416
417 if (mkv_add_seekhead_entry(mkv->cluster_seekhead, MATROSKA_ID_CLUSTER, url_ftell(pb)) < 0)
418 return -1;
419
290 mkv->cluster = start_ebml_master(pb, MATROSKA_ID_CLUSTER); 420 mkv->cluster = start_ebml_master(pb, MATROSKA_ID_CLUSTER);
291 put_ebml_uint(pb, MATROSKA_ID_CLUSTERTIMECODE, 0); 421 put_ebml_uint(pb, MATROSKA_ID_CLUSTERTIMECODE, 0);
292 mkv->cluster_pts = 0; 422 mkv->cluster_pts = 0;
293 423
294 return 0; 424 return 0;
301 offset_t block; 431 offset_t block;
302 432
303 // start a new cluster every 5 MB or 5 sec 433 // start a new cluster every 5 MB or 5 sec
304 if (url_ftell(pb) > mkv->cluster + 5*1024*1024 || pkt->pts > mkv->cluster_pts + 5000) { 434 if (url_ftell(pb) > mkv->cluster + 5*1024*1024 || pkt->pts > mkv->cluster_pts + 5000) {
305 end_ebml_master(pb, mkv->cluster); 435 end_ebml_master(pb, mkv->cluster);
436
437 if (mkv_add_seekhead_entry(mkv->cluster_seekhead, MATROSKA_ID_CLUSTER, url_ftell(pb)) < 0)
438 return -1;
439
306 mkv->cluster = start_ebml_master(pb, MATROSKA_ID_CLUSTER); 440 mkv->cluster = start_ebml_master(pb, MATROSKA_ID_CLUSTER);
307 put_ebml_uint(pb, MATROSKA_ID_CLUSTERTIMECODE, pkt->pts); 441 put_ebml_uint(pb, MATROSKA_ID_CLUSTERTIMECODE, pkt->pts);
308 mkv->cluster_pts = pkt->pts; 442 mkv->cluster_pts = pkt->pts;
309 } 443 }
310 444
321 455
322 static int mkv_write_trailer(AVFormatContext *s) 456 static int mkv_write_trailer(AVFormatContext *s)
323 { 457 {
324 MatroskaMuxContext *mkv = s->priv_data; 458 MatroskaMuxContext *mkv = s->priv_data;
325 ByteIOContext *pb = &s->pb; 459 ByteIOContext *pb = &s->pb;
326 offset_t currentpos; 460 offset_t currentpos, second_seekhead;
327 461
328 end_ebml_master(pb, mkv->cluster); 462 end_ebml_master(pb, mkv->cluster);
463
464 second_seekhead = mkv_write_seekhead(pb, mkv->cluster_seekhead);
465 mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_SEEKHEAD, second_seekhead);
466 mkv_write_seekhead(pb, mkv->main_seekhead);
329 467
330 // update the duration 468 // update the duration
331 currentpos = url_ftell(pb); 469 currentpos = url_ftell(pb);
332 url_fseek(pb, mkv->duration_offset, SEEK_SET); 470 url_fseek(pb, mkv->duration_offset, SEEK_SET);
333 put_ebml_float(pb, MATROSKA_ID_DURATION, mkv->duration); 471 put_ebml_float(pb, MATROSKA_ID_DURATION, mkv->duration);