📄 matroska.c
字号:
/* * Matroska file demuxer (no muxer yet) * Copyright (c) 2003-2004 The ffmpeg Project * * This library 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 of the License, or (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *//** * @file matroska.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_bmp_id and codec_get_wav_id. */#include "avi.h"#include "intfloat_readwrite.h"/* EBML version supported */#define EBML_VERSION 1/* top-level master-IDs */#define EBML_ID_HEADER 0x1A45DFA3/* IDs in the HEADER master */#define EBML_ID_EBMLVERSION 0x4286#define EBML_ID_EBMLREADVERSION 0x42F7#define EBML_ID_EBMLMAXIDLENGTH 0x42F2#define EBML_ID_EBMLMAXSIZELENGTH 0x42F3#define EBML_ID_DOCTYPE 0x4282#define EBML_ID_DOCTYPEVERSION 0x4287#define EBML_ID_DOCTYPEREADVERSION 0x4285/* general EBML types */#define EBML_ID_VOID 0xEC/* * Matroska element IDs. max. 32-bit. *//* toplevel segment */#define MATROSKA_ID_SEGMENT 0x18538067/* matroska top-level master IDs */#define MATROSKA_ID_INFO 0x1549A966#define MATROSKA_ID_TRACKS 0x1654AE6B#define MATROSKA_ID_CUES 0x1C53BB6B#define MATROSKA_ID_TAGS 0x1254C367#define MATROSKA_ID_SEEKHEAD 0x114D9B74#define MATROSKA_ID_CLUSTER 0x1F43B675/* IDs in the info master */#define MATROSKA_ID_TIMECODESCALE 0x2AD7B1#define MATROSKA_ID_DURATION 0x4489#define MATROSKA_ID_WRITINGAPP 0x5741#define MATROSKA_ID_MUXINGAPP 0x4D80#define MATROSKA_ID_DATEUTC 0x4461/* ID in the tracks master */#define MATROSKA_ID_TRACKENTRY 0xAE/* IDs in the trackentry master */#define MATROSKA_ID_TRACKNUMBER 0xD7#define MATROSKA_ID_TRACKUID 0x73C5#define MATROSKA_ID_TRACKTYPE 0x83#define MATROSKA_ID_TRACKAUDIO 0xE1#define MATROSKA_ID_TRACKVIDEO 0xE0#define MATROSKA_ID_CODECID 0x86#define MATROSKA_ID_CODECPRIVATE 0x63A2#define MATROSKA_ID_CODECNAME 0x258688#define MATROSKA_ID_CODECINFOURL 0x3B4040#define MATROSKA_ID_CODECDOWNLOADURL 0x26B240#define MATROSKA_ID_TRACKNAME 0x536E#define MATROSKA_ID_TRACKLANGUAGE 0x22B59C#define MATROSKA_ID_TRACKFLAGENABLED 0xB9#define MATROSKA_ID_TRACKFLAGDEFAULT 0x88#define MATROSKA_ID_TRACKFLAGLACING 0x9C#define MATROSKA_ID_TRACKMINCACHE 0x6DE7#define MATROSKA_ID_TRACKMAXCACHE 0x6DF8#define MATROSKA_ID_TRACKDEFAULTDURATION 0x23E383/* IDs in the trackvideo master */#define MATROSKA_ID_VIDEOFRAMERATE 0x2383E3#define MATROSKA_ID_VIDEODISPLAYWIDTH 0x54B0#define MATROSKA_ID_VIDEODISPLAYHEIGHT 0x54BA#define MATROSKA_ID_VIDEOPIXELWIDTH 0xB0#define MATROSKA_ID_VIDEOPIXELHEIGHT 0xBA#define MATROSKA_ID_VIDEOFLAGINTERLACED 0x9A#define MATROSKA_ID_VIDEOSTEREOMODE 0x53B9#define MATROSKA_ID_VIDEOASPECTRATIO 0x54B3#define MATROSKA_ID_VIDEOCOLOURSPACE 0x2EB524/* IDs in the trackaudio master */#define MATROSKA_ID_AUDIOSAMPLINGFREQ 0xB5#define MATROSKA_ID_AUDIOBITDEPTH 0x6264#define MATROSKA_ID_AUDIOCHANNELS 0x9F/* ID in the cues master */#define MATROSKA_ID_POINTENTRY 0xBB/* IDs in the pointentry master */#define MATROSKA_ID_CUETIME 0xB3#define MATROSKA_ID_CUETRACKPOSITION 0xB7/* IDs in the cuetrackposition master */#define MATROSKA_ID_CUETRACK 0xF7#define MATROSKA_ID_CUECLUSTERPOSITION 0xF1/* IDs in the tags master *//* TODO *//* IDs in the seekhead master */#define MATROSKA_ID_SEEKENTRY 0x4DBB/* IDs in the seekpoint master */#define MATROSKA_ID_SEEKID 0x53AB#define MATROSKA_ID_SEEKPOSITION 0x53AC/* IDs in the cluster master */#define MATROSKA_ID_CLUSTERTIMECODE 0xE7#define MATROSKA_ID_BLOCKGROUP 0xA0/* IDs in the blockgroup master */#define MATROSKA_ID_BLOCK 0xA1#define MATROSKA_ID_BLOCKDURATION 0x9B#define MATROSKA_ID_BLOCKREFERENCE 0xFBtypedef enum { MATROSKA_TRACK_TYPE_VIDEO = 0x1, MATROSKA_TRACK_TYPE_AUDIO = 0x2, MATROSKA_TRACK_TYPE_COMPLEX = 0x3, MATROSKA_TRACK_TYPE_LOGO = 0x10, MATROSKA_TRACK_TYPE_SUBTITLE = 0x11, MATROSKA_TRACK_TYPE_CONTROL = 0x20,} MatroskaTrackType;typedef enum { MATROSKA_EYE_MODE_MONO = 0x0, MATROSKA_EYE_MODE_RIGHT = 0x1, MATROSKA_EYE_MODE_LEFT = 0x2, MATROSKA_EYE_MODE_BOTH = 0x3,} MatroskaEyeMode;typedef enum { MATROSKA_ASPECT_RATIO_MODE_FREE = 0x0, MATROSKA_ASPECT_RATIO_MODE_KEEP = 0x1, MATROSKA_ASPECT_RATIO_MODE_FIXED = 0x2,} MatroskaAspectRatioMode;/* * These aren't in any way "matroska-form" things, * it's just something I use in the muxer/demuxer. */typedef enum { MATROSKA_TRACK_ENABLED = (1<<0), MATROSKA_TRACK_DEFAULT = (1<<1), MATROSKA_TRACK_LACING = (1<<2), MATROSKA_TRACK_SHIFT = (1<<16)} MatroskaTrackFlags;typedef enum { MATROSKA_VIDEOTRACK_INTERLACED = (MATROSKA_TRACK_SHIFT<<0)} MatroskaVideoTrackFlags;/* * Matroska Codec IDs. Strings. */typedef struct CodecTags{ char *str; enum CodecID id;}CodecTags;#define MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC "V_MS/VFW/FOURCC"#define MATROSKA_CODEC_ID_AUDIO_ACM "A_MS/ACM"CodecTags codec_tags[]={// {"V_MS/VFW/FOURCC" , CODEC_ID_NONE}, {"V_UNCOMPRESSED" , CODEC_ID_RAWVIDEO}, {"V_MPEG4/ISO/SP" , CODEC_ID_MPEG4}, {"V_MPEG4/ISO/ASP" , CODEC_ID_MPEG4}, {"V_MPEG4/ISO/AP" , CODEC_ID_MPEG4}, {"V_MPEG4/ISO/AVC" , CODEC_ID_H264}, {"V_MPEG4/MS/V3" , CODEC_ID_MSMPEG4V3}, {"V_MPEG1" , CODEC_ID_MPEG1VIDEO}, {"V_MPEG2" , CODEC_ID_MPEG2VIDEO}, {"V_MJPEG" , CODEC_ID_MJPEG}, {"V_REAL/RV10" , CODEC_ID_RV10}, {"V_REAL/RV20" , CODEC_ID_RV20}, {"V_REAL/RV30" , CODEC_ID_RV30}, {"V_REAL/RV40" , CODEC_ID_RV40},/* TODO: Real/Quicktime */// {"A_MS/ACM" , CODEC_ID_NONE}, {"A_MPEG/L1" , CODEC_ID_MP3}, {"A_MPEG/L2" , CODEC_ID_MP3}, {"A_MPEG/L3" , CODEC_ID_MP3}, {"A_PCM/INT/BIG" , CODEC_ID_PCM_U16BE}, {"A_PCM/INT/LIT" , CODEC_ID_PCM_U16LE},// {"A_PCM/FLOAT/IEEE" , CODEC_ID_NONE}, {"A_AC3" , CODEC_ID_AC3}, {"A_DTS" , CODEC_ID_DTS}, {"A_VORBIS" , CODEC_ID_VORBIS}, {"A_AAC/MPEG2/" , CODEC_ID_AAC}, {"A_AAC/MPEG4/" , CODEC_ID_AAC}, {NULL , CODEC_ID_NONE}/* TODO: AC3-9/10 (?), Real, Musepack, Quicktime */};/* max. depth in the EBML tree structure */#define EBML_MAX_DEPTH 16typedef 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, uid, stream_index; char *name, *language; char *codec_id, *codec_name; unsigned char *codec_priv; int codec_priv_size; int64_t default_duration; MatroskaTrackFlags flags;} MatroskaTrack;typedef struct MatroskaVideoTrack { MatroskaTrack track; int pixel_width, pixel_height, display_width, display_height; uint32_t fourcc; MatroskaAspectRatioMode ar_mode; MatroskaEyeMode eye_mode; //..} MatroskaVideoTrack;typedef struct MatroskaAudioTrack { MatroskaTrack track; int channels, bitdepth, samplerate; //..} MatroskaAudioTrack;typedef struct MatroskaSubtitleTrack { MatroskaTrack track; //..} MatroskaSubtitleTrack;typedef struct MatroskaLevel { uint64_t start, 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, *muxing_app; int64_t created; /* timescale in the file */ int64_t time_scale; /* position (time, ns) */ int64_t pos; /* num_streams is the number of streams that av_new_stream() was called * for ( = that are available to the calling program). */ int num_tracks, 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, index_parsed, done; /* The index for seeking. */ int num_indexes; MatroskaDemuxIndex *index;} 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_IO; /* 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -