Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(56)

Side by Side Diff: source/libvpx/third_party/nestegg/src/nestegg.c

Issue 341293003: libvpx: Pull from upstream (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/third_party/libvpx/
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 /*
2 * Copyright © 2010 Mozilla Foundation
3 *
4 * This program is made available under an ISC-style license. See the
5 * accompanying file LICENSE for details.
6 */
7 #include <assert.h>
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include "third_party/nestegg/halloc/halloc.h"
12 #include "third_party/nestegg/include/nestegg/nestegg.h"
13
14 /* EBML Elements */
15 #define ID_EBML 0x1a45dfa3
16 #define ID_EBML_VERSION 0x4286
17 #define ID_EBML_READ_VERSION 0x42f7
18 #define ID_EBML_MAX_ID_LENGTH 0x42f2
19 #define ID_EBML_MAX_SIZE_LENGTH 0x42f3
20 #define ID_DOCTYPE 0x4282
21 #define ID_DOCTYPE_VERSION 0x4287
22 #define ID_DOCTYPE_READ_VERSION 0x4285
23
24 /* Global Elements */
25 #define ID_VOID 0xec
26 #define ID_CRC32 0xbf
27
28 /* WebM Elements */
29 #define ID_SEGMENT 0x18538067
30
31 /* Seek Head Elements */
32 #define ID_SEEK_HEAD 0x114d9b74
33 #define ID_SEEK 0x4dbb
34 #define ID_SEEK_ID 0x53ab
35 #define ID_SEEK_POSITION 0x53ac
36
37 /* Info Elements */
38 #define ID_INFO 0x1549a966
39 #define ID_TIMECODE_SCALE 0x2ad7b1
40 #define ID_DURATION 0x4489
41
42 /* Cluster Elements */
43 #define ID_CLUSTER 0x1f43b675
44 #define ID_TIMECODE 0xe7
45 #define ID_BLOCK_GROUP 0xa0
46 #define ID_SIMPLE_BLOCK 0xa3
47
48 /* BlockGroup Elements */
49 #define ID_BLOCK 0xa1
50 #define ID_BLOCK_DURATION 0x9b
51 #define ID_REFERENCE_BLOCK 0xfb
52 #define ID_DISCARD_PADDING 0x75a2
53
54 /* Tracks Elements */
55 #define ID_TRACKS 0x1654ae6b
56 #define ID_TRACK_ENTRY 0xae
57 #define ID_TRACK_NUMBER 0xd7
58 #define ID_TRACK_UID 0x73c5
59 #define ID_TRACK_TYPE 0x83
60 #define ID_FLAG_ENABLED 0xb9
61 #define ID_FLAG_DEFAULT 0x88
62 #define ID_FLAG_LACING 0x9c
63 #define ID_TRACK_TIMECODE_SCALE 0x23314f
64 #define ID_LANGUAGE 0x22b59c
65 #define ID_CODEC_ID 0x86
66 #define ID_CODEC_PRIVATE 0x63a2
67 #define ID_CODEC_DELAY 0x56aa
68 #define ID_SEEK_PREROLL 0x56bb
69
70 /* Video Elements */
71 #define ID_VIDEO 0xe0
72 #define ID_STEREO_MODE 0x53b8
73 #define ID_PIXEL_WIDTH 0xb0
74 #define ID_PIXEL_HEIGHT 0xba
75 #define ID_PIXEL_CROP_BOTTOM 0x54aa
76 #define ID_PIXEL_CROP_TOP 0x54bb
77 #define ID_PIXEL_CROP_LEFT 0x54cc
78 #define ID_PIXEL_CROP_RIGHT 0x54dd
79 #define ID_DISPLAY_WIDTH 0x54b0
80 #define ID_DISPLAY_HEIGHT 0x54ba
81
82 /* Audio Elements */
83 #define ID_AUDIO 0xe1
84 #define ID_SAMPLING_FREQUENCY 0xb5
85 #define ID_CHANNELS 0x9f
86 #define ID_BIT_DEPTH 0x6264
87
88 /* Cues Elements */
89 #define ID_CUES 0x1c53bb6b
90 #define ID_CUE_POINT 0xbb
91 #define ID_CUE_TIME 0xb3
92 #define ID_CUE_TRACK_POSITIONS 0xb7
93 #define ID_CUE_TRACK 0xf7
94 #define ID_CUE_CLUSTER_POSITION 0xf1
95 #define ID_CUE_BLOCK_NUMBER 0x5378
96
97 /* EBML Types */
98 enum ebml_type_enum {
99 TYPE_UNKNOWN,
100 TYPE_MASTER,
101 TYPE_UINT,
102 TYPE_FLOAT,
103 TYPE_INT,
104 TYPE_STRING,
105 TYPE_BINARY
106 };
107
108 #define LIMIT_STRING (1 << 20)
109 #define LIMIT_BINARY (1 << 24)
110 #define LIMIT_BLOCK (1 << 30)
111 #define LIMIT_FRAME (1 << 28)
112
113 /* Field Flags */
114 #define DESC_FLAG_NONE 0
115 #define DESC_FLAG_MULTI (1 << 0)
116 #define DESC_FLAG_SUSPEND (1 << 1)
117 #define DESC_FLAG_OFFSET (1 << 2)
118
119 /* Block Header Flags */
120 #define BLOCK_FLAGS_LACING 6
121
122 /* Lacing Constants */
123 #define LACING_NONE 0
124 #define LACING_XIPH 1
125 #define LACING_FIXED 2
126 #define LACING_EBML 3
127
128 /* Track Types */
129 #define TRACK_TYPE_VIDEO 1
130 #define TRACK_TYPE_AUDIO 2
131
132 /* Track IDs */
133 #define TRACK_ID_VP8 "V_VP8"
134 #define TRACK_ID_VP9 "V_VP9"
135 #define TRACK_ID_VORBIS "A_VORBIS"
136 #define TRACK_ID_OPUS "A_OPUS"
137
138 enum vint_mask {
139 MASK_NONE,
140 MASK_FIRST_BIT
141 };
142
143 struct ebml_binary {
144 unsigned char * data;
145 size_t length;
146 };
147
148 struct ebml_list_node {
149 struct ebml_list_node * next;
150 uint64_t id;
151 void * data;
152 };
153
154 struct ebml_list {
155 struct ebml_list_node * head;
156 struct ebml_list_node * tail;
157 };
158
159 struct ebml_type {
160 union ebml_value {
161 uint64_t u;
162 double f;
163 int64_t i;
164 char * s;
165 struct ebml_binary b;
166 } v;
167 enum ebml_type_enum type;
168 int read;
169 };
170
171 /* EBML Definitions */
172 struct ebml {
173 struct ebml_type ebml_version;
174 struct ebml_type ebml_read_version;
175 struct ebml_type ebml_max_id_length;
176 struct ebml_type ebml_max_size_length;
177 struct ebml_type doctype;
178 struct ebml_type doctype_version;
179 struct ebml_type doctype_read_version;
180 };
181
182 /* Matroksa Definitions */
183 struct seek {
184 struct ebml_type id;
185 struct ebml_type position;
186 };
187
188 struct seek_head {
189 struct ebml_list seek;
190 };
191
192 struct info {
193 struct ebml_type timecode_scale;
194 struct ebml_type duration;
195 };
196
197 struct block_group {
198 struct ebml_type duration;
199 struct ebml_type reference_block;
200 struct ebml_type discard_padding;
201 };
202
203 struct cluster {
204 struct ebml_type timecode;
205 struct ebml_list block_group;
206 };
207
208 struct video {
209 struct ebml_type stereo_mode;
210 struct ebml_type pixel_width;
211 struct ebml_type pixel_height;
212 struct ebml_type pixel_crop_bottom;
213 struct ebml_type pixel_crop_top;
214 struct ebml_type pixel_crop_left;
215 struct ebml_type pixel_crop_right;
216 struct ebml_type display_width;
217 struct ebml_type display_height;
218 };
219
220 struct audio {
221 struct ebml_type sampling_frequency;
222 struct ebml_type channels;
223 struct ebml_type bit_depth;
224 };
225
226 struct track_entry {
227 struct ebml_type number;
228 struct ebml_type uid;
229 struct ebml_type type;
230 struct ebml_type flag_enabled;
231 struct ebml_type flag_default;
232 struct ebml_type flag_lacing;
233 struct ebml_type track_timecode_scale;
234 struct ebml_type language;
235 struct ebml_type codec_id;
236 struct ebml_type codec_private;
237 struct ebml_type codec_delay;
238 struct ebml_type seek_preroll;
239 struct video video;
240 struct audio audio;
241 };
242
243 struct tracks {
244 struct ebml_list track_entry;
245 };
246
247 struct cue_track_positions {
248 struct ebml_type track;
249 struct ebml_type cluster_position;
250 struct ebml_type block_number;
251 };
252
253 struct cue_point {
254 struct ebml_type time;
255 struct ebml_list cue_track_positions;
256 };
257
258 struct cues {
259 struct ebml_list cue_point;
260 };
261
262 struct segment {
263 struct ebml_list seek_head;
264 struct info info;
265 struct ebml_list cluster;
266 struct tracks tracks;
267 struct cues cues;
268 };
269
270 /* Misc. */
271 struct pool_ctx {
272 char dummy;
273 };
274
275 struct list_node {
276 struct list_node * previous;
277 struct ebml_element_desc * node;
278 unsigned char * data;
279 };
280
281 struct saved_state {
282 int64_t stream_offset;
283 struct list_node * ancestor;
284 uint64_t last_id;
285 uint64_t last_size;
286 int last_valid;
287 };
288
289 struct frame {
290 unsigned char * data;
291 size_t length;
292 struct frame * next;
293 };
294
295 /* Public (opaque) Structures */
296 struct nestegg {
297 nestegg_io * io;
298 nestegg_log log;
299 struct pool_ctx * alloc_pool;
300 uint64_t last_id;
301 uint64_t last_size;
302 int last_valid;
303 struct list_node * ancestor;
304 struct ebml ebml;
305 struct segment segment;
306 int64_t segment_offset;
307 unsigned int track_count;
308 };
309
310 struct nestegg_packet {
311 uint64_t track;
312 uint64_t timecode;
313 struct frame * frame;
314 int64_t discard_padding;
315 };
316
317 /* Element Descriptor */
318 struct ebml_element_desc {
319 char const * name;
320 uint64_t id;
321 enum ebml_type_enum type;
322 size_t offset;
323 unsigned int flags;
324 struct ebml_element_desc * children;
325 size_t size;
326 size_t data_offset;
327 };
328
329 #define E_FIELD(ID, TYPE, STRUCT, FIELD) \
330 { #ID, ID, TYPE, offsetof(STRUCT, FIELD), DESC_FLAG_NONE, NULL, 0, 0 }
331 #define E_MASTER(ID, TYPE, STRUCT, FIELD) \
332 { #ID, ID, TYPE, offsetof(STRUCT, FIELD), DESC_FLAG_MULTI, ne_ ## FIELD ## _el ements, \
333 sizeof(struct FIELD), 0 }
334 #define E_SINGLE_MASTER_O(ID, TYPE, STRUCT, FIELD) \
335 { #ID, ID, TYPE, offsetof(STRUCT, FIELD), DESC_FLAG_OFFSET, ne_ ## FIELD ## _e lements, 0, \
336 offsetof(STRUCT, FIELD ## _offset) }
337 #define E_SINGLE_MASTER(ID, TYPE, STRUCT, FIELD) \
338 { #ID, ID, TYPE, offsetof(STRUCT, FIELD), DESC_FLAG_NONE, ne_ ## FIELD ## _ele ments, 0, 0 }
339 #define E_SUSPEND(ID, TYPE) \
340 { #ID, ID, TYPE, 0, DESC_FLAG_SUSPEND, NULL, 0, 0 }
341 #define E_LAST \
342 { NULL, 0, 0, 0, DESC_FLAG_NONE, NULL, 0, 0 }
343
344 /* EBML Element Lists */
345 static struct ebml_element_desc ne_ebml_elements[] = {
346 E_FIELD(ID_EBML_VERSION, TYPE_UINT, struct ebml, ebml_version),
347 E_FIELD(ID_EBML_READ_VERSION, TYPE_UINT, struct ebml, ebml_read_version),
348 E_FIELD(ID_EBML_MAX_ID_LENGTH, TYPE_UINT, struct ebml, ebml_max_id_length),
349 E_FIELD(ID_EBML_MAX_SIZE_LENGTH, TYPE_UINT, struct ebml, ebml_max_size_length) ,
350 E_FIELD(ID_DOCTYPE, TYPE_STRING, struct ebml, doctype),
351 E_FIELD(ID_DOCTYPE_VERSION, TYPE_UINT, struct ebml, doctype_version),
352 E_FIELD(ID_DOCTYPE_READ_VERSION, TYPE_UINT, struct ebml, doctype_read_version) ,
353 E_LAST
354 };
355
356 /* WebM Element Lists */
357 static struct ebml_element_desc ne_seek_elements[] = {
358 E_FIELD(ID_SEEK_ID, TYPE_BINARY, struct seek, id),
359 E_FIELD(ID_SEEK_POSITION, TYPE_UINT, struct seek, position),
360 E_LAST
361 };
362
363 static struct ebml_element_desc ne_seek_head_elements[] = {
364 E_MASTER(ID_SEEK, TYPE_MASTER, struct seek_head, seek),
365 E_LAST
366 };
367
368 static struct ebml_element_desc ne_info_elements[] = {
369 E_FIELD(ID_TIMECODE_SCALE, TYPE_UINT, struct info, timecode_scale),
370 E_FIELD(ID_DURATION, TYPE_FLOAT, struct info, duration),
371 E_LAST
372 };
373
374 static struct ebml_element_desc ne_block_group_elements[] = {
375 E_SUSPEND(ID_BLOCK, TYPE_BINARY),
376 E_FIELD(ID_BLOCK_DURATION, TYPE_UINT, struct block_group, duration),
377 E_FIELD(ID_REFERENCE_BLOCK, TYPE_INT, struct block_group, reference_block),
378 E_FIELD(ID_DISCARD_PADDING, TYPE_INT, struct block_group, discard_padding),
379 E_LAST
380 };
381
382 static struct ebml_element_desc ne_cluster_elements[] = {
383 E_FIELD(ID_TIMECODE, TYPE_UINT, struct cluster, timecode),
384 E_MASTER(ID_BLOCK_GROUP, TYPE_MASTER, struct cluster, block_group),
385 E_SUSPEND(ID_SIMPLE_BLOCK, TYPE_BINARY),
386 E_LAST
387 };
388
389 static struct ebml_element_desc ne_video_elements[] = {
390 E_FIELD(ID_STEREO_MODE, TYPE_UINT, struct video, stereo_mode),
391 E_FIELD(ID_PIXEL_WIDTH, TYPE_UINT, struct video, pixel_width),
392 E_FIELD(ID_PIXEL_HEIGHT, TYPE_UINT, struct video, pixel_height),
393 E_FIELD(ID_PIXEL_CROP_BOTTOM, TYPE_UINT, struct video, pixel_crop_bottom),
394 E_FIELD(ID_PIXEL_CROP_TOP, TYPE_UINT, struct video, pixel_crop_top),
395 E_FIELD(ID_PIXEL_CROP_LEFT, TYPE_UINT, struct video, pixel_crop_left),
396 E_FIELD(ID_PIXEL_CROP_RIGHT, TYPE_UINT, struct video, pixel_crop_right),
397 E_FIELD(ID_DISPLAY_WIDTH, TYPE_UINT, struct video, display_width),
398 E_FIELD(ID_DISPLAY_HEIGHT, TYPE_UINT, struct video, display_height),
399 E_LAST
400 };
401
402 static struct ebml_element_desc ne_audio_elements[] = {
403 E_FIELD(ID_SAMPLING_FREQUENCY, TYPE_FLOAT, struct audio, sampling_frequency),
404 E_FIELD(ID_CHANNELS, TYPE_UINT, struct audio, channels),
405 E_FIELD(ID_BIT_DEPTH, TYPE_UINT, struct audio, bit_depth),
406 E_LAST
407 };
408
409 static struct ebml_element_desc ne_track_entry_elements[] = {
410 E_FIELD(ID_TRACK_NUMBER, TYPE_UINT, struct track_entry, number),
411 E_FIELD(ID_TRACK_UID, TYPE_UINT, struct track_entry, uid),
412 E_FIELD(ID_TRACK_TYPE, TYPE_UINT, struct track_entry, type),
413 E_FIELD(ID_FLAG_ENABLED, TYPE_UINT, struct track_entry, flag_enabled),
414 E_FIELD(ID_FLAG_DEFAULT, TYPE_UINT, struct track_entry, flag_default),
415 E_FIELD(ID_FLAG_LACING, TYPE_UINT, struct track_entry, flag_lacing),
416 E_FIELD(ID_TRACK_TIMECODE_SCALE, TYPE_FLOAT, struct track_entry, track_timecod e_scale),
417 E_FIELD(ID_LANGUAGE, TYPE_STRING, struct track_entry, language),
418 E_FIELD(ID_CODEC_ID, TYPE_STRING, struct track_entry, codec_id),
419 E_FIELD(ID_CODEC_PRIVATE, TYPE_BINARY, struct track_entry, codec_private),
420 E_FIELD(ID_CODEC_DELAY, TYPE_UINT, struct track_entry, codec_delay),
421 E_FIELD(ID_SEEK_PREROLL, TYPE_UINT, struct track_entry, seek_preroll),
422 E_SINGLE_MASTER(ID_VIDEO, TYPE_MASTER, struct track_entry, video),
423 E_SINGLE_MASTER(ID_AUDIO, TYPE_MASTER, struct track_entry, audio),
424 E_LAST
425 };
426
427 static struct ebml_element_desc ne_tracks_elements[] = {
428 E_MASTER(ID_TRACK_ENTRY, TYPE_MASTER, struct tracks, track_entry),
429 E_LAST
430 };
431
432 static struct ebml_element_desc ne_cue_track_positions_elements[] = {
433 E_FIELD(ID_CUE_TRACK, TYPE_UINT, struct cue_track_positions, track),
434 E_FIELD(ID_CUE_CLUSTER_POSITION, TYPE_UINT, struct cue_track_positions, cluste r_position),
435 E_FIELD(ID_CUE_BLOCK_NUMBER, TYPE_UINT, struct cue_track_positions, block_numb er),
436 E_LAST
437 };
438
439 static struct ebml_element_desc ne_cue_point_elements[] = {
440 E_FIELD(ID_CUE_TIME, TYPE_UINT, struct cue_point, time),
441 E_MASTER(ID_CUE_TRACK_POSITIONS, TYPE_MASTER, struct cue_point, cue_track_posi tions),
442 E_LAST
443 };
444
445 static struct ebml_element_desc ne_cues_elements[] = {
446 E_MASTER(ID_CUE_POINT, TYPE_MASTER, struct cues, cue_point),
447 E_LAST
448 };
449
450 static struct ebml_element_desc ne_segment_elements[] = {
451 E_MASTER(ID_SEEK_HEAD, TYPE_MASTER, struct segment, seek_head),
452 E_SINGLE_MASTER(ID_INFO, TYPE_MASTER, struct segment, info),
453 E_MASTER(ID_CLUSTER, TYPE_MASTER, struct segment, cluster),
454 E_SINGLE_MASTER(ID_TRACKS, TYPE_MASTER, struct segment, tracks),
455 E_SINGLE_MASTER(ID_CUES, TYPE_MASTER, struct segment, cues),
456 E_LAST
457 };
458
459 static struct ebml_element_desc ne_top_level_elements[] = {
460 E_SINGLE_MASTER(ID_EBML, TYPE_MASTER, nestegg, ebml),
461 E_SINGLE_MASTER_O(ID_SEGMENT, TYPE_MASTER, nestegg, segment),
462 E_LAST
463 };
464
465 #undef E_FIELD
466 #undef E_MASTER
467 #undef E_SINGLE_MASTER_O
468 #undef E_SINGLE_MASTER
469 #undef E_SUSPEND
470 #undef E_LAST
471
472 static struct pool_ctx *
473 ne_pool_init(void)
474 {
475 struct pool_ctx * pool;
476
477 pool = h_malloc(sizeof(*pool));
478 if (!pool)
479 abort();
480 return pool;
481 }
482
483 static void
484 ne_pool_destroy(struct pool_ctx * pool)
485 {
486 h_free(pool);
487 }
488
489 static void *
490 ne_pool_alloc(size_t size, struct pool_ctx * pool)
491 {
492 void * p;
493
494 p = h_malloc(size);
495 if (!p)
496 abort();
497 hattach(p, pool);
498 memset(p, 0, size);
499 return p;
500 }
501
502 static void *
503 ne_alloc(size_t size)
504 {
505 void * p;
506
507 p = calloc(1, size);
508 if (!p)
509 abort();
510 return p;
511 }
512
513 static int
514 ne_io_read(nestegg_io * io, void * buffer, size_t length)
515 {
516 return io->read(buffer, length, io->userdata);
517 }
518
519 static int
520 ne_io_seek(nestegg_io * io, int64_t offset, int whence)
521 {
522 return io->seek(offset, whence, io->userdata);
523 }
524
525 static int
526 ne_io_read_skip(nestegg_io * io, size_t length)
527 {
528 size_t get;
529 unsigned char buf[8192];
530 int r = 1;
531
532 while (length > 0) {
533 get = length < sizeof(buf) ? length : sizeof(buf);
534 r = ne_io_read(io, buf, get);
535 if (r != 1)
536 break;
537 length -= get;
538 }
539
540 return r;
541 }
542
543 static int64_t
544 ne_io_tell(nestegg_io * io)
545 {
546 return io->tell(io->userdata);
547 }
548
549 static int
550 ne_bare_read_vint(nestegg_io * io, uint64_t * value, uint64_t * length, enum vin t_mask maskflag)
551 {
552 int r;
553 unsigned char b;
554 size_t maxlen = 8;
555 unsigned int count = 1, mask = 1 << 7;
556
557 r = ne_io_read(io, &b, 1);
558 if (r != 1)
559 return r;
560
561 while (count < maxlen) {
562 if ((b & mask) != 0)
563 break;
564 mask >>= 1;
565 count += 1;
566 }
567
568 if (length)
569 *length = count;
570 *value = b;
571
572 if (maskflag == MASK_FIRST_BIT)
573 *value = b & ~mask;
574
575 while (--count) {
576 r = ne_io_read(io, &b, 1);
577 if (r != 1)
578 return r;
579 *value <<= 8;
580 *value |= b;
581 }
582
583 return 1;
584 }
585
586 static int
587 ne_read_id(nestegg_io * io, uint64_t * value, uint64_t * length)
588 {
589 return ne_bare_read_vint(io, value, length, MASK_NONE);
590 }
591
592 static int
593 ne_read_vint(nestegg_io * io, uint64_t * value, uint64_t * length)
594 {
595 return ne_bare_read_vint(io, value, length, MASK_FIRST_BIT);
596 }
597
598 static int
599 ne_read_svint(nestegg_io * io, int64_t * value, uint64_t * length)
600 {
601 int r;
602 uint64_t uvalue;
603 uint64_t ulength;
604 int64_t svint_subtr[] = {
605 0x3f, 0x1fff,
606 0xfffff, 0x7ffffff,
607 0x3ffffffffLL, 0x1ffffffffffLL,
608 0xffffffffffffLL, 0x7fffffffffffffLL
609 };
610
611 r = ne_bare_read_vint(io, &uvalue, &ulength, MASK_FIRST_BIT);
612 if (r != 1)
613 return r;
614 *value = uvalue - svint_subtr[ulength - 1];
615 if (length)
616 *length = ulength;
617 return r;
618 }
619
620 static int
621 ne_read_uint(nestegg_io * io, uint64_t * val, uint64_t length)
622 {
623 unsigned char b;
624 int r;
625
626 if (length == 0 || length > 8)
627 return -1;
628 r = ne_io_read(io, &b, 1);
629 if (r != 1)
630 return r;
631 *val = b;
632 while (--length) {
633 r = ne_io_read(io, &b, 1);
634 if (r != 1)
635 return r;
636 *val <<= 8;
637 *val |= b;
638 }
639 return 1;
640 }
641
642 static int
643 ne_read_int(nestegg_io * io, int64_t * val, uint64_t length)
644 {
645 int r;
646 uint64_t uval, base;
647
648 r = ne_read_uint(io, &uval, length);
649 if (r != 1)
650 return r;
651
652 if (length < sizeof(int64_t)) {
653 base = 1;
654 base <<= length * 8 - 1;
655 if (uval >= base) {
656 base = 1;
657 base <<= length * 8;
658 } else {
659 base = 0;
660 }
661 *val = uval - base;
662 } else {
663 *val = (int64_t) uval;
664 }
665
666 return 1;
667 }
668
669 static int
670 ne_read_float(nestegg_io * io, double * val, uint64_t length)
671 {
672 union {
673 uint64_t u;
674 float f;
675 double d;
676 } value;
677 int r;
678
679 /* Length == 10 not implemented. */
680 if (length != 4 && length != 8)
681 return -1;
682 r = ne_read_uint(io, &value.u, length);
683 if (r != 1)
684 return r;
685 if (length == 4)
686 *val = value.f;
687 else
688 *val = value.d;
689 return 1;
690 }
691
692 static int
693 ne_read_string(nestegg * ctx, char ** val, uint64_t length)
694 {
695 char * str;
696 int r;
697 const size_t alloc_size = (size_t)length + 1;
698
699 if (length == 0 || length > LIMIT_STRING)
700 return -1;
701 str = ne_pool_alloc(alloc_size, ctx->alloc_pool);
702 r = ne_io_read(ctx->io, (unsigned char *) str, alloc_size - 1);
703 if (r != 1)
704 return r;
705 str[alloc_size - 1] = '\0';
706 *val = str;
707 return 1;
708 }
709
710 static int
711 ne_read_binary(nestegg * ctx, struct ebml_binary * val, uint64_t length)
712 {
713 if (length == 0 || length > LIMIT_BINARY)
714 return -1;
715 val->length = (size_t)length;
716 val->data = ne_pool_alloc(val->length, ctx->alloc_pool);
717 return ne_io_read(ctx->io, val->data, val->length);
718 }
719
720 static int
721 ne_get_uint(struct ebml_type type, uint64_t * value)
722 {
723 if (!type.read)
724 return -1;
725
726 assert(type.type == TYPE_UINT);
727
728 *value = type.v.u;
729
730 return 0;
731 }
732
733 static int
734 ne_get_uint32(struct ebml_type type, unsigned int * value)
735 {
736 uint64_t v;
737 if (ne_get_uint(type, &v))
738 return -1;
739
740 assert((unsigned int)v == v);
741
742 *value = (unsigned int)v;
743
744 return 0;
745 }
746
747 static int
748 ne_get_float(struct ebml_type type, double * value)
749 {
750 if (!type.read)
751 return -1;
752
753 assert(type.type == TYPE_FLOAT);
754
755 *value = type.v.f;
756
757 return 0;
758 }
759
760 static int
761 ne_get_string(struct ebml_type type, char ** value)
762 {
763 if (!type.read)
764 return -1;
765
766 assert(type.type == TYPE_STRING);
767
768 *value = type.v.s;
769
770 return 0;
771 }
772
773 static int
774 ne_get_binary(struct ebml_type type, struct ebml_binary * value)
775 {
776 if (!type.read)
777 return -1;
778
779 assert(type.type == TYPE_BINARY);
780
781 *value = type.v.b;
782
783 return 0;
784 }
785
786 static int
787 ne_is_ancestor_element(uint64_t id, struct list_node * ancestor)
788 {
789 struct ebml_element_desc * element;
790
791 for (; ancestor; ancestor = ancestor->previous)
792 for (element = ancestor->node; element->id; ++element)
793 if (element->id == id)
794 return 1;
795
796 return 0;
797 }
798
799 static struct ebml_element_desc *
800 ne_find_element(uint64_t id, struct ebml_element_desc * elements)
801 {
802 struct ebml_element_desc * element;
803
804 for (element = elements; element->id; ++element)
805 if (element->id == id)
806 return element;
807
808 return NULL;
809 }
810
811 static void
812 ne_ctx_push(nestegg * ctx, struct ebml_element_desc * ancestor, void * data)
813 {
814 struct list_node * item;
815
816 item = ne_alloc(sizeof(*item));
817 item->previous = ctx->ancestor;
818 item->node = ancestor;
819 item->data = data;
820 ctx->ancestor = item;
821 }
822
823 static void
824 ne_ctx_pop(nestegg * ctx)
825 {
826 struct list_node * item;
827
828 item = ctx->ancestor;
829 ctx->ancestor = item->previous;
830 free(item);
831 }
832
833 static int
834 ne_ctx_save(nestegg * ctx, struct saved_state * s)
835 {
836 s->stream_offset = ne_io_tell(ctx->io);
837 if (s->stream_offset < 0)
838 return -1;
839 s->ancestor = ctx->ancestor;
840 s->last_id = ctx->last_id;
841 s->last_size = ctx->last_size;
842 s->last_valid = ctx->last_valid;
843 return 0;
844 }
845
846 static int
847 ne_ctx_restore(nestegg * ctx, struct saved_state * s)
848 {
849 int r;
850
851 r = ne_io_seek(ctx->io, s->stream_offset, NESTEGG_SEEK_SET);
852 if (r != 0)
853 return -1;
854 ctx->ancestor = s->ancestor;
855 ctx->last_id = s->last_id;
856 ctx->last_size = s->last_size;
857 ctx->last_valid = s->last_valid;
858 return 0;
859 }
860
861 static int
862 ne_peek_element(nestegg * ctx, uint64_t * id, uint64_t * size)
863 {
864 int r;
865
866 if (ctx->last_valid) {
867 if (id)
868 *id = ctx->last_id;
869 if (size)
870 *size = ctx->last_size;
871 return 1;
872 }
873
874 r = ne_read_id(ctx->io, &ctx->last_id, NULL);
875 if (r != 1)
876 return r;
877
878 r = ne_read_vint(ctx->io, &ctx->last_size, NULL);
879 if (r != 1)
880 return r;
881
882 if (id)
883 *id = ctx->last_id;
884 if (size)
885 *size = ctx->last_size;
886
887 ctx->last_valid = 1;
888
889 return 1;
890 }
891
892 static int
893 ne_read_element(nestegg * ctx, uint64_t * id, uint64_t * size)
894 {
895 int r;
896
897 r = ne_peek_element(ctx, id, size);
898 if (r != 1)
899 return r;
900
901 ctx->last_valid = 0;
902
903 return 1;
904 }
905
906 static void
907 ne_read_master(nestegg * ctx, struct ebml_element_desc * desc)
908 {
909 struct ebml_list * list;
910 struct ebml_list_node * node, * oldtail;
911
912 assert(desc->type == TYPE_MASTER && desc->flags & DESC_FLAG_MULTI);
913
914 ctx->log(ctx, NESTEGG_LOG_DEBUG, "multi master element %llx (%s)",
915 desc->id, desc->name);
916
917 list = (struct ebml_list *) (ctx->ancestor->data + desc->offset);
918
919 node = ne_pool_alloc(sizeof(*node), ctx->alloc_pool);
920 node->id = desc->id;
921 node->data = ne_pool_alloc(desc->size, ctx->alloc_pool);
922
923 oldtail = list->tail;
924 if (oldtail)
925 oldtail->next = node;
926 list->tail = node;
927 if (!list->head)
928 list->head = node;
929
930 ctx->log(ctx, NESTEGG_LOG_DEBUG, " -> using data %p", node->data);
931
932 ne_ctx_push(ctx, desc->children, node->data);
933 }
934
935 static void
936 ne_read_single_master(nestegg * ctx, struct ebml_element_desc * desc)
937 {
938 assert(desc->type == TYPE_MASTER && !(desc->flags & DESC_FLAG_MULTI));
939
940 ctx->log(ctx, NESTEGG_LOG_DEBUG, "single master element %llx (%s)",
941 desc->id, desc->name);
942 ctx->log(ctx, NESTEGG_LOG_DEBUG, " -> using data %p (%u)",
943 ctx->ancestor->data + desc->offset, desc->offset);
944
945 ne_ctx_push(ctx, desc->children, ctx->ancestor->data + desc->offset);
946 }
947
948 static int
949 ne_read_simple(nestegg * ctx, struct ebml_element_desc * desc, size_t length)
950 {
951 struct ebml_type * storage;
952 int r = 0;
953
954 storage = (struct ebml_type *) (ctx->ancestor->data + desc->offset);
955
956 if (storage->read) {
957 ctx->log(ctx, NESTEGG_LOG_DEBUG, "element %llx (%s) already read, skipping",
958 desc->id, desc->name);
959 return 0;
960 }
961
962 storage->type = desc->type;
963
964 ctx->log(ctx, NESTEGG_LOG_DEBUG, "element %llx (%s) -> %p (%u)",
965 desc->id, desc->name, storage, desc->offset);
966
967 switch (desc->type) {
968 case TYPE_UINT:
969 r = ne_read_uint(ctx->io, &storage->v.u, length);
970 break;
971 case TYPE_FLOAT:
972 r = ne_read_float(ctx->io, &storage->v.f, length);
973 break;
974 case TYPE_INT:
975 r = ne_read_int(ctx->io, &storage->v.i, length);
976 break;
977 case TYPE_STRING:
978 r = ne_read_string(ctx, &storage->v.s, length);
979 break;
980 case TYPE_BINARY:
981 r = ne_read_binary(ctx, &storage->v.b, length);
982 break;
983 case TYPE_MASTER:
984 case TYPE_UNKNOWN:
985 assert(0);
986 break;
987 }
988
989 if (r == 1)
990 storage->read = 1;
991
992 return r;
993 }
994
995 static int
996 ne_parse(nestegg * ctx, struct ebml_element_desc * top_level, int64_t max_offset )
997 {
998 int r;
999 int64_t * data_offset;
1000 uint64_t id, size, peeked_id;
1001 struct ebml_element_desc * element;
1002
1003 if (!ctx->ancestor)
1004 return -1;
1005
1006 for (;;) {
1007 if (max_offset > 0 && ne_io_tell(ctx->io) >= max_offset) {
1008 /* Reached end of offset allowed for parsing - return gracefully */
1009 r = 1;
1010 break;
1011 }
1012 r = ne_peek_element(ctx, &id, &size);
1013 if (r != 1)
1014 break;
1015 peeked_id = id;
1016
1017 element = ne_find_element(id, ctx->ancestor->node);
1018 if (element) {
1019 if (element->flags & DESC_FLAG_SUSPEND) {
1020 assert(element->type == TYPE_BINARY);
1021 ctx->log(ctx, NESTEGG_LOG_DEBUG, "suspend parse at %llx", id);
1022 r = 1;
1023 break;
1024 }
1025
1026 r = ne_read_element(ctx, &id, &size);
1027 if (r != 1)
1028 break;
1029 assert(id == peeked_id);
1030
1031 if (element->flags & DESC_FLAG_OFFSET) {
1032 data_offset = (int64_t *) (ctx->ancestor->data + element->data_offset);
1033 *data_offset = ne_io_tell(ctx->io);
1034 if (*data_offset < 0) {
1035 r = -1;
1036 break;
1037 }
1038 }
1039
1040 if (element->type == TYPE_MASTER) {
1041 if (element->flags & DESC_FLAG_MULTI)
1042 ne_read_master(ctx, element);
1043 else
1044 ne_read_single_master(ctx, element);
1045 continue;
1046 } else {
1047 r = ne_read_simple(ctx, element, (size_t)size);
1048 if (r < 0)
1049 break;
1050 }
1051 } else if (ne_is_ancestor_element(id, ctx->ancestor->previous)) {
1052 ctx->log(ctx, NESTEGG_LOG_DEBUG, "parent element %llx", id);
1053 if (top_level && ctx->ancestor->node == top_level) {
1054 ctx->log(ctx, NESTEGG_LOG_DEBUG, "*** parse about to back up past top_le vel");
1055 r = 1;
1056 break;
1057 }
1058 ne_ctx_pop(ctx);
1059 } else {
1060 r = ne_read_element(ctx, &id, &size);
1061 if (r != 1)
1062 break;
1063
1064 if (id != ID_VOID && id != ID_CRC32)
1065 ctx->log(ctx, NESTEGG_LOG_DEBUG, "unknown element %llx", id);
1066 r = ne_io_read_skip(ctx->io, (size_t)size);
1067 if (r != 1)
1068 break;
1069 }
1070 }
1071
1072 if (r != 1)
1073 while (ctx->ancestor)
1074 ne_ctx_pop(ctx);
1075
1076 return r;
1077 }
1078
1079 static uint64_t
1080 ne_xiph_lace_value(unsigned char ** np)
1081 {
1082 uint64_t lace;
1083 uint64_t value;
1084 unsigned char * p = *np;
1085
1086 lace = *p++;
1087 value = lace;
1088 while (lace == 255) {
1089 lace = *p++;
1090 value += lace;
1091 }
1092
1093 *np = p;
1094
1095 return value;
1096 }
1097
1098 static int
1099 ne_read_xiph_lace_value(nestegg_io * io, uint64_t * value, size_t * consumed)
1100 {
1101 int r;
1102 uint64_t lace;
1103
1104 r = ne_read_uint(io, &lace, 1);
1105 if (r != 1)
1106 return r;
1107 *consumed += 1;
1108
1109 *value = lace;
1110 while (lace == 255) {
1111 r = ne_read_uint(io, &lace, 1);
1112 if (r != 1)
1113 return r;
1114 *consumed += 1;
1115 *value += lace;
1116 }
1117
1118 return 1;
1119 }
1120
1121 static int
1122 ne_read_xiph_lacing(nestegg_io * io, size_t block, size_t * read, uint64_t n, ui nt64_t * sizes)
1123 {
1124 int r;
1125 size_t i = 0;
1126 uint64_t sum = 0;
1127
1128 while (--n) {
1129 r = ne_read_xiph_lace_value(io, &sizes[i], read);
1130 if (r != 1)
1131 return r;
1132 sum += sizes[i];
1133 i += 1;
1134 }
1135
1136 if (*read + sum > block)
1137 return -1;
1138
1139 /* Last frame is the remainder of the block. */
1140 sizes[i] = block - *read - sum;
1141 return 1;
1142 }
1143
1144 static int
1145 ne_read_ebml_lacing(nestegg_io * io, size_t block, size_t * read, uint64_t n, ui nt64_t * sizes)
1146 {
1147 int r;
1148 uint64_t lace, sum, length;
1149 int64_t slace;
1150 size_t i = 0;
1151
1152 r = ne_read_vint(io, &lace, &length);
1153 if (r != 1)
1154 return r;
1155 assert(length <= 8);
1156 *read += (size_t)length;
1157
1158 sizes[i] = lace;
1159 sum = sizes[i];
1160
1161 i += 1;
1162 n -= 1;
1163
1164 while (--n) {
1165 r = ne_read_svint(io, &slace, &length);
1166 if (r != 1)
1167 return r;
1168 assert(length <= 8);
1169 *read += (size_t)length;
1170 sizes[i] = sizes[i - 1] + slace;
1171 sum += sizes[i];
1172 i += 1;
1173 }
1174
1175 if (*read + sum > block)
1176 return -1;
1177
1178 /* Last frame is the remainder of the block. */
1179 sizes[i] = block - *read - sum;
1180 return 1;
1181 }
1182
1183 static uint64_t
1184 ne_get_timecode_scale(nestegg * ctx)
1185 {
1186 uint64_t scale;
1187
1188 if (ne_get_uint(ctx->segment.info.timecode_scale, &scale) != 0)
1189 scale = 1000000;
1190
1191 return scale;
1192 }
1193
1194 static int
1195 ne_map_track_number_to_index(nestegg * ctx,
1196 unsigned int track_number,
1197 unsigned int * track_index)
1198 {
1199 struct ebml_list_node * node;
1200 struct track_entry * t_entry;
1201 uint64_t t_number = 0;
1202
1203 if (!track_index)
1204 return -1;
1205 *track_index = 0;
1206
1207 if (track_number == 0)
1208 return -1;
1209
1210 node = ctx->segment.tracks.track_entry.head;
1211 while (node) {
1212 assert(node->id == ID_TRACK_ENTRY);
1213 t_entry = node->data;
1214 if (ne_get_uint(t_entry->number, &t_number) != 0)
1215 return -1;
1216 if (t_number == track_number)
1217 return 0;
1218 *track_index += 1;
1219 node = node->next;
1220 }
1221
1222 return -1;
1223 }
1224
1225 static struct track_entry *
1226 ne_find_track_entry(nestegg * ctx, unsigned int track)
1227 {
1228 struct ebml_list_node * node;
1229 unsigned int tracks = 0;
1230
1231 node = ctx->segment.tracks.track_entry.head;
1232 while (node) {
1233 assert(node->id == ID_TRACK_ENTRY);
1234 if (track == tracks)
1235 return node->data;
1236 tracks += 1;
1237 node = node->next;
1238 }
1239
1240 return NULL;
1241 }
1242
1243 static int
1244 ne_read_block(nestegg * ctx, uint64_t block_id, uint64_t block_size, nestegg_pac ket ** data)
1245 {
1246 int r;
1247 int64_t timecode, abs_timecode;
1248 nestegg_packet * pkt;
1249 struct cluster * cluster;
1250 struct frame * f, * last;
1251 struct track_entry * entry;
1252 const int track_scale = 1;
1253 uint64_t track_number, length, frame_sizes[256], cluster_tc, flags, frames, tc _scale, total;
1254 unsigned int i, lacing, track;
1255 size_t consumed = 0;
1256
1257 *data = NULL;
1258
1259 if (block_size > LIMIT_BLOCK)
1260 return -1;
1261
1262 r = ne_read_vint(ctx->io, &track_number, &length);
1263 if (r != 1)
1264 return r;
1265
1266 if (track_number == 0 || (unsigned int)track_number != track_number)
1267 return -1;
1268
1269 assert(length <= 8);
1270 consumed += (size_t)length;
1271
1272 r = ne_read_int(ctx->io, &timecode, 2);
1273 if (r != 1)
1274 return r;
1275
1276 consumed += 2;
1277
1278 r = ne_read_uint(ctx->io, &flags, 1);
1279 if (r != 1)
1280 return r;
1281
1282 consumed += 1;
1283
1284 frames = 0;
1285
1286 /* Flags are different between Block and SimpleBlock, but lacing is
1287 encoded the same way. */
1288 lacing = (flags & BLOCK_FLAGS_LACING) >> 1;
1289
1290 switch (lacing) {
1291 case LACING_NONE:
1292 frames = 1;
1293 break;
1294 case LACING_XIPH:
1295 case LACING_FIXED:
1296 case LACING_EBML:
1297 r = ne_read_uint(ctx->io, &frames, 1);
1298 if (r != 1)
1299 return r;
1300 consumed += 1;
1301 frames += 1;
1302 }
1303
1304 if (frames > 256)
1305 return -1;
1306
1307 switch (lacing) {
1308 case LACING_NONE:
1309 frame_sizes[0] = block_size - consumed;
1310 break;
1311 case LACING_XIPH:
1312 if (frames == 1)
1313 return -1;
1314 r = ne_read_xiph_lacing(ctx->io, (size_t)block_size, &consumed, frames, fram e_sizes);
1315 if (r != 1)
1316 return r;
1317 break;
1318 case LACING_FIXED:
1319 if ((block_size - consumed) % frames)
1320 return -1;
1321 for (i = 0; i < frames; ++i)
1322 frame_sizes[i] = (block_size - consumed) / frames;
1323 break;
1324 case LACING_EBML:
1325 if (frames == 1)
1326 return -1;
1327 r = ne_read_ebml_lacing(ctx->io, (size_t)block_size, &consumed, frames, fram e_sizes);
1328 if (r != 1)
1329 return r;
1330 break;
1331 }
1332
1333 /* Sanity check unlaced frame sizes against total block size. */
1334 total = consumed;
1335 for (i = 0; i < frames; ++i)
1336 total += frame_sizes[i];
1337 if (total > block_size)
1338 return -1;
1339
1340 if (ne_map_track_number_to_index(ctx, (unsigned int)track_number, &track) != 0 )
1341 return -1;
1342
1343 entry = ne_find_track_entry(ctx, track);
1344 if (!entry)
1345 return -1;
1346
1347 tc_scale = ne_get_timecode_scale(ctx);
1348
1349 assert(ctx->segment.cluster.tail->id == ID_CLUSTER);
1350 cluster = ctx->segment.cluster.tail->data;
1351 if (ne_get_uint(cluster->timecode, &cluster_tc) != 0)
1352 return -1;
1353
1354 abs_timecode = timecode + cluster_tc;
1355 if (abs_timecode < 0)
1356 return -1;
1357
1358 pkt = ne_alloc(sizeof(*pkt));
1359 pkt->track = track;
1360 pkt->timecode = abs_timecode * tc_scale * track_scale;
1361
1362 ctx->log(ctx, NESTEGG_LOG_DEBUG, "%sblock t %lld pts %f f %llx frames: %llu",
1363 block_id == ID_BLOCK ? "" : "simple", pkt->track, pkt->timecode / 1e9 , flags, frames);
1364
1365 last = NULL;
1366 for (i = 0; i < frames; ++i) {
1367 if (frame_sizes[i] > LIMIT_FRAME) {
1368 nestegg_free_packet(pkt);
1369 return -1;
1370 }
1371 f = ne_alloc(sizeof(*f));
1372 f->length = (size_t)frame_sizes[i];
1373 f->data = ne_alloc(f->length);
1374 r = ne_io_read(ctx->io, f->data, f->length);
1375 if (r != 1) {
1376 free(f->data);
1377 free(f);
1378 nestegg_free_packet(pkt);
1379 return -1;
1380 }
1381
1382 if (!last)
1383 pkt->frame = f;
1384 else
1385 last->next = f;
1386 last = f;
1387 }
1388
1389 *data = pkt;
1390
1391 return 1;
1392 }
1393
1394 static int
1395 ne_read_discard_padding(nestegg * ctx, nestegg_packet * pkt)
1396 {
1397 int r;
1398 uint64_t id, size;
1399 struct ebml_element_desc * element;
1400 struct ebml_type * storage;
1401
1402 r = ne_peek_element(ctx, &id, &size);
1403 if (r != 1)
1404 return r;
1405
1406 if (id != ID_DISCARD_PADDING)
1407 return 1;
1408
1409 element = ne_find_element(id, ctx->ancestor->node);
1410 if (!element)
1411 return 1;
1412
1413 assert((size_t)size == size);
1414 r = ne_read_simple(ctx, element, (size_t)size);
1415 if (r != 1)
1416 return r;
1417 storage = (struct ebml_type *) (ctx->ancestor->data + element->offset);
1418 pkt->discard_padding = storage->v.i;
1419
1420 return 1;
1421 }
1422
1423
1424 static uint64_t
1425 ne_buf_read_id(unsigned char const * p, size_t length)
1426 {
1427 uint64_t id = 0;
1428
1429 while (length--) {
1430 id <<= 8;
1431 id |= *p++;
1432 }
1433
1434 return id;
1435 }
1436
1437 static struct seek *
1438 ne_find_seek_for_id(struct ebml_list_node * seek_head, uint64_t id)
1439 {
1440 struct ebml_list * head;
1441 struct ebml_list_node * seek;
1442 struct ebml_binary binary_id;
1443 struct seek * s;
1444
1445 while (seek_head) {
1446 assert(seek_head->id == ID_SEEK_HEAD);
1447 head = seek_head->data;
1448 seek = head->head;
1449
1450 while (seek) {
1451 assert(seek->id == ID_SEEK);
1452 s = seek->data;
1453
1454 if (ne_get_binary(s->id, &binary_id) == 0 &&
1455 ne_buf_read_id(binary_id.data, binary_id.length) == id)
1456 return s;
1457
1458 seek = seek->next;
1459 }
1460
1461 seek_head = seek_head->next;
1462 }
1463
1464 return NULL;
1465 }
1466
1467 static struct cue_track_positions *
1468 ne_find_cue_position_for_track(nestegg * ctx, struct ebml_list_node * node, unsi gned int track)
1469 {
1470 struct cue_track_positions * pos = NULL;
1471 unsigned int track_number;
1472 unsigned int t;
1473
1474 while (node) {
1475 assert(node->id == ID_CUE_TRACK_POSITIONS);
1476 pos = node->data;
1477 if (ne_get_uint32(pos->track, &track_number) != 0)
1478 return NULL;
1479
1480 if (ne_map_track_number_to_index(ctx, track_number, &t) != 0)
1481 return NULL;
1482
1483 if (t == track)
1484 return pos;
1485
1486 node = node->next;
1487 }
1488
1489 return NULL;
1490 }
1491
1492 static struct cue_point *
1493 ne_find_cue_point_for_tstamp(nestegg * ctx, struct ebml_list_node * cue_point, u nsigned int track, uint64_t scale, uint64_t tstamp)
1494 {
1495 uint64_t time;
1496 struct cue_point * c, * prev = NULL;
1497
1498 while (cue_point) {
1499 assert(cue_point->id == ID_CUE_POINT);
1500 c = cue_point->data;
1501
1502 if (!prev)
1503 prev = c;
1504
1505 if (ne_get_uint(c->time, &time) == 0 && time * scale > tstamp)
1506 break;
1507
1508 if (ne_find_cue_position_for_track(ctx, c->cue_track_positions.head, track) != NULL)
1509 prev = c;
1510
1511 cue_point = cue_point->next;
1512 }
1513
1514 return prev;
1515 }
1516
1517 static int
1518 ne_is_suspend_element(uint64_t id)
1519 {
1520 if (id == ID_SIMPLE_BLOCK || id == ID_BLOCK)
1521 return 1;
1522 return 0;
1523 }
1524
1525 static void
1526 ne_null_log_callback(nestegg * ctx, unsigned int severity, char const * fmt, ... )
1527 {
1528 if (ctx && severity && fmt)
1529 return;
1530 }
1531
1532 static int
1533 ne_init_cue_points(nestegg * ctx, int64_t max_offset)
1534 {
1535 int r;
1536 struct ebml_list_node * node = ctx->segment.cues.cue_point.head;
1537 struct seek * found;
1538 uint64_t seek_pos, id;
1539 struct saved_state state;
1540
1541 /* If there are no cues loaded, check for cues element in the seek head
1542 and load it. */
1543 if (!node) {
1544 found = ne_find_seek_for_id(ctx->segment.seek_head.head, ID_CUES);
1545 if (!found)
1546 return -1;
1547
1548 if (ne_get_uint(found->position, &seek_pos) != 0)
1549 return -1;
1550
1551 /* Save old parser state. */
1552 r = ne_ctx_save(ctx, &state);
1553 if (r != 0)
1554 return -1;
1555
1556 /* Seek and set up parser state for segment-level element (Cues). */
1557 r = ne_io_seek(ctx->io, ctx->segment_offset + seek_pos, NESTEGG_SEEK_SET);
1558 if (r != 0)
1559 return -1;
1560 ctx->last_valid = 0;
1561
1562 r = ne_read_element(ctx, &id, NULL);
1563 if (r != 1)
1564 return -1;
1565
1566 if (id != ID_CUES)
1567 return -1;
1568
1569 ctx->ancestor = NULL;
1570 ne_ctx_push(ctx, ne_top_level_elements, ctx);
1571 ne_ctx_push(ctx, ne_segment_elements, &ctx->segment);
1572 ne_ctx_push(ctx, ne_cues_elements, &ctx->segment.cues);
1573 /* parser will run until end of cues element. */
1574 ctx->log(ctx, NESTEGG_LOG_DEBUG, "seek: parsing cue elements");
1575 r = ne_parse(ctx, ne_cues_elements, max_offset);
1576 while (ctx->ancestor)
1577 ne_ctx_pop(ctx);
1578
1579 /* Reset parser state to original state and seek back to old position. */
1580 if (ne_ctx_restore(ctx, &state) != 0)
1581 return -1;
1582
1583 if (r < 0)
1584 return -1;
1585
1586 node = ctx->segment.cues.cue_point.head;
1587 if (!node)
1588 return -1;
1589 }
1590
1591 return 0;
1592 }
1593
1594 /* Three functions that implement the nestegg_io interface, operating on a
1595 * sniff_buffer. */
1596 struct sniff_buffer {
1597 unsigned char const * buffer;
1598 size_t length;
1599 int64_t offset;
1600 };
1601
1602 static int
1603 ne_buffer_read(void * buffer, size_t length, void * user_data)
1604 {
1605 struct sniff_buffer * sb = user_data;
1606
1607 int rv = 1;
1608 size_t available = sb->length - (size_t)sb->offset;
1609
1610 if (available < length)
1611 return 0;
1612
1613 memcpy(buffer, sb->buffer + sb->offset, length);
1614 sb->offset += length;
1615
1616 return rv;
1617 }
1618
1619 static int
1620 ne_buffer_seek(int64_t offset, int whence, void * user_data)
1621 {
1622 struct sniff_buffer * sb = user_data;
1623 int64_t o = sb->offset;
1624
1625 switch(whence) {
1626 case NESTEGG_SEEK_SET:
1627 o = offset;
1628 break;
1629 case NESTEGG_SEEK_CUR:
1630 o += offset;
1631 break;
1632 case NESTEGG_SEEK_END:
1633 o = sb->length + offset;
1634 break;
1635 }
1636
1637 if (o < 0 || o > (int64_t) sb->length)
1638 return -1;
1639
1640 sb->offset = o;
1641 return 0;
1642 }
1643
1644 static int64_t
1645 ne_buffer_tell(void * user_data)
1646 {
1647 struct sniff_buffer * sb = user_data;
1648 return sb->offset;
1649 }
1650
1651 static int
1652 ne_match_webm(nestegg_io io, int64_t max_offset)
1653 {
1654 int r;
1655 uint64_t id;
1656 char * doctype;
1657 nestegg * ctx;
1658
1659 if (!(io.read && io.seek && io.tell))
1660 return -1;
1661
1662 ctx = ne_alloc(sizeof(*ctx));
1663
1664 ctx->io = ne_alloc(sizeof(*ctx->io));
1665 *ctx->io = io;
1666 ctx->alloc_pool = ne_pool_init();
1667 ctx->log = ne_null_log_callback;
1668
1669 r = ne_peek_element(ctx, &id, NULL);
1670 if (r != 1) {
1671 nestegg_destroy(ctx);
1672 return 0;
1673 }
1674
1675 if (id != ID_EBML) {
1676 nestegg_destroy(ctx);
1677 return 0;
1678 }
1679
1680 ne_ctx_push(ctx, ne_top_level_elements, ctx);
1681
1682 /* we don't check the return value of ne_parse, that might fail because
1683 * max_offset is not on a valid element end point. We only want to check
1684 * the EBML ID and that the doctype is "webm". */
1685 ne_parse(ctx, NULL, max_offset);
1686
1687 if (ne_get_string(ctx->ebml.doctype, &doctype) != 0 ||
1688 strcmp(doctype, "webm") != 0) {
1689 nestegg_destroy(ctx);
1690 return 0;
1691 }
1692
1693 nestegg_destroy(ctx);
1694
1695 return 1;
1696 }
1697
1698 int
1699 nestegg_init(nestegg ** context, nestegg_io io, nestegg_log callback, int64_t ma x_offset)
1700 {
1701 int r;
1702 uint64_t id, version, docversion;
1703 struct ebml_list_node * track;
1704 char * doctype;
1705 nestegg * ctx;
1706
1707 if (!(io.read && io.seek && io.tell))
1708 return -1;
1709
1710 ctx = ne_alloc(sizeof(*ctx));
1711
1712 ctx->io = ne_alloc(sizeof(*ctx->io));
1713 *ctx->io = io;
1714 ctx->log = callback;
1715 ctx->alloc_pool = ne_pool_init();
1716
1717 if (!ctx->log)
1718 ctx->log = ne_null_log_callback;
1719
1720 r = ne_peek_element(ctx, &id, NULL);
1721 if (r != 1) {
1722 nestegg_destroy(ctx);
1723 return -1;
1724 }
1725
1726 if (id != ID_EBML) {
1727 nestegg_destroy(ctx);
1728 return -1;
1729 }
1730
1731 ctx->log(ctx, NESTEGG_LOG_DEBUG, "ctx %p", ctx);
1732
1733 ne_ctx_push(ctx, ne_top_level_elements, ctx);
1734
1735 r = ne_parse(ctx, NULL, max_offset);
1736
1737 if (r != 1) {
1738 nestegg_destroy(ctx);
1739 return -1;
1740 }
1741
1742 if (ne_get_uint(ctx->ebml.ebml_read_version, &version) != 0)
1743 version = 1;
1744 if (version != 1) {
1745 nestegg_destroy(ctx);
1746 return -1;
1747 }
1748
1749 if (ne_get_string(ctx->ebml.doctype, &doctype) != 0)
1750 doctype = "matroska";
1751 if (strcmp(doctype, "webm") != 0) {
1752 nestegg_destroy(ctx);
1753 return -1;
1754 }
1755
1756 if (ne_get_uint(ctx->ebml.doctype_read_version, &docversion) != 0)
1757 docversion = 1;
1758 if (docversion < 1 || docversion > 2) {
1759 nestegg_destroy(ctx);
1760 return -1;
1761 }
1762
1763 if (!ctx->segment.tracks.track_entry.head) {
1764 nestegg_destroy(ctx);
1765 return -1;
1766 }
1767
1768 track = ctx->segment.tracks.track_entry.head;
1769 ctx->track_count = 0;
1770
1771 while (track) {
1772 ctx->track_count += 1;
1773 track = track->next;
1774 }
1775
1776 *context = ctx;
1777
1778 return 0;
1779 }
1780
1781 void
1782 nestegg_destroy(nestegg * ctx)
1783 {
1784 while (ctx->ancestor)
1785 ne_ctx_pop(ctx);
1786 ne_pool_destroy(ctx->alloc_pool);
1787 free(ctx->io);
1788 free(ctx);
1789 }
1790
1791 int
1792 nestegg_duration(nestegg * ctx, uint64_t * duration)
1793 {
1794 uint64_t tc_scale;
1795 double unscaled_duration;
1796
1797 if (ne_get_float(ctx->segment.info.duration, &unscaled_duration) != 0)
1798 return -1;
1799
1800 tc_scale = ne_get_timecode_scale(ctx);
1801
1802 *duration = (uint64_t) (unscaled_duration * tc_scale);
1803 return 0;
1804 }
1805
1806 int
1807 nestegg_tstamp_scale(nestegg * ctx, uint64_t * scale)
1808 {
1809 *scale = ne_get_timecode_scale(ctx);
1810 return 0;
1811 }
1812
1813 int
1814 nestegg_track_count(nestegg * ctx, unsigned int * tracks)
1815 {
1816 *tracks = ctx->track_count;
1817 return 0;
1818 }
1819
1820 int
1821 nestegg_get_cue_point(nestegg * ctx, unsigned int cluster_num, int64_t max_offse t,
1822 int64_t * start_pos, int64_t * end_pos, uint64_t * tstamp)
1823 {
1824 int range_obtained = 0;
1825 unsigned int cluster_count = 0;
1826 struct cue_point * cue_point;
1827 struct cue_track_positions * pos;
1828 uint64_t seek_pos, track_number, tc_scale, time;
1829 struct ebml_list_node * cues_node = ctx->segment.cues.cue_point.head;
1830 struct ebml_list_node * cue_pos_node = NULL;
1831 unsigned int track = 0, track_count = 0, track_index;
1832
1833 if (!start_pos || !end_pos || !tstamp)
1834 return -1;
1835
1836 /* Initialise return values */
1837 *start_pos = -1;
1838 *end_pos = -1;
1839 *tstamp = 0;
1840
1841 if (!cues_node) {
1842 ne_init_cue_points(ctx, max_offset);
1843 cues_node = ctx->segment.cues.cue_point.head;
1844 /* Verify cues have been added to context. */
1845 if (!cues_node)
1846 return -1;
1847 }
1848
1849 nestegg_track_count(ctx, &track_count);
1850
1851 tc_scale = ne_get_timecode_scale(ctx);
1852
1853 while (cues_node && !range_obtained) {
1854 assert(cues_node->id == ID_CUE_POINT);
1855 cue_point = cues_node->data;
1856 cue_pos_node = cue_point->cue_track_positions.head;
1857 while (cue_pos_node) {
1858 assert(cue_pos_node->id == ID_CUE_TRACK_POSITIONS);
1859 pos = cue_pos_node->data;
1860 for (track = 0; track < track_count; track++) {
1861 if (ne_get_uint(pos->track, &track_number) != 0)
1862 return -1;
1863
1864 if (ne_map_track_number_to_index(ctx, (unsigned int)track_number, &track _index) != 0)
1865 return -1;
1866
1867 if (track_index == track) {
1868 if (ne_get_uint(pos->cluster_position, &seek_pos) != 0)
1869 return -1;
1870 if (cluster_count == cluster_num) {
1871 *start_pos = ctx->segment_offset+seek_pos;
1872 if (ne_get_uint(cue_point->time, &time) != 0)
1873 return -1;
1874 *tstamp = time * tc_scale;
1875 } else if (cluster_count == cluster_num+1) {
1876 *end_pos = (ctx->segment_offset+seek_pos)-1;
1877 range_obtained = 1;
1878 break;
1879 }
1880 cluster_count++;
1881 }
1882 }
1883 cue_pos_node = cue_pos_node->next;
1884 }
1885 cues_node = cues_node->next;
1886 }
1887
1888 return 0;
1889 }
1890
1891 int
1892 nestegg_offset_seek(nestegg * ctx, uint64_t offset)
1893 {
1894 int r;
1895
1896 /* Seek and set up parser state for segment-level element (Cluster). */
1897 r = ne_io_seek(ctx->io, offset, NESTEGG_SEEK_SET);
1898 if (r != 0)
1899 return -1;
1900 ctx->last_valid = 0;
1901
1902 while (ctx->ancestor)
1903 ne_ctx_pop(ctx);
1904
1905 ne_ctx_push(ctx, ne_top_level_elements, ctx);
1906 ne_ctx_push(ctx, ne_segment_elements, &ctx->segment);
1907
1908 return 0;
1909 }
1910
1911 int
1912 nestegg_track_seek(nestegg * ctx, unsigned int track, uint64_t tstamp)
1913 {
1914 int r;
1915 struct cue_point * cue_point;
1916 struct cue_track_positions * pos;
1917 uint64_t seek_pos, tc_scale;
1918
1919 /* If there are no cues loaded, check for cues element in the seek head
1920 and load it. */
1921 if (!ctx->segment.cues.cue_point.head) {
1922 r = ne_init_cue_points(ctx, -1);
1923 if (r != 0)
1924 return -1;
1925 }
1926
1927 tc_scale = ne_get_timecode_scale(ctx);
1928
1929 cue_point = ne_find_cue_point_for_tstamp(ctx, ctx->segment.cues.cue_point.head ,
1930 track, tc_scale, tstamp);
1931 if (!cue_point)
1932 return -1;
1933
1934 pos = ne_find_cue_position_for_track(ctx, cue_point->cue_track_positions.head, track);
1935 if (pos == NULL)
1936 return -1;
1937
1938 if (ne_get_uint(pos->cluster_position, &seek_pos) != 0)
1939 return -1;
1940
1941 /* Seek and set up parser state for segment-level element (Cluster). */
1942 r = nestegg_offset_seek(ctx, ctx->segment_offset + seek_pos);
1943 ctx->log(ctx, NESTEGG_LOG_DEBUG, "seek: parsing cluster elements");
1944 r = ne_parse(ctx, NULL, -1);
1945 if (r != 1)
1946 return -1;
1947
1948 if (!ne_is_suspend_element(ctx->last_id))
1949 return -1;
1950
1951 return 0;
1952 }
1953
1954 int
1955 nestegg_track_type(nestegg * ctx, unsigned int track)
1956 {
1957 struct track_entry * entry;
1958 uint64_t type;
1959
1960 entry = ne_find_track_entry(ctx, track);
1961 if (!entry)
1962 return -1;
1963
1964 if (ne_get_uint(entry->type, &type) != 0)
1965 return -1;
1966
1967 if (type & TRACK_TYPE_VIDEO)
1968 return NESTEGG_TRACK_VIDEO;
1969
1970 if (type & TRACK_TYPE_AUDIO)
1971 return NESTEGG_TRACK_AUDIO;
1972
1973 return -1;
1974 }
1975
1976 int
1977 nestegg_track_codec_id(nestegg * ctx, unsigned int track)
1978 {
1979 char * codec_id;
1980 struct track_entry * entry;
1981
1982 entry = ne_find_track_entry(ctx, track);
1983 if (!entry)
1984 return -1;
1985
1986 if (ne_get_string(entry->codec_id, &codec_id) != 0)
1987 return -1;
1988
1989 if (strcmp(codec_id, TRACK_ID_VP8) == 0)
1990 return NESTEGG_CODEC_VP8;
1991
1992 if (strcmp(codec_id, TRACK_ID_VP9) == 0)
1993 return NESTEGG_CODEC_VP9;
1994
1995 if (strcmp(codec_id, TRACK_ID_VORBIS) == 0)
1996 return NESTEGG_CODEC_VORBIS;
1997
1998 if (strcmp(codec_id, TRACK_ID_OPUS) == 0)
1999 return NESTEGG_CODEC_OPUS;
2000
2001 return -1;
2002 }
2003
2004 int
2005 nestegg_track_codec_data_count(nestegg * ctx, unsigned int track,
2006 unsigned int * count)
2007 {
2008 struct track_entry * entry;
2009 struct ebml_binary codec_private;
2010 unsigned char * p;
2011
2012 *count = 0;
2013
2014 entry = ne_find_track_entry(ctx, track);
2015 if (!entry)
2016 return -1;
2017
2018 if (nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_VORBIS)
2019 return -1;
2020
2021 if (ne_get_binary(entry->codec_private, &codec_private) != 0)
2022 return -1;
2023
2024 if (codec_private.length < 1)
2025 return -1;
2026
2027 p = codec_private.data;
2028 *count = *p + 1;
2029
2030 if (*count > 3)
2031 return -1;
2032
2033 return 0;
2034 }
2035
2036 int
2037 nestegg_track_codec_data(nestegg * ctx, unsigned int track, unsigned int item,
2038 unsigned char ** data, size_t * length)
2039 {
2040 struct track_entry * entry;
2041 struct ebml_binary codec_private;
2042 uint64_t sizes[3], total;
2043 unsigned char * p;
2044 unsigned int count, i;
2045
2046 *data = NULL;
2047 *length = 0;
2048
2049 entry = ne_find_track_entry(ctx, track);
2050 if (!entry)
2051 return -1;
2052
2053 if (nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_VORBIS
2054 && nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_OPUS)
2055 return -1;
2056
2057 if (ne_get_binary(entry->codec_private, &codec_private) != 0)
2058 return -1;
2059
2060 if (nestegg_track_codec_id(ctx, track) == NESTEGG_CODEC_VORBIS) {
2061 p = codec_private.data;
2062 count = *p++ + 1;
2063
2064 if (count > 3)
2065 return -1;
2066
2067 i = 0;
2068 total = 0;
2069 while (--count) {
2070 sizes[i] = ne_xiph_lace_value(&p);
2071 total += sizes[i];
2072 i += 1;
2073 }
2074 sizes[i] = codec_private.length - total - (p - codec_private.data);
2075
2076 for (i = 0; i < item; ++i) {
2077 if (sizes[i] > LIMIT_FRAME)
2078 return -1;
2079 p += sizes[i];
2080 }
2081 *data = p;
2082 *length = (size_t)sizes[item];
2083 } else {
2084 *data = codec_private.data;
2085 *length = codec_private.length;
2086 }
2087
2088 return 0;
2089 }
2090
2091 int
2092 nestegg_track_video_params(nestegg * ctx, unsigned int track,
2093 nestegg_video_params * params)
2094 {
2095 struct track_entry * entry;
2096 unsigned int value;
2097
2098 memset(params, 0, sizeof(*params));
2099
2100 entry = ne_find_track_entry(ctx, track);
2101 if (!entry)
2102 return -1;
2103
2104 if (nestegg_track_type(ctx, track) != NESTEGG_TRACK_VIDEO)
2105 return -1;
2106
2107 value = 0;
2108 ne_get_uint32(entry->video.stereo_mode, &value);
2109 if (value <= NESTEGG_VIDEO_STEREO_TOP_BOTTOM ||
2110 value == NESTEGG_VIDEO_STEREO_RIGHT_LEFT)
2111 params->stereo_mode = value;
2112
2113 if (ne_get_uint32(entry->video.pixel_width, &value) != 0)
2114 return -1;
2115 params->width = value;
2116
2117 if (ne_get_uint32(entry->video.pixel_height, &value) != 0)
2118 return -1;
2119 params->height = value;
2120
2121 value = 0;
2122 ne_get_uint32(entry->video.pixel_crop_bottom, &value);
2123 params->crop_bottom = value;
2124
2125 value = 0;
2126 ne_get_uint32(entry->video.pixel_crop_top, &value);
2127 params->crop_top = value;
2128
2129 value = 0;
2130 ne_get_uint32(entry->video.pixel_crop_left, &value);
2131 params->crop_left = value;
2132
2133 value = 0;
2134 ne_get_uint32(entry->video.pixel_crop_right, &value);
2135 params->crop_right = value;
2136
2137 value = params->width;
2138 ne_get_uint32(entry->video.display_width, &value);
2139 params->display_width = value;
2140
2141 value = params->height;
2142 ne_get_uint32(entry->video.display_height, &value);
2143 params->display_height = value;
2144
2145 return 0;
2146 }
2147
2148 int
2149 nestegg_track_audio_params(nestegg * ctx, unsigned int track,
2150 nestegg_audio_params * params)
2151 {
2152 struct track_entry * entry;
2153 unsigned int value;
2154
2155 memset(params, 0, sizeof(*params));
2156
2157 entry = ne_find_track_entry(ctx, track);
2158 if (!entry)
2159 return -1;
2160
2161 if (nestegg_track_type(ctx, track) != NESTEGG_TRACK_AUDIO)
2162 return -1;
2163
2164 params->rate = 8000;
2165 ne_get_float(entry->audio.sampling_frequency, &params->rate);
2166
2167 value = 1;
2168 ne_get_uint32(entry->audio.channels, &value);
2169 params->channels = value;
2170
2171 value = 16;
2172 ne_get_uint32(entry->audio.bit_depth, &value);
2173 params->depth = value;
2174
2175 value = 0;
2176 ne_get_uint32(entry->codec_delay, &value);
2177 params->codec_delay = value;
2178
2179 value = 0;
2180 ne_get_uint32(entry->seek_preroll, &value);
2181 params->seek_preroll = value;
2182
2183 return 0;
2184 }
2185
2186 int
2187 nestegg_read_packet(nestegg * ctx, nestegg_packet ** pkt)
2188 {
2189 int r;
2190 uint64_t id, size;
2191
2192 *pkt = NULL;
2193
2194 for (;;) {
2195 r = ne_peek_element(ctx, &id, &size);
2196 if (r != 1)
2197 return r;
2198
2199 /* Any DESC_FLAG_SUSPEND fields must be handled here. */
2200 if (ne_is_suspend_element(id)) {
2201 r = ne_read_element(ctx, &id, &size);
2202 if (r != 1)
2203 return r;
2204
2205 /* The only DESC_FLAG_SUSPEND fields are Blocks and SimpleBlocks, which we
2206 handle directly. */
2207 r = ne_read_block(ctx, id, size, pkt);
2208 if (r != 1)
2209 return r;
2210
2211 r = ne_read_discard_padding(ctx, *pkt);
2212 if (r != 1)
2213 return r;
2214
2215 return r;
2216 }
2217
2218 r = ne_parse(ctx, NULL, -1);
2219 if (r != 1)
2220 return r;
2221 }
2222
2223 return 1;
2224 }
2225
2226 void
2227 nestegg_free_packet(nestegg_packet * pkt)
2228 {
2229 struct frame * frame;
2230
2231 while (pkt->frame) {
2232 frame = pkt->frame;
2233 pkt->frame = frame->next;
2234 free(frame->data);
2235 free(frame);
2236 }
2237
2238 free(pkt);
2239 }
2240
2241 int
2242 nestegg_packet_track(nestegg_packet * pkt, unsigned int * track)
2243 {
2244 *track = (unsigned int)pkt->track;
2245 return 0;
2246 }
2247
2248 int
2249 nestegg_packet_tstamp(nestegg_packet * pkt, uint64_t * tstamp)
2250 {
2251 *tstamp = pkt->timecode;
2252 return 0;
2253 }
2254
2255 int
2256 nestegg_packet_discard_padding(nestegg_packet * pkt, int64_t * discard_padding)
2257 {
2258 *discard_padding = pkt->discard_padding;
2259 return 0;
2260 }
2261
2262 int
2263 nestegg_packet_count(nestegg_packet * pkt, unsigned int * count)
2264 {
2265 struct frame * f = pkt->frame;
2266
2267 *count = 0;
2268
2269 while (f) {
2270 *count += 1;
2271 f = f->next;
2272 }
2273
2274 return 0;
2275 }
2276
2277 int
2278 nestegg_packet_data(nestegg_packet * pkt, unsigned int item,
2279 unsigned char ** data, size_t * length)
2280 {
2281 struct frame * f = pkt->frame;
2282 unsigned int count = 0;
2283
2284 *data = NULL;
2285 *length = 0;
2286
2287 while (f) {
2288 if (count == item) {
2289 *data = f->data;
2290 *length = f->length;
2291 return 0;
2292 }
2293 count += 1;
2294 f = f->next;
2295 }
2296
2297 return -1;
2298 }
2299
2300 int
2301 nestegg_has_cues(nestegg * ctx)
2302 {
2303 return ctx->segment.cues.cue_point.head ||
2304 ne_find_seek_for_id(ctx->segment.seek_head.head, ID_CUES);
2305 }
2306
2307 int
2308 nestegg_sniff(unsigned char const * buffer, size_t length)
2309 {
2310 nestegg_io io;
2311 struct sniff_buffer user_data;
2312
2313 user_data.buffer = buffer;
2314 user_data.length = length;
2315 user_data.offset = 0;
2316
2317 io.read = ne_buffer_read;
2318 io.seek = ne_buffer_seek;
2319 io.tell = ne_buffer_tell;
2320 io.userdata = &user_data;
2321 return ne_match_webm(io, length);
2322 }
2323
OLDNEW
« no previous file with comments | « source/libvpx/third_party/nestegg/include/nestegg/nestegg.h ('k') | source/libvpx/third_party/nestegg/test/test.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698