Bug 1064705 - Don't treat EOS as fatal when reading optional block subelements in nestegg_read_packet. r=cajbir

This commit is contained in:
Matthew Gregan 2014-09-10 10:51:28 +12:00
Родитель 6393ec70b5
Коммит ba4e7fa834
6 изменённых файлов: 238 добавлений и 21 удалений

Просмотреть файл

@ -72,8 +72,9 @@ runWithMSE(function () {
}); });
v.addEventListener("ended", function () { v.addEventListener("ended", function () {
is(v.duration, 4, "Video has correct duration"); // XXX: Duration should be exactly 4.0, see bug 1065207.
is(v.currentTime, 4, "Video has played to end"); is(v.duration, 4.001, "Video has correct duration");
is(v.currentTime, 4.001, "Video has played to end");
v.parentNode.removeChild(v); v.parentNode.removeChild(v);
SimpleTest.finish(); SimpleTest.finish();
}); });

Просмотреть файл

@ -32,8 +32,9 @@ runWithMSE(function (ms, v) {
}); });
v.addEventListener("ended", function () { v.addEventListener("ended", function () {
is(v.duration, 4, "Video has correct duration"); // XXX: Duration should be exactly 4.0, see bug 1065207.
is(v.currentTime, 4, "Video has played to end"); is(v.duration, 4.001, "Video has correct duration");
is(v.currentTime, 4.001, "Video has played to end");
SimpleTest.finish(); SimpleTest.finish();
}); });
}); });

Просмотреть файл

@ -34,8 +34,9 @@ runWithMSE(function (ms, v) {
}); });
v.addEventListener("ended", function () { v.addEventListener("ended", function () {
is(v.duration, 4, "Video has correct duration"); // XXX: Duration should be exactly 4.0, see bug 1065207.
is(v.currentTime, 4, "Video has played to end"); is(v.duration, 4.001, "Video has correct duration");
is(v.currentTime, 4.001, "Video has played to end");
SimpleTest.finish(); SimpleTest.finish();
}); });
}); });

Просмотреть файл

@ -5,4 +5,4 @@ Makefile.in build files for the Mozilla build system.
The nestegg git repository is: git://github.com/kinetiknz/nestegg.git The nestegg git repository is: git://github.com/kinetiknz/nestegg.git
The git commit ID used was 276ccd80e723b0edaf0ef42dbacb5a3a42e02d5c. The git commit ID used was 46ab96bcc8b099704cc8a15993f80fe0269a5284.

Просмотреть файл

