]> git.sesse.net Git - vlc/blob - modules/demux/mkv/util.cpp
demux: mkv: fix warning & int overflow
[vlc] / modules / demux / mkv / util.cpp
1 /*****************************************************************************
2  * util.cpp : matroska demuxer
3  *****************************************************************************
4  * Copyright (C) 2003-2004 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *          Steve Lhomme <steve.lhomme@free.fr>
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation; either version 2.1 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24 #include "mkv.hpp"
25 #include "util.hpp"
26 #include "demux.hpp"
27
28 #include <stdint.h>
29 /*****************************************************************************
30  * Local prototypes
31  *****************************************************************************/
32
33 #ifdef HAVE_ZLIB_H
34 int32_t zlib_decompress_extra( demux_t * p_demux, mkv_track_t * tk )
35 {
36     int result;
37     z_stream d_stream;
38     size_t n = 0;
39     uint8_t * p_new_extra = NULL;
40
41     msg_Dbg(p_demux,"Inflating private data");
42
43     d_stream.zalloc = Z_NULL;
44     d_stream.zfree = Z_NULL;
45     d_stream.opaque = Z_NULL;
46     if( inflateInit( &d_stream ) != Z_OK )
47     {
48         msg_Err( p_demux, "Couldn't initiate inflation ignore track %d",
49                  tk->i_number );
50         free(tk->p_extra_data);
51         delete tk;
52         return 1;
53     }
54
55     d_stream.next_in = tk->p_extra_data;
56     d_stream.avail_in = tk->i_extra_data;
57     do
58     {
59         n++;
60         p_new_extra = (uint8_t *) realloc(p_new_extra, n*1024);
61         if( !p_new_extra )
62         {
63             msg_Err( p_demux, "Couldn't allocate buffer to inflate data, ignore track %d",
64                       tk->i_number );
65             inflateEnd( &d_stream );
66             free(tk->p_extra_data);
67             delete tk;
68             return 1;
69         }
70         d_stream.next_out = &p_new_extra[(n - 1) * 1024];
71         d_stream.avail_out = 1024;
72         result = inflate(&d_stream, Z_NO_FLUSH);
73         if( result != Z_OK && result != Z_STREAM_END )
74         {
75             msg_Err( p_demux, "Zlib decompression failed. Result: %d", result );
76             inflateEnd( &d_stream );
77             free(p_new_extra);
78             free(tk->p_extra_data);
79             delete tk;
80             return 1;
81         }
82     }
83     while ( d_stream.avail_out == 0 && d_stream.avail_in != 0  &&
84             result != Z_STREAM_END );
85
86     free( tk->p_extra_data );
87     tk->i_extra_data = d_stream.total_out;
88     p_new_extra = (uint8_t *) realloc(p_new_extra, tk->i_extra_data);
89     if( !p_new_extra )
90     {
91         msg_Err( p_demux, "Couldn't allocate buffer to inflate data, ignore track %d",
92                  tk->i_number );
93         inflateEnd( &d_stream );
94         free(p_new_extra);
95         delete tk;
96         return 1;
97     }
98
99     tk->p_extra_data = p_new_extra;
100     
101     inflateEnd( &d_stream );
102     return 0;
103 }
104
105 block_t *block_zlib_decompress( vlc_object_t *p_this, block_t *p_in_block ) {
106     int result, dstsize, n;
107     unsigned char *dst;
108     block_t *p_block;
109     z_stream d_stream;
110
111     d_stream.zalloc = (alloc_func)0;
112     d_stream.zfree = (free_func)0;
113     d_stream.opaque = (voidpf)0;
114     result = inflateInit(&d_stream);
115     if( result != Z_OK )
116     {
117         msg_Dbg( p_this, "inflateInit() failed. Result: %d", result );
118         return NULL;
119     }
120
121     d_stream.next_in = (Bytef *)p_in_block->p_buffer;
122     d_stream.avail_in = p_in_block->i_buffer;
123     n = 0;
124     p_block = block_Alloc( 0 );
125     dst = NULL;
126     do
127     {
128         n++;
129         p_block = block_Realloc( p_block, 0, n * 1000 );
130         dst = (unsigned char *)p_block->p_buffer;
131         d_stream.next_out = (Bytef *)&dst[(n - 1) * 1000];
132         d_stream.avail_out = 1000;
133         result = inflate(&d_stream, Z_NO_FLUSH);
134         if( ( result != Z_OK ) && ( result != Z_STREAM_END ) )
135         {
136             msg_Err( p_this, "Zlib decompression failed. Result: %d", result );
137             inflateEnd( &d_stream );
138             block_Release( p_block );
139             return p_in_block;
140         }
141     }
142     while( ( d_stream.avail_out == 0 ) && ( d_stream.avail_in != 0 ) &&
143            ( result != Z_STREAM_END ) );
144
145     dstsize = d_stream.total_out;
146     inflateEnd( &d_stream );
147
148     p_block = block_Realloc( p_block, 0, dstsize );
149     p_block->i_buffer = dstsize;
150     block_Release( p_in_block );
151
152     return p_block;
153 }
154 #endif
155
156 /* Utility function for BlockDecode */
157 block_t *MemToBlock( uint8_t *p_mem, size_t i_mem, size_t offset)
158 {
159     if( unlikely( i_mem > SIZE_MAX - offset ) )
160         return NULL;
161
162     block_t *p_block = block_Alloc( i_mem + offset );
163     if( likely(p_block != NULL) )
164     {
165         memcpy( p_block->p_buffer + offset, p_mem, i_mem );
166     }
167     return p_block;
168 }
169
170
171 void handle_real_audio(demux_t * p_demux, mkv_track_t * p_tk, block_t * p_blk, mtime_t i_pts)
172 {
173     uint8_t * p_frame = p_blk->p_buffer;
174     Cook_PrivateTrackData * p_sys = (Cook_PrivateTrackData *) p_tk->p_sys;
175     size_t size = p_blk->i_buffer;
176
177     if( p_tk->i_last_dts == VLC_TS_INVALID )
178     {
179         for( size_t i = 0; i < p_sys->i_subpackets; i++)
180             if( p_sys->p_subpackets[i] )
181             {
182                 block_Release(p_sys->p_subpackets[i]);
183                 p_sys->p_subpackets[i] = NULL;
184             }
185         p_sys->i_subpacket = 0;
186     }
187
188     if( p_tk->fmt.i_codec == VLC_CODEC_COOK ||
189         p_tk->fmt.i_codec == VLC_CODEC_ATRAC3 )
190     {
191         const uint16_t i_num = p_sys->i_frame_size / p_sys->i_subpacket_size;
192         const size_t y = p_sys->i_subpacket / ( p_sys->i_frame_size / p_sys->i_subpacket_size );
193
194         for( uint16_t i = 0; i < i_num; i++ )
195         {
196             size_t i_index = (size_t) p_sys->i_sub_packet_h * i +
197                           ((p_sys->i_sub_packet_h + 1) / 2) * (y&1) + (y>>1);
198             if( i_index >= p_sys->i_subpackets )
199                 return;
200
201             block_t *p_block = block_Alloc( p_sys->i_subpacket_size );
202             if( !p_block )
203                 return;
204
205             if( size < p_sys->i_subpacket_size )
206                 return;
207
208             memcpy( p_block->p_buffer, p_frame, p_sys->i_subpacket_size );
209             p_block->i_dts = VLC_TS_INVALID;
210             p_block->i_pts = VLC_TS_INVALID;
211             if( !p_sys->i_subpacket )
212             {
213                 p_tk->i_last_dts = 
214                 p_block->i_pts = i_pts + VLC_TS_0;
215             }
216
217             p_frame += p_sys->i_subpacket_size;
218             size -=  p_sys->i_subpacket_size;
219
220             p_sys->i_subpacket++;
221             p_sys->p_subpackets[i_index] = p_block;
222         }
223     }
224     else
225     {
226         /*TODO*/
227     }
228     if( p_sys->i_subpacket == p_sys->i_subpackets )
229     {
230         for( size_t i = 0; i < p_sys->i_subpackets; i++)
231         {
232             es_out_Send( p_demux->out, p_tk->p_es,  p_sys->p_subpackets[i]);
233             p_sys->p_subpackets[i] = NULL;
234         }
235         p_sys->i_subpacket = 0;
236     }
237 }
238
239 int32_t Cook_PrivateTrackData::Init()
240 {
241     i_subpackets = (size_t) i_sub_packet_h * (size_t) i_frame_size / (size_t) i_subpacket_size;
242     p_subpackets = (block_t**) calloc(i_subpackets, sizeof(block_t*));
243
244     if( unlikely( !p_subpackets ) )
245     {
246         i_subpackets = 0;
247         return 1;
248     }
249
250     return 0;
251 }
252
253 Cook_PrivateTrackData::~Cook_PrivateTrackData()
254 {
255     for( size_t i = 0; i < i_subpackets; i++ )
256         if( p_subpackets[i] )
257             block_Release( p_subpackets[i] );
258
259     free( p_subpackets );    
260 }
261
262 static inline void fill_wvpk_block(uint16_t version, uint32_t block_samples, uint32_t flags,
263                                    uint32_t crc, uint8_t * src, size_t srclen, uint8_t * dst)
264 {
265     const uint8_t wvpk_header[] = {'w','v','p','k',         /* ckId */
266                                     0x0, 0x0, 0x0, 0x0,     /* ckSize */
267                                     0x0, 0x0,               /* version */
268                                     0x0,                    /* track_no */
269                                     0x0,                    /* index_no */
270                                     0xFF, 0xFF, 0xFF, 0xFF, /* total_samples */
271                                     0x0, 0x0, 0x0, 0x0 };   /* block_index */
272     memcpy( dst, wvpk_header, sizeof( wvpk_header ) );
273     SetDWLE( dst + 4, srclen + 24 );
274     SetWLE( dst + 8, version );
275     SetDWLE( dst + 20, block_samples );
276     SetDWLE( dst + 24, flags );
277     SetDWLE( dst + 28, crc );
278     memcpy( dst + 32, src, srclen ); 
279 }
280
281 block_t * packetize_wavpack( mkv_track_t * p_tk, uint8_t * buffer, size_t  size)
282 {
283     uint16_t version = 0x403;
284     uint32_t block_samples;
285     uint32_t flags;
286     uint32_t crc;
287     block_t * p_block = NULL;
288     
289     if( p_tk->i_extra_data >= 2 )
290         version = GetWLE( p_tk->p_extra_data );
291
292     if( size < 12 )
293         return NULL;
294  
295     block_samples = GetDWLE(buffer);
296     buffer += 4;
297     flags = GetDWLE(buffer);
298     size -= 4;
299
300     /* Check if WV_INITIAL_BLOCK and WV_FINAL_BLOCK are present */
301     if( ( flags & 0x1800 ) == 0x1800 )
302     {
303         crc = GetDWLE(buffer+4);
304         buffer += 8;
305         size -= 8;
306
307         p_block = block_Alloc( size + 32 );
308         if( !p_block )
309             return NULL;
310
311         fill_wvpk_block(version, block_samples, flags, crc, buffer, size, p_block->p_buffer);
312     }
313     else
314     {
315         /* Multiblock */
316         size_t total_size = 0; 
317
318         p_block = block_Alloc( 0 );
319         if( !p_block )
320             return NULL;
321
322         while(size >= 12)
323         {
324             flags = GetDWLE(buffer);
325             buffer += 4;
326             crc = GetDWLE(buffer);
327             buffer += 4;
328             uint32_t bsz = GetDWLE(buffer);
329             buffer+= 4;
330             size -= 12;
331
332             bsz = (bsz < size)?bsz:size;
333
334             total_size += bsz + 32;
335
336             assert(total_size >= p_block->i_buffer);
337
338             p_block = block_Realloc( p_block, 0, total_size );
339
340             if( !p_block )
341                 return NULL;
342
343             fill_wvpk_block(version, block_samples, flags, crc, buffer, bsz,
344                             p_block->p_buffer + total_size - bsz - 32 );
345             buffer += bsz;
346             size -= bsz;
347         }
348     }
349
350     return p_block;
351 }