Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc
Commits
72be09f0
Commit
72be09f0
authored
Mar 17, 2005
by
Steve Lhomme
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
mkv.cpp: allow seamless transition between segments
parent
77a1a288
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
425 additions
and
390 deletions
+425
-390
modules/demux/mkv.cpp
modules/demux/mkv.cpp
+425
-390
No files found.
modules/demux/mkv.cpp
View file @
72be09f0
...
...
@@ -507,6 +507,8 @@ public:
void
ParseTrackEntry
(
EbmlMaster
*
m
);
void
IndexAppendCluster
(
KaxCluster
*
cluster
);
int
BlockGet
(
KaxBlock
**
pp_block
,
int64_t
*
pi_ref1
,
int64_t
*
pi_ref2
,
int64_t
*
pi_duration
);
bool
Select
(
);
void
UnSelect
(
);
};
class
matroska_stream_t
...
...
@@ -542,7 +544,7 @@ public:
return
NULL
;
}
matroska_segment_t
*
FindSegment
(
EbmlBinary
&
uid
)
const
;
matroska_segment_t
*
FindSegment
(
const
EbmlBinary
&
uid
)
const
;
void
PreloadFamily
(
const
matroska_segment_t
&
segment
);
size_t
PreloadLinked
(
const
demux_sys_t
&
of_sys
);
...
...
@@ -588,7 +590,7 @@ public:
return
NULL
;
}
matroska_segment_t
*
FindSegment
(
EbmlBinary
&
uid
)
const
;
matroska_segment_t
*
FindSegment
(
const
EbmlBinary
&
uid
)
const
;
void
PreloadFamily
(
);
void
PreloadLinked
(
);
matroska_stream_t
*
AnalyseAllSegmentsFound
(
EbmlStream
*
p_estream
);
...
...
@@ -615,7 +617,6 @@ static int Open( vlc_object_t * p_this )
matroska_segment_t
*
p_segment
;
uint8_t
*
p_peek
;
std
::
string
s_path
,
s_filename
;
size_t
i_track
;
vlc_stream_io_callback
*
p_io_callback
;
EbmlStream
*
p_io_stream
;
...
...
@@ -758,758 +759,787 @@ static int Open( vlc_object_t * p_this )
p_segment
->
b_cues
=
VLC_FALSE
;
}
/* add all es */
msg_Dbg
(
p_demux
,
"found %d es"
,
p_segment
->
tracks
.
size
()
);
for
(
i_track
=
0
;
i_track
<
p_segment
->
tracks
.
size
();
i_track
++
)
{
#define tk p_segment->tracks[i_track]
if
(
tk
->
fmt
.
i_cat
==
UNKNOWN_ES
)
if
(
!
p_segment
->
Select
()
)
{
msg_Warn
(
p_demux
,
"invalid track[%d, n=%d]"
,
i_track
,
tk
->
i_number
);
tk
->
p_es
=
NULL
;
continue
;
msg_Err
(
p_demux
,
"cannot use the segment"
);
goto
error
;
}
if
(
!
strcmp
(
tk
->
psz_codec
,
"V_MS/VFW/FOURCC"
)
)
/* add information */
InformationCreate
(
p_demux
);
return
VLC_SUCCESS
;
error:
delete
p_sys
;
return
VLC_EGENERIC
;
}
/*****************************************************************************
* Close: frees unused data
*****************************************************************************/
static
void
Close
(
vlc_object_t
*
p_this
)
{
demux_t
*
p_demux
=
(
demux_t
*
)
p_this
;
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
matroska_stream_t
*
p_stream
=
p_sys
->
Stream
();
matroska_segment_t
*
p_segment
=
p_stream
->
Segment
();
/* TODO close everything ? */
delete
p_segment
->
segment
;
delete
p_sys
;
}
/*****************************************************************************
* Control:
*****************************************************************************/
static
int
Control
(
demux_t
*
p_demux
,
int
i_query
,
va_list
args
)
{
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
matroska_stream_t
*
p_stream
=
p_sys
->
Stream
();
matroska_segment_t
*
p_segment
=
p_stream
->
Segment
();
int64_t
*
pi64
;
double
*
pf
,
f
;
int
i_skp
;
vlc_meta_t
**
pp_meta
;
switch
(
i_query
)
{
if
(
tk
->
i_extra_data
<
(
int
)
sizeof
(
BITMAPINFOHEADER
)
)
case
DEMUX_GET_META
:
pp_meta
=
(
vlc_meta_t
**
)
va_arg
(
args
,
vlc_meta_t
**
);
*
pp_meta
=
vlc_meta_Duplicate
(
p_sys
->
meta
);
return
VLC_SUCCESS
;
case
DEMUX_GET_LENGTH
:
pi64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
if
(
p_segment
->
f_duration
>
0.0
)
{
msg_Err
(
p_demux
,
"missing/invalid BITMAPINFOHEADER"
);
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'u'
,
'n'
,
'd'
,
'f'
)
;
*
pi64
=
(
int64_t
)(
p_segment
->
f_duration
*
1000
);
return
VLC_SUCCESS
;
}
else
return
VLC_EGENERIC
;
case
DEMUX_GET_POSITION
:
pf
=
(
double
*
)
va_arg
(
args
,
double
*
);
*
pf
=
(
double
)
p_sys
->
i_pts
/
(
1000.0
*
p_segment
->
f_duration
);
return
VLC_SUCCESS
;
case
DEMUX_SET_POSITION
:
f
=
(
double
)
va_arg
(
args
,
double
);
Seek
(
p_demux
,
-
1
,
f
,
NULL
);
return
VLC_SUCCESS
;
case
DEMUX_GET_TIME
:
pi64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
*
pi64
=
p_sys
->
i_pts
;
return
VLC_SUCCESS
;
case
DEMUX_GET_TITLE_INFO
:
if
(
p_sys
->
title
&&
p_sys
->
title
->
i_seekpoint
>
0
)
{
BITMAPINFOHEADER
*
p_bih
=
(
BITMAPINFOHEADER
*
)
tk
->
p_extra_data
;
input_title_t
***
ppp_title
=
(
input_title_t
***
)
va_arg
(
args
,
input_title_t
***
);
int
*
pi_int
=
(
int
*
)
va_arg
(
args
,
int
*
);
tk
->
fmt
.
video
.
i_width
=
GetDWLE
(
&
p_bih
->
biWidth
);
tk
->
fmt
.
video
.
i_height
=
GetDWLE
(
&
p_bih
->
biHeight
);
tk
->
fmt
.
i_codec
=
GetFOURCC
(
&
p_bih
->
biCompression
);
*
pi_int
=
1
;
*
ppp_title
=
(
input_title_t
**
)
malloc
(
sizeof
(
input_title_t
**
)
);
tk
->
fmt
.
i_extra
=
GetDWLE
(
&
p_bih
->
biSize
)
-
sizeof
(
BITMAPINFOHEADER
);
if
(
tk
->
fmt
.
i_extra
>
0
)
(
*
ppp_title
)[
0
]
=
vlc_input_title_Duplicate
(
p_sys
->
title
);
return
VLC_SUCCESS
;
}
return
VLC_EGENERIC
;
case
DEMUX_SET_TITLE
:
/* TODO handle editions as titles & DVD titles as well */
if
(
p_sys
->
title
&&
p_sys
->
title
->
i_seekpoint
>
0
)
{
tk
->
fmt
.
p_extra
=
malloc
(
tk
->
fmt
.
i_extra
);
memcpy
(
tk
->
fmt
.
p_extra
,
&
p_bih
[
1
],
tk
->
fmt
.
i_extra
);
return
VLC_SUCCESS
;
}
return
VLC_EGENERIC
;
case
DEMUX_SET_SEEKPOINT
:
/* FIXME do a better implementation */
i_skp
=
(
int
)
va_arg
(
args
,
int
);
if
(
p_sys
->
title
&&
i_skp
<
p_sys
->
title
->
i_seekpoint
)
{
Seek
(
p_demux
,
(
int64_t
)
p_sys
->
title
->
seekpoint
[
i_skp
]
->
i_time_offset
,
-
1
,
NULL
);
p_demux
->
info
.
i_seekpoint
|=
INPUT_UPDATE_SEEKPOINT
;
p_demux
->
info
.
i_seekpoint
=
i_skp
;
return
VLC_SUCCESS
;
}
return
VLC_EGENERIC
;
case
DEMUX_SET_TIME
:
case
DEMUX_GET_FPS
:
default:
return
VLC_EGENERIC
;
}
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"V_MPEG1"
)
||
!
strcmp
(
tk
->
psz_codec
,
"V_MPEG2"
)
)
}
int
matroska_segment_t
::
BlockGet
(
KaxBlock
**
pp_block
,
int64_t
*
pi_ref1
,
int64_t
*
pi_ref2
,
int64_t
*
pi_duration
)
{
*
pp_block
=
NULL
;
*
pi_ref1
=
-
1
;
*
pi_ref2
=
-
1
;
for
(
;;
)
{
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'v'
);
EbmlElement
*
el
;
int
i_level
;
if
(
sys
.
demuxer
.
b_die
)
{
return
VLC_EGENERIC
;
}
else
if
(
!
strncmp
(
tk
->
psz_codec
,
"V_MPEG4"
,
7
)
)
el
=
ep
->
Get
();
i_level
=
ep
->
GetLevel
();
if
(
el
==
NULL
&&
*
pp_block
!=
NULL
)
{
if
(
!
strcmp
(
tk
->
psz_codec
,
"V_MPEG4/MS/V3"
)
)
/* update the index */
#define idx index[i_index - 1]
if
(
i_index
>
0
&&
idx
.
i_time
==
-
1
)
{
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'D'
,
'I'
,
'V'
,
'3'
);
idx
.
i_time
=
(
*
pp_block
)
->
GlobalTimecode
()
/
(
mtime_t
)
1000
;
idx
.
b_key
=
*
pi_ref1
==
-
1
?
VLC_TRUE
:
VLC_FALSE
;
}
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"V_MPEG4/ISO/AVC"
)
)
{
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'a'
,
'v'
,
'c'
,
'1'
);
tk
->
fmt
.
b_packetized
=
VLC_FALSE
;
tk
->
fmt
.
i_extra
=
tk
->
i_extra_data
;
tk
->
fmt
.
p_extra
=
malloc
(
tk
->
i_extra_data
);
memcpy
(
tk
->
fmt
.
p_extra
,
tk
->
p_extra_data
,
tk
->
i_extra_data
);
#undef idx
return
VLC_SUCCESS
;
}
else
if
(
el
==
NULL
)
{
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'v'
);
if
(
ep
->
GetLevel
()
>
1
)
{
ep
->
Up
();
continue
;
}
msg_Warn
(
&
sys
.
demuxer
,
"EOF"
);
return
VLC_EGENERIC
;
}
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"V_QUICKTIME"
)
)
/* do parsing */
if
(
i_level
==
1
)
{
MP4_Box_t
*
p_box
=
(
MP4_Box_t
*
)
malloc
(
sizeof
(
MP4_Box_t
)
);
stream_t
*
p_mp4_stream
=
stream_MemoryNew
(
VLC_OBJECT
(
p_demux
),
tk
->
p_extra_data
,
tk
->
i_extra_data
);
MP4_ReadBoxCommon
(
p_mp4_stream
,
p_box
);
MP4_ReadBox_sample_vide
(
p_mp4_stream
,
p_box
);
tk
->
fmt
.
i_codec
=
p_box
->
i_type
;
tk
->
fmt
.
video
.
i_width
=
p_box
->
data
.
p_sample_vide
->
i_width
;
tk
->
fmt
.
video
.
i_height
=
p_box
->
data
.
p_sample_vide
->
i_height
;
tk
->
fmt
.
i_extra
=
p_box
->
data
.
p_sample_vide
->
i_qt_image_description
;
tk
->
fmt
.
p_extra
=
malloc
(
tk
->
fmt
.
i_extra
);
memcpy
(
tk
->
fmt
.
p_extra
,
p_box
->
data
.
p_sample_vide
->
p_qt_image_description
,
tk
->
fmt
.
i_extra
);
MP4_FreeBox_sample_vide
(
p_box
);
stream_MemoryDelete
(
p_mp4_stream
,
VLC_TRUE
);
}
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"A_MS/ACM"
)
)
if
(
MKV_IS_ID
(
el
,
KaxCluster
)
)
{
if
(
tk
->
i_extra_data
<
(
int
)
sizeof
(
WAVEFORMATEX
)
)
cluster
=
(
KaxCluster
*
)
el
;
/* add it to the index */
if
(
i_index
==
0
||
(
i_index
>
0
&&
index
[
i_index
-
1
].
i_position
<
(
int64_t
)
cluster
->
GetElementPosition
()
)
)
{
msg_Err
(
p_demux
,
"missing/invalid WAVEFORMATEX"
);
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'u'
,
'n'
,
'd'
,
'f'
);
IndexAppendCluster
(
cluster
);
}
else
{
WAVEFORMATEX
*
p_wf
=
(
WAVEFORMATEX
*
)
tk
->
p_extra_data
;
wf_tag_to_fourcc
(
GetWLE
(
&
p_wf
->
wFormatTag
),
&
tk
->
fmt
.
i_codec
,
NULL
);
tk
->
fmt
.
audio
.
i_channels
=
GetWLE
(
&
p_wf
->
nChannels
);
tk
->
fmt
.
audio
.
i_rate
=
GetDWLE
(
&
p_wf
->
nSamplesPerSec
);
tk
->
fmt
.
i_bitrate
=
GetDWLE
(
&
p_wf
->
nAvgBytesPerSec
)
*
8
;
tk
->
fmt
.
audio
.
i_blockalign
=
GetWLE
(
&
p_wf
->
nBlockAlign
);;
tk
->
fmt
.
audio
.
i_bitspersample
=
GetWLE
(
&
p_wf
->
wBitsPerSample
);
tk
->
fmt
.
i_extra
=
GetWLE
(
&
p_wf
->
cbSize
);
if
(
tk
->
fmt
.
i_extra
>
0
)
// reset silent tracks
for
(
size_t
i
=
0
;
i
<
tracks
.
size
();
i
++
)
{
tk
->
fmt
.
p_extra
=
malloc
(
tk
->
fmt
.
i_extra
);
memcpy
(
tk
->
fmt
.
p_extra
,
&
p_wf
[
1
],
tk
->
fmt
.
i_extra
);
tracks
[
i
]
->
b_silent
=
VLC_FALSE
;
}
ep
->
Down
();
}
else
if
(
MKV_IS_ID
(
el
,
KaxCues
)
)
{
msg_Warn
(
&
sys
.
demuxer
,
"find KaxCues FIXME"
);
return
VLC_EGENERIC
;
}
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"A_MPEG/L3"
)
||
!
strcmp
(
tk
->
psz_codec
,
"A_MPEG/L2"
)
||
!
strcmp
(
tk
->
psz_codec
,
"A_MPEG/L1"
)
)
else
{
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'a'
);
msg_Dbg
(
&
sys
.
demuxer
,
"unknown (%s)"
,
typeid
(
el
).
name
()
);
}
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"A_AC3"
)
)
}
else
if
(
i_level
==
2
)
{
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'a'
,
'5'
,
'2'
,
' '
);
if
(
MKV_IS_ID
(
el
,
KaxClusterTimecode
)
)
{
KaxClusterTimecode
&
ctc
=
*
(
KaxClusterTimecode
*
)
el
;
ctc
.
ReadData
(
es
.
I_O
(),
SCOPE_ALL_DATA
);
cluster
->
InitTimecode
(
uint64
(
ctc
),
i_timescale
);
}
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"A_DTS"
)
)
else
if
(
MKV_IS_ID
(
el
,
KaxClusterSilentTracks
)
)
{
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'd'
,
't'
,
's'
,
' '
);
ep
->
Down
(
);
}
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"A_FLAC"
)
)
else
if
(
MKV_IS_ID
(
el
,
KaxBlockGroup
)
)
{
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'f'
,
'l'
,
'a'
,
'c'
);
tk
->
fmt
.
i_extra
=
tk
->
i_extra_data
;
tk
->
fmt
.
p_extra
=
malloc
(
tk
->
i_extra_data
);
memcpy
(
tk
->
fmt
.
p_extra
,
tk
->
p_extra_data
,
tk
->
i_extra_data
);
ep
->
Down
();
}
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"A_VORBIS"
)
)
}
else
if
(
i_level
==
3
)
{
int
i
,
i_offset
=
1
,
i_size
[
3
],
i_extra
;
uint8_t
*
p_extra
;
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'v'
,
'o'
,
'r'
,
'b'
);
/* Split the 3 headers */
if
(
tk
->
p_extra_data
[
0
]
!=
0x02
)
msg_Err
(
p_demux
,
"invalid vorbis header"
);
for
(
i
=
0
;
i
<
2
;
i
++
)
{
i_size
[
i
]
=
0
;
while
(
i_offset
<
tk
->
i_extra_data
)
if
(
MKV_IS_ID
(
el
,
KaxBlock
)
)
{
i_size
[
i
]
+=
tk
->
p_extra_data
[
i_offset
];
if
(
tk
->
p_extra_data
[
i_offset
++
]
!=
0xff
)
break
;
}
}
*
pp_block
=
(
KaxBlock
*
)
el
;
i_size
[
0
]
=
__MIN
(
i_size
[
0
],
tk
->
i_extra_data
-
i_offset
);
i_size
[
1
]
=
__MIN
(
i_size
[
1
],
tk
->
i_extra_data
-
i_offset
-
i_size
[
0
]);
i_size
[
2
]
=
tk
->
i_extra_data
-
i_offset
-
i_size
[
0
]
-
i_size
[
1
];
(
*
pp_block
)
->
ReadData
(
es
.
I_O
()
);
(
*
pp_block
)
->
SetParent
(
*
cluster
);
tk
->
fmt
.
i_extra
=
3
*
2
+
i_size
[
0
]
+
i_size
[
1
]
+
i_size
[
2
];
tk
->
fmt
.
p_extra
=
malloc
(
tk
->
fmt
.
i_extra
);
p_extra
=
(
uint8_t
*
)
tk
->
fmt
.
p_extra
;
i_extra
=
0
;
for
(
i
=
0
;
i
<
3
;
i
++
)
{
*
(
p_extra
++
)
=
i_size
[
i
]
>>
8
;
*
(
p_extra
++
)
=
i_size
[
i
]
&
0xFF
;
memcpy
(
p_extra
,
tk
->
p_extra_data
+
i_offset
+
i_extra
,
i_size
[
i
]
);
p_extra
+=
i_size
[
i
];
i_extra
+=
i_size
[
i
];
}
ep
->
Keep
();
}
else
if
(
!
strncmp
(
tk
->
psz_codec
,
"A_AAC/MPEG2/"
,
strlen
(
"A_AAC/MPEG2/"
)
)
||
!
strncmp
(
tk
->
psz_codec
,
"A_AAC/MPEG4/"
,
strlen
(
"A_AAC/MPEG4/"
)
)
)
{
int
i_profile
,
i_srate
;
static
unsigned
int
i_sample_rates
[]
=
else
if
(
MKV_IS_ID
(
el
,
KaxBlockDuration
)
)
{
96000
,
88200
,
64000
,
48000
,
44100
,
32000
,
24000
,
22050
,
16000
,
12000
,
11025
,
8000
,
7350
,
0
,
0
,
0
};
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
);
/* create data for faad (MP4DecSpecificDescrTag)*/
KaxBlockDuration
&
dur
=
*
(
KaxBlockDuration
*
)
el
;
if
(
!
strcmp
(
&
tk
->
psz_codec
[
12
],
"MAIN"
)
)
{
i_profile
=
0
;
}
else
if
(
!
strcmp
(
&
tk
->
psz_codec
[
12
],
"LC"
)
)
{
i_profile
=
1
;
}
else
if
(
!
strcmp
(
&
tk
->
psz_codec
[
12
],
"SSR"
)
)
{
i_profile
=
2
;
}
else
{
i_profile
=
3
;
dur
.
ReadData
(
es
.
I_O
()
);
*
pi_duration
=
uint64
(
dur
);
}
for
(
i_srate
=
0
;
i_srate
<
13
;
i_srate
++
)
{
if
(
i_sample_rates
[
i_srate
]
==
tk
->
fmt
.
audio
.
i_rate
)
else
if
(
MKV_IS_ID
(
el
,
KaxReferenceBlock
)
)
{
break
;
}
}
msg_Dbg
(
p_demux
,
"profile=%d srate=%d"
,
i_profile
,
i_srate
);
KaxReferenceBlock
&
ref
=
*
(
KaxReferenceBlock
*
)
el
;
tk
->
fmt
.
i_extra
=
2
;
tk
->
fmt
.
p_extra
=
malloc
(
tk
->
fmt
.
i_extra
);
((
uint8_t
*
)
tk
->
fmt
.
p_extra
)[
0
]
=
((
i_profile
+
1
)
<<
3
)
|
((
i_srate
&
0xe
)
>>
1
);
((
uint8_t
*
)
tk
->
fmt
.
p_extra
)[
1
]
=
((
i_srate
&
0x1
)
<<
7
)
|
(
tk
->
fmt
.
audio
.
i_channels
<<
3
);
}
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"A_PCM/INT/BIG"
)
||
!
strcmp
(
tk
->
psz_codec
,
"A_PCM/INT/LIT"
)
||
!
strcmp
(
tk
->
psz_codec
,
"A_PCM/FLOAT/IEEE"
)
)
{
if
(
!
strcmp
(
tk
->
psz_codec
,
"A_PCM/INT/BIG"
)
)
ref
.
ReadData
(
es
.
I_O
()
);
if
(
*
pi_ref1
==
-
1
)
{
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
't'
,
'w'
,
'o'
,
's'
);
*
pi_ref1
=
int64
(
ref
);
}
else
{
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'a'
,
'r'
,
'a'
,
'w'
);
}
tk
->
fmt
.
audio
.
i_blockalign
=
(
tk
->
fmt
.
audio
.
i_bitspersample
+
7
)
/
8
*
tk
->
fmt
.
audio
.
i_channels
;
}
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"A_TTA1"
)
)
{
/* FIXME: support this codec */
msg_Err
(
p_demux
,
"TTA not supported yet[%d, n=%d]"
,
i_track
,
tk
->
i_number
);
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'u'
,
'n'
,
'd'
,
'f'
);
}
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"A_WAVPACK4"
)
)
{
/* FIXME: support this codec */
msg_Err
(
p_demux
,
"Wavpack not supported yet[%d, n=%d]"
,
i_track
,
tk
->
i_number
);
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'u'
,
'n'
,
'd'
,
'f'
);
}
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"S_TEXT/UTF8"
)
)
{
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
's'
,
'u'
,
'b'
,
't'
);
tk
->
fmt
.
subs
.
psz_encoding
=
strdup
(
"UTF-8"
);
*
pi_ref2
=
int64
(
ref
);
}
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"S_TEXT/SSA"
)
||
!
strcmp
(
tk
->
psz_codec
,
"S_TEXT/ASS"
)
||
!
strcmp
(
tk
->
psz_codec
,
"S_SSA"
)
||
!
strcmp
(
tk
->
psz_codec
,
"S_ASS"
))
{
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
's'
,
's'
,
'a'
,
' '
);
tk
->
fmt
.
subs
.
psz_encoding
=
strdup
(
"UTF-8"
);
}
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"S_VOBSUB"
)
)
{
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
's'
,
'p'
,
'u'
,
' '
);
if
(
tk
->
i_extra_data
)
else
if
(
MKV_IS_ID
(
el
,
KaxClusterSilentTrackNumber
)
)
{
char
*
p_start
;
char
*
p_buf
=
(
char
*
)
malloc
(
tk
->
i_extra_data
+
1
);
memcpy
(
p_buf
,
tk
->
p_extra_data
,
tk
->
i_extra_data
);
p_buf
[
tk
->
i_extra_data
]
=
'\0'
;
p_start
=
strstr
(
p_buf
,
"size:"
);
if
(
sscanf
(
p_start
,
"size: %dx%d"
,
&
tk
->
fmt
.
subs
.
spu
.
i_original_frame_width
,
&
tk
->
fmt
.
subs
.
spu
.
i_original_frame_height
)
==
2
)
KaxClusterSilentTrackNumber
&
track_num
=
*
(
KaxClusterSilentTrackNumber
*
)
el
;
track_num
.
ReadData
(
es
.
I_O
()
);
// find the track
for
(
size_t
i
=
0
;
i
<
tracks
.
size
();
i
++
)
{
msg_Dbg
(
p_demux
,
"original frame size vobsubs: %dx%d"
,
tk
->
fmt
.
subs
.
spu
.
i_original_frame_width
,
tk
->
fmt
.
subs
.
spu
.
i_original_frame_height
);
}
else
if
(
tracks
[
i
]
->
i_number
==
uint32
(
track_num
))
{
msg_Warn
(
p_demux
,
"reading original frame size for vobsub failed"
);
tracks
[
i
]
->
b_silent
=
VLC_TRUE
;
break
;
}
free
(
p_buf
);
}
}
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"B_VOBBTN"
)
)
{
/* FIXME: support this codec */
msg_Err
(
p_demux
,
"Vob Buttons not supported yet[%d, n=%d]"
,
i_track
,
tk
->
i_number
);
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'u'
,
'n'
,
'd'
,
'f'
);
}
else
{
msg_Err
(
p_demux
,
"unknow codec id=`%s'"
,
tk
->
psz_codec
);
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'u'
,
'n'
,
'd'
,
'f'
);
}
if
(
tk
->
b_default
)
{
tk
->
fmt
.
i_priority
=
1000
;
msg_Err
(
&
sys
.
demuxer
,
"invalid level = %d"
,
i_level
);
return
VLC_EGENERIC
;
}
tk
->
p_es
=
es_out_Add
(
p_demux
->
out
,
&
tk
->
fmt
);
#undef tk
}
/* add information */
InformationCreate
(
p_demux
);
return
VLC_SUCCESS
;
error:
delete
p_sys
;
return
VLC_EGENERIC
;
}
/*****************************************************************************
* Close: frees unused data
*****************************************************************************/
static
void
Close
(
vlc_object_t
*
p_this
)
static
block_t
*
MemToBlock
(
demux_t
*
p_demux
,
uint8_t
*
p_mem
,
int
i_mem
)
{
demux_t
*
p_demux
=
(
demux_t
*
)
p_this
;
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
matroska_stream_t
*
p_stream
=
p_sys
->
Stream
();
matroska_segment_t
*
p_segment
=
p_stream
->
Segment
();
/* TODO close everything ? */
delete
p_segment
->
segment
;
delete
p_sys
;
block_t
*
p_block
;
if
(
!
(
p_block
=
block_New
(
p_demux
,
i_mem
)
)
)
return
NULL
;
memcpy
(
p_block
->
p_buffer
,
p_mem
,
i_mem
);
//p_block->i_rate = p_input->stream.control.i_rate;
return
p_block
;
}
/*****************************************************************************
* Control:
*****************************************************************************/
static
int
Control
(
demux_t
*
p_demux
,
int
i_query
,
va_list
args
)
static
void
BlockDecode
(
demux_t
*
p_demux
,
KaxBlock
*
block
,
mtime_t
i_pts
,
mtime_t
i_duration
)
{
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
matroska_stream_t
*
p_stream
=
p_sys
->
Stream
();
matroska_segment_t
*
p_segment
=
p_stream
->
Segment
();
int64_t
*
pi64
;
double
*
pf
,
f
;
int
i_skp
;
vlc_meta_t
**
pp_meta
;
size_t
i_track
;
unsigned
int
i
;
vlc_bool_t
b
;
switch
(
i_query
)
#define tk p_segment->tracks[i_track]
for
(
i_track
=
0
;
i_track
<
p_segment
->
tracks
.
size
();
i_track
++
)
{
case
DEMUX_GET_META
:
pp_meta
=
(
vlc_meta_t
**
)
va_arg
(
args
,
vlc_meta_t
**
);
*
pp_meta
=
vlc_meta_Duplicate
(
p_sys
->
meta
);
return
VLC_SUCCESS
;
if
(
tk
->
i_number
==
block
->
TrackNum
()
)
{
break
;
}
}
case
DEMUX_GET_LENGTH
:
pi64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
if
(
p_segment
->
f_duration
>
0.0
)
if
(
i_track
>=
p_segment
->
tracks
.
size
()
)
{
*
pi64
=
(
int64_t
)(
p_segment
->
f_duration
*
1000
);
return
VLC_SUCCESS
;
msg_Err
(
p_demux
,
"invalid track number=%d"
,
block
->
TrackNum
()
);
return
;
}
if
(
tk
->
p_es
==
NULL
)
{
msg_Err
(
p_demux
,
"unknown track number=%d"
,
block
->
TrackNum
()
);
return
;
}
if
(
i_pts
<
p_sys
->
i_start_pts
&&
tk
->
fmt
.
i_cat
==
AUDIO_ES
)
{
return
;
/* discard audio packets that shouldn't be rendered */
}
return
VLC_EGENERIC
;
case
DEMUX_GET_POSITION
:
pf
=
(
double
*
)
va_arg
(
args
,
double
*
);
*
pf
=
(
double
)
p_sys
->
i_pts
/
(
1000.0
*
p_segment
->
f_duration
);
return
VLC_SUCCESS
;
es_out_Control
(
p_demux
->
out
,
ES_OUT_GET_ES_STATE
,
tk
->
p_es
,
&
b
);
if
(
!
b
)
{
tk
->
b_inited
=
VLC_FALSE
;
return
;
}
case
DEMUX_SET_POSITION
:
f
=
(
double
)
va_arg
(
args
,
double
);
Seek
(
p_demux
,
-
1
,
f
,
NULL
);
return
VLC_SUCCESS
;
/* First send init data */
if
(
!
tk
->
b_inited
&&
tk
->
i_data_init
>
0
)
{
block_t
*
p_init
;
case
DEMUX_GET_TIME
:
pi64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
*
pi64
=
p_sys
->
i_pts
;
return
VLC_SUCCESS
;
msg_Dbg
(
p_demux
,
"sending header (%d bytes)"
,
tk
->
i_data_init
);
p_init
=
MemToBlock
(
p_demux
,
tk
->
p_data_init
,
tk
->
i_data_init
);
if
(
p_init
)
es_out_Send
(
p_demux
->
out
,
tk
->
p_es
,
p_init
);
}
tk
->
b_inited
=
VLC_TRUE
;
case
DEMUX_GET_TITLE_INFO
:
if
(
p_sys
->
title
&&
p_sys
->
title
->
i_seekpoint
>
0
)
{
input_title_t
***
ppp_title
=
(
input_title_t
***
)
va_arg
(
args
,
input_title_t
***
);
int
*
pi_int
=
(
int
*
)
va_arg
(
args
,
int
*
);
*
pi_int
=
1
;
*
ppp_title
=
(
input_title_t
**
)
malloc
(
sizeof
(
input_title_t
**
)
);
for
(
i
=
0
;
i
<
block
->
NumberFrames
();
i
++
)
{
block_t
*
p_block
;
DataBuffer
&
data
=
block
->
GetBuffer
(
i
);
(
*
ppp_title
)[
0
]
=
vlc_input_title_Duplicate
(
p_sys
->
title
);
p_block
=
MemToBlock
(
p_demux
,
data
.
Buffer
(),
data
.
Size
()
);
return
VLC_SUCCESS
;
if
(
p_block
==
NULL
)
{
break
;
}
return
VLC_EGENERIC
;
case
DEMUX_SET_TITLE
:
/* TODO handle editions as titles & DVD titles as well */
if
(
p_sys
->
title
&&
p_sys
->
title
->
i_seekpoint
>
0
)
#if defined(HAVE_ZLIB_H)
if
(
tk
->
i_compression_type
)
{
return
VLC_SUCCESS
;
p_block
=
block_zlib_decompress
(
VLC_OBJECT
(
p_demux
),
p_block
)
;
}
return
VLC_EGENERIC
;
#endif
case
DEMUX_SET_SEEKPOINT
:
/* FIXME do a better implementation */
i_skp
=
(
int
)
va_arg
(
args
,
int
);
// TODO implement correct timestamping when B frames are used
if
(
tk
->
fmt
.
i_cat
!=
VIDEO_ES
)
{
p_block
->
i_dts
=
p_block
->
i_pts
=
i_pts
;
}
else
{
p_block
->
i_dts
=
i_pts
;
p_block
->
i_pts
=
0
;
}
if
(
p_sys
->
title
&&
i_skp
<
p_sys
->
title
->
i_seekpoint
)
if
(
tk
->
fmt
.
i_cat
==
SPU_ES
&&
strcmp
(
tk
->
psz_codec
,
"S_VOBSUB"
)
)
{
Seek
(
p_demux
,
(
int64_t
)
p_sys
->
title
->
seekpoint
[
i_skp
]
->
i_time_offset
,
-
1
,
NULL
);
p_demux
->
info
.
i_seekpoint
|=
INPUT_UPDATE_SEEKPOINT
;
p_demux
->
info
.
i_seekpoint
=
i_skp
;
return
VLC_SUCCESS
;
p_block
->
i_length
=
i_duration
*
1000
;
}
return
VLC_EGENERIC
;
es_out_Send
(
p_demux
->
out
,
tk
->
p_es
,
p_block
)
;
case
DEMUX_SET_TIME
:
case
DEMUX_GET_FPS
:
default:
return
VLC_EGENERIC
;
/* use time stamp only for first block */
i_pts
=
0
;
}
#undef tk
}
int
matroska_segment_t
::
BlockGet
(
KaxBlock
**
pp_block
,
int64_t
*
pi_ref1
,
int64_t
*
pi_ref2
,
int64_t
*
pi_duration
)
matroska_stream_t
*
demux_sys_t
::
AnalyseAllSegmentsFound
(
EbmlStream
*
p_estream
)
{
*
pp_block
=
NULL
;
*
pi_ref1
=
-
1
;
*
pi_ref2
=
-
1
;
int
i_upper_lvl
=
0
;
size_t
i
;
EbmlElement
*
p_l0
,
*
p_l1
,
*
p_l2
;
bool
b_keep_stream
=
false
,
b_keep_segment
;
for
(
;;
)
// verify the EBML Header
p_l0
=
p_estream
->
FindNextID
(
EbmlHead
::
ClassInfos
,
0xFFFFFFFFL
);
if
(
p_l0
==
NULL
)
{
EbmlElement
*
el
;
int
i_level
;
return
NULL
;
}
p_l0
->
SkipData
(
*
p_estream
,
EbmlHead_Context
);
delete
p_l0
;
if
(
sys
.
demuxer
.
b_die
)
// find all segments in this file
p_l0
=
p_estream
->
FindNextID
(
KaxSegment
::
ClassInfos
,
0xFFFFFFFFL
);
if
(
p_l0
==
NULL
)
{
return
VLC_EGENERIC
;
return
NULL
;
}
el
=
ep
->
Get
();
i_level
=
ep
->
GetLevel
();
matroska_stream_t
*
p_stream1
=
new
matroska_stream_t
(
*
this
);
if
(
el
==
NULL
&&
*
pp_block
!=
NULL
)
while
(
p_l0
!=
0
)
{
/* update the index */
#define idx index[i_index - 1]
if
(
i_index
>
0
&&
idx
.
i_time
==
-
1
)
if
(
EbmlId
(
*
p_l0
)
==
KaxSegment
::
ClassInfos
.
GlobalId
)
{
idx
.
i_time
=
(
*
pp_block
)
->
GlobalTimecode
()
/
(
mtime_t
)
1000
;
idx
.
b_key
=
*
pi_ref1
==
-
1
?
VLC_TRUE
:
VLC_FALSE
;
}
#undef idx
return
VLC_SUCCESS
;
}
EbmlParser
*
ep
;
matroska_segment_t
*
p_segment1
=
new
matroska_segment_t
(
*
this
,
*
p_estream
);
b_keep_segment
=
false
;
if
(
el
==
NULL
)
{
if
(
ep
->
GetLevel
()
>
1
)
{
ep
->
Up
();
continue
;
}
msg_Warn
(
&
sys
.
demuxer
,
"EOF"
);
return
VLC_EGENERIC
;
}
ep
=
new
EbmlParser
(
p_estream
,
p_l0
);
p_segment1
->
ep
=
ep
;
p_segment1
->
segment
=
(
KaxSegment
*
)
p_l0
;
/* do parsing */
if
(
i_level
==
1
)
while
((
p_l1
=
ep
->
Get
()))
{
if
(
MKV_IS_ID
(
el
,
KaxCluster
)
)
if
(
MKV_IS_ID
(
p_l1
,
KaxInfo
)
)
{
cluster
=
(
KaxCluster
*
)
el
;
// find the families of this segment
KaxInfo
*
p_info
=
static_cast
<
KaxInfo
*>
(
p_l1
);
/* add it to the index */
if
(
i_index
==
0
||
(
i_index
>
0
&&
index
[
i_index
-
1
].
i_position
<
(
int64_t
)
cluster
->
GetElementPosition
()
)
)
p_info
->
Read
(
*
p_estream
,
KaxInfo
::
ClassInfos
.
Context
,
i_upper_lvl
,
p_l2
,
true
);
for
(
i
=
0
;
i
<
p_info
->
ListSize
();
i
++
)
{
IndexAppendCluster
(
cluster
);
}
EbmlElement
*
l
=
(
*
p_info
)[
i
];
// reset silent tracks
for
(
size_t
i
=
0
;
i
<
tracks
.
size
();
i
++
)
if
(
MKV_IS_ID
(
l
,
KaxSegmentUID
)
)
{
tracks
[
i
]
->
b_silent
=
VLC_FALSE
;
KaxSegmentUID
*
p_uid
=
static_cast
<
KaxSegmentUID
*>
(
l
);
b_keep_segment
=
(
FindSegment
(
*
p_uid
)
==
NULL
);
if
(
!
b_keep_segment
)
break
;
// this segment is already known
p_segment1
->
segment_uid
=
*
(
new
KaxSegmentUID
(
*
p_uid
)
);
}
ep
->
Down
();
else
if
(
MKV_IS_ID
(
l
,
KaxPrevUID
)
)
{
p_segment1
->
prev_segment_uid
=
*
(
new
KaxPrevUID
(
*
static_cast
<
KaxPrevUID
*>
(
l
)
)
);
}
else
if
(
MKV_IS_ID
(
el
,
KaxCues
)
)
else
if
(
MKV_IS_ID
(
l
,
KaxNextUID
)
)
{
msg_Warn
(
&
sys
.
demuxer
,
"find KaxCues FIXME"
);
return
VLC_EGENERIC
;
p_segment1
->
next_segment_uid
=
*
(
new
KaxNextUID
(
*
static_cast
<
KaxNextUID
*>
(
l
)
)
);
}
else
else
if
(
MKV_IS_ID
(
l
,
KaxSegmentFamily
)
)
{
msg_Dbg
(
&
sys
.
demuxer
,
"unknown (%s)"
,
typeid
(
el
).
name
()
);
KaxSegmentFamily
*
p_fam
=
new
KaxSegmentFamily
(
*
static_cast
<
KaxSegmentFamily
*>
(
l
)
);
std
::
vector
<
KaxSegmentFamily
>::
iterator
iter
;
p_segment1
->
families
.
push_back
(
*
p_fam
);
}
}
else
if
(
i_level
==
2
)
{
if
(
MKV_IS_ID
(
el
,
KaxClusterTimecode
)
)
{
KaxClusterTimecode
&
ctc
=
*
(
KaxClusterTimecode
*
)
el
;
ctc
.
ReadData
(
es
.
I_O
(),
SCOPE_ALL_DATA
);
cluster
->
InitTimecode
(
uint64
(
ctc
),
i_timescale
);
break
;
}
else
if
(
MKV_IS_ID
(
el
,
KaxClusterSilentTracks
)
)
{
ep
->
Down
();
}
else
if
(
MKV_IS_ID
(
el
,
KaxBlockGroup
)
)
if
(
b_keep_segment
)
{
ep
->
Down
();
b_keep_stream
=
true
;
p_stream1
->
segments
.
push_back
(
p_segment1
);
}
else
delete
p_segment1
;
}
else
if
(
i_level
==
3
)
{
if
(
MKV_IS_ID
(
el
,
KaxBlock
)
)
{
*
pp_block
=
(
KaxBlock
*
)
el
;
(
*
pp_block
)
->
ReadData
(
es
.
I_O
()
);
(
*
pp_block
)
->
SetParent
(
*
cluster
);
ep
->
Keep
();
p_l0
->
SkipData
(
*
p_estream
,
EbmlHead_Context
);
p_l0
=
p_estream
->
FindNextID
(
KaxSegment
::
ClassInfos
,
0xFFFFFFFFL
);
}
else
if
(
MKV_IS_ID
(
el
,
KaxBlockDuration
)
)
{
KaxBlockDuration
&
dur
=
*
(
KaxBlockDuration
*
)
el
;
dur
.
ReadData
(
es
.
I_O
()
);
*
pi_duration
=
uint64
(
dur
);
if
(
!
b_keep_stream
)
{
delete
p_stream1
;
p_stream1
=
NULL
;
}
else
if
(
MKV_IS_ID
(
el
,
KaxReferenceBlock
)
)
return
p_stream1
;
}
bool
matroska_segment_t
::
Select
(
)
{
size_t
i_track
;
/* add all es */
msg_Dbg
(
&
sys
.
demuxer
,
"found %d es"
,
tracks
.
size
()
);
for
(
i_track
=
0
;
i_track
<
tracks
.
size
();
i_track
++
)
{
KaxReferenceBlock
&
ref
=
*
(
KaxReferenceBlock
*
)
el
;
#define tk tracks[i_track]
if
(
tk
->
fmt
.
i_cat
==
UNKNOWN_ES
)
{
msg_Warn
(
&
sys
.
demuxer
,
"invalid track[%d, n=%d]"
,
i_track
,
tk
->
i_number
);
tk
->
p_es
=
NULL
;
continue
;
}
ref
.
ReadData
(
es
.
I_O
()
);
if
(
*
pi_ref1
==
-
1
)
if
(
!
strcmp
(
tk
->
psz_codec
,
"V_MS/VFW/FOURCC"
)
)
{
*
pi_ref1
=
int64
(
ref
);
if
(
tk
->
i_extra_data
<
(
int
)
sizeof
(
BITMAPINFOHEADER
)
)
{
msg_Err
(
&
sys
.
demuxer
,
"missing/invalid BITMAPINFOHEADER"
);
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'u'
,
'n'
,
'd'
,
'f'
);
}
else
{
*
pi_ref2
=
int64
(
ref
);
BITMAPINFOHEADER
*
p_bih
=
(
BITMAPINFOHEADER
*
)
tk
->
p_extra_data
;
tk
->
fmt
.
video
.
i_width
=
GetDWLE
(
&
p_bih
->
biWidth
);
tk
->
fmt
.
video
.
i_height
=
GetDWLE
(
&
p_bih
->
biHeight
);
tk
->
fmt
.
i_codec
=
GetFOURCC
(
&
p_bih
->
biCompression
);
tk
->
fmt
.
i_extra
=
GetDWLE
(
&
p_bih
->
biSize
)
-
sizeof
(
BITMAPINFOHEADER
);
if
(
tk
->
fmt
.
i_extra
>
0
)
{
tk
->
fmt
.
p_extra
=
malloc
(
tk
->
fmt
.
i_extra
);
memcpy
(
tk
->
fmt
.
p_extra
,
&
p_bih
[
1
],
tk
->
fmt
.
i_extra
);
}
}
else
if
(
MKV_IS_ID
(
el
,
KaxClusterSilentTrackNumber
)
)
}
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"V_MPEG1"
)
||
!
strcmp
(
tk
->
psz_codec
,
"V_MPEG2"
)
)
{
KaxClusterSilentTrackNumber
&
track_num
=
*
(
KaxClusterSilentTrackNumber
*
)
el
;
track_num
.
ReadData
(
es
.
I_O
()
);
// find the track
for
(
size_t
i
=
0
;
i
<
tracks
.
size
();
i
++
)
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'v'
);
}
else
if
(
!
strncmp
(
tk
->
psz_codec
,
"V_MPEG4"
,
7
)
)
{
if
(
tracks
[
i
]
->
i_number
==
uint32
(
track_num
)
)
if
(
!
strcmp
(
tk
->
psz_codec
,
"V_MPEG4/MS/V3"
)
)
{
tracks
[
i
]
->
b_silent
=
VLC_TRUE
;
break
;
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'D'
,
'I'
,
'V'
,
'3'
);
}
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"V_MPEG4/ISO/AVC"
)
)
{
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'a'
,
'v'
,
'c'
,
'1'
);
tk
->
fmt
.
b_packetized
=
VLC_FALSE
;
tk
->
fmt
.
i_extra
=
tk
->
i_extra_data
;
tk
->
fmt
.
p_extra
=
malloc
(
tk
->
i_extra_data
);
memcpy
(
tk
->
fmt
.
p_extra
,
tk
->
p_extra_data
,
tk
->
i_extra_data
);
}
else
{
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'v'
);
}
}
else
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"V_QUICKTIME"
)
)
{
msg_Err
(
&
sys
.
demuxer
,
"invalid level = %d"
,
i_level
);
return
VLC_EGENERIC
;
MP4_Box_t
*
p_box
=
(
MP4_Box_t
*
)
malloc
(
sizeof
(
MP4_Box_t
)
);
stream_t
*
p_mp4_stream
=
stream_MemoryNew
(
VLC_OBJECT
(
&
sys
.
demuxer
),
tk
->
p_extra_data
,
tk
->
i_extra_data
);
MP4_ReadBoxCommon
(
p_mp4_stream
,
p_box
);
MP4_ReadBox_sample_vide
(
p_mp4_stream
,
p_box
);
tk
->
fmt
.
i_codec
=
p_box
->
i_type
;
tk
->
fmt
.
video
.
i_width
=
p_box
->
data
.
p_sample_vide
->
i_width
;
tk
->
fmt
.
video
.
i_height
=
p_box
->
data
.
p_sample_vide
->
i_height
;
tk
->
fmt
.
i_extra
=
p_box
->
data
.
p_sample_vide
->
i_qt_image_description
;
tk
->
fmt
.
p_extra
=
malloc
(
tk
->
fmt
.
i_extra
);
memcpy
(
tk
->
fmt
.
p_extra
,
p_box
->
data
.
p_sample_vide
->
p_qt_image_description
,
tk
->
fmt
.
i_extra
);
MP4_FreeBox_sample_vide
(
p_box
);
stream_MemoryDelete
(
p_mp4_stream
,
VLC_TRUE
);
}
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"A_MS/ACM"
)
)
{
if
(
tk
->
i_extra_data
<
(
int
)
sizeof
(
WAVEFORMATEX
)
)
{
msg_Err
(
&
sys
.
demuxer
,
"missing/invalid WAVEFORMATEX"
);
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'u'
,
'n'
,
'd'
,
'f'
);
}
}
static
block_t
*
MemToBlock
(
demux_t
*
p_demux
,
uint8_t
*
p_mem
,
int
i_mem
)
{
block_t
*
p_block
;
if
(
!
(
p_block
=
block_New
(
p_demux
,
i_mem
)
)
)
return
NULL
;
memcpy
(
p_block
->
p_buffer
,
p_mem
,
i_mem
);
//p_block->i_rate = p_input->stream.control.i_rate;
return
p_block
;
}
else
{
WAVEFORMATEX
*
p_wf
=
(
WAVEFORMATEX
*
)
tk
->
p_extra_data
;
static
void
BlockDecode
(
demux_t
*
p_demux
,
KaxBlock
*
block
,
mtime_t
i_pts
,
mtime_t
i_duration
)
{
demux_sys_t
*
p_sys
=
p_demux
->
p_sys
;
matroska_stream_t
*
p_stream
=
p_sys
->
Stream
();
matroska_segment_t
*
p_segment
=
p_stream
->
Segment
();
wf_tag_to_fourcc
(
GetWLE
(
&
p_wf
->
wFormatTag
),
&
tk
->
fmt
.
i_codec
,
NULL
);
size_t
i_track
;
unsigned
int
i
;
vlc_bool_t
b
;
tk
->
fmt
.
audio
.
i_channels
=
GetWLE
(
&
p_wf
->
nChannels
);
tk
->
fmt
.
audio
.
i_rate
=
GetDWLE
(
&
p_wf
->
nSamplesPerSec
);
tk
->
fmt
.
i_bitrate
=
GetDWLE
(
&
p_wf
->
nAvgBytesPerSec
)
*
8
;
tk
->
fmt
.
audio
.
i_blockalign
=
GetWLE
(
&
p_wf
->
nBlockAlign
);;
tk
->
fmt
.
audio
.
i_bitspersample
=
GetWLE
(
&
p_wf
->
wBitsPerSample
);
#define tk p_segment->tracks[i_track]
for
(
i_track
=
0
;
i_track
<
p_segment
->
tracks
.
size
();
i_track
++
)
{
if
(
tk
->
i_number
==
block
->
TrackNum
()
)
tk
->
fmt
.
i_extra
=
GetWLE
(
&
p_wf
->
cbSize
);
if
(
tk
->
fmt
.
i_extra
>
0
)
{
break
;
tk
->
fmt
.
p_extra
=
malloc
(
tk
->
fmt
.
i_extra
);
memcpy
(
tk
->
fmt
.
p_extra
,
&
p_wf
[
1
],
tk
->
fmt
.
i_extra
);
}
}
if
(
i_track
>=
p_segment
->
tracks
.
size
()
)
}
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"A_MPEG/L3"
)
||
!
strcmp
(
tk
->
psz_codec
,
"A_MPEG/L2"
)
||
!
strcmp
(
tk
->
psz_codec
,
"A_MPEG/L1"
)
)
{
msg_Err
(
p_demux
,
"invalid track number=%d"
,
block
->
TrackNum
()
);
return
;
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'm'
,
'p'
,
'g'
,
'a'
);
}
if
(
tk
->
p_es
==
NULL
)
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"A_AC3"
)
)
{
msg_Err
(
p_demux
,
"unknown track number=%d"
,
block
->
TrackNum
()
);
return
;
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'a'
,
'5'
,
'2'
,
' '
);
}
if
(
i_pts
<
p_sys
->
i_start_pts
&&
tk
->
fmt
.
i_cat
==
AUDIO_ES
)
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"A_DTS"
)
)
{
return
;
/* discard audio packets that shouldn't be rendered */
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'd'
,
't'
,
's'
,
' '
);
}
es_out_Control
(
p_demux
->
out
,
ES_OUT_GET_ES_STATE
,
tk
->
p_es
,
&
b
);
if
(
!
b
)
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"A_FLAC"
)
)
{
tk
->
b_inited
=
VLC_FALSE
;
return
;
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'f'
,
'l'
,
'a'
,
'c'
);
tk
->
fmt
.
i_extra
=
tk
->
i_extra_data
;
tk
->
fmt
.
p_extra
=
malloc
(
tk
->
i_extra_data
);
memcpy
(
tk
->
fmt
.
p_extra
,
tk
->
p_extra_data
,
tk
->
i_extra_data
);
}
/* First send init data */
if
(
!
tk
->
b_inited
&&
tk
->
i_data_init
>
0
)
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"A_VORBIS"
)
)
{
block_t
*
p_init
;
int
i
,
i_offset
=
1
,
i_size
[
3
],
i_extra
;
uint8_t
*
p_extra
;
msg_Dbg
(
p_demux
,
"sending header (%d bytes)"
,
tk
->
i_data_init
);
p_init
=
MemToBlock
(
p_demux
,
tk
->
p_data_init
,
tk
->
i_data_init
);
if
(
p_init
)
es_out_Send
(
p_demux
->
out
,
tk
->
p_es
,
p_init
);
}
tk
->
b_inited
=
VLC_TRUE
;
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'v'
,
'o'
,
'r'
,
'b'
);
/* Split the 3 headers */
if
(
tk
->
p_extra_data
[
0
]
!=
0x02
)
msg_Err
(
&
sys
.
demuxer
,
"invalid vorbis header"
);
for
(
i
=
0
;
i
<
block
->
NumberFrames
()
;
i
++
)
for
(
i
=
0
;
i
<
2
;
i
++
)
{
block_t
*
p_block
;
DataBuffer
&
data
=
block
->
GetBuffer
(
i
);
p_block
=
MemToBlock
(
p_demux
,
data
.
Buffer
(),
data
.
Size
()
);
if
(
p_block
==
NULL
)
i_size
[
i
]
=
0
;
while
(
i_offset
<
tk
->
i_extra_data
)
{
break
;
i_size
[
i
]
+=
tk
->
p_extra_data
[
i_offset
];
if
(
tk
->
p_extra_data
[
i_offset
++
]
!=
0xff
)
break
;
}
#if defined(HAVE_ZLIB_H)
if
(
tk
->
i_compression_type
)
{
p_block
=
block_zlib_decompress
(
VLC_OBJECT
(
p_demux
),
p_block
);
}
#endif
// TODO implement correct timestamping when B frames are used
if
(
tk
->
fmt
.
i_cat
!=
VIDEO_ES
)
i_size
[
0
]
=
__MIN
(
i_size
[
0
],
tk
->
i_extra_data
-
i_offset
);
i_size
[
1
]
=
__MIN
(
i_size
[
1
],
tk
->
i_extra_data
-
i_offset
-
i_size
[
0
]);
i_size
[
2
]
=
tk
->
i_extra_data
-
i_offset
-
i_size
[
0
]
-
i_size
[
1
];
tk
->
fmt
.
i_extra
=
3
*
2
+
i_size
[
0
]
+
i_size
[
1
]
+
i_size
[
2
];
tk
->
fmt
.
p_extra
=
malloc
(
tk
->
fmt
.
i_extra
);
p_extra
=
(
uint8_t
*
)
tk
->
fmt
.
p_extra
;
i_extra
=
0
;
for
(
i
=
0
;
i
<
3
;
i
++
)
{
p_block
->
i_dts
=
p_block
->
i_pts
=
i_pts
;
*
(
p_extra
++
)
=
i_size
[
i
]
>>
8
;
*
(
p_extra
++
)
=
i_size
[
i
]
&
0xFF
;
memcpy
(
p_extra
,
tk
->
p_extra_data
+
i_offset
+
i_extra
,
i_size
[
i
]
);
p_extra
+=
i_size
[
i
];
i_extra
+=
i_size
[
i
];
}
else
{
p_block
->
i_dts
=
i_pts
;
p_block
->
i_pts
=
0
;
}
else
if
(
!
strncmp
(
tk
->
psz_codec
,
"A_AAC/MPEG2/"
,
strlen
(
"A_AAC/MPEG2/"
)
)
||
!
strncmp
(
tk
->
psz_codec
,
"A_AAC/MPEG4/"
,
strlen
(
"A_AAC/MPEG4/"
)
)
)
{
int
i_profile
,
i_srate
;
static
unsigned
int
i_sample_rates
[]
=
{
96000
,
88200
,
64000
,
48000
,
44100
,
32000
,
24000
,
22050
,
16000
,
12000
,
11025
,
8000
,
7350
,
0
,
0
,
0
};
if
(
tk
->
fmt
.
i_cat
==
SPU_ES
&&
strcmp
(
tk
->
psz_codec
,
"S_VOBSUB"
)
)
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'm'
,
'p'
,
'4'
,
'a'
);
/* create data for faad (MP4DecSpecificDescrTag)*/
if
(
!
strcmp
(
&
tk
->
psz_codec
[
12
],
"MAIN"
)
)
{
p_block
->
i_length
=
i_duration
*
100
0
;
i_profile
=
0
;
}
es_out_Send
(
p_demux
->
out
,
tk
->
p_es
,
p_block
);
/* use time stamp only for first block */
i_pts
=
0
;
else
if
(
!
strcmp
(
&
tk
->
psz_codec
[
12
],
"LC"
)
)
{
i_profile
=
1
;
}
#undef tk
}
matroska_stream_t
*
demux_sys_t
::
AnalyseAllSegmentsFound
(
EbmlStream
*
p_estream
)
{
int
i_upper_lvl
=
0
;
size_t
i
;
EbmlElement
*
p_l0
,
*
p_l1
,
*
p_l2
;
bool
b_keep_stream
=
false
,
b_keep_segment
;
// verify the EBML Header
p_l0
=
p_estream
->
FindNextID
(
EbmlHead
::
ClassInfos
,
0xFFFFFFFFL
);
if
(
p_l0
==
NULL
)
else
if
(
!
strcmp
(
&
tk
->
psz_codec
[
12
],
"SSR"
)
)
{
return
NULL
;
i_profile
=
2
;
}
p_l0
->
SkipData
(
*
p_estream
,
EbmlHead_Context
);
delete
p_l0
;
// find all segments in this file
p_l0
=
p_estream
->
FindNextID
(
KaxSegment
::
ClassInfos
,
0xFFFFFFFFL
);
if
(
p_l0
==
NULL
)
else
{
return
NULL
;
i_profile
=
3
;
}
matroska_stream_t
*
p_stream1
=
new
matroska_stream_t
(
*
this
);
while
(
p_l0
!=
0
)
for
(
i_srate
=
0
;
i_srate
<
13
;
i_srate
++
)
{
if
(
EbmlId
(
*
p_l0
)
==
KaxSegment
::
ClassInfos
.
GlobalId
)
if
(
i_sample_rates
[
i_srate
]
==
tk
->
fmt
.
audio
.
i_rate
)
{
EbmlParser
*
ep
;
matroska_segment_t
*
p_segment1
=
new
matroska_segment_t
(
*
this
,
*
p_estream
);
b_keep_segment
=
false
;
ep
=
new
EbmlParser
(
p_estream
,
p_l0
);
p_segment1
->
ep
=
ep
;
p_segment1
->
segment
=
(
KaxSegment
*
)
p_l0
;
break
;
}
}
msg_Dbg
(
&
sys
.
demuxer
,
"profile=%d srate=%d"
,
i_profile
,
i_srate
);
while
((
p_l1
=
ep
->
Get
()))
tk
->
fmt
.
i_extra
=
2
;
tk
->
fmt
.
p_extra
=
malloc
(
tk
->
fmt
.
i_extra
);
((
uint8_t
*
)
tk
->
fmt
.
p_extra
)[
0
]
=
((
i_profile
+
1
)
<<
3
)
|
((
i_srate
&
0xe
)
>>
1
);
((
uint8_t
*
)
tk
->
fmt
.
p_extra
)[
1
]
=
((
i_srate
&
0x1
)
<<
7
)
|
(
tk
->
fmt
.
audio
.
i_channels
<<
3
);
}
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"A_PCM/INT/BIG"
)
||
!
strcmp
(
tk
->
psz_codec
,
"A_PCM/INT/LIT"
)
||
!
strcmp
(
tk
->
psz_codec
,
"A_PCM/FLOAT/IEEE"
)
)
{
if
(
MKV_IS_ID
(
p_l1
,
KaxInfo
)
)
if
(
!
strcmp
(
tk
->
psz_codec
,
"A_PCM/INT/BIG"
)
)
{
// find the families of this segment
KaxInfo
*
p_info
=
static_cast
<
KaxInfo
*>
(
p_l1
);
p_info
->
Read
(
*
p_estream
,
KaxInfo
::
ClassInfos
.
Context
,
i_upper_lvl
,
p_l2
,
true
);
for
(
i
=
0
;
i
<
p_info
->
ListSize
();
i
++
)
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
't'
,
'w'
,
'o'
,
's'
);
}
else
{
EbmlElement
*
l
=
(
*
p_info
)[
i
];
if
(
MKV_IS_ID
(
l
,
KaxSegmentUID
)
)
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'a'
,
'r'
,
'a'
,
'w'
);
}
tk
->
fmt
.
audio
.
i_blockalign
=
(
tk
->
fmt
.
audio
.
i_bitspersample
+
7
)
/
8
*
tk
->
fmt
.
audio
.
i_channels
;
}
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"A_TTA1"
)
)
{
KaxSegmentUID
*
p_uid
=
static_cast
<
KaxSegmentUID
*>
(
l
);
b_keep_segment
=
(
FindSegment
(
*
p_uid
)
==
NULL
);
if
(
!
b_keep_segment
)
break
;
// this segment is already known
p_segment1
->
segment_uid
=
*
(
new
KaxSegmentUID
(
*
p_uid
)
);
/* FIXME: support this codec */
msg_Err
(
&
sys
.
demuxer
,
"TTA not supported yet[%d, n=%d]"
,
i_track
,
tk
->
i_number
);
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'u'
,
'n'
,
'd'
,
'f'
);
}
else
if
(
MKV_IS_ID
(
l
,
KaxPrevUID
)
)
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"A_WAVPACK4"
)
)
{
p_segment1
->
prev_segment_uid
=
*
(
new
KaxPrevUID
(
*
static_cast
<
KaxPrevUID
*>
(
l
)
)
);
/* FIXME: support this codec */
msg_Err
(
&
sys
.
demuxer
,
"Wavpack not supported yet[%d, n=%d]"
,
i_track
,
tk
->
i_number
);
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'u'
,
'n'
,
'd'
,
'f'
);
}
else
if
(
MKV_IS_ID
(
l
,
KaxNextUID
)
)
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"S_TEXT/UTF8"
)
)
{
p_segment1
->
next_segment_uid
=
*
(
new
KaxNextUID
(
*
static_cast
<
KaxNextUID
*>
(
l
)
)
);
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
's'
,
'u'
,
'b'
,
't'
);
tk
->
fmt
.
subs
.
psz_encoding
=
strdup
(
"UTF-8"
);
}
else
if
(
MKV_IS_ID
(
l
,
KaxSegmentFamily
)
)
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"S_TEXT/SSA"
)
||
!
strcmp
(
tk
->
psz_codec
,
"S_TEXT/ASS"
)
||
!
strcmp
(
tk
->
psz_codec
,
"S_SSA"
)
||
!
strcmp
(
tk
->
psz_codec
,
"S_ASS"
))
{
KaxSegmentFamily
*
p_fam
=
new
KaxSegmentFamily
(
*
static_cast
<
KaxSegmentFamily
*>
(
l
)
);
std
::
vector
<
KaxSegmentFamily
>::
iterator
iter
;
p_segment1
->
families
.
push_back
(
*
p_fam
);
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
's'
,
's'
,
'a'
,
' '
);
tk
->
fmt
.
subs
.
psz_encoding
=
strdup
(
"UTF-8"
);
}
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"S_VOBSUB"
)
)
{
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
's'
,
'p'
,
'u'
,
' '
);
if
(
tk
->
i_extra_data
)
{
char
*
p_start
;
char
*
p_buf
=
(
char
*
)
malloc
(
tk
->
i_extra_data
+
1
);
memcpy
(
p_buf
,
tk
->
p_extra_data
,
tk
->
i_extra_data
);
p_buf
[
tk
->
i_extra_data
]
=
'\0'
;
p_start
=
strstr
(
p_buf
,
"size:"
);
if
(
sscanf
(
p_start
,
"size: %dx%d"
,
&
tk
->
fmt
.
subs
.
spu
.
i_original_frame_width
,
&
tk
->
fmt
.
subs
.
spu
.
i_original_frame_height
)
==
2
)
{
msg_Dbg
(
&
sys
.
demuxer
,
"original frame size vobsubs: %dx%d"
,
tk
->
fmt
.
subs
.
spu
.
i_original_frame_width
,
tk
->
fmt
.
subs
.
spu
.
i_original_frame_height
);
}
else
{
msg_Warn
(
&
sys
.
demuxer
,
"reading original frame size for vobsub failed"
);
}
break
;
free
(
p_buf
)
;
}
}
if
(
b_keep_segment
)
else
if
(
!
strcmp
(
tk
->
psz_codec
,
"B_VOBBTN"
)
)
{
b_keep_stream
=
true
;
p_stream1
->
segments
.
push_back
(
p_segment1
);
/* FIXME: support this codec */
msg_Err
(
&
sys
.
demuxer
,
"Vob Buttons not supported yet[%d, n=%d]"
,
i_track
,
tk
->
i_number
);
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'u'
,
'n'
,
'd'
,
'f'
);
}
else
delete
p_segment1
;
{
msg_Err
(
&
sys
.
demuxer
,
"unknow codec id=`%s'"
,
tk
->
psz_codec
);
tk
->
fmt
.
i_codec
=
VLC_FOURCC
(
'u'
,
'n'
,
'd'
,
'f'
);
}
if
(
tk
->
b_default
)
{
tk
->
fmt
.
i_priority
=
1000
;
}
p_l0
->
SkipData
(
*
p_estream
,
EbmlHead_Context
);
p_l0
=
p_estream
->
FindNextID
(
KaxSegment
::
ClassInfos
,
0xFFFFFFFFL
);
tk
->
p_es
=
es_out_Add
(
sys
.
demuxer
.
out
,
&
tk
->
fmt
);
#undef tk
}
if
(
!
b_keep_stream
)
return
true
;
}
void
matroska_segment_t
::
UnSelect
(
)
{
size_t
i_track
;
for
(
i_track
=
0
;
i_track
<
tracks
.
size
();
i_track
++
)
{
delete
p_stream1
;
p_stream1
=
NULL
;
#define tk tracks[i_track]
if
(
tk
->
p_es
!=
NULL
)
{
es_out_Del
(
sys
.
demuxer
.
out
,
tk
->
p_es
);
tk
->
p_es
=
NULL
;
}
#undef tk
}
return
p_stream1
;
}
static
void
UpdateCurrentToChapter
(
demux_t
&
demux
)
...
...
@@ -1767,8 +1797,13 @@ static int Demux( demux_t *p_demux)
/* nothing left to read in this ordered edition */
if
(
p_stream
->
i_current_segment
==
p_stream
->
segments
.
size
()
-
1
)
return
0
;
p_segment
->
UnSelect
(
);
/* switch to the next segment (TODO update the duration) */
p_stream
->
i_current_segment
++
;
p_segment
=
p_stream
->
Segment
();
if
(
!
p_segment
||
!
p_segment
->
Select
(
)
)
return
0
;
continue
;
}
...
...
@@ -3441,7 +3476,7 @@ bool matroska_segment_t::Preload( )
return
true
;
}
matroska_segment_t
*
demux_sys_t
::
FindSegment
(
EbmlBinary
&
uid
)
const
matroska_segment_t
*
demux_sys_t
::
FindSegment
(
const
EbmlBinary
&
uid
)
const
{
matroska_segment_t
*
p_segment
=
NULL
;
for
(
size_t
i
=
0
;
i
<
streams
.
size
()
&&
p_segment
==
NULL
;
i
++
)
...
...
@@ -3451,7 +3486,7 @@ matroska_segment_t *demux_sys_t::FindSegment( EbmlBinary & uid ) const
return
p_segment
;
}
matroska_segment_t
*
matroska_stream_t
::
FindSegment
(
EbmlBinary
&
uid
)
const
matroska_segment_t
*
matroska_stream_t
::
FindSegment
(
const
EbmlBinary
&
uid
)
const
{
for
(
size_t
i
=
0
;
i
<
segments
.
size
();
i
++
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment