media/libnestegg/src/nestegg.c

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial