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

📄 matroskadec.c

📁 mediastreamer2是开源的网络传输媒体流的库
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Matroska file demuxer (no muxer yet) * Copyright (c) 2003-2004 The ffmpeg Project * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *//** * @file matroskadec.c * Matroska file demuxer * by Ronald Bultje <rbultje@ronald.bitfreak.net> * with a little help from Moritz Bunkus <moritz@bunkus.org> * Specs available on the matroska project page: * http://www.matroska.org/. */#include "avformat.h"/* For codec_get_id(). */#include "riff.h"#include "intfloat_readwrite.h"#include "matroska.h"typedef struct Track {    MatroskaTrackType type;    /* Unique track number and track ID. stream_index is the index that     * the calling app uses for this track. */    uint32_t num;    uint32_t uid;    int stream_index;    char *name;    char language[4];    char *codec_id;    char *codec_name;    unsigned char *codec_priv;    int codec_priv_size;    uint64_t default_duration;    MatroskaTrackFlags flags;} MatroskaTrack;typedef struct MatroskaVideoTrack {    MatroskaTrack track;    int pixel_width;    int pixel_height;    int display_width;    int display_height;    uint32_t fourcc;    MatroskaAspectRatioMode ar_mode;    MatroskaEyeMode eye_mode;    //..} MatroskaVideoTrack;typedef struct MatroskaAudioTrack {    MatroskaTrack track;    int channels;    int bitdepth;    int internal_samplerate;    int samplerate;    int block_align;    /* real audio header */    int coded_framesize;    int sub_packet_h;    int frame_size;    int sub_packet_size;    int sub_packet_cnt;    int pkt_cnt;    uint8_t *buf;    //..} MatroskaAudioTrack;typedef struct MatroskaSubtitleTrack {    MatroskaTrack track;    //..} MatroskaSubtitleTrack;#define MAX_TRACK_SIZE (FFMAX(FFMAX(sizeof(MatroskaVideoTrack), \                                    sizeof(MatroskaAudioTrack)), \                                    sizeof(MatroskaSubtitleTrack)))typedef struct MatroskaLevel {    uint64_t start;    uint64_t length;} MatroskaLevel;typedef struct MatroskaDemuxIndex {  uint64_t        pos;   /* of the corresponding *cluster*! */  uint16_t        track; /* reference to 'num' */  uint64_t        time;  /* in nanoseconds */} MatroskaDemuxIndex;typedef struct MatroskaDemuxContext {    AVFormatContext *ctx;    /* ebml stuff */    int num_levels;    MatroskaLevel levels[EBML_MAX_DEPTH];    int level_up;    /* matroska stuff */    char *writing_app;    char *muxing_app;    int64_t created;    /* timescale in the file */    int64_t time_scale;    /* num_streams is the number of streams that av_new_stream() was called     * for ( = that are available to the calling program). */    int num_tracks;    int num_streams;    MatroskaTrack *tracks[MAX_STREAMS];    /* cache for ID peeking */    uint32_t peek_id;    /* byte position of the segment inside the stream */    offset_t segment_start;    /* The packet queue. */    AVPacket **packets;    int num_packets;    /* have we already parse metadata/cues/clusters? */    int metadata_parsed;    int index_parsed;    int done;    /* The index for seeking. */    int num_indexes;    MatroskaDemuxIndex *index;    /* What to skip before effectively reading a packet. */    int skip_to_keyframe;    AVStream *skip_to_stream;} MatroskaDemuxContext;/* * The first few functions handle EBML file parsing. The rest * is the document interpretation. Matroska really just is a * EBML file. *//* * Return: the amount of levels in the hierarchy that the * current element lies higher than the previous one. * The opposite isn't done - that's auto-done using master * element reading. */static intebml_read_element_level_up (MatroskaDemuxContext *matroska){    ByteIOContext *pb = matroska->ctx->pb;    offset_t pos = url_ftell(pb);    int num = 0;    while (matroska->num_levels > 0) {        MatroskaLevel *level = &matroska->levels[matroska->num_levels - 1];        if (pos >= level->start + level->length) {            matroska->num_levels--;            num++;        } else {            break;        }    }    return num;}/* * Read: an "EBML number", which is defined as a variable-length * array of bytes. The first byte indicates the length by giving a * number of 0-bits followed by a one. The position of the first * "one" bit inside the first byte indicates the length of this * number. * Returns: num. of bytes read. < 0 on error. */static intebml_read_num (MatroskaDemuxContext *matroska,               int                   max_size,               uint64_t             *number){    ByteIOContext *pb = matroska->ctx->pb;    int len_mask = 0x80, read = 1, n = 1;    int64_t total = 0;    /* the first byte tells us the length in bytes - get_byte() can normally     * return 0, but since that's not a valid first ebmlID byte, we can     * use it safely here to catch EOS. */    if (!(total = get_byte(pb))) {        /* we might encounter EOS here */        if (!url_feof(pb)) {            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); /* EOS or actual I/O error */    }    /* get the length of the EBML number */    while (read <= max_size && !(total & len_mask)) {        read++;        len_mask >>= 1;    }    if (read > max_size) {        offset_t pos = url_ftell(pb) - 1;        av_log(matroska->ctx, AV_LOG_ERROR,               "Invalid EBML number size tag 0x%02x at pos %"PRIu64" (0x%"PRIx64")\n",               (uint8_t) total, pos, pos);        return AVERROR_INVALIDDATA;    }    /* read out length */    total &= ~len_mask;    while (n++ < read)        total = (total << 8) | get_byte(pb);    *number = total;    return read;}/* * Read: the element content data ID. * Return: the number of bytes read or < 0 on error. */static intebml_read_element_id (MatroskaDemuxContext *matroska,                      uint32_t             *id,                      int                  *level_up){    int read;    uint64_t total;    /* if we re-call this, use our cached ID */    if (matroska->peek_id != 0) {        if (level_up)            *level_up = 0;        *id = matroska->peek_id;        return 0;    }    /* read out the "EBML number", include tag in ID */    if ((read = ebml_read_num(matroska, 4, &total)) < 0)        return read;    *id = matroska->peek_id  = total | (1 << (read * 7));    /* level tracking */    if (level_up)        *level_up = ebml_read_element_level_up(matroska);    return read;}/* * Read: element content length. * Return: the number of bytes read or < 0 on error. */static intebml_read_element_length (MatroskaDemuxContext *matroska,                          uint64_t             *length){    /* clear cache since we're now beyond that data point */    matroska->peek_id = 0;    /* read out the "EBML number", include tag in ID */    return ebml_read_num(matroska, 8, length);}/* * Return: the ID of the next element, or 0 on error. * Level_up contains the amount of levels that this * next element lies higher than the previous one. */static uint32_tebml_peek_id (MatroskaDemuxContext *matroska,              int                  *level_up){    uint32_t id;    if (ebml_read_element_id(matroska, &id, level_up) < 0)        return 0;    return id;}/* * Seek to a given offset. * 0 is success, -1 is failure. */static intebml_read_seek (MatroskaDemuxContext *matroska,                offset_t              offset){    ByteIOContext *pb = matroska->ctx->pb;    /* clear ID cache, if any */    matroska->peek_id = 0;    return (url_fseek(pb, offset, SEEK_SET) == offset) ? 0 : -1;}/* * Skip the next element. * 0 is success, -1 is failure. */static intebml_read_skip (MatroskaDemuxContext *matroska){    ByteIOContext *pb = matroska->ctx->pb;    uint32_t id;    uint64_t length;    int res;    if ((res = ebml_read_element_id(matroska, &id, NULL)) < 0 ||        (res = ebml_read_element_length(matroska, &length)) < 0)        return res;    url_fskip(pb, length);    return 0;}/* * Read the next element as an unsigned int. * 0 is success, < 0 is failure. */static intebml_read_uint (MatroskaDemuxContext *matroska,                uint32_t             *id,                uint64_t             *num){    ByteIOContext *pb = matroska->ctx->pb;    int n = 0, 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 < 1 || size > 8) {        offset_t pos = url_ftell(pb);        av_log(matroska->ctx, AV_LOG_ERROR,               "Invalid uint element size %d at position %"PRId64" (0x%"PRIx64")\n",                size, pos, pos);        return AVERROR_INVALIDDATA;    }    /* big-endian ordening; build up number */    *num = 0;    while (n++ < size)        *num = (*num << 8) | get_byte(pb);    return 0;}/* * Read the next element as a signed int. * 0 is success, < 0 is failure. */static intebml_read_sint (MatroskaDemuxContext *matroska,                uint32_t             *id,                int64_t              *num){    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) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -