/src/vlc/modules/demux/mkv/util.cpp
Line | Count | Source |
1 | | /***************************************************************************** |
2 | | * util.cpp : matroska demuxer |
3 | | ***************************************************************************** |
4 | | * Copyright (C) 2003-2004 VLC authors and VideoLAN |
5 | | * |
6 | | * Authors: Laurent Aimar <fenrir@via.ecp.fr> |
7 | | * Steve Lhomme <steve.lhomme@free.fr> |
8 | | * |
9 | | * This program is free software; you can redistribute it and/or modify it |
10 | | * under the terms of the GNU Lesser General Public License as published by |
11 | | * the Free Software Foundation; either version 2.1 of the License, or |
12 | | * (at your option) any later version. |
13 | | * |
14 | | * This program is distributed in the hope that it will be useful, |
15 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | | * GNU Lesser General Public License for more details. |
18 | | * |
19 | | * You should have received a copy of the GNU Lesser General Public License |
20 | | * along with this program; if not, write to the Free Software Foundation, |
21 | | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
22 | | *****************************************************************************/ |
23 | | #include "mkv.hpp" |
24 | | #include "util.hpp" |
25 | | #include "demux.hpp" |
26 | | #include "virtual_segment.hpp" |
27 | | #include "../../codec/webvtt/helpers.h" |
28 | | |
29 | | #include "lzokay.hpp" |
30 | | |
31 | | namespace mkv { |
32 | | |
33 | | /***************************************************************************** |
34 | | * Local prototypes |
35 | | *****************************************************************************/ |
36 | | |
37 | | #ifdef HAVE_ZLIB |
38 | | int32_t zlib_decompress_extra( demux_t * p_demux, mkv_track_t & tk ) |
39 | | { |
40 | | int result; |
41 | | z_stream d_stream; |
42 | | size_t n = 0; |
43 | | uint8_t * p_new_extra = NULL; |
44 | | |
45 | | msg_Dbg(p_demux,"Inflating private data"); |
46 | | |
47 | | d_stream.zalloc = Z_NULL; |
48 | | d_stream.zfree = Z_NULL; |
49 | | d_stream.opaque = Z_NULL; |
50 | | if( inflateInit( &d_stream ) != Z_OK ) |
51 | | { |
52 | | msg_Err( p_demux, "Couldn't initiate inflation ignore track %u", |
53 | | tk.i_number ); |
54 | | return 1; |
55 | | } |
56 | | |
57 | | d_stream.next_in = tk.p_extra_data; |
58 | | d_stream.avail_in = tk.i_extra_data; |
59 | | do |
60 | | { |
61 | | n++; |
62 | | void *alloc = realloc(p_new_extra, n*1024); |
63 | | if( alloc == NULL ) |
64 | | { |
65 | | msg_Err( p_demux, "Couldn't allocate buffer to inflate data, ignore track %u", |
66 | | tk.i_number ); |
67 | | free(p_new_extra); |
68 | | inflateEnd( &d_stream ); |
69 | | return 1; |
70 | | } |
71 | | |
72 | | p_new_extra = static_cast<uint8_t *>( alloc ); |
73 | | d_stream.next_out = &p_new_extra[(n - 1) * 1024]; |
74 | | d_stream.avail_out = 1024; |
75 | | result = inflate(&d_stream, Z_NO_FLUSH); |
76 | | if( result != Z_OK && result != Z_STREAM_END ) |
77 | | { |
78 | | msg_Err( p_demux, "Zlib decompression failed. Result: %d", result ); |
79 | | inflateEnd( &d_stream ); |
80 | | free(p_new_extra); |
81 | | return 1; |
82 | | } |
83 | | } |
84 | | while ( d_stream.avail_out == 0 && d_stream.avail_in != 0 && |
85 | | result != Z_STREAM_END ); |
86 | | |
87 | | free( tk.p_extra_data ); |
88 | | tk.i_extra_data = d_stream.total_out; |
89 | | p_new_extra = static_cast<uint8_t *>( realloc(p_new_extra, tk.i_extra_data) ); |
90 | | if( !p_new_extra ) |
91 | | { |
92 | | msg_Err( p_demux, "Couldn't allocate buffer to inflate data, ignore track %u", |
93 | | tk.i_number ); |
94 | | inflateEnd( &d_stream ); |
95 | | tk.p_extra_data = NULL; |
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 = NULL; |
112 | | d_stream.zfree = NULL; |
113 | | d_stream.opaque = NULL; |
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 = static_cast<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 | | bool lzo1x_decompress_extra( demux_t * p_demux, mkv_track_t & tk ) |
157 | 0 | { |
158 | 0 | lzokay::EResult result; |
159 | 0 | size_t n = 0, total_out = 0; |
160 | 0 | uint8_t * p_new_extra = nullptr; |
161 | |
|
162 | 0 | msg_Dbg(p_demux,"Inflating private data"); |
163 | |
|
164 | 0 | do |
165 | 0 | { |
166 | 0 | n++; |
167 | 0 | void *alloc = realloc(p_new_extra, n * 1024); |
168 | 0 | if( alloc == nullptr ) |
169 | 0 | { |
170 | 0 | msg_Err( p_demux, "Couldn't allocate buffer to inflate data, ignore track %u", |
171 | 0 | tk.i_number ); |
172 | 0 | free(p_new_extra); |
173 | 0 | return false; |
174 | 0 | } |
175 | | |
176 | 0 | p_new_extra = static_cast<uint8_t *>( alloc ); |
177 | 0 | result = lzokay::decompress( tk.p_extra_data, tk.i_extra_data, |
178 | 0 | p_new_extra, n * 1024, total_out ); |
179 | 0 | } |
180 | 0 | while ( result == lzokay::EResult::OutputOverrun ); |
181 | | |
182 | 0 | if( result != lzokay::EResult::Success ) |
183 | 0 | { |
184 | 0 | msg_Err( p_demux, "LZO1X private data decompression failed. Result: %d", (int)result ); |
185 | 0 | free(p_new_extra); |
186 | 0 | return false; |
187 | 0 | } |
188 | | |
189 | 0 | free( tk.p_extra_data ); |
190 | 0 | tk.i_extra_data = total_out; |
191 | 0 | tk.p_extra_data = p_new_extra; |
192 | |
|
193 | 0 | return true; |
194 | 0 | } |
195 | | |
196 | 24.1k | block_t *block_lzo1x_decompress( vlc_object_t *p_this, block_t *p_in_block ) { |
197 | 24.1k | lzokay::EResult result; |
198 | 24.1k | size_t dstsize = 0, n; |
199 | 24.1k | block_t *p_block; |
200 | | |
201 | 24.1k | n = 0; |
202 | 24.1k | p_block = block_Alloc( 0 ); |
203 | 24.1k | do |
204 | 27.3k | { |
205 | 27.3k | n++; |
206 | 27.3k | p_block = block_Realloc( p_block, 0, n * 1000 ); |
207 | 27.3k | result = lzokay::decompress( p_in_block->p_buffer, p_in_block->i_buffer, |
208 | 27.3k | p_block->p_buffer, p_block->i_buffer, dstsize ); |
209 | 27.3k | } |
210 | 27.3k | while( result == lzokay::EResult::OutputOverrun ); |
211 | | |
212 | 24.1k | if( result != lzokay::EResult::Success ) |
213 | 22.6k | { |
214 | 22.6k | msg_Err( p_this, "LZO1X decompression failed. Result: %d", (int)result ); |
215 | 22.6k | block_Release( p_block ); |
216 | 22.6k | return p_in_block; |
217 | 22.6k | } |
218 | | |
219 | 1.41k | p_block = block_Realloc( p_block, 0, dstsize ); |
220 | 1.41k | p_block->i_buffer = dstsize; |
221 | 1.41k | block_Release( p_in_block ); |
222 | | |
223 | 1.41k | return p_block; |
224 | 24.1k | } |
225 | | |
226 | | /* Utility function for BlockDecode */ |
227 | | block_t *MemToBlock( uint8_t *p_mem, size_t i_mem, size_t offset) |
228 | 74.4k | { |
229 | 74.4k | if( unlikely( i_mem > SIZE_MAX - offset ) ) |
230 | 0 | return NULL; |
231 | | |
232 | 74.4k | block_t *p_block = block_Alloc( i_mem + offset ); |
233 | 74.4k | if( likely(p_block != NULL) ) |
234 | 74.4k | { |
235 | 74.4k | memcpy( p_block->p_buffer + offset, p_mem, i_mem ); |
236 | 74.4k | } |
237 | 74.4k | return p_block; |
238 | 74.4k | } |
239 | | |
240 | | |
241 | | void handle_real_audio(demux_t * p_demux, mkv_track_t * p_tk, block_t * p_blk, vlc_tick_t i_pts) |
242 | 2.57k | { |
243 | 2.57k | uint8_t * p_frame = p_blk->p_buffer; |
244 | 2.57k | Cook_PrivateTrackData * p_sys = static_cast<Cook_PrivateTrackData *>(p_tk->p_sys); |
245 | 2.57k | size_t size = p_blk->i_buffer; |
246 | | |
247 | 2.57k | if( p_tk->i_last_dts == VLC_TICK_INVALID ) |
248 | 1.78k | { |
249 | 304M | for( size_t i = 0; i < p_sys->p_subpackets.size(); i++) |
250 | 304M | if( p_sys->p_subpackets[i] ) |
251 | 49 | { |
252 | 49 | block_Release(p_sys->p_subpackets[i]); |
253 | 49 | p_sys->p_subpackets[i] = NULL; |
254 | 49 | } |
255 | 1.78k | p_sys->i_subpacket = 0; |
256 | | |
257 | 1.78k | if ( !( p_blk->i_flags & BLOCK_FLAG_TYPE_I) ) |
258 | 187 | { |
259 | 187 | msg_Dbg( p_demux, "discard non-key preroll block in track %u at %" PRId64, |
260 | 187 | p_tk->i_number, i_pts ); |
261 | 187 | return; |
262 | 187 | } |
263 | 1.78k | } |
264 | | |
265 | 2.38k | if( p_tk->fmt.i_codec == VLC_CODEC_COOK || |
266 | 0 | p_tk->fmt.i_codec == VLC_CODEC_ATRAC3 ) |
267 | 2.38k | { |
268 | 2.38k | const uint16_t i_num = p_sys->i_frame_size / p_sys->i_subpacket_size; |
269 | 2.38k | if ( i_num == 0 ) |
270 | 558 | return; |
271 | 1.82k | const size_t y = p_sys->i_subpacket / i_num; |
272 | | |
273 | 7.70k | for( uint16_t i = 0; i < i_num; i++ ) |
274 | 7.10k | { |
275 | 7.10k | size_t i_index = (size_t) p_sys->i_sub_packet_h * i + |
276 | 7.10k | ((p_sys->i_sub_packet_h + 1) / 2) * (y&1) + (y>>1); |
277 | 7.10k | if( unlikely(i_index >= p_sys->p_subpackets.size()) ) |
278 | 150 | return; |
279 | | |
280 | 6.95k | if( size < p_sys->i_subpacket_size ) |
281 | 1.07k | return; |
282 | | |
283 | 5.87k | if (likely(p_sys->p_subpackets[i_index] == nullptr)) |
284 | 4.61k | { |
285 | | // the index was not used |
286 | 4.61k | block_t *p_block = block_Alloc( p_sys->i_subpacket_size ); |
287 | 4.61k | if( !p_block ) |
288 | 0 | return; |
289 | | |
290 | 4.61k | memcpy( p_block->p_buffer, p_frame, p_sys->i_subpacket_size ); |
291 | 4.61k | p_block->i_dts = VLC_TICK_INVALID; |
292 | 4.61k | p_block->i_pts = VLC_TICK_INVALID; |
293 | 4.61k | if( p_sys->i_subpacket == 0 ) |
294 | 118 | { |
295 | 118 | p_tk->i_last_dts = |
296 | 118 | p_block->i_pts = i_pts; |
297 | 118 | } |
298 | 4.61k | p_sys->p_subpackets[i_index] = p_block; |
299 | 4.61k | } |
300 | | |
301 | 5.87k | p_frame += p_sys->i_subpacket_size; |
302 | 5.87k | size -= p_sys->i_subpacket_size; |
303 | | |
304 | 5.87k | p_sys->i_subpacket++; |
305 | 5.87k | } |
306 | 1.82k | } |
307 | 0 | else |
308 | 0 | { |
309 | | /*TODO*/ |
310 | 0 | } |
311 | 598 | if( p_sys->i_subpacket == p_sys->p_subpackets.size() ) |
312 | 48 | { |
313 | 1.24k | for( size_t i = 0; i < p_sys->p_subpackets.size(); i++) |
314 | 1.19k | { |
315 | 1.19k | if (likely(p_sys->p_subpackets[i])) |
316 | 1.16k | { |
317 | 1.16k | send_Block( p_demux, p_tk, p_sys->p_subpackets[i], 1, 0 ); |
318 | 1.16k | p_sys->p_subpackets[i] = NULL; |
319 | 1.16k | } |
320 | 1.19k | } |
321 | 48 | p_sys->i_subpacket = 0; |
322 | 48 | } |
323 | 598 | } |
324 | | |
325 | | block_t *WEBVTT_Repack_Sample(block_t *p_block, bool b_webm, |
326 | | const uint8_t *p_add, size_t i_add) |
327 | 0 | { |
328 | 0 | struct webvtt_cueelements_s els; |
329 | 0 | memset(&els, 0, sizeof(els)); |
330 | 0 | size_t newsize = 0; |
331 | 0 | block_t *newblock = nullptr; |
332 | | /* Repack to ISOBMFF samples format */ |
333 | 0 | if( !b_webm ) /* S_TEXT/WEBVTT */ |
334 | 0 | { |
335 | | /* process addition fields */ |
336 | 0 | if( i_add ) |
337 | 0 | { |
338 | 0 | const uint8_t *end = p_add + i_add; |
339 | 0 | const uint8_t *iden = |
340 | 0 | reinterpret_cast<const uint8_t *>(std::memchr( p_add, '\n', i_add )); |
341 | 0 | if( iden && ++iden != end ) |
342 | 0 | { |
343 | 0 | els.sttg.p_data = p_add; |
344 | 0 | els.sttg.i_data = &iden[-1] - p_add; |
345 | 0 | const uint8_t *comm = |
346 | 0 | reinterpret_cast<const uint8_t *>(std::memchr( iden, '\n', end - iden )); |
347 | 0 | els.iden.p_data = iden; |
348 | 0 | if( comm ) |
349 | 0 | els.iden.i_data = comm - iden; |
350 | 0 | else |
351 | 0 | els.iden.i_data = end - iden; |
352 | 0 | } |
353 | 0 | } |
354 | | /* the payload being in the block */ |
355 | 0 | els.payl.p_data = p_block->p_buffer; |
356 | 0 | els.payl.i_data = p_block->i_buffer; |
357 | 0 | } |
358 | 0 | else /* deprecated D_WEBVTT/ */ |
359 | 0 | { |
360 | 0 | const uint8_t *start = p_block->p_buffer; |
361 | 0 | const uint8_t *end = p_block->p_buffer + p_block->i_buffer; |
362 | 0 | const uint8_t *sttg = |
363 | 0 | reinterpret_cast<const uint8_t *>(std::memchr( start, '\n', p_block->i_buffer )); |
364 | 0 | if( !sttg || ++sttg == end ) |
365 | 0 | goto error; |
366 | 0 | const uint8_t *payl = |
367 | 0 | reinterpret_cast<const uint8_t *>(std::memchr( sttg, '\n', end - sttg )); |
368 | 0 | if( !payl || ++payl == end ) |
369 | 0 | goto error; |
370 | 0 | els.iden.p_data = start; |
371 | 0 | els.iden.i_data = &sttg[-1] - start; |
372 | 0 | els.sttg.p_data = sttg; |
373 | 0 | els.sttg.i_data = &payl[-1] - sttg; |
374 | 0 | els.payl.p_data = payl; |
375 | 0 | els.payl.i_data = end - payl; |
376 | 0 | } |
377 | | |
378 | 0 | newsize = WEBVTT_Pack_CueElementsGetNewSize( &els ); |
379 | 0 | newblock = block_Alloc( newsize ); |
380 | 0 | if( !newblock ) |
381 | 0 | goto error; |
382 | 0 | WEBVTT_Pack_CueElements( &els, newblock->p_buffer ); |
383 | 0 | block_CopyProperties( newblock, p_block ); |
384 | 0 | block_Release( p_block ); |
385 | 0 | return newblock; |
386 | | |
387 | 0 | error: |
388 | 0 | block_Release( p_block ); |
389 | 0 | return NULL; |
390 | 0 | } |
391 | | |
392 | | int UpdatePCR( demux_t * p_demux ) |
393 | 34.3k | { |
394 | 34.3k | demux_sys_t *p_sys = (demux_sys_t *)p_demux->p_sys; |
395 | 34.3k | matroska_segment_c *p_segment = p_sys->GetCurrentVSegment()->CurrentSegment(); |
396 | | |
397 | 34.3k | vlc_tick_t i_pcr = VLC_TICK_INVALID; |
398 | | |
399 | 34.3k | for( const auto & it : p_segment->tracks ) |
400 | 67.3k | { |
401 | 67.3k | const auto &track = it.second; |
402 | | |
403 | 67.3k | if( track->i_last_dts == VLC_TICK_INVALID ) |
404 | 28.9k | continue; |
405 | | |
406 | 38.3k | if( track->fmt.i_cat != VIDEO_ES && track->fmt.i_cat != AUDIO_ES ) |
407 | 469 | continue; |
408 | | |
409 | 37.9k | if( track->i_last_dts < i_pcr || i_pcr == VLC_TICK_INVALID ) |
410 | 30.4k | { |
411 | 30.4k | i_pcr = track->i_last_dts; |
412 | 30.4k | } |
413 | 37.9k | } |
414 | | |
415 | 34.3k | if( i_pcr != VLC_TICK_INVALID && i_pcr > p_sys->i_pcr ) |
416 | 14.5k | { |
417 | 14.5k | if( es_out_SetPCR( p_demux->out, i_pcr ) ) |
418 | 0 | { |
419 | 0 | msg_Err( p_demux, "ES_OUT_SET_PCR failed, aborting." ); |
420 | 0 | return VLC_EGENERIC; |
421 | 0 | } |
422 | | |
423 | 14.5k | p_sys->i_pcr = i_pcr; |
424 | 14.5k | } |
425 | | |
426 | 34.3k | return VLC_SUCCESS; |
427 | 34.3k | } |
428 | | |
429 | | void send_Block( demux_t * p_demux, mkv_track_t * p_tk, block_t * p_block, unsigned int i_number_frames, int64_t i_duration ) |
430 | 73.5k | { |
431 | 73.5k | demux_sys_t *p_sys = (demux_sys_t *)p_demux->p_sys; |
432 | 73.5k | matroska_segment_c *p_segment = p_sys->GetCurrentVSegment()->CurrentSegment(); |
433 | | |
434 | 73.5k | if( p_tk->fmt.i_cat == AUDIO_ES && p_tk->i_chans_to_reorder ) |
435 | 0 | { |
436 | 0 | aout_ChannelReorder( p_block->p_buffer, p_block->i_buffer, |
437 | 0 | p_tk->i_chans_to_reorder, |
438 | 0 | p_tk->pi_chan_table, p_tk->fmt.i_codec ); |
439 | 0 | } |
440 | | |
441 | 73.5k | if( p_block->i_dts != VLC_TICK_INVALID && |
442 | 48.6k | ( p_tk->fmt.i_cat == VIDEO_ES || p_tk->fmt.i_cat == AUDIO_ES ) ) |
443 | 47.1k | { |
444 | 47.1k | p_tk->i_last_dts = p_block->i_dts; |
445 | 47.1k | } |
446 | | |
447 | 73.5k | if( !p_tk->b_no_duration ) |
448 | 72.2k | { |
449 | 72.2k | p_block->i_length = VLC_TICK_FROM_NS(i_duration * p_tk->f_timecodescale * |
450 | 72.2k | p_segment->i_timescale) / i_number_frames; |
451 | 72.2k | } |
452 | | |
453 | 73.5k | if( p_tk->b_discontinuity ) |
454 | 230 | { |
455 | 230 | p_block->i_flags |= BLOCK_FLAG_DISCONTINUITY; |
456 | 230 | p_tk->b_discontinuity = false; |
457 | 230 | } |
458 | | |
459 | 73.5k | if ( p_sys->i_pcr == VLC_TICK_INVALID ) |
460 | 3.38k | UpdatePCR( p_demux ); |
461 | | |
462 | 73.5k | es_out_Send( p_demux->out, p_tk->p_es, p_block); |
463 | 73.5k | } |
464 | | |
465 | | struct real_audio_private |
466 | | { |
467 | | uint32_t fourcc; |
468 | | uint16_t version; |
469 | | uint16_t unknown1; |
470 | | uint8_t unknown2[12]; |
471 | | uint16_t unknown3; |
472 | | uint16_t flavor; |
473 | | uint32_t coded_frame_size; |
474 | | uint32_t unknown4[3]; |
475 | | uint16_t sub_packet_h; |
476 | | uint16_t frame_size; |
477 | | uint16_t sub_packet_size; |
478 | | uint16_t unknown5; |
479 | | }; |
480 | | |
481 | | struct real_audio_private_v4 |
482 | | { |
483 | | real_audio_private header; |
484 | | uint16_t sample_rate; |
485 | | uint16_t unknown; |
486 | | uint16_t sample_size; |
487 | | uint16_t channels; |
488 | | }; |
489 | | |
490 | | |
491 | | struct real_audio_private_v5 |
492 | | { |
493 | | real_audio_private header; |
494 | | uint32_t unknown1; |
495 | | uint16_t unknown2; |
496 | | uint16_t sample_rate; |
497 | | uint16_t unknown3; |
498 | | uint16_t sample_size; |
499 | | uint16_t channels; |
500 | | }; |
501 | | |
502 | | bool Cook_PrivateTrackData::Init() |
503 | 183 | { |
504 | | // real_audio_private |
505 | 183 | bytes.skip(4); // fourcc |
506 | | |
507 | | /* FIXME RALF and SIPR */ |
508 | 183 | uint16_t version = bytes.GetBE16(); // version |
509 | 183 | bytes.skip(2); // unknown1 |
510 | 183 | bytes.skip(12); // unknown2 |
511 | 183 | bytes.skip(2); // unknown3 |
512 | 183 | bytes.skip(2); // flavor |
513 | 183 | coded_frame_size = bytes.GetBE32(); // coded_frame_size |
514 | 183 | bytes.skip(3*4); // unknown4 |
515 | 183 | i_sub_packet_h = bytes.GetBE16(); // sub_packet_h |
516 | 183 | i_frame_size = bytes.GetBE16(); // frame_size |
517 | 183 | i_subpacket_size = bytes.GetBE16(); // sub_packet_size |
518 | 183 | bytes.skip(2); // unknown5 |
519 | | |
520 | 183 | if ( i_subpacket_size == 0 ) |
521 | 5 | return false; |
522 | | |
523 | 178 | if( version == 4 ) |
524 | 6 | { |
525 | | // real_audio_private_v4 |
526 | 6 | i_rate = bytes.GetBE16(); // sample_rate |
527 | 6 | bytes.skip(2); // unknown |
528 | 6 | i_bitspersample = bytes.GetBE16(); // sample_size |
529 | 6 | i_channels = bytes.GetBE16(); // channels |
530 | 6 | } |
531 | 172 | else if( version == 5 ) |
532 | 167 | { |
533 | | // real_audio_private_v5 |
534 | 167 | bytes.skip(4); // unknown1 |
535 | 167 | bytes.skip(2); // unknown2 |
536 | 167 | i_rate = bytes.GetBE16(); // sample_rate |
537 | 167 | bytes.skip(2); // unknown2 |
538 | 167 | i_bitspersample = bytes.GetBE16(); // sample_size |
539 | 167 | i_channels = bytes.GetBE16(); // channels |
540 | 167 | } |
541 | 5 | else |
542 | 5 | return false; |
543 | 173 | if (bytes.hasErrors()) |
544 | 19 | return false; |
545 | | |
546 | 154 | size_t i_subpackets = (size_t) i_sub_packet_h * (size_t) i_frame_size / (size_t) i_subpacket_size; |
547 | 154 | p_subpackets.resize(i_subpackets); |
548 | | |
549 | 154 | return true; |
550 | 173 | } |
551 | | |
552 | | Cook_PrivateTrackData::~Cook_PrivateTrackData() |
553 | 183 | { |
554 | 256M | for( size_t i = 0; i < p_subpackets.size(); i++ ) |
555 | 256M | if( p_subpackets[i] ) |
556 | 3.39k | block_Release( p_subpackets[i] ); |
557 | 183 | } |
558 | | |
559 | | static inline void fill_wvpk_block(uint16_t version, uint32_t block_samples, uint32_t flags, |
560 | | uint32_t crc, uint8_t * src, size_t srclen, uint8_t * dst) |
561 | 857 | { |
562 | 857 | const uint8_t wvpk_header[] = {'w','v','p','k', /* ckId */ |
563 | 857 | 0x0, 0x0, 0x0, 0x0, /* ckSize */ |
564 | 857 | 0x0, 0x0, /* version */ |
565 | 857 | 0x0, /* track_no */ |
566 | 857 | 0x0, /* index_no */ |
567 | 857 | 0xFF, 0xFF, 0xFF, 0xFF, /* total_samples */ |
568 | 857 | 0x0, 0x0, 0x0, 0x0 }; /* block_index */ |
569 | 857 | memcpy( dst, wvpk_header, sizeof( wvpk_header ) ); |
570 | 857 | SetDWLE( dst + 4, srclen + 24 ); |
571 | 857 | SetWLE( dst + 8, version ); |
572 | 857 | SetDWLE( dst + 20, block_samples ); |
573 | 857 | SetDWLE( dst + 24, flags ); |
574 | 857 | SetDWLE( dst + 28, crc ); |
575 | 857 | memcpy( dst + 32, src, srclen ); |
576 | 857 | } |
577 | | |
578 | | block_t * packetize_wavpack( const mkv_track_t & tk, uint8_t * buffer, size_t size) |
579 | 522 | { |
580 | 522 | uint16_t version = 0x403; |
581 | 522 | uint32_t block_samples; |
582 | 522 | uint32_t flags; |
583 | 522 | uint32_t crc; |
584 | 522 | block_t * p_block = NULL; |
585 | | |
586 | 522 | if( tk.i_extra_data >= 2 ) |
587 | 522 | version = GetWLE( tk.p_extra_data ); |
588 | | |
589 | 522 | if( size < 12 ) |
590 | 6 | return NULL; |
591 | | |
592 | 516 | block_samples = GetDWLE(buffer); |
593 | 516 | buffer += 4; |
594 | 516 | flags = GetDWLE(buffer); |
595 | 516 | size -= 4; |
596 | | |
597 | | /* Check if WV_INITIAL_BLOCK and WV_FINAL_BLOCK are present */ |
598 | 516 | if( ( flags & 0x1800 ) == 0x1800 ) |
599 | 117 | { |
600 | 117 | crc = GetDWLE(buffer+4); |
601 | 117 | buffer += 8; |
602 | 117 | size -= 8; |
603 | | |
604 | 117 | p_block = block_Alloc( size + 32 ); |
605 | 117 | if( !p_block ) |
606 | 0 | return NULL; |
607 | | |
608 | 117 | fill_wvpk_block(version, block_samples, flags, crc, buffer, size, p_block->p_buffer); |
609 | 117 | } |
610 | 399 | else |
611 | 399 | { |
612 | | /* Multiblock */ |
613 | 399 | size_t total_size = 0; |
614 | | |
615 | 399 | p_block = block_Alloc( 0 ); |
616 | 399 | if( !p_block ) |
617 | 0 | return NULL; |
618 | | |
619 | 1.13k | while(size >= 12) |
620 | 740 | { |
621 | 740 | flags = GetDWLE(buffer); |
622 | 740 | buffer += 4; |
623 | 740 | crc = GetDWLE(buffer); |
624 | 740 | buffer += 4; |
625 | 740 | uint32_t bsz = GetDWLE(buffer); |
626 | 740 | buffer+= 4; |
627 | 740 | size -= 12; |
628 | | |
629 | 740 | bsz = (bsz < size)?bsz:size; |
630 | | |
631 | 740 | total_size += bsz + 32; |
632 | | |
633 | 740 | assert(total_size >= p_block->i_buffer); |
634 | | |
635 | 740 | p_block = block_Realloc( p_block, 0, total_size ); |
636 | | |
637 | 740 | if( !p_block ) |
638 | 0 | return NULL; |
639 | | |
640 | 740 | fill_wvpk_block(version, block_samples, flags, crc, buffer, bsz, |
641 | 740 | p_block->p_buffer + total_size - bsz - 32 ); |
642 | 740 | buffer += bsz; |
643 | 740 | size -= bsz; |
644 | 740 | } |
645 | 399 | } |
646 | | |
647 | 516 | return p_block; |
648 | 516 | } |
649 | | |
650 | | void MkvTree_va( demux_t& demuxer, int i_level, const char* fmt, va_list args) |
651 | 419k | { |
652 | 419k | static const char indent[] = "| "; |
653 | 419k | static const char prefix[] = "+ "; |
654 | 419k | static int const indent_len = sizeof( indent ) - 1; |
655 | 419k | static int const prefix_len = sizeof( prefix ) - 1; |
656 | | |
657 | 419k | char fixed_buffer[256] = {}; |
658 | 419k | size_t const static_len = sizeof( fixed_buffer ); |
659 | 419k | char * buffer = fixed_buffer; |
660 | 419k | size_t total_len = indent_len * i_level + prefix_len + strlen( fmt ) + 1; |
661 | | |
662 | 419k | if( total_len >= static_len ) { |
663 | 0 | buffer = new (std::nothrow) char[total_len] (); |
664 | |
|
665 | 0 | if (buffer == NULL) { |
666 | 0 | msg_Err (&demuxer, "Unable to allocate memory for format string"); |
667 | 0 | return; |
668 | 0 | } |
669 | 0 | } |
670 | | |
671 | 419k | char * dst = buffer; |
672 | | |
673 | 1.79M | for (int i = 0; i < i_level; ++i, dst += indent_len) |
674 | 1.37M | memcpy( dst, indent, indent_len ); |
675 | | |
676 | 419k | strcat( dst, prefix ); |
677 | 419k | strcat( dst, fmt ); |
678 | | |
679 | 419k | msg_GenericVa( &demuxer, VLC_MSG_DBG, buffer, args ); |
680 | | |
681 | 419k | if (buffer != fixed_buffer) |
682 | 0 | delete [] buffer; |
683 | 419k | } |
684 | | |
685 | | void MkvTree( demux_t & demuxer, int i_level, const char *psz_format, ... ) |
686 | 69.7k | { |
687 | 69.7k | va_list args; va_start( args, psz_format ); |
688 | 69.7k | MkvTree_va( demuxer, i_level, psz_format, args ); |
689 | | va_end( args ); |
690 | 69.7k | } |
691 | | |
692 | | } // namespace |