Commit 67f3022a authored by Jean-Baptiste Kempf's avatar Jean-Baptiste Kempf
Browse files

MKV: Copy mkv.cpp to many different files.

parent 8e13a232
/*****************************************************************************
* mkv.cpp : matroska demuxer
*****************************************************************************
* Copyright (C) 2003-2004 the VideoLAN team
* $Id$
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Steve Lhomme <steve.lhomme@free.fr>
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
/* config.h may include inttypes.h, so make sure we define that option
* early enough. */
#define __STDC_FORMAT_MACROS 1
#define __STDC_CONSTANT_MACROS 1
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <inttypes.h>
#include <vlc_common.h>
#include <vlc_plugin.h>
#ifdef HAVE_TIME_H
# include <time.h> /* time() */
#endif
#include <vlc_codecs.h> /* BITMAPINFOHEADER, WAVEFORMATEX */
#include <vlc_iso_lang.h>
#include "vlc_meta.h"
#include <vlc_charset.h>
#include <vlc_input.h>
#include <vlc_demux.h>
#include <iostream>
#include <cassert>
#include <typeinfo>
#include <string>
#include <vector>
#include <algorithm>
#ifdef HAVE_DIRENT_H
# include <dirent.h>
#endif
/* libebml and matroska */
#include "ebml/EbmlHead.h"
#include "ebml/EbmlSubHead.h"
#include "ebml/EbmlStream.h"
#include "ebml/EbmlContexts.h"
#include "ebml/EbmlVoid.h"
#include "ebml/EbmlVersion.h"
#include "ebml/StdIOCallback.h"
#include "matroska/KaxAttachments.h"
#include "matroska/KaxAttached.h"
#include "matroska/KaxBlock.h"
#include "matroska/KaxBlockData.h"
#include "matroska/KaxChapters.h"
#include "matroska/KaxCluster.h"
#include "matroska/KaxClusterData.h"
#include "matroska/KaxContexts.h"
#include "matroska/KaxCues.h"
#include "matroska/KaxCuesData.h"
#include "matroska/KaxInfo.h"
#include "matroska/KaxInfoData.h"
#include "matroska/KaxSeekHead.h"
#include "matroska/KaxSegment.h"
#include "matroska/KaxTag.h"
#include "matroska/KaxTags.h"
#include "matroska/KaxTagMulti.h"
#include "matroska/KaxTracks.h"
#include "matroska/KaxTrackAudio.h"
#include "matroska/KaxTrackVideo.h"
#include "matroska/KaxTrackEntryData.h"
#include "matroska/KaxContentEncoding.h"
#include "matroska/KaxVersion.h"
#include "ebml/StdIOCallback.h"
#include "vlc_keys.h"
extern "C" {
#include "../mp4/libmp4.h"
}
#ifdef HAVE_ZLIB_H
# include <zlib.h>
#endif
/*****************************************************************************
* Module descriptor
*****************************************************************************/
static int Open ( vlc_object_t * );
static void Close( vlc_object_t * );
vlc_module_begin();
set_shortname( "Matroska" );
set_description( N_("Matroska stream demuxer" ) );
set_capability( "demux", 0 );
set_callbacks( Open, Close );
set_category( CAT_INPUT );
set_subcategory( SUBCAT_INPUT_DEMUX );
add_bool( "mkv-use-ordered-chapters", 1, NULL,
N_("Ordered chapters"),
N_("Play ordered chapters as specified in the segment."), true );
add_bool( "mkv-use-chapter-codec", 1, NULL,
N_("Chapter codecs"),
N_("Use chapter codecs found in the segment."), true );
add_bool( "mkv-preload-local-dir", 1, NULL,
N_("Preload Directory"),
N_("Preload matroska files from the same family in the same directory (not good for broken files)."), true );
add_bool( "mkv-seek-percent", 0, NULL,
N_("Seek based on percent not time"),
N_("Seek based on percent not time."), true );
add_bool( "mkv-use-dummy", 0, NULL,
N_("Dummy Elements"),
N_("Read and discard unknown EBML elements (not good for broken files)."), true );
add_shortcut( "mka" );
add_shortcut( "mkv" );
vlc_module_end();
#define MATROSKA_COMPRESSION_NONE -1
#define MATROSKA_COMPRESSION_ZLIB 0
#define MATROSKA_COMPRESSION_BLIB 1
#define MATROSKA_COMPRESSION_LZOX 2
#define MATROSKA_COMPRESSION_HEADER 3
#define MKVD_TIMECODESCALE 1000000
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#undef ATTRIBUTE_PACKED
#undef PRAGMA_PACK_BEGIN
#undef PRAGMA_PACK_END
#if defined(__GNUC__)
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
#define ATTRIBUTE_PACKED __attribute__ ((packed))
#define PRAGMA_PACK 0
#endif
#endif
#if !defined(ATTRIBUTE_PACKED)
#define ATTRIBUTE_PACKED
#define PRAGMA_PACK 1
#endif
#if PRAGMA_PACK
#pragma pack(1)
#endif
/*************************************
* taken from libdvdnav / libdvdread
**************************************/
/**
* DVD Time Information.
*/
typedef struct {
uint8_t hour;
uint8_t minute;
uint8_t second;
uint8_t frame_u; /* The two high bits are the frame rate. */
} ATTRIBUTE_PACKED dvd_time_t;
/**
* User Operations.
*/
typedef struct {
#ifdef WORDS_BIGENDIAN
unsigned char zero : 7; /* 25-31 */
unsigned char video_pres_mode_change : 1; /* 24 */
unsigned char karaoke_audio_pres_mode_change : 1; /* 23 */
unsigned char angle_change : 1;
unsigned char subpic_stream_change : 1;
unsigned char audio_stream_change : 1;
unsigned char pause_on : 1;
unsigned char still_off : 1;
unsigned char button_select_or_activate : 1;
unsigned char resume : 1; /* 16 */
unsigned char chapter_menu_call : 1; /* 15 */
unsigned char angle_menu_call : 1;
unsigned char audio_menu_call : 1;
unsigned char subpic_menu_call : 1;
unsigned char root_menu_call : 1;
unsigned char title_menu_call : 1;
unsigned char backward_scan : 1;
unsigned char forward_scan : 1; /* 8 */
unsigned char next_pg_search : 1; /* 7 */
unsigned char prev_or_top_pg_search : 1;
unsigned char time_or_chapter_search : 1;
unsigned char go_up : 1;
unsigned char stop : 1;
unsigned char title_play : 1;
unsigned char chapter_search_or_play : 1;
unsigned char title_or_time_play : 1; /* 0 */
#else
unsigned char video_pres_mode_change : 1; /* 24 */
unsigned char zero : 7; /* 25-31 */
unsigned char resume : 1; /* 16 */
unsigned char button_select_or_activate : 1;
unsigned char still_off : 1;
unsigned char pause_on : 1;
unsigned char audio_stream_change : 1;
unsigned char subpic_stream_change : 1;
unsigned char angle_change : 1;
unsigned char karaoke_audio_pres_mode_change : 1; /* 23 */
unsigned char forward_scan : 1; /* 8 */
unsigned char backward_scan : 1;
unsigned char title_menu_call : 1;
unsigned char root_menu_call : 1;
unsigned char subpic_menu_call : 1;
unsigned char audio_menu_call : 1;
unsigned char angle_menu_call : 1;
unsigned char chapter_menu_call : 1; /* 15 */
unsigned char title_or_time_play : 1; /* 0 */
unsigned char chapter_search_or_play : 1;
unsigned char title_play : 1;
unsigned char stop : 1;
unsigned char go_up : 1;
unsigned char time_or_chapter_search : 1;
unsigned char prev_or_top_pg_search : 1;
unsigned char next_pg_search : 1; /* 7 */
#endif
} ATTRIBUTE_PACKED user_ops_t;
/**
* Type to store per-command data.
*/
typedef struct {
uint8_t bytes[8];
} ATTRIBUTE_PACKED vm_cmd_t;
#define COMMAND_DATA_SIZE 8
/**
* PCI General Information
*/
typedef struct {
uint32_t nv_pck_lbn; /**< sector address of this nav pack */
uint16_t vobu_cat; /**< 'category' of vobu */
uint16_t zero1; /**< reserved */
user_ops_t vobu_uop_ctl; /**< UOP of vobu */
uint32_t vobu_s_ptm; /**< start presentation time of vobu */
uint32_t vobu_e_ptm; /**< end presentation time of vobu */
uint32_t vobu_se_e_ptm; /**< end ptm of sequence end in vobu */
dvd_time_t e_eltm; /**< Cell elapsed time */
char vobu_isrc[32];
} ATTRIBUTE_PACKED pci_gi_t;
/**
* Non Seamless Angle Information
*/
typedef struct {
uint32_t nsml_agl_dsta[9]; /**< address of destination vobu in AGL_C#n */
} ATTRIBUTE_PACKED nsml_agli_t;
/**
* Highlight General Information
*
* For btngrX_dsp_ty the bits have the following meaning:
* 000b: normal 4/3 only buttons
* XX1b: wide (16/9) buttons
* X1Xb: letterbox buttons
* 1XXb: pan&scan buttons
*/
typedef struct {
uint16_t hli_ss; /**< status, only low 2 bits 0: no buttons, 1: different 2: equal 3: eual except for button cmds */
uint32_t hli_s_ptm; /**< start ptm of hli */
uint32_t hli_e_ptm; /**< end ptm of hli */
uint32_t btn_se_e_ptm; /**< end ptm of button select */
#ifdef WORDS_BIGENDIAN
unsigned char zero1 : 2; /**< reserved */
unsigned char btngr_ns : 2; /**< number of button groups 1, 2 or 3 with 36/18/12 buttons */
unsigned char zero2 : 1; /**< reserved */
unsigned char btngr1_dsp_ty : 3; /**< display type of subpic stream for button group 1 */
unsigned char zero3 : 1; /**< reserved */
unsigned char btngr2_dsp_ty : 3; /**< display type of subpic stream for button group 2 */
unsigned char zero4 : 1; /**< reserved */
unsigned char btngr3_dsp_ty : 3; /**< display type of subpic stream for button group 3 */
#else
unsigned char btngr1_dsp_ty : 3;
unsigned char zero2 : 1;
unsigned char btngr_ns : 2;
unsigned char zero1 : 2;
unsigned char btngr3_dsp_ty : 3;
unsigned char zero4 : 1;
unsigned char btngr2_dsp_ty : 3;
unsigned char zero3 : 1;
#endif
uint8_t btn_ofn; /**< button offset number range 0-255 */
uint8_t btn_ns; /**< number of valid buttons <= 36/18/12 (low 6 bits) */
uint8_t nsl_btn_ns; /**< number of buttons selectable by U_BTNNi (low 6 bits) nsl_btn_ns <= btn_ns */
uint8_t zero5; /**< reserved */
uint8_t fosl_btnn; /**< forcedly selected button (low 6 bits) */
uint8_t foac_btnn; /**< forcedly activated button (low 6 bits) */
} ATTRIBUTE_PACKED hl_gi_t;
/**
* Button Color Information Table
* Each entry beeing a 32bit word that contains the color indexs and alpha
* values to use. They are all represented by 4 bit number and stored
* like this [Ci3, Ci2, Ci1, Ci0, A3, A2, A1, A0]. The actual palette
* that the indexes reference is in the PGC.
* \todo split the uint32_t into a struct
*/
typedef struct {
uint32_t btn_coli[3][2]; /**< [button color number-1][select:0/action:1] */
} ATTRIBUTE_PACKED btn_colit_t;
/**
* Button Information
*
* NOTE: I've had to change the structure from the disk layout to get
* the packing to work with Sun's Forte C compiler.
* The 4 and 7 bytes are 'rotated' was: ABC DEF GHIJ is: ABCG DEFH IJ
*/
typedef struct {
#ifdef WORDS_BIGENDIAN
uint32 btn_coln : 2; /**< button color number */
uint32 x_start : 10; /**< x start offset within the overlay */
uint32 zero1 : 2; /**< reserved */
uint32 x_end : 10; /**< x end offset within the overlay */
uint32 zero3 : 2; /**< reserved */
uint32 up : 6; /**< button index when pressing up */
uint32 auto_action_mode : 2; /**< 0: no, 1: activated if selected */
uint32 y_start : 10; /**< y start offset within the overlay */
uint32 zero2 : 2; /**< reserved */
uint32 y_end : 10; /**< y end offset within the overlay */
uint32 zero4 : 2; /**< reserved */
uint32 down : 6; /**< button index when pressing down */
unsigned char zero5 : 2; /**< reserved */
unsigned char left : 6; /**< button index when pressing left */
unsigned char zero6 : 2; /**< reserved */
unsigned char right : 6; /**< button index when pressing right */
#else
uint32 x_end : 10;
uint32 zero1 : 2;
uint32 x_start : 10;
uint32 btn_coln : 2;
uint32 up : 6;
uint32 zero3 : 2;
uint32 y_end : 10;
uint32 zero2 : 2;
uint32 y_start : 10;
uint32 auto_action_mode : 2;
uint32 down : 6;
uint32 zero4 : 2;
unsigned char left : 6;
unsigned char zero5 : 2;
unsigned char right : 6;
unsigned char zero6 : 2;
#endif
vm_cmd_t cmd;
} ATTRIBUTE_PACKED btni_t;
/**
* Highlight Information
*/
typedef struct {
hl_gi_t hl_gi;
btn_colit_t btn_colit;
btni_t btnit[36];
} ATTRIBUTE_PACKED hli_t;
/**
* PCI packet
*/
typedef struct {
pci_gi_t pci_gi;
nsml_agli_t nsml_agli;
hli_t hli;
uint8_t zero1[189];
} ATTRIBUTE_PACKED pci_t;
#if PRAGMA_PACK
#pragma pack()
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* What's between a directory and a filename?
*/
#if defined( WIN32 )
#define DIRECTORY_SEPARATOR '\\'
#else
#define DIRECTORY_SEPARATOR '/'
#endif
using namespace LIBMATROSKA_NAMESPACE;
using namespace std;
/*****************************************************************************
* Local prototypes
*****************************************************************************/
#ifdef HAVE_ZLIB_H
block_t *block_zlib_decompress( vlc_object_t *p_this, block_t *p_in_block ) {
int result, dstsize, n;
unsigned char *dst;
block_t *p_block;
z_stream d_stream;
d_stream.zalloc = (alloc_func)0;
d_stream.zfree = (free_func)0;
d_stream.opaque = (voidpf)0;
result = inflateInit(&d_stream);
if( result != Z_OK )
{
msg_Dbg( p_this, "inflateInit() failed. Result: %d", result );
return NULL;
}
d_stream.next_in = (Bytef *)p_in_block->p_buffer;
d_stream.avail_in = p_in_block->i_buffer;
n = 0;
p_block = block_New( p_this, 0 );
dst = NULL;
do
{
n++;
p_block = block_Realloc( p_block, 0, n * 1000 );
dst = (unsigned char *)p_block->p_buffer;
d_stream.next_out = (Bytef *)&dst[(n - 1) * 1000];
d_stream.avail_out = 1000;
result = inflate(&d_stream, Z_NO_FLUSH);
if( ( result != Z_OK ) && ( result != Z_STREAM_END ) )
{
msg_Dbg( p_this, "Zlib decompression failed. Result: %d", result );
return NULL;
}
}
while( ( d_stream.avail_out == 0 ) && ( d_stream.avail_in != 0 ) &&
( result != Z_STREAM_END ) );
dstsize = d_stream.total_out;
inflateEnd( &d_stream );
p_block = block_Realloc( p_block, 0, dstsize );
p_block->i_buffer = dstsize;
block_Release( p_in_block );
return p_block;
}
#endif
/**
* Helper function to print the mkv parse tree
*/
static void MkvTree( demux_t & demuxer, int i_level, const char *psz_format, ... )
{
va_list args;
if( i_level > 9 )
{
msg_Err( &demuxer, "too deep tree" );
return;
}
va_start( args, psz_format );
static const char psz_foo[] = "| | | | | | | | | |";
char *psz_foo2 = (char*)malloc( ( i_level * 4 + 3 + strlen( psz_format ) ) * sizeof(char) );
strncpy( psz_foo2, psz_foo, 4 * i_level );
psz_foo2[ 4 * i_level ] = '+';
psz_foo2[ 4 * i_level + 1 ] = ' ';
strcpy( &psz_foo2[ 4 * i_level + 2 ], psz_format );
__msg_GenericVa( VLC_OBJECT(&demuxer),VLC_MSG_DBG, "mkv", psz_foo2, args );
free( psz_foo2 );
va_end( args );
}
/*****************************************************************************
* Stream managment
*****************************************************************************/
class vlc_stream_io_callback: public IOCallback
{
private:
stream_t *s;
bool mb_eof;
bool b_owner;
public:
vlc_stream_io_callback( stream_t *, bool );
virtual ~vlc_stream_io_callback()
{
if( b_owner )
stream_Delete( s );
}
virtual uint32 read ( void *p_buffer, size_t i_size);
virtual void setFilePointer ( int64_t i_offset, seek_mode mode = seek_beginning );
virtual size_t write ( const void *p_buffer, size_t i_size);
virtual uint64 getFilePointer ( void );
virtual void close ( void );
};
/*****************************************************************************
* Ebml Stream parser
*****************************************************************************/
class EbmlParser
{
public:
EbmlParser( EbmlStream *es, EbmlElement *el_start, demux_t *p_demux );
virtual ~EbmlParser( void );
void Up( void );
void Down( void );
void Reset( demux_t *p_demux );
EbmlElement *Get( void );
void Keep( void );
EbmlElement *UnGet( uint64 i_block_pos, uint64 i_cluster_pos );
int GetLevel( void );
/* Is the provided element presents in our upper elements */
bool IsTopPresent( EbmlElement * );
private:
EbmlStream *m_es;
int mi_level;
EbmlElement *m_el[10];
int64_t mi_remain_size[10];
EbmlElement *m_got;
int mi_user_level;
bool mb_keep;
bool mb_dummy;
};
/*****************************************************************************
* Some functions to manipulate memory
*****************************************************************************/
#define GetFOURCC( p ) __GetFOURCC( (uint8_t*)p )
static vlc_fourcc_t __GetFOURCC( uint8_t *p )
{
return VLC_FOURCC( p[0], p[1], p[2], p[3] );
}
/*****************************************************************************
* definitions of structures and functions used by this plugins
*****************************************************************************/
typedef struct
{
// ~mkv_track_t();
bool b_default;
bool b_enabled;
unsigned int i_number;
int i_extra_data;
uint8_t *p_extra_data;
char *psz_codec;
uint64_t i_default_duration;
float f_timecodescale;
mtime_t i_last_dts;
/* video */
es_format_t fmt;
float f_fps;
es_out_id_t *p_es;
/* audio */
unsigned int i_original_rate;
bool b_inited;
/* data to be send first */
int i_data_init;
uint8_t *p_data_init;
/* hack : it's for seek */
bool b_search_keyframe;
bool b_silent;
/* informative */
const char *psz_codec_name;
const char *psz_codec_settings;
const char *psz_codec_info_url;
const char