2004-01-19 19:16:10 +00:00
|
|
|
/*
|
2009-05-08 21:51:13 +00:00
|
|
|
* Matroska demuxer
|
|
|
|
* Copyright (C) 2004 Aurelien Jacobs <aurel@gnuage.org>
|
2004-01-19 19:16:10 +00:00
|
|
|
* Based on the one written by Ronald Bultje for gstreamer
|
2009-05-08 21:51:13 +00:00
|
|
|
* and on demux_mkv.cpp from Moritz Bunkus.
|
|
|
|
*
|
|
|
|
* This file is part of MPlayer.
|
|
|
|
*
|
|
|
|
* MPlayer is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* MPlayer 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 General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2004-01-19 19:16:10 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <ctype.h>
|
2006-06-04 22:41:27 +00:00
|
|
|
#include <inttypes.h>
|
2009-03-16 21:30:48 +00:00
|
|
|
#include <stdbool.h>
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-03-16 21:30:48 +00:00
|
|
|
#include "talloc.h"
|
2008-04-16 04:11:12 +00:00
|
|
|
#include "options.h"
|
2007-03-15 18:36:36 +00:00
|
|
|
#include "stream/stream.h"
|
2004-01-19 19:16:10 +00:00
|
|
|
#include "demuxer.h"
|
|
|
|
#include "stheader.h"
|
|
|
|
#include "ebml.h"
|
|
|
|
#include "matroska.h"
|
|
|
|
|
2006-11-05 13:53:27 +00:00
|
|
|
#include "mp_msg.h"
|
|
|
|
#include "help_mp.h"
|
|
|
|
|
2007-12-08 12:15:03 +00:00
|
|
|
#include "vobsub.h"
|
2005-11-18 14:39:25 +00:00
|
|
|
#include "subreader.h"
|
|
|
|
#include "libvo/sub.h"
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-07-25 04:24:39 +00:00
|
|
|
#include "ass_mp.h"
|
2006-07-07 18:26:51 +00:00
|
|
|
|
2007-03-16 14:55:41 +00:00
|
|
|
#include "libavutil/common.h"
|
|
|
|
|
2008-07-30 12:01:30 +00:00
|
|
|
#ifdef CONFIG_QTX_CODECS
|
2007-03-15 22:34:45 +00:00
|
|
|
#include "loader/qtx/qtxsdk/components.h"
|
2004-01-19 19:16:10 +00:00
|
|
|
#endif
|
|
|
|
|
2009-02-07 15:23:55 +00:00
|
|
|
#if CONFIG_ZLIB
|
2004-01-19 19:16:10 +00:00
|
|
|
#include <zlib.h>
|
|
|
|
#endif
|
|
|
|
|
2007-01-31 23:28:34 +00:00
|
|
|
#include "libavutil/lzo.h"
|
2009-07-22 00:04:08 +00:00
|
|
|
#include "ffmpeg_files/intreadwrite.h"
|
2007-07-05 22:01:07 +00:00
|
|
|
#include "libavutil/avstring.h"
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static const unsigned char sipr_swaps[38][2] = {
|
2006-04-03 19:41:17 +00:00
|
|
|
{0,63},{1,22},{2,44},{3,90},{5,81},{7,31},{8,86},{9,58},{10,36},{12,68},
|
|
|
|
{13,39},{14,73},{15,53},{16,69},{17,57},{19,88},{20,34},{21,71},{24,46},
|
|
|
|
{25,94},{26,54},{28,75},{29,50},{32,70},{33,92},{35,74},{38,85},{40,56},
|
|
|
|
{42,87},{43,65},{45,59},{48,79},{49,93},{51,89},{55,95},{61,76},{67,83},
|
2009-12-29 19:06:21 +00:00
|
|
|
{77,80}
|
|
|
|
};
|
2006-04-03 19:41:17 +00:00
|
|
|
|
|
|
|
// Map flavour to bytes per second
|
|
|
|
#define SIPR_FLAVORS 4
|
|
|
|
#define ATRC_FLAVORS 8
|
|
|
|
#define COOK_FLAVORS 34
|
2009-12-29 19:06:21 +00:00
|
|
|
static const int sipr_fl2bps[SIPR_FLAVORS] = { 813, 1062, 625, 2000 };
|
|
|
|
static const int atrc_fl2bps[ATRC_FLAVORS] =
|
|
|
|
{ 8269, 11714, 13092, 16538, 18260, 22050, 33075, 44100 };
|
2008-04-12 15:51:11 +00:00
|
|
|
static const int cook_fl2bps[COOK_FLAVORS] = {
|
|
|
|
1000, 1378, 2024, 2584, 4005, 5513, 8010, 4005, 750, 2498,
|
|
|
|
4048, 5513, 8010, 11973, 8010, 2584, 4005, 2067, 2584, 2584,
|
|
|
|
4005, 4005, 5513, 5513, 8010, 12059, 1550, 8010, 12059, 5513,
|
2009-12-29 19:06:21 +00:00
|
|
|
12016, 16408, 22911, 33506
|
|
|
|
};
|
2006-04-03 19:41:17 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
typedef struct {
|
|
|
|
uint32_t order, type, scope;
|
|
|
|
uint32_t comp_algo;
|
|
|
|
uint8_t *comp_settings;
|
|
|
|
int comp_settings_len;
|
2004-01-19 19:16:10 +00:00
|
|
|
} mkv_content_encoding_t;
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
typedef struct mkv_track {
|
|
|
|
int tnum;
|
|
|
|
char *name;
|
2009-07-06 23:26:13 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
char *codec_id;
|
|
|
|
int ms_compat;
|
|
|
|
char *language;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
int type;
|
2009-07-06 23:26:13 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
uint32_t v_width, v_height, v_dwidth, v_dheight;
|
|
|
|
double v_frate;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
uint32_t a_formattag;
|
|
|
|
uint32_t a_channels, a_bps;
|
|
|
|
float a_sfreq;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
double default_duration;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
int default_track;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
unsigned char *private_data;
|
|
|
|
unsigned int private_size;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
/* stuff for realmedia */
|
|
|
|
int realmedia;
|
|
|
|
int64_t rv_kf_base;
|
|
|
|
int rv_kf_pts;
|
|
|
|
double rv_pts; /* previous video timestamp */
|
|
|
|
double ra_pts; /* previous audio timestamp */
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2006-04-03 19:41:17 +00:00
|
|
|
/** realaudio descrambling */
|
2009-12-29 19:06:21 +00:00
|
|
|
int sub_packet_size; ///< sub packet size, per stream
|
|
|
|
int sub_packet_h; ///< number of coded frames per block
|
|
|
|
int coded_framesize; ///< coded frame size, per stream
|
|
|
|
int audiopk_size; ///< audio packet size
|
|
|
|
unsigned char *audio_buf; ///< place to store reordered audio data
|
|
|
|
double *audio_timestamp; ///< timestamp for each audio packet
|
|
|
|
int sub_packet_cnt; ///< number of subpacket already received
|
|
|
|
int audio_filepos; ///< file position of first audio packet in block
|
|
|
|
|
|
|
|
/* stuff for quicktime */
|
|
|
|
int fix_i_bps;
|
|
|
|
double qt_last_a_pts;
|
|
|
|
|
|
|
|
int subtitle_type;
|
|
|
|
|
|
|
|
/* The timecodes of video frames might have to be reordered if they're
|
|
|
|
in display order (the timecodes, not the frames themselves!). In this
|
|
|
|
case demux packets have to be cached with the help of these variables. */
|
|
|
|
int reorder_timecodes;
|
|
|
|
demux_packet_t **cached_dps;
|
|
|
|
int num_cached_dps, num_allocated_dps;
|
|
|
|
double max_pts;
|
|
|
|
|
|
|
|
/* generic content encoding support */
|
|
|
|
mkv_content_encoding_t *encodings;
|
|
|
|
int num_encodings;
|
|
|
|
|
|
|
|
/* For VobSubs and SSA/ASS */
|
|
|
|
sh_sub_t *sh_sub;
|
2004-01-19 19:16:10 +00:00
|
|
|
} mkv_track_t;
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
typedef struct mkv_index {
|
|
|
|
int tnum;
|
|
|
|
uint64_t timecode, filepos;
|
2004-01-19 19:16:10 +00:00
|
|
|
} mkv_index_t;
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
typedef struct mkv_demuxer {
|
|
|
|
off_t segment_start;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
double duration, last_pts;
|
|
|
|
uint64_t last_filepos;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_track_t **tracks;
|
|
|
|
int num_tracks;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
uint64_t tc_scale, cluster_tc;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
uint64_t cluster_size;
|
|
|
|
uint64_t blockgroup_size;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_index_t *indexes;
|
|
|
|
int num_indexes;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
off_t *parsed_cues;
|
|
|
|
int parsed_cues_num;
|
|
|
|
off_t *parsed_seekhead;
|
|
|
|
int parsed_seekhead_num;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
uint64_t *cluster_positions;
|
|
|
|
int num_cluster_pos;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
int64_t skip_to_timecode;
|
|
|
|
int v_skip_to_keyframe, a_skip_to_keyframe;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
int last_aid;
|
|
|
|
int audio_tracks[MAX_A_STREAMS];
|
2004-01-19 19:16:10 +00:00
|
|
|
} mkv_demuxer_t;
|
|
|
|
|
2007-05-28 18:13:33 +00:00
|
|
|
#define REALHEADER_SIZE 16
|
|
|
|
#define RVPROPERTIES_SIZE 34
|
|
|
|
#define RAPROPERTIES4_SIZE 56
|
|
|
|
#define RAPROPERTIES5_SIZE 70
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2006-10-10 15:01:11 +00:00
|
|
|
/**
|
|
|
|
* \brief ensures there is space for at least one additional element
|
|
|
|
* \param array array to grow
|
|
|
|
* \param nelem current number of elements in array
|
|
|
|
* \param elsize size of one array element
|
|
|
|
*/
|
2009-12-29 19:06:21 +00:00
|
|
|
static void *grow_array(void *array, int nelem, size_t elsize)
|
|
|
|
{
|
|
|
|
if (!(nelem & 31))
|
|
|
|
array = realloc(array, (nelem + 32) * elsize);
|
|
|
|
return array;
|
2006-10-10 15:01:11 +00:00
|
|
|
}
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static mkv_track_t *demux_mkv_find_track_by_num(mkv_demuxer_t *d, int n,
|
|
|
|
int type)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
int i, id;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
for (i = 0, id = 0; i < d->num_tracks; i++)
|
|
|
|
if (d->tracks[i] != NULL && d->tracks[i]->type == type)
|
|
|
|
if (id++ == n)
|
|
|
|
return d->tracks[i];
|
2009-07-06 23:26:13 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
return NULL;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static void add_cluster_position(mkv_demuxer_t *mkv_d, uint64_t position)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
int i = mkv_d->num_cluster_pos;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
while (i--)
|
|
|
|
if (mkv_d->cluster_positions[i] == position)
|
|
|
|
return;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_d->cluster_positions =
|
|
|
|
grow_array(mkv_d->cluster_positions, mkv_d->num_cluster_pos,
|
|
|
|
sizeof(uint64_t));
|
|
|
|
mkv_d->cluster_positions[mkv_d->num_cluster_pos++] = position;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define AAC_SYNC_EXTENSION_TYPE 0x02b7
|
2009-12-29 19:06:21 +00:00
|
|
|
static int aac_get_sample_rate_index(uint32_t sample_rate)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
static const int srates[] = {
|
|
|
|
92017, 75132, 55426, 46009, 37566, 27713,
|
|
|
|
23004, 18783, 13856, 11502, 9391, 0
|
|
|
|
};
|
|
|
|
int i = 0;
|
|
|
|
while (sample_rate < srates[i])
|
|
|
|
i++;
|
|
|
|
return i;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2004-11-26 16:36:03 +00:00
|
|
|
/** \brief Free cached demux packets
|
|
|
|
*
|
|
|
|
* Reordering the timecodes requires caching of demux packets. This function
|
|
|
|
* frees all these cached packets and the memory for the cached pointers
|
|
|
|
* itself.
|
|
|
|
*
|
|
|
|
* \param demuxer The demuxer for which the cache is to be freed.
|
|
|
|
*/
|
2009-12-29 19:06:21 +00:00
|
|
|
static void free_cached_dps(demuxer_t *demuxer)
|
2004-11-26 16:36:03 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
|
|
|
mkv_track_t *track;
|
|
|
|
int i, k;
|
|
|
|
|
|
|
|
for (k = 0; k < mkv_d->num_tracks; k++) {
|
|
|
|
track = mkv_d->tracks[k];
|
|
|
|
for (i = 0; i < track->num_cached_dps; i++)
|
|
|
|
free_demux_packet(track->cached_dps[i]);
|
|
|
|
free(track->cached_dps);
|
|
|
|
track->cached_dps = NULL;
|
|
|
|
track->num_cached_dps = 0;
|
|
|
|
track->num_allocated_dps = 0;
|
|
|
|
track->max_pts = 0;
|
2004-11-26 16:36:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static int demux_mkv_decode(mkv_track_t *track, uint8_t *src,
|
|
|
|
uint8_t **dest, uint32_t *size, uint32_t type)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
int i, result;
|
|
|
|
int modified = 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
*dest = src;
|
|
|
|
if (track->num_encodings <= 0)
|
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
for (i = 0; i < track->num_encodings; i++) {
|
|
|
|
if (!(track->encodings[i].scope & type))
|
|
|
|
continue;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-02-07 15:23:55 +00:00
|
|
|
#if CONFIG_ZLIB
|
2009-12-29 19:06:21 +00:00
|
|
|
if (track->encodings[i].comp_algo == 0) {
|
|
|
|
/* zlib encoded track */
|
|
|
|
z_stream zstream;
|
|
|
|
|
|
|
|
zstream.zalloc = (alloc_func) 0;
|
|
|
|
zstream.zfree = (free_func) 0;
|
|
|
|
zstream.opaque = (voidpf) 0;
|
|
|
|
if (inflateInit(&zstream) != Z_OK) {
|
|
|
|
mp_tmsg(MSGT_DEMUX, MSGL_WARN,
|
|
|
|
"[mkv] zlib initialization failed.\n");
|
2004-01-19 19:16:10 +00:00
|
|
|
return modified;
|
2009-12-29 19:06:21 +00:00
|
|
|
}
|
|
|
|
zstream.next_in = (Bytef *) src;
|
|
|
|
zstream.avail_in = *size;
|
|
|
|
|
|
|
|
modified = 1;
|
|
|
|
*dest = NULL;
|
|
|
|
zstream.avail_out = *size;
|
|
|
|
do {
|
|
|
|
*size += 4000;
|
|
|
|
*dest = realloc(*dest, *size);
|
|
|
|
zstream.next_out = (Bytef *) (*dest + zstream.total_out);
|
|
|
|
result = inflate(&zstream, Z_NO_FLUSH);
|
|
|
|
if (result != Z_OK && result != Z_STREAM_END) {
|
|
|
|
mp_tmsg(MSGT_DEMUX, MSGL_WARN,
|
|
|
|
"[mkv] zlib decompression failed.\n");
|
|
|
|
free(*dest);
|
|
|
|
*dest = NULL;
|
|
|
|
inflateEnd(&zstream);
|
|
|
|
return modified;
|
|
|
|
}
|
|
|
|
zstream.avail_out += 4000;
|
|
|
|
} while (zstream.avail_out == 4000 && zstream.avail_in != 0
|
|
|
|
&& result != Z_STREAM_END);
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
*size = zstream.total_out;
|
|
|
|
inflateEnd(&zstream);
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
#endif
|
2009-12-29 19:06:21 +00:00
|
|
|
if (track->encodings[i].comp_algo == 2) {
|
|
|
|
/* lzo encoded track */
|
|
|
|
int dstlen = *size * 3;
|
|
|
|
|
|
|
|
*dest = NULL;
|
|
|
|
while (1) {
|
|
|
|
int srclen = *size;
|
|
|
|
if (dstlen > SIZE_MAX - AV_LZO_OUTPUT_PADDING)
|
|
|
|
goto lzo_fail;
|
|
|
|
*dest = realloc(*dest, dstlen + AV_LZO_OUTPUT_PADDING);
|
|
|
|
result = av_lzo1x_decode(*dest, &dstlen, src, &srclen);
|
|
|
|
if (result == 0)
|
|
|
|
break;
|
|
|
|
if (!(result & AV_LZO_OUTPUT_FULL)) {
|
|
|
|
lzo_fail:
|
|
|
|
mp_tmsg(MSGT_DEMUX, MSGL_WARN,
|
|
|
|
"[mkv] lzo decompression failed.\n");
|
|
|
|
free(*dest);
|
|
|
|
*dest = NULL;
|
|
|
|
return modified;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_DBG2,
|
|
|
|
"[mkv] lzo decompression buffer too small.\n");
|
|
|
|
dstlen *= 2;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
*size = dstlen;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
return modified;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-13 01:26:32 +00:00
|
|
|
static int demux_mkv_read_info(demuxer_t *demuxer)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-03-13 01:26:32 +00:00
|
|
|
mkv_demuxer_t *mkv_d = demuxer->priv;
|
|
|
|
stream_t *s = demuxer->stream;
|
|
|
|
uint64_t length, l;
|
|
|
|
int i;
|
|
|
|
uint64_t tc_scale = 1000000;
|
|
|
|
long double duration = 0.;
|
|
|
|
|
|
|
|
length = ebml_read_length(s, NULL);
|
|
|
|
while (length > 0) {
|
|
|
|
uint32_t id = ebml_read_id(s, &i);
|
|
|
|
length -= i;
|
|
|
|
switch (id) {
|
2004-01-19 19:16:10 +00:00
|
|
|
case MATROSKA_ID_TIMECODESCALE:
|
2009-03-13 01:26:32 +00:00
|
|
|
tc_scale = ebml_read_uint(s, &l);
|
|
|
|
length -= l;
|
|
|
|
if (tc_scale == EBML_UINT_INVALID)
|
|
|
|
return 1;
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V,
|
|
|
|
"[mkv] | + timecode scale: %" PRIu64 "\n", tc_scale);
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MATROSKA_ID_DURATION:
|
2009-03-13 01:26:32 +00:00
|
|
|
duration = ebml_read_float(s, &l);
|
|
|
|
length -= l;
|
|
|
|
if (duration == EBML_FLOAT_INVALID)
|
|
|
|
return 1;
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
|
2009-03-16 21:30:48 +00:00
|
|
|
case MATROSKA_ID_SEGMENTUID:;
|
|
|
|
l = ebml_read_length(s, &i);
|
|
|
|
length -= i;
|
|
|
|
if (l != sizeof(demuxer->matroska_data.segment_uid)) {
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_INFO,
|
2009-12-29 19:06:21 +00:00
|
|
|
"[mkv] segment uid invalid length %" PRIu64 "\n", l);
|
2009-03-16 21:30:48 +00:00
|
|
|
stream_skip(s, l);
|
|
|
|
} else {
|
|
|
|
stream_read(s, demuxer->matroska_data.segment_uid, l);
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + segment uid");
|
|
|
|
for (int i = 0; i < l; i++)
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, " %02x",
|
|
|
|
demuxer->matroska_data.segment_uid[i]);
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "\n");
|
|
|
|
}
|
|
|
|
length -= l;
|
|
|
|
break;
|
|
|
|
|
2004-01-19 19:16:10 +00:00
|
|
|
default:
|
2009-03-13 01:26:32 +00:00
|
|
|
ebml_read_skip(s, &l);
|
|
|
|
length -= l;
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
}
|
2009-03-13 01:26:32 +00:00
|
|
|
mkv_d->tc_scale = tc_scale;
|
|
|
|
mkv_d->duration = duration * tc_scale / 1000000000.0;
|
|
|
|
if (duration)
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + duration: %.3fs\n",
|
|
|
|
mkv_d->duration);
|
|
|
|
|
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2006-10-09 18:28:58 +00:00
|
|
|
/**
|
|
|
|
* \brief free array of kv_content_encoding_t
|
|
|
|
* \param encodings pointer to array
|
|
|
|
* \param numencodings number of encodings in array
|
|
|
|
*/
|
2009-12-29 19:06:21 +00:00
|
|
|
static void demux_mkv_free_encodings(mkv_content_encoding_t *encodings,
|
|
|
|
int numencodings)
|
2006-10-09 18:28:58 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
while (numencodings-- > 0)
|
|
|
|
free(encodings[numencodings].comp_settings);
|
|
|
|
free(encodings);
|
2006-10-09 18:28:58 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static int demux_mkv_read_trackencodings(demuxer_t *demuxer,
|
|
|
|
mkv_track_t *track)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
stream_t *s = demuxer->stream;
|
|
|
|
mkv_content_encoding_t *ce, e;
|
|
|
|
uint64_t len1, len2, length, l;
|
|
|
|
int i, il, n;
|
|
|
|
|
|
|
|
ce = malloc(sizeof(*ce));
|
|
|
|
n = 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
len1 = length = ebml_read_length(s, &il);
|
|
|
|
len1 += il;
|
|
|
|
while (length > 0) {
|
|
|
|
switch (ebml_read_id(s, &il)) {
|
|
|
|
case MATROSKA_ID_CONTENTENCODING:
|
|
|
|
memset(&e, 0, sizeof(e));
|
2004-01-19 19:16:10 +00:00
|
|
|
e.scope = 1;
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
len2 = ebml_read_length(s, &i);
|
|
|
|
l = len2 + i;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
while (len2 > 0) {
|
2004-01-19 19:16:10 +00:00
|
|
|
uint64_t num, l;
|
|
|
|
int il;
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
switch (ebml_read_id(s, &il)) {
|
|
|
|
case MATROSKA_ID_CONTENTENCODINGORDER:
|
|
|
|
num = ebml_read_uint(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
if (num == EBML_UINT_INVALID)
|
2009-12-29 19:06:21 +00:00
|
|
|
goto err_out;
|
2004-01-19 19:16:10 +00:00
|
|
|
e.order = num;
|
|
|
|
break;
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
case MATROSKA_ID_CONTENTENCODINGSCOPE:
|
|
|
|
num = ebml_read_uint(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
if (num == EBML_UINT_INVALID)
|
2009-12-29 19:06:21 +00:00
|
|
|
goto err_out;
|
2004-01-19 19:16:10 +00:00
|
|
|
e.scope = num;
|
|
|
|
break;
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
case MATROSKA_ID_CONTENTENCODINGTYPE:
|
|
|
|
num = ebml_read_uint(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
if (num == EBML_UINT_INVALID)
|
2009-12-29 19:06:21 +00:00
|
|
|
goto err_out;
|
2004-01-19 19:16:10 +00:00
|
|
|
e.type = num;
|
|
|
|
break;
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
case MATROSKA_ID_CONTENTCOMPRESSION:;
|
|
|
|
uint64_t le;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
le = ebml_read_length(s, &i);
|
|
|
|
l = le + i;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
while (le > 0) {
|
|
|
|
uint64_t l;
|
|
|
|
int il;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
switch (ebml_read_id(s, &il)) {
|
|
|
|
case MATROSKA_ID_CONTENTCOMPALGO:
|
|
|
|
num = ebml_read_uint(s, &l);
|
|
|
|
if (num == EBML_UINT_INVALID)
|
2006-10-09 18:28:58 +00:00
|
|
|
goto err_out;
|
2009-12-29 19:06:21 +00:00
|
|
|
e.comp_algo = num;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MATROSKA_ID_CONTENTCOMPSETTINGS:
|
|
|
|
l = ebml_read_length(s, &i);
|
|
|
|
e.comp_settings = malloc(l);
|
|
|
|
stream_read(s, e.comp_settings, l);
|
|
|
|
e.comp_settings_len = l;
|
|
|
|
l += i;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
ebml_read_skip(s, &l);
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
le -= l + il;
|
|
|
|
}
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
if (e.type == 1) {
|
|
|
|
mp_tmsg(MSGT_DEMUX, MSGL_WARN, "[mkv] Track "
|
|
|
|
"number %u has been encrypted and "
|
|
|
|
"decryption has not yet been\n"
|
|
|
|
"[mkv] implemented. Skipping track.\n",
|
|
|
|
track->tnum);
|
|
|
|
} else if (e.type != 0) {
|
|
|
|
mp_tmsg(MSGT_DEMUX, MSGL_WARN,
|
|
|
|
"[mkv] Unknown content encoding type for "
|
|
|
|
"track %u. Skipping track.\n",
|
|
|
|
track->tnum);
|
|
|
|
}
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
if (e.comp_algo != 0 && e.comp_algo != 2) {
|
|
|
|
mp_tmsg(MSGT_DEMUX, MSGL_WARN,
|
|
|
|
"[mkv] Track %u has been compressed with "
|
|
|
|
"an unknown/unsupported compression\n"
|
|
|
|
"[mkv] algorithm (%u). Skipping track.\n",
|
|
|
|
track->tnum, e.comp_algo);
|
|
|
|
}
|
2009-02-07 15:23:55 +00:00
|
|
|
#if !CONFIG_ZLIB
|
2009-12-29 19:06:21 +00:00
|
|
|
else if (e.comp_algo == 0) {
|
|
|
|
mp_tmsg(MSGT_DEMUX, MSGL_WARN,
|
|
|
|
"[mkv] Track %u was compressed with zlib "
|
|
|
|
"but mplayer has not been compiled\n"
|
|
|
|
"[mkv] with support for zlib compression. "
|
|
|
|
"Skipping track.\n",
|
|
|
|
track->tnum);
|
|
|
|
}
|
2004-01-19 19:16:10 +00:00
|
|
|
#endif
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
default:
|
|
|
|
ebml_read_skip(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
2009-12-29 19:06:21 +00:00
|
|
|
}
|
|
|
|
len2 -= l + il;
|
|
|
|
}
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
if (e.order <= ce[i].order)
|
|
|
|
break;
|
|
|
|
ce = realloc(ce, (n + 1) * sizeof(*ce));
|
|
|
|
memmove(ce + i + 1, ce + i, (n - i) * sizeof(*ce));
|
|
|
|
memcpy(ce + i, &e, sizeof(e));
|
2004-01-19 19:16:10 +00:00
|
|
|
n++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2009-12-29 19:06:21 +00:00
|
|
|
ebml_read_skip(s, &l);
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
length -= l + il;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
track->encodings = ce;
|
|
|
|
track->num_encodings = n;
|
|
|
|
return len1;
|
2006-10-09 18:28:58 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
err_out:
|
|
|
|
demux_mkv_free_encodings(ce, n);
|
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static int demux_mkv_read_trackaudio(demuxer_t *demuxer, mkv_track_t *track)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
stream_t *s = demuxer->stream;
|
|
|
|
uint64_t len, length, l;
|
|
|
|
uint64_t num;
|
|
|
|
long double fnum;
|
|
|
|
int il;
|
|
|
|
|
|
|
|
track->a_sfreq = 8000.0;
|
|
|
|
track->a_channels = 1;
|
|
|
|
|
|
|
|
len = length = ebml_read_length(s, &il);
|
|
|
|
len += il;
|
|
|
|
while (length > 0) {
|
|
|
|
switch (ebml_read_id(s, &il)) {
|
2004-01-19 19:16:10 +00:00
|
|
|
case MATROSKA_ID_AUDIOSAMPLINGFREQ:
|
2009-12-29 19:06:21 +00:00
|
|
|
fnum = ebml_read_float(s, &l);
|
|
|
|
if (fnum == EBML_FLOAT_INVALID)
|
|
|
|
return 0;
|
|
|
|
track->a_sfreq = fnum;
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V,
|
|
|
|
"[mkv] | + Sampling frequency: %f\n", track->a_sfreq);
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MATROSKA_ID_AUDIOBITDEPTH:
|
2009-12-29 19:06:21 +00:00
|
|
|
num = ebml_read_uint(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
if (num == EBML_UINT_INVALID)
|
2009-12-29 19:06:21 +00:00
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
track->a_bps = num;
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Bit depth: %u\n",
|
|
|
|
track->a_bps);
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MATROSKA_ID_AUDIOCHANNELS:
|
2009-12-29 19:06:21 +00:00
|
|
|
num = ebml_read_uint(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
if (num == EBML_UINT_INVALID)
|
2009-12-29 19:06:21 +00:00
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
track->a_channels = num;
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Channels: %u\n",
|
|
|
|
track->a_channels);
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2009-12-29 19:06:21 +00:00
|
|
|
ebml_read_skip(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
length -= l + il;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
return len;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static int demux_mkv_read_trackvideo(demuxer_t *demuxer, mkv_track_t *track)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
stream_t *s = demuxer->stream;
|
|
|
|
uint64_t len, length, l;
|
|
|
|
uint64_t num;
|
|
|
|
long double fnum;
|
|
|
|
int il;
|
|
|
|
|
|
|
|
len = length = ebml_read_length(s, &il);
|
|
|
|
len += il;
|
|
|
|
while (length > 0) {
|
|
|
|
switch (ebml_read_id(s, &il)) {
|
2004-01-19 19:16:10 +00:00
|
|
|
case MATROSKA_ID_VIDEOFRAMERATE:
|
2009-12-29 19:06:21 +00:00
|
|
|
fnum = ebml_read_float(s, &l);
|
|
|
|
if (fnum == EBML_FLOAT_INVALID)
|
|
|
|
return 0;
|
|
|
|
track->v_frate = fnum;
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Frame rate: %f\n",
|
|
|
|
track->v_frate);
|
2004-11-28 21:08:46 +00:00
|
|
|
if (track->v_frate > 0)
|
2009-12-29 19:06:21 +00:00
|
|
|
track->default_duration = 1 / track->v_frate;
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MATROSKA_ID_VIDEODISPLAYWIDTH:
|
2009-12-29 19:06:21 +00:00
|
|
|
num = ebml_read_uint(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
if (num == EBML_UINT_INVALID)
|
2009-12-29 19:06:21 +00:00
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
track->v_dwidth = num;
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Display width: %u\n",
|
|
|
|
track->v_dwidth);
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MATROSKA_ID_VIDEODISPLAYHEIGHT:
|
2009-12-29 19:06:21 +00:00
|
|
|
num = ebml_read_uint(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
if (num == EBML_UINT_INVALID)
|
2009-12-29 19:06:21 +00:00
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
track->v_dheight = num;
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Display height: %u\n",
|
|
|
|
track->v_dheight);
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MATROSKA_ID_VIDEOPIXELWIDTH:
|
2009-12-29 19:06:21 +00:00
|
|
|
num = ebml_read_uint(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
if (num == EBML_UINT_INVALID)
|
2009-12-29 19:06:21 +00:00
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
track->v_width = num;
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Pixel width: %u\n",
|
|
|
|
track->v_width);
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MATROSKA_ID_VIDEOPIXELHEIGHT:
|
2009-12-29 19:06:21 +00:00
|
|
|
num = ebml_read_uint(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
if (num == EBML_UINT_INVALID)
|
2009-12-29 19:06:21 +00:00
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
track->v_height = num;
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Pixel height: %u\n",
|
|
|
|
track->v_height);
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2009-12-29 19:06:21 +00:00
|
|
|
ebml_read_skip(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
length -= l + il;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
return len;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2006-10-09 18:48:55 +00:00
|
|
|
/**
|
|
|
|
* \brief free any data associated with given track
|
|
|
|
* \param track track of which to free data
|
|
|
|
*/
|
2009-12-29 19:06:21 +00:00
|
|
|
static void demux_mkv_free_trackentry(mkv_track_t *track)
|
|
|
|
{
|
|
|
|
free(track->name);
|
|
|
|
free(track->codec_id);
|
|
|
|
free(track->language);
|
|
|
|
free(track->private_data);
|
|
|
|
free(track->audio_buf);
|
|
|
|
free(track->audio_timestamp);
|
|
|
|
demux_mkv_free_encodings(track->encodings, track->num_encodings);
|
|
|
|
free(track);
|
2006-10-09 18:48:55 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static int demux_mkv_read_trackentry(demuxer_t *demuxer)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
|
|
|
stream_t *s = demuxer->stream;
|
|
|
|
mkv_track_t *track;
|
|
|
|
uint64_t len, length, l;
|
|
|
|
uint64_t num;
|
|
|
|
int il;
|
|
|
|
|
|
|
|
track = calloc(1, sizeof(*track));
|
|
|
|
/* set default values */
|
|
|
|
track->default_track = 1;
|
|
|
|
track->name = 0;
|
|
|
|
track->language = strdup("eng");
|
|
|
|
|
|
|
|
len = length = ebml_read_length(s, &il);
|
|
|
|
len += il;
|
|
|
|
while (length > 0) {
|
|
|
|
switch (ebml_read_id(s, &il)) {
|
2004-01-19 19:16:10 +00:00
|
|
|
case MATROSKA_ID_TRACKNUMBER:
|
2009-12-29 19:06:21 +00:00
|
|
|
num = ebml_read_uint(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
if (num == EBML_UINT_INVALID)
|
2009-12-29 19:06:21 +00:00
|
|
|
goto err_out;
|
2004-01-19 19:16:10 +00:00
|
|
|
track->tnum = num;
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Track number: %u\n",
|
|
|
|
track->tnum);
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
|
2006-09-02 19:39:24 +00:00
|
|
|
case MATROSKA_ID_TRACKNAME:
|
2009-12-29 19:06:21 +00:00
|
|
|
track->name = ebml_read_utf8(s, &l);
|
2006-09-02 19:39:24 +00:00
|
|
|
if (track->name == NULL)
|
2009-12-29 19:06:21 +00:00
|
|
|
goto err_out;
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Name: %s\n",
|
|
|
|
track->name);
|
2006-09-02 19:39:24 +00:00
|
|
|
break;
|
2009-07-06 23:26:13 +00:00
|
|
|
|
2004-01-19 19:16:10 +00:00
|
|
|
case MATROSKA_ID_TRACKTYPE:
|
2009-12-29 19:06:21 +00:00
|
|
|
num = ebml_read_uint(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
if (num == EBML_UINT_INVALID)
|
2009-12-29 19:06:21 +00:00
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
track->type = num;
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Track type: ");
|
|
|
|
switch (track->type) {
|
|
|
|
case MATROSKA_TRACK_AUDIO:
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "Audio\n");
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
2009-12-29 19:06:21 +00:00
|
|
|
case MATROSKA_TRACK_VIDEO:
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "Video\n");
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
2009-12-29 19:06:21 +00:00
|
|
|
case MATROSKA_TRACK_SUBTITLE:
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "Subtitle\n");
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
2009-12-29 19:06:21 +00:00
|
|
|
default:
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "unknown\n");
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MATROSKA_ID_TRACKAUDIO:
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Audio track\n");
|
|
|
|
l = demux_mkv_read_trackaudio(demuxer, track);
|
|
|
|
if (l == 0)
|
|
|
|
goto err_out;
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
|
|
|
case MATROSKA_ID_TRACKVIDEO:
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Video track\n");
|
|
|
|
l = demux_mkv_read_trackvideo(demuxer, track);
|
|
|
|
if (l == 0)
|
|
|
|
goto err_out;
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
|
|
|
case MATROSKA_ID_CODECID:
|
2009-12-29 19:06:21 +00:00
|
|
|
track->codec_id = ebml_read_ascii(s, &l);
|
|
|
|
if (track->codec_id == NULL)
|
|
|
|
goto err_out;
|
|
|
|
if (!strcmp(track->codec_id, MKV_V_MSCOMP)
|
|
|
|
|| !strcmp(track->codec_id, MKV_A_ACM))
|
|
|
|
track->ms_compat = 1;
|
|
|
|
else if (!strcmp(track->codec_id, MKV_S_VOBSUB))
|
|
|
|
track->subtitle_type = MATROSKA_SUBTYPE_VOBSUB;
|
|
|
|
else if (!strcmp(track->codec_id, MKV_S_TEXTSSA)
|
|
|
|
|| !strcmp(track->codec_id, MKV_S_TEXTASS)
|
|
|
|
|| !strcmp(track->codec_id, MKV_S_SSA)
|
|
|
|
|| !strcmp(track->codec_id, MKV_S_ASS)) {
|
|
|
|
track->subtitle_type = MATROSKA_SUBTYPE_SSA;
|
|
|
|
} else if (!strcmp(track->codec_id, MKV_S_TEXTASCII))
|
|
|
|
track->subtitle_type = MATROSKA_SUBTYPE_TEXT;
|
|
|
|
if (!strcmp(track->codec_id, MKV_S_TEXTUTF8)) {
|
|
|
|
track->subtitle_type = MATROSKA_SUBTYPE_TEXT;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Codec ID: %s\n",
|
|
|
|
track->codec_id);
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
case MATROSKA_ID_CODECPRIVATE:;
|
2004-01-19 19:16:10 +00:00
|
|
|
int x;
|
2009-12-29 19:06:21 +00:00
|
|
|
num = ebml_read_length(s, &x);
|
|
|
|
// audit: cheap guard against overflows later..
|
|
|
|
if (num > SIZE_MAX - 1000)
|
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
l = x + num;
|
2009-12-29 19:06:21 +00:00
|
|
|
track->private_data = malloc(num + AV_LZO_INPUT_PADDING);
|
2004-01-19 19:16:10 +00:00
|
|
|
if (stream_read(s, track->private_data, num) != (int) num)
|
2009-12-29 19:06:21 +00:00
|
|
|
goto err_out;
|
2004-01-19 19:16:10 +00:00
|
|
|
track->private_size = num;
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V,
|
|
|
|
"[mkv] | + CodecPrivate, length " "%u\n",
|
|
|
|
track->private_size);
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MATROSKA_ID_TRACKLANGUAGE:
|
2009-12-29 19:06:21 +00:00
|
|
|
free(track->language);
|
|
|
|
track->language = ebml_read_utf8(s, &l);
|
|
|
|
if (track->language == NULL)
|
|
|
|
goto err_out;
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Language: %s\n",
|
|
|
|
track->language);
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
|
|
|
case MATROSKA_ID_TRACKFLAGDEFAULT:
|
2009-12-29 19:06:21 +00:00
|
|
|
num = ebml_read_uint(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
if (num == EBML_UINT_INVALID)
|
2009-12-29 19:06:21 +00:00
|
|
|
goto err_out;
|
2004-01-19 19:16:10 +00:00
|
|
|
track->default_track = num;
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Default flag: %u\n",
|
|
|
|
track->default_track);
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MATROSKA_ID_TRACKDEFAULTDURATION:
|
2009-12-29 19:06:21 +00:00
|
|
|
num = ebml_read_uint(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
if (num == EBML_UINT_INVALID)
|
2009-12-29 19:06:21 +00:00
|
|
|
goto err_out;
|
2004-01-19 19:16:10 +00:00
|
|
|
if (num == 0)
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V,
|
|
|
|
"[mkv] | + Default duration: 0");
|
|
|
|
else {
|
2004-01-19 19:16:10 +00:00
|
|
|
track->v_frate = 1000000000.0 / num;
|
2004-11-28 21:08:46 +00:00
|
|
|
track->default_duration = num / 1000000000.0;
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V,
|
|
|
|
"[mkv] | + Default duration: "
|
|
|
|
"%.3fms ( = %.3f fps)\n", num / 1000000.0,
|
|
|
|
track->v_frate);
|
|
|
|
}
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MATROSKA_ID_TRACKENCODINGS:
|
2009-12-29 19:06:21 +00:00
|
|
|
l = demux_mkv_read_trackencodings(demuxer, track);
|
|
|
|
if (l == 0)
|
|
|
|
goto err_out;
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
|
|
|
default:
|
2009-12-29 19:06:21 +00:00
|
|
|
ebml_read_skip(s, &l);
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
length -= l + il;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_d->tracks[mkv_d->num_tracks++] = track;
|
|
|
|
return len;
|
2006-10-09 18:48:55 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
err_out:
|
|
|
|
demux_mkv_free_trackentry(track);
|
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static int demux_mkv_read_tracks(demuxer_t *demuxer)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
|
|
|
stream_t *s = demuxer->stream;
|
|
|
|
uint64_t length, l;
|
|
|
|
int il;
|
|
|
|
|
|
|
|
mkv_d->tracks = malloc(sizeof(*mkv_d->tracks));
|
|
|
|
mkv_d->num_tracks = 0;
|
|
|
|
|
|
|
|
length = ebml_read_length(s, NULL);
|
|
|
|
while (length > 0) {
|
|
|
|
switch (ebml_read_id(s, &il)) {
|
2004-01-19 19:16:10 +00:00
|
|
|
case MATROSKA_ID_TRACKENTRY:
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + a track...\n");
|
|
|
|
mkv_d->tracks = realloc(mkv_d->tracks, (mkv_d->num_tracks + 1)
|
|
|
|
* sizeof(*mkv_d->tracks));
|
|
|
|
l = demux_mkv_read_trackentry(demuxer);
|
|
|
|
if (l == 0)
|
|
|
|
return 1;
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
|
|
|
default:
|
2009-12-29 19:06:21 +00:00
|
|
|
ebml_read_skip(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
length -= l + il;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static int demux_mkv_read_cues(demuxer_t *demuxer)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
|
|
|
stream_t *s = demuxer->stream;
|
|
|
|
uint64_t length, l, time, track, pos;
|
|
|
|
off_t off;
|
|
|
|
int i, il;
|
|
|
|
|
2009-12-31 05:05:11 +00:00
|
|
|
if (index_mode == 0 || index_mode == 2) {
|
2009-12-29 19:06:21 +00:00
|
|
|
ebml_read_skip(s, NULL);
|
2004-01-19 19:16:10 +00:00
|
|
|
return 0;
|
2009-12-29 19:06:21 +00:00
|
|
|
}
|
|
|
|
off = stream_tell(s);
|
|
|
|
for (i = 0; i < mkv_d->parsed_cues_num; i++)
|
|
|
|
if (mkv_d->parsed_cues[i] == off) {
|
|
|
|
ebml_read_skip(s, NULL);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
mkv_d->parsed_cues =
|
|
|
|
realloc(mkv_d->parsed_cues, (mkv_d->parsed_cues_num + 1)
|
|
|
|
* sizeof(off_t));
|
|
|
|
mkv_d->parsed_cues[mkv_d->parsed_cues_num++] = off;
|
|
|
|
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] /---- [ parsing cues ] -----------\n");
|
|
|
|
length = ebml_read_length(s, NULL);
|
|
|
|
|
|
|
|
while (length > 0) {
|
|
|
|
time = track = pos = EBML_UINT_INVALID;
|
|
|
|
|
|
|
|
switch (ebml_read_id(s, &il)) {
|
|
|
|
case MATROSKA_ID_POINTENTRY:;
|
2004-01-19 19:16:10 +00:00
|
|
|
uint64_t len;
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
len = ebml_read_length(s, &i);
|
2004-01-19 19:16:10 +00:00
|
|
|
l = len + i;
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
while (len > 0) {
|
2004-01-19 19:16:10 +00:00
|
|
|
uint64_t l;
|
|
|
|
int il;
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
switch (ebml_read_id(s, &il)) {
|
|
|
|
case MATROSKA_ID_CUETIME:
|
|
|
|
time = ebml_read_uint(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
case MATROSKA_ID_CUETRACKPOSITION:;
|
|
|
|
uint64_t le = ebml_read_length(s, &i);
|
|
|
|
l = le + i;
|
|
|
|
|
|
|
|
while (le > 0) {
|
|
|
|
uint64_t l;
|
|
|
|
int il;
|
|
|
|
|
|
|
|
switch (ebml_read_id(s, &il)) {
|
|
|
|
case MATROSKA_ID_CUETRACK:
|
|
|
|
track = ebml_read_uint(s, &l);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MATROSKA_ID_CUECLUSTERPOSITION:
|
|
|
|
pos = ebml_read_uint(s, &l);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
ebml_read_skip(s, &l);
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
le -= l + il;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
default:
|
|
|
|
ebml_read_skip(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
2009-12-29 19:06:21 +00:00
|
|
|
}
|
2004-01-19 19:16:10 +00:00
|
|
|
len -= l + il;
|
2009-12-29 19:06:21 +00:00
|
|
|
}
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2009-12-29 19:06:21 +00:00
|
|
|
ebml_read_skip(s, &l);
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
length -= l + il;
|
|
|
|
|
|
|
|
if (time != EBML_UINT_INVALID && track != EBML_UINT_INVALID
|
|
|
|
&& pos != EBML_UINT_INVALID) {
|
|
|
|
mkv_d->indexes =
|
|
|
|
grow_array(mkv_d->indexes, mkv_d->num_indexes,
|
|
|
|
sizeof(mkv_index_t));
|
|
|
|
mkv_d->indexes[mkv_d->num_indexes].tnum = track;
|
|
|
|
mkv_d->indexes[mkv_d->num_indexes].timecode = time;
|
|
|
|
mkv_d->indexes[mkv_d->num_indexes].filepos =
|
|
|
|
mkv_d->segment_start + pos;
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_DBG2,
|
|
|
|
"[mkv] |+ found cue point " "for track %" PRIu64
|
|
|
|
": timecode %" PRIu64 ", filepos: %" PRIu64 "\n", track,
|
|
|
|
time, mkv_d->segment_start + pos);
|
|
|
|
mkv_d->num_indexes++;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] \\---- [ parsing cues ] -----------\n");
|
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-01 12:28:34 +00:00
|
|
|
static uint64_t read_one_chapter(struct demuxer *demuxer, stream_t *s,
|
|
|
|
struct matroska_chapter *chapters,
|
|
|
|
int chapter_num)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-03-13 01:26:32 +00:00
|
|
|
uint64_t len, l;
|
|
|
|
uint64_t start = 0, end = 0;
|
2009-12-29 19:06:21 +00:00
|
|
|
struct matroska_chapter chapter = { };
|
2009-03-13 01:26:32 +00:00
|
|
|
char *name = 0;
|
|
|
|
int i;
|
|
|
|
uint32_t id;
|
2009-12-01 11:59:38 +00:00
|
|
|
bool badchapter = false;
|
2009-03-13 01:26:32 +00:00
|
|
|
|
|
|
|
len = ebml_read_length(s, &i);
|
|
|
|
uint64_t bytes_read = len + i;
|
|
|
|
|
|
|
|
while (len > 0) {
|
|
|
|
id = ebml_read_id(s, &i);
|
|
|
|
len -= i;
|
|
|
|
switch (id) {
|
|
|
|
case MATROSKA_ID_CHAPTERTIMESTART:
|
|
|
|
start = ebml_read_uint(s, &l) / 1000000;
|
|
|
|
len -= l;
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-03-13 01:26:32 +00:00
|
|
|
case MATROSKA_ID_CHAPTERTIMEEND:
|
|
|
|
end = ebml_read_uint(s, &l) / 1000000;
|
|
|
|
len -= l;
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-03-13 01:26:32 +00:00
|
|
|
case MATROSKA_ID_CHAPTERDISPLAY:;
|
|
|
|
uint64_t displaylen = ebml_read_length(s, &i);
|
|
|
|
len -= displaylen + i;
|
|
|
|
while (displaylen > 0) {
|
|
|
|
id = ebml_read_id(s, &i);
|
|
|
|
displaylen -= i;
|
|
|
|
switch (id) {
|
|
|
|
case MATROSKA_ID_CHAPSTRING:
|
|
|
|
name = ebml_read_utf8(s, &l);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ebml_read_skip(s, &l);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
displaylen -= l;
|
|
|
|
}
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-03-16 21:30:48 +00:00
|
|
|
case MATROSKA_ID_CHAPTERSEGMENTUID:
|
|
|
|
l = ebml_read_length(s, &i);
|
|
|
|
len -= l + i;
|
|
|
|
if (l != sizeof(chapter.segment_uid)) {
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_INFO,
|
2009-12-29 19:06:21 +00:00
|
|
|
"[mkv] chapter segment uid invalid length %" PRIu64
|
|
|
|
"\n", l);
|
2009-03-16 21:30:48 +00:00
|
|
|
stream_skip(s, l);
|
|
|
|
} else {
|
|
|
|
stream_read(s, chapter.segment_uid, l);
|
|
|
|
chapter.has_segment_uid = true;
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Chapter segment uid ");
|
|
|
|
for (int i = 0; i < l; i++)
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "%02x ",
|
|
|
|
chapter.segment_uid[i]);
|
2009-03-16 21:30:48 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "\n");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2009-12-01 11:59:38 +00:00
|
|
|
case MATROSKA_ID_CHAPTERSEGMENTEDITIONUID:
|
|
|
|
mp_tmsg(MSGT_DEMUX, MSGL_WARN,
|
|
|
|
"[mkv] Warning: unsupported edition recursion in chapter; "
|
|
|
|
"will skip on playback!\n");
|
|
|
|
ebml_read_skip(s, &l);
|
|
|
|
len -= l;
|
|
|
|
badchapter = true;
|
|
|
|
break;
|
|
|
|
|
2009-03-13 01:26:32 +00:00
|
|
|
default:
|
|
|
|
ebml_read_skip(s, &l);
|
|
|
|
len -= l;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-03-13 01:26:32 +00:00
|
|
|
if (!name)
|
|
|
|
name = strdup("(unnamed)");
|
|
|
|
|
2009-03-16 21:30:48 +00:00
|
|
|
chapter.start = start;
|
|
|
|
chapter.end = end;
|
2009-12-01 12:28:34 +00:00
|
|
|
chapter.name = talloc_strdup(chapters, name);
|
|
|
|
chapters[chapter_num] = chapter;
|
2009-03-13 01:26:32 +00:00
|
|
|
|
2009-12-01 11:59:38 +00:00
|
|
|
if (badchapter) {
|
|
|
|
memset(&chapter.segment_uid, 0, sizeof(chapter.segment_uid));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V,
|
|
|
|
"[mkv] Chapter %u from %02d:%02d:%02d."
|
|
|
|
"%03d to %02d:%02d:%02d.%03d, %s\n", chapter_num,
|
|
|
|
(int) (start / 60 / 60 / 1000), (int) ((start / 60 / 1000) % 60),
|
|
|
|
(int) ((start / 1000) % 60), (int) (start % 1000),
|
|
|
|
(int) (end / 60 / 60 / 1000), (int) ((end / 60 / 1000) % 60),
|
|
|
|
(int) ((end / 1000) % 60), (int) (end % 1000), name);
|
|
|
|
|
|
|
|
cleanup:
|
2009-03-13 01:26:32 +00:00
|
|
|
free(name);
|
|
|
|
return bytes_read;
|
|
|
|
}
|
2006-08-06 18:55:34 +00:00
|
|
|
|
2009-03-13 01:26:32 +00:00
|
|
|
static int demux_mkv_read_chapters(struct demuxer *demuxer)
|
|
|
|
{
|
2009-12-01 12:28:34 +00:00
|
|
|
struct MPOpts *opts = demuxer->opts;
|
2009-03-13 01:26:32 +00:00
|
|
|
stream_t *s = demuxer->stream;
|
|
|
|
uint64_t length, l;
|
|
|
|
int i;
|
|
|
|
uint32_t id;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-03-13 01:26:32 +00:00
|
|
|
if (demuxer->chapters) {
|
|
|
|
ebml_read_skip(s, NULL);
|
|
|
|
return 0;
|
|
|
|
}
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-03-13 01:26:32 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] /---- [ parsing chapters ] ---------\n");
|
|
|
|
length = ebml_read_length(s, NULL);
|
|
|
|
|
2009-12-01 12:28:34 +00:00
|
|
|
struct matroska_chapter *selected_chapters = NULL;
|
|
|
|
int num_selected_chapters = 0;
|
|
|
|
bool have_default = false;
|
|
|
|
bool have_user_specified = false;
|
|
|
|
int selected_edition = -1;
|
|
|
|
bool se_is_ordered = false;
|
|
|
|
int cur_idx = -1;
|
2009-03-13 01:26:32 +00:00
|
|
|
while (length > 0) {
|
|
|
|
id = ebml_read_id(s, &i);
|
|
|
|
length -= i;
|
|
|
|
switch (id) {
|
2009-03-16 21:30:48 +00:00
|
|
|
case MATROSKA_ID_EDITIONENTRY:
|
2009-12-01 12:28:34 +00:00
|
|
|
cur_idx++;
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] New edition %d\n", cur_idx);
|
2009-03-13 01:26:32 +00:00
|
|
|
uint64_t editionlen = ebml_read_length(s, &i);
|
|
|
|
length -= editionlen + i;
|
2009-12-01 12:28:34 +00:00
|
|
|
bool defaultflag = false;
|
2009-03-16 21:30:48 +00:00
|
|
|
bool ordered = false;
|
2009-12-01 12:28:34 +00:00
|
|
|
struct matroska_chapter *chapters = NULL;
|
|
|
|
int num_chapters = 0;
|
2009-03-13 01:26:32 +00:00
|
|
|
while (editionlen > 0) {
|
|
|
|
id = ebml_read_id(s, &i);
|
|
|
|
editionlen -= i;
|
|
|
|
switch (id) {
|
|
|
|
case MATROSKA_ID_CHAPTERATOM:
|
2009-12-29 19:06:21 +00:00
|
|
|
chapters =
|
|
|
|
talloc_realloc(demuxer, chapters,
|
|
|
|
struct matroska_chapter,
|
|
|
|
num_chapters + 1);
|
2009-12-01 12:28:34 +00:00
|
|
|
l = read_one_chapter(demuxer, s, chapters, num_chapters++);
|
|
|
|
break;
|
|
|
|
case MATROSKA_ID_EDITIONFLAGDEFAULT:
|
|
|
|
defaultflag = ebml_read_uint(s, &l);
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V,
|
|
|
|
"[mkv] Default edition flag: %d\n", defaultflag);
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
2009-03-16 21:30:48 +00:00
|
|
|
case MATROSKA_ID_EDITIONFLAGORDERED:
|
|
|
|
ordered = ebml_read_uint(s, &l);
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V,
|
|
|
|
"[mkv] Ordered chapter flag: %d\n", ordered);
|
|
|
|
break;
|
|
|
|
|
2009-03-13 01:26:32 +00:00
|
|
|
default:
|
|
|
|
ebml_read_skip(s, &l);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
editionlen -= l;
|
|
|
|
}
|
2009-12-01 12:28:34 +00:00
|
|
|
if (cur_idx == opts->edition_id) {
|
|
|
|
have_user_specified = true;
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V,
|
|
|
|
"[mkv] Found user-selected edition\n");
|
|
|
|
} else if (!have_user_specified && !have_default && defaultflag) {
|
|
|
|
have_default = true;
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Default edition: %d\n",
|
|
|
|
cur_idx);
|
|
|
|
} else if (selected_edition < 0) {
|
|
|
|
;
|
|
|
|
} else {
|
|
|
|
talloc_free(chapters);
|
|
|
|
break;
|
2009-03-16 21:30:48 +00:00
|
|
|
}
|
2009-12-01 12:28:34 +00:00
|
|
|
selected_edition = cur_idx;
|
|
|
|
talloc_free(selected_chapters);
|
|
|
|
selected_chapters = chapters;
|
|
|
|
num_selected_chapters = num_chapters;
|
|
|
|
se_is_ordered = ordered;
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2009-03-13 01:26:32 +00:00
|
|
|
ebml_read_skip(s, &l);
|
|
|
|
length -= l;
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
}
|
2009-12-01 12:28:34 +00:00
|
|
|
if (cur_idx > 0)
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_INFO,
|
|
|
|
"[mkv] Found %d editions, will play #%d (first is 0).\n",
|
|
|
|
cur_idx + 1, selected_edition);
|
|
|
|
|
|
|
|
for (i = 0; i < num_selected_chapters; i++)
|
|
|
|
demuxer_add_chapter(demuxer, selected_chapters[i].name,
|
|
|
|
selected_chapters[i].start,
|
|
|
|
selected_chapters[i].end);
|
|
|
|
struct matroska_data *m = &demuxer->matroska_data;
|
|
|
|
talloc_free(m->ordered_chapters);
|
|
|
|
if (se_is_ordered) {
|
|
|
|
m->ordered_chapters = selected_chapters;
|
|
|
|
m->num_ordered_chapters = num_selected_chapters;
|
|
|
|
} else {
|
|
|
|
m->ordered_chapters = NULL;
|
|
|
|
m->num_ordered_chapters = 0;
|
|
|
|
talloc_free(selected_chapters);
|
|
|
|
}
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V,
|
|
|
|
"[mkv] \\---- [ parsing chapters ] ---------\n");
|
2009-03-13 01:26:32 +00:00
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static int demux_mkv_read_tags(demuxer_t *demuxer)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
ebml_read_skip(demuxer->stream, NULL);
|
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static int demux_mkv_read_attachments(demuxer_t *demuxer)
|
2006-07-07 18:26:51 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
stream_t *s = demuxer->stream;
|
|
|
|
uint64_t length, l;
|
|
|
|
int il;
|
|
|
|
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V,
|
|
|
|
"[mkv] /---- [ parsing attachments ] ---------\n");
|
|
|
|
length = ebml_read_length(s, NULL);
|
|
|
|
|
|
|
|
while (length > 0) {
|
|
|
|
switch (ebml_read_id(s, &il)) {
|
|
|
|
case MATROSKA_ID_ATTACHEDFILE:;
|
|
|
|
uint64_t len;
|
|
|
|
int i;
|
|
|
|
char *name = NULL;
|
|
|
|
char *mime = NULL;
|
|
|
|
char *data = NULL;
|
|
|
|
int data_size = 0;
|
|
|
|
|
|
|
|
len = ebml_read_length(s, &i);
|
|
|
|
l = len + i;
|
|
|
|
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + an attachment...\n");
|
|
|
|
|
|
|
|
while (len > 0) {
|
|
|
|
uint64_t l;
|
|
|
|
int il;
|
|
|
|
|
|
|
|
switch (ebml_read_id(s, &il)) {
|
|
|
|
case MATROSKA_ID_FILENAME:
|
|
|
|
free(name);
|
|
|
|
name = ebml_read_utf8(s, &l);
|
|
|
|
if (name == NULL)
|
|
|
|
goto error;
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + FileName: %s\n",
|
|
|
|
name);
|
|
|
|
break;
|
2006-07-07 18:26:51 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
case MATROSKA_ID_FILEMIMETYPE:
|
|
|
|
free(mime);
|
|
|
|
mime = ebml_read_ascii(s, &l);
|
|
|
|
if (mime == NULL)
|
|
|
|
goto error;
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V,
|
|
|
|
"[mkv] | + FileMimeType: %s\n", mime);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MATROSKA_ID_FILEDATA:;
|
|
|
|
int x;
|
|
|
|
uint64_t num = ebml_read_length(s, &x);
|
|
|
|
l = x + num;
|
|
|
|
free(data);
|
|
|
|
data = malloc(num);
|
|
|
|
if (stream_read(s, data, num) != (int) num) {
|
|
|
|
error:
|
|
|
|
free(data);
|
|
|
|
free(mime);
|
|
|
|
free(name);
|
|
|
|
return 0;
|
2006-07-07 18:26:51 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
data_size = num;
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V,
|
|
|
|
"[mkv] | + FileData, length " "%u\n",
|
|
|
|
data_size);
|
|
|
|
break;
|
2006-07-07 18:26:51 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
default:
|
|
|
|
ebml_read_skip(s, &l);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
len -= l + il;
|
2006-07-07 18:26:51 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
demuxer_add_attachment(demuxer, name, mime, data, data_size);
|
|
|
|
free(data);
|
|
|
|
free(mime);
|
|
|
|
free(name);
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V,
|
|
|
|
"[mkv] Attachment: %s, %s, %u bytes\n", name, mime,
|
|
|
|
data_size);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
ebml_read_skip(s, &l);
|
2006-07-07 18:26:51 +00:00
|
|
|
break;
|
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
length -= l + il;
|
2006-07-07 18:26:51 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V,
|
|
|
|
"[mkv] \\---- [ parsing attachments ] ---------\n");
|
|
|
|
return 0;
|
2006-07-07 18:26:51 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static int demux_mkv_read_seekhead(demuxer_t *demuxer)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
|
|
|
stream_t *s = demuxer->stream;
|
|
|
|
uint64_t length, l, seek_pos, saved_pos, num;
|
|
|
|
uint32_t seek_id;
|
|
|
|
int i, il, res = 0;
|
|
|
|
off_t off;
|
|
|
|
|
|
|
|
off = stream_tell(s);
|
|
|
|
for (i = 0; i < mkv_d->parsed_seekhead_num; i++)
|
|
|
|
if (mkv_d->parsed_seekhead[i] == off) {
|
|
|
|
ebml_read_skip(s, NULL);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
mkv_d->parsed_seekhead = realloc(mkv_d->parsed_seekhead,
|
|
|
|
(mkv_d->parsed_seekhead_num + 1) * sizeof(off_t));
|
|
|
|
mkv_d->parsed_seekhead[mkv_d->parsed_seekhead_num++] = off;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V,
|
|
|
|
"[mkv] /---- [ parsing seek head ] ---------\n");
|
|
|
|
length = ebml_read_length(s, NULL);
|
|
|
|
/* off now holds the position of the next element after the seek head. */
|
|
|
|
off = stream_tell(s) + length;
|
|
|
|
while (length > 0 && !res) {
|
|
|
|
|
|
|
|
seek_id = 0;
|
|
|
|
seek_pos = EBML_UINT_INVALID;
|
|
|
|
|
|
|
|
switch (ebml_read_id(s, &il)) {
|
|
|
|
case MATROSKA_ID_SEEKENTRY:;
|
|
|
|
uint64_t len = ebml_read_length(s, &i);
|
2004-01-19 19:16:10 +00:00
|
|
|
l = len + i;
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
while (len > 0) {
|
2004-01-19 19:16:10 +00:00
|
|
|
uint64_t l;
|
|
|
|
int il;
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
switch (ebml_read_id(s, &il)) {
|
|
|
|
case MATROSKA_ID_SEEKID:
|
|
|
|
num = ebml_read_uint(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
if (num != EBML_UINT_INVALID)
|
2009-12-29 19:06:21 +00:00
|
|
|
seek_id = num;
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
case MATROSKA_ID_SEEKPOSITION:
|
|
|
|
seek_pos = ebml_read_uint(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
default:
|
|
|
|
ebml_read_skip(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
2009-12-29 19:06:21 +00:00
|
|
|
}
|
2004-01-19 19:16:10 +00:00
|
|
|
len -= l + il;
|
2009-12-29 19:06:21 +00:00
|
|
|
}
|
2004-01-19 19:16:10 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2009-12-29 19:06:21 +00:00
|
|
|
ebml_read_skip(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
length -= l + il;
|
|
|
|
|
|
|
|
if (seek_id == 0 || seek_id == MATROSKA_ID_CLUSTER
|
|
|
|
|| seek_pos == EBML_UINT_INVALID
|
|
|
|
|| ((mkv_d->segment_start + seek_pos) >=
|
|
|
|
(uint64_t) demuxer->movi_end))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
saved_pos = stream_tell(s);
|
|
|
|
if (!stream_seek(s, mkv_d->segment_start + seek_pos))
|
2004-01-19 19:16:10 +00:00
|
|
|
res = 1;
|
2009-12-29 19:06:21 +00:00
|
|
|
else {
|
|
|
|
if (ebml_read_id(s, &il) != seek_id)
|
|
|
|
res = 1;
|
|
|
|
else
|
|
|
|
switch (seek_id) {
|
|
|
|
case MATROSKA_ID_CUES:
|
|
|
|
if (demux_mkv_read_cues(demuxer))
|
|
|
|
res = 1;
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
case MATROSKA_ID_TAGS:
|
|
|
|
if (demux_mkv_read_tags(demuxer))
|
|
|
|
res = 1;
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
case MATROSKA_ID_SEEKHEAD:
|
|
|
|
if (demux_mkv_read_seekhead(demuxer))
|
|
|
|
res = 1;
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
case MATROSKA_ID_CHAPTERS:
|
|
|
|
if (demux_mkv_read_chapters(demuxer))
|
|
|
|
res = 1;
|
|
|
|
break;
|
|
|
|
}
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
stream_seek(s, saved_pos);
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
if (res) {
|
|
|
|
/* If there was an error then try to skip this seek head. */
|
|
|
|
if (stream_seek(s, off))
|
|
|
|
res = 0;
|
|
|
|
} else if (length > 0)
|
|
|
|
stream_seek(s, stream_tell(s) + length);
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V,
|
|
|
|
"[mkv] \\---- [ parsing seek head ] ---------\n");
|
|
|
|
return res;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track,
|
|
|
|
int vid);
|
|
|
|
static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track,
|
|
|
|
int aid);
|
|
|
|
static int demux_mkv_open_sub(demuxer_t *demuxer, mkv_track_t *track,
|
|
|
|
int sid);
|
2006-08-26 19:17:04 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static void display_create_tracks(demuxer_t *demuxer)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
|
|
|
int i, vid = 0, aid = 0, sid = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < mkv_d->num_tracks; i++) {
|
|
|
|
char *type = "unknown", str[32];
|
|
|
|
*str = '\0';
|
|
|
|
switch (mkv_d->tracks[i]->type) {
|
2004-01-19 19:16:10 +00:00
|
|
|
case MATROSKA_TRACK_VIDEO:
|
2009-12-29 19:06:21 +00:00
|
|
|
type = "video";
|
|
|
|
demux_mkv_open_video(demuxer, mkv_d->tracks[i], vid);
|
|
|
|
if (mkv_d->tracks[i]->name)
|
|
|
|
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VID_%d_NAME=%s\n", vid,
|
|
|
|
mkv_d->tracks[i]->name);
|
|
|
|
sprintf(str, "-vid %u", vid++);
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
case MATROSKA_TRACK_AUDIO:
|
2009-12-29 19:06:21 +00:00
|
|
|
type = "audio";
|
|
|
|
demux_mkv_open_audio(demuxer, mkv_d->tracks[i], aid);
|
|
|
|
if (mkv_d->tracks[i]->name)
|
|
|
|
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AID_%d_NAME=%s\n", aid,
|
|
|
|
mkv_d->tracks[i]->name);
|
|
|
|
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AID_%d_LANG=%s\n", aid,
|
|
|
|
mkv_d->tracks[i]->language);
|
|
|
|
sprintf(str, "-aid %u, -alang %.5s", aid++,
|
|
|
|
mkv_d->tracks[i]->language);
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
case MATROSKA_TRACK_SUBTITLE:
|
2009-12-29 19:06:21 +00:00
|
|
|
type = "subtitles";
|
|
|
|
demux_mkv_open_sub(demuxer, mkv_d->tracks[i], sid);
|
|
|
|
if (mkv_d->tracks[i]->name)
|
|
|
|
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_SID_%d_NAME=%s\n", sid,
|
|
|
|
mkv_d->tracks[i]->name);
|
|
|
|
mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_SID_%d_LANG=%s\n", sid,
|
|
|
|
mkv_d->tracks[i]->language);
|
|
|
|
sprintf(str, "-sid %u, -slang %.5s", sid++,
|
|
|
|
mkv_d->tracks[i]->language);
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
if (mkv_d->tracks[i]->name)
|
|
|
|
mp_tmsg(MSGT_DEMUX, MSGL_INFO,
|
|
|
|
"[mkv] Track ID %u: %s (%s) \"%s\", %s\n",
|
|
|
|
mkv_d->tracks[i]->tnum, type, mkv_d->tracks[i]->codec_id,
|
|
|
|
mkv_d->tracks[i]->name, str);
|
|
|
|
else
|
|
|
|
mp_tmsg(MSGT_DEMUX, MSGL_INFO, "[mkv] Track ID %u: %s (%s), %s\n",
|
|
|
|
mkv_d->tracks[i]->tnum, type, mkv_d->tracks[i]->codec_id,
|
|
|
|
str);
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-10 13:58:57 +00:00
|
|
|
typedef struct {
|
2009-12-29 19:06:21 +00:00
|
|
|
char *id;
|
|
|
|
int fourcc;
|
|
|
|
int extradata;
|
2007-05-10 13:58:57 +00:00
|
|
|
} videocodec_info_t;
|
|
|
|
|
|
|
|
static const videocodec_info_t vinfo[] = {
|
2009-12-29 19:06:21 +00:00
|
|
|
{MKV_V_MPEG1, mmioFOURCC('m', 'p', 'g', '1'), 0},
|
|
|
|
{MKV_V_MPEG2, mmioFOURCC('m', 'p', 'g', '2'), 0},
|
|
|
|
{MKV_V_MPEG4_SP, mmioFOURCC('m', 'p', '4', 'v'), 1},
|
|
|
|
{MKV_V_MPEG4_ASP, mmioFOURCC('m', 'p', '4', 'v'), 1},
|
|
|
|
{MKV_V_MPEG4_AP, mmioFOURCC('m', 'p', '4', 'v'), 1},
|
|
|
|
{MKV_V_MPEG4_AVC, mmioFOURCC('a', 'v', 'c', '1'), 1},
|
|
|
|
{MKV_V_THEORA, mmioFOURCC('t', 'h', 'e', 'o'), 1},
|
|
|
|
{NULL, 0, 0}
|
2007-05-10 13:58:57 +00:00
|
|
|
};
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track,
|
|
|
|
int vid)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
struct MPOpts *opts = demuxer->opts;
|
|
|
|
BITMAPINFOHEADER *bih;
|
|
|
|
void *ImageDesc = NULL;
|
|
|
|
sh_video_t *sh_v;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
if (track->ms_compat) { /* MS compatibility mode */
|
|
|
|
BITMAPINFOHEADER *src;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
if (track->private_data == NULL
|
|
|
|
|| track->private_size < sizeof(BITMAPINFOHEADER))
|
|
|
|
return 1;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
src = (BITMAPINFOHEADER *) track->private_data;
|
|
|
|
bih = calloc(1, track->private_size);
|
|
|
|
bih->biSize = le2me_32(src->biSize);
|
|
|
|
bih->biWidth = le2me_32(src->biWidth);
|
|
|
|
bih->biHeight = le2me_32(src->biHeight);
|
|
|
|
bih->biPlanes = le2me_16(src->biPlanes);
|
|
|
|
bih->biBitCount = le2me_16(src->biBitCount);
|
|
|
|
bih->biCompression = le2me_32(src->biCompression);
|
|
|
|
bih->biSizeImage = le2me_32(src->biSizeImage);
|
|
|
|
bih->biXPelsPerMeter = le2me_32(src->biXPelsPerMeter);
|
|
|
|
bih->biYPelsPerMeter = le2me_32(src->biYPelsPerMeter);
|
|
|
|
bih->biClrUsed = le2me_32(src->biClrUsed);
|
|
|
|
bih->biClrImportant = le2me_32(src->biClrImportant);
|
|
|
|
memcpy((char *) bih + sizeof(BITMAPINFOHEADER),
|
|
|
|
(char *) src + sizeof(BITMAPINFOHEADER),
|
|
|
|
track->private_size - sizeof(BITMAPINFOHEADER));
|
|
|
|
|
|
|
|
if (track->v_width == 0)
|
|
|
|
track->v_width = bih->biWidth;
|
|
|
|
if (track->v_height == 0)
|
|
|
|
track->v_height = bih->biHeight;
|
|
|
|
} else {
|
|
|
|
bih = calloc(1, sizeof(BITMAPINFOHEADER));
|
|
|
|
bih->biSize = sizeof(BITMAPINFOHEADER);
|
|
|
|
bih->biWidth = track->v_width;
|
|
|
|
bih->biHeight = track->v_height;
|
|
|
|
bih->biBitCount = 24;
|
|
|
|
bih->biSizeImage = bih->biWidth * bih->biHeight * bih->biBitCount / 8;
|
|
|
|
|
|
|
|
if (track->private_size >= RVPROPERTIES_SIZE
|
|
|
|
&& (!strcmp(track->codec_id, MKV_V_REALV10)
|
|
|
|
|| !strcmp(track->codec_id, MKV_V_REALV20)
|
|
|
|
|| !strcmp(track->codec_id, MKV_V_REALV30)
|
|
|
|
|| !strcmp(track->codec_id, MKV_V_REALV40))) {
|
|
|
|
unsigned char *dst, *src;
|
|
|
|
uint32_t type2;
|
|
|
|
unsigned int cnt;
|
|
|
|
|
|
|
|
src = (uint8_t *) track->private_data + RVPROPERTIES_SIZE;
|
|
|
|
|
|
|
|
cnt = track->private_size - RVPROPERTIES_SIZE;
|
|
|
|
bih = realloc(bih, sizeof(BITMAPINFOHEADER) + 8 + cnt);
|
|
|
|
bih->biSize = 48 + cnt;
|
|
|
|
bih->biPlanes = 1;
|
|
|
|
type2 = AV_RB32(src - 4);
|
|
|
|
if (type2 == 0x10003000 || type2 == 0x10003001)
|
|
|
|
bih->biCompression = mmioFOURCC('R', 'V', '1', '3');
|
|
|
|
else
|
|
|
|
bih->biCompression =
|
|
|
|
mmioFOURCC('R', 'V', track->codec_id[9], '0');
|
|
|
|
dst = (unsigned char *) (bih + 1);
|
|
|
|
// copy type1 and type2 info from rv properties
|
|
|
|
memcpy(dst, src - 8, 8);
|
|
|
|
stream_read(demuxer->stream, dst + 8, cnt);
|
|
|
|
track->realmedia = 1;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2008-07-30 12:01:30 +00:00
|
|
|
#ifdef CONFIG_QTX_CODECS
|
2009-12-29 19:06:21 +00:00
|
|
|
} else if (track->private_size >= sizeof(ImageDescription)
|
|
|
|
&& !strcmp(track->codec_id, MKV_V_QUICKTIME)) {
|
|
|
|
ImageDescriptionPtr idesc;
|
|
|
|
|
|
|
|
idesc = (ImageDescriptionPtr) track->private_data;
|
|
|
|
idesc->idSize = be2me_32(idesc->idSize);
|
|
|
|
idesc->cType = be2me_32(idesc->cType);
|
|
|
|
idesc->version = be2me_16(idesc->version);
|
|
|
|
idesc->revisionLevel = be2me_16(idesc->revisionLevel);
|
|
|
|
idesc->vendor = be2me_32(idesc->vendor);
|
|
|
|
idesc->temporalQuality = be2me_32(idesc->temporalQuality);
|
|
|
|
idesc->spatialQuality = be2me_32(idesc->spatialQuality);
|
|
|
|
idesc->width = be2me_16(idesc->width);
|
|
|
|
idesc->height = be2me_16(idesc->height);
|
|
|
|
idesc->hRes = be2me_32(idesc->hRes);
|
|
|
|
idesc->vRes = be2me_32(idesc->vRes);
|
|
|
|
idesc->dataSize = be2me_32(idesc->dataSize);
|
|
|
|
idesc->frameCount = be2me_16(idesc->frameCount);
|
|
|
|
idesc->depth = be2me_16(idesc->depth);
|
|
|
|
idesc->clutID = be2me_16(idesc->clutID);
|
|
|
|
bih->biPlanes = 1;
|
|
|
|
bih->biCompression = idesc->cType;
|
|
|
|
ImageDesc = idesc;
|
|
|
|
#endif /* CONFIG_QTX_CODECS */
|
|
|
|
|
|
|
|
} else {
|
|
|
|
const videocodec_info_t *vi = vinfo;
|
|
|
|
while (vi->id && strcmp(vi->id, track->codec_id))
|
|
|
|
vi++;
|
|
|
|
bih->biCompression = vi->fourcc;
|
|
|
|
if (vi->extradata && track->private_data
|
|
|
|
&& (track->private_size > 0)) {
|
|
|
|
bih->biSize += track->private_size;
|
|
|
|
bih = realloc(bih, bih->biSize);
|
|
|
|
memcpy(bih + 1, track->private_data, track->private_size);
|
|
|
|
}
|
|
|
|
track->reorder_timecodes = opts->user_correct_pts == 0;
|
|
|
|
if (!vi->id) {
|
|
|
|
mp_tmsg(MSGT_DEMUX, MSGL_WARN, "[mkv] Unknown/unsupported "
|
|
|
|
"CodecID (%s) or missing/bad CodecPrivate\n"
|
|
|
|
"[mkv] data (track %u).\n",
|
|
|
|
track->codec_id, track->tnum);
|
|
|
|
free(bih);
|
|
|
|
return 1;
|
2005-01-11 08:30:56 +00:00
|
|
|
}
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
sh_v = new_sh_video_vid(demuxer, track->tnum, vid);
|
|
|
|
sh_v->bih = bih;
|
|
|
|
sh_v->format = sh_v->bih->biCompression;
|
|
|
|
if (track->v_frate == 0.0)
|
|
|
|
track->v_frate = 25.0;
|
|
|
|
sh_v->fps = track->v_frate;
|
|
|
|
sh_v->frametime = 1 / track->v_frate;
|
|
|
|
sh_v->aspect = 0;
|
|
|
|
if (!track->realmedia) {
|
|
|
|
sh_v->disp_w = track->v_width;
|
|
|
|
sh_v->disp_h = track->v_height;
|
|
|
|
if (track->v_dheight)
|
|
|
|
sh_v->aspect = (double) track->v_dwidth / track->v_dheight;
|
|
|
|
} else {
|
|
|
|
// vd_realvid.c will set aspect to disp_w/disp_h and rederive
|
|
|
|
// disp_w and disp_h from the RealVideo stream contents returned
|
|
|
|
// by the Real DLLs. If DisplayWidth/DisplayHeight was not set in
|
|
|
|
// the Matroska file then it has already been set to PixelWidth/Height
|
|
|
|
// by check_track_information.
|
|
|
|
sh_v->disp_w = track->v_dwidth;
|
|
|
|
sh_v->disp_h = track->v_dheight;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
sh_v->ImageDesc = ImageDesc;
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Aspect: %f\n", sh_v->aspect);
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
sh_v->ds = demuxer->video;
|
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track,
|
|
|
|
int aid)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
|
|
|
sh_audio_t *sh_a = new_sh_audio_aid(demuxer, track->tnum, aid);
|
|
|
|
if (!sh_a)
|
|
|
|
return 1;
|
|
|
|
mkv_d->audio_tracks[mkv_d->last_aid] = track->tnum;
|
|
|
|
|
|
|
|
if (track->language && (strcmp(track->language, "und") != 0))
|
|
|
|
sh_a->lang = strdup(track->language);
|
|
|
|
sh_a->default_track = track->default_track;
|
|
|
|
sh_a->ds = demuxer->audio;
|
|
|
|
sh_a->wf = malloc(sizeof(WAVEFORMATEX));
|
|
|
|
if (track->ms_compat && (track->private_size >= sizeof(WAVEFORMATEX))) {
|
|
|
|
WAVEFORMATEX *wf = (WAVEFORMATEX *) track->private_data;
|
|
|
|
sh_a->wf = realloc(sh_a->wf, track->private_size);
|
|
|
|
sh_a->wf->wFormatTag = le2me_16(wf->wFormatTag);
|
|
|
|
sh_a->wf->nChannels = le2me_16(wf->nChannels);
|
|
|
|
sh_a->wf->nSamplesPerSec = le2me_32(wf->nSamplesPerSec);
|
|
|
|
sh_a->wf->nAvgBytesPerSec = le2me_32(wf->nAvgBytesPerSec);
|
|
|
|
sh_a->wf->nBlockAlign = le2me_16(wf->nBlockAlign);
|
|
|
|
sh_a->wf->wBitsPerSample = le2me_16(wf->wBitsPerSample);
|
|
|
|
sh_a->wf->cbSize = track->private_size - sizeof(WAVEFORMATEX);
|
|
|
|
memcpy(sh_a->wf + 1, wf + 1,
|
|
|
|
track->private_size - sizeof(WAVEFORMATEX));
|
|
|
|
if (track->a_sfreq == 0.0)
|
|
|
|
track->a_sfreq = sh_a->wf->nSamplesPerSec;
|
|
|
|
if (track->a_channels == 0)
|
|
|
|
track->a_channels = sh_a->wf->nChannels;
|
|
|
|
if (track->a_bps == 0)
|
|
|
|
track->a_bps = sh_a->wf->wBitsPerSample;
|
|
|
|
track->a_formattag = sh_a->wf->wFormatTag;
|
|
|
|
} else {
|
|
|
|
memset(sh_a->wf, 0, sizeof(WAVEFORMATEX));
|
|
|
|
if (!strcmp(track->codec_id, MKV_A_MP3)
|
|
|
|
|| !strcmp(track->codec_id, MKV_A_MP2))
|
|
|
|
track->a_formattag = 0x0055;
|
|
|
|
else if (!strncmp(track->codec_id, MKV_A_AC3, strlen(MKV_A_AC3)))
|
|
|
|
track->a_formattag = 0x2000;
|
|
|
|
else if (!strcmp(track->codec_id, MKV_A_DTS))
|
|
|
|
track->a_formattag = 0x2001;
|
|
|
|
else if (!strcmp(track->codec_id, MKV_A_PCM)
|
|
|
|
|| !strcmp(track->codec_id, MKV_A_PCM_BE))
|
|
|
|
track->a_formattag = 0x0001;
|
|
|
|
else if (!strcmp(track->codec_id, MKV_A_AAC_2MAIN)
|
|
|
|
|| !strncmp(track->codec_id, MKV_A_AAC_2LC,
|
|
|
|
strlen(MKV_A_AAC_2LC))
|
|
|
|
|| !strcmp(track->codec_id, MKV_A_AAC_2SSR)
|
|
|
|
|| !strcmp(track->codec_id, MKV_A_AAC_4MAIN)
|
|
|
|
|| !strncmp(track->codec_id, MKV_A_AAC_4LC,
|
|
|
|
strlen(MKV_A_AAC_4LC))
|
|
|
|
|| !strcmp(track->codec_id, MKV_A_AAC_4SSR)
|
|
|
|
|| !strcmp(track->codec_id, MKV_A_AAC_4LTP)
|
|
|
|
|| !strcmp(track->codec_id, MKV_A_AAC))
|
|
|
|
track->a_formattag = mmioFOURCC('M', 'P', '4', 'A');
|
|
|
|
else if (!strcmp(track->codec_id, MKV_A_VORBIS)) {
|
|
|
|
if (track->private_data == NULL)
|
|
|
|
return 1;
|
|
|
|
track->a_formattag = mmioFOURCC('v', 'r', 'b', 's');
|
|
|
|
} else if (!strcmp(track->codec_id, MKV_A_QDMC))
|
|
|
|
track->a_formattag = mmioFOURCC('Q', 'D', 'M', 'C');
|
|
|
|
else if (!strcmp(track->codec_id, MKV_A_QDMC2))
|
|
|
|
track->a_formattag = mmioFOURCC('Q', 'D', 'M', '2');
|
|
|
|
else if (!strcmp(track->codec_id, MKV_A_WAVPACK))
|
|
|
|
track->a_formattag = mmioFOURCC('W', 'V', 'P', 'K');
|
|
|
|
else if (!strcmp(track->codec_id, MKV_A_TRUEHD))
|
|
|
|
track->a_formattag = mmioFOURCC('T', 'R', 'H', 'D');
|
|
|
|
else if (!strcmp(track->codec_id, MKV_A_FLAC)) {
|
|
|
|
if (track->private_data == NULL || track->private_size == 0) {
|
|
|
|
mp_tmsg(MSGT_DEMUX, MSGL_WARN,
|
|
|
|
"[mkv] FLAC track does not contain valid headers.\n");
|
|
|
|
return 1;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
track->a_formattag = mmioFOURCC('f', 'L', 'a', 'C');
|
|
|
|
} else if (track->private_size >= RAPROPERTIES4_SIZE) {
|
|
|
|
if (!strcmp(track->codec_id, MKV_A_REAL28))
|
|
|
|
track->a_formattag = mmioFOURCC('2', '8', '_', '8');
|
|
|
|
else if (!strcmp(track->codec_id, MKV_A_REALATRC))
|
|
|
|
track->a_formattag = mmioFOURCC('a', 't', 'r', 'c');
|
|
|
|
else if (!strcmp(track->codec_id, MKV_A_REALCOOK))
|
|
|
|
track->a_formattag = mmioFOURCC('c', 'o', 'o', 'k');
|
|
|
|
else if (!strcmp(track->codec_id, MKV_A_REALDNET))
|
|
|
|
track->a_formattag = mmioFOURCC('d', 'n', 'e', 't');
|
|
|
|
else if (!strcmp(track->codec_id, MKV_A_REALSIPR))
|
|
|
|
track->a_formattag = mmioFOURCC('s', 'i', 'p', 'r');
|
|
|
|
} else {
|
|
|
|
mp_tmsg(MSGT_DEMUX, MSGL_WARN, "[mkv] Unknown/unsupported audio "
|
|
|
|
"codec ID '%s' for track %u or missing/faulty\n[mkv] "
|
|
|
|
"private codec data.\n", track->codec_id, track->tnum);
|
|
|
|
free_sh_audio(demuxer, track->tnum);
|
|
|
|
return 1;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
sh_a->format = track->a_formattag;
|
|
|
|
sh_a->wf->wFormatTag = track->a_formattag;
|
|
|
|
sh_a->channels = track->a_channels;
|
|
|
|
sh_a->wf->nChannels = track->a_channels;
|
|
|
|
sh_a->samplerate = (uint32_t) track->a_sfreq;
|
|
|
|
sh_a->wf->nSamplesPerSec = (uint32_t) track->a_sfreq;
|
|
|
|
if (track->a_bps == 0) {
|
|
|
|
sh_a->samplesize = 2;
|
|
|
|
sh_a->wf->wBitsPerSample = 16;
|
|
|
|
} else {
|
|
|
|
sh_a->samplesize = track->a_bps / 8;
|
|
|
|
sh_a->wf->wBitsPerSample = track->a_bps;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
if (track->a_formattag == 0x0055) { /* MP3 || MP2 */
|
|
|
|
sh_a->wf->nAvgBytesPerSec = 16000;
|
|
|
|
sh_a->wf->nBlockAlign = 1152;
|
|
|
|
} else if ((track->a_formattag == 0x2000) /* AC3 */
|
|
|
|
|| (track->a_formattag == 0x2001)) { /* DTS */
|
|
|
|
free(sh_a->wf);
|
|
|
|
sh_a->wf = NULL;
|
|
|
|
} else if (track->a_formattag == 0x0001) { /* PCM || PCM_BE */
|
|
|
|
sh_a->wf->nAvgBytesPerSec = sh_a->channels * sh_a->samplerate * 2;
|
|
|
|
sh_a->wf->nBlockAlign = sh_a->wf->nAvgBytesPerSec;
|
|
|
|
if (!strcmp(track->codec_id, MKV_A_PCM_BE))
|
|
|
|
sh_a->format = mmioFOURCC('t', 'w', 'o', 's');
|
|
|
|
} else if (!strcmp(track->codec_id, MKV_A_QDMC)
|
|
|
|
|| !strcmp(track->codec_id, MKV_A_QDMC2)) {
|
|
|
|
sh_a->wf->nAvgBytesPerSec = 16000;
|
|
|
|
sh_a->wf->nBlockAlign = 1486;
|
|
|
|
track->fix_i_bps = 1;
|
|
|
|
track->qt_last_a_pts = 0.0;
|
|
|
|
if (track->private_data != NULL) {
|
|
|
|
sh_a->codecdata = malloc(track->private_size);
|
|
|
|
memcpy(sh_a->codecdata, track->private_data, track->private_size);
|
|
|
|
sh_a->codecdata_len = track->private_size;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
} else if (track->a_formattag == mmioFOURCC('M', 'P', '4', 'A')) {
|
|
|
|
int profile, srate_idx;
|
|
|
|
|
|
|
|
sh_a->wf->nAvgBytesPerSec = 16000;
|
|
|
|
sh_a->wf->nBlockAlign = 1024;
|
|
|
|
|
|
|
|
if (!strcmp(track->codec_id, MKV_A_AAC)
|
|
|
|
&& (NULL != track->private_data)) {
|
|
|
|
sh_a->codecdata = malloc(track->private_size);
|
|
|
|
memcpy(sh_a->codecdata, track->private_data, track->private_size);
|
|
|
|
sh_a->codecdata_len = track->private_size;
|
|
|
|
return 0;
|
2005-10-22 10:13:28 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
/* Recreate the 'private data' */
|
|
|
|
/* which faad2 uses in its initialization */
|
|
|
|
srate_idx = aac_get_sample_rate_index(sh_a->samplerate);
|
|
|
|
if (!strncmp(&track->codec_id[12], "MAIN", 4))
|
|
|
|
profile = 0;
|
|
|
|
else if (!strncmp(&track->codec_id[12], "LC", 2))
|
|
|
|
profile = 1;
|
|
|
|
else if (!strncmp(&track->codec_id[12], "SSR", 3))
|
|
|
|
profile = 2;
|
|
|
|
else
|
|
|
|
profile = 3;
|
|
|
|
sh_a->codecdata = malloc(5);
|
|
|
|
sh_a->codecdata[0] = ((profile + 1) << 3) | ((srate_idx & 0xE) >> 1);
|
|
|
|
sh_a->codecdata[1] =
|
|
|
|
((srate_idx & 0x1) << 7) | (track->a_channels << 3);
|
|
|
|
|
|
|
|
if (strstr(track->codec_id, "SBR") != NULL) {
|
|
|
|
/* HE-AAC (aka SBR AAC) */
|
|
|
|
sh_a->codecdata_len = 5;
|
|
|
|
|
|
|
|
sh_a->samplerate *= 2;
|
|
|
|
sh_a->wf->nSamplesPerSec *= 2;
|
|
|
|
srate_idx = aac_get_sample_rate_index(sh_a->samplerate);
|
|
|
|
sh_a->codecdata[2] = AAC_SYNC_EXTENSION_TYPE >> 3;
|
|
|
|
sh_a->codecdata[3] = ((AAC_SYNC_EXTENSION_TYPE & 0x07) << 5) | 5;
|
|
|
|
sh_a->codecdata[4] = (1 << 7) | (srate_idx << 3);
|
|
|
|
track->default_duration = 1024.0 / (sh_a->samplerate / 2);
|
|
|
|
} else {
|
|
|
|
sh_a->codecdata_len = 2;
|
|
|
|
track->default_duration = 1024.0 / sh_a->samplerate;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
} else if (track->a_formattag == mmioFOURCC('v', 'r', 'b', 's')) { /* VORBIS */
|
|
|
|
sh_a->wf->cbSize = track->private_size;
|
|
|
|
sh_a->wf = realloc(sh_a->wf, sizeof(WAVEFORMATEX) + sh_a->wf->cbSize);
|
|
|
|
memcpy((unsigned char *) (sh_a->wf + 1), track->private_data,
|
|
|
|
sh_a->wf->cbSize);
|
|
|
|
} else if (track->private_size >= RAPROPERTIES4_SIZE
|
|
|
|
&& !strncmp(track->codec_id, MKV_A_REALATRC, 7)) {
|
|
|
|
/* Common initialization for all RealAudio codecs */
|
|
|
|
unsigned char *src = track->private_data;
|
|
|
|
int codecdata_length, version;
|
|
|
|
int flavor;
|
|
|
|
|
|
|
|
sh_a->wf->nAvgBytesPerSec = 0; /* FIXME !? */
|
|
|
|
|
|
|
|
version = AV_RB16(src + 4);
|
|
|
|
flavor = AV_RB16(src + 22);
|
|
|
|
track->coded_framesize = AV_RB32(src + 24);
|
|
|
|
track->sub_packet_h = AV_RB16(src + 40);
|
|
|
|
sh_a->wf->nBlockAlign = track->audiopk_size = AV_RB16(src + 42);
|
|
|
|
track->sub_packet_size = AV_RB16(src + 44);
|
|
|
|
if (version == 4) {
|
|
|
|
src += RAPROPERTIES4_SIZE;
|
|
|
|
src += src[0] + 1;
|
|
|
|
src += src[0] + 1;
|
|
|
|
} else
|
|
|
|
src += RAPROPERTIES5_SIZE;
|
|
|
|
|
|
|
|
src += 3;
|
|
|
|
if (version == 5)
|
|
|
|
src++;
|
|
|
|
codecdata_length = AV_RB32(src);
|
|
|
|
src += 4;
|
|
|
|
sh_a->wf->cbSize = codecdata_length;
|
|
|
|
sh_a->wf = realloc(sh_a->wf, sizeof(WAVEFORMATEX) + sh_a->wf->cbSize);
|
|
|
|
memcpy(((char *) (sh_a->wf + 1)), src, codecdata_length);
|
|
|
|
|
|
|
|
switch (track->a_formattag) {
|
2006-04-03 19:41:17 +00:00
|
|
|
case mmioFOURCC('a', 't', 'r', 'c'):
|
2009-12-29 19:06:21 +00:00
|
|
|
sh_a->wf->nAvgBytesPerSec = atrc_fl2bps[flavor];
|
|
|
|
sh_a->wf->nBlockAlign = track->sub_packet_size;
|
|
|
|
track->audio_buf =
|
|
|
|
malloc(track->sub_packet_h * track->audiopk_size);
|
|
|
|
track->audio_timestamp =
|
|
|
|
malloc(track->sub_packet_h * sizeof(double));
|
|
|
|
break;
|
2006-04-03 19:41:17 +00:00
|
|
|
case mmioFOURCC('c', 'o', 'o', 'k'):
|
2009-12-29 19:06:21 +00:00
|
|
|
sh_a->wf->nAvgBytesPerSec = cook_fl2bps[flavor];
|
|
|
|
sh_a->wf->nBlockAlign = track->sub_packet_size;
|
|
|
|
track->audio_buf =
|
|
|
|
malloc(track->sub_packet_h * track->audiopk_size);
|
|
|
|
track->audio_timestamp =
|
|
|
|
malloc(track->sub_packet_h * sizeof(double));
|
|
|
|
break;
|
2006-04-03 19:41:17 +00:00
|
|
|
case mmioFOURCC('s', 'i', 'p', 'r'):
|
2009-12-29 19:06:21 +00:00
|
|
|
sh_a->wf->nAvgBytesPerSec = sipr_fl2bps[flavor];
|
|
|
|
sh_a->wf->nBlockAlign = track->coded_framesize;
|
|
|
|
track->audio_buf =
|
|
|
|
malloc(track->sub_packet_h * track->audiopk_size);
|
|
|
|
track->audio_timestamp =
|
|
|
|
malloc(track->sub_packet_h * sizeof(double));
|
|
|
|
break;
|
2006-04-03 19:41:17 +00:00
|
|
|
case mmioFOURCC('2', '8', '_', '8'):
|
2009-12-29 19:06:21 +00:00
|
|
|
sh_a->wf->nAvgBytesPerSec = 3600;
|
|
|
|
sh_a->wf->nBlockAlign = track->coded_framesize;
|
|
|
|
track->audio_buf =
|
|
|
|
malloc(track->sub_packet_h * track->audiopk_size);
|
|
|
|
track->audio_timestamp =
|
|
|
|
malloc(track->sub_packet_h * sizeof(double));
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
|
|
|
|
track->realmedia = 1;
|
|
|
|
} else if (!strcmp(track->codec_id, MKV_A_FLAC)
|
|
|
|
|| (track->a_formattag == 0xf1ac)) {
|
|
|
|
unsigned char *ptr;
|
|
|
|
int size;
|
|
|
|
free(sh_a->wf);
|
|
|
|
sh_a->wf = NULL;
|
|
|
|
|
|
|
|
if (track->a_formattag == mmioFOURCC('f', 'L', 'a', 'C')) {
|
|
|
|
ptr = track->private_data;
|
|
|
|
size = track->private_size;
|
|
|
|
} else {
|
|
|
|
sh_a->format = mmioFOURCC('f', 'L', 'a', 'C');
|
|
|
|
ptr = track->private_data + sizeof(WAVEFORMATEX);
|
|
|
|
size = track->private_size - sizeof(WAVEFORMATEX);
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
if (size < 4 || ptr[0] != 'f' || ptr[1] != 'L' || ptr[2] != 'a'
|
|
|
|
|| ptr[3] != 'C') {
|
2009-10-17 17:30:49 +00:00
|
|
|
sh_a->codecdata = malloc(4);
|
|
|
|
sh_a->codecdata_len = 4;
|
|
|
|
memcpy(sh_a->codecdata, "fLaC", 4);
|
2009-12-29 19:06:21 +00:00
|
|
|
} else {
|
2009-10-17 17:30:49 +00:00
|
|
|
sh_a->codecdata = malloc(size);
|
|
|
|
sh_a->codecdata_len = size;
|
|
|
|
memcpy(sh_a->codecdata, ptr, size);
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
} else if (track->a_formattag == mmioFOURCC('W', 'V', 'P', 'K') || track->a_formattag == mmioFOURCC('T', 'R', 'H', 'D')) { /* do nothing, still works */
|
|
|
|
} else if (!track->ms_compat
|
|
|
|
|| (track->private_size < sizeof(WAVEFORMATEX))) {
|
|
|
|
free_sh_audio(demuxer, track->tnum);
|
|
|
|
return 1;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static int demux_mkv_open_sub(demuxer_t *demuxer, mkv_track_t *track,
|
|
|
|
int sid)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
if (track->subtitle_type != MATROSKA_SUBTYPE_UNKNOWN) {
|
|
|
|
int size, m;
|
|
|
|
uint8_t *buffer;
|
|
|
|
sh_sub_t *sh = new_sh_sub_sid(demuxer, track->tnum, sid);
|
|
|
|
track->sh_sub = sh;
|
|
|
|
sh->type = 't';
|
|
|
|
if (track->subtitle_type == MATROSKA_SUBTYPE_VOBSUB)
|
|
|
|
sh->type = 'v';
|
|
|
|
if (track->subtitle_type == MATROSKA_SUBTYPE_SSA)
|
|
|
|
sh->type = 'a';
|
|
|
|
size = track->private_size;
|
|
|
|
m = demux_mkv_decode(track, track->private_data, &buffer, &size, 2);
|
|
|
|
if (buffer && m) {
|
|
|
|
free(track->private_data);
|
|
|
|
track->private_data = buffer;
|
|
|
|
track->private_size = size;
|
2008-01-11 21:45:08 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
sh->extradata = malloc(track->private_size);
|
|
|
|
memcpy(sh->extradata, track->private_data, track->private_size);
|
|
|
|
sh->extradata_len = track->private_size;
|
|
|
|
if (track->language && (strcmp(track->language, "und") != 0))
|
|
|
|
sh->lang = strdup(track->language);
|
|
|
|
sh->default_track = track->default_track;
|
|
|
|
} else {
|
|
|
|
mp_tmsg(MSGT_DEMUX, MSGL_ERR,
|
|
|
|
"[mkv] Subtitle type '%s' is not supported.\n",
|
|
|
|
track->codec_id);
|
|
|
|
return 1;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static int demux_mkv_open(demuxer_t *demuxer)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
stream_t *s = demuxer->stream;
|
|
|
|
mkv_demuxer_t *mkv_d;
|
|
|
|
mkv_track_t *track;
|
|
|
|
int i, version, cont = 0;
|
|
|
|
char *str;
|
|
|
|
|
|
|
|
stream_seek(s, s->start_pos);
|
|
|
|
str = ebml_read_header(s, &version);
|
|
|
|
if (str == NULL || strcmp(str, "matroska") || version > 2) {
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_DBG2, "[mkv] no head found\n");
|
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
free(str);
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] Found the head...\n");
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
if (ebml_read_id(s, NULL) != MATROSKA_ID_SEGMENT) {
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] but no segment :(\n");
|
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
ebml_read_length(s, NULL); /* return bytes number until EOF */
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] + a segment...\n");
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_d = calloc(1, sizeof(mkv_demuxer_t));
|
|
|
|
demuxer->priv = mkv_d;
|
|
|
|
mkv_d->tc_scale = 1000000;
|
|
|
|
mkv_d->segment_start = stream_tell(s);
|
|
|
|
mkv_d->parsed_cues = malloc(sizeof(off_t));
|
|
|
|
mkv_d->parsed_seekhead = malloc(sizeof(off_t));
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
while (!cont) {
|
|
|
|
switch (ebml_read_id(s, NULL)) {
|
2004-01-19 19:16:10 +00:00
|
|
|
case MATROSKA_ID_INFO:
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |+ segment information...\n");
|
|
|
|
cont = demux_mkv_read_info(demuxer);
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
|
|
|
case MATROSKA_ID_TRACKS:
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] |+ segment tracks...\n");
|
|
|
|
cont = demux_mkv_read_tracks(demuxer);
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
|
|
|
case MATROSKA_ID_CUES:
|
2009-12-29 19:06:21 +00:00
|
|
|
cont = demux_mkv_read_cues(demuxer);
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
|
|
|
case MATROSKA_ID_TAGS:
|
2009-12-29 19:06:21 +00:00
|
|
|
cont = demux_mkv_read_tags(demuxer);
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
|
|
|
case MATROSKA_ID_SEEKHEAD:
|
2009-12-29 19:06:21 +00:00
|
|
|
cont = demux_mkv_read_seekhead(demuxer);
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
|
|
|
case MATROSKA_ID_CHAPTERS:
|
2009-12-29 19:06:21 +00:00
|
|
|
cont = demux_mkv_read_chapters(demuxer);
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2006-07-07 18:26:51 +00:00
|
|
|
case MATROSKA_ID_ATTACHMENTS:
|
2009-12-29 19:06:21 +00:00
|
|
|
cont = demux_mkv_read_attachments(demuxer);
|
|
|
|
break;
|
2006-07-07 18:26:51 +00:00
|
|
|
|
2009-12-31 06:08:50 +00:00
|
|
|
case MATROSKA_ID_CLUSTER:
|
2009-12-29 19:06:21 +00:00
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V,
|
|
|
|
"[mkv] |+ found cluster, headers are "
|
|
|
|
"parsed completely :)\n");
|
2009-12-31 06:08:50 +00:00
|
|
|
stream_seek(s, stream_tell(s) - 4);
|
2004-01-19 19:16:10 +00:00
|
|
|
cont = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2009-12-29 19:06:21 +00:00
|
|
|
cont = 1;
|
2004-01-19 19:16:10 +00:00
|
|
|
case EBML_ID_VOID:
|
2009-12-29 19:06:21 +00:00
|
|
|
ebml_read_skip(s, NULL);
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
display_create_tracks(demuxer);
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
/* select video track */
|
|
|
|
track = NULL;
|
|
|
|
if (demuxer->video->id == -1) { /* automatically select a video track */
|
|
|
|
/* search for a video track that has the 'default' flag set */
|
|
|
|
for (i = 0; i < mkv_d->num_tracks; i++)
|
|
|
|
if (mkv_d->tracks[i]->type == MATROSKA_TRACK_VIDEO
|
|
|
|
&& mkv_d->tracks[i]->default_track) {
|
|
|
|
track = mkv_d->tracks[i];
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
|
|
|
|
if (track == NULL)
|
|
|
|
/* no track has the 'default' flag set */
|
|
|
|
/* let's take the first video track */
|
|
|
|
for (i = 0; i < mkv_d->num_tracks; i++)
|
|
|
|
if (mkv_d->tracks[i]->type == MATROSKA_TRACK_VIDEO) {
|
|
|
|
track = mkv_d->tracks[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (demuxer->video->id != -2) /* -2 = no video at all */
|
|
|
|
track =
|
|
|
|
demux_mkv_find_track_by_num(mkv_d, demuxer->video->id,
|
|
|
|
MATROSKA_TRACK_VIDEO);
|
|
|
|
|
|
|
|
if (track && demuxer->v_streams[track->tnum]) {
|
|
|
|
mp_tmsg(MSGT_DEMUX, MSGL_INFO, "[mkv] Will play video track %u.\n",
|
|
|
|
track->tnum);
|
|
|
|
demuxer->video->id = track->tnum;
|
|
|
|
demuxer->video->sh = demuxer->v_streams[track->tnum];
|
|
|
|
} else {
|
|
|
|
mp_tmsg(MSGT_DEMUX, MSGL_INFO, "[mkv] No video track found/wanted.\n");
|
|
|
|
demuxer->video->id = -2;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
/* select audio track */
|
|
|
|
track = NULL;
|
|
|
|
if (track == NULL)
|
|
|
|
/* search for an audio track that has the 'default' flag set */
|
|
|
|
for (i = 0; i < mkv_d->num_tracks; i++)
|
|
|
|
if (mkv_d->tracks[i]->type == MATROSKA_TRACK_AUDIO
|
|
|
|
&& mkv_d->tracks[i]->default_track) {
|
|
|
|
track = mkv_d->tracks[i];
|
|
|
|
break;
|
|
|
|
}
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
if (track == NULL)
|
|
|
|
/* no track has the 'default' flag set */
|
|
|
|
/* let's take the first audio track */
|
|
|
|
for (i = 0; i < mkv_d->num_tracks; i++)
|
|
|
|
if (mkv_d->tracks[i]->type == MATROSKA_TRACK_AUDIO) {
|
|
|
|
track = mkv_d->tracks[i];
|
|
|
|
break;
|
|
|
|
}
|
2008-02-29 17:25:52 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
if (track && demuxer->a_streams[track->tnum]) {
|
|
|
|
demuxer->audio->id = track->tnum;
|
|
|
|
demuxer->audio->sh = demuxer->a_streams[track->tnum];
|
|
|
|
} else {
|
|
|
|
mp_tmsg(MSGT_DEMUX, MSGL_INFO, "[mkv] No audio track found/wanted.\n");
|
|
|
|
demuxer->audio->id = -2;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2006-06-19 18:34:29 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
if (demuxer->audio->id != -2)
|
|
|
|
for (i = 0; i < mkv_d->num_tracks; i++) {
|
|
|
|
if (mkv_d->tracks[i]->type != MATROSKA_TRACK_AUDIO)
|
|
|
|
continue;
|
|
|
|
if (demuxer->a_streams[track->tnum]) {
|
|
|
|
mkv_d->last_aid++;
|
|
|
|
if (mkv_d->last_aid == MAX_A_STREAMS)
|
|
|
|
break;
|
|
|
|
}
|
2006-06-19 18:34:29 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
if (s->end_pos == 0 || (mkv_d->indexes == NULL && index_mode < 0))
|
|
|
|
demuxer->seekable = 0;
|
|
|
|
else {
|
|
|
|
demuxer->movi_start = s->start_pos;
|
|
|
|
demuxer->movi_end = s->end_pos;
|
|
|
|
demuxer->seekable = 1;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
demuxer->accurate_seek = true;
|
2009-03-19 03:25:12 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
return DEMUXER_TYPE_MATROSKA;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static void demux_close_mkv(demuxer_t *demuxer)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
|
|
|
|
|
|
|
if (mkv_d) {
|
|
|
|
int i;
|
|
|
|
free_cached_dps(demuxer);
|
|
|
|
if (mkv_d->tracks) {
|
|
|
|
for (i = 0; i < mkv_d->num_tracks; i++)
|
|
|
|
demux_mkv_free_trackentry(mkv_d->tracks[i]);
|
|
|
|
free(mkv_d->tracks);
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
free(mkv_d->indexes);
|
|
|
|
free(mkv_d->cluster_positions);
|
|
|
|
free(mkv_d->parsed_cues);
|
|
|
|
free(mkv_d->parsed_seekhead);
|
|
|
|
free(mkv_d);
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static int demux_mkv_read_block_lacing(uint8_t *buffer, uint64_t *size,
|
|
|
|
uint8_t *laces,
|
|
|
|
uint32_t **all_lace_sizes)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
uint32_t total = 0, *lace_size;
|
|
|
|
uint8_t flags;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
*all_lace_sizes = NULL;
|
|
|
|
lace_size = NULL;
|
|
|
|
/* lacing flags */
|
|
|
|
flags = *buffer++;
|
|
|
|
(*size)--;
|
|
|
|
|
|
|
|
switch ((flags & 0x06) >> 1) {
|
|
|
|
case 0: /* no lacing */
|
|
|
|
*laces = 1;
|
|
|
|
lace_size = calloc(*laces, sizeof(uint32_t));
|
|
|
|
lace_size[0] = *size;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1: /* xiph lacing */
|
|
|
|
case 2: /* fixed-size lacing */
|
|
|
|
case 3: /* EBML lacing */
|
|
|
|
*laces = *buffer++;
|
|
|
|
(*size)--;
|
|
|
|
(*laces)++;
|
|
|
|
lace_size = calloc(*laces, sizeof(uint32_t));
|
|
|
|
|
|
|
|
switch ((flags & 0x06) >> 1) {
|
|
|
|
case 1: /* xiph lacing */
|
|
|
|
for (i = 0; i < *laces - 1; i++) {
|
|
|
|
lace_size[i] = 0;
|
|
|
|
do {
|
|
|
|
lace_size[i] += *buffer;
|
|
|
|
(*size)--;
|
2004-01-19 19:16:10 +00:00
|
|
|
} while (*buffer++ == 0xFF);
|
2009-12-29 19:06:21 +00:00
|
|
|
total += lace_size[i];
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
lace_size[i] = *size - total;
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
case 2: /* fixed-size lacing */
|
|
|
|
for (i = 0; i < *laces; i++)
|
|
|
|
lace_size[i] = *size / *laces;
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
case 3:; /* EBML lacing */
|
2004-01-19 19:16:10 +00:00
|
|
|
int l;
|
2009-12-29 19:06:21 +00:00
|
|
|
uint64_t num = ebml_read_vlen_uint(buffer, &l);
|
2004-03-25 20:47:37 +00:00
|
|
|
if (num == EBML_UINT_INVALID) {
|
2009-12-29 19:06:21 +00:00
|
|
|
free(lace_size);
|
|
|
|
return 1;
|
2004-03-25 20:47:37 +00:00
|
|
|
}
|
2004-01-19 19:16:10 +00:00
|
|
|
buffer += l;
|
|
|
|
*size -= l;
|
|
|
|
|
|
|
|
total = lace_size[0] = num;
|
2009-12-29 19:06:21 +00:00
|
|
|
for (i = 1; i < *laces - 1; i++) {
|
2004-01-19 19:16:10 +00:00
|
|
|
int64_t snum;
|
2009-12-29 19:06:21 +00:00
|
|
|
snum = ebml_read_vlen_int(buffer, &l);
|
2004-03-25 20:47:37 +00:00
|
|
|
if (snum == EBML_INT_INVALID) {
|
2009-12-29 19:06:21 +00:00
|
|
|
free(lace_size);
|
|
|
|
return 1;
|
2004-03-25 20:47:37 +00:00
|
|
|
}
|
2004-01-19 19:16:10 +00:00
|
|
|
buffer += l;
|
|
|
|
*size -= l;
|
2009-12-29 19:06:21 +00:00
|
|
|
lace_size[i] = lace_size[i - 1] + snum;
|
2004-01-19 19:16:10 +00:00
|
|
|
total += lace_size[i];
|
2009-12-29 19:06:21 +00:00
|
|
|
}
|
2004-01-19 19:16:10 +00:00
|
|
|
lace_size[i] = *size - total;
|
|
|
|
break;
|
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
*all_lace_sizes = lace_size;
|
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static void handle_subtitles(demuxer_t *demuxer, mkv_track_t *track,
|
|
|
|
char *block, int64_t size,
|
|
|
|
uint64_t block_duration, uint64_t timecode)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
demux_packet_t *dp;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
if (block_duration == 0) {
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_WARN,
|
|
|
|
"[mkv] Warning: No BlockDuration for subtitle track found.\n");
|
|
|
|
return;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
sub_utf8 = 1;
|
|
|
|
dp = new_demux_packet(size);
|
|
|
|
memcpy(dp->buffer, block, size);
|
|
|
|
dp->pts = timecode / 1000.0;
|
|
|
|
dp->endpts = (timecode + block_duration) / 1000.0;
|
|
|
|
ds_add_packet(demuxer->sub, dp);
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
double real_fix_timestamp(unsigned char *buf, unsigned int timestamp,
|
|
|
|
unsigned int format, int64_t *kf_base, int *kf_pts,
|
|
|
|
double *pts);
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static void handle_realvideo(demuxer_t *demuxer, mkv_track_t *track,
|
|
|
|
uint8_t *buffer, uint32_t size, int block_bref)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
|
|
|
demux_packet_t *dp;
|
|
|
|
uint32_t timestamp = mkv_d->last_pts * 1000;
|
|
|
|
|
|
|
|
dp = new_demux_packet(size);
|
|
|
|
memcpy(dp->buffer, buffer, size);
|
|
|
|
|
|
|
|
if (mkv_d->v_skip_to_keyframe) {
|
|
|
|
dp->pts = mkv_d->last_pts;
|
|
|
|
track->rv_kf_base = 0;
|
|
|
|
track->rv_kf_pts = timestamp;
|
|
|
|
} else
|
|
|
|
dp->pts =
|
|
|
|
real_fix_timestamp(dp->buffer, timestamp,
|
|
|
|
((sh_video_t *) demuxer->video->sh)->bih->
|
|
|
|
biCompression, &track->rv_kf_base,
|
|
|
|
&track->rv_kf_pts, NULL);
|
|
|
|
dp->pos = demuxer->filepos;
|
|
|
|
dp->flags = block_bref ? 0 : 0x10;
|
|
|
|
|
|
|
|
ds_add_packet(demuxer->video, dp);
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static void handle_realaudio(demuxer_t *demuxer, mkv_track_t *track,
|
|
|
|
uint8_t *buffer, uint32_t size, int block_bref)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
|
|
|
int sps = track->sub_packet_size;
|
|
|
|
int sph = track->sub_packet_h;
|
|
|
|
int cfs = track->coded_framesize;
|
|
|
|
int w = track->audiopk_size;
|
|
|
|
int spc = track->sub_packet_cnt;
|
|
|
|
demux_packet_t *dp;
|
|
|
|
int x;
|
|
|
|
|
|
|
|
if ((track->a_formattag == mmioFOURCC('2', '8', '_', '8'))
|
|
|
|
|| (track->a_formattag == mmioFOURCC('c', 'o', 'o', 'k'))
|
|
|
|
|| (track->a_formattag == mmioFOURCC('a', 't', 'r', 'c'))
|
|
|
|
|| (track->a_formattag == mmioFOURCC('s', 'i', 'p', 'r'))) {
|
2006-04-03 19:41:17 +00:00
|
|
|
// if(!block_bref)
|
|
|
|
// spc = track->sub_packet_cnt = 0;
|
2009-12-29 19:06:21 +00:00
|
|
|
switch (track->a_formattag) {
|
2006-04-03 19:41:17 +00:00
|
|
|
case mmioFOURCC('2', '8', '_', '8'):
|
2009-12-29 19:06:21 +00:00
|
|
|
for (x = 0; x < sph / 2; x++)
|
|
|
|
memcpy(track->audio_buf + x * 2 * w + spc * cfs,
|
|
|
|
buffer + cfs * x, cfs);
|
|
|
|
break;
|
2006-04-03 19:41:17 +00:00
|
|
|
case mmioFOURCC('c', 'o', 'o', 'k'):
|
|
|
|
case mmioFOURCC('a', 't', 'r', 'c'):
|
2009-12-29 19:06:21 +00:00
|
|
|
for (x = 0; x < w / sps; x++)
|
|
|
|
memcpy(track->audio_buf +
|
|
|
|
sps * (sph * x + ((sph + 1) / 2) * (spc & 1) +
|
|
|
|
(spc >> 1)), buffer + sps * x, sps);
|
|
|
|
break;
|
2006-04-03 19:41:17 +00:00
|
|
|
case mmioFOURCC('s', 'i', 'p', 'r'):
|
2009-12-29 19:06:21 +00:00
|
|
|
memcpy(track->audio_buf + spc * w, buffer, w);
|
|
|
|
if (spc == sph - 1) {
|
|
|
|
int n;
|
|
|
|
int bs = sph * w * 2 / 96; // nibbles per subpacket
|
|
|
|
// Perform reordering
|
|
|
|
for (n = 0; n < 38; n++) {
|
|
|
|
int j;
|
|
|
|
int i = bs * sipr_swaps[n][0];
|
|
|
|
int o = bs * sipr_swaps[n][1];
|
|
|
|
// swap nibbles of block 'i' with 'o' TODO: optimize
|
|
|
|
for (j = 0; j < bs; j++) {
|
|
|
|
int x = (i & 1) ?
|
|
|
|
(track->audio_buf[i >> 1] >> 4) :
|
|
|
|
(track->audio_buf[i >> 1] & 0x0F);
|
|
|
|
int y = (o & 1) ?
|
|
|
|
(track->audio_buf[o >> 1] >> 4) :
|
|
|
|
(track->audio_buf[o >> 1] & 0x0F);
|
|
|
|
if (o & 1)
|
|
|
|
track->audio_buf[o >> 1] =
|
|
|
|
(track->audio_buf[o >> 1] & 0x0F) | (x << 4);
|
|
|
|
else
|
|
|
|
track->audio_buf[o >> 1] =
|
|
|
|
(track->audio_buf[o >> 1] & 0xF0) | x;
|
|
|
|
if (i & 1)
|
|
|
|
track->audio_buf[i >> 1] =
|
|
|
|
(track->audio_buf[i >> 1] & 0x0F) | (y << 4);
|
|
|
|
else
|
|
|
|
track->audio_buf[i >> 1] =
|
|
|
|
(track->audio_buf[i >> 1] & 0xF0) | y;
|
|
|
|
++i;
|
|
|
|
++o;
|
2006-04-03 19:41:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
track->audio_timestamp[track->sub_packet_cnt] =
|
|
|
|
(track->ra_pts == mkv_d->last_pts) ? 0 : (mkv_d->last_pts);
|
|
|
|
track->ra_pts = mkv_d->last_pts;
|
|
|
|
if (track->sub_packet_cnt == 0)
|
|
|
|
track->audio_filepos = demuxer->filepos;
|
|
|
|
if (++(track->sub_packet_cnt) == sph) {
|
|
|
|
int apk_usize =
|
|
|
|
((WAVEFORMATEX *) ((sh_audio_t *) demuxer->audio->sh)->wf)->
|
|
|
|
nBlockAlign;
|
|
|
|
track->sub_packet_cnt = 0;
|
|
|
|
// Release all the audio packets
|
|
|
|
for (x = 0; x < sph * w / apk_usize; x++) {
|
|
|
|
dp = new_demux_packet(apk_usize);
|
|
|
|
memcpy(dp->buffer, track->audio_buf + x * apk_usize,
|
|
|
|
apk_usize);
|
|
|
|
/* Put timestamp only on packets that correspond to original
|
|
|
|
* audio packets in file */
|
|
|
|
dp->pts = (x * apk_usize % w) ? 0 :
|
|
|
|
track->audio_timestamp[x * apk_usize / w];
|
|
|
|
dp->pos = track->audio_filepos; // all equal
|
|
|
|
dp->flags = x ? 0 : 0x10; // Mark first packet as keyframe
|
|
|
|
ds_add_packet(demuxer->audio, dp);
|
|
|
|
}
|
2006-04-03 19:41:17 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
} else { // Not a codec that require reordering
|
|
|
|
dp = new_demux_packet(size);
|
|
|
|
memcpy(dp->buffer, buffer, size);
|
|
|
|
if (track->ra_pts == mkv_d->last_pts && !mkv_d->a_skip_to_keyframe)
|
|
|
|
dp->pts = 0;
|
|
|
|
else
|
|
|
|
dp->pts = mkv_d->last_pts;
|
|
|
|
track->ra_pts = mkv_d->last_pts;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
dp->pos = demuxer->filepos;
|
|
|
|
dp->flags = block_bref ? 0 : 0x10;
|
|
|
|
ds_add_packet(demuxer->audio, dp);
|
|
|
|
}
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2004-11-26 16:36:03 +00:00
|
|
|
/** Reorder timecodes and add cached demux packets to the queues.
|
|
|
|
*
|
|
|
|
* Timecode reordering is needed if a video track contains B frames that
|
|
|
|
* are timestamped in display order (e.g. MPEG-1, MPEG-2 or "native" MPEG-4).
|
|
|
|
* MPlayer doesn't like timestamps in display order. This function adjusts
|
|
|
|
* the timestamp of cached frames (which are exactly one I/P frame followed
|
|
|
|
* by one or more B frames) so that they are in coding order again.
|
|
|
|
*
|
|
|
|
* Example: The track with 25 FPS contains four frames with the timecodes
|
|
|
|
* I at 0ms, P at 120ms, B at 40ms and B at 80ms. As soon as the next I
|
|
|
|
* or P frame arrives these timecodes can be changed to I at 0ms, P at 40ms,
|
|
|
|
* B at 80ms and B at 120ms.
|
|
|
|
*
|
2005-11-05 04:56:23 +00:00
|
|
|
* This works for simple H.264 B-frame pyramids, but not for arbitrary orders.
|
|
|
|
*
|
2004-11-26 16:36:03 +00:00
|
|
|
* \param demuxer The Matroska demuxer struct for this instance.
|
|
|
|
* \param track The track structure whose cache should be handled.
|
|
|
|
*/
|
2009-12-29 19:06:21 +00:00
|
|
|
static void flush_cached_dps(demuxer_t *demuxer, mkv_track_t *track)
|
2004-11-26 16:36:03 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
int i, ok;
|
|
|
|
|
|
|
|
if (track->num_cached_dps == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
do {
|
|
|
|
ok = 1;
|
|
|
|
for (i = 1; i < track->num_cached_dps; i++)
|
|
|
|
if (track->cached_dps[i - 1]->pts > track->cached_dps[i]->pts) {
|
|
|
|
double tmp_pts = track->cached_dps[i - 1]->pts;
|
|
|
|
track->cached_dps[i - 1]->pts = track->cached_dps[i]->pts;
|
|
|
|
track->cached_dps[i]->pts = tmp_pts;
|
|
|
|
ok = 0;
|
|
|
|
}
|
|
|
|
} while (!ok);
|
|
|
|
|
|
|
|
for (i = 0; i < track->num_cached_dps; i++)
|
|
|
|
ds_add_packet(demuxer->video, track->cached_dps[i]);
|
|
|
|
track->num_cached_dps = 0;
|
2004-11-26 16:36:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Cache video frames if timecodes have to be reordered.
|
|
|
|
*
|
|
|
|
* Timecode reordering is needed if a video track contains B frames that
|
|
|
|
* are timestamped in display order (e.g. MPEG-1, MPEG-2 or "native" MPEG-4).
|
|
|
|
* This function takes in a Matroska block read from the file, allocates a
|
|
|
|
* demux packet for it, fills in its values, allocates space for storing
|
|
|
|
* pointers to the cached demux packets and adds the packet to it. If
|
|
|
|
* the packet contains an I or a P frame then ::flush_cached_dps is called
|
|
|
|
* in order to send the old cached frames downstream.
|
|
|
|
*
|
|
|
|
* \param demuxer The Matroska demuxer struct for this instance.
|
|
|
|
* \param track The packet is meant for this track.
|
|
|
|
* \param buffer The actual frame contents.
|
|
|
|
* \param size The frame size in bytes.
|
|
|
|
* \param block_bref A relative timecode (backward reference). If it is \c 0
|
|
|
|
* then the frame is an I frame.
|
|
|
|
* \param block_fref A relative timecode (forward reference). If it is \c 0
|
|
|
|
* then the frame is either an I frame or a P frame depending on the value
|
|
|
|
* of \a block_bref. Otherwise it's a B frame.
|
|
|
|
*/
|
2009-12-29 19:06:21 +00:00
|
|
|
static void handle_video_bframes(demuxer_t *demuxer, mkv_track_t *track,
|
|
|
|
uint8_t *buffer, uint32_t size,
|
|
|
|
int block_bref, int block_fref)
|
2004-11-26 16:36:03 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
|
|
|
demux_packet_t *dp;
|
|
|
|
|
|
|
|
dp = new_demux_packet(size);
|
|
|
|
memcpy(dp->buffer, buffer, size);
|
|
|
|
dp->pos = demuxer->filepos;
|
|
|
|
dp->pts = mkv_d->last_pts;
|
|
|
|
if ((track->num_cached_dps > 0) && (dp->pts < track->max_pts))
|
|
|
|
block_fref = 1;
|
|
|
|
if (block_fref == 0) /* I or P frame */
|
|
|
|
flush_cached_dps(demuxer, track);
|
|
|
|
if (block_bref != 0) /* I frame, don't cache it */
|
|
|
|
dp->flags = 0x10;
|
|
|
|
if ((track->num_cached_dps + 1) > track->num_allocated_dps) {
|
|
|
|
track->cached_dps = (demux_packet_t **)
|
|
|
|
realloc(track->cached_dps,
|
|
|
|
(track->num_cached_dps + 10) * sizeof(demux_packet_t *));
|
|
|
|
track->num_allocated_dps += 10;
|
2004-11-26 16:36:03 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
track->cached_dps[track->num_cached_dps] = dp;
|
|
|
|
track->num_cached_dps++;
|
|
|
|
if (dp->pts > track->max_pts)
|
|
|
|
track->max_pts = dp->pts;
|
2004-11-26 16:36:03 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static int handle_block(demuxer_t *demuxer, uint8_t *block, uint64_t length,
|
|
|
|
uint64_t block_duration, int64_t block_bref,
|
|
|
|
int64_t block_fref, uint8_t simpleblock)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
|
|
|
mkv_track_t *track = NULL;
|
|
|
|
demux_stream_t *ds = NULL;
|
|
|
|
uint64_t old_length;
|
|
|
|
int64_t tc;
|
|
|
|
uint32_t *lace_size;
|
|
|
|
uint8_t laces, flags;
|
|
|
|
int i, num, tmp, use_this_block = 1;
|
|
|
|
double current_pts;
|
|
|
|
int16_t time;
|
|
|
|
|
|
|
|
/* first byte(s): track num */
|
|
|
|
num = ebml_read_vlen_uint(block, &tmp);
|
|
|
|
block += tmp;
|
|
|
|
/* time (relative to cluster time) */
|
|
|
|
time = block[0] << 8 | block[1];
|
|
|
|
block += 2;
|
|
|
|
length -= tmp + 2;
|
|
|
|
old_length = length;
|
|
|
|
flags = block[0];
|
|
|
|
if (demux_mkv_read_block_lacing(block, &length, &laces, &lace_size))
|
|
|
|
return 0;
|
|
|
|
block += old_length - length;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
tc = (time * mkv_d->tc_scale + mkv_d->cluster_tc) / 1000000.0 + 0.5;
|
|
|
|
if (tc < 0)
|
|
|
|
tc = 0;
|
|
|
|
current_pts = tc / 1000.0;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
for (i = 0; i < mkv_d->num_tracks; i++)
|
|
|
|
if (mkv_d->tracks[i]->tnum == num) {
|
|
|
|
track = mkv_d->tracks[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (track == NULL) {
|
|
|
|
free(lace_size);
|
|
|
|
return 1;
|
2004-06-28 16:43:01 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
if (num == demuxer->audio->id) {
|
|
|
|
ds = demuxer->audio;
|
|
|
|
|
|
|
|
if (mkv_d->a_skip_to_keyframe) {
|
|
|
|
if (simpleblock) {
|
|
|
|
if (!(flags & 0x80)) /*current frame isn't a keyframe */
|
|
|
|
use_this_block = 0;
|
|
|
|
} else if (block_bref != 0)
|
|
|
|
use_this_block = 0;
|
|
|
|
} else if (mkv_d->v_skip_to_keyframe)
|
2006-09-25 21:17:43 +00:00
|
|
|
use_this_block = 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
if (track->fix_i_bps && use_this_block) {
|
|
|
|
sh_audio_t *sh = (sh_audio_t *) ds->sh;
|
|
|
|
|
|
|
|
if (block_duration != 0) {
|
|
|
|
sh->i_bps = length * 1000 / block_duration;
|
|
|
|
track->fix_i_bps = 0;
|
|
|
|
} else if (track->qt_last_a_pts == 0.0)
|
|
|
|
track->qt_last_a_pts = current_pts;
|
|
|
|
else if (track->qt_last_a_pts != current_pts) {
|
|
|
|
sh->i_bps = length / (current_pts - track->qt_last_a_pts);
|
|
|
|
track->fix_i_bps = 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
} else if (tc < mkv_d->skip_to_timecode)
|
|
|
|
use_this_block = 0;
|
|
|
|
else if (num == demuxer->video->id) {
|
|
|
|
ds = demuxer->video;
|
|
|
|
if (mkv_d->v_skip_to_keyframe) {
|
|
|
|
if (simpleblock) {
|
|
|
|
if (!(flags & 0x80)) /*current frame isn't a keyframe */
|
|
|
|
use_this_block = 0;
|
|
|
|
} else if (block_bref != 0 || block_fref != 0)
|
2006-09-25 21:17:43 +00:00
|
|
|
use_this_block = 0;
|
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
} else if (num == demuxer->sub->id) {
|
|
|
|
ds = demuxer->sub;
|
|
|
|
if (track->subtitle_type != MATROSKA_SUBTYPE_VOBSUB) {
|
|
|
|
if (!mkv_d->v_skip_to_keyframe)
|
|
|
|
handle_subtitles(demuxer, track, block, length, block_duration,
|
|
|
|
tc);
|
|
|
|
use_this_block = 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
} else
|
|
|
|
use_this_block = 0;
|
|
|
|
|
|
|
|
if (use_this_block) {
|
|
|
|
mkv_d->last_pts = current_pts;
|
|
|
|
mkv_d->last_filepos = demuxer->filepos;
|
|
|
|
|
|
|
|
for (i = 0; i < laces; i++) {
|
|
|
|
if (ds == demuxer->video && track->realmedia)
|
|
|
|
handle_realvideo(demuxer, track, block, lace_size[i],
|
|
|
|
block_bref);
|
|
|
|
else if (ds == demuxer->audio && track->realmedia)
|
|
|
|
handle_realaudio(demuxer, track, block, lace_size[i],
|
|
|
|
block_bref);
|
|
|
|
else if (ds == demuxer->video && track->reorder_timecodes)
|
|
|
|
handle_video_bframes(demuxer, track, block, lace_size[i],
|
|
|
|
block_bref, block_fref);
|
|
|
|
else {
|
|
|
|
int modified, size = lace_size[i];
|
|
|
|
demux_packet_t *dp;
|
|
|
|
uint8_t *buffer;
|
|
|
|
modified = demux_mkv_decode(track, block, &buffer, &size, 1);
|
|
|
|
if (buffer) {
|
|
|
|
dp = new_demux_packet(size);
|
|
|
|
memcpy(dp->buffer, buffer, size);
|
|
|
|
if (modified)
|
|
|
|
free(buffer);
|
|
|
|
dp->flags = (block_bref == 0
|
|
|
|
&& block_fref == 0) ? 0x10 : 0;
|
|
|
|
/* If default_duration is 0, assume no pts value is known
|
|
|
|
* for packets after the first one (rather than all pts
|
|
|
|
* values being the same) */
|
|
|
|
if (i == 0 || track->default_duration)
|
|
|
|
dp->pts =
|
|
|
|
mkv_d->last_pts + i * track->default_duration;
|
|
|
|
ds_add_packet(ds, dp);
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
block += lace_size[i];
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
if (ds == demuxer->video) {
|
|
|
|
mkv_d->v_skip_to_keyframe = 0;
|
|
|
|
mkv_d->skip_to_timecode = 0;
|
|
|
|
} else if (ds == demuxer->audio)
|
|
|
|
mkv_d->a_skip_to_keyframe = 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
free(lace_size);
|
|
|
|
return 1;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
free(lace_size);
|
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static int demux_mkv_fill_buffer(demuxer_t *demuxer, demux_stream_t *ds)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
|
|
|
stream_t *s = demuxer->stream;
|
|
|
|
uint64_t l;
|
|
|
|
int il, tmp;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
while (mkv_d->cluster_size > 0) {
|
|
|
|
uint64_t block_duration = 0, block_length = 0;
|
|
|
|
int64_t block_bref = 0, block_fref = 0;
|
|
|
|
uint8_t *block = NULL;
|
|
|
|
|
|
|
|
while (mkv_d->blockgroup_size > 0) {
|
|
|
|
switch (ebml_read_id(s, &il)) {
|
2004-01-19 19:16:10 +00:00
|
|
|
case MATROSKA_ID_BLOCKDURATION:
|
2009-12-29 19:06:21 +00:00
|
|
|
block_duration = ebml_read_uint(s, &l);
|
2007-07-05 22:06:05 +00:00
|
|
|
if (block_duration == EBML_UINT_INVALID) {
|
2009-12-29 19:06:21 +00:00
|
|
|
free(block);
|
|
|
|
return 0;
|
2007-07-05 22:06:05 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
block_duration =
|
|
|
|
block_duration * mkv_d->tc_scale / 1000000.0 + 0.5;
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MATROSKA_ID_BLOCK:
|
2009-12-29 19:06:21 +00:00
|
|
|
block_length = ebml_read_length(s, &tmp);
|
2006-10-11 15:57:51 +00:00
|
|
|
free(block);
|
2009-12-29 19:06:21 +00:00
|
|
|
if (block_length > SIZE_MAX - AV_LZO_INPUT_PADDING)
|
|
|
|
return 0;
|
|
|
|
block = malloc(block_length + AV_LZO_INPUT_PADDING);
|
|
|
|
demuxer->filepos = stream_tell(s);
|
|
|
|
if (stream_read(s, block, block_length) !=
|
|
|
|
(int) block_length) {
|
|
|
|
free(block);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
l = tmp + block_length;
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
case MATROSKA_ID_REFERENCEBLOCK:;
|
|
|
|
int64_t num = ebml_read_int(s, &l);
|
2007-07-05 22:06:05 +00:00
|
|
|
if (num == EBML_INT_INVALID) {
|
2009-12-29 19:06:21 +00:00
|
|
|
free(block);
|
|
|
|
return 0;
|
2007-07-05 22:06:05 +00:00
|
|
|
}
|
2004-11-26 16:36:03 +00:00
|
|
|
if (num <= 0)
|
2009-12-29 19:06:21 +00:00
|
|
|
block_bref = num;
|
2004-11-26 16:36:03 +00:00
|
|
|
else
|
2009-12-29 19:06:21 +00:00
|
|
|
block_fref = num;
|
2004-01-19 19:16:10 +00:00
|
|
|
break;
|
|
|
|
|
2004-02-09 19:21:08 +00:00
|
|
|
case EBML_ID_INVALID:
|
2009-12-29 19:06:21 +00:00
|
|
|
free(block);
|
|
|
|
return 0;
|
2004-02-09 19:21:08 +00:00
|
|
|
|
2004-01-19 19:16:10 +00:00
|
|
|
default:
|
2009-12-29 19:06:21 +00:00
|
|
|
ebml_read_skip(s, &l);
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_d->blockgroup_size -= l + il;
|
|
|
|
mkv_d->cluster_size -= l + il;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
if (block) {
|
|
|
|
int res = handle_block(demuxer, block, block_length,
|
|
|
|
block_duration, block_bref, block_fref,
|
|
|
|
0);
|
|
|
|
free(block);
|
|
|
|
if (res < 0)
|
|
|
|
return 0;
|
|
|
|
if (res)
|
|
|
|
return 1;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
if (mkv_d->cluster_size > 0) {
|
|
|
|
switch (ebml_read_id(s, &il)) {
|
|
|
|
case MATROSKA_ID_CLUSTERTIMECODE:;
|
|
|
|
uint64_t num = ebml_read_uint(s, &l);
|
2004-01-19 19:16:10 +00:00
|
|
|
if (num == EBML_UINT_INVALID)
|
2009-12-29 19:06:21 +00:00
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
mkv_d->cluster_tc = num * mkv_d->tc_scale;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MATROSKA_ID_BLOCKGROUP:
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_d->blockgroup_size = ebml_read_length(s, &tmp);
|
|
|
|
l = tmp;
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
case MATROSKA_ID_SIMPLEBLOCK:;
|
2006-09-25 21:17:43 +00:00
|
|
|
int res;
|
2009-12-29 19:06:21 +00:00
|
|
|
block_length = ebml_read_length(s, &tmp);
|
|
|
|
block = malloc(block_length);
|
|
|
|
demuxer->filepos = stream_tell(s);
|
|
|
|
if (stream_read(s, block, block_length) !=
|
|
|
|
(int) block_length) {
|
|
|
|
free(block);
|
|
|
|
return 0;
|
2006-10-11 15:57:51 +00:00
|
|
|
}
|
2006-09-25 21:17:43 +00:00
|
|
|
l = tmp + block_length;
|
2009-12-29 19:06:21 +00:00
|
|
|
res = handle_block(demuxer, block, block_length,
|
|
|
|
block_duration, block_bref,
|
|
|
|
block_fref, 1);
|
|
|
|
free(block);
|
2006-09-25 21:17:43 +00:00
|
|
|
mkv_d->cluster_size -= l + il;
|
|
|
|
if (res < 0)
|
2009-12-29 19:06:21 +00:00
|
|
|
return 0;
|
2006-09-25 21:17:43 +00:00
|
|
|
else if (res)
|
2009-12-29 19:06:21 +00:00
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
mkv_d->cluster_size += l + il;
|
2006-09-25 21:17:43 +00:00
|
|
|
break;
|
2009-12-29 19:06:21 +00:00
|
|
|
|
2004-02-09 19:21:08 +00:00
|
|
|
case EBML_ID_INVALID:
|
2009-12-29 19:06:21 +00:00
|
|
|
return 0;
|
2004-02-09 19:21:08 +00:00
|
|
|
|
2004-01-19 19:16:10 +00:00
|
|
|
default:
|
2009-12-29 19:06:21 +00:00
|
|
|
ebml_read_skip(s, &l);
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_d->cluster_size -= l + il;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
if (ebml_read_id(s, &il) != MATROSKA_ID_CLUSTER)
|
|
|
|
return 0;
|
|
|
|
add_cluster_position(mkv_d, stream_tell(s) - il);
|
|
|
|
mkv_d->cluster_size = ebml_read_length(s, NULL);
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
return 0;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs,
|
|
|
|
float audio_delay, int flags)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-03-19 03:25:12 +00:00
|
|
|
if (!(flags & (SEEK_BACKWARD | SEEK_FORWARD))) {
|
|
|
|
if (flags & SEEK_ABSOLUTE || rel_seek_secs < 0)
|
|
|
|
flags |= SEEK_BACKWARD;
|
|
|
|
else
|
|
|
|
flags |= SEEK_FORWARD;
|
|
|
|
}
|
2009-03-31 16:30:14 +00:00
|
|
|
// Adjust the target a little bit to catch cases where the target position
|
|
|
|
// specifies a keyframe with high, but not perfect, precision.
|
2009-07-09 15:23:35 +00:00
|
|
|
rel_seek_secs += flags & SEEK_FORWARD ? -0.005 : 0.005;
|
2009-03-31 16:30:14 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
free_cached_dps(demuxer);
|
|
|
|
if (!(flags & SEEK_FACTOR)) { /* time in secs */
|
|
|
|
mkv_index_t *index = NULL;
|
|
|
|
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
|
|
|
stream_t *s = demuxer->stream;
|
|
|
|
int64_t target_timecode = 0, diff, min_diff = 0xFFFFFFFFFFFFFFFLL;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!(flags & SEEK_ABSOLUTE)) /* relative seek */
|
|
|
|
target_timecode = (int64_t) (mkv_d->last_pts * 1000.0);
|
|
|
|
target_timecode += (int64_t) (rel_seek_secs * 1000.0);
|
|
|
|
if (target_timecode < 0)
|
|
|
|
target_timecode = 0;
|
|
|
|
|
|
|
|
if (mkv_d->indexes == NULL) { /* no index was found */
|
|
|
|
uint64_t target_filepos, cluster_pos, max_pos;
|
|
|
|
|
|
|
|
target_filepos =
|
|
|
|
(uint64_t) (target_timecode * mkv_d->last_filepos /
|
|
|
|
(mkv_d->last_pts * 1000.0));
|
|
|
|
|
|
|
|
max_pos = mkv_d->num_cluster_pos ?
|
|
|
|
mkv_d->cluster_positions[mkv_d->num_cluster_pos - 1] : 0;
|
|
|
|
if (target_filepos > max_pos) {
|
|
|
|
if ((off_t) max_pos > stream_tell(s))
|
|
|
|
stream_seek(s, max_pos);
|
|
|
|
else
|
|
|
|
stream_seek(s, stream_tell(s) + mkv_d->cluster_size);
|
|
|
|
/* parse all the clusters upto target_filepos */
|
|
|
|
while (!s->eof && stream_tell(s) < (off_t) target_filepos) {
|
|
|
|
switch (ebml_read_id(s, &i)) {
|
2004-01-19 19:16:10 +00:00
|
|
|
case MATROSKA_ID_CLUSTER:
|
2009-12-29 19:06:21 +00:00
|
|
|
add_cluster_position(mkv_d,
|
|
|
|
(uint64_t) stream_tell(s) - i);
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
|
|
|
case MATROSKA_ID_CUES:
|
2009-12-29 19:06:21 +00:00
|
|
|
demux_mkv_read_cues(demuxer);
|
|
|
|
break;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
ebml_read_skip(s, NULL);
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
if (s->eof)
|
|
|
|
stream_reset(s);
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
if (mkv_d->indexes == NULL) {
|
|
|
|
cluster_pos = mkv_d->cluster_positions[0];
|
|
|
|
/* Let's find the nearest cluster */
|
|
|
|
for (i = 0; i < mkv_d->num_cluster_pos; i++) {
|
|
|
|
diff = mkv_d->cluster_positions[i] - target_filepos;
|
|
|
|
if (flags & SEEK_BACKWARD && diff < 0 && -diff < min_diff) {
|
|
|
|
cluster_pos = mkv_d->cluster_positions[i];
|
|
|
|
min_diff = -diff;
|
|
|
|
} else if (flags & SEEK_FORWARD
|
|
|
|
&& (diff < 0 ? -1 * diff : diff) < min_diff) {
|
|
|
|
cluster_pos = mkv_d->cluster_positions[i];
|
|
|
|
min_diff = diff < 0 ? -1 * diff : diff;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_d->cluster_size = mkv_d->blockgroup_size = 0;
|
|
|
|
stream_seek(s, cluster_pos);
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
} else {
|
|
|
|
int seek_id = (demuxer->video->id < 0) ?
|
|
|
|
demuxer->audio->id : demuxer->video->id;
|
|
|
|
|
|
|
|
/* let's find the entry in the indexes with the smallest */
|
|
|
|
/* difference to the wanted timecode. */
|
|
|
|
for (i = 0; i < mkv_d->num_indexes; i++)
|
|
|
|
if (mkv_d->indexes[i].tnum == seek_id) {
|
|
|
|
diff =
|
|
|
|
target_timecode -
|
|
|
|
(int64_t) (mkv_d->indexes[i].timecode *
|
|
|
|
mkv_d->tc_scale / 1000000.0 + 0.5);
|
|
|
|
|
|
|
|
if (flags & SEEK_BACKWARD) {
|
|
|
|
// Seek backward: find the last index position
|
|
|
|
// before target time
|
|
|
|
if (diff < 0 || diff >= min_diff)
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
// Seek forward: find the first index position
|
|
|
|
// after target time. If no such index exists, find last
|
|
|
|
// position between current position and target time.
|
|
|
|
if (diff <= 0) {
|
|
|
|
if (min_diff <= 0 && diff <= min_diff)
|
|
|
|
continue;
|
|
|
|
} else if (diff >=
|
|
|
|
FFMIN(target_timecode - mkv_d->last_pts,
|
|
|
|
min_diff))
|
2007-03-16 14:55:41 +00:00
|
|
|
continue;
|
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
min_diff = diff;
|
|
|
|
index = mkv_d->indexes + i;
|
2007-03-16 14:55:41 +00:00
|
|
|
}
|
2009-12-29 19:06:21 +00:00
|
|
|
|
|
|
|
if (index) { /* We've found an entry. */
|
|
|
|
mkv_d->cluster_size = mkv_d->blockgroup_size = 0;
|
|
|
|
stream_seek(s, index->filepos);
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
if (demuxer->video->id >= 0)
|
|
|
|
mkv_d->v_skip_to_keyframe = 1;
|
|
|
|
if (flags & SEEK_FORWARD)
|
|
|
|
mkv_d->skip_to_timecode = target_timecode;
|
|
|
|
else
|
|
|
|
mkv_d->skip_to_timecode = index ? index->timecode : 0;
|
|
|
|
mkv_d->a_skip_to_keyframe = 1;
|
|
|
|
|
|
|
|
demux_mkv_fill_buffer(demuxer, NULL);
|
|
|
|
} else if ((demuxer->movi_end <= 0) || !(flags & SEEK_ABSOLUTE))
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek unsupported flags\n");
|
|
|
|
else {
|
|
|
|
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
|
|
|
stream_t *s = demuxer->stream;
|
|
|
|
uint64_t target_filepos;
|
|
|
|
mkv_index_t *index = NULL;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (mkv_d->indexes == NULL) { /* not implemented without index */
|
|
|
|
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek unsupported flags\n");
|
|
|
|
return;
|
2004-03-26 19:45:06 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
target_filepos = (uint64_t) (demuxer->movi_end * rel_seek_secs);
|
|
|
|
for (i = 0; i < mkv_d->num_indexes; i++)
|
|
|
|
if (mkv_d->indexes[i].tnum == demuxer->video->id)
|
|
|
|
if ((index == NULL)
|
|
|
|
|| ((mkv_d->indexes[i].filepos >= target_filepos)
|
|
|
|
&& ((index->filepos < target_filepos)
|
|
|
|
|| (mkv_d->indexes[i].filepos < index->filepos))))
|
|
|
|
index = &mkv_d->indexes[i];
|
2004-03-26 19:45:06 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
if (!index)
|
|
|
|
return;
|
2004-03-26 19:45:06 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_d->cluster_size = mkv_d->blockgroup_size = 0;
|
|
|
|
stream_seek(s, index->filepos);
|
2004-03-26 19:45:06 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
if (demuxer->video->id >= 0)
|
|
|
|
mkv_d->v_skip_to_keyframe = 1;
|
|
|
|
mkv_d->skip_to_timecode = index->timecode;
|
|
|
|
mkv_d->a_skip_to_keyframe = 1;
|
2004-03-26 19:45:06 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
demux_mkv_fill_buffer(demuxer, NULL);
|
2004-03-26 19:45:06 +00:00
|
|
|
}
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
static int demux_mkv_control(demuxer_t *demuxer, int cmd, void *arg)
|
2004-01-19 19:16:10 +00:00
|
|
|
{
|
2009-12-29 19:06:21 +00:00
|
|
|
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
2009-07-06 23:26:13 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
switch (cmd) {
|
2008-02-03 12:14:29 +00:00
|
|
|
case DEMUXER_CTRL_CORRECT_PTS:
|
2009-12-29 19:06:21 +00:00
|
|
|
return DEMUXER_CTRL_OK;
|
2004-01-19 19:16:10 +00:00
|
|
|
case DEMUXER_CTRL_GET_TIME_LENGTH:
|
2009-12-29 19:06:21 +00:00
|
|
|
if (mkv_d->duration == 0)
|
|
|
|
return DEMUXER_CTRL_DONTKNOW;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
*((double *) arg) = (double) mkv_d->duration;
|
|
|
|
return DEMUXER_CTRL_OK;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
|
|
|
case DEMUXER_CTRL_GET_PERCENT_POS:
|
2009-12-29 19:06:21 +00:00
|
|
|
if (mkv_d->duration == 0) {
|
2004-01-19 19:16:10 +00:00
|
|
|
return DEMUXER_CTRL_DONTKNOW;
|
|
|
|
}
|
|
|
|
|
2009-12-29 19:06:21 +00:00
|
|
|
*((int *) arg) = (int) (100 * mkv_d->last_pts / mkv_d->duration);
|
|
|
|
return DEMUXER_CTRL_OK;
|
2004-01-19 19:16:10 +00:00
|
|
|
|
2005-04-13 22:33:19 +00:00
|
|
|
case DEMUXER_CTRL_SWITCH_AUDIO:
|
2009-12-29 19:06:21 +00:00
|
|
|
if (demuxer->audio && demuxer->audio->sh) {
|
|
|
|
sh_audio_t *sh = demuxer->a_streams[demuxer->audio->id];
|
|
|
|
int aid = *(int *) arg;
|
|
|
|
if (aid < 0)
|
|
|
|
aid = (sh->aid + 1) % mkv_d->last_aid;
|
|
|
|
if (aid != sh->aid) {
|
|
|
|
mkv_track_t *track =
|
|
|
|
demux_mkv_find_track_by_num(mkv_d, aid,
|
|
|
|
MATROSKA_TRACK_AUDIO);
|
|
|
|
if (track) {
|
|
|
|
demuxer->audio->id = track->tnum;
|
|
|
|
sh = demuxer->a_streams[demuxer->audio->id];
|
|
|
|
ds_free_packs(demuxer->audio);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*(int *) arg = sh->aid;
|
|
|
|
} else
|
|
|
|
*(int *) arg = -2;
|
|
|
|
return DEMUXER_CTRL_OK;
|
2005-04-13 22:33:19 +00:00
|
|
|
|
2004-01-19 19:16:10 +00:00
|
|
|
default:
|
2009-12-29 19:06:21 +00:00
|
|
|
return DEMUXER_CTRL_NOTIMPL;
|
2004-01-19 19:16:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-13 16:00:39 +00:00
|
|
|
const demuxer_desc_t demuxer_desc_matroska = {
|
2009-12-29 19:06:21 +00:00
|
|
|
"Matroska demuxer",
|
|
|
|
"mkv",
|
|
|
|
"Matroska",
|
|
|
|
"Aurelien Jacobs",
|
|
|
|
"",
|
|
|
|
DEMUXER_TYPE_MATROSKA,
|
|
|
|
1, // safe autodetect
|
|
|
|
demux_mkv_open,
|
|
|
|
demux_mkv_fill_buffer,
|
|
|
|
NULL,
|
|
|
|
demux_close_mkv,
|
|
|
|
demux_mkv_seek,
|
|
|
|
demux_mkv_control
|
2005-08-05 19:57:47 +00:00
|
|
|
};
|