⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 matroskadec.c

📁 ffmpeg的完整源代码和作者自己写的文档。不但有在Linux的工程哦
💻 C
📖 第 1 页 / 共 5 页
字号:
    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 + -