]> git.sesse.net Git - vlc/blob - modules/demux/mkv/util.cpp
MKV: fix COOK/ATRAC3 seeking
[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         if ( !( p_blk->i_flags & BLOCK_FLAG_TYPE_I) )
188         {
189             msg_Dbg( p_demux, "discard non-key preroll block in track %d at%"PRId64,
190                      p_tk->i_number, i_pts );
191             return;
192         }
193     }
194
195     if( p_tk->fmt.i_codec == VLC_CODEC_COOK ||
196         p_tk->fmt.i_codec == VLC_CODEC_ATRAC3 )
197     {
198         const uint16_t i_num = p_sys->i_frame_size / p_sys->i_subpacket_size;
199         const size_t y = p_sys->i_subpacket / ( p_sys->i_frame_size / p_sys->i_subpacket_size );
200
201         for( uint16_t i = 0; i < i_num; i++ )
202         {
203             size_t i_index = (size_t) p_sys->i_sub_packet_h * i +
204                           ((p_sys->i_sub_packet_h + 1) / 2) * (y&1) + (y>>1);
205             if( i_index >= p_sys->i_subpackets )
206                 return;
207
208             block_t *p_block = block_Alloc( p_sys->i_subpacket_size );
209             if( !p_block )
210                 return;
211
212             if( size < p_sys->i_subpacket_size )
213                 return;
214
215             memcpy( p_block->p_buffer, p_frame, p_sys->i_subpacket_size );
216             p_block->i_dts = VLC_TS_INVALID;
217             p_block->i_pts = VLC_TS_INVALID;
218             if( !p_sys->i_subpacket )
219             {
220                 p_tk->i_last_dts = 
221                 p_block->i_pts = i_pts;
222             }
223
224             p_frame += p_sys->i_subpacket_size;
225             size -=  p_sys->i_subpacket_size;
226
227             p_sys->i_subpacket++;
228             p_sys->p_subpackets[i_index] = p_block;
229         }
230     }
231     else
232     {
233         /*TODO*/
234     }
235     if( p_sys->i_subpacket == p_sys->i_subpackets )
236     {
237         for( size_t i = 0; i < p_sys->i_subpackets; i++)
238         {
239             es_out_Send( p_demux->out, p_tk->p_es,  p_sys->p_subpackets[i]);
240             p_sys->p_subpackets[i] = NULL;
241         }
242         p_sys->i_subpacket = 0;
243     }
244 }
245
246 int32_t Cook_PrivateTrackData::Init()
247 {
248     i_subpackets = (size_t) i_sub_packet_h * (size_t) i_frame_size / (size_t) i_subpacket_size;
249     p_subpackets = (block_t**) calloc(i_subpackets, sizeof(block_t*));
250
251     if( unlikely( !p_subpackets ) )
252     {
253         i_subpackets = 0;
254         return 1;
255     }
256
257     return 0;
258 }
259
260 Cook_PrivateTrackData::~Cook_PrivateTrackData()
261 {
262     for( size_t i = 0; i < i_subpackets; i++ )
263         if( p_subpackets[i] )
264             block_Release( p_subpackets[i] );
265
266     free( p_subpackets );    
267 }
268
269 static inline void fill_wvpk_block(uint16_t version, uint32_t block_samples, uint32_t flags,
270                                    uint32_t crc, uint8_t * src, size_t srclen, uint8_t * dst)
271 {
272     const uint8_t wvpk_header[] = {'w','v','p','k',         /* ckId */
273                                     0x0, 0x0, 0x0, 0x0,     /* ckSize */
274                                     0x0, 0x0,               /* version */
275                                     0x0,                    /* track_no */
276                                     0x0,                    /* index_no */
277                                     0xFF, 0xFF, 0xFF, 0xFF, /* total_samples */
278                                     0x0, 0x0, 0x0, 0x0 };   /* block_index */
279     memcpy( dst, wvpk_header, sizeof( wvpk_header ) );
280     SetDWLE( dst + 4, srclen + 24 );
281     SetWLE( dst + 8, version );
282     SetDWLE( dst + 20, block_samples );
283     SetDWLE( dst + 24, flags );
284     SetDWLE( dst + 28, crc );
285     memcpy( dst + 32, src, srclen ); 
286 }
287
288 block_t * packetize_wavpack( mkv_track_t * p_tk, uint8_t * buffer, size_t  size)
289 {
290     uint16_t version = 0x403;
291     uint32_t block_samples;
292     uint32_t flags;
293     uint32_t crc;
294     block_t * p_block = NULL;
295     
296     if( p_tk->i_extra_data >= 2 )
297         version = GetWLE( p_tk->p_extra_data );
298
299     if( size < 12 )
300         return NULL;
301  
302     block_samples = GetDWLE(buffer);
303     buffer += 4;
304     flags = GetDWLE(buffer);
305     size -= 4;
306
307     /* Check if WV_INITIAL_BLOCK and WV_FINAL_BLOCK are present */
308     if( ( flags & 0x1800 ) == 0x1800 )
309     {
310         crc = GetDWLE(buffer+4);
311         buffer += 8;
312         size -= 8;
313
314         p_block = block_Alloc( size + 32 );
315         if( !p_block )
316             return NULL;
317
318         fill_wvpk_block(version, block_samples, flags, crc, buffer, size, p_block->p_buffer);
319     }
320     else
321     {
322         /* Multiblock */
323         size_t total_size = 0; 
324
325         p_block = block_Alloc( 0 );
326         if( !p_block )
327             return NULL;
328
329         while(size >= 12)
330         {
331             flags = GetDWLE(buffer);
332             buffer += 4;
333             crc = GetDWLE(buffer);
334             buffer += 4;
335             uint32_t bsz = GetDWLE(buffer);
336             buffer+= 4;
337             size -= 12;
338
339             bsz = (bsz < size)?bsz:size;
340
341             total_size += bsz + 32;
342
343             assert(total_size >= p_block->i_buffer);
344
345             p_block = block_Realloc( p_block, 0, total_size );
346
347             if( !p_block )
348                 return NULL;
349
350             fill_wvpk_block(version, block_samples, flags, crc, buffer, bsz,
351                             p_block->p_buffer + total_size - bsz - 32 );
352             buffer += bsz;
353             size -= bsz;
354         }
355     }
356
357     return p_block;
358 }