Files
luban-lite/packages/artinchip/mpp/middle_media/base/parser/mkv/matroska.c
刘可亮 724d6bf65e v1.1.2
2025-01-08 19:12:06 +08:00

2150 lines
81 KiB
C

/*
* Copyright (C) 2020-2024 ArtInChip Technology Co. Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Author: <che.jiang@artinchip.com>
* Desc: Matroska file demuxer
*/
#define LOG_TAG "mkv"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "matroska.h"
#include "aic_stream.h"
#include "avi.h"
#include "mpp_mem.h"
#include "mpp_log.h"
#include "mpp_list.h"
#include "aic_parser.h"
#include "aic_tag.h"
#define CHILD_OF(parent) { .def = { .n = parent } }
#define MKV_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
const int mkv_priv_mpeg4audio_sample_rates[16] = {
96000, 88200, 64000, 48000, 44100, 32000,
24000, 22050, 16000, 12000, 11025, 8000, 7350
};
static ebml_syntax g_ebml_syntax[3], g_matroska_segment[9], g_matroska_track_video_color[15], g_matroska_track_video[19],
g_matroska_track[27], g_matroska_track_encoding[6], g_matroska_track_encodings[2],
g_matroska_track_combine_planes[2], g_matroska_track_operation[2], g_matroska_tracks[2],
g_matroska_attachments[2], g_matroska_chapter_entry[9], g_matroska_chapter[6], g_matroska_chapters[2],
g_matroska_index_entry[3], g_matroska_index[2], g_matroska_tag[3], g_matroska_tags[2], g_matroska_seekhead[2],
g_matroska_blockadditions[2], g_matroska_blockgroup[8], g_matroska_cluster_parsing[8];
static ebml_syntax g_ebml_header[] = {
{ EBML_ID_EBMLREADVERSION, EBML_UINT, 0, mpp_offsetof(ebml_header, version), { .u = EBML_VERSION } },
{ EBML_ID_EBMLMAXSIZELENGTH, EBML_UINT, 0, mpp_offsetof(ebml_header, max_size), { .u = 8 } },
{ EBML_ID_EBMLMAXIDLENGTH, EBML_UINT, 0, mpp_offsetof(ebml_header, id_length), { .u = 4 } },
{ EBML_ID_DOCTYPE, EBML_STR, 0, mpp_offsetof(ebml_header, doctype), { .s = "(none)" } },
{ EBML_ID_DOCTYPEREADVERSION, EBML_UINT, 0, mpp_offsetof(ebml_header, doctype_version), { .u = 1 } },
{ EBML_ID_EBMLVERSION, EBML_NONE },
{ EBML_ID_DOCTYPEVERSION, EBML_NONE },
CHILD_OF(g_ebml_syntax)
};
static ebml_syntax g_ebml_syntax[] = {
{ EBML_ID_HEADER, EBML_NEST, 0, 0, { .n = g_ebml_header } },
{ MATROSKA_ID_SEGMENT, EBML_STOP },
{ 0 }
};
static ebml_syntax g_matroska_info[] = {
{ MATROSKA_ID_TIMECODESCALE, EBML_UINT, 0, mpp_offsetof(struct matroska_demux_context, time_scale), { .u = 1000000 } },
{ MATROSKA_ID_DURATION, EBML_FLOAT, 0, mpp_offsetof(struct matroska_demux_context, duration) },
{ MATROSKA_ID_TITLE, EBML_UTF8, 0, mpp_offsetof(struct matroska_demux_context, title) },
{ MATROSKA_ID_WRITINGAPP, EBML_NONE },
{ MATROSKA_ID_MUXINGAPP, EBML_UTF8, 0, mpp_offsetof(struct matroska_demux_context, muxingapp) },
{ MATROSKA_ID_DATEUTC, EBML_BIN, 0, mpp_offsetof(struct matroska_demux_context, date_utc) },
{ MATROSKA_ID_SEGMENTUID, EBML_NONE },
CHILD_OF(g_matroska_segment)
};
static ebml_syntax g_matroska_mastering_meta[] = {
{ MATROSKA_ID_VIDEOCOLOR_RX, EBML_FLOAT, 0, mpp_offsetof(matroska_mastering_meta, r_x), { .f=-1 } },
{ MATROSKA_ID_VIDEOCOLOR_RY, EBML_FLOAT, 0, mpp_offsetof(matroska_mastering_meta, r_y), { .f=-1 } },
{ MATROSKA_ID_VIDEOCOLOR_GX, EBML_FLOAT, 0, mpp_offsetof(matroska_mastering_meta, g_x), { .f=-1 } },
{ MATROSKA_ID_VIDEOCOLOR_GY, EBML_FLOAT, 0, mpp_offsetof(matroska_mastering_meta, g_y), { .f=-1 } },
{ MATROSKA_ID_VIDEOCOLOR_BX, EBML_FLOAT, 0, mpp_offsetof(matroska_mastering_meta, b_x), { .f=-1 } },
{ MATROSKA_ID_VIDEOCOLOR_BY, EBML_FLOAT, 0, mpp_offsetof(matroska_mastering_meta, b_y), { .f=-1 } },
{ MATROSKA_ID_VIDEOCOLOR_WHITEX, EBML_FLOAT, 0, mpp_offsetof(matroska_mastering_meta, white_x), { .f=-1 } },
{ MATROSKA_ID_VIDEOCOLOR_WHITEY, EBML_FLOAT, 0, mpp_offsetof(matroska_mastering_meta, white_y), { .f=-1 } },
{ MATROSKA_ID_VIDEOCOLOR_LUMINANCEMIN, EBML_FLOAT, 0, mpp_offsetof(matroska_mastering_meta, min_luminance), { .f=-1 } },
{ MATROSKA_ID_VIDEOCOLOR_LUMINANCEMAX, EBML_FLOAT, 0, mpp_offsetof(matroska_mastering_meta, max_luminance), { .f=-1 } },
CHILD_OF(g_matroska_track_video_color)
};
static ebml_syntax g_matroska_track_video_color[] = {
{ MATROSKA_ID_VIDEOCOLORMATRIXCOEFF, EBML_UINT, 0, mpp_offsetof(matroska_track_video_color, matrix_coefficients), { .u = 2 } },
{ MATROSKA_ID_VIDEOCOLORBITSPERCHANNEL, EBML_UINT, 0, mpp_offsetof(matroska_track_video_color, bits_per_channel), { .u=0 } },
{ MATROSKA_ID_VIDEOCOLORCHROMASUBHORZ, EBML_UINT, 0, mpp_offsetof(matroska_track_video_color, chroma_sub_horz), { .u=0 } },
{ MATROSKA_ID_VIDEOCOLORCHROMASUBVERT, EBML_UINT, 0, mpp_offsetof(matroska_track_video_color, chroma_sub_vert), { .u=0 } },
{ MATROSKA_ID_VIDEOCOLORCBSUBHORZ, EBML_UINT, 0, mpp_offsetof(matroska_track_video_color, cb_sub_horz), { .u=0 } },
{ MATROSKA_ID_VIDEOCOLORCBSUBVERT, EBML_UINT, 0, mpp_offsetof(matroska_track_video_color, cb_sub_vert), { .u=0 } },
{ MATROSKA_ID_VIDEOCOLORCHROMASITINGHORZ, EBML_UINT, 0, mpp_offsetof(matroska_track_video_color, chroma_siting_horz), { .u = MATROSKA_COLOUR_CHROMASITINGHORZ_UNDETERMINED } },
{ MATROSKA_ID_VIDEOCOLORCHROMASITINGVERT, EBML_UINT, 0, mpp_offsetof(matroska_track_video_color, chroma_siting_vert), { .u = MATROSKA_COLOUR_CHROMASITINGVERT_UNDETERMINED } },
{ MATROSKA_ID_VIDEOCOLORRANGE, EBML_UINT, 0, mpp_offsetof(matroska_track_video_color, range), { .u = 0 } },
{ MATROSKA_ID_VIDEOCOLORTRANSFERCHARACTERISTICS, EBML_UINT, 0, mpp_offsetof(matroska_track_video_color, transfer_characteristics), { .u = 2 } },
{ MATROSKA_ID_VIDEOCOLORPRIMARIES, EBML_UINT, 0, mpp_offsetof(matroska_track_video_color, primaries), { .u = 2 } },
{ MATROSKA_ID_VIDEOCOLORMAXCLL, EBML_UINT, 0, mpp_offsetof(matroska_track_video_color, max_cll), { .u=0 } },
{ MATROSKA_ID_VIDEOCOLORMAXFALL, EBML_UINT, 0, mpp_offsetof(matroska_track_video_color, max_fall), { .u=0 } },
{ MATROSKA_ID_VIDEOCOLORMASTERINGMETA, EBML_NEST, 0, mpp_offsetof(matroska_track_video_color, mastering_meta), { .n = g_matroska_mastering_meta } },
CHILD_OF(g_matroska_track_video)
};
static ebml_syntax g_matroska_track_video_projection[] = {
{ MATROSKA_ID_VIDEOPROJECTIONTYPE, EBML_UINT, 0, mpp_offsetof(matroska_track_video_projection, type), { .u = MATROSKA_VIDEO_PROJECTION_TYPE_RECTANGULAR } },
{ MATROSKA_ID_VIDEOPROJECTIONPRIVATE, EBML_BIN, 0, mpp_offsetof(matroska_track_video_projection, private) },
{ MATROSKA_ID_VIDEOPROJECTIONPOSEYAW, EBML_FLOAT, 0, mpp_offsetof(matroska_track_video_projection, yaw), { .f=0.0 } },
{ MATROSKA_ID_VIDEOPROJECTIONPOSEPITCH, EBML_FLOAT, 0, mpp_offsetof(matroska_track_video_projection, pitch), { .f=0.0 } },
{ MATROSKA_ID_VIDEOPROJECTIONPOSEROLL, EBML_FLOAT, 0, mpp_offsetof(matroska_track_video_projection, roll), { .f=0.0 } },
CHILD_OF(g_matroska_track_video)
};
static ebml_syntax g_matroska_track_video[] = {
{ MATROSKA_ID_VIDEOFRAMERATE, EBML_FLOAT, 0, mpp_offsetof(matroska_track_video, frame_rate) },
{ MATROSKA_ID_VIDEODISPLAYWIDTH, EBML_UINT, 0, mpp_offsetof(matroska_track_video, display_width), { .u=-1 } },
{ MATROSKA_ID_VIDEODISPLAYHEIGHT, EBML_UINT, 0, mpp_offsetof(matroska_track_video, display_height), { .u=-1 } },
{ MATROSKA_ID_VIDEOPIXELWIDTH, EBML_UINT, 0, mpp_offsetof(matroska_track_video, pixel_width) },
{ MATROSKA_ID_VIDEOPIXELHEIGHT, EBML_UINT, 0, mpp_offsetof(matroska_track_video, pixel_height) },
{ MATROSKA_ID_VIDEOCOLORSPACE, EBML_BIN, 0, mpp_offsetof(matroska_track_video, color_space) },
{ MATROSKA_ID_VIDEOALPHAMODE, EBML_UINT, 0, mpp_offsetof(matroska_track_video, alpha_mode) },
{ MATROSKA_ID_VIDEOCOLOR, EBML_NEST, sizeof(matroska_track_video_color), mpp_offsetof(matroska_track_video, color), { .n = g_matroska_track_video_color } },
{ MATROSKA_ID_VIDEOPROJECTION, EBML_NEST, 0, mpp_offsetof(matroska_track_video, projection), { .n = g_matroska_track_video_projection } },
{ MATROSKA_ID_VIDEOPIXELCROPB, EBML_NONE },
{ MATROSKA_ID_VIDEOPIXELCROPT, EBML_NONE },
{ MATROSKA_ID_VIDEOPIXELCROPL, EBML_NONE },
{ MATROSKA_ID_VIDEOPIXELCROPR, EBML_NONE },
{ MATROSKA_ID_VIDEODISPLAYUNIT, EBML_UINT, 0, mpp_offsetof(matroska_track_video, display_unit), { .u= MATROSKA_VIDEO_DISPLAYUNIT_PIXELS } },
{ MATROSKA_ID_VIDEOFLAGINTERLACED, EBML_UINT, 0, mpp_offsetof(matroska_track_video, interlaced), { .u = MATROSKA_VIDEO_INTERLACE_FLAG_UNDETERMINED } },
{ MATROSKA_ID_VIDEOFIELDORDER, EBML_UINT, 0, mpp_offsetof(matroska_track_video, field_order), { .u = MATROSKA_VIDEO_FIELDORDER_UNDETERMINED } },
{ MATROSKA_ID_VIDEOSTEREOMODE, EBML_UINT, 0, mpp_offsetof(matroska_track_video, stereo_mode), { .u = MATROSKA_VIDEO_STEREOMODE_TYPE_NB } },
{ MATROSKA_ID_VIDEOASPECTRATIO, EBML_NONE },
CHILD_OF(g_matroska_track)
};
static ebml_syntax g_matroska_track_audio[] = {
{ MATROSKA_ID_AUDIOSAMPLINGFREQ, EBML_FLOAT, 0, mpp_offsetof(matroska_track_audio, samplerate), { .f = 8000.0 } },
{ MATROSKA_ID_AUDIOOUTSAMPLINGFREQ, EBML_FLOAT, 0, mpp_offsetof(matroska_track_audio, out_samplerate) },
{ MATROSKA_ID_AUDIOBITDEPTH, EBML_UINT, 0, mpp_offsetof(matroska_track_audio, bitdepth) },
{ MATROSKA_ID_AUDIOCHANNELS, EBML_UINT, 0, mpp_offsetof(matroska_track_audio, channels), { .u = 1 } },
CHILD_OF(g_matroska_track)
};
static ebml_syntax g_matroska_track_encoding_compression[] = {
{ MATROSKA_ID_ENCODINGCOMPALGO, EBML_UINT, 0, mpp_offsetof(matroska_track_compression, algo), { .u = 0 } },
{ MATROSKA_ID_ENCODINGCOMPSETTINGS, EBML_BIN, 0, mpp_offsetof(matroska_track_compression, settings) },
CHILD_OF(g_matroska_track_encoding)
};
static ebml_syntax g_matroska_track_encoding_encryption[] = {
{ MATROSKA_ID_ENCODINGENCALGO, EBML_UINT, 0, mpp_offsetof(matroska_track_encryption,algo), {.u = 0} },
{ MATROSKA_ID_ENCODINGENCKEYID, EBML_BIN, 0, mpp_offsetof(matroska_track_encryption,key_id) },
{ MATROSKA_ID_ENCODINGENCAESSETTINGS, EBML_NONE },
{ MATROSKA_ID_ENCODINGSIGALGO, EBML_NONE },
{ MATROSKA_ID_ENCODINGSIGHASHALGO, EBML_NONE },
{ MATROSKA_ID_ENCODINGSIGKEYID, EBML_NONE },
{ MATROSKA_ID_ENCODINGSIGNATURE, EBML_NONE },
CHILD_OF(g_matroska_track_encoding)
};
static ebml_syntax g_matroska_track_encoding[] = {
{ MATROSKA_ID_ENCODINGSCOPE, EBML_UINT, 0, mpp_offsetof(matroska_track_encoding, scope), { .u = 1 } },
{ MATROSKA_ID_ENCODINGTYPE, EBML_UINT, 0, mpp_offsetof(matroska_track_encoding, type), { .u = 0 } },
{ MATROSKA_ID_ENCODINGCOMPRESSION, EBML_NEST, 0, mpp_offsetof(matroska_track_encoding, compression), { .n = g_matroska_track_encoding_compression } },
{ MATROSKA_ID_ENCODINGENCRYPTION, EBML_NEST, 0, mpp_offsetof(matroska_track_encoding, encryption), { .n = g_matroska_track_encoding_encryption } },
{ MATROSKA_ID_ENCODINGORDER, EBML_NONE },
CHILD_OF(g_matroska_track_encodings)
};
static ebml_syntax g_matroska_track_encodings[] = {
{ MATROSKA_ID_TRACKCONTENTENCODING, EBML_NEST, sizeof(g_matroska_track_encoding), mpp_offsetof(matroska_track, encodings), { .n = g_matroska_track_encoding } },
CHILD_OF(g_matroska_track)
};
static ebml_syntax g_matroska_track_plane[] = {
{ MATROSKA_ID_TRACKPLANEUID, EBML_UINT, 0, mpp_offsetof(matroska_track_plane, uid) },
{ MATROSKA_ID_TRACKPLANETYPE, EBML_UINT, 0, mpp_offsetof(matroska_track_plane, type) },
CHILD_OF(g_matroska_track_combine_planes)
};
static ebml_syntax g_matroska_track_combine_planes[] = {
{ MATROSKA_ID_TRACKPLANE, EBML_NEST, sizeof(matroska_track_plane), mpp_offsetof(matroska_track_operation,combine_planes), {.n = g_matroska_track_plane} },
CHILD_OF(g_matroska_track_operation)
};
static ebml_syntax g_matroska_track_operation[] = {
{ MATROSKA_ID_TRACKCOMBINEPLANES, EBML_NEST, 0, 0, {.n = g_matroska_track_combine_planes} },
CHILD_OF(g_matroska_track)
};
static ebml_syntax g_matroska_track[] = {
{ MATROSKA_ID_TRACKNUMBER, EBML_UINT, 0, mpp_offsetof(matroska_track, num) },
{ MATROSKA_ID_TRACKNAME, EBML_UTF8, 0, mpp_offsetof(matroska_track, name) },
{ MATROSKA_ID_TRACKUID, EBML_UINT, 0, mpp_offsetof(matroska_track, uid) },
{ MATROSKA_ID_TRACKTYPE, EBML_UINT, 0, mpp_offsetof(matroska_track, type) },
{ MATROSKA_ID_CODECID, EBML_STR, 0, mpp_offsetof(matroska_track, codec_id) },
{ MATROSKA_ID_CODECPRIVATE, EBML_BIN, 0, mpp_offsetof(matroska_track, codec_priv) },
{ MATROSKA_ID_CODECDELAY, EBML_UINT, 0, mpp_offsetof(matroska_track, codec_delay) },
{ MATROSKA_ID_TRACKLANGUAGE, EBML_STR, 0, mpp_offsetof(matroska_track, language), { .s = "eng" } },
{ MATROSKA_ID_TRACKDEFAULTDURATION, EBML_UINT, 0, mpp_offsetof(matroska_track, default_duration) },
{ MATROSKA_ID_TRACKTIMECODESCALE, EBML_FLOAT, 0, mpp_offsetof(matroska_track, time_scale), { .f = 1.0 } },
{ MATROSKA_ID_TRACKFLAGDEFAULT, EBML_UINT, 0, mpp_offsetof(matroska_track, flag_default), { .u = 1 } },
{ MATROSKA_ID_TRACKFLAGFORCED, EBML_UINT, 0, mpp_offsetof(matroska_track, flag_forced), { .u = 0 } },
{ MATROSKA_ID_TRACKVIDEO, EBML_NEST, 0, mpp_offsetof(matroska_track, video), { .n = g_matroska_track_video } },
{ MATROSKA_ID_TRACKAUDIO, EBML_NEST, 0, mpp_offsetof(matroska_track, audio), { .n = g_matroska_track_audio } },
{ MATROSKA_ID_TRACKOPERATION, EBML_NEST, 0, mpp_offsetof(matroska_track, operation), { .n = g_matroska_track_operation } },
{ MATROSKA_ID_TRACKCONTENTENCODINGS, EBML_NEST, 0, 0, { .n = g_matroska_track_encodings } },
{ MATROSKA_ID_TRACKMAXBLKADDID, EBML_UINT, 0, mpp_offsetof(matroska_track, max_block_additional_id) },
{ MATROSKA_ID_SEEKPREROLL, EBML_UINT, 0, mpp_offsetof(matroska_track, seek_preroll) },
{ MATROSKA_ID_TRACKFLAGENABLED, EBML_NONE },
{ MATROSKA_ID_TRACKFLAGLACING, EBML_NONE },
{ MATROSKA_ID_CODECNAME, EBML_NONE },
{ MATROSKA_ID_CODECDECODEALL, EBML_NONE },
{ MATROSKA_ID_CODECINFOURL, EBML_NONE },
{ MATROSKA_ID_CODECDOWNLOADURL, EBML_NONE },
{ MATROSKA_ID_TRACKMINCACHE, EBML_NONE },
{ MATROSKA_ID_TRACKMAXCACHE, EBML_NONE },
CHILD_OF(g_matroska_tracks)
};
static ebml_syntax g_matroska_tracks[] = {
{ MATROSKA_ID_TRACKENTRY, EBML_NEST, sizeof(matroska_track), mpp_offsetof(struct matroska_demux_context, tracks), { .n = g_matroska_track } },
CHILD_OF(g_matroska_segment)
};
static ebml_syntax g_matroska_attachment[] = {
{ MATROSKA_ID_FILEUID, EBML_UINT, 0, mpp_offsetof(matroska_attachment, uid) },
{ MATROSKA_ID_FILENAME, EBML_UTF8, 0, mpp_offsetof(matroska_attachment, filename) },
{ MATROSKA_ID_FILEMIMETYPE, EBML_STR, 0, mpp_offsetof(matroska_attachment, mime) },
{ MATROSKA_ID_FILEDATA, EBML_BIN, 0, mpp_offsetof(matroska_attachment, bin) },
{ MATROSKA_ID_FILEDESC, EBML_UTF8, 0, mpp_offsetof(matroska_attachment, description) },
CHILD_OF(g_matroska_attachments)
};
static ebml_syntax g_matroska_attachments[] = {
{ MATROSKA_ID_ATTACHEDFILE, EBML_NEST, sizeof(matroska_attachment), mpp_offsetof(struct matroska_demux_context, attachments), { .n = g_matroska_attachment } },
CHILD_OF(g_matroska_segment)
};
static ebml_syntax g_matroska_chapter_display[] = {
{ MATROSKA_ID_CHAPSTRING, EBML_UTF8, 0, mpp_offsetof(matroska_chapter, title) },
{ MATROSKA_ID_CHAPLANG, EBML_NONE },
{ MATROSKA_ID_CHAPCOUNTRY, EBML_NONE },
CHILD_OF(g_matroska_chapter_entry)
};
static ebml_syntax g_matroska_chapter_entry[] = {
{ MATROSKA_ID_CHAPTERTIMESTART, EBML_UINT, 0, mpp_offsetof(matroska_chapter, start), { .u = 0 } },
{ MATROSKA_ID_CHAPTERTIMEEND, EBML_UINT, 0, mpp_offsetof(matroska_chapter, end), { .u = 0 } },
{ MATROSKA_ID_CHAPTERUID, EBML_UINT, 0, mpp_offsetof(matroska_chapter, uid) },
{ MATROSKA_ID_CHAPTERDISPLAY, EBML_NEST, 0, 0, { .n = g_matroska_chapter_display } },
{ MATROSKA_ID_CHAPTERFLAGHIDDEN, EBML_NONE },
{ MATROSKA_ID_CHAPTERFLAGENABLED, EBML_NONE },
{ MATROSKA_ID_CHAPTERPHYSEQUIV, EBML_NONE },
{ MATROSKA_ID_CHAPTERATOM, EBML_NONE },
CHILD_OF(g_matroska_chapter)
};
static ebml_syntax g_matroska_chapter[] = {
{ MATROSKA_ID_CHAPTERATOM, EBML_NEST, sizeof(matroska_chapter), mpp_offsetof(struct matroska_demux_context, chapters), { .n = g_matroska_chapter_entry } },
{ MATROSKA_ID_EDITIONUID, EBML_NONE },
{ MATROSKA_ID_EDITIONFLAGHIDDEN, EBML_NONE },
{ MATROSKA_ID_EDITIONFLAGDEFAULT, EBML_NONE },
{ MATROSKA_ID_EDITIONFLAGORDERED, EBML_NONE },
CHILD_OF(g_matroska_chapters)
};
static ebml_syntax g_matroska_chapters[] = {
{ MATROSKA_ID_EDITIONENTRY, EBML_NEST, 0, 0, { .n = g_matroska_chapter } },
CHILD_OF(g_matroska_segment)
};
static ebml_syntax g_matroska_index_pos[] = {
{ MATROSKA_ID_CUETRACK, EBML_UINT, 0, mpp_offsetof(matroska_index_pos, track) },
{ MATROSKA_ID_CUECLUSTERPOSITION, EBML_UINT, 0, mpp_offsetof(matroska_index_pos, pos) },
{ MATROSKA_ID_CUERELATIVEPOSITION,EBML_NONE },
{ MATROSKA_ID_CUEDURATION, EBML_NONE },
{ MATROSKA_ID_CUEBLOCKNUMBER, EBML_NONE },
CHILD_OF(g_matroska_index_entry)
};
static ebml_syntax g_matroska_index_entry[] = {
{ MATROSKA_ID_CUETIME, EBML_UINT, 0, mpp_offsetof(matroska_index, time) },
{ MATROSKA_ID_CUETRACKPOSITION, EBML_NEST, sizeof(matroska_index_pos), mpp_offsetof(matroska_index, pos), { .n = g_matroska_index_pos } },
CHILD_OF(g_matroska_index)
};
static ebml_syntax g_matroska_index[] = {
{ MATROSKA_ID_POINTENTRY, EBML_NEST, sizeof(matroska_index), mpp_offsetof(struct matroska_demux_context, index), { .n = g_matroska_index_entry } },
CHILD_OF(g_matroska_segment)
};
static ebml_syntax g_matroska_simpletag[] = {
{ MATROSKA_ID_TAGNAME, EBML_UTF8, 0, mpp_offsetof(matroska_tag, name) },
{ MATROSKA_ID_TAGSTRING, EBML_UTF8, 0, mpp_offsetof(matroska_tag, string) },
{ MATROSKA_ID_TAGLANG, EBML_STR, 0, mpp_offsetof(matroska_tag, lang), { .s = "und" } },
{ MATROSKA_ID_TAGDEFAULT, EBML_UINT, 0, mpp_offsetof(matroska_tag, def) },
{ MATROSKA_ID_TAGDEFAULT_BUG, EBML_UINT, 0, mpp_offsetof(matroska_tag, def) },
{ MATROSKA_ID_SIMPLETAG, EBML_NEST, sizeof(matroska_tag), mpp_offsetof(matroska_tag, sub), { .n = g_matroska_simpletag } },
CHILD_OF(g_matroska_tag)
};
static ebml_syntax g_matroska_tag_targets[] = {
{ MATROSKA_ID_TAGTARGETS_TYPE, EBML_STR, 0, mpp_offsetof(matroska_tag_targets, type) },
{ MATROSKA_ID_TAGTARGETS_TYPEVALUE, EBML_UINT, 0, mpp_offsetof(matroska_tag_targets, typevalue), { .u = 50 } },
{ MATROSKA_ID_TAGTARGETS_TRACKUID, EBML_UINT, 0, mpp_offsetof(matroska_tag_targets, trackuid) },
{ MATROSKA_ID_TAGTARGETS_CHAPTERUID, EBML_UINT, 0, mpp_offsetof(matroska_tag_targets, chapteruid) },
{ MATROSKA_ID_TAGTARGETS_ATTACHUID, EBML_UINT, 0, mpp_offsetof(matroska_tag_targets, attachuid) },
CHILD_OF(g_matroska_tag)
};
static ebml_syntax g_matroska_tag[] = {
{ MATROSKA_ID_SIMPLETAG, EBML_NEST, sizeof(matroska_tag), mpp_offsetof(matroska_tags, tag), { .n = g_matroska_simpletag } },
{ MATROSKA_ID_TAGTARGETS, EBML_NEST, 0, mpp_offsetof(matroska_tags, target), { .n = g_matroska_tag_targets } },
CHILD_OF(g_matroska_tags)
};
static ebml_syntax g_matroska_tags[] = {
{ MATROSKA_ID_TAG, EBML_NEST, sizeof(matroska_tags), mpp_offsetof(struct matroska_demux_context, tags), { .n = g_matroska_tag } },
CHILD_OF(g_matroska_segment)
};
static ebml_syntax g_matroska_seekhead_entry[] = {
{ MATROSKA_ID_SEEKID, EBML_UINT, 0, mpp_offsetof(matroska_seek_head, id) },
{ MATROSKA_ID_SEEKPOSITION, EBML_UINT, 0, mpp_offsetof(matroska_seek_head, pos), { .u = -1 } },
CHILD_OF(g_matroska_seekhead)
};
static ebml_syntax g_matroska_seekhead[] = {
{ MATROSKA_ID_SEEKENTRY, EBML_NEST, sizeof(matroska_seek_head), mpp_offsetof(struct matroska_demux_context, seekhead), { .n = g_matroska_seekhead_entry } },
CHILD_OF(g_matroska_segment)
};
static ebml_syntax g_matroska_segment[] = {
{ MATROSKA_ID_CLUSTER, EBML_STOP },
{ MATROSKA_ID_INFO, EBML_LEVEL1, 0, 0, { .n = g_matroska_info } },
{ MATROSKA_ID_TRACKS, EBML_LEVEL1, 0, 0, { .n = g_matroska_tracks } },
{ MATROSKA_ID_ATTACHMENTS, EBML_LEVEL1, 0, 0, { .n = g_matroska_attachments } },
{ MATROSKA_ID_CHAPTERS, EBML_LEVEL1, 0, 0, { .n = g_matroska_chapters } },
{ MATROSKA_ID_CUES, EBML_LEVEL1, 0, 0, { .n = g_matroska_index } },
{ MATROSKA_ID_TAGS, EBML_LEVEL1, 0, 0, { .n = g_matroska_tags } },
{ MATROSKA_ID_SEEKHEAD, EBML_LEVEL1, 0, 0, { .n = g_matroska_seekhead } },
{ 0 } /* We don't want to go back to level 0, so don't add the parent. */
};
static ebml_syntax g_matroska_segments[] = {
{ MATROSKA_ID_SEGMENT, EBML_NEST, 0, 0, { .n = g_matroska_segment } },
{ 0 }
};
static ebml_syntax g_matroska_blockmore[] = {
{ MATROSKA_ID_BLOCKADDID, EBML_UINT, 0, mpp_offsetof(matroska_block,additional_id), { .u = 1 } },
{ MATROSKA_ID_BLOCKADDITIONAL, EBML_BIN, 0, mpp_offsetof(matroska_block,additional) },
CHILD_OF(g_matroska_blockadditions)
};
static ebml_syntax g_matroska_blockadditions[] = {
{ MATROSKA_ID_BLOCKMORE, EBML_NEST, 0, 0, {.n = g_matroska_blockmore} },
CHILD_OF(g_matroska_blockgroup)
};
static ebml_syntax g_matroska_blockgroup[] = {
{ MATROSKA_ID_BLOCK, EBML_BIN, 0, mpp_offsetof(matroska_block, bin) },
{ MATROSKA_ID_BLOCKADDITIONS, EBML_NEST, 0, 0, { .n = g_matroska_blockadditions } },
{ MATROSKA_ID_BLOCKDURATION, EBML_UINT, 0, mpp_offsetof(matroska_block, duration) },
{ MATROSKA_ID_DISCARDPADDING, EBML_SINT, 0, mpp_offsetof(matroska_block, discard_padding) },
{ MATROSKA_ID_BLOCKREFERENCE, EBML_SINT, 0, mpp_offsetof(matroska_block, reference), { .i = INT64_MIN } },
{ MATROSKA_ID_CODECSTATE, EBML_NONE },
{ 1, EBML_UINT, 0, mpp_offsetof(matroska_block, non_simple), { .u = 1 } },
CHILD_OF(g_matroska_cluster_parsing)
};
// The following array contains SimpleBlock and BlockGroup twice
// in order to reuse the other values for matroska_cluster_enter.
static ebml_syntax g_matroska_cluster_parsing[] = {
{ MATROSKA_ID_SIMPLEBLOCK, EBML_STREAM, 0, mpp_offsetof(matroska_block, bin) },
{ MATROSKA_ID_BLOCKGROUP, EBML_NEST, 0, 0, { .n = g_matroska_blockgroup } },
{ MATROSKA_ID_CLUSTERTIMECODE, EBML_UINT, 0, mpp_offsetof(matroska_cluster, timecode) },
{ MATROSKA_ID_SIMPLEBLOCK, EBML_STOP },
{ MATROSKA_ID_BLOCKGROUP, EBML_STOP },
{ MATROSKA_ID_CLUSTERPOSITION, EBML_NONE },
{ MATROSKA_ID_CLUSTERPREVSIZE, EBML_NONE },
CHILD_OF(g_matroska_segment)
};
static ebml_syntax g_matroska_cluster_enter[] = {
{ MATROSKA_ID_CLUSTER, EBML_NEST, 0, 0, { .n = &g_matroska_cluster_parsing[2] } },
{ 0 }
};
#undef CHILD_OF
static const char *const g_matroska_doctypes[] = { "matroska", "webm" };
const uint8_t log2_tab[256] = {
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
static inline int log2_c(unsigned int v)
{
int n = 0;
if (v & 0xffff0000) {
v >>= 16;
n += 16;
}
if (v & 0xff00) {
v >>= 8;
n += 8;
}
n += log2_tab[v];
return n;
}
static inline int sign_extend(int val, unsigned bits)
{
unsigned shift = 8 * sizeof(int) - bits;
union { unsigned u; int s; } v = { (unsigned) val << shift };
return v.s >> shift;
}
/*
* This function prepares the status for parsing of level 1 elements.
*/
static int matroska_reset_status(struct aic_stream *c,
struct matroska_demux_context *matroska,
uint32_t id, int64_t position)
{
if (position >= 0) {
int64_t err = aic_stream_seek(c, position, SEEK_SET);
if (err < 0)
return err;
}
matroska->current_id = id;
matroska->num_levels = 1;
matroska->unknown_count = 0;
matroska->resync_pos = aic_stream_tell(c);
if (id)
matroska->resync_pos -= (log2_c(id) + 7) / 8;
return 0;
}
static int matroska_resync(struct aic_stream *c, struct matroska_demux_context *matroska, int64_t last_pos)
{
struct aic_stream *pb = c;
uint32_t id;
int64_t size = aic_stream_size(pb);
/* Try to seek to the last position to resync from. If this doesn't work,
* we resync from the earliest position available: The start of the buffer. */
if (last_pos < aic_stream_tell(pb) && aic_stream_seek(pb, last_pos + 1, SEEK_SET) < 0) {
logw("Seek to desired resync point failed. Seeking to "
"earliest point available instead.\n");
aic_stream_seek(pb, last_pos + 1, SEEK_SET);
}
id = aic_stream_rb32(pb);
// try to find a toplevel element
while (aic_stream_tell(pb) < size) {
if (id == MATROSKA_ID_INFO || id == MATROSKA_ID_TRACKS ||
id == MATROSKA_ID_CUES || id == MATROSKA_ID_TAGS ||
id == MATROSKA_ID_SEEKHEAD || id == MATROSKA_ID_ATTACHMENTS ||
id == MATROSKA_ID_CLUSTER || id == MATROSKA_ID_CHAPTERS) {
/* Prepare the context for parsing of a level 1 element. */
matroska_reset_status(pb, matroska, id, -1);
/* Given that we are here means that an error has occurred,
* so treat the segment as unknown length in order not to
* discard valid data that happens to be beyond the designated
* end of the segment. */
matroska->levels[0].length = EBML_UNKNOWN_LENGTH;
return 0;
}
id = (id << 8) | aic_stream_r8(pb);
}
matroska->done = 1;
return PARSER_EOS;
}
/*
* 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: number of bytes read, < 0 on error
*/
static int ebml_read_num(struct matroska_demux_context *matroska, struct aic_stream *pb,
int max_size, uint64_t *number, int eof_forbidden)
{
int read, n = 1;
uint64_t total;
int64_t pos;
/* The first byte tells us the length in bytes - except when it is zero. */
/* e.g.: EBML Header tatal = 0x1a[0001 1010], ID len = 4*/
total = aic_stream_r8(pb);
/* get the length of the EBML number, e.g.: EBML Header read = 4 */
read = 8 - log2_tab[total];
if (!total || read > max_size) {
pos = aic_stream_tell(pb) - 1;
if (!total) {
loge("0x00 at pos %"PRId64" (0x%"PRIx64") invalid as first byte "
"of an EBML number\n", pos, pos);
} else {
loge("Length %d indicated by an EBML number's first byte 0x%02x "
"at pos %"PRId64" (0x%"PRIx64") exceeds max length %d.\n",
read, (uint8_t) total, pos, pos, max_size);
}
return PARSER_ERROR;
}
/* read out length Example: EBML Header total = 0xa*/
total ^= 1 << log2_tab[total];
/* e.g. EBML Header total = 0x0a45dfa3*/
while (n++ < read)
total = (total << 8) | aic_stream_r8(pb);
*number = total;
return read;
}
/**
* Read a EBML length value.
* This needs special handling for the "unknown length" case which has multiple
* encodings.
*/
static int ebml_read_length(struct matroska_demux_context *matroska, struct aic_stream *pb,
uint64_t *number)
{
int res = ebml_read_num(matroska, pb, 8, number, 1);
if (res > 0 && *number + 1 == 1ULL << (7 * res))
*number = EBML_UNKNOWN_LENGTH;
return res;
}
/*
* Read the next element as an unsigned int.
* Returns NEEDS_CHECKING.
*/
static int ebml_read_uint(struct aic_stream *pb, int size, uint64_t *num)
{
int n = 0;
/* big-endian ordering; build up number */
*num = 0;
while (n++ < size)
*num = (*num << 8) | aic_stream_r8(pb);
return NEEDS_CHECKING;
}
/*
* Read the next element as a signed int.
* Returns NEEDS_CHECKING.
*/
static int ebml_read_sint(struct aic_stream *pb, int size, int64_t *num)
{
int n = 1;
if (size == 0) {
*num = 0;
} else {
*num = sign_extend(aic_stream_r8(pb), 8);
/* big-endian ordering; build up number */
while (n++ < size)
*num = ((uint64_t)*num << 8) | aic_stream_r8(pb);
}
return NEEDS_CHECKING;
}
/*
* Read the next element as a float.
* Returns NEEDS_CHECKING or < 0 on obvious failure.
*/
static int ebml_read_float(struct aic_stream *pb, int size, double *num)
{
if (size == 0)
*num = 0;
else if (size == 4)
*num = (float)aic_stream_rb32(pb);
else if (size == 8)
*num = (double)aic_stream_rb64(pb);
else
return PARSER_ERROR;
return NEEDS_CHECKING;
}
/*
* Read the next element as an ASCII string.
* 0 is success, < 0 or NEEDS_CHECKING is failure.
*/
static int ebml_read_ascii(struct aic_stream *pb, int size, char **str)
{
char *res;
int ret;
/* EBML strings are usually not 0-terminated, so we allocate one
* byte more, read the string and NULL-terminate it ourselves. */
if (!(res = malloc(size + 1)))
return PARSER_NOMEM;
if ((ret = aic_stream_read(pb, (uint8_t *) res, size)) != size) {
free(res);
return ret < 0 ? ret : NEEDS_CHECKING;
}
(res)[size] = '\0';
free(*str);
*str = res;
return 0;
}
/*
* Read the next element as binary data.
* 0 is success, < 0 or NEEDS_CHECKING is failure.
*/
static int ebml_read_binary(struct aic_stream *pb, int length,
int64_t pos, ebml_bin *bin)
{
int ret;
bin->data = realloc(bin->data, length + 64);
memset(bin->data + length, 0, 64);
bin->size = length;
bin->pos = pos;
if ((ret = aic_stream_read(pb, bin->data, length)) != length) {
free(bin->data);
bin->data = NULL;
bin->size = 0;
return ret < 0 ? ret : NEEDS_CHECKING;
}
return 0;
}
static int ebml_peek_stream(int length, int64_t pos, ebml_bin *bin)
{
bin->size = length;
bin->pos = pos;
return 0;
}
/*
* 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(struct matroska_demux_context *matroska,
uint64_t length, int64_t pos)
{
matroska_level *level;
if (matroska->num_levels >= EBML_MAX_DEPTH) {
loge("File moves beyond max. allowed depth (%d)\n", EBML_MAX_DEPTH);
return PARSER_ERROR;
}
level = &matroska->levels[matroska->num_levels++];
level->start = pos;
level->length = length;
return 0;
}
/*
* Read a signed "EBML number"
* Return: number of bytes processed, < 0 on error
*/
static int matroska_ebmlnum_sint(struct matroska_demux_context *matroska,
struct aic_stream *pb, int64_t *num)
{
uint64_t unum;
int res;
/* read as unsigned number first */
if ((res = ebml_read_num(matroska, pb, 8, &unum, 1)) <= 0)
return res;
/* make signed (weird way) */
*num = unum - ((1LL << (7 * res - 1)) - 1);
return res;
}
static ebml_syntax *ebml_parse_id(ebml_syntax *syntax, uint32_t id)
{
int i;
// Whoever touches this should be aware of the duplication
// existing in matroska_cluster_parsing.
for (i = 0; syntax[i].id; i++)
if (id == syntax[i].id)
break;
return &syntax[i];
}
static int ebml_parse(struct matroska_demux_context *matroska, struct aic_stream *c,
ebml_syntax *syntax, void *data);
static int is_ebml_id_valid(uint32_t id)
{
// Due to endian nonsense in Matroska, the highest byte with any bits set
// will contain the leading length bit. This bit in turn identifies the
// total byte length of the element by its position within the byte.
unsigned int bits = log2_c(id);
return id && (bits + 7) / 8 == (8 - bits % 8);
}
/*
* Allocate and return the entry for the level1 element with the given ID. If
* an entry already exists, return the existing entry.
*/
static matroska_level1_element *matroska_find_level1_elem(struct matroska_demux_context *matroska,
uint32_t id, int64_t pos)
{
int i;
matroska_level1_element *elem;
if (!is_ebml_id_valid(id))
return NULL;
// Some files link to all clusters; useless.
if (id == MATROSKA_ID_CLUSTER)
return NULL;
// There can be multiple SeekHeads and Tags.
for (i = 0; i < matroska->num_level1_elems; i++) {
if (matroska->level1_elems[i].id == id) {
if (matroska->level1_elems[i].pos == pos ||
(id != MATROSKA_ID_SEEKHEAD && id != MATROSKA_ID_TAGS))
return &matroska->level1_elems[i];
}
}
// Only a completely broken file would have more elements.
if (matroska->num_level1_elems >= MKV_ARRAY_ELEMS(matroska->level1_elems)) {
loge("Too many level1 elements.\n");
return NULL;
}
elem = &matroska->level1_elems[matroska->num_level1_elems++];
*elem = (matroska_level1_element){.id = id};
return elem;
}
static int ebml_parse_nest(struct matroska_demux_context *matroska, struct aic_stream *c,
ebml_syntax *syntax, void *data)
{
int res, i;
if (data) {
for (i = 0; syntax[i].id; i++)
logd("i:%d type:%d, data_offset:%d!!!", i, syntax[i].type, (int)syntax[i].data_offset);
switch (syntax[i].type) {
case EBML_UINT:
*(uint64_t *) ((char *) data + syntax[i].data_offset) = syntax[i].def.u;
break;
case EBML_SINT:
*(int64_t *) ((char *) data + syntax[i].data_offset) = syntax[i].def.i;
break;
case EBML_FLOAT:
*(double *) ((char *) data + syntax[i].data_offset) = syntax[i].def.f;
break;
case EBML_STR:
case EBML_UTF8:
// the default may be NULL
if (syntax[i].def.s) {
uint8_t **dst = (uint8_t **) ((uint8_t *) data + syntax[i].data_offset);
logi("malloc for nest str %d!!!", (int)strlen(syntax[i].def.s) + 1);
*dst = realloc(NULL, strlen(syntax[i].def.s) + 1);
if (*dst) {
memcpy(*dst, syntax[i].def.s, strlen(syntax[i].def.s) + 1);
} else {
return PARSER_NOMEM;
}
}
break;
default:
logd("unknown type %d", syntax[i].type);
break;
}
if (!matroska->levels[matroska->num_levels - 1].length) {
matroska->num_levels--;
return 0;
}
}
do {
res = ebml_parse(matroska, c, syntax, data);
} while (!res);
return res == LEVEL_ENDED ? 0 : res;
}
static int ebml_parse(struct matroska_demux_context *matroska, struct aic_stream *c,
ebml_syntax *syntax, void *data)
{
static const uint64_t max_lengths[EBML_TYPE_COUNT] = {
// Forbid unknown-length EBML_NONE elements.
[EBML_NONE] = EBML_UNKNOWN_LENGTH - 1,
[EBML_UINT] = 8,
[EBML_SINT] = 8,
[EBML_FLOAT] = 8,
// max. 16 MB for strings
[EBML_STR] = 0x1000000,
[EBML_UTF8] = 0x1000000,
// max. 256 MB for binary data
[EBML_BIN] = 0x10000000,
// stream only for peek
[EBML_STREAM] = 0x1000000,
};
struct aic_stream *pb = c;
uint32_t id;
uint64_t length;
int64_t pos = aic_stream_tell(pb), pos_alt;
int res = 0, update_pos = 1, level_check = 0;
matroska_level1_element *level1_elem;
matroska_level *level = matroska->num_levels ? &matroska->levels[matroska->num_levels - 1] : NULL;
/*curent level data overange need to back to pre level*/
if (matroska->num_levels > 0 && level != NULL) {
if (pos == level->start + level->length) {
level_check = LEVEL_ENDED;
goto level_check;
}
}
if (!matroska->current_id) {
uint64_t temp_id;
res = ebml_read_num(matroska, pb, 4, &temp_id, 0);
if (res < 0) {
if (res == PARSER_EOS) {
if (matroska->is_live)
// in live mode, finish parsing if EOF is reached.
return 1;
if (level && pos == aic_stream_tell(pb)) {
if (level->length == EBML_UNKNOWN_LENGTH) {
// Unknown-length levels automatically end at EOF.
loge("unknown length levels automatically end at EOF");
matroska->num_levels--;
return LEVEL_ENDED;
} else {
loge( "File ended prematurely "
"at pos. %"PRIu64" (0x%"PRIx64")\n", pos, pos);
}
}
}
return res;
}
matroska->current_id = temp_id | 1 << (7 * res);
pos_alt = pos + res;
} else {
pos_alt = pos;
pos -= (log2_c(matroska->current_id) + 7) / 8;
}
id = matroska->current_id;
syntax = ebml_parse_id(syntax, id);
if (!syntax->id && id != EBML_ID_VOID && id != EBML_ID_CRC32) {
if (level && level->length == EBML_UNKNOWN_LENGTH) {
// Unknown-length levels end when an element from an upper level
// in the hierarchy is encountered.
while (syntax->def.n) {
syntax = ebml_parse_id(syntax->def.n, id);
if (syntax->id) {
loge("unknown syntax id %"PRIu32" automatically end at EOF", syntax->id);
matroska->num_levels--;
return LEVEL_ENDED;
}
};
}
loge("Unknown entry id 0x%"PRIX32" at pos.0x%"PRIx64", "
"synatx id 0x%"PRIX32"\n", id, pos, syntax->id);
update_pos = 0; /* Don't update resync_pos as an error might have happened. */
}
if (data) {
data = (char *) data + syntax->data_offset;
if (syntax->list_elem_size) {
ebml_list *list = data;
void *newelem;
if ((unsigned)list->nb_elem + 1 >= UINT_MAX / syntax->list_elem_size)
return PARSER_NOMEM;
newelem = realloc(list->elem, (list->nb_elem + 1) * syntax->list_elem_size);
if (!newelem)
return PARSER_NOMEM;
list->elem = newelem;
data = (char *) list->elem + list->nb_elem * syntax->list_elem_size;
memset(data, 0, syntax->list_elem_size);
list->nb_elem++;
}
}
if (syntax->type != EBML_STOP) {
matroska->current_id = 0;
if ((res = ebml_read_length(matroska, pb, &length)) < 0)
return res;
pos_alt += res;
if (matroska->num_levels > 0) {
if (length != EBML_UNKNOWN_LENGTH &&
level->length != EBML_UNKNOWN_LENGTH) {
uint64_t elem_end = pos_alt + length;
uint64_t level_end = level->start + level->length;
if (elem_end < level_end) {
level_check = 0;
} else if (elem_end == level_end) {
logd("elem_end = level_end(0x%"PRIx64")", elem_end);
level_check = LEVEL_ENDED;
} else {
loge("id: 0x%"PRIx32", pos_alt 0x%"PRIx64" length 0x%"PRIx64","
" level: start 0x%"PRIx64" length 0x%"PRIx64"",
id, pos_alt, length, level->start, level->length);
loge("Element at 0x%"PRIx64" ending at 0x%"PRIx64" exceeds "
"containing master element ending at 0x%"PRIx64"\n",
pos, elem_end, level_end);
return PARSER_ERROR;
}
} else if (length != EBML_UNKNOWN_LENGTH) {
level_check = 0;
} else if (level->length != EBML_UNKNOWN_LENGTH) {
loge( "Unknown-sized element "
"at 0x%"PRIx64" inside parent with finite size\n", pos);
return PARSER_ERROR;
} else {
level_check = 0;
if (id != MATROSKA_ID_CLUSTER && (syntax->type == EBML_LEVEL1
|| syntax->type == EBML_NEST)) {
// According to the current specifications only clusters and
// segments are allowed to be unknown-length. We also accept
// other unknown-length master elements.
logw("Found unknown-length element 0x%"PRIX32" other than "
"a cluster at 0x%"PRIx64". Spec-incompliant, but "
"parsing will nevertheless be attempted.\n", id, pos);
update_pos = -1;
}
}
} else {
level_check = 0;
}
if (max_lengths[syntax->type] && length > max_lengths[syntax->type]) {
if (length != EBML_UNKNOWN_LENGTH) {
loge("Invalid length 0x%"PRIx64" > 0x%"PRIx64" for element "
"with ID 0x%"PRIX32" at 0x%"PRIx64"\n",
length, max_lengths[syntax->type], id, pos);
} else if (syntax->type != EBML_NONE) {
loge("Element with ID 0x%"PRIX32" at pos. 0x%"PRIx64" has "
"unknown length, yet the length of an element of its "
"type must be known.\n", id, pos);
} else {
loge("Found unknown-length element with ID 0x%"PRIX32" at "
"pos. 0x%"PRIx64" for which no syntax for parsing is "
"available.\n", id, pos);
}
return PARSER_ERROR;
}
if (update_pos > 0) {
// We have found an element that is allowed at this place
// in the hierarchy and it passed all checks, so treat the beginning
// of the element as the "last known good" position.
matroska->resync_pos = pos;
}
if (!data && length != EBML_UNKNOWN_LENGTH)
goto skip;
}
switch (syntax->type) {
case EBML_UINT:
res = ebml_read_uint(pb, length, data);
break;
case EBML_SINT:
res = ebml_read_sint(pb, length, data);
break;
case EBML_FLOAT:
res = ebml_read_float(pb, length, data);
break;
case EBML_STR:
case EBML_UTF8:
res = ebml_read_ascii(pb, length, data);
break;
case EBML_BIN:
res = ebml_read_binary(pb, length, pos_alt, data);
break;
case EBML_STREAM:
res = ebml_peek_stream(length, pos_alt, data);
break;
case EBML_LEVEL1:
case EBML_NEST:
if ((res = ebml_read_master(matroska, length, pos_alt)) < 0)
return res;
if (id == MATROSKA_ID_SEGMENT)
matroska->segment_start = pos_alt;
if (id == MATROSKA_ID_CUES)
matroska->cues_parsing_deferred = 0;
if (syntax->type == EBML_LEVEL1 &&
(level1_elem = matroska_find_level1_elem(matroska, syntax->id, pos))) {
if (!level1_elem->pos) {
// Zero is not a valid position for a level 1 element.
level1_elem->pos = pos;
} else if (level1_elem->pos != pos) {
loge("Duplicate element\n");
}
level1_elem->parsed = 1;
}
/*eg. nest is g_ebml_header*/
res = ebml_parse_nest(matroska, c, syntax->def.n, data);
if (res != 0)
return res;
break;
case EBML_STOP:
return 1;
skip:
default:
if (length) {
int64_t res2;
if ((res2 = aic_stream_skip(pb, length - 1)) >= 0) {
// aic_stream_skip might take us past EOF. We check for this
// by skipping only length - 1 bytes, reading a byte and
// checking the error flags. This is done in order to check
// that the element has been properly skipped even when
// no filesize (that ffio_limit relies on) is available.
aic_stream_r8(pb);
res = NEEDS_CHECKING;
} else {
res = res2;
}
} else {
res = 0;
}
}
if (res) {
if (res == NEEDS_CHECKING) {
goto level_check;
}
if (res == PARSER_NOMEM) {
loge("Malloc failed\n");
} else if (res == PARSER_EOS) {
loge("File ended prematurely\n");
} else if (res < 0) {
loge("Invalid element\n");
}
return res;
}
level_check:
if (level_check == LEVEL_ENDED && matroska->num_levels) {
level = &matroska->levels[matroska->num_levels - 1];
pos = aic_stream_tell(pb);
// Given that pos >= level->start no check for
// level->length != EBML_UNKNOWN_LENGTH is necessary.
while (matroska->num_levels && pos == level->start + level->length) {
matroska->num_levels--;
level--;
}
}
return level_check;
}
static void ebml_freep(void *arg)
{
void *val;
memcpy(&val, arg, sizeof(val));
memcpy(arg, &(void *){ NULL }, sizeof(val));
free(val);
}
static void ebml_free(ebml_syntax *syntax, void *data)
{
int i, j;
for (i = 0; syntax[i].id; i++) {
void *data_off = (char *) data + syntax[i].data_offset;
switch (syntax[i].type) {
case EBML_STR:
case EBML_UTF8:
ebml_freep(data_off);
break;
case EBML_BIN:
ebml_freep(&((ebml_bin *) data_off)->data);
break;
case EBML_LEVEL1:
case EBML_NEST:
if (syntax[i].list_elem_size) {
ebml_list *list = data_off;
char *ptr = list->elem;
for (j = 0; j < list->nb_elem;
j++, ptr += syntax[i].list_elem_size)
ebml_free(syntax[i].def.n, ptr);
ebml_freep(&list->elem);
list->nb_elem = 0;
list->alloc_elem_size = 0;
} else {
ebml_free(syntax[i].def.n, data_off);
}
default:
break;
}
}
}
static matroska_track *matroska_find_track_by_num(struct matroska_demux_context *matroska,
uint64_t num)
{
matroska_track *tracks = matroska->tracks.elem;
int i;
for (i = 0; i < matroska->tracks.nb_elem; i++) {
logd("track[%d] number %"PRIu64"\n", i, tracks[i].num);
if (tracks[i].num == num)
return &tracks[i];
}
loge("Invalid track number %"PRIu64", nb_elem %d is euqal i %d\n",
num, matroska->tracks.nb_elem, i);
return NULL;
}
static int matroska_decode_buffer(uint8_t **buf, int *buf_size,
matroska_track *track)
{
matroska_track_encoding *encodings = track->encodings.elem;
uint8_t *data = *buf;
int isize = *buf_size;
uint8_t *pkt_data = NULL;
int pkt_size = isize;
if (pkt_size >= 10000000U)
return PARSER_ERROR;
switch (encodings[0].compression.algo) {
case MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP:
{
int header_size = encodings[0].compression.settings.size;
uint8_t *header = encodings[0].compression.settings.data;
if (header_size && !header) {
loge("Compression size but no data in headerstrip\n");
return -1;
}
if (!header_size)
return 0;
pkt_size = isize + header_size;
pkt_data = malloc(pkt_size + 64);
if (!pkt_data)
return PARSER_NOMEM;
memcpy(pkt_data, header, header_size);
memcpy(pkt_data + header_size, data, isize);
break;
}
default:
return PARSER_ERROR;
}
memset(pkt_data + pkt_size, 0, 64);
*buf = pkt_data;
*buf_size = pkt_size;
return 0;
}
static int matroska_parse_seekhead_entry(struct matroska_demux_context *matroska,
struct aic_stream *c, int64_t pos)
{
uint32_t saved_id = matroska->current_id;
int64_t before_pos = aic_stream_tell(c);
int ret = 0;
/* seek */
if (aic_stream_seek(c, pos, SEEK_SET) == pos) {
/* We don't want to lose our seekhead level, so we add
* a dummy. This is a crude hack. */
if (matroska->num_levels == EBML_MAX_DEPTH) {
logi("Max EBML element depth (%d) reached, "
"cannot parse further.\n", EBML_MAX_DEPTH);
ret = PARSER_ERROR;
} else {
matroska->levels[matroska->num_levels] = (matroska_level) { 0, EBML_UNKNOWN_LENGTH };
matroska->num_levels++;
matroska->current_id = 0;
ret = ebml_parse(matroska, c, g_matroska_segment, matroska);
if (ret == LEVEL_ENDED) {
/* This can only happen if the seek brought us beyond EOF. */
ret = PARSER_EOS;
}
}
}
/* Seek back - notice that in all instances where this is used
* it is safe to set the level to 1. */
matroska_reset_status(c, matroska, saved_id, before_pos);
return ret;
}
static void matroska_execute_seekhead(struct matroska_demux_context *matroska, struct aic_stream *c)
{
ebml_list *seekhead_list = &matroska->seekhead;
int i;
for (i = 0; i < seekhead_list->nb_elem; i++) {
matroska_seek_head *seekheads = seekhead_list->elem;
uint32_t id = seekheads[i].id;
int64_t pos = seekheads[i].pos + matroska->segment_start;
matroska_level1_element *elem;
if (id != seekheads[i].id || pos < matroska->segment_start)
continue;
elem = matroska_find_level1_elem(matroska, id, pos);
if (!elem || elem->parsed)
continue;
elem->pos = pos;
// defer cues parsing until we actually need cue data.
if (id == MATROSKA_ID_CUES)
continue;
if (matroska_parse_seekhead_entry(matroska, c, pos) < 0) {
// mark index as broken
matroska->cues_parsing_deferred = -1;
break;
}
elem->parsed = 1;
}
}
static int matroska_add_index_entries(struct matroska_demux_context *matroska,
struct matroska_stream_ctx *st)
{
ebml_list *index_list;
matroska_index *index;
int i = 0, j = 0;
uint32_t size = 0;
index_list = &matroska->index;
index = index_list->elem;
if (index_list->nb_elem < 2)
return PARSER_ERROR;
if (index[1].time > 1E14 / matroska->time_scale) {
logw("Dropping apparently-broken index.\n");
return PARSER_ERROR;
}
logd("index_list:nb_elem %d", index_list->nb_elem);
st->nb_index_entries = index_list->nb_elem;
size = st->nb_index_entries * sizeof(struct matroska_index_entry);
st->index_entries = malloc(size);
if (st->index_entries == NULL) {
loge("malloc index_entries size %"PRIu32" failed\n", size);
return PARSER_NOMEM;
}
for (i = 0; i < index_list->nb_elem; i++) {
ebml_list *pos_list = &index[i].pos;
matroska_index_pos *pos = pos_list->elem;
for (j = 0; j < pos_list->nb_elem; j++) {
matroska_track *track = matroska_find_track_by_num(matroska, pos[j].track);
if (track) {
st->index_entries[i].pos = pos->pos + matroska->segment_start;
st->index_entries[i].timestamp = index[i].time * 1000;
st->index_entries[i].flags = 1;
}
}
}
return 0;
}
static void matroska_release_index_entries(struct matroska_stream_ctx *st)
{
if (st->index_entries) {
free(st->index_entries);
st->index_entries = NULL;
}
}
static void matroska_parse_cues(struct matroska_demux_context *matroska,
struct aic_stream *c, struct matroska_stream_ctx *st)
{
int i;
logd("num_level1_elems: %d", matroska->num_level1_elems);
for (i = 0; i < matroska->num_level1_elems; i++) {
matroska_level1_element *elem = &matroska->level1_elems[i];
if (elem->id == MATROSKA_ID_CUES && !elem->parsed) {
logd("elem: id 0x%"PRIx32", pos 0x%"PRIx64"", elem->id, elem->pos);
if (matroska_parse_seekhead_entry(matroska, c, elem->pos) < 0)
matroska->cues_parsing_deferred = -1;
elem->parsed = 1;
break;
}
}
matroska_add_index_entries(matroska, st);
}
static int matroska_aac_profile(char *codec_id)
{
static const char *const aac_profiles[] = { "MAIN", "LC", "SSR" };
int profile;
for (profile = 0; profile < MKV_ARRAY_ELEMS(aac_profiles); profile++)
if (strstr(codec_id, aac_profiles[profile]))
break;
return profile + 1;
}
static int matroska_aac_sri(int samplerate)
{
int sri;
for (sri = 0; sri < MKV_ARRAY_ELEMS(mkv_priv_mpeg4audio_sample_rates); sri++)
if (mkv_priv_mpeg4audio_sample_rates[sri] == samplerate)
break;
return sri;
}
static void mkv_stereo_mode_display_mul(int stereo_mode,
int *h_width, int *h_height)
{
switch (stereo_mode) {
case MATROSKA_VIDEO_STEREOMODE_TYPE_MONO:
case MATROSKA_VIDEO_STEREOMODE_TYPE_CHECKERBOARD_RL:
case MATROSKA_VIDEO_STEREOMODE_TYPE_CHECKERBOARD_LR:
case MATROSKA_VIDEO_STEREOMODE_TYPE_BOTH_EYES_BLOCK_RL:
case MATROSKA_VIDEO_STEREOMODE_TYPE_BOTH_EYES_BLOCK_LR:
break;
case MATROSKA_VIDEO_STEREOMODE_TYPE_RIGHT_LEFT:
case MATROSKA_VIDEO_STEREOMODE_TYPE_LEFT_RIGHT:
case MATROSKA_VIDEO_STEREOMODE_TYPE_COL_INTERLEAVED_RL:
case MATROSKA_VIDEO_STEREOMODE_TYPE_COL_INTERLEAVED_LR:
*h_width = 2;
break;
case MATROSKA_VIDEO_STEREOMODE_TYPE_BOTTOM_TOP:
case MATROSKA_VIDEO_STEREOMODE_TYPE_TOP_BOTTOM:
case MATROSKA_VIDEO_STEREOMODE_TYPE_ROW_INTERLEAVED_RL:
case MATROSKA_VIDEO_STEREOMODE_TYPE_ROW_INTERLEAVED_LR:
*h_height = 2;
break;
}
}
static struct matroska_stream_ctx *matroska_new_stream(struct aic_matroska_parser *s)
{
struct matroska_stream_ctx *sc;
sc = (struct matroska_stream_ctx *)mpp_alloc(sizeof(struct matroska_stream_ctx));
if (sc == NULL) {
return NULL;
}
memset(sc, 0, sizeof(struct matroska_stream_ctx));
sc->index = s->nb_streams;
s->streams[s->nb_streams++] = sc;
return sc;
}
static int matroska_parse_tracks(struct aic_matroska_parser *s)
{
struct matroska_demux_context *matroska = &s->matroska_c;
matroska_track *tracks = (matroska_track *)matroska->tracks.elem;
struct matroska_stream_ctx *st = NULL;
int i, j;
int k;
for (i = 0; i < matroska->tracks.nb_elem; i++) {
matroska_track *track = (matroska_track *)&tracks[i];
enum CodecID codec_id = CODEC_ID_NONE;
ebml_list *encodings_list = &track->encodings;
matroska_track_encoding *encodings = encodings_list->elem;
uint8_t *extradata = NULL;
int extradata_size = 0;
int extradata_offset = 0;
uint32_t fourcc = 0;
//struct aic_stream b;
//char* key_id_base64 = NULL;
int bit_depth = -1;
/* Apply some sanity checks. */
if (track->type != MATROSKA_TRACK_TYPE_VIDEO &&
track->type != MATROSKA_TRACK_TYPE_AUDIO &&
track->type != MATROSKA_TRACK_TYPE_SUBTITLE &&
track->type != MATROSKA_TRACK_TYPE_METADATA) {
logi("Unknown or unsupported track type %"PRIu64"\n", track->type);
continue;
}
if (!track->codec_id)
continue;
if ( (track->type == MATROSKA_TRACK_TYPE_AUDIO && track->codec_id[0] != 'A')
|| (track->type == MATROSKA_TRACK_TYPE_VIDEO && track->codec_id[0] != 'V')
|| (track->type == MATROSKA_TRACK_TYPE_SUBTITLE && track->codec_id[0] != 'D' && track->codec_id[0] != 'S')
|| (track->type == MATROSKA_TRACK_TYPE_METADATA && track->codec_id[0] != 'D' && track->codec_id[0] != 'S')) {
logi("Inconsistent track type\n");
continue;
}
if (track->audio.samplerate < 0 || track->audio.samplerate > UINT_MAX) {
logw("Invalid sample rate %f, defaulting to 8000 instead.\n",
track->audio.samplerate);
track->audio.samplerate = 8000;
}
if (track->type == MATROSKA_TRACK_TYPE_VIDEO) {
if (!track->default_duration && track->video.frame_rate > 0) {
double default_duration = 1000000000 / track->video.frame_rate;
if (default_duration > UINT64_MAX || default_duration < 0) {
logw("Invalid frame rate %e. Cannot calculate default duration.\n",
track->video.frame_rate);
} else {
track->default_duration = default_duration;
}
}
if (track->video.display_width == -1)
track->video.display_width = track->video.pixel_width;
if (track->video.display_height == -1)
track->video.display_height = track->video.pixel_height;
if (track->video.color_space.size == 4)
fourcc = AIC_RL32(track->video.color_space.data);
} else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) {
if (!track->audio.out_samplerate)
track->audio.out_samplerate = track->audio.samplerate;
}
if (encodings_list->nb_elem > 1) {
loge("Multiple combined encodings not supported");
} else if (encodings_list->nb_elem == 1) {
if (encodings[0].type) {
if (encodings[0].encryption.key_id.size > 0) {
/* Save the encryption key id to be stored later as a
metadata tag. */
loge("Unsupported encoding encryption");
} else {
encodings[0].scope = 0;
loge("Unsupported encoding type");
}
} else if (
#if CONFIG_ZLIB
encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_ZLIB &&
#endif
#if CONFIG_BZLIB
encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_BZLIB &&
#endif
#if CONFIG_LZO
encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_LZO &&
#endif
encodings[0].compression.algo != MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP) {
encodings[0].scope = 0;
loge("Unsupported encoding type");
} else if (track->codec_priv.size && encodings[0].scope & 2) {
uint8_t *codec_priv = track->codec_priv.data;
int ret = matroska_decode_buffer(&track->codec_priv.data,
&track->codec_priv.size,
track);
if (ret < 0) {
track->codec_priv.data = NULL;
track->codec_priv.size = 0;
loge("Failed to decode codec private data\n");
}
if (codec_priv != track->codec_priv.data) {
free(&track->codec_priv.data);
track->codec_priv.data = malloc(track->codec_priv.size + 64);
if (!track->codec_priv.data) {
track->codec_priv.size = 0;
return PARSER_NOMEM;
}
}
}
}
track->needs_decoding = encodings && !encodings[0].type &&
encodings[0].scope & 1 &&
(encodings[0].compression.algo !=
MATROSKA_TRACK_ENCODING_COMP_HEADERSTRIP ||
encodings[0].compression.settings.size);
for (j = 0; mkv_codec_tags[j].id != CODEC_ID_NONE; j++) {
if (!strncmp(mkv_codec_tags[j].str, track->codec_id,
strlen(mkv_codec_tags[j].str))) {
codec_id = mkv_codec_tags[j].id;
break;
}
}
st = track->stream = matroska_new_stream(s);
if (!st) {
return PARSER_NOMEM;
}
if (codec_id == CODEC_ID_PCM_S16BE) {
switch (track->audio.bitdepth) {
case 8:
codec_id = CODEC_ID_PCM_U8;
break;
case 24:
codec_id = CODEC_ID_PCM_S24BE;
break;
case 32:
codec_id = CODEC_ID_PCM_S32BE;
break;
}
} else if (codec_id == CODEC_ID_PCM_S16LE) {
switch (track->audio.bitdepth) {
case 8:
codec_id = CODEC_ID_PCM_U8;
break;
case 24:
codec_id = CODEC_ID_PCM_S24LE;
break;
case 32:
codec_id = CODEC_ID_PCM_S32LE;
break;
}
} else if (codec_id == CODEC_ID_PCM_F32LE &&
track->audio.bitdepth == 64) {
codec_id = CODEC_ID_PCM_F64LE;
} else if (codec_id == CODEC_ID_AAC && !track->codec_priv.size) {
int profile = matroska_aac_profile(track->codec_id);
int sri = matroska_aac_sri(track->audio.samplerate);
extradata = malloc(5 + 64);
if (!extradata)
return PARSER_NOMEM;
extradata[0] = (profile << 3) | ((sri & 0x0E) >> 1);
extradata[1] = ((sri & 0x01) << 7) | (track->audio.channels << 3);
if (strstr(track->codec_id, "SBR")) {
sri = matroska_aac_sri(track->audio.out_samplerate);
extradata[2] = 0x56;
extradata[3] = 0xE5;
extradata[4] = 0x80 | (sri << 3);
extradata_size = 5;
} else {
extradata_size = 2;
}
}
track->codec_priv.size -= extradata_offset;
if (codec_id == CODEC_ID_NONE)
loge("Unknown/unsupported CodecID %d.\n", codec_id);
st->codecpar.codec_id = codec_id;
if (!st->codecpar.extradata) {
if (extradata) {
st->codecpar.extradata = extradata;
st->codecpar.extradata_size = extradata_size;
} else if (track->codec_priv.data && track->codec_priv.size > 0) {
st->codecpar.extradata = malloc(track->codec_priv.size + 64);
if (NULL == st->codecpar.extradata)
return PARSER_NOMEM;
st->codecpar.extradata_size = track->codec_priv.size;
memset(st->codecpar.extradata + track->codec_priv.size, 0, 64);
memcpy(st->codecpar.extradata,
track->codec_priv.data + extradata_offset,
track->codec_priv.size);
}
}
if (track->type == MATROSKA_TRACK_TYPE_VIDEO) {
matroska_track_plane *planes = track->operation.combine_planes.elem;
int display_width_mul = 1;
int display_height_mul = 1;
st->codecpar.codec_type = MPP_MEDIA_TYPE_VIDEO;
st->codecpar.codec_tag = fourcc;
if (bit_depth >= 0)
st->codecpar.bits_per_coded_sample = bit_depth;
st->codecpar.width = track->video.pixel_width;
st->codecpar.height = track->video.pixel_height;
if (track->video.stereo_mode && track->video.stereo_mode < MATROSKA_VIDEO_STEREOMODE_TYPE_NB)
mkv_stereo_mode_display_mul(track->video.stereo_mode, &display_width_mul, &display_height_mul);
/* if we have virtual track, mark the real tracks */
for (j=0; j < track->operation.combine_planes.nb_elem; j++) {
if (planes[j].type >= MATROSKA_VIDEO_STEREO_PLANE_COUNT)
continue;
for (k=0; k < matroska->tracks.nb_elem; k++)
if (planes[j].uid == tracks[k].uid) {
break;
}
}
st->duration = matroska->duration * matroska->time_scale * 1000 / TIME_BASE;
} else if (track->type == MATROSKA_TRACK_TYPE_AUDIO) {
st->codecpar.codec_type = MPP_MEDIA_TYPE_AUDIO;
st->codecpar.codec_tag = fourcc;
st->codecpar.sample_rate = track->audio.out_samplerate;
st->codecpar.channels = track->audio.channels;
if (!st->codecpar.bits_per_coded_sample)
st->codecpar.bits_per_coded_sample = track->audio.bitdepth;
st->duration = matroska->duration * matroska->time_scale * 1000 / TIME_BASE;
}
}
return 0;
}
static void matroska_parse_cluster_eos(struct matroska_demux_context *matroska)
{
int i;
for (i = 0; i < matroska->num_level1_elems; i++) {
matroska_level1_element *elem = &matroska->level1_elems[i];
if (elem->id == MATROSKA_ID_CUES && !elem->parsed) {
printf("elem: id 0x%"PRIx32", pos 0x%"PRIx64"", elem->id, elem->pos);
matroska->eos_pos = elem->pos;
break;
}
}
}
int matroska_read_header(struct aic_matroska_parser *s)
{
struct matroska_demux_context *matroska = &s->matroska_c;
struct aic_stream *c = s->stream;
int64_t pos;
ebml_header ebml = { 0 };
int i, res = PARSER_OK;
matroska->cues_parsing_deferred = 1;
/* First read the EBML header. */
if (ebml_parse(matroska, c, g_ebml_syntax, &ebml) || !ebml.doctype) {
loge("EBML header parsing failed\n");
ebml_free(g_ebml_syntax, &ebml);
return PARSER_ERROR;
}
if (ebml.version > EBML_VERSION ||
ebml.max_size > sizeof(uint64_t) ||
ebml.id_length > sizeof(uint32_t) ||
ebml.doctype_version > 3) {
loge("EBML version %"PRIu64", doctype %s, doc version %"PRIu64,
ebml.version, ebml.doctype, ebml.doctype_version);
ebml_free(g_ebml_syntax, &ebml);
return PARSER_ERROR;
} else if (ebml.doctype_version == 3) {
logw("EBML header using unsupported features\n"
"(EBML version %"PRIu64", doctype %s, doc version %"PRIu64")\n",
ebml.version, ebml.doctype, ebml.doctype_version);
}
for (i = 0; i < MKV_ARRAY_ELEMS(g_matroska_doctypes); i++)
if (!strcmp(ebml.doctype, g_matroska_doctypes[i]))
break;
if (i >= MKV_ARRAY_ELEMS(g_matroska_doctypes)) {
logw("Unknown EBML doctype '%s'\n", ebml.doctype);
}
ebml_free(g_ebml_syntax, &ebml);
/* The next thing is a segment. */
pos = aic_stream_tell(c);
res = ebml_parse(matroska, c, g_matroska_segments, matroska);
// Try resyncing until we find an EBML_STOP type element.
while (res != 1) {
res = matroska_resync(c, matroska, pos);
if (res < 0)
goto fail;
pos = aic_stream_tell(c);
res = ebml_parse(matroska, c, g_matroska_segment, matroska);
}
matroska_execute_seekhead(matroska, c);
if (!matroska->time_scale)
matroska->time_scale = 1000000;
res = matroska_parse_tracks(s);
if (res < 0)
goto fail;
/* Find the end cluster */
matroska_parse_cluster_eos(matroska);
return 0;
fail:
matroska_read_close(s);
return res;
}
static int matroska_parse_laces(struct matroska_demux_context *matroska, uint8_t **buf,
int size, int type, struct aic_stream *pb,
uint32_t lace_size[256], int *laces)
{
int n;
uint8_t *data = *buf;
if (!type) {
*laces = 1;
lace_size[0] = size;
return 0;
}
if (size <= 0)
return PARSER_ERROR;
*laces = *data + 1;
data += 1;
size -= 1;
switch (type) {
case 0x1: /* Xiph lacing */
{
uint8_t temp;
uint32_t total = 0;
for (n = 0; n < *laces - 1; n++) {
lace_size[n] = 0;
do {
if (size <= total)
return PARSER_ERROR;
temp = *data;
total += temp;
lace_size[n] += temp;
data += 1;
size -= 1;
} while (temp == 0xff);
}
if (size < total)
return PARSER_ERROR;
lace_size[n] = size - total;
break;
}
case 0x2: /* fixed-size lacing */
if (size % (*laces))
return PARSER_ERROR;
for (n = 0; n < *laces; n++)
lace_size[n] = size / *laces;
break;
case 0x3: /* EBML lacing */
{
uint64_t num;
uint64_t total;
int offset;
aic_stream_skip(pb, 4);
n = ebml_read_num(matroska, pb, 8, &num, 1);
if (n < 0)
return n;
if (num > INT_MAX)
return PARSER_ERROR;
total = lace_size[0] = num;
offset = n;
for (n = 1; n < *laces - 1; n++) {
int64_t snum = 0;
int r;
r = matroska_ebmlnum_sint(matroska, pb, &snum);
if (r < 0)
return r;
if (lace_size[n - 1] + snum > (uint64_t)INT_MAX)
return PARSER_ERROR;
lace_size[n] = lace_size[n - 1] + snum;
total += lace_size[n];
offset += r;
}
data += offset;
size -= offset;
if (size < total)
return PARSER_ERROR;
lace_size[*laces - 1] = size - total;
break;
}
}
*buf = data;
return 0;
}
static int matroska_parse_block(struct matroska_demux_context *matroska, struct aic_stream *pb, uint8_t *data,
int size, int64_t pos, uint64_t cluster_time,
uint64_t block_duration, int is_keyframe,
uint8_t *additional, uint64_t additional_id, int additional_size,
int64_t cluster_pos, int64_t discard_padding, struct aic_parser_packet *pkt)
{
uint64_t timecode = 0;
matroska_track *track;
int res = 0;
struct matroska_stream_ctx *st = NULL;
int16_t block_time;
uint32_t lace_size[256];
int n, flags, laces = 0;
uint64_t num = 0;
int trust_default_duration = 1;
if ((n = ebml_read_num(matroska, pb, 8, &num, 1)) < 0)
return n;
size -= n;
if (aic_stream_tell(pb) >= matroska->eos_pos) {
matroska->done = 1;
return PARSER_EOS;
}
logi("simple block: num %"PRIu64"", num);
track = matroska_find_track_by_num(matroska, num);
if (!track || size < 3) {
loge("matroska_find_track_by_num failed track %p, size %d", track, size);
return PARSER_ERROR;
}
if (!(st = track->stream)) {
loge("No stream associated to TrackNumber %"PRIu64". "
"Ignoring Block with this TrackNumber.\n", num);
return 0;
}
if (block_duration > INT64_MAX)
block_duration = INT64_MAX;
block_time = aic_stream_rb16(pb);
flags = aic_stream_r8(pb);
size -= 3;
if (is_keyframe == -1)
is_keyframe = flags & 0x80 ? 1 : 0;
if (cluster_time != (uint64_t) -1 &&
(block_time >= 0 || cluster_time >= -block_time)) {
timecode = cluster_time + block_time - track->codec_delay_in_track_tb;
}
if (matroska->skip_to_keyframe &&
track->type != MATROSKA_TRACK_TYPE_SUBTITLE) {
// Compare signed timecodes. Timecode may be negative due to codec delay
// offset. We don't support timestamps greater than int64_t
if ((int64_t)timecode < (int64_t)matroska->skip_to_timecode)
return res;
if (is_keyframe)
matroska->skip_to_keyframe = 0;
}
res = matroska_parse_laces(matroska, &data, size, (flags & 0x06) >> 1,
pb, lace_size, &laces);
if (res < 0) {
loge("Error parsing frame sizes.\n");
return res;
}
logi("skip_track 0x%x track:type %"PRIu64" default_duration %"PRIu64" "
"end_timecode %"PRIu64", needs_decoding %d audio.buf %p",
matroska->skip_track, track->type, track->default_duration,
track->end_timecode, track->needs_decoding, track->audio.buf);
if (!block_duration && trust_default_duration)
block_duration = track->default_duration * laces / matroska->time_scale;
if (cluster_time != (uint64_t)-1 && (block_time >= 0 || cluster_time >= -block_time))
track->end_timecode =
MPP_MAX(track->end_timecode, timecode + block_duration);
for (n = 0; n < laces; n++) {
int64_t lace_duration = block_duration*(n+1) / laces - block_duration*n / laces;
int out_size = lace_size[n];
if (track->needs_decoding) {
loge("not support needs decoding");
return PARSER_ERROR;
}
matroska->cur_pos = aic_stream_tell(pb);
pkt->size = out_size;
pkt->pts = timecode * 1000;
pkt->duration = lace_duration * 1000;
pkt->type = st->codecpar.codec_type;
pkt->flag = 0;
logd("type %d cur_pos 0x%"PRIx64", eos_pos 0x%"PRIx64" size 0x%x",
pkt->type, matroska->cur_pos, matroska->eos_pos, out_size);
/*Unsupport video or audio type need to be skip cur packet*/
if (pkt->type == MPP_MEDIA_TYPE_VIDEO &&
matroska->skip_track & EBML_SKIP_VIDEO_TRACK) {
aic_stream_skip(pb, out_size);
}
if (pkt->type == MPP_MEDIA_TYPE_AUDIO &&
matroska->skip_track & EBML_SKIP_AUDIO_TRACK) {
aic_stream_skip(pb, out_size);
}
if (timecode != 0)
timecode = lace_duration ? timecode + lace_duration : 0;
data += lace_size[n];
}
return PARSER_OK;
}
static int matroska_parse_cluster(struct matroska_demux_context *matroska,
struct aic_stream *c, struct aic_parser_packet *pkt)
{
matroska_cluster *cluster = &matroska->current_cluster;
matroska_block *block = &cluster->block;
int res = PARSER_OK;
matroska->cur_pos = 0;
assert(matroska->num_levels <= 2);
if (matroska->num_levels == 1) {
res = ebml_parse(matroska, c, g_matroska_segment, NULL);
logd("current_id 0x%"PRIx32", num_levels:%d, g_matroska_segment res:%d eos_pos 0x%"PRIx64"",
matroska->current_id, matroska->num_levels, res, matroska->eos_pos);
if (res == 1) {
/* Found a cluster: subtract the size of the ID already read. */
cluster->pos = aic_stream_tell(c) - 4;
res = ebml_parse(matroska, c, g_matroska_cluster_enter, cluster);
if (res < 0)
return res;
}
}
if (matroska->num_levels == 2) {
/* We are inside a cluster. */
res = ebml_parse(matroska, c, g_matroska_cluster_parsing, cluster);
logd("matroska: current_id 0x%"PRIx32", num_levels:%d, "
"cluster parsing: timecode %"PRIu64", pos 0x%"PRIx64",cur pos 0x%"PRIx64", "
"block: size %d, pos 0x%"PRIx64", duration %"PRIu64", reference %"PRId64"",
matroska->current_id, matroska->num_levels,
cluster->timecode, cluster->pos, (int64_t)aic_stream_tell(c),
block->bin.size, block->bin.pos, block->duration, block->reference);
if (res >= 0 && block->bin.size > 0) {
int is_keyframe = block->non_simple ? block->reference == INT64_MIN : -1;
uint8_t* additional = block->additional.size > 0 ?
block->additional.data : NULL;
res = matroska_parse_block(matroska, c, block->bin.data,
block->bin.size, block->bin.pos,
cluster->timecode, block->duration,
is_keyframe, additional, block->additional_id,
block->additional.size, cluster->pos,
block->discard_padding, pkt);
} else {
memset(pkt, 0, sizeof(struct aic_parser_packet));
pkt->type = MPP_MEDIA_TYPE_UNKNOWN;
}
ebml_free(g_matroska_blockgroup, block);
memset(block, 0, sizeof(*block));
} else if (!matroska->num_levels) {
res = PARSER_EOS;
loge("warong levels %d", matroska->num_levels);
goto exit;
}
if (aic_stream_tell(c) >= matroska->eos_pos) {
res = PARSER_EOS;
goto exit;
}
if (res != PARSER_OK) {
goto exit;
}
return PARSER_OK;
exit:
if (res == PARSER_EOS) {
matroska->done = 1;
pkt->size = 0;
pkt->flag = PACKET_EOS;
printf("[%s:%d]packet eos!!!!!!", __FUNCTION__, __LINE__);
}
return res;
}
int matroska_peek_packet(struct aic_matroska_parser *s, struct aic_parser_packet *pkt)
{
struct aic_stream *c = s->stream;
struct matroska_demux_context *matroska = &s->matroska_c;
if (matroska->resync_pos == -1) {
// This can only happen if generic seeking has been used.
matroska->resync_pos = aic_stream_tell(c);
}
/*cluster contains a data stream of audio, video and subtitle tracks*/
if (matroska_parse_cluster(matroska, c, pkt) < 0)
matroska_resync(c, matroska, matroska->resync_pos);
if (matroska->done) {
return PARSER_EOS;
}
return PARSER_OK;
}
int matroska_read_packet(struct aic_matroska_parser *s, struct aic_parser_packet *pkt)
{
aic_stream_seek(s->stream, s->matroska_c.cur_pos, SEEK_SET);
aic_stream_read(s->stream, pkt->data, pkt->size);
return PARSER_OK;
}
static int find_index_by_pts(struct matroska_stream_ctx *st, s64 pts)
{
int i, index = 0;
int64_t min = INT64_MAX;
int64_t sample_pts = 0;
int64_t diff = 0;
struct matroska_index_entry *cur_sample = NULL;
logd("nb_index_entries:%d\n", st->nb_index_entries);
/* First step: find current frame by pts*/
for (i = 0; i < st->nb_index_entries; i++) {
cur_sample = &st->index_entries[i];
sample_pts = cur_sample->timestamp;
diff = MPP_ABS(pts, sample_pts);
if (diff < min) {
min = diff;
index = i;
}
}
if (index > 0) {
return index;
}
return PARSER_ERROR;
}
int matroska_seek_packet(struct aic_matroska_parser *s, s64 pts)
{
struct matroska_demux_context *matroska = &s->matroska_c;
struct matroska_stream_ctx *st = s->streams[0];
struct aic_stream *c = s->stream;
int index;
/* Parse the CUES now since we need the index data to seek. */
if (matroska->cues_parsing_deferred > 0)
{
matroska->cues_parsing_deferred = 0;
matroska_parse_cues(matroska, c, st);
}
if (st->nb_index_entries <= 0) {
logd("find index entries %d", st->nb_index_entries);
goto err;
}
index = find_index_by_pts(st, pts);
if (index < 0) {
logd("find index failed");
goto err;
}
/* We seek to a level 1 element, so set the appropriate status. */
matroska_reset_status(c, matroska, 0, st->index_entries[index].pos);
return PARSER_OK;
err:
// slightly hackish but allows proper fallback to
// the generic seeking code.
matroska_reset_status(c, matroska, 0, -1);
matroska->resync_pos = -1;
return PARSER_ERROR;
}
int matroska_read_close(struct aic_matroska_parser *s)
{
struct matroska_demux_context *matroska = &s->matroska_c;
matroska_release_index_entries(s->streams[0]);
ebml_free(g_matroska_segment, matroska);
return PARSER_OK;
}
int matroska_control(struct aic_matroska_parser *s, enum parse_command cmd, void *params)
{
switch (cmd) {
case PARSER_VIDEO_SKIP_PACKET:
s->matroska_c.skip_track |= EBML_SKIP_VIDEO_TRACK;
break;
case PARSER_AUDIO_SKIP_PACKET:
s->matroska_c.skip_track |= EBML_SKIP_AUDIO_TRACK;
break;
default:
return PARSER_INVALIDPARAM;
}
return PARSER_OK;
}