Coverage Report

Created: 2026-01-17 06:26

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
108
vlc_module_begin ()
42
43
54
    set_subcategory( SUBCAT_INPUT_ACODEC )
44
54
    set_description( N_("AES3/SMPTE 302M audio decoder") )
45
54
    set_capability( "audio decoder", 100 )
46
54
    set_callback( OpenDecoder )
47
48
54
    add_submodule ()
49
54
    set_description( N_("AES3/SMPTE 302M audio packetizer") )
50
54
    set_capability( "audio packetizer", 100 )
51
54
    set_callback( OpenPacketizer )
52
53
54
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
111k
#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
2.75M
{
81
2.75M
    decoder_t *p_dec = (decoder_t*)p_this;
82
83
2.75M
    return Open( p_dec, false );
84
2.75M
}
85
86
/*****************************************************************************
87
 * OpenPacketizer:
88
 *****************************************************************************/
89
static int OpenPacketizer( vlc_object_t *p_this )
90
2.75M
{
91
2.75M
    decoder_t *p_dec = (decoder_t*)p_this;
92
93
2.75M
    return Open( p_dec, true );
94
2.75M
}
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
54.8k
{
128
54.8k
    decoder_sys_t *p_sys = p_dec->p_sys;
129
54.8k
    block_t       *p_aout_buffer;
130
54.8k
    int            i_frame_length, i_bits;
131
132
54.8k
    p_block = Parse( p_dec, &i_frame_length, &i_bits, p_block, false );
133
54.8k
    if( !p_block )
134
53.6k
        return VLCDEC_SUCCESS;
135
136
1.19k
    if( decoder_UpdateAudioFormat( p_dec ) )
137
1.19k
    {
138
1.19k
        p_aout_buffer = NULL;
139
1.19k
        goto exit;
140
1.19k
    }
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
1.19k
exit:
209
1.19k
    block_Release( p_block );
210
1.19k
    if( p_aout_buffer != NULL )
211
0
        decoder_QueueAudio( p_dec, p_aout_buffer );
212
1.19k
    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
54.5k
{
232
54.5k
    decoder_sys_t *p_sys = p_dec->p_sys;
233
54.5k
    block_t       *p_block;
234
54.5k
    int           i_frame_length, i_bits;
235
236
54.5k
    if( !pp_block ) /* No Drain */
237
29
        return NULL;
238
54.4k
    p_block = *pp_block;
239
54.4k
    *pp_block = NULL; /* So the packet doesn't get re-sent */
240
241
54.4k
    p_block = Parse( p_dec, &i_frame_length, &i_bits, p_block, true );
242
54.4k
    if( !p_block )
243
53.2k
        return NULL;
244
245
1.19k
    p_block->i_pts = p_block->i_dts = date_Get( &p_sys->end_date );
246
1.19k
    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
1.19k
    return p_block;
250
54.4k
}
251
252
/*****************************************************************************
253
 *
254
 ****************************************************************************/
255
static int Open( decoder_t *p_dec, bool b_packetizer )
256
5.50M
{
257
5.50M
    decoder_sys_t *p_sys;
258
259
5.50M
    if( p_dec->fmt_in->i_codec != VLC_CODEC_302M )
260
5.50M
        return VLC_EGENERIC;
261
262
    /* Allocate the memory needed to store the decoder's structure */
263
401
    p_sys = vlc_obj_malloc( VLC_OBJECT(p_dec), sizeof(*p_sys) );
264
265
401
    if( unlikely( !p_sys ) )
266
0
        return VLC_EGENERIC;
267
268
    /* Misc init */
269
401
    date_Init( &p_sys->end_date, 48000, 1 );
270
271
    /* Set output properties */
272
401
    p_dec->fmt_out.audio.i_rate = 48000;
273
274
    /* Set callback */
275
401
    if( b_packetizer )
276
29
    {
277
29
        p_dec->fmt_out.i_codec = VLC_CODEC_302M;
278
279
29
        p_dec->pf_packetize    = Packetize;
280
29
    }
281
372
    else
282
372
    {
283
372
        p_dec->fmt_out.i_codec = VLC_CODEC_S16N;
284
372
        p_dec->fmt_out.audio.i_bitspersample = 16;
285
286
372
        p_dec->pf_decode    = Decode;
287
372
    }
288
401
    p_dec->pf_flush            = Flush;
289
401
    p_dec->p_sys = p_sys;
290
401
    return VLC_SUCCESS;
291
401
}
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
109k
{
309
109k
    decoder_sys_t *p_sys = p_dec->p_sys;
310
109k
    uint32_t h;
311
109k
    unsigned int i_size;
312
109k
    int i_channels;
313
109k
    int i_bits;
314
315
109k
    if( !p_block ) /* No drain */
316
54.8k
        return NULL;
317
318
54.4k
    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
54.4k
    if( p_block->i_pts != VLC_TICK_INVALID &&
330
54.4k
        p_block->i_pts != date_Get( &p_sys->end_date ) )
331
49.7k
    {
332
49.7k
        date_Set( &p_sys->end_date, p_block->i_pts );
333
49.7k
    }
334
335
54.4k
    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
54.4k
    if( p_block->i_buffer <= AES3_HEADER_LEN )
343
8
    {
344
8
        msg_Err(p_dec, "frame is too short");
345
8
        block_Release( p_block );
346
8
        return NULL;
347
8
    }
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
54.4k
    h = GetDWBE( p_block->p_buffer );
359
54.4k
    i_size = (h >> 16) & 0xffff;
360
54.4k
    i_channels = 2 + 2*( (h >> 14) & 0x03 );
361
54.4k
    i_bits = 16 + 4*( (h >> 4)&0x03 );
362
363
54.4k
    if( AES3_HEADER_LEN + i_size != p_block->i_buffer || i_bits > 24 )
364
52.0k
    {
365
52.0k
        msg_Err(p_dec, "frame has invalid header");
366
52.0k
        block_Release( p_block );
367
52.0k
        return NULL;
368
52.0k
    }
369
370
    /* Set output properties */
371
2.38k
    if( b_packetizer )
372
1.19k
    {
373
1.19k
        p_dec->fmt_out.audio.i_bitspersample = i_bits;
374
1.19k
    }
375
1.19k
    else
376
1.19k
    {
377
1.19k
        p_dec->fmt_out.i_codec = i_bits == 16 ? VLC_CODEC_S16N : VLC_CODEC_S32N;
378
1.19k
        p_dec->fmt_out.audio.i_bitspersample = i_bits == 16 ? 16 : 32;
379
1.19k
    }
380
381
2.38k
    p_dec->fmt_out.audio.i_channels = i_channels;
382
2.38k
    p_dec->fmt_out.audio.i_physical_channels = pi_original_channels[i_channels/2-1];
383
384
2.38k
    *pi_frame_length = (p_block->i_buffer - AES3_HEADER_LEN) / ( (4+i_bits) * i_channels / 8 );
385
2.38k
    *pi_bits = i_bits;
386
2.38k
    return p_block;
387
54.4k
}