📄 matroskadec.c
字号:
ByteIOContext *pb = &matroska->ctx->pb;
int size, n = 1, negative = 0, res;
uint64_t rlength;
if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 ||
(res = ebml_read_element_length(matroska, &rlength)) < 0)
return res;
size = rlength;
if (size < 1 || size > 8) {
offset_t pos = url_ftell(pb);
av_log(matroska->ctx, AV_LOG_ERROR,
"Invalid sint element size %d at position %"PRId64" (0x%"PRIx64")\n",
size, pos, pos);
return AVERROR_INVALIDDATA;
}
if ((*num = get_byte(pb)) & 0x80) {
negative = 1;
*num &= ~0x80;
}
while (n++ < size)
*num = (*num << 8) | get_byte(pb);
/* make signed */
if (negative)
*num = *num - (1LL << ((8 * size) - 1));
return 0;
}
/*
* Read the next element as a float.
* 0 is success, < 0 is failure.
*/
static int
ebml_read_float (MatroskaDemuxContext *matroska,
uint32_t *id,
double *num)
{
ByteIOContext *pb = &matroska->ctx->pb;
int size, res;
uint64_t rlength;
if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 ||
(res = ebml_read_element_length(matroska, &rlength)) < 0)
return res;
size = rlength;
if (size == 4) {
*num= av_int2flt(get_be32(pb));
} else if(size==8){
*num= av_int2dbl(get_be64(pb));
} else{
offset_t pos = url_ftell(pb);
av_log(matroska->ctx, AV_LOG_ERROR,
"Invalid float element size %d at position %"PRIu64" (0x%"PRIx64")\n",
size, pos, pos);
return AVERROR_INVALIDDATA;
}
return 0;
}
/*
* Read the next element as an ASCII string.
* 0 is success, < 0 is failure.
*/
static int
ebml_read_ascii (MatroskaDemuxContext *matroska,
uint32_t *id,
char **str)
{
ByteIOContext *pb = &matroska->ctx->pb;
int size, res;
uint64_t rlength;
if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 ||
(res = ebml_read_element_length(matroska, &rlength)) < 0)
return res;
size = rlength;
/* ebml strings are usually not 0-terminated, so we allocate one
* byte more, read the string and NULL-terminate it ourselves. */
if (size < 0 || !(*str = av_malloc(size + 1))) {
av_log(matroska->ctx, AV_LOG_ERROR, "Memory allocation failed\n");
return AVERROR(ENOMEM);
}
if (get_buffer(pb, (uint8_t *) *str, size) != size) {
offset_t pos = url_ftell(pb);
av_log(matroska->ctx, AV_LOG_ERROR,
"Read error at pos. %"PRIu64" (0x%"PRIx64")\n", pos, pos);
return AVERROR(EIO);
}
(*str)[size] = '\0';
return 0;
}
/*
* Read the next element as a UTF-8 string.
* 0 is success, < 0 is failure.
*/
static int
ebml_read_utf8 (MatroskaDemuxContext *matroska,
uint32_t *id,
char **str)
{
return ebml_read_ascii(matroska, id, str);
}
/*
* Read the next element as a date (nanoseconds since 1/1/2000).
* 0 is success, < 0 is failure.
*/
static int
ebml_read_date (MatroskaDemuxContext *matroska,
uint32_t *id,
int64_t *date)
{
return ebml_read_sint(matroska, id, date);
}
/*
* Read the next element, but only the header. The contents
* are supposed to be sub-elements which can be read separately.
* 0 is success, < 0 is failure.
*/
static int
ebml_read_master (MatroskaDemuxContext *matroska,
uint32_t *id)
{
ByteIOContext *pb = &matroska->ctx->pb;
uint64_t length;
MatroskaLevel *level;
int res;
if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 ||
(res = ebml_read_element_length(matroska, &length)) < 0)
return res;
/* protect... (Heaven forbids that the '>' is true) */
if (matroska->num_levels >= EBML_MAX_DEPTH) {
av_log(matroska->ctx, AV_LOG_ERROR,
"File moves beyond max. allowed depth (%d)\n", EBML_MAX_DEPTH);
return AVERROR(ENOSYS);
}
/* remember level */
level = &matroska->levels[matroska->num_levels++];
level->start = url_ftell(pb);
level->length = length;
return 0;
}
/*
* Read the next element as binary data.
* 0 is success, < 0 is failure.
*/
static int
ebml_read_binary (MatroskaDemuxContext *matroska,
uint32_t *id,
uint8_t **binary,
int *size)
{
ByteIOContext *pb = &matroska->ctx->pb;
uint64_t rlength;
int res;
if ((res = ebml_read_element_id(matroska, id, NULL)) < 0 ||
(res = ebml_read_element_length(matroska, &rlength)) < 0)
return res;
*size = rlength;
if (!(*binary = av_malloc(*size))) {
av_log(matroska->ctx, AV_LOG_ERROR,
"Memory allocation error\n");
return AVERROR(ENOMEM);
}
if (get_buffer(pb, *binary, *size) != *size) {
offset_t pos = url_ftell(pb);
av_log(matroska->ctx, AV_LOG_ERROR,
"Read error at pos. %"PRIu64" (0x%"PRIx64")\n", pos, pos);
return AVERROR(EIO);
}
return 0;
}
/*
* Read signed/unsigned "EBML" numbers.
* Return: number of bytes processed, < 0 on error.
* XXX: use ebml_read_num().
*/
static int
matroska_ebmlnum_uint (uint8_t *data,
uint32_t size,
uint64_t *num)
{
int len_mask = 0x80, read = 1, n = 1, num_ffs = 0;
uint64_t total;
if (size <= 0)
return AVERROR_INVALIDDATA;
total = data[0];
while (read <= 8 && !(total & len_mask)) {
read++;
len_mask >>= 1;
}
if (read > 8)
return AVERROR_INVALIDDATA;
if ((total &= (len_mask - 1)) == len_mask - 1)
num_ffs++;
if (size < read)
return AVERROR_INVALIDDATA;
while (n < read) {
if (data[n] == 0xff)
num_ffs++;
total = (total << 8) | data[n];
n++;
}
if (read == num_ffs)
*num = (uint64_t)-1;
else
*num = total;
return read;
}
/*
* Same as above, but signed.
*/
static int
matroska_ebmlnum_sint (uint8_t *data,
uint32_t size,
int64_t *num)
{
uint64_t unum;
int res;
/* read as unsigned number first */
if ((res = matroska_ebmlnum_uint(data, size, &unum)) < 0)
return res;
/* make signed (weird way) */
if (unum == (uint64_t)-1)
*num = INT64_MAX;
else
*num = unum - ((1LL << ((7 * res) - 1)) - 1);
return res;
}
/*
* Read an EBML header.
* 0 is success, < 0 is failure.
*/
static int
ebml_read_header (MatroskaDemuxContext *matroska,
char **doctype,
int *version)
{
uint32_t id;
int level_up, res = 0;
/* default init */
if (doctype)
*doctype = NULL;
if (version)
*version = 1;
if (!(id = ebml_peek_id(matroska, &level_up)) ||
level_up != 0 || id != EBML_ID_HEADER) {
av_log(matroska->ctx, AV_LOG_ERROR,
"This is not an EBML file (id=0x%x/0x%x)\n", id, EBML_ID_HEADER);
return AVERROR_INVALIDDATA;
}
if ((res = ebml_read_master(matroska, &id)) < 0)
return res;
while (res == 0) {
if (!(id = ebml_peek_id(matroska, &level_up)))
return AVERROR(EIO);
/* end-of-header */
if (level_up)
break;
switch (id) {
/* is our read version uptodate? */
case EBML_ID_EBMLREADVERSION: {
uint64_t num;
if ((res = ebml_read_uint(matroska, &id, &num)) < 0)
return res;
if (num > EBML_VERSION) {
av_log(matroska->ctx, AV_LOG_ERROR,
"EBML version %"PRIu64" (> %d) is not supported\n",
num, EBML_VERSION);
return AVERROR_INVALIDDATA;
}
break;
}
/* we only handle 8 byte lengths at max */
case EBML_ID_EBMLMAXSIZELENGTH: {
uint64_t num;
if ((res = ebml_read_uint(matroska, &id, &num)) < 0)
return res;
if (num > sizeof(uint64_t)) {
av_log(matroska->ctx, AV_LOG_ERROR,
"Integers of size %"PRIu64" (> %zd) not supported\n",
num, sizeof(uint64_t));
return AVERROR_INVALIDDATA;
}
break;
}
/* we handle 4 byte IDs at max */
case EBML_ID_EBMLMAXIDLENGTH: {
uint64_t num;
if ((res = ebml_read_uint(matroska, &id, &num)) < 0)
return res;
if (num > sizeof(uint32_t)) {
av_log(matroska->ctx, AV_LOG_ERROR,
"IDs of size %"PRIu64" (> %zu) not supported\n",
num, sizeof(uint32_t));
return AVERROR_INVALIDDATA;
}
break;
}
case EBML_ID_DOCTYPE: {
char *text;
if ((res = ebml_read_ascii(matroska, &id, &text)) < 0)
return res;
if (doctype) {
if (*doctype)
av_free(*doctype);
*doctype = text;
} else
av_free(text);
break;
}
case EBML_ID_DOCTYPEREADVERSION: {
uint64_t num;
if ((res = ebml_read_uint(matroska, &id, &num)) < 0)
return res;
if (version)
*version = num;
break;
}
default:
av_log(matroska->ctx, AV_LOG_INFO,
"Unknown data type 0x%x in EBML header", id);
/* pass-through */
case EBML_ID_VOID:
/* we ignore these two, as they don't tell us anything we
* care about */
case EBML_ID_EBMLVERSION:
case EBML_ID_DOCTYPEVERSION:
res = ebml_read_skip (matroska);
break;
}
}
return 0;
}
static int
matroska_find_track_by_num (MatroskaDemuxContext *matroska,
int num)
{
int i;
for (i = 0; i < matroska->num_tracks; i++)
if (matroska->tracks[i]->num == num)
return i;
return -1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -