Coverage Report

Created: 2026-10-17 07:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/modules/codec/mpg123.c
Line
Count
Source
1
/*****************************************************************************
2
 * mpg123.c: MPEG-1 & 2 audio layer I, II, III + MPEG 2.5 decoder
3
 *****************************************************************************
4
 * Copyright (C) 2001-2016 VLC authors and VideoLAN
5
 *
6
 * Authors: Ludovic Fauvet <etix@videolan.org>
7
 *
8
 * This program is free software; you can redistribute it and/or modify it
9
 * under the terms of the GNU Lesser General Public License as published by
10
 * the Free Software Foundation; either version 2.1 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
 * GNU Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program; if not, write to the Free Software Foundation,
20
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21
 *****************************************************************************/
22
23
/*****************************************************************************
24
* Preamble
25
*****************************************************************************/
26
27
#ifdef HAVE_CONFIG_H
28
# include "config.h"
29
#endif
30
31
#include <assert.h>
32
33
#include <mpg123.h>
34
35
#include <vlc_common.h>
36
#include <vlc_plugin.h>
37
#include <vlc_aout.h>
38
#include <vlc_block.h>
39
#include <vlc_codec.h>
40
41
/*****************************************************************************
42
 * Local prototypes
43
 *****************************************************************************/
44
static int      OpenDecoder( vlc_object_t * );
45
static void     CloseDecoder( vlc_object_t * );
46
47
static unsigned int mpg123_refcount = 0;
48
static vlc_mutex_t mpg123_mutex = VLC_STATIC_MUTEX;
49
50
/*****************************************************************************
51
 * Local structures
52
 *****************************************************************************/
53
typedef struct
54
{
55
    mpg123_handle * p_handle;
56
    date_t          end_date;
57
    block_t       * p_out;
58
    bool            b_opened;
59
} decoder_sys_t;
60
61
/*****************************************************************************
62
 * Module descriptor
63
 *****************************************************************************/
64
174
vlc_module_begin ()
65
87
    set_subcategory( SUBCAT_INPUT_ACODEC )
66
87
    set_description( N_("MPEG audio decoder using mpg123") )
67
87
    set_capability( "audio decoder", 100 )
68
87
    set_shortname( "mpg123" )
69
174
    set_callbacks( OpenDecoder, CloseDecoder )
70
87
vlc_module_end ()
71
72
/*****************************************************************************
73
 * MPG123Open
74
 *****************************************************************************/
75
static int MPG123Open( decoder_t *p_dec )
76
385k
{
77
385k
    decoder_sys_t *p_sys = p_dec->p_sys;
78
79
    /* Create our mpg123 handle */
80
385k
    if( ( p_sys->p_handle = mpg123_new( NULL, NULL ) ) == NULL )
81
0
    {
82
0
        msg_Err( p_dec, "mpg123 error: can't create handle" );
83
0
        return VLC_EGENERIC;
84
0
    }
85
86
    /* Open a new bitstream */
87
385k
    if( mpg123_open_feed( p_sys->p_handle ) != MPG123_OK )
88
0
    {
89
0
        msg_Err( p_dec, "mpg123 error: can't open feed" );
90
0
        mpg123_delete( p_sys->p_handle );
91
0
        return VLC_EGENERIC;
92
0
    }
93
94
    /* Disable resync stream after error */
95
385k
    mpg123_param( p_sys->p_handle, MPG123_ADD_FLAGS, MPG123_NO_RESYNC, 0 );
96
97
    /* Setup output format */
98
385k
    mpg123_format_none( p_sys->p_handle );
99
100
385k
    int i_ret = MPG123_OK;
101
385k
    if( p_dec->fmt_in->audio.i_rate != 0 )
102
310k
    {
103
310k
        i_ret =  mpg123_format( p_sys->p_handle, p_dec->fmt_in->audio.i_rate,
104
310k
                                MPG123_MONO | MPG123_STEREO,
105
310k
                                MPG123_ENC_FLOAT_32 );
106
310k
    }
107
74.6k
    else
108
74.6k
    {
109
        /* The rate from the input is unknown. Tell mpg123 to accept all rates
110
         * to avoid conversion on their side */
111
74.6k
        static const long mp3_rates[] = {
112
74.6k
            8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
113
74.6k
        };
114
746k
        for( size_t i = 0; i < ARRAY_SIZE(mp3_rates) && i_ret == MPG123_OK; ++i )
115
671k
        {
116
671k
            i_ret =  mpg123_format( p_sys->p_handle, mp3_rates[i],
117
671k
                                    MPG123_MONO | MPG123_STEREO,
118
671k
                                    MPG123_ENC_FLOAT_32 );
119
671k
        }
120
74.6k
    }
121
385k
    if( i_ret != MPG123_OK )
122
0
    {
123
0
        msg_Err( p_dec, "mpg123 error: %s",
124
0
                 mpg123_strerror( p_sys->p_handle ) );
125
0
        mpg123_close( p_sys->p_handle );
126
0
        mpg123_delete( p_sys->p_handle );
127
0
        return VLC_EGENERIC;
128
0
    }
129
130
385k
    p_sys->b_opened = true;
131
385k
    return VLC_SUCCESS;
132
385k
}
133
134
/*****************************************************************************
135
 * Flush:
136
 *****************************************************************************/
