Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc-gpu
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-gpu
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