@ -133,6 +133,7 @@ typedef struct {
unsigned int crop_top; /**< Pixels to crop from the top of the frame. */ unsigned int crop_top; /**< Pixels to crop from the top of the frame. */
unsigned int crop_left; /**< Pixels to crop from the left of the frame. */ unsigned int crop_left; /**< Pixels to crop from the left of the frame. */
unsigned int crop_right; /**< Pixels to crop from the right of the frame. */ unsigned int crop_right; /**< Pixels to crop from the right of the frame. */
unsigned int alpha_mode; /**< 1 if an additional opacity stream is available, otherwise 0. */
} nestegg_video_params; } nestegg_video_params;
/** Parameters specific to an audio track. */ /** Parameters specific to an audio track. */
@ -340,6 +341,19 @@ int nestegg_packet_count(nestegg_packet * packet, unsigned int * count);
int nestegg_packet_data(nestegg_packet * packet, unsigned int item, int nestegg_packet_data(nestegg_packet * packet, unsigned int item,
unsigned char ** data, size_t * length); unsigned char ** data, size_t * length);
/** Get a pointer to additional data with identifier @a id of additional packet
data. If @a id isn't present in the packet, returns -1.
@param packet Packet initialized by #nestegg_read_packet.
@param id Codec specific identifer. For VP8, use 1 to get a VP8 encoded
frame containing an alpha channel in its Y plane.
@param data Storage for the queried data pointer.
The data is owned by the #nestegg_packet packet.
@param length Storage for the queried data size.
@retval 0 Success.
@retval -1 Error. */
int nestegg_packet_additional_data(nestegg_packet * packet, unsigned int id,
unsigned char ** data, size_t * length);
/** Returns discard_padding for given packet /** Returns discard_padding for given packet
@param packet Packet initialized by #nestegg_read_packet. @param packet Packet initialized by #nestegg_read_packet.
@param discard_padding pointer to store discard padding in. @param discard_padding pointer to store discard padding in.

Просмотреть файл

@ -47,10 +47,18 @@
/* BlockGroup Elements */ /* BlockGroup Elements */
#define ID_BLOCK 0xa1 #define ID_BLOCK 0xa1
#define ID_BLOCK_ADDITIONS 0x75a1
#define ID_BLOCK_DURATION 0x9b #define ID_BLOCK_DURATION 0x9b
#define ID_REFERENCE_BLOCK 0xfb #define ID_REFERENCE_BLOCK 0xfb
#define ID_DISCARD_PADDING 0x75a2 #define ID_DISCARD_PADDING 0x75a2
/* BlockAdditions Elements */
#define ID_BLOCK_MORE 0xa6
/* BlockMore Elements */
#define ID_BLOCK_ADD_ID 0xee
#define ID_BLOCK_ADDITIONAL 0xa5
/* Tracks Elements */ /* Tracks Elements */
#define ID_TRACKS 0x1654ae6b #define ID_TRACKS 0x1654ae6b
#define ID_TRACK_ENTRY 0xae #define ID_TRACK_ENTRY 0xae
@ -71,6 +79,7 @@
/* Video Elements */ /* Video Elements */
#define ID_VIDEO 0xe0 #define ID_VIDEO 0xe0
#define ID_STEREO_MODE 0x53b8 #define ID_STEREO_MODE 0x53b8
#define ID_ALPHA_MODE 0x53c0
#define ID_PIXEL_WIDTH 0xb0 #define ID_PIXEL_WIDTH 0xb0
#define ID_PIXEL_HEIGHT 0xba #define ID_PIXEL_HEIGHT 0xba
#define ID_PIXEL_CROP_BOTTOM 0x54aa #define ID_PIXEL_CROP_BOTTOM 0x54aa
@ -195,7 +204,17 @@ struct info {
struct ebml_type duration; struct ebml_type duration;
}; };
struct block_more {
struct ebml_type block_add_id;
struct ebml_type block_additional;
};
struct block_additions {
struct ebml_list block_more;
};
struct block_group { struct block_group {
struct ebml_type block_additions;
struct ebml_type duration; struct ebml_type duration;
struct ebml_type reference_block; struct ebml_type reference_block;
struct ebml_type discard_padding; struct ebml_type discard_padding;
@ -208,6 +227,7 @@ struct cluster {
struct video { struct video {
struct ebml_type stereo_mode; struct ebml_type stereo_mode;
struct ebml_type alpha_mode;
struct ebml_type pixel_width; struct ebml_type pixel_width;
struct ebml_type pixel_height; struct ebml_type pixel_height;
struct ebml_type pixel_crop_bottom; struct ebml_type pixel_crop_bottom;
@ -294,6 +314,13 @@ struct frame {
struct frame * next; struct frame * next;
}; };
struct block_additional {
unsigned int id;
unsigned char * data;
size_t length;
struct block_additional * next;
};
/* Public (opaque) Structures */ /* Public (opaque) Structures */
struct nestegg { struct nestegg {
nestegg_io * io; nestegg_io * io;
@ -314,6 +341,7 @@ struct nestegg_packet {
uint64_t timecode; uint64_t timecode;
uint64_t duration; uint64_t duration;
struct frame * frame; struct frame * frame;
struct block_additional * block_additional;
int64_t discard_padding; int64_t discard_padding;
}; };
@ -374,11 +402,23 @@ static struct ebml_element_desc ne_info_elements[] = {
E_LAST E_LAST
}; };
static struct ebml_element_desc ne_block_more_elements[] = {
E_FIELD(ID_BLOCK_ADD_ID, TYPE_UINT, struct block_more, block_add_id),
E_FIELD(ID_BLOCK_ADDITIONAL, TYPE_BINARY, struct block_more, block_additional),
E_LAST
};
static struct ebml_element_desc ne_block_additions_elements[] = {
E_MASTER(ID_BLOCK_MORE, TYPE_MASTER, struct block_additions, block_more),
E_LAST
};
static struct ebml_element_desc ne_block_group_elements[] = { static struct ebml_element_desc ne_block_group_elements[] = {
E_SUSPEND(ID_BLOCK, TYPE_BINARY), E_SUSPEND(ID_BLOCK, TYPE_BINARY),
E_FIELD(ID_BLOCK_DURATION, TYPE_UINT, struct block_group, duration), E_FIELD(ID_BLOCK_DURATION, TYPE_UINT, struct block_group, duration),
E_FIELD(ID_REFERENCE_BLOCK, TYPE_INT, struct block_group, reference_block), E_FIELD(ID_REFERENCE_BLOCK, TYPE_INT, struct block_group, reference_block),
E_FIELD(ID_DISCARD_PADDING, TYPE_INT, struct block_group, discard_padding), E_FIELD(ID_DISCARD_PADDING, TYPE_INT, struct block_group, discard_padding),
E_SINGLE_MASTER(ID_BLOCK_ADDITIONS, TYPE_MASTER, struct block_group, block_additions),
E_LAST E_LAST
}; };
@ -391,6 +431,7 @@ static struct ebml_element_desc ne_cluster_elements[] = {
static struct ebml_element_desc ne_video_elements[] = { static struct ebml_element_desc ne_video_elements[] = {
E_FIELD(ID_STEREO_MODE, TYPE_UINT, struct video, stereo_mode), E_FIELD(ID_STEREO_MODE, TYPE_UINT, struct video, stereo_mode),
E_FIELD(ID_ALPHA_MODE, TYPE_UINT, struct video, alpha_mode),
E_FIELD(ID_PIXEL_WIDTH, TYPE_UINT, struct video, pixel_width), E_FIELD(ID_PIXEL_WIDTH, TYPE_UINT, struct video, pixel_width),
E_FIELD(ID_PIXEL_HEIGHT, TYPE_UINT, struct video, pixel_height), E_FIELD(ID_PIXEL_HEIGHT, TYPE_UINT, struct video, pixel_height),
E_FIELD(ID_PIXEL_CROP_BOTTOM, TYPE_UINT, struct video, pixel_crop_bottom), E_FIELD(ID_PIXEL_CROP_BOTTOM, TYPE_UINT, struct video, pixel_crop_bottom),
@ -689,14 +730,16 @@ ne_read_string(nestegg * ctx, char ** val, uint64_t length)
char * str; char * str;
int r; int r;
if (length == 0 || length > LIMIT_STRING) if (length > LIMIT_STRING)
return -1; return -1;
str = ne_pool_alloc(length + 1, ctx->alloc_pool); str = ne_pool_alloc(length + 1, ctx->alloc_pool);
if (!str) if (!str)
return -1; return -1;
r = ne_io_read(ctx->io, (unsigned char *) str, length); if (length) {
if (r != 1) r = ne_io_read(ctx->io, (unsigned char *) str, length);
return r; if (r != 1)
return r;
}
str[length] = '\0'; str[length] = '\0';
*val = str; *val = str;
return 1; return 1;
@ -1420,6 +1463,7 @@ ne_read_block_duration(nestegg * ctx, nestegg_packet * pkt)
r = ne_read_simple(ctx, element, size); r = ne_read_simple(ctx, element, size);
if (r != 1) if (r != 1)
return r; return r;
storage = (struct ebml_type *) (ctx->ancestor->data + element->offset); storage = (struct ebml_type *) (ctx->ancestor->data + element->offset);
pkt->duration = storage->v.i * ne_get_timecode_scale(ctx); pkt->duration = storage->v.i * ne_get_timecode_scale(ctx);
@ -1448,12 +1492,123 @@ ne_read_discard_padding(nestegg * ctx, nestegg_packet * pkt)
r = ne_read_simple(ctx, element, size); r = ne_read_simple(ctx, element, size);
if (r != 1) if (r != 1)
return r; return r;
storage = (struct ebml_type *) (ctx->ancestor->data + element->offset); storage = (struct ebml_type *) (ctx->ancestor->data + element->offset);
pkt->discard_padding = storage->v.i; pkt->discard_padding = storage->v.i;
return 1; return 1;
} }
static int
ne_read_block_additions(nestegg * ctx, nestegg_packet * pkt)
{
int r;
uint64_t id, size, data_size;
int64_t block_additions_end, block_more_end;
void * data;
int has_data;
struct block_additional * block_additional;
uint64_t add_id;
assert(pkt != NULL);
assert(pkt->block_additional == NULL);
r = ne_peek_element(ctx, &id, &size);
if (r != 1)
return r;
if (id != ID_BLOCK_ADDITIONS)
return 1;
/* This makes ne_read_element read the next element instead of returning
information about the already "peeked" one. */
ctx->last_valid = 0;
block_additions_end = ne_io_tell(ctx->io) + size;
while (ne_io_tell(ctx->io) < block_additions_end) {
add_id = 1;
data = NULL;
has_data = 0;
r = ne_read_element(ctx, &id, &size);
if (r != 1)
return -1;
if (id != ID_BLOCK_MORE) {
/* We don't know what this element is, so skip over it */
if (id != ID_VOID && id != ID_CRC32)
ctx->log(ctx, NESTEGG_LOG_DEBUG,
"unknown element %llx in BlockAdditions", id);
ne_io_read_skip(ctx->io, size);
continue;
}
block_more_end = ne_io_tell(ctx->io) + size;
while (ne_io_tell(ctx->io) < block_more_end) {
r = ne_read_element(ctx, &id, &size);
if (r != 1) {
free(data);
return r;
}
if (id == ID_BLOCK_ADD_ID) {
r = ne_read_uint(ctx->io, &add_id, size);
if (r != 1) {
free(data);
return r;
}
if (add_id == 0) {
ctx->log(ctx, NESTEGG_LOG_ERROR, "Disallowed BlockAddId 0 used");
free(data);
return -1;
}
} else if (id == ID_BLOCK_ADDITIONAL) {
if (has_data) {
/* BlockAdditional is supposed to only occur once in a
BlockMore. */
ctx->log(ctx, NESTEGG_LOG_ERROR,
"Multiple BlockAdditional elements in a BlockMore");
free(data);
return -1;
}
has_data = 1;
data_size = size;
if (size != 0) {
data = ne_alloc(size);
r = ne_io_read(ctx->io, data, size);
if (r != 1) {
free(data);
return r;
}
}
} else {
/* We don't know what this element is, so skip over it */
if (id != ID_VOID && id != ID_CRC32)
ctx->log(ctx, NESTEGG_LOG_DEBUG,
"unknown element %llx in BlockMore", id);
ne_io_read_skip(ctx->io, size);
}
}
if (has_data == 0) {
ctx->log(ctx, NESTEGG_LOG_ERROR,
"No BlockAdditional element in a BlockMore");
return -1;
}
block_additional = ne_alloc(sizeof(*block_additional));
block_additional->next = pkt->block_additional;
block_additional->id = add_id;
block_additional->data = data;
block_additional->length = data_size;
pkt->block_additional = block_additional;
}
return 1;
}
static uint64_t static uint64_t
ne_buf_read_id(unsigned char const * p, size_t length) ne_buf_read_id(unsigned char const * p, size_t length)
@ -1727,8 +1882,8 @@ ne_match_webm(nestegg_io io, int64_t max_offset)
ne_ctx_push(ctx, ne_top_level_elements, ctx); ne_ctx_push(ctx, ne_top_level_elements, ctx);
/* we don't check the return value of ne_parse, that might fail because /* we don't check the return value of ne_parse, that might fail because
* max_offset is not on a valid element end point. We only want to check max_offset is not on a valid element end point. We only want to check
* the EBML ID and that the doctype is "webm". */ the EBML ID and that the doctype is "webm". */
ne_parse(ctx, NULL, max_offset); ne_parse(ctx, NULL, max_offset);
if (ne_get_string(ctx->ebml.doctype, &doctype) != 0 || if (ne_get_string(ctx->ebml.doctype, &doctype) != 0 ||
@ -2168,6 +2323,10 @@ nestegg_track_video_params(nestegg * ctx, unsigned int track,
value == NESTEGG_VIDEO_STEREO_RIGHT_LEFT) value == NESTEGG_VIDEO_STEREO_RIGHT_LEFT)
params->stereo_mode = value; params->stereo_mode = value;
value = 0;
ne_get_uint(entry->video.alpha_mode, &value);
params->alpha_mode = value;
if (ne_get_uint(entry->video.pixel_width, &value) != 0) if (ne_get_uint(entry->video.pixel_width, &value) != 0)
return -1; return -1;
params->width = value; params->width = value;
@ -2262,7 +2421,7 @@ nestegg_track_default_duration(nestegg * ctx, unsigned int track,
int int
nestegg_read_packet(nestegg * ctx, nestegg_packet ** pkt) nestegg_read_packet(nestegg * ctx, nestegg_packet ** pkt)
{ {
int r; int r, read_block = 0;
uint64_t id, size; uint64_t id, size;
*pkt = NULL; *pkt = NULL;
@ -2284,15 +2443,27 @@ nestegg_read_packet(nestegg * ctx, nestegg_packet ** pkt)
if (r != 1) if (r != 1)
return r; return r;
r = ne_read_block_duration(ctx, *pkt); read_block = 1;
if (r != 1)
return r;
r = ne_read_discard_padding(ctx, *pkt); /* These are not valid elements of a SimpleBlock, only a full-blown
if (r != 1) Block. */
return r; if (id != ID_SIMPLE_BLOCK) {
r = ne_read_block_duration(ctx, *pkt);
if (r < 0)
return r;
return r; r = ne_read_discard_padding(ctx, *pkt);
if (r < 0)
return r;
r = ne_read_block_additions(ctx, *pkt);
if (r < 0)
return r;
}
/* If we have read a block and hit EOS when reading optional block
subelements, don't report EOS until the next call. */
return read_block;
} }
r = ne_parse(ctx, NULL, -1); r = ne_parse(ctx, NULL, -1);
@ -2307,6 +2478,7 @@ void
nestegg_free_packet(nestegg_packet * pkt) nestegg_free_packet(nestegg_packet * pkt)
{ {
struct frame * frame; struct frame * frame;
struct block_additional * block_additional;
while (pkt->frame) { while (pkt->frame) {
frame = pkt->frame; frame = pkt->frame;
@ -2315,6 +2487,13 @@ nestegg_free_packet(nestegg_packet * pkt)
free(frame); free(frame);
} }
while (pkt->block_additional) {
block_additional = pkt->block_additional;
pkt->block_additional = block_additional->next;
free(block_additional->data);
free(block_additional);
}
free(pkt); free(pkt);
} }
@ -2384,6 +2563,27 @@ nestegg_packet_data(nestegg_packet * pkt, unsigned int item,
return -1; return -1;
} }
int
nestegg_packet_additional_data(nestegg_packet * pkt, unsigned int id,
unsigned char ** data, size_t * length)
{
struct block_additional * a = pkt->block_additional;
*data = NULL;
*length = 0;
while (a) {
if (a->id == id) {
*data = a->data;
*length = a->length;
return 0;
}
a = a->next;
}
return -1;
}
int int
nestegg_has_cues(nestegg * ctx) nestegg_has_cues(nestegg * ctx)
{ {