Coverage Report

Created: 2025-08-29 06:30

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