Coverage Report

Created: 2026-09-28 07:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/modules/codec/aes3.c
Line
Count
Source
1
/*****************************************************************************
2
 * aes3.c: aes3 decoder/packetizer module
3
 *****************************************************************************
4
 * Copyright (C) 2008 VLC authors and VideoLAN
5
 *
6
 * Authors: Laurent Aimar <fenrir@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
#ifdef HAVE_CONFIG_H
27
# include "config.h"
28
#endif
29
30
#include <vlc_common.h>
31
#include <vlc_plugin.h>
32
#include <vlc_codec.h>
33
#include <assert.h>
34
35
/*****************************************************************************
36
 * Module descriptor
37
 *****************************************************************************/
38
static int  OpenDecoder   ( vlc_object_t * );
39
static int  OpenPacketizer( vlc_object_t * );
40
41
174
vlc_module_begin ()
42
43
87
    set_subcategory( SUBCAT_INPUT_ACODEC )
44
87
    set_description( N_("AES3/SMPTE 302M audio decoder") )
45
87
    set_capability( "audio decoder", 100 )
46
87
    set_callback( OpenDecoder )
47
48
87
    add_submodule ()
49
87
    set_description( N_("AES3/SMPTE 302M audio packetizer") )
50
87
    set_capability( "audio packetizer", 100 )
51
87
    set_callback( OpenPacketizer )
52
53
87
vlc_module_end ()
54
55
/*****************************************************************************
56
 * decoder_sys_t : aes3 decoder descriptor
57
 *****************************************************************************/
58
typedef struct
59
{
60
    /*
61
     * Output properties
62
     */
63
    date_t end_date;
64
} decoder_sys_t;
65
66
36.9k
#define AES3_HEADER_LEN 4
67
68
/*****************************************************************************
69
 * Local prototypes
70
 *****************************************************************************/
71
static int Open( decoder_t *p_dec, bool b_packetizer );
72
73
static block_t *Parse( decoder_t *p_dec, int *pi_frame_length, int *pi_bits,
74
                       block_t *p_block, bool b_packetizer );
75
76
/*****************************************************************************
77
 * OpenDecoder:
78
 *****************************************************************************/
79
static int OpenDecoder( vlc_object_t *p_this )
80
923k
{
81
923k
    decoder_t *p_dec = (decoder_t*)p_this;
82
83
923k
    return Open( p_dec, false );
84
923k
}
85
86
/*****************************************************************************
87
 * OpenPacketizer:
88
 *****************************************************************************/
89
static int OpenPacketizer( vlc_object_t *p_this )
90
230k
{
91
230k
    decoder_t *p_dec = (decoder_t*)p_this;
92
93
230k
    return Open( p_dec, true );
94
230k
}
95
96
static const uint8_t reverse[256] = {
97
    0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0,
98
    0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
99
    0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4,
100
    0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
101
    0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc,
102
    0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
103
    0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca,
104
    0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
105
    0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6,
106
    0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
107
    0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1,
108
    0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
109
    0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9,
110
    0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
111
    0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd,
112
    0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
113
    0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3,
114
    0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
115
    0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7,
116
    0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
117
    0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf,
118
    0x3f, 0xbf, 0x7f, 0xff
119
};
120
121
/*****************************************************************************
122
 * Decode: decodes an aes3 frame.
123
 ****************************************************************************
124
 * Beware, this function must be fed with complete frames (PES packet).
125
 *****************************************************************************/