137
static void Flush( decoder_t *p_dec )
138
10.9k
{
139
10.9k
    decoder_sys_t *p_sys = p_dec->p_sys;
140
141
10.9k
    date_Set( &p_sys->end_date, VLC_TICK_INVALID );
142
143
10.9k
    mpg123_close( p_sys->p_handle );
144
10.9k
    mpg123_delete( p_sys->p_handle );
145
10.9k
    p_sys->b_opened = false;
146
10.9k
    MPG123Open( p_dec );
147
10.9k
}
148
149
static int UpdateAudioFormat( decoder_t *p_dec )
150
226k
{
151
226k
    int i_err;
152
226k
    decoder_sys_t *p_sys = p_dec->p_sys;
153
226k
    struct mpg123_frameinfo frame_info;
154
155
    /* Get details about the stream */
156
226k
    i_err = mpg123_info( p_sys->p_handle, &frame_info );
157
226k
    if( i_err != MPG123_OK )
158
0
    {
159
0
        msg_Err( p_dec, "mpg123_info failed: %s",
160
0
                 mpg123_plain_strerror( i_err ) );
161
0
        return VLC_EGENERIC;
162
0
    }
163
164
226k
    p_dec->fmt_out.i_bitrate = frame_info.bitrate * 1000;
165
166
226k
    switch( frame_info.mode )
167
226k
    {
168
5.08k
        case MPG123_M_DUAL:
169
5.08k
            p_dec->fmt_out.audio.i_chan_mode = AOUT_CHANMODE_DUALMONO;
170
            /* fall through */
171
94.7k
        case MPG123_M_STEREO:
172
138k
        case MPG123_M_JOINT:
173
138k
            p_dec->fmt_out.audio.i_physical_channels =
174
138k
                AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
175
138k
            break;
176
88.3k
        case MPG123_M_MONO:
177
88.3k
            p_dec->fmt_out.audio.i_physical_channels = AOUT_CHAN_CENTER;
178
88.3k
            break;
179
0
        default:
180
0
            return VLC_EGENERIC;
181
226k
    }
182
183
226k
    aout_FormatPrepare( &p_dec->fmt_out.audio );
184
185
    /* Date management */
186
226k
    if( p_dec->fmt_out.audio.i_rate != (unsigned int)frame_info.rate )
187
226k
    {
188
226k
        p_dec->fmt_out.audio.i_rate = (unsigned int)frame_info.rate;
189
226k
        date_Init( &p_sys->end_date, p_dec->fmt_out.audio.i_rate, 1 );
190
226k
    }
191
192
226k
    return decoder_UpdateAudioFormat( p_dec );
193
226k
}
194
195
/****************************************************************************
196
 * DecodeBlock: the whole thing
197
 ****************************************************************************/
