3 * @brief Sidplay demux module for VLC media player
5 /*****************************************************************************
6 * Copyright © 2010 Rémi Denis-Courmont
7 * Copyright © 2010 Alan Fischer <alan@lightningtoads.com>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * This library 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 General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 ****************************************************************************/
28 /* INT64_C and UINT64_C are only exposed to c++ if this is defined */
29 #ifndef __STDC_CONSTANT_MACROS
30 # define __STDC_CONSTANT_MACROS
33 #include <vlc_common.h>
34 #include <vlc_input.h>
35 #include <vlc_demux.h>
36 #include <vlc_plugin.h>
40 #include <sidplay/sidplay2.h>
41 #include <sidplay/builders/resid.h>
43 static int Open (vlc_object_t *);
44 static void Close (vlc_object_t *);
48 set_description ( N_("C64 sid demuxer") )
49 set_category (CAT_INPUT)
50 set_subcategory (SUBCAT_INPUT_DEMUX)
51 set_capability ("demux", 100)
52 set_callbacks (Open, Close)
70 static int Demux (demux_t *);
71 static int Control (demux_t *, int, va_list);
73 static int Open (vlc_object_t *obj)
75 demux_t *demux = (demux_t *)obj;
76 demux_sys_t *sys = NULL;
80 sidplay2 *player = NULL;
81 ReSIDBuilder *builder = NULL;
83 int64_t size = stream_Size (demux->s);
84 if (size < 4 || size > LONG_MAX) /* We need to load the whole file for sidplay */
88 if (stream_Peek (demux->s, &peek, 4) < 4)
91 /* sidplay2 can read PSID and the newer RSID formats */
92 if(memcmp(peek,"PSID",4)!=0 && memcmp(peek,"RSID",4)!=0)
95 uint8_t *data = (uint8_t*) malloc(size);
96 if (unlikely (data==NULL))
99 if (stream_Read (demux->s,data,size) < size) {
104 tune = new SidTune(0);
105 if (unlikely (tune==NULL)) {
110 result = tune->read (data, size);
115 player = new sidplay2();
116 if (unlikely(player==NULL))
119 sys = (demux_sys_t*) calloc (1, sizeof(demux_sys_t));
120 if (unlikely(sys==NULL))
123 sys->player = player;
126 tune->getInfo (sys->tuneInfo);
128 sys->info = player->info();
129 sys->config = player->config();
131 builder = new ReSIDBuilder ("ReSID");
132 if (unlikely(builder==NULL))
135 builder->create (sys->info.maxsids);
136 builder->sampling (sys->config.frequency);
138 sys->config.sidEmulation = builder;
139 sys->config.precision = 16;
140 sys->config.playback = (sys->info.channels == 2 ? sid2_stereo : sid2_mono);
142 player->config (sys->config);
144 sys->bytes_per_frame = sys->info.channels * sys->config.precision / 8;
145 sys->block_size = sys->config.frequency / 10 * sys->bytes_per_frame;
147 es_format_Init (&fmt, AUDIO_ES, VLC_CODEC_S16N);
149 fmt.audio.i_channels = sys->info.channels;
150 fmt.audio.i_bitspersample = sys->config.precision;
151 fmt.audio.i_rate = sys->config.frequency;
152 fmt.audio.i_bytes_per_frame = sys->bytes_per_frame;
153 fmt.audio.i_frame_length = fmt.audio.i_bytes_per_frame;
154 fmt.audio.i_blockalign = fmt.audio.i_bytes_per_frame;
156 fmt.i_bitrate = fmt.audio.i_rate * fmt.audio.i_bytes_per_frame;
158 sys->es = es_out_Add (demux->out, &fmt);
160 date_Init (&sys->pts, fmt.audio.i_rate, 1);
161 date_Set (&sys->pts, 0);
163 sys->tune->selectSong (0);
164 result = (sys->player->load (sys->tune) >=0 );
165 sys->player->fastForward (100);
170 demux->pf_demux = Demux;
171 demux->pf_control = Control;
177 msg_Err (demux, "An error occured during sid demuxing" );
186 static void Close (vlc_object_t *obj)
188 demux_t *demux = (demux_t *)obj;
189 demux_sys_t *sys = demux->p_sys;
192 delete sys->config.sidEmulation;
197 static int Demux (demux_t *demux)
199 demux_sys_t *sys = demux->p_sys;
201 block_t *block = block_New( p_demux, sys->block_size);
202 if (unlikely(block==NULL))
205 if (sys->tune->getStatus() == false) {
206 block_Release (block);
210 int i_read = sys->player->play ((void*)block->p_buffer, block->i_buffer);
212 block_Release (block);
215 block->i_buffer = i_read;
216 block->i_pts = block->i_dts = VLC_TS_0 + date_Get (&sys->pts);
218 es_out_Control (demux->out, ES_OUT_SET_PCR, block->i_pts);
220 es_out_Send (demux->out, sys->es, block);
222 date_Increment (&sys->pts, i_read / sys->bytes_per_frame);
228 static int Control (demux_t *demux, int query, va_list args)
230 demux_sys_t *sys = demux->p_sys;
234 case DEMUX_GET_TIME : {
235 int64_t *v = va_arg (args, int64_t*);
236 *v = sys->player->time() * sys->player->timebase() * (CLOCK_FREQ / 100);
240 case DEMUX_GET_META : {
241 vlc_meta_t *p_meta = (vlc_meta_t *) va_arg (args, vlc_meta_t*);
243 /* These are specified in the sid tune class as 0 = Title, 1 = Artist, 2 = Copyright/Publisher */
244 vlc_meta_SetTitle( p_meta, sys->tuneInfo.infoString[0] );
245 vlc_meta_SetArtist( p_meta, sys->tuneInfo.infoString[1] );
246 vlc_meta_SetCopyright( p_meta, sys->tuneInfo.infoString[2] );
251 case DEMUX_GET_TITLE_INFO :
252 if ( sys->tuneInfo.songs > 1 ) {
253 input_title_t ***ppp_title = (input_title_t***) va_arg (args, input_title_t***);
254 int *pi_int = (int*)va_arg( args, int* );
256 *pi_int = sys->tuneInfo.songs;
257 *ppp_title = (input_title_t**) malloc( sizeof (input_title_t**) * sys->tuneInfo.songs);
259 for( int i = 0; i < sys->tuneInfo.songs; i++ ) {
260 (*ppp_title)[i] = vlc_input_title_New();
267 case DEMUX_SET_TITLE : {
268 int i_idx = (int) va_arg (args, int);
269 sys->tune->selectSong (i_idx+1);
270 bool result = (sys->player->load (sys->tune) >=0 );
274 demux->info.i_title = i_idx;
275 demux->info.i_update = INPUT_UPDATE_TITLE;
276 msg_Dbg( demux, "set song %i", i_idx);