]> git.sesse.net Git - vlc/blob - modules/demux/mkv/Ebml_parser.cpp
Fix the subtitles loss at MKV segment changes
[vlc] / modules / demux / mkv / Ebml_parser.cpp
1
2 /*****************************************************************************
3  * EbmlParser for the matroska demuxer
4  *****************************************************************************
5  * Copyright (C) 2003-2004 the VideoLAN team
6  * $Id$
7  *
8  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
9  *          Steve Lhomme <steve.lhomme@free.fr>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 #include "Ebml_parser.hpp"
27 #include "stream_io_callback.hpp"
28
29 /*****************************************************************************
30  * Ebml Stream parser
31  *****************************************************************************/
32 EbmlParser::EbmlParser( EbmlStream *es, EbmlElement *el_start, demux_t *p_demux ) :
33     m_es( es ),
34     mi_level( 1 ),
35     m_got( NULL ),
36     mi_user_level( 1 ),
37     mb_keep( false )
38 {
39     mi_remain_size[0] = el_start->GetSize();
40     memset( m_el, 0, 6 * sizeof( *m_el ) );
41     m_el[0] = el_start;
42     mb_dummy = var_InheritBool( p_demux, "mkv-use-dummy" );
43 }
44
45 EbmlParser::~EbmlParser( void )
46 {
47     if( !mi_level )
48     {
49         assert( !mb_keep );
50         delete m_el[1];
51         return;
52     }
53
54     for( int i = 1; i <= mi_level; i++ )
55     {
56         if( !mb_keep )
57         {
58             delete m_el[i];
59         }
60         mb_keep = false;
61     }
62 }
63
64 EbmlElement* EbmlParser::UnGet( uint64 i_block_pos, uint64 i_cluster_pos )
65 {
66     if ( mi_user_level > mi_level )
67     {
68         while ( mi_user_level != mi_level )
69         {
70             delete m_el[mi_user_level];
71             m_el[mi_user_level] = NULL;
72             mi_user_level--;
73         }
74     }
75
76     /* Avoid data skip in BlockGet */
77     delete m_el[mi_level];
78     m_el[mi_level] = NULL;
79
80     m_got = NULL;
81     mb_keep = false;
82     if ( m_el[1] && m_el[1]->GetElementPosition() == i_cluster_pos )
83     {
84         m_es->I_O().setFilePointer( i_block_pos, seek_beginning );
85         return m_el[1];
86     }
87     else
88     {
89         // seek to the previous Cluster
90         m_es->I_O().setFilePointer( i_cluster_pos, seek_beginning );
91         while(mi_level > 1)
92         {
93             mi_level--;
94             mi_user_level--;
95             delete m_el[mi_level];
96             m_el[mi_level] = NULL;
97         }
98         return NULL;
99     }
100 }
101
102 void EbmlParser::Up( void )
103 {
104     if( mi_user_level == mi_level )
105     {
106         fprintf( stderr,"MKV/Ebml Parser: Up cannot escape itself\n" );
107     }
108
109     mi_user_level--;
110 }
111
112 void EbmlParser::Down( void )
113 {
114     mi_user_level++;
115     mi_level++;
116 }
117
118 void EbmlParser::Keep( void )
119 {
120     mb_keep = true;
121 }
122
123 int EbmlParser::GetLevel( void ) const
124 {
125     return mi_user_level;
126 }
127
128 void EbmlParser::Reset( demux_t *p_demux )
129 {
130     while ( mi_level > 0)
131     {
132         delete m_el[mi_level];
133         m_el[mi_level] = NULL;
134         mi_level--;
135     }
136     mi_user_level = mi_level = 1;
137     // a little faster and cleaner
138     m_es->I_O().setFilePointer( static_cast<KaxSegment*>(m_el[0])->GetGlobalPosition(0) );
139     mb_dummy = var_InheritBool( p_demux, "mkv-use-dummy" );
140 }
141
142 EbmlElement *EbmlParser::Get( void )
143 {
144     int i_ulev = 0;
145
146     if( mi_user_level != mi_level )
147     {
148         return NULL;
149     }
150     if( m_got )
151     {
152         EbmlElement *ret = m_got;
153         m_got = NULL;
154
155         return ret;
156     }
157
158     if( m_el[mi_level] )
159     {
160         m_el[mi_level]->SkipData( *m_es, EBML_CONTEXT(m_el[mi_level]) );
161         if( !mb_keep )
162         {
163             if( MKV_IS_ID( m_el[mi_level], KaxBlockVirtual ) )
164                 static_cast<KaxBlockVirtualWorkaround*>(m_el[mi_level])->Fix();
165             delete m_el[mi_level];
166         }
167         mb_keep = false;
168     }
169     vlc_stream_io_callback & io_stream = (vlc_stream_io_callback &) m_es->I_O();
170     uint64 i_size = io_stream.toRead();
171     m_el[mi_level] = m_es->FindNextElement( EBML_CONTEXT(m_el[mi_level - 1]),
172                                             i_ulev, i_size, mb_dummy, 1 );
173 //    mi_remain_size[mi_level] = m_el[mi_level]->GetSize();
174     if( i_ulev > 0 )
175     {
176         while( i_ulev > 0 )
177         {
178             if( mi_level == 1 )
179             {
180                 mi_level = 0;
181                 return NULL;
182             }
183
184             delete m_el[mi_level - 1];
185             m_got = m_el[mi_level -1] = m_el[mi_level];
186             m_el[mi_level] = NULL;
187
188             mi_level--;
189             i_ulev--;
190         }
191         return NULL;
192     }
193     else if( m_el[mi_level] == NULL )
194     {
195         fprintf( stderr,"MKV/Ebml Parser: m_el[mi_level] == NULL\n" );
196     }
197
198     return m_el[mi_level];
199 }
200
201 bool EbmlParser::IsTopPresent( EbmlElement *el ) const
202 {
203     for( int i = 0; i < mi_level; i++ )
204     {
205         if( m_el[i] && m_el[i] == el )
206             return true;
207     }
208     return false;
209 }
210