Coverage Report

Created: 2023-03-26 07:08

/src/vlc/modules/demux/tta.c
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************
2
 * tta.c : The Lossless True Audio parser
3
 *****************************************************************************
4
 * Copyright (C) 2006 VLC authors and VideoLAN
5
 *
6
 * Authors: Derk-Jan Hartman <hartman at videolan dot 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_demux.h>
33
#include <vlc_codec.h>
34
#include <math.h>
35
#include <limits.h>
36
37
/*****************************************************************************
38
 * Module descriptor
39
 *****************************************************************************/
40
static int  Open  ( vlc_object_t * );
41
static void Close ( vlc_object_t * );
42
43
4
vlc_module_begin ()
44
2
    set_shortname( "TTA" )
45
2
    set_description( N_("TTA demuxer") )
46
2
    set_subcategory( SUBCAT_INPUT_DEMUX )
47
2
    set_capability( "demux", 145 )
48
49
4
    set_callbacks( Open, Close )
50
2
    add_shortcut( "tta" )
51
2
vlc_module_end ()
52
53
0
#define TTA_FRAMETIME 1.04489795918367346939
54
55
/*****************************************************************************
56
 * Local prototypes
57
 *****************************************************************************/
58
static int Demux  ( demux_t * );
59
static int Control( demux_t *, int, va_list );
60
61
typedef struct
62
{
63
    /* */
64
    es_out_id_t *p_es;
65
66
    /* */
67
    uint32_t i_totalframes;
68
    uint32_t i_currentframe;
69
    uint32_t *pi_seektable;
70
    uint32_t i_datalength;
71
    int      i_framelength;
72
73
    /* */
74
    vlc_meta_t     *p_meta;
75
    int64_t        i_start;
76
} demux_sys_t;
77
78
/*****************************************************************************
79
 * Open: initializes ES structures
80
 *****************************************************************************/
81
static int Open( vlc_object_t * p_this )
82
16
{
83
16
    demux_t     *p_demux = (demux_t*)p_this;
84
16
    demux_sys_t *p_sys;
85
16
    es_format_t fmt;
86
16
    const uint8_t *p_peek;
87
16
    uint8_t     p_header[22];
88
16
    uint8_t     *p_fullheader;
89
16
    int         i_seektable_size = 0;
90
    //char        psz_info[4096];
91
    //module_t    *p_id3;
92
93
16
    if( vlc_stream_Peek( p_demux->s, &p_peek, 4 ) < 4 )
94
0
        return VLC_EGENERIC;
95
96
16
    if( memcmp( p_peek, "TTA1", 4 ) )
97
16
    {
98
16
        if( !p_demux->obj.force )
99
16
            return VLC_EGENERIC;
100
101
        /* User forced */
102
0
        msg_Err( p_demux, "this doesn't look like a true-audio stream, "
103
0
                 "continuing anyway" );
104
0
    }
105
106
0
    if( vlc_stream_Read( p_demux->s, p_header, 22 ) < 22 )
107
0
        return VLC_EGENERIC;
108
109
    /* Fill p_demux fields */
110
0
    p_demux->pf_demux = Demux;
111
0
    p_demux->pf_control = Control;
112
0
    p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
113
0
    if( !p_sys )
114
0
        return VLC_ENOMEM;
115
116
0
    p_sys->pi_seektable = NULL;
117
118
    /* Read the metadata */
119
0
    es_format_Init( &fmt, AUDIO_ES, VLC_CODEC_TTA );
120
0
    fmt.audio.i_channels = GetWLE( &p_header[6] );
121
0
    fmt.audio.i_bitspersample = GetWLE( &p_header[8] );
122
0
    fmt.audio.i_rate = GetDWLE( &p_header[10] );
123
0
    if( fmt.audio.i_rate == 0 || /* Avoid divide by 0 */
124
0
        fmt.audio.i_rate > ( 1 << 20 ) /* Avoid i_framelength overflow */ )
125
0
    {
126
0
        msg_Warn( p_demux, "Wrong sample rate" );
127
0
        goto error;
128
0
    }
129
130
0
    p_sys->i_datalength = GetDWLE( &p_header[14] );
131
0
    p_sys->i_framelength = TTA_FRAMETIME * fmt.audio.i_rate;
132
133
0
    p_sys->i_totalframes = p_sys->i_datalength / p_sys->i_framelength +
134
0
                          ((p_sys->i_datalength % p_sys->i_framelength) != 0);
135
0
    p_sys->i_currentframe = 0;
136
0
    if( (INT_MAX - 22 - 4) / sizeof(uint32_t) < p_sys->i_totalframes )
137
0
        goto error;
138
139
0
    i_seektable_size = sizeof(uint32_t)*p_sys->i_totalframes;
140
141
    /* Store the header and Seektable for avcodec */
142
0
    fmt.i_extra = 22 + i_seektable_size + 4;
143
0
    fmt.p_extra = p_fullheader = malloc( fmt.i_extra );
144
0
    if( !p_fullheader )
145
0
    {
146
0
        fmt.i_extra = 0;
147
0
        goto error;
148
0
    }
149
150
0
    memcpy( p_fullheader, p_header, 22 );
151
0
    p_fullheader += 22;
152
0
    if( vlc_stream_Read( p_demux->s, p_fullheader, i_seektable_size )
153
0
             != i_seektable_size )
154
0
        goto error;
155
156
0
    p_sys->pi_seektable = calloc( p_sys->i_totalframes, sizeof(uint32_t) );
157
0
    if( !p_sys->pi_seektable )
158
0
        goto error;
159
0
    for( uint32_t i = 0; i < p_sys->i_totalframes; i++ )
160
0
    {
161
0
        p_sys->pi_seektable[i] = GetDWLE( p_fullheader );
162
0
        p_fullheader += 4;
163
0
    }
164
165
0
    if( 4 != vlc_stream_Read( p_demux->s, p_fullheader, 4 ) ) /* CRC */
166
0
        goto error;
167
0
    p_fullheader += 4;
168
169
0
    p_sys->p_es = es_out_Add( p_demux->out, &fmt );
170
0
    p_sys->i_start = p_fullheader - (uint8_t *)fmt.p_extra;
171
0
    es_format_Clean( &fmt );
172
173
0
    return VLC_SUCCESS;
174
0
error:
175
0
    es_format_Clean( &fmt );
176
0
    Close( p_this );
177
0
    return VLC_EGENERIC;
178
0
}
179
180
/*****************************************************************************
181
 * Close: frees unused data
182
 *****************************************************************************/
183
static void Close( vlc_object_t * p_this )
184
0
{
185
0
    demux_t        *p_demux = (demux_t*)p_this;
186
0
    demux_sys_t    *p_sys = p_demux->p_sys;
187
188
0
    free( p_sys->pi_seektable );
189
0
    free( p_sys );
190
0
}
191
192
/*****************************************************************************
193
 * Demux:
194
 *****************************************************************************
195
 * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
196
 *****************************************************************************/
197
static int Demux( demux_t *p_demux )
198
0
{
199
0
    demux_sys_t *p_sys = p_demux->p_sys;
200
0
    block_t     *p_data;
201
202
0
    if( p_sys->i_currentframe >= p_sys->i_totalframes )
203
0
        return VLC_DEMUXER_EOF;
204
205
0
    p_data = vlc_stream_Block( p_demux->s,
206
0
                               p_sys->pi_seektable[p_sys->i_currentframe] );
207
0
    if( p_data == NULL )
208
0
        return VLC_DEMUXER_EOF;
209
0
    p_data->i_dts = p_data->i_pts = VLC_TICK_0 + vlc_tick_from_sec( p_sys->i_currentframe * TTA_FRAMETIME );
210
211
0
    p_sys->i_currentframe++;
212
213
0
    es_out_SetPCR( p_demux->out, p_data->i_dts );
214
0
    if( p_sys->p_es )
215
0
        es_out_Send( p_demux->out, p_sys->p_es, p_data );
216
217
0
    return VLC_DEMUXER_SUCCESS;
218
0
}
219
220
/*****************************************************************************
221
 * Control:
222
 *****************************************************************************/
223
static int Control( demux_t *p_demux, int i_query, va_list args )
224
0
{
225
0
    demux_sys_t *p_sys = p_demux->p_sys;
226
0
    double   f, *pf;
227
0
    int64_t i64;
228
229
0
    switch( i_query )
230
0
    {
231
0
        case DEMUX_CAN_SEEK:
232
0
            return vlc_stream_vaControl( p_demux->s, i_query, args );
233
234
0
        case DEMUX_GET_POSITION:
235
0
            pf = va_arg( args, double * );
236
0
            i64 = stream_Size( p_demux->s ) - p_sys->i_start;
237
0
            if( i64 > 0 )
238
0
            {
239
0
                *pf = (double)(vlc_stream_Tell( p_demux->s ) - p_sys->i_start )/ (double)i64;
240
0
            }
241
0
            else
242
0
            {
243
0
                *pf = 0.0;
244
0
            }
245
0
            return VLC_SUCCESS;
246
247
0
        case DEMUX_SET_POSITION:
248
0
            f = va_arg( args, double );
249
0
            i64 = (int64_t)(f * (stream_Size( p_demux->s ) - p_sys->i_start));
250
0
            if( i64 > 0 )
251
0
            {
252
0
                int64_t tmp = 0;
253
0
                uint32_t i;
254
0
                for( i=0; i < p_sys->i_totalframes && tmp+p_sys->pi_seektable[i] < i64; i++)
255
0
                {
256
0
                    tmp += p_sys->pi_seektable[i];
257
0
                }
258
0
                if( vlc_stream_Seek( p_demux->s, tmp+p_sys->i_start ) )
259
0
                    return VLC_EGENERIC;
260
0
                p_sys->i_currentframe = i;
261
0
                return VLC_SUCCESS;
262
0
            }
263
0
            return VLC_EGENERIC;
264
265
0
        case DEMUX_GET_LENGTH:
266
0
            *va_arg( args, vlc_tick_t * ) =
267
0
                vlc_tick_from_sec( p_sys->i_totalframes * TTA_FRAMETIME );
268
0
            return VLC_SUCCESS;
269
270
0
        case DEMUX_GET_TIME:
271
0
            *va_arg( args, vlc_tick_t * ) = vlc_tick_from_sec( p_sys->i_currentframe * TTA_FRAMETIME );
272
0
            return VLC_SUCCESS;
273
274
0
        case DEMUX_CAN_PAUSE:
275
0
        case DEMUX_SET_PAUSE_STATE:
276
0
        case DEMUX_CAN_CONTROL_PACE:
277
0
        case DEMUX_GET_PTS_DELAY:
278
0
            return demux_vaControlHelper( p_demux->s, 0, p_sys->i_datalength,
279
0
                                          0, p_sys->i_framelength, i_query, args );
280
281
0
        default:
282
0
            return VLC_EGENERIC;
283
0
    }
284
0
}
285