126
static int Decode( decoder_t *p_dec, block_t *p_block )
127
18.2k
{
128
18.2k
    decoder_sys_t *p_sys = p_dec->p_sys;
129
18.2k
    block_t       *p_aout_buffer;
130
18.2k
    int            i_frame_length, i_bits;
131
132
18.2k
    p_block = Parse( p_dec, &i_frame_length, &i_bits, p_block, false );
133
18.2k
    if( !p_block )
134
17.8k
        return VLCDEC_SUCCESS;
135
136
418
    if( decoder_UpdateAudioFormat( p_dec ) )
137
418
    {
138
418
        p_aout_buffer = NULL;
139
418
        goto exit;
140
418
    }
141
142
0
    p_aout_buffer = decoder_NewAudioBuffer( p_dec, i_frame_length );
143
0
    if( p_aout_buffer == NULL )
144
0
        goto exit;
145
146
0
    p_aout_buffer->i_pts = date_Get( &p_sys->end_date );
147
0
    p_aout_buffer->i_length = date_Increment( &p_sys->end_date,
148
0
                                      i_frame_length ) - p_aout_buffer->i_pts;
149
150
0
    p_block->i_buffer -= AES3_HEADER_LEN;
151
0
    p_block->p_buffer += AES3_HEADER_LEN;
152
153
0
    if( i_bits == 24 )
154
0
    {
155
0
        uint32_t *p_out = (uint32_t *)p_aout_buffer->p_buffer;
156
157
0
        while( p_block->i_buffer / 7 )
158
0
        {
159
0
            *(p_out++) =  (reverse[p_block->p_buffer[0]] <<  8)
160
0
                        | (reverse[p_block->p_buffer[1]] << 16)
161
0
                        | (reverse[p_block->p_buffer[2]] << 24);
162
0
            *(p_out++) = ((reverse[p_block->p_buffer[3]] <<  4)
163
0
                        | (reverse[p_block->p_buffer[4]] << 12)
164
0
                        | (reverse[p_block->p_buffer[5]] << 20)
165
0
                        | (reverse[p_block->p_buffer[6]] << 28)) & 0xFFFFFF00;
166
167
0
            p_block->i_buffer -= 7;
168
0
            p_block->p_buffer += 7;
169
0
        }
170
171
0
    }
172
0
    else if( i_bits == 20 )
173
0
    {
174
0
        uint32_t *p_out = (uint32_t *)p_aout_buffer->p_buffer;
175
176
0
        while( p_block->i_buffer / 6 )
177
0
        {
178
0
            *(p_out++) = (reverse[p_block->p_buffer[0]] << 12)
179
0
                       | (reverse[p_block->p_buffer[1]] << 20)
180
0
                       | (reverse[p_block->p_buffer[2]] << 28);
181
0
            *(p_out++) = (reverse[p_block->p_buffer[3]] << 12)
182
0
                       | (reverse[p_block->p_buffer[4]] << 20)
183
0
                       | (reverse[p_block->p_buffer[5]] << 28);
184
185
0
            p_block->i_buffer -= 6;
186
0
            p_block->p_buffer += 6;
187
0
        }
188
0
    }
189
0
    else
190
0
    {
191
0
        uint16_t *p_out = (uint16_t *)p_aout_buffer->p_buffer;
192
193
0
        assert( i_bits == 16 );
194
195
0
        while( p_block->i_buffer / 5 )
196
0
        {
197
0
            *(p_out++) =  reverse[p_block->p_buffer[0]]
198
0
                        |(reverse[p_block->p_buffer[1]] <<  8);
199
0
            *(p_out++) = (reverse[p_block->p_buffer[2]] >>  4)
200
0
                       | (reverse[p_block->p_buffer[3]] <<  4)
201
0
                       | (reverse[p_block->p_buffer[4]] << 12);
202
203
0
            p_block->i_buffer -= 5;
204
0
            p_block->p_buffer += 5;
205
0
        }
206
0
    }
207
208
418
exit:
209
418
    block_Release( p_block );
210
418
    if( p_aout_buffer != NULL )
211
0
        decoder_QueueAudio( p_dec, p_aout_buffer );
212
418
    return VLCDEC_SUCCESS;
213
0
}
214
215
/*****************************************************************************
216
 * Flush:
217
 *****************************************************************************/
218
static void Flush( decoder_t *p_dec )
219
0
{
220
0
    decoder_sys_t *p_sys = p_dec->p_sys;
221
222
0
    date_Set( &p_sys->end_date, VLC_TICK_INVALID );
223
0
}
224
225
/*****************************************************************************
226
 * Packetize: packetizes an aes3 frame.
227
 ****************************************************************************
228
 * Beware, this function must be fed with complete frames (PES packet).
229
 *****************************************************************************/
230
static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
231
18.0k
{
232
18.0k
    decoder_sys_t *p_sys = p_dec->p_sys;
233
18.0k
    block_t       *p_block;
234
18.0k
    int           i_frame_length, i_bits;
235
236
18.0k
    if( !pp_block ) /* No Drain */
237
2
        return NULL;
238
18.0k
    p_block = *pp_block;
239
18.0k
    *pp_block = NULL; /* So the packet doesn't get re-sent */
240
241
18.0k
    p_block = Parse( p_dec, &i_frame_length, &i_bits, p_block, true );
242
18.0k
    if( !p_block )
243
17.6k
        return NULL;
244
245
418
    p_block->i_pts = p_block->i_dts = date_Get( &p_sys->end_date );
246
418
    p_block->i_length = date_Increment( &p_sys->end_date, i_frame_length ) - p_block->i_pts;
247
248
    /* Just pass on the incoming frame */
249
418
    return p_block;
250
18.0k
}
251
252
/*****************************************************************************
253
 *
254
 ****************************************************************************/
255
static int Open( decoder_t *p_dec, bool b_packetizer )
256
1.15M
{
257
1.15M
    decoder_sys_t *p_sys;
258
259
1.15M
    if( p_dec->fmt_in->i_codec != VLC_CODEC_302M )
260
1.15M
        return VLC_EGENERIC;
261
262
    /* Allocate the memory needed to store the decoder's structure */
263
197
    p_sys = vlc_obj_malloc( VLC_OBJECT(p_dec), sizeof(*p_sys) );
264
265
197
    if( unlikely( !p_sys ) )
266
0
        return VLC_EGENERIC;
267
268
    /* Misc init */
269
197
    date_Init( &p_sys->end_date, 48000, 1 );
270
271
    /* Set output properties */
272
197
    p_dec->fmt_out.audio.i_rate = 48000;
273
274
    /* Set callback */
275
197
    if( b_packetizer )
276
2
    {
277
2
        p_dec->fmt_out.i_codec = VLC_CODEC_302M;
278
279
2
        p_dec->pf_packetize    = Packetize;
280
2
    }
281
195
    else
282
195
    {
283
195
        p_dec->fmt_out.i_codec = VLC_CODEC_S16N;
284
195
        p_dec->fmt_out.audio.i_bitspersample = 16;
285
286
195
        p_dec->pf_decode    = Decode;
287
195
    }
288
197
    p_dec->pf_flush            = Flush;
289
197
    p_dec->p_sys = p_sys;
290
197
    return VLC_SUCCESS;
291
197
}
292
293
static const unsigned int pi_original_channels[4] = {
294
    AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
295
    AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
296
        AOUT_CHAN_CENTER | AOUT_CHAN_LFE,
297
    AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
298
        AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT |
299
        AOUT_CHAN_CENTER | AOUT_CHAN_LFE,
300
    AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
301
        AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT |
302
        AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT |
303
        AOUT_CHAN_CENTER | AOUT_CHAN_LFE,
304
};
305
306
static block_t * Parse( decoder_t *p_dec, int *pi_frame_length, int *pi_bits,
307
                        block_t *p_block, bool b_packetizer )
308
36.2k
{
309
36.2k
    decoder_sys_t *p_sys = p_dec->p_sys;
310
36.2k
    uint32_t h;
311
36.2k
    unsigned int i_size;
312
36.2k
    int i_channels;
313
36.2k
    int i_bits;
314
315
36.2k
    if( !p_block ) /* No drain */
316
18.2k
        return NULL;
317
318
18.0k
    if( p_block->i_flags & (BLOCK_FLAG_CORRUPTED|BLOCK_FLAG_DISCONTINUITY) )
319
0
    {
320
0
        Flush( p_dec );
321
0
        if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
322
0
        {
323
0
            block_Release( p_block );
324
0
            return NULL;
325
0
        }
326
0
    }
327
328
    /* Date management */
329
18.0k
    if( p_block->i_pts != VLC_TICK_INVALID &&
330
18.0k
        p_block->i_pts != date_Get( &p_sys->end_date ) )
331
16.1k
    {
332
16.1k
        date_Set( &p_sys->end_date, p_block->i_pts );
333
16.1k
    }
334
335
18.0k
    if( date_Get( &p_sys->end_date ) == VLC_TICK_INVALID )
336
0
    {
337
        /* We've just started the stream, wait for the first PTS. */
338
0
        block_Release( p_block );
339
0
        return NULL;
340
0
    }
341
342
18.0k
    if( p_block->i_buffer <= AES3_HEADER_LEN )
343
1
    {
344
1
        msg_Err(p_dec, "frame is too short");
345
1
        block_Release( p_block );
346
1
        return NULL;
347
1
    }
348
349
    /*
350
     * AES3 header :
351
     * size:            16
352
     * number channels   2
353
     * channel_id        8
354
     * bits per samples  2
355
     * alignments        4
356
     */
357
358
18.0k
    h = GetDWBE( p_block->p_buffer );
359
18.0k
    i_size = (h >> 16) & 0xffff;
360
18.0k
    i_channels = 2 + 2*( (h >> 14) & 0x03 );
361
18.0k
    i_bits = 16 + 4*( (h >> 4)&0x03 );
362
363
18.0k
    if( AES3_HEADER_LEN + i_size != p_block->i_buffer || i_bits > 24 )
364
17.2k
    {
365
17.2k
        msg_Err(p_dec, "frame has invalid header");
366
17.2k
        block_Release( p_block );
367
17.2k
        return NULL;
368
17.2k
    }
369
370
    /* Set output properties */
371
836
    if( b_packetizer )
372
418
    {
373
418
        p_dec->fmt_out.audio.i_bitspersample = i_bits;
374
418
    }
375
418
    else
376
418
    {
377
418
        p_dec->fmt_out.i_codec = i_bits == 16 ? VLC_CODEC_S16N : VLC_CODEC_S32N;
378
418
        p_dec->fmt_out.audio.i_bitspersample = i_bits == 16 ? 16 : 32;
379
418
    }
380
381
836
    p_dec->fmt_out.audio.i_channels = i_channels;
382
836
    p_dec->fmt_out.audio.i_physical_channels = pi_original_channels[i_channels/2-1];
383
384
836
    *pi_frame_length = (p_block->i_buffer - AES3_HEADER_LEN) / ( (4+i_bits) * i_channels / 8 );
385
836
    *pi_bits = i_bits;
386
836
    return p_block;
387
18.0k
}