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
e617b434
Commit
e617b434
authored
Mar 28, 2005
by
Steve Lhomme
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
mkv.cpp: major rewrite to handle hard-linked segments easily though a virtual segment
parent
6c7dc61b
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
154 additions
and
134 deletions
+154
-134
modules/demux/mkv.cpp
modules/demux/mkv.cpp
+154
-134
No files found.
modules/demux/mkv.cpp
View file @
e617b434
...
...
@@ -508,7 +508,6 @@ public:
bool
Preload
(
);
bool
PreloadFamily
(
const
matroska_segment_t
&
segment
);
size_t
PreloadLinked
(
const
demux_sys_t
&
of_sys
,
std
::
vector
<
matroska_segment_t
*>
&
segments
);
void
ParseInfo
(
EbmlElement
*
info
);
void
ParseChapters
(
EbmlElement
*
chapters
);
void
ParseSeekHead
(
EbmlElement
*
seekhead
);
...
...
@@ -525,15 +524,48 @@ public:
static
bool
CompareSegmentUIDs
(
const
matroska_segment_t
*
item_a
,
const
matroska_segment_t
*
item_b
);
};
// class holding hard-linked segment together in the playback order
class
virtual_segment_t
{
public:
virtual_segment_t
()
:
i_current_segment
(
0
)
{}
std
::
vector
<
matroska_segment_t
*>
linked_segments
;
size_t
i_current_segment
;
void
Sort
();
size_t
AddSegment
(
matroska_segment_t
*
p_segment
);
void
PreloadLinked
(
);
float
Duration
(
)
const
;
void
LoadCues
(
);
matroska_segment_t
*
Segment
()
const
{
if
(
linked_segments
.
size
()
==
0
||
i_current_segment
>=
linked_segments
.
size
()
)
return
NULL
;
return
linked_segments
[
i_current_segment
];
}
bool
SelectNext
()
{
if
(
i_current_segment
<
linked_segments
.
size
()
-
1
)
{
i_current_segment
++
;
return
true
;
}
return
false
;
}
};
class
matroska_stream_t
{
public:
matroska_stream_t
(
demux_sys_t
&
demuxer
)
:
p_in
(
NULL
)
,
p_es
(
NULL
)
,
i_current_segment
(
-
1
)
,
sys
(
demuxer
)
,
f_duration
(
-
1.0
)
{}
~
matroska_stream_t
()
...
...
@@ -546,25 +578,10 @@ public:
EbmlStream
*
p_es
;
std
::
vector
<
matroska_segment_t
*>
segments
;
size_t
i_current_segment
;
demux_sys_t
&
sys
;
/* duration of the stream */
float
f_duration
;
inline
matroska_segment_t
*
Segment
()
{
if
(
i_current_segment
>=
0
&&
size_t
(
i_current_segment
)
<
segments
.
size
()
)
return
segments
[
i_current_segment
];
return
NULL
;
}
matroska_segment_t
*
FindSegment
(
const
EbmlBinary
&
uid
)
const
;
void
PreloadFamily
(
const
matroska_segment_t
&
segment
);
size_t
PreloadLinked
(
const
demux_sys_t
&
of_sys
);
void
PreparePlayback
(
);
};
class
demux_sys_t
...
...
@@ -577,7 +594,8 @@ public:
,
i_chapter_time
(
0
)
,
meta
(
NULL
)
,
title
(
NULL
)
,
i_current_stream
(
-
1
)
,
p_current_segment
(
NULL
)
,
f_duration
(
-
1.0
)
{}
~
demux_sys_t
()
...
...
@@ -600,19 +618,15 @@ public:
input_title_t
*
title
;
std
::
vector
<
matroska_stream_t
*>
streams
;
int
i_current_stream
;
std
::
vector
<
matroska_segment_t
*>
opened_segments
;
virtual_segment_t
*
p_current_segment
;
inline
matroska_stream_t
*
Stream
()
{
if
(
i_current_stream
>=
0
&&
size_t
(
i_current_stream
)
<
streams
.
size
()
)
return
streams
[
i_current_stream
];
return
NULL
;
}
/* duration of the stream */
float
f_duration
;
matroska_segment_t
*
FindSegment
(
const
EbmlBinary
&
uid
)
const
;
void
PreloadFamily
(
);
void
PreloadLinked
(
);
void
PreloadLinked
(
matroska_segment_t
*
p_segment
);
void
PreparePlayback
(
);
matroska_stream_t
*
AnalyseAllSegmentsFound
(
EbmlStream
*
p_estream
);
};
...
...
@@ -669,7 +683,6 @@ static int Open( vlc_object_t * p_this )
goto
error
;
}
p_sys
->
streams
.
push_back
(
p_stream
);
p_sys
->
i_current_stream
=
0
;
p_stream
->
p_in
=
p_io_callback
;
p_stream
->
p_es
=
p_io_stream
;
...
...
@@ -678,9 +691,8 @@ static int Open( vlc_object_t * p_this )
{
p_stream
->
segments
[
i
]
->
Preload
();
}
p_stream
->
i_current_segment
=
0
;
p_segment
=
p_stream
->
Segment
()
;
p_segment
=
p_stream
->
segments
[
0
]
;
if
(
p_segment
->
cluster
==
NULL
)
{
msg_Err
(
p_demux
,
"cannot find any cluster, damaged file ?"
);
...
...
@@ -755,7 +767,7 @@ static int Open( vlc_object_t * p_this )
}
p_sys
->
PreloadFamily
(
);
p_sys
->
PreloadLinked
(
);
p_sys
->
PreloadLinked
(
p_segment
);
p_sys
->
PreparePlayback
(
);
if
(
!
p_segment
->
b_cues
||
p_segment
->
i_index
<=
0
)
...
...
@@ -800,9 +812,7 @@ static void Close( vlc_object_t *p_this )
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
();
if
(
p_stream
==
NULL
)
return
VLC_EGENERIC
;
matroska_segment_t
*
p_segment
=
p_stream
->
Segment
();
matroska_segment_t
*
p_segment
=
p_sys
->
p_current_segment
->
Segment
();
int64_t
*
pi64
;
double
*
pf
,
f
;
int
i_skp
;
...
...
@@ -818,17 +828,17 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
case
DEMUX_GET_LENGTH
:
pi64
=
(
int64_t
*
)
va_arg
(
args
,
int64_t
*
);
if
(
p_s
tream
->
f_duration
>
0.0
)
if
(
p_s
ys
->
f_duration
>
0.0
)
{
*
pi64
=
(
int64_t
)(
p_s
tream
->
f_duration
*
1000
);
*
pi64
=
(
int64_t
)(
p_s
ys
->
f_duration
*
1000
);
return
VLC_SUCCESS
;
}
return
VLC_EGENERIC
;
case
DEMUX_GET_POSITION
:
pf
=
(
double
*
)
va_arg
(
args
,
double
*
);
if
(
p_s
tream
->
f_duration
>
0.0
)
*
pf
=
(
double
)
p_sys
->
i_pts
/
(
1000.0
*
p_s
tream
->
f_duration
);
if
(
p_s
ys
->
f_duration
>
0.0
)
*
pf
=
(
double
)
p_sys
->
i_pts
/
(
1000.0
*
p_s
ys
->
f_duration
);
return
VLC_SUCCESS
;
case
DEMUX_SET_POSITION
:
...
...
@@ -1045,8 +1055,7 @@ 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
();
matroska_segment_t
*
p_segment
=
p_sys
->
p_current_segment
->
Segment
();
size_t
i_track
;
unsigned
int
i
;
...
...
@@ -1559,8 +1568,7 @@ void matroska_segment_t::UnSelect( )
static
void
UpdateCurrentToChapter
(
demux_t
&
demux
)
{
demux_sys_t
&
sys
=
*
demux
.
p_sys
;
matroska_stream_t
*
p_stream
=
sys
.
Stream
();
matroska_segment_t
*
p_segment
=
p_stream
->
Segment
();
matroska_segment_t
*
p_segment
=
sys
.
p_current_segment
->
Segment
();
const
chapter_item_t
*
psz_curr_chapter
;
/* update current chapter/seekpoint */
...
...
@@ -1597,8 +1605,7 @@ static void UpdateCurrentToChapter( demux_t & demux )
static
void
Seek
(
demux_t
*
p_demux
,
mtime_t
i_date
,
double
f_percent
,
const
chapter_item_t
*
psz_chapter
)
{
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
();
matroska_segment_t
*
p_segment
=
p_sys
->
p_current_segment
->
Segment
();
mtime_t
i_time_offset
=
0
;
KaxBlock
*
block
;
...
...
@@ -1623,15 +1630,15 @@ static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, const chap
}
delete
p_segment
->
ep
;
p_segment
->
ep
=
new
EbmlParser
(
p_stream
->
p_
es
,
p_segment
->
segment
);
p_segment
->
ep
=
new
EbmlParser
(
&
p_segment
->
es
,
p_segment
->
segment
);
p_segment
->
cluster
=
NULL
;
/* seek without index or without date */
if
(
f_percent
>=
0
&&
(
config_GetInt
(
p_demux
,
"mkv-seek-percent"
)
||
!
p_segment
->
b_cues
||
i_date
<
0
))
{
if
(
p_s
tream
->
f_duration
>=
0
)
if
(
p_s
ys
->
f_duration
>=
0
)
{
i_date
=
int64_t
(
f_percent
*
p_s
tream
->
f_duration
*
1000.0
);
i_date
=
int64_t
(
f_percent
*
p_s
ys
->
f_duration
*
1000.0
);
}
else
{
...
...
@@ -1718,7 +1725,7 @@ static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, const chap
(
int
)(
100
*
p_segment
->
index
[
i_index
].
i_position
/
stream_Size
(
p_demux
->
s
)
)
);
p_s
tream
->
p_in
->
setFilePointer
(
p_segment
->
index
[
i_index
].
i_position
,
p_s
egment
->
es
.
I_O
().
setFilePointer
(
p_segment
->
index
[
i_index
].
i_position
,
seek_beginning
);
p_sys
->
i_start_pts
=
i_date
;
...
...
@@ -1792,8 +1799,7 @@ static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, const chap
static
int
Demux
(
demux_t
*
p_demux
)
{
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
();
matroska_segment_t
*
p_segment
=
p_sys
->
p_current_segment
->
Segment
();
if
(
p_segment
==
NULL
)
return
0
;
int
i_block_count
=
0
;
...
...
@@ -1810,17 +1816,19 @@ static int Demux( demux_t *p_demux)
if
(
p_segment
->
editions
.
size
()
&&
p_segment
->
editions
[
p_segment
->
i_current_edition
].
b_ordered
&&
p_segment
->
psz_current_chapter
==
NULL
)
{
/* nothing left to read in this ordered edition */
if
(
p_stream
->
i_current_segment
==
p_stream
->
segments
.
size
()
-
1
)
if
(
!
p_sys
->
p_current_segment
->
SelectNext
()
)
return
0
;
p_segment
->
UnSelect
(
);
es_out_Control
(
p_demux
->
out
,
ES_OUT_RESET_PCR
);
/* 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
(
0
)
)
/* switch to the next segment */
p_segment
=
p_sys
->
p_current_segment
->
Segment
();
if
(
!
p_segment
->
Select
(
0
)
)
{
msg_Err
(
p_demux
,
"Failed to select new segment"
);
return
0
;
}
continue
;
}
...
...
@@ -1843,11 +1851,15 @@ static int Demux( demux_t *p_demux)
es_out_Control
(
p_demux
->
out
,
ES_OUT_RESET_PCR
);
/* switch to the next segment */
p_stream
->
i_current_segment
++
;
p_segment
=
p_stream
->
Segment
();
if
(
!
p_segment
||
!
p_segment
->
Select
(
0
)
)
if
(
!
p_sys
->
p_current_segment
->
SelectNext
()
)
// no more segments in this stream
return
0
;
p_segment
=
p_sys
->
p_current_segment
->
Segment
();
if
(
!
p_segment
->
Select
(
0
)
)
{
msg_Err
(
p_demux
,
"Failed to select new segment"
);
return
0
;
}
continue
;
}
...
...
@@ -3364,6 +3376,7 @@ const chapter_item_t *chapter_edition_t::FindTimecode( mtime_t i_user_timecode )
void
demux_sys_t
::
PreloadFamily
(
)
{
/* family handling disabled for the moment
matroska_stream_t *p_stream = Stream();
if ( p_stream )
{
...
...
@@ -3376,6 +3389,7 @@ void demux_sys_t::PreloadFamily( )
}
}
}
*/
}
void
matroska_stream_t
::
PreloadFamily
(
const
matroska_segment_t
&
of_segment
)
...
...
@@ -3404,83 +3418,34 @@ bool matroska_segment_t::PreloadFamily( const matroska_segment_t & of_segment )
}
// preload all the linked segments for all preloaded segments
void
demux_sys_t
::
PreloadLinked
(
)
void
demux_sys_t
::
PreloadLinked
(
matroska_segment_t
*
p_segment
)
{
size_t
i_prealoaded
;
do
{
i_prealoaded
=
0
;
for
(
size_t
i
=
0
;
i
<
streams
.
size
();
i
++
)
{
i_prealoaded
+=
streams
[
i
]
->
PreloadLinked
(
*
this
);
}
}
while
(
i_prealoaded
);
// worst case: will stop when all segments are preloaded
}
size_t
i_preloaded
,
i
;
size_t
matroska_stream_t
::
PreloadLinked
(
const
demux_sys_t
&
of_sys
)
{
size_t
i_result
=
0
;
for
(
size_t
i
=
0
;
i
<
segments
.
size
();
i
++
)
{
i_result
+=
segments
[
i
]
->
PreloadLinked
(
of_sys
,
segments
);
}
delete
p_current_segment
;
p_current_segment
=
new
virtual_segment_t
();
return
i_result
;
}
// fill our current virtual segment with the used segment from the current stream
p_current_segment
->
linked_segments
.
push_back
(
p_segment
);
size_t
matroska_segment_t
::
PreloadLinked
(
const
demux_sys_t
&
of_sys
,
std
::
vector
<
matroska_segment_t
*>
&
segments
)
{
size_t
i_result
=
0
;
if
(
prev_segment_uid
.
GetBuffer
()
)
{
matroska_segment_t
*
p_segment
=
of_sys
.
FindSegment
(
prev_segment_uid
);
if
(
p_segment
)
{
if
(
p_segment
->
Preload
(
)
)
{
segments
.
push_back
(
p_segment
);
i_result
++
;
}
}
}
if
(
next_segment_uid
.
GetBuffer
()
)
{
matroska_segment_t
*
p_segment
=
of_sys
.
FindSegment
(
next_segment_uid
);
if
(
p_segment
)
{
if
(
p_segment
->
Preload
(
)
)
// fill our current virtual segment with all hard linked segments
do
{
i_preloaded
=
0
;
for
(
i
=
0
;
i
<
opened_segments
.
size
();
i
++
)
{
segments
.
push_back
(
p_segment
);
i_result
++
;
}
i_preloaded
+=
p_current_segment
->
AddSegment
(
opened_segments
[
i
]
);
}
}
return
i_result
;
}
}
while
(
i_preloaded
);
// worst case: will stop when all segments are found as linked
void
demux_sys_t
::
PreparePlayback
(
)
{
matroska_stream_t
*
p_stream
=
Stream
();
if
(
p_stream
)
{
p_stream
->
PreparePlayback
(
);
}
p_current_segment
->
Sort
(
);
p_current_segment
->
PreloadLinked
(
);
}
void
matroska_stream
_t
::
PreparePlayback
(
)
void
demux_sys
_t
::
PreparePlayback
(
)
{
size_t
i
;
// update duration
f_duration
=
0.0
;
for
(
i
=
0
;
i
<
segments
.
size
();
i
++
)
{
f_duration
+=
segments
[
i
]
->
f_duration
;
segments
[
i
]
->
LoadCues
(
);
}
// sort segment order
std
::
sort
(
segments
.
begin
(),
segments
.
end
(),
matroska_segment_t
::
CompareSegmentUIDs
);
f_duration
=
p_current_segment
->
Duration
();
p_current_segment
->
LoadCues
();
}
bool
matroska_segment_t
::
CompareSegmentUIDs
(
const
matroska_segment_t
*
p_item_a
,
const
matroska_segment_t
*
p_item_b
)
...
...
@@ -3561,20 +3526,75 @@ bool matroska_segment_t::Preload( )
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
++
)
for
(
size_t
i
=
0
;
i
<
opened_segments
.
size
();
i
++
)
{
p_segment
=
streams
[
i
]
->
FindSegment
(
uid
);
if
(
opened_segments
[
i
]
->
segment_uid
==
uid
)
return
opened_segments
[
i
];
}
return
p_segment
;
return
NULL
;
}
matroska_segment_t
*
matroska_stream_t
::
FindSegment
(
const
EbmlBinary
&
uid
)
const
void
virtual_segment_t
::
Sort
()
{
for
(
size_t
i
=
0
;
i
<
segments
.
size
();
i
++
)
// keep the current segment index
matroska_segment_t
*
p_segment
=
linked_segments
[
i_current_segment
];
std
::
sort
(
linked_segments
.
begin
(),
linked_segments
.
end
(),
matroska_segment_t
::
CompareSegmentUIDs
);
for
(
i_current_segment
=
0
;
i_current_segment
<
linked_segments
.
size
();
i_current_segment
++
)
if
(
linked_segments
[
i_current_segment
]
==
p_segment
)
break
;
}
size_t
virtual_segment_t
::
AddSegment
(
matroska_segment_t
*
p_segment
)
{
size_t
i
;
// check if it's not already in here
for
(
i
=
0
;
i
<
linked_segments
.
size
();
i
++
)
{
if
(
segments
[
i
]
->
segment_uid
==
uid
)
return
segments
[
i
];
if
(
p_segment
->
segment_uid
==
linked_segments
[
i
]
->
segment_uid
)
return
0
;
}
// find possible mates
for
(
i
=
0
;
i
<
linked_segments
.
size
();
i
++
)
{
if
(
p_segment
->
segment_uid
==
linked_segments
[
i
]
->
prev_segment_uid
)
{
linked_segments
.
push_back
(
p_segment
);
return
1
;
}
if
(
p_segment
->
segment_uid
==
linked_segments
[
i
]
->
next_segment_uid
)
{
linked_segments
.
push_back
(
p_segment
);
return
1
;
}
}
return
0
;
}
void
virtual_segment_t
::
PreloadLinked
(
)
{
for
(
size_t
i
=
0
;
i
<
linked_segments
.
size
();
i
++
)
{
linked_segments
[
i
]
->
Preload
(
);
}
}
float
virtual_segment_t
::
Duration
()
const
{
float
f_duration
=
0.0
;
for
(
size_t
i
=
0
;
i
<
linked_segments
.
size
();
i
++
)
{
f_duration
+=
linked_segments
[
i
]
->
f_duration
;
}
return
f_duration
;
}
void
virtual_segment_t
::
LoadCues
(
)
{
for
(
size_t
i
=
0
;
i
<
linked_segments
.
size
();
i
++
)
{
linked_segments
[
i
]
->
LoadCues
();
}
return
NULL
;
}
\ No newline at end of file
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