/src/vlc/modules/packetizer/mpegaudio.c
Line | Count | Source |
1 | | /***************************************************************************** |
2 | | * mpegaudio.c: parse MPEG audio sync info and packetize the stream |
3 | | ***************************************************************************** |
4 | | * Copyright (C) 2001-2016 VLC authors and VideoLAN |
5 | | * |
6 | | * Authors: Laurent Aimar <fenrir@via.ecp.fr> |
7 | | * Eric Petit <titer@videolan.org> |
8 | | * Christophe Massiot <massiot@via.ecp.fr> |
9 | | * Gildas Bazin <gbazin@videolan.org> |
10 | | * |
11 | | * This program is free software; you can redistribute it and/or modify it |
12 | | * under the terms of the GNU Lesser General Public License as published by |
13 | | * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. |
20 | | * |
21 | | * You should have received a copy of the GNU Lesser General Public License |
22 | | * along with this program; if not, write to the Free Software Foundation, |
23 | | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
24 | | *****************************************************************************/ |
25 | | |
26 | | /***************************************************************************** |
27 | | * Preamble |
28 | | *****************************************************************************/ |
29 | | #ifdef HAVE_CONFIG_H |
30 | | # include "config.h" |
31 | | #endif |
32 | | |
33 | | #include <vlc_common.h> |
34 | | #include <vlc_plugin.h> |
35 | | #include <vlc_codec.h> |
36 | | #include <vlc_aout.h> |
37 | | #include <vlc_modules.h> |
38 | | #include <assert.h> |
39 | | |
40 | | #include <vlc_block_helper.h> |
41 | | |
42 | | #include "packetizer_helper.h" |
43 | | #include "mpegaudio.h" |
44 | | |
45 | | /***************************************************************************** |
46 | | * decoder_sys_t : decoder descriptor |
47 | | *****************************************************************************/ |
48 | | typedef struct |
49 | | { |
50 | | /* |
51 | | * Input properties |
52 | | */ |
53 | | int i_state; |
54 | | |
55 | | block_bytestream_t bytestream; |
56 | | |
57 | | /* |
58 | | * Common properties |
59 | | */ |
60 | | date_t end_date; |
61 | | |
62 | | vlc_tick_t i_pts; |
63 | | |
64 | | unsigned int i_free_frame_size; |
65 | | struct mpga_frameheader_s header; |
66 | | |
67 | | bool b_discontinuity; |
68 | | } decoder_sys_t; |
69 | | |
70 | 14.4M | #define MAD_BUFFER_GUARD 8 |
71 | 11.8M | #define MPGA_HEADER_SIZE 4 |
72 | | |
73 | | /**************************************************************************** |
74 | | * Local prototypes |
75 | | ****************************************************************************/ |
76 | | |
77 | | static int Open( vlc_object_t * ); |
78 | | static void Close( vlc_object_t * ); |
79 | | |
80 | | /***************************************************************************** |
81 | | * Module descriptor |
82 | | *****************************************************************************/ |
83 | 104 | vlc_module_begin () |
84 | 52 | set_subcategory( SUBCAT_INPUT_ACODEC ) |
85 | 52 | set_description( N_("MPEG audio layer I/II/III packetizer") ) |
86 | 52 | set_capability( "audio packetizer", 10 ) |
87 | 104 | set_callbacks( Open, Close ) |
88 | 52 | vlc_module_end () |
89 | | |
90 | | /***************************************************************************** |
91 | | * Flush: |
92 | | *****************************************************************************/ |
93 | | static void Flush( decoder_t *p_dec ) |
94 | 0 | { |
95 | 0 | decoder_sys_t *p_sys = p_dec->p_sys; |
96 | |
|
97 | 0 | date_Set( &p_sys->end_date, VLC_TICK_INVALID ); |
98 | 0 | p_sys->i_state = STATE_NOSYNC; |
99 | 0 | block_BytestreamEmpty( &p_sys->bytestream ); |
100 | 0 | p_sys->b_discontinuity = true; |
101 | 0 | } |
102 | | |
103 | | /***************************************************************************** |
104 | | * GetOutBuffer: |
105 | | *****************************************************************************/ |
106 | | static uint8_t *GetOutBuffer( decoder_t *p_dec, block_t **pp_out_buffer ) |
107 | 276k | { |
108 | 276k | decoder_sys_t *p_sys = p_dec->p_sys; |
109 | | |
110 | 276k | if( p_dec->fmt_out.audio.i_rate != p_sys->header.i_sample_rate || |
111 | 275k | date_Get( &p_sys->end_date ) == VLC_TICK_INVALID ) |
112 | 1.68k | { |
113 | 1.68k | msg_Dbg( p_dec, "MPGA channels:%"PRIu8" samplerate:%u bitrate:%"PRIu16, |
114 | 1.68k | p_sys->header.i_channels, p_sys->header.i_sample_rate, |
115 | 1.68k | p_sys->header.i_bit_rate ); |
116 | | |
117 | 1.68k | if( p_sys->end_date.i_divider_num == 0 ) |
118 | 0 | date_Init( &p_sys->end_date, p_sys->header.i_sample_rate, 1 ); |
119 | 1.68k | else |
120 | 1.68k | date_Change( &p_sys->end_date, p_sys->header.i_sample_rate, 1 ); |
121 | 1.68k | date_Set( &p_sys->end_date, p_sys->i_pts ); |
122 | 1.68k | } |
123 | | |
124 | 276k | p_dec->fmt_out.i_profile = p_sys->header.i_layer; |
125 | 276k | p_dec->fmt_out.audio.i_rate = p_sys->header.i_sample_rate; |
126 | 276k | p_dec->fmt_out.audio.i_channels = p_sys->header.i_channels; |
127 | 276k | p_dec->fmt_out.audio.i_frame_length = p_sys->header.i_samples_per_frame; |
128 | 276k | p_dec->fmt_out.audio.i_bytes_per_frame = p_sys->header.i_max_frame_size; |
129 | | |
130 | 276k | p_dec->fmt_out.audio.i_physical_channels = p_sys->header.i_channels_conf; |
131 | 276k | p_dec->fmt_out.audio.i_chan_mode = p_sys->header.i_chan_mode; |
132 | | |
133 | 276k | p_dec->fmt_out.i_bitrate = p_sys->header.i_bit_rate * 1000U; |
134 | | |
135 | 276k | block_t *p_block = block_Alloc( p_sys->header.i_frame_size ); |
136 | 276k | if( p_block == NULL ) |
137 | 0 | return NULL; |
138 | | |
139 | 276k | p_block->i_pts = p_block->i_dts = date_Get( &p_sys->end_date ); |
140 | 276k | p_block->i_length = |
141 | 276k | date_Increment( &p_sys->end_date, p_sys->header.i_samples_per_frame ) - p_block->i_pts; |
142 | | |
143 | 276k | *pp_out_buffer = p_block; |
144 | 276k | return p_block->p_buffer; |
145 | 276k | } |
146 | | |
147 | | /**************************************************************************** |
148 | | * DecodeBlock: the whole thing |
149 | | **************************************************************************** |
150 | | * This function is called just after the thread is launched. |
151 | | ****************************************************************************/ |
152 | | static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) |
153 | 325k | { |
154 | 325k | decoder_sys_t *p_sys = p_dec->p_sys; |
155 | 325k | uint8_t p_header[MAD_BUFFER_GUARD]; |
156 | 325k | uint32_t i_header; |
157 | 325k | uint8_t *p_buf; |
158 | 325k | block_t *p_out_buffer; |
159 | | |
160 | 325k | block_t *p_block = pp_block ? *pp_block : NULL; |
161 | | |
162 | 325k | if (p_block) |
163 | 323k | { |
164 | 323k | if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) |
165 | 0 | { |
166 | | /* First always drain complete blocks before discontinuity */ |
167 | 0 | block_t *p_drain = DecodeBlock( p_dec, NULL ); |
168 | 0 | if( p_drain ) |
169 | 0 | return p_drain; |
170 | | |
171 | 0 | Flush( p_dec ); |
172 | |
|
173 | 0 | if( p_block->i_flags & BLOCK_FLAG_CORRUPTED ) |
174 | 0 | { |
175 | 0 | block_Release( p_block ); |
176 | 0 | return NULL; |
177 | 0 | } |
178 | 0 | } |
179 | | |
180 | 323k | if( p_block->i_pts == VLC_TICK_INVALID && |
181 | 319k | date_Get( &p_sys->end_date ) == VLC_TICK_INVALID ) |
182 | 5.39k | { |
183 | | /* We've just started the stream, wait for the first PTS. */ |
184 | 5.39k | msg_Dbg( p_dec, "waiting for PTS" ); |
185 | 5.39k | block_Release( p_block ); |
186 | 5.39k | return NULL; |
187 | 5.39k | } |
188 | | |
189 | 318k | block_BytestreamPush( &p_sys->bytestream, p_block ); |
190 | 318k | } |
191 | | |
192 | 23.5M | while( 1 ) |
193 | 23.5M | { |
194 | 23.5M | switch( p_sys->i_state ) |
195 | 23.5M | { |
196 | | |
197 | 11.6M | case STATE_NOSYNC: |
198 | 35.7M | while( block_PeekBytes( &p_sys->bytestream, p_header, 2 ) |
199 | 35.7M | == VLC_SUCCESS ) |
200 | 35.7M | { |
201 | | /* Look for sync word - should be 0xffe */ |
202 | 35.7M | if( p_header[0] == 0xff && (p_header[1] & 0xe0) == 0xe0 ) |
203 | 11.6M | { |
204 | 11.6M | p_sys->i_state = STATE_SYNC; |
205 | 11.6M | break; |
206 | 11.6M | } |
207 | 24.1M | block_SkipByte( &p_sys->bytestream ); |
208 | 24.1M | } |
209 | 11.6M | if( p_sys->i_state != STATE_SYNC ) |
210 | 6.32k | { |
211 | 6.32k | block_BytestreamFlush( &p_sys->bytestream ); |
212 | | |
213 | | /* Need more data */ |
214 | 6.32k | return NULL; |
215 | 6.32k | } |
216 | | /* fallthrough */ |
217 | | |
218 | 11.6M | case STATE_SYNC: |
219 | | /* New frame, set the Presentation Time Stamp */ |
220 | 11.6M | p_sys->i_pts = p_sys->bytestream.p_block->i_pts; |
221 | 11.6M | if( p_sys->i_pts != VLC_TICK_INVALID && |
222 | 250k | p_sys->i_pts != date_Get( &p_sys->end_date ) ) |
223 | 1.07k | { |
224 | 1.07k | if( p_dec->fmt_in->i_original_fourcc == VLC_FOURCC( 'D','V','R',' ') ) |
225 | 0 | { |
226 | 0 | if( date_Get( &p_sys->end_date ) == VLC_TICK_INVALID ) |
227 | 0 | date_Set( &p_sys->end_date, p_sys->i_pts ); |
228 | 0 | } |
229 | 1.07k | else if ( p_sys->i_pts != date_Get( &p_sys->end_date ) ) |
230 | 1.07k | { |
231 | 1.07k | date_Set( &p_sys->end_date, p_sys->i_pts ); |
232 | 1.07k | } |
233 | 1.07k | } |
234 | 11.6M | p_sys->i_state = STATE_HEADER; |
235 | | /* fallthrough */ |
236 | | |
237 | 11.6M | case STATE_HEADER: |
238 | | /* Get MPGA frame header (MPGA_HEADER_SIZE bytes) */ |
239 | 11.6M | if( block_PeekBytes( &p_sys->bytestream, p_header, |
240 | 11.6M | MPGA_HEADER_SIZE ) != VLC_SUCCESS ) |
241 | 4.51k | { |
242 | | /* Need more data */ |
243 | 4.51k | return NULL; |
244 | 4.51k | } |
245 | | |
246 | | /* Build frame header */ |
247 | 11.6M | i_header = GetDWBE(p_header); |
248 | | |
249 | | /* Check if frame is valid and get frame info */ |
250 | 11.6M | if( mpga_decode_frameheader( i_header, &p_sys->header ) ) |
251 | 8.83M | { |
252 | 8.83M | msg_Dbg( p_dec, "emulated startcode" ); |
253 | 8.83M | block_SkipByte( &p_sys->bytestream ); |
254 | 8.83M | p_sys->i_state = STATE_NOSYNC; |
255 | 8.83M | break; |
256 | 8.83M | } |
257 | | |
258 | 2.78M | if( p_sys->header.i_bit_rate == 0 ) |
259 | 245k | { |
260 | | /* Free bitrate, but 99% emulated startcode :( */ |
261 | 245k | if( p_sys->i_free_frame_size == MPGA_HEADER_SIZE ) |
262 | 63.1k | { |
263 | 63.1k | msg_Dbg( p_dec, "free bitrate mode"); |
264 | 63.1k | } |
265 | | /* The -1 below is to account for the frame padding */ |
266 | 245k | p_sys->header.i_frame_size = p_sys->i_free_frame_size - 1; |
267 | 245k | } |
268 | | |
269 | 2.78M | p_sys->i_state = STATE_NEXT_SYNC; |
270 | | /* fallthrough */ |
271 | | |
272 | 14.4M | case STATE_NEXT_SYNC: |
273 | | /* Check if next expected frame contains the sync word */ |
274 | 14.4M | if( block_PeekOffsetBytes( &p_sys->bytestream, |
275 | 14.4M | p_sys->header.i_frame_size, p_header, |
276 | 14.4M | MAD_BUFFER_GUARD ) != VLC_SUCCESS ) |
277 | 33.7k | { |
278 | 33.7k | if( p_block == NULL ) /* drain */ |
279 | 698 | { |
280 | 698 | p_sys->i_state = STATE_SEND_DATA; |
281 | 698 | break; |
282 | 698 | } |
283 | | /* Need more data */ |
284 | 33.0k | return NULL; |
285 | 33.7k | } |
286 | | |
287 | 14.4M | if( p_header[0] == 0xff && (p_header[1] & 0xe0) == 0xe0 ) |
288 | 3.95M | { |
289 | | /* Startcode is fine, let's try the header as an extra check */ |
290 | | |
291 | | /* Build frame header */ |
292 | 3.95M | i_header = GetDWBE(p_header); |
293 | | |
294 | 3.95M | struct mpga_frameheader_s nextheader; |
295 | 3.95M | if(mpga_decode_frameheader( i_header, &nextheader )) |
296 | 2.83M | { |
297 | | /* Free bitrate only */ |
298 | 2.83M | if( p_sys->header.i_bit_rate == 0 ) |
299 | 2.37M | { |
300 | 2.37M | if( p_sys->header.i_frame_size > p_sys->header.i_max_frame_size ) |
301 | 2.19k | { |
302 | 2.19k | msg_Dbg( p_dec, "frame too big %u > %u " |
303 | 2.19k | "(emulated startcode ?)", |
304 | 2.19k | p_sys->header.i_frame_size, |
305 | 2.19k | p_sys->header.i_max_frame_size ); |
306 | 2.19k | block_SkipByte( &p_sys->bytestream ); |
307 | 2.19k | p_sys->i_state = STATE_NOSYNC; |
308 | 2.19k | p_sys->i_free_frame_size = MPGA_HEADER_SIZE; |
309 | 2.19k | } |
310 | 2.37M | else |
311 | 2.37M | { |
312 | 2.37M | p_sys->header.i_frame_size++; |
313 | 2.37M | } |
314 | 2.37M | } |
315 | 458k | else |
316 | 458k | { |
317 | 458k | msg_Dbg( p_dec, "emulated startcode on next frame" ); |
318 | 458k | block_SkipByte( &p_sys->bytestream ); |
319 | 458k | p_sys->i_state = STATE_NOSYNC; |
320 | 458k | } |
321 | 2.83M | break; |
322 | 2.83M | } |
323 | | |
324 | | /* Check info is in sync with previous one */ |
325 | 1.11M | if( nextheader.i_channels_conf != p_sys->header.i_channels_conf || |
326 | 669k | nextheader.i_chan_mode != p_sys->header.i_chan_mode || |
327 | 606k | nextheader.i_sample_rate != p_sys->header.i_sample_rate || |
328 | 316k | nextheader.i_layer != p_sys->header.i_layer || |
329 | 302k | nextheader.i_samples_per_frame != p_sys->header.i_samples_per_frame ) |
330 | 811k | { |
331 | | /* Free bitrate only */ |
332 | 811k | if( p_sys->header.i_bit_rate == 0 ) |
333 | 251k | { |
334 | 251k | p_sys->header.i_frame_size++; |
335 | 251k | break; |
336 | 251k | } |
337 | | |
338 | 559k | msg_Dbg( p_dec, "parameters changed unexpectedly " |
339 | 559k | "(emulated startcode ?)" ); |
340 | 559k | block_SkipByte( &p_sys->bytestream ); |
341 | 559k | p_sys->i_state = STATE_NOSYNC; |
342 | 559k | break; |
343 | 811k | } |
344 | | |
345 | | /* Free bitrate only */ |
346 | 301k | if( p_sys->header.i_bit_rate == 0 ) |
347 | 262k | { |
348 | 262k | if( nextheader.i_bit_rate != 0 ) |
349 | 26.1k | { |
350 | 26.1k | p_sys->header.i_frame_size++; |
351 | 26.1k | break; |
352 | 26.1k | } |
353 | 262k | } |
354 | | |
355 | 301k | } |
356 | 10.4M | else |
357 | 10.4M | { |
358 | | /* Free bitrate only */ |
359 | 10.4M | if( p_sys->header.i_bit_rate == 0 ) |
360 | 8.98M | { |
361 | 8.98M | if( p_sys->header.i_frame_size > p_sys->header.i_max_frame_size ) |
362 | 6.70k | { |
363 | 6.70k | msg_Dbg( p_dec, "frame too big %u > %u " |
364 | 6.70k | "(emulated startcode ?)", |
365 | 6.70k | p_sys->header.i_frame_size, |
366 | 6.70k | p_sys->header.i_max_frame_size ); |
367 | 6.70k | block_SkipByte( &p_sys->bytestream ); |
368 | 6.70k | p_sys->i_state = STATE_NOSYNC; |
369 | 6.70k | p_sys->i_free_frame_size = MPGA_HEADER_SIZE; |
370 | 6.70k | break; |
371 | 6.70k | } |
372 | | |
373 | 8.98M | p_sys->header.i_frame_size++; |
374 | 8.98M | break; |
375 | 8.98M | } |
376 | | |
377 | 1.47M | msg_Dbg( p_dec, "emulated startcode " |
378 | 1.47M | "(no startcode on following frame)" ); |
379 | 1.47M | p_sys->i_state = STATE_NOSYNC; |
380 | 1.47M | block_SkipByte( &p_sys->bytestream ); |
381 | 1.47M | break; |
382 | 10.4M | } |
383 | | |
384 | 275k | p_sys->i_state = STATE_GET_DATA; |
385 | 275k | break; |
386 | | |
387 | 275k | case STATE_GET_DATA: |
388 | | /* Make sure we have enough data. |
389 | | * (Not useful if we went through NEXT_SYNC) */ |
390 | 275k | if( block_WaitBytes( &p_sys->bytestream, |
391 | 275k | p_sys->header.i_frame_size ) != VLC_SUCCESS ) |
392 | 0 | { |
393 | | /* Need more data */ |
394 | 0 | return NULL; |
395 | 0 | } |
396 | 275k | p_sys->i_state = STATE_SEND_DATA; |
397 | | /* fallthrough */ |
398 | | |
399 | 276k | case STATE_SEND_DATA: |
400 | 276k | if( !(p_buf = GetOutBuffer( p_dec, &p_out_buffer )) ) |
401 | 0 | { |
402 | 0 | return NULL; |
403 | 0 | } |
404 | | |
405 | | /* Free bitrate only */ |
406 | 276k | if( p_sys->header.i_bit_rate == 0 ) |
407 | 236k | { |
408 | 236k | p_sys->i_free_frame_size = p_sys->header.i_frame_size; |
409 | 236k | } |
410 | | |
411 | | /* Copy the whole frame into the buffer. */ |
412 | 276k | if ( block_GetBytes( &p_sys->bytestream, p_buf, |
413 | 276k | __MIN( p_sys->header.i_frame_size, |
414 | 276k | p_out_buffer->i_buffer ) ) ) |
415 | 371 | { |
416 | 371 | block_Release(p_out_buffer); |
417 | 371 | return NULL; |
418 | 371 | } |
419 | | |
420 | 276k | p_sys->i_state = STATE_NOSYNC; |
421 | | |
422 | | /* Make sure we don't reuse the same pts twice */ |
423 | 276k | if( p_sys->i_pts == p_sys->bytestream.p_block->i_pts ) |
424 | 275k | p_sys->i_pts = p_sys->bytestream.p_block->i_pts = VLC_TICK_INVALID; |
425 | | |
426 | 276k | if( p_sys->b_discontinuity ) |
427 | 0 | { |
428 | 0 | p_out_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY; |
429 | 0 | p_sys->b_discontinuity = false; |
430 | 0 | } |
431 | | |
432 | | /* So p_block doesn't get re-added several times */ |
433 | 276k | p_block = block_BytestreamPop( &p_sys->bytestream ); |
434 | 276k | if (pp_block) |
435 | 275k | *pp_block = p_block; |
436 | 508 | else if (p_block) |
437 | 466 | block_Release(p_block); |
438 | | |
439 | 276k | return p_out_buffer; |
440 | 23.5M | } |
441 | 23.5M | } |
442 | | |
443 | 0 | return NULL; |
444 | 320k | } |
445 | | |
446 | | /***************************************************************************** |
447 | | * Close: clean up the decoder |
448 | | *****************************************************************************/ |
449 | | static void Close( vlc_object_t *p_this ) |
450 | 4.60k | { |
451 | 4.60k | decoder_t *p_dec = (decoder_t *)p_this; |
452 | 4.60k | decoder_sys_t *p_sys = p_dec->p_sys; |
453 | | |
454 | 4.60k | block_BytestreamRelease( &p_sys->bytestream ); |
455 | | |
456 | 4.60k | free( p_sys ); |
457 | 4.60k | } |
458 | | |
459 | | /***************************************************************************** |
460 | | * Open: probe the decoder and return score |
461 | | *****************************************************************************/ |
462 | | static int Open( vlc_object_t *p_this ) |
463 | 1.87M | { |
464 | 1.87M | decoder_t *p_dec = (decoder_t*)p_this; |
465 | 1.87M | decoder_sys_t *p_sys; |
466 | | |
467 | 1.87M | if( p_dec->fmt_in->i_codec != VLC_CODEC_MPGA && |
468 | 1.87M | p_dec->fmt_in->i_codec != VLC_CODEC_MP2 && |
469 | 1.86M | p_dec->fmt_in->i_codec != VLC_CODEC_MP3 ) |
470 | 1.86M | { |
471 | 1.86M | return VLC_EGENERIC; |
472 | 1.86M | } |
473 | | |
474 | | /* Allocate the memory needed to store the decoder's structure */ |
475 | 4.60k | if( ( p_dec->p_sys = p_sys = |
476 | 4.60k | (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL ) |
477 | 0 | return VLC_ENOMEM; |
478 | | |
479 | | /* Misc init */ |
480 | 4.60k | p_sys->i_state = STATE_NOSYNC; |
481 | 4.60k | date_Init( &p_sys->end_date, 1, 1 ); |
482 | 4.60k | block_BytestreamInit( &p_sys->bytestream ); |
483 | 4.60k | p_sys->i_pts = VLC_TICK_INVALID; |
484 | 4.60k | p_sys->b_discontinuity = false; |
485 | | |
486 | 4.60k | memset(&p_sys->header, 0, sizeof(p_sys->header)); |
487 | | |
488 | | /* Set output properties */ |
489 | 4.60k | p_dec->fmt_out.i_codec = p_dec->fmt_in->i_codec; |
490 | 4.60k | p_dec->fmt_out.audio.i_rate = 0; /* So end_date gets initialized */ |
491 | | |
492 | | /* Set callback */ |
493 | 4.60k | p_dec->pf_packetize = DecodeBlock; |
494 | 4.60k | p_dec->pf_flush = Flush; |
495 | 4.60k | p_dec->pf_get_cc = NULL; |
496 | | |
497 | | /* Start with the minimum size for a free bitrate frame */ |
498 | 4.60k | p_sys->i_free_frame_size = MPGA_HEADER_SIZE; |
499 | | |
500 | 4.60k | return VLC_SUCCESS; |
501 | 4.60k | } |