--- a/media/libnestegg/include/nestegg.h
+++ b/media/libnestegg/include/nestegg.h
@@ -87,19 +87,20 @@ extern "C" {
#define NESTEGG_LOG_INFO 10 /**< Informational level log message. */
#define NESTEGG_LOG_WARNING 100 /**< Warning level log message. */
#define NESTEGG_LOG_ERROR 1000 /**< Error level log message. */
#define NESTEGG_LOG_CRITICAL 10000 /**< Critical level log message. */
#define NESTEGG_ENCODING_COMPRESSION 0 /**< Content encoding type is compression. */
#define NESTEGG_ENCODING_ENCRYPTION 1 /**< Content encoding type is encryption. */
-#define NESTEGG_PACKET_HAS_SIGNAL_BYTE_FALSE 0 /**< Packet does not have signal byte */
-#define NESTEGG_PACKET_HAS_SIGNAL_BYTE_UNENCRYPTED 1 /**< Packet has signal byte and is unencrypted */
-#define NESTEGG_PACKET_HAS_SIGNAL_BYTE_ENCRYPTED 2 /**< Packet has signal byte and is encrypted */
+#define NESTEGG_PACKET_HAS_SIGNAL_BYTE_FALSE 0 /**< Packet does not have signal byte */
+#define NESTEGG_PACKET_HAS_SIGNAL_BYTE_UNENCRYPTED 1 /**< Packet has signal byte and is unencrypted */
+#define NESTEGG_PACKET_HAS_SIGNAL_BYTE_ENCRYPTED 2 /**< Packet has signal byte and is encrypted */
+#define NESTEGG_PACKET_HAS_SIGNAL_BYTE_PARTITIONED 4 /**< Packet has signal byte and is partitioned */
#define NESTEGG_PACKET_HAS_KEYFRAME_FALSE 0 /**< Packet contains only keyframes. */
#define NESTEGG_PACKET_HAS_KEYFRAME_TRUE 1 /**< Packet does not contain any keyframes */
#define NESTEGG_PACKET_HAS_KEYFRAME_UNKNOWN 2 /**< Packet may or may not contain keyframes */
typedef struct nestegg nestegg; /**< Opaque handle referencing the stream state. */
typedef struct nestegg_packet nestegg_packet; /**< Opaque handle referencing a packet of data. */
@@ -419,31 +420,45 @@ int nestegg_packet_discard_padding(neste
/** Query if a packet is encrypted.
@param packet Packet initialized by #nestegg_read_packet.
@retval #NESTEGG_PACKET_HAS_SIGNAL_BYTE_FALSE No signal byte, encryption
information not read from packet.
@retval #NESTEGG_PACKET_HAS_SIGNAL_BYTE_UNENCRYPTED Encrypted bit not
set, encryption information not read from packet.
@retval #NESTEGG_PACKET_HAS_SIGNAL_BYTE_ENCRYPTED Encrypted bit set,
encryption infomation read from packet.
+ @retval #NESTEGG_PACKET_HAS_SIGNAL_BYTE_PARTITIONED Partitioned bit set,
+ encryption and parition information read from packet.
@retval -1 Error.*/
int nestegg_packet_encryption(nestegg_packet * packet);
/** Query the IV for an encrypted packet. Expects a packet from an encrypted
track, and will return error if given a packet that has no signal btye.
@param packet Packet initialized by #nestegg_read_packet.
@param iv Storage for queried iv.
@param length Length of returned iv, may be 0.
The data is owned by the #nestegg_packet packet.
@retval 0 Success.
@retval -1 Error.
*/
int nestegg_packet_iv(nestegg_packet * packet, unsigned char const ** iv,
size_t * length);
+/** Query the packet for offsets.
+@param packet Packet initialized by #nestegg_read_packet.
+@param partition_offsets Storage for queried offsets.
+@param num_offsets Length of returned offsets, may be 0.
+The data is owned by the #nestegg_packet packet.
+@retval 0 Success.
+@retval -1 Error.
+*/
+int nestegg_packet_offsets(nestegg_packet * packet,
+ uint32_t const ** partition_offsets,
+ uint8_t * num_offsets);
+
/** Returns reference_block given packet
@param packet Packet initialized by #nestegg_read_packet.
@param reference_block pointer to store reference block in.
@retval 0 Success.
@retval -1 Error. */
int nestegg_packet_reference_block(nestegg_packet * packet,
int64_t * reference_block);
--- a/media/libnestegg/src/nestegg.c
+++ b/media/libnestegg/src/nestegg.c
@@ -159,21 +159,26 @@ enum ebml_type_enum {
/* Track Encryption */
#define CONTENT_ENC_ALGO_AES 5
#define AES_SETTINGS_CIPHER_CTR 1
/* Packet Encryption */
#define SIGNAL_BYTE_SIZE 1
#define IV_SIZE 8
+#define NUM_PACKETS_SIZE 1
+#define PACKET_OFFSET_SIZE 4
/* Signal Byte */
#define PACKET_ENCRYPTED 1
#define ENCRYPTED_BIT_MASK (1 << 0)
+#define PACKET_PARTITIONED 2
+#define PARTITIONED_BIT_MASK (1 << 1)
+
enum vint_mask {
MASK_NONE,
MASK_FIRST_BIT
};
struct ebml_binary {
unsigned char * data;
size_t length;
@@ -333,16 +338,18 @@ struct saved_state {
uint64_t last_size;
int last_valid;
};
struct frame_encryption {
unsigned char * iv;
size_t length;
uint8_t signal_byte;
+ uint8_t num_partitions;
+ uint32_t * partition_offsets;
};
struct frame {
unsigned char * data;
size_t length;
struct frame_encryption * frame_encryption;
struct frame * next;
};
@@ -1065,17 +1072,16 @@ ne_read_simple(nestegg * ctx, struct ebm
r = ne_read_string(ctx, &storage->v.s, length);
break;
case TYPE_BINARY:
r = ne_read_binary(ctx, &storage->v.b, length);
break;
case TYPE_MASTER:
case TYPE_UNKNOWN:
default:
- r = 0;
assert(0);
break;
}
if (r == 1)
storage->read = 1;
return r;
@@ -1354,29 +1360,75 @@ ne_find_track_entry(nestegg * ctx, unsig
return node->data;
tracks += 1;
node = node->next;
}
return NULL;
}
+static struct frame *
+ne_alloc_frame(void)
+{
+ struct frame * f = ne_alloc(sizeof(*f));
+
+ if (!f)
+ return NULL;
+
+ f->data = NULL;
+ f->length = 0;
+ f->frame_encryption = NULL;
+ f->next = NULL;
+
+ return f;
+}
+
+static struct frame_encryption *
+ne_alloc_frame_encryption(void)
+{
+ struct frame_encryption * f = ne_alloc(sizeof(*f));
+
+ if (!f)
+ return NULL;
+
+ f->iv = NULL;
+ f->length = 0;
+ f->signal_byte = 0;
+ f->num_partitions = 0;
+ f->partition_offsets = NULL;
+
+ return f;
+}
+
+static void
+ne_free_frame(struct frame * f)
+{
+ if (f->frame_encryption) {
+ free(f->frame_encryption->iv);
+ free(f->frame_encryption->partition_offsets);
+ }
+
+ free(f->frame_encryption);
+ free(f->data);
+ free(f);
+}
+
static int
ne_read_block(nestegg * ctx, uint64_t block_id, uint64_t block_size, nestegg_packet ** data)
{
int r;
int64_t timecode, abs_timecode;
nestegg_packet * pkt;
struct frame * f, * last;
struct track_entry * entry;
double track_scale;
uint64_t track_number, length, frame_sizes[256], cluster_tc, flags, frames, tc_scale, total,
encoding_type, encryption_algo, encryption_mode;
unsigned int i, lacing, track;
- uint8_t signal_byte, keyframe = NESTEGG_PACKET_HAS_KEYFRAME_UNKNOWN;
+ uint8_t signal_byte, keyframe = NESTEGG_PACKET_HAS_KEYFRAME_UNKNOWN, j = 0;
size_t consumed = 0, data_size, encryption_size;
*data = NULL;
if (block_size > LIMIT_BLOCK)
return -1;
r = ne_read_vint(ctx->io, &track_number, &length);
@@ -1419,16 +1471,20 @@ ne_read_block(nestegg * ctx, uint64_t bl
case LACING_XIPH:
case LACING_FIXED:
case LACING_EBML:
r = ne_read_uint(ctx->io, &frames, 1);
if (r != 1)
return r;
consumed += 1;
frames += 1;
+ break;
+ default:
+ assert(0);
+ return -1;
}
if (frames > 256)
return -1;
switch (lacing) {
case LACING_NONE:
frame_sizes[0] = block_size - consumed;
@@ -1448,16 +1504,19 @@ ne_read_block(nestegg * ctx, uint64_t bl
break;
case LACING_EBML:
if (frames == 1)
return -1;
r = ne_read_ebml_lacing(ctx->io, block_size, &consumed, frames, frame_sizes);
if (r != 1)
return r;
break;
+ default:
+ assert(0);
+ return -1;
}
/* Sanity check unlaced frame sizes against total block size. */
total = consumed;
for (i = 0; i < frames; ++i)
total += frame_sizes[i];
if (total > block_size)
return -1;
@@ -1504,82 +1563,98 @@ ne_read_block(nestegg * ctx, uint64_t bl
block_id == ID_BLOCK ? "" : "simple", pkt->track, pkt->timecode / 1e9, flags, frames);
last = NULL;
for (i = 0; i < frames; ++i) {
if (frame_sizes[i] > LIMIT_FRAME) {
nestegg_free_packet(pkt);
return -1;
}
- f = ne_alloc(sizeof(*f));
+ f = ne_alloc_frame();
if (!f) {
nestegg_free_packet(pkt);
return -1;
}
/* Parse encryption */
if (encoding_type == NESTEGG_ENCODING_ENCRYPTION) {
r = ne_io_read(ctx->io, &signal_byte, SIGNAL_BYTE_SIZE);
if (r != 1) {
- free(f);
+ ne_free_frame(f);
nestegg_free_packet(pkt);
return r;
}
- f->frame_encryption = ne_alloc(sizeof(*f->frame_encryption));
+ f->frame_encryption = ne_alloc_frame_encryption();
if (!f->frame_encryption) {
- free(f);
+ ne_free_frame(f);
nestegg_free_packet(pkt);
return -1;
}
f->frame_encryption->signal_byte = signal_byte;
if ((signal_byte & ENCRYPTED_BIT_MASK) == PACKET_ENCRYPTED) {
f->frame_encryption->iv = ne_alloc(IV_SIZE);
if (!f->frame_encryption->iv) {
- free(f->frame_encryption);
- free(f);
+ ne_free_frame(f);
nestegg_free_packet(pkt);
return -1;
}
r = ne_io_read(ctx->io, f->frame_encryption->iv, IV_SIZE);
if (r != 1) {
- free(f->frame_encryption->iv);
- free(f->frame_encryption);
- free(f);
+ ne_free_frame(f);
nestegg_free_packet(pkt);
return r;
}
f->frame_encryption->length = IV_SIZE;
encryption_size = SIGNAL_BYTE_SIZE + IV_SIZE;
+
+ if ((signal_byte & PARTITIONED_BIT_MASK) == PACKET_PARTITIONED) {
+ r = ne_io_read(ctx->io, &f->frame_encryption->num_partitions, NUM_PACKETS_SIZE);
+ if (r != 1) {
+ ne_free_frame(f);
+ nestegg_free_packet(pkt);
+ return r;
+ }
+
+ encryption_size += NUM_PACKETS_SIZE + f->frame_encryption->num_partitions * PACKET_OFFSET_SIZE;
+ f->frame_encryption->partition_offsets = ne_alloc(f->frame_encryption->num_partitions * PACKET_OFFSET_SIZE);
+
+ for (j = 0; j < f->frame_encryption->num_partitions; ++j) {
+ uint64_t value = 0;
+ r = ne_read_uint(ctx->io, &value, PACKET_OFFSET_SIZE);
+ if (r != 1) {
+ break;
+ }
+
+ f->frame_encryption->partition_offsets[j] = (uint32_t) value;
+ }
+
+ /* If any of the partition offsets did not return 1, then fail. */
+ if (j != f->frame_encryption->num_partitions) {
+ ne_free_frame(f);
+ nestegg_free_packet(pkt);
+ return r;
+ }
+ }
} else {
- f->frame_encryption->iv = NULL;
- f->frame_encryption->length = 0;
encryption_size = SIGNAL_BYTE_SIZE;
}
} else {
- f->frame_encryption = NULL;
encryption_size = 0;
}
data_size = frame_sizes[i] - encryption_size;
/* Encryption parsed */
f->data = ne_alloc(data_size);
if (!f->data) {
- if (f->frame_encryption)
- free(f->frame_encryption->iv);
- free(f->frame_encryption);
- free(f);
+ ne_free_frame(f);
nestegg_free_packet(pkt);
return -1;
}
f->length = data_size;
r = ne_io_read(ctx->io, f->data, data_size);
if (r != 1) {
- if (f->frame_encryption)
- free(f->frame_encryption->iv);
- free(f->frame_encryption);
- free(f->data);
- free(f);
+ ne_free_frame(f);
nestegg_free_packet(pkt);
return r;
}
if (!last)
pkt->frame = f;
else
last->next = f;
@@ -1859,70 +1934,70 @@ ne_init_cue_points(nestegg * ctx, int64_
if (!node)
return -1;
}
return 0;
}
/* Three functions that implement the nestegg_io interface, operating on a
- * sniff_buffer. */
-struct sniff_buffer {
+ io_buffer. */
+struct io_buffer {
unsigned char const * buffer;
size_t length;
int64_t offset;
};
static int
ne_buffer_read(void * buffer, size_t length, void * userdata)
{
- struct sniff_buffer * sb = userdata;
+ struct io_buffer * iob = userdata;
int rv = 1;
- size_t available = sb->length - sb->offset;
+ size_t available = iob->length - iob->offset;
if (available < length)
return 0;
- memcpy(buffer, sb->buffer + sb->offset, length);
- sb->offset += length;
+ memcpy(buffer, iob->buffer + iob->offset, length);
+ iob->offset += length;
return rv;
}
static int
ne_buffer_seek(int64_t offset, int whence, void * userdata)
{
- struct sniff_buffer * sb = userdata;
- int64_t o = sb->offset;
+ struct io_buffer * iob = userdata;
+ int64_t o = iob->offset;
switch(whence) {
case NESTEGG_SEEK_SET:
o = offset;
break;
case NESTEGG_SEEK_CUR:
o += offset;
break;
case NESTEGG_SEEK_END:
- o = sb->length + offset;
+ o = iob->length + offset;
break;
}
- if (o < 0 || o > (int64_t) sb->length)
+ if (o < 0 || o > (int64_t) iob->length)
return -1;
- sb->offset = o;
+ iob->offset = o;
return 0;
}
static int64_t
ne_buffer_tell(void * userdata)
{
- struct sniff_buffer * sb = userdata;
- return sb->offset;
+ struct io_buffer * iob = userdata;
+ return iob->offset;
}
static int
ne_context_new(nestegg ** context, nestegg_io io, nestegg_log callback)
{
nestegg * ctx;
if (!(io.read && io.seek && io.tell))
@@ -2345,71 +2420,77 @@ nestegg_track_codec_data_count(nestegg *
}
int
nestegg_track_codec_data(nestegg * ctx, unsigned int track, unsigned int item,
unsigned char ** data, size_t * length)
{
struct track_entry * entry;
struct ebml_binary codec_private;
- uint64_t sizes[3], size, total, avail;
- unsigned char * p;
- unsigned int count, i;
*data = NULL;
*length = 0;
- count = 1;
entry = ne_find_track_entry(ctx, track);
if (!entry)
return -1;
- if (nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_VORBIS
- && nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_OPUS)
+ if (nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_VORBIS &&
+ nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_OPUS)
return -1;
if (ne_get_binary(entry->codec_private, &codec_private) != 0)
return -1;
if (nestegg_track_codec_id(ctx, track) == NESTEGG_CODEC_VORBIS) {
- p = codec_private.data;
- avail = codec_private.length;
- if (avail < 1)
- return -1;
-
- count = *p++ + 1;
- avail -= 1;
-
- if (count > 3 || item >= count)
- return -1;
+ uint64_t count;
+ uint64_t sizes[3];
+ size_t total;
+ unsigned char * p;
+ unsigned int i;
+ int r;
+
+ nestegg_io io;
+ struct io_buffer userdata;
+ userdata.buffer = codec_private.data;
+ userdata.length = codec_private.length;
+ userdata.offset = 0;
+
+ io.read = ne_buffer_read;
+ io.seek = ne_buffer_seek;
+ io.tell = ne_buffer_tell;
+ io.userdata = &userdata;
total = 0;
- for (i = 0; i < count - 1; ++i) {
- size = 0;
- do {
- if (avail - total <= size) {
- return -1;
- }
- size += *p;
- avail -= 1;
- } while (*p++ == 255);
- if (avail - total < size)
- return -1;
- sizes[i] = size;
- total += size;
- }
- sizes[i] = avail - total;
-
+
+ r = ne_read_uint(&io, &count, 1);
+ if (r != 1)
+ return r;
+ total += 1;
+ count += 1;
+
+ if (count > 3)
+ return -1;
+ r = ne_read_xiph_lacing(&io, codec_private.length, &total, count, sizes);
+ if (r != 1)
+ return r;
+
+ if (item >= count)
+ return -1;
+
+ p = codec_private.data + total;
for (i = 0; i < item; ++i) {
p += sizes[i];
}
+ assert((size_t) (p - codec_private.data) <= codec_private.length &&
+ codec_private.length - (p - codec_private.data) >= sizes[item]);
*data = p;
*length = sizes[item];
} else {
- if (item >= count)
+ if (item >= 1)
return -1;
*data = codec_private.data;
*length = codec_private.length;
}
return 0;
}
@@ -2843,22 +2924,18 @@ void
nestegg_free_packet(nestegg_packet * pkt)
{
struct frame * frame;
struct block_additional * block_additional;
while (pkt->frame) {
frame = pkt->frame;
pkt->frame = frame->next;
- if (frame->frame_encryption) {
- free(frame->frame_encryption->iv);
- }
- free(frame->frame_encryption);
- free(frame->data);
- free(frame);
+
+ ne_free_frame(frame);
}
while (pkt->block_additional) {
block_additional = pkt->block_additional;
pkt->block_additional = block_additional->next;
free(block_additional->data);
free(block_additional);
}
@@ -2972,28 +3049,33 @@ nestegg_packet_additional_data(nestegg_p
return -1;
}
int
nestegg_packet_encryption(nestegg_packet * pkt)
{
struct frame * f = pkt->frame;
unsigned char encrypted_bit;
+ unsigned char partitioned_bit;
if (!f->frame_encryption)
return NESTEGG_PACKET_HAS_SIGNAL_BYTE_FALSE;
/* Should never have parsed blocks with both encryption and lacing */
assert(f->next == NULL);
encrypted_bit = f->frame_encryption->signal_byte & ENCRYPTED_BIT_MASK;
+ partitioned_bit = f->frame_encryption->signal_byte & PARTITIONED_BIT_MASK;
if (encrypted_bit != PACKET_ENCRYPTED)
return NESTEGG_PACKET_HAS_SIGNAL_BYTE_UNENCRYPTED;
+ if (partitioned_bit == PACKET_PARTITIONED)
+ return NESTEGG_PACKET_HAS_SIGNAL_BYTE_PARTITIONED;
+
return NESTEGG_PACKET_HAS_SIGNAL_BYTE_ENCRYPTED;
}
int
nestegg_packet_iv(nestegg_packet * pkt, unsigned char const ** iv, size_t * length)
{
struct frame * f = pkt->frame;
unsigned char encrypted_bit;
@@ -3012,27 +3094,56 @@ nestegg_packet_iv(nestegg_packet * pkt,
return 0;
*iv = f->frame_encryption->iv;
*length = f->frame_encryption->length;
return 0;
}
int
+nestegg_packet_offsets(nestegg_packet * pkt,
+ uint32_t const ** partition_offsets,
+ uint8_t * num_partitions)
+{
+ struct frame * f = pkt->frame;
+ unsigned char encrypted_bit;
+ unsigned char partitioned_bit;
+
+ *partition_offsets = NULL;
+ *num_partitions = 0;
+
+ if (!f->frame_encryption)
+ return -1;
+
+ /* Should never have parsed blocks with both encryption and lacing */
+ assert(f->next == NULL);
+
+ encrypted_bit = f->frame_encryption->signal_byte & ENCRYPTED_BIT_MASK;
+ partitioned_bit = f->frame_encryption->signal_byte & PARTITIONED_BIT_MASK;
+
+ if (encrypted_bit != PACKET_ENCRYPTED || partitioned_bit != PACKET_PARTITIONED)
+ return -1;
+
+ *num_partitions = f->frame_encryption->num_partitions;
+ *partition_offsets = f->frame_encryption->partition_offsets;
+ return 0;
+}
+
+int
nestegg_has_cues(nestegg * ctx)
{
return ctx->segment.cues.cue_point.head ||
ne_find_seek_for_id(ctx->segment.seek_head.head, ID_CUES);
}
int
nestegg_sniff(unsigned char const * buffer, size_t length)
{
nestegg_io io;
- struct sniff_buffer userdata;
+ struct io_buffer userdata;
userdata.buffer = buffer;
userdata.length = length;
userdata.offset = 0;
io.read = ne_buffer_read;
io.seek = ne_buffer_seek;
io.tell = ne_buffer_tell;