contrib/gpg-error: simplify darwin triplet handling
[vlc.git] / modules / demux / sid.cpp
blob3ddec12115ac0091966af66ce9c8ca502d4c097a
1 /**
2 * @file sid.cpp
3 * @brief Sidplay demux module for VLC media player
4 */
5 /*****************************************************************************
6 * Copyright © 2010 Rémi Denis-Courmont
7 * Copyright © 2010 Alan Fischer <alan@lightningtoads.com>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
25 * NOTA BENE: this module requires the linking against a library which is
26 * known to require licensing under the GNU General Public License version 2
27 * (or later). Therefore, the result of compiling this module will normally
28 * be subject to the terms of that later license.
29 *****************************************************************************/
32 #ifdef HAVE_CONFIG_H
33 # include <config.h>
34 #endif
36 #include <vlc_common.h>
37 #include <vlc_input.h>
38 #include <vlc_demux.h>
39 #include <vlc_plugin.h>
41 #include <limits.h>
43 #include <sidplay/sidplay2.h>
44 #include <sidplay/builders/resid.h>
46 #include <new>
48 static int Open (vlc_object_t *);
49 static void Close (vlc_object_t *);
51 vlc_module_begin ()
52 set_shortname ("sid")
53 set_description ( N_("C64 sid demuxer") )
54 set_category (CAT_INPUT)
55 set_subcategory (SUBCAT_INPUT_DEMUX)
56 set_capability ("demux", 100)
57 set_callbacks (Open, Close)
58 vlc_module_end ()
60 namespace {
62 struct demux_sys_t
64 sidplay2 *player;
65 sid2_config_t config;
66 sid2_info_t info;
67 SidTune *tune;
68 SidTuneInfo tuneInfo;
70 int bytes_per_frame;
71 int block_size;
72 es_out_id_t *es;
73 date_t pts;
75 int last_title;
76 bool title_changed;
79 } // namespace
81 static int Demux (demux_t *);
82 static int Control (demux_t *, int, va_list);
84 static int Open (vlc_object_t *obj)
86 demux_t *demux = (demux_t *)obj;
87 demux_sys_t *sys = NULL;
88 es_format_t fmt;
89 bool result = false;
90 SidTune *tune = NULL;
91 sidplay2 *player = NULL;
92 ReSIDBuilder *builder = NULL;
94 int64_t size = stream_Size (demux->s);
95 if (size < 4 || size > LONG_MAX) /* We need to load the whole file for sidplay */
96 return VLC_EGENERIC;
98 const uint8_t *peek;
99 if (vlc_stream_Peek (demux->s, &peek, 4) < 4)
100 return VLC_EGENERIC;
102 /* sidplay2 can read PSID and the newer RSID formats */
103 if(memcmp(peek,"PSID",4)!=0 && memcmp(peek,"RSID",4)!=0)
104 return VLC_EGENERIC;
106 uint8_t *data = (uint8_t*) malloc(size);
107 if (unlikely (data==NULL))
108 goto error;
110 if (vlc_stream_Read (demux->s,data,size) < size) {
111 free (data);
112 goto error;
115 tune = new (std::nothrow) SidTune(0);
116 if (unlikely (tune==NULL)) {
117 free (data);
118 goto error;
121 result = tune->read (data, size);
122 free (data);
123 if (!result)
124 goto error;
126 player = new (std::nothrow) sidplay2();
127 if (unlikely(player==NULL))
128 goto error;
130 sys = reinterpret_cast<demux_sys_t *>(calloc(1, sizeof(demux_sys_t)));
131 if (unlikely(sys==NULL))
132 goto error;
134 sys->player = player;
135 sys->tune = tune;
137 tune->getInfo (sys->tuneInfo);
139 sys->info = player->info();
140 sys->config = player->config();
142 builder = new (std::nothrow) ReSIDBuilder ("ReSID");
143 if (unlikely(builder==NULL))
144 goto error;
146 builder->create (sys->info.maxsids);
147 builder->sampling (sys->config.frequency);
149 sys->config.sidEmulation = builder;
150 sys->config.precision = 16;
151 sys->config.playback = (sys->info.channels == 2 ? sid2_stereo : sid2_mono);
153 player->config (sys->config);
155 sys->bytes_per_frame = sys->info.channels * sys->config.precision / 8;
156 sys->block_size = sys->config.frequency / 10 * sys->bytes_per_frame;
158 es_format_Init (&fmt, AUDIO_ES, VLC_CODEC_S16N);
160 fmt.audio.i_channels = sys->info.channels;
161 fmt.audio.i_bitspersample = sys->config.precision;
162 fmt.audio.i_rate = sys->config.frequency;
163 fmt.audio.i_bytes_per_frame = sys->bytes_per_frame;
164 fmt.audio.i_frame_length = fmt.audio.i_bytes_per_frame;
165 fmt.audio.i_blockalign = fmt.audio.i_bytes_per_frame;
167 fmt.i_bitrate = fmt.audio.i_rate * fmt.audio.i_bytes_per_frame;
169 sys->es = es_out_Add (demux->out, &fmt);
171 date_Init (&sys->pts, fmt.audio.i_rate, 1);
172 date_Set(&sys->pts, VLC_TICK_0);
174 sys->tune->selectSong (0);
175 result = (sys->player->load (sys->tune) >=0 );
176 sys->player->fastForward (100);
177 if (!result)
178 goto error;
180 /* Callbacks */
181 demux->pf_demux = Demux;
182 demux->pf_control = Control;
183 demux->p_sys = sys;
185 return VLC_SUCCESS;
187 error:
188 msg_Err (demux, "An error occurred during sid demuxing" );
189 delete player;
190 delete builder;
191 delete tune;
192 free (sys);
193 return VLC_EGENERIC;
197 static void Close (vlc_object_t *obj)
199 demux_t *demux = (demux_t *)obj;
200 demux_sys_t *sys = reinterpret_cast<demux_sys_t *>(demux->p_sys);
202 delete sys->player;
203 delete sys->config.sidEmulation;
204 delete sys->tune;
205 free (sys);
208 static int Demux (demux_t *demux)
210 demux_sys_t *sys = reinterpret_cast<demux_sys_t *>(demux->p_sys);
212 block_t *block = block_Alloc( sys->block_size);
213 if (unlikely(block==NULL))
214 return VLC_DEMUXER_EOF;
216 if (!sys->tune->getStatus()) {
217 block_Release (block);
218 return VLC_DEMUXER_EOF;
221 int i_read = sys->player->play ((void*)block->p_buffer, block->i_buffer);
222 if (i_read <= 0) {
223 block_Release (block);
224 return VLC_DEMUXER_EOF;
226 block->i_buffer = i_read;
227 block->i_pts = block->i_dts = date_Get (&sys->pts);
229 es_out_SetPCR (demux->out, block->i_pts);
231 es_out_Send (demux->out, sys->es, block);
233 date_Increment (&sys->pts, i_read / sys->bytes_per_frame);
235 return VLC_DEMUXER_SUCCESS;
239 static int Control (demux_t *demux, int query, va_list args)
241 demux_sys_t *sys = reinterpret_cast<demux_sys_t *>(demux->p_sys);
243 switch (query)
245 case DEMUX_GET_TIME : {
246 /* FIXME resolution in 100ns? */
247 *va_arg (args, vlc_tick_t*) =
248 sys->player->time() * sys->player->timebase() * VLC_TICK_FROM_MS(10);
249 return VLC_SUCCESS;
252 case DEMUX_GET_META : {
253 vlc_meta_t *p_meta = va_arg (args, vlc_meta_t *);
255 /* These are specified in the sid tune class as 0 = Title, 1 = Artist, 2 = Copyright/Publisher */
256 vlc_meta_SetTitle( p_meta, sys->tuneInfo.infoString[0] );
257 vlc_meta_SetArtist( p_meta, sys->tuneInfo.infoString[1] );
258 vlc_meta_SetCopyright( p_meta, sys->tuneInfo.infoString[2] );
260 return VLC_SUCCESS;
263 case DEMUX_GET_TITLE_INFO :
264 if ( sys->tuneInfo.songs > 1 ) {
265 input_title_t ***ppp_title = va_arg (args, input_title_t ***);
266 int *pi_int = va_arg( args, int* );
268 *pi_int = sys->tuneInfo.songs;
269 *ppp_title = (input_title_t**) vlc_alloc( sys->tuneInfo.songs, sizeof (input_title_t*));
271 for( int i = 0; i < sys->tuneInfo.songs; i++ ) {
272 (*ppp_title)[i] = vlc_input_title_New();
275 return VLC_SUCCESS;
277 return VLC_EGENERIC;
279 case DEMUX_SET_TITLE : {
280 int i_idx = va_arg (args, int);
281 sys->tune->selectSong (i_idx+1);
282 bool result = (sys->player->load (sys->tune) >=0 );
283 if (!result)
284 return VLC_EGENERIC;
286 sys->last_title = i_idx;
287 sys->title_changed = true;
288 msg_Dbg( demux, "set song %i", i_idx);
290 return VLC_SUCCESS;
293 case DEMUX_TEST_AND_CLEAR_FLAGS: {
294 unsigned *restrict flags = va_arg(args, unsigned *);
296 if ((*flags & INPUT_UPDATE_TITLE) && sys->title_changed) {
297 *flags = INPUT_UPDATE_TITLE;
298 sys->title_changed = false;
299 } else
300 *flags = 0;
301 return VLC_SUCCESS;
304 case DEMUX_GET_TITLE:
305 *va_arg(args, int *) = sys->last_title;
306 return VLC_SUCCESS;
308 case DEMUX_CAN_PAUSE:
309 case DEMUX_SET_PAUSE_STATE:
310 case DEMUX_CAN_CONTROL_PACE:
311 case DEMUX_GET_PTS_DELAY:
312 return demux_vaControlHelper( demux->s, 0, -1, 0,
313 sys->bytes_per_frame, query, args );
316 return VLC_EGENERIC;