198
static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
199
6.63M
{
200
6.63M
    int i_err;
201
6.63M
    decoder_sys_t *p_sys = p_dec->p_sys;
202
6.63M
    vlc_tick_t i_pts = VLC_TICK_INVALID;
203
204
6.63M
    if( !p_sys->b_opened )
205
0
    {
206
0
        if( p_block )
207
0
            block_Release( p_block );
208
0
        return VLCDEC_ECRITICAL;
209
0
    }
210
211
    /* Feed input block */
212
6.63M
    if( p_block != NULL )
213
6.25M
    {
214
6.25M
        i_pts = p_block->i_pts != VLC_TICK_INVALID ? p_block->i_pts : p_block->i_dts;
215
216
6.25M
        if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
217
10.9k
        {
218
10.9k
            Flush( p_dec );
219
10.9k
            if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
220
0
            {
221
0
                block_Release( p_block );
222
0
                return VLCDEC_SUCCESS;
223
0
            }
224
10.9k
        }
225
226
6.25M
        if( i_pts == VLC_TICK_INVALID &&
227
42.3k
            date_Get( &p_sys->end_date ) == VLC_TICK_INVALID )
228
42.3k
        {
229
            /* We've just started the stream, wait for the first PTS. */
230
42.3k
            msg_Dbg( p_dec, "waiting for PTS" );
231
42.3k
            block_Release( p_block );
232
42.3k
            return VLCDEC_SUCCESS;
233
42.3k
        }
234
235
        /* Feed mpg123 with raw data */
236
6.21M
        i_err = mpg123_feed( p_sys->p_handle, p_block->p_buffer, p_block->i_buffer );
237
6.21M
        block_Release( p_block );
238
239
6.21M
        if( i_err != MPG123_OK )
240
0
        {
241
0
            msg_Err( p_dec, "mpg123_feed failed: %s",
242
0
                     mpg123_plain_strerror( i_err ) );
243
0
            return VLCDEC_SUCCESS;
244
0
        }
245
6.21M
    }
246
247
6.59M
    while( true )
248
9.39M
    {
249
        /* Fetch a new output block (if possible) */
250
9.39M
        if( !p_sys->p_out
251
6.21M
            || p_sys->p_out->i_buffer != mpg123_outblock( p_sys->p_handle ) )
252
3.40M
        {
253
3.40M
            if( p_sys->p_out )
254
226k
                block_Release( p_sys->p_out );
255
256
            /* Keep the output buffer for next calls in case it's not used (in case
257
             * of MPG123_NEED_MORE status) */
258
3.40M
            p_sys->p_out = block_Alloc( mpg123_outblock( p_sys->p_handle ) );
259
260
3.40M
            if( unlikely( !p_sys->p_out ) )
261
0
                return VLCDEC_SUCCESS;
262
3.40M
        }
263
264
        /* Do the actual decoding now */
265
9.39M
        size_t i_bytes = 0;
266
267
        /* Make mpg123 write directly into the VLC output buffer */
268
9.39M
        i_err = mpg123_replace_buffer( p_sys->p_handle, p_sys->p_out->p_buffer,
269
9.39M
                                       p_sys->p_out->i_buffer );
270
9.39M
        if( i_err != MPG123_OK )
271
0
        {
272
0
            msg_Err( p_dec, "could not replace buffer: %s",
273
0
                     mpg123_plain_strerror( i_err ) );
274
0
            block_Release( p_sys->p_out );
275
0
            p_sys->p_out = NULL;
276
0
            break;
277
0
        }
278
279
9.39M
        i_err = mpg123_decode_frame( p_sys->p_handle, NULL, NULL, &i_bytes );
280
9.39M
        if( i_err != MPG123_OK && i_err != MPG123_NEED_MORE )
281
3.52M
        {
282
3.52M
            if( i_err == MPG123_NEW_FORMAT )
283
242k
            {
284
242k
                p_dec->fmt_out.audio.i_rate = 0;
285
242k
            }
286
3.28M
            else
287
3.28M
            {
288
3.28M
                msg_Err( p_dec, "mpg123_decode_frame error: %s",
289
3.28M
                         mpg123_plain_strerror( i_err ) );
290
3.28M
                date_Set( &p_sys->end_date, VLC_TICK_INVALID );
291
3.28M
                break;
292
3.28M
            }
293
3.52M
        }
294
295
6.11M
        if( i_bytes == 0 )
296
3.04M
            break;
297
298
3.06M
        if( p_dec->fmt_out.audio.i_rate == 0 )
299
226k
        {
300
226k
            if( UpdateAudioFormat( p_dec ) != VLC_SUCCESS )
301
226k
            {
302
226k
                date_Set( &p_sys->end_date, VLC_TICK_INVALID );
303
226k
                break;
304
226k
            }
305
226k
        }
306
307
2.83M
        block_t *p_out = p_sys->p_out;
308
2.83M
        p_sys->p_out = NULL;
309
310
2.83M
        if( date_Get( &p_sys->end_date ) == VLC_TICK_INVALID )
311
440k
        {
312
440k
            if( i_pts != VLC_TICK_INVALID )
313
409k
            {
314
409k
                date_Set( &p_sys->end_date, i_pts );
315
409k
            }
316
31.4k
            else if( p_out ) /* we need a valid date and that's not guaranteed on flush/error */
317
31.4k
            {
318
31.4k
                block_Release( p_out );
319
31.4k
                break;
320
31.4k
            }
321
440k
        }
322
323
2.80M
        if( p_out )
324
2.80M
        {
325
2.80M
            assert( p_dec->fmt_out.audio.i_rate != 0 );
326
2.80M
            assert( p_out->i_buffer >= i_bytes );
327
2.80M
            p_out->i_buffer = i_bytes;
328
2.80M
            p_out->i_nb_samples = p_out->i_buffer * p_dec->fmt_out.audio.i_frame_length
329
2.80M
                                / p_dec->fmt_out.audio.i_bytes_per_frame;
330
331
            /* Configure the buffer */
332
2.80M
            p_out->i_dts = p_out->i_pts = date_Get( &p_sys->end_date );
333
2.80M
            p_out->i_length = date_Increment( &p_sys->end_date, p_out->i_nb_samples )
334
2.80M
                            - p_out->i_pts;
335
2.80M
            decoder_QueueAudio( p_dec, p_out );
336
2.80M
        }
337
2.80M
    }
338
339
6.59M
    return VLCDEC_SUCCESS;
340
6.59M
}
341
342
343
/*****************************************************************************
344
 * InitMPG123 : initialize the mpg123 library (reentrant)
345
 *****************************************************************************/
346
static int InitMPG123( void )
347
374k
{
348
374k
    int i_ret;
349
374k
    vlc_mutex_lock( &mpg123_mutex );
350
374k
    if( mpg123_refcount > 0 )
351
6.16k
    {
352
6.16k
        mpg123_refcount++;
353
6.16k
        vlc_mutex_unlock( &mpg123_mutex );
354
6.16k
        return MPG123_OK;
355
6.16k
    }
356
368k
    if( ( i_ret = mpg123_init() ) == MPG123_OK )
357
368k
        mpg123_refcount++;
358
368k
    vlc_mutex_unlock( &mpg123_mutex );
359
368k
    return i_ret;
360
374k
}
361
362
/*****************************************************************************
363
 * ExitMPG123 : close down the mpg123 library (reentrant)
364
 *****************************************************************************/
365
static void ExitMPG123( void )
366
374k
{
367
374k
    vlc_mutex_lock( &mpg123_mutex );
368
374k
    mpg123_refcount--;
369
374k
    if( mpg123_refcount == 0 )
370
368k
        mpg123_exit();
371
374k
    vlc_mutex_unlock( &mpg123_mutex );
372
374k
}
373
374
/*****************************************************************************
375
 * OpenDecoder :
376
 *****************************************************************************/
377
static int OpenDecoder( vlc_object_t *p_this )
378
1.56M
{
379
1.56M
    decoder_t *p_dec = (decoder_t *)p_this;
380
1.56M
    decoder_sys_t *p_sys;
381
382
1.56M
    if( p_dec->fmt_in->i_codec != VLC_CODEC_MPGA &&
383
1.56M
        p_dec->fmt_in->i_codec != VLC_CODEC_MP2 &&
384
1.28M
        p_dec->fmt_in->i_codec != VLC_CODEC_MP3 )
385
1.18M
        return VLC_EGENERIC;
386
387
    /* Initialize libmpg123 */
388
374k
    if( InitMPG123() != MPG123_OK )
389
0
        return VLC_EGENERIC;
390
391
    /* Allocate the memory needed to store the module's structure */
392
374k
    p_sys = p_dec->p_sys = malloc( sizeof(decoder_sys_t) );
393
374k
    if( p_sys == NULL )
394
0
        return VLC_ENOMEM;
395
396
374k
    p_sys->p_out = NULL;
397
374k
    date_Set( &p_sys->end_date, VLC_TICK_INVALID );
398
399
374k
    if( MPG123Open( p_dec ) )
400
0
        goto error;
401
402
374k
    p_dec->fmt_out.i_codec = VLC_CODEC_FL32;
403
374k
    p_dec->fmt_out.audio.i_rate = 0; /* So end_date gets initialized */
404
374k
    p_dec->fmt_out.audio.i_format = p_dec->fmt_out.i_codec;
405
374k
    p_dec->pf_decode = DecodeBlock;
406
374k
    p_dec->pf_flush  = Flush;
407
408
374k
    msg_Dbg( p_this, "%4.4s->%4.4s, bits per sample: %i",
409
374k
             (char *)&p_dec->fmt_in->i_codec,
410
374k
             (char *)&p_dec->fmt_out.i_codec,
411
374k
             aout_BitsPerSample( p_dec->fmt_out.i_codec ) );
412
413
374k
    return VLC_SUCCESS;
414
0
error:
415
0
    ExitMPG123();
416
0
    free( p_sys );
417
0
    return VLC_EGENERIC;
418
374k
}
419
420
/*****************************************************************************
421
 * CloseDecoder : deallocate data structures
422
 *****************************************************************************/
423
static void CloseDecoder( vlc_object_t *p_this )
424
374k
{
425
374k
    decoder_t *p_dec = (decoder_t *)p_this;
426
374k
    decoder_sys_t *p_sys = p_dec->p_sys;
427
428
374k
    mpg123_close( p_sys->p_handle );
429
374k
    mpg123_delete( p_sys->p_handle );
430
374k
    ExitMPG123();
431
374k
    if( p_sys->p_out )
432
342k
        block_Release( p_sys->p_out );
433
374k
    free( p_sys );
434
374k
}