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 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 *****************************************************************************/
36 #include <vlc_common.h>
37 #include <vlc_input.h>
38 #include <vlc_demux.h>
39 #include <vlc_plugin.h>
43 #include <sidplay/sidplay2.h>
44 #include <sidplay/builders/resid.h>
48 static int Open (vlc_object_t
*);
49 static void Close (vlc_object_t
*);
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
)
78 static int Demux (demux_t
*);
79 static int Control (demux_t
*, int, va_list);
81 static int Open (vlc_object_t
*obj
)
83 demux_t
*demux
= (demux_t
*)obj
;
84 demux_sid
*sys
= NULL
;
88 sidplay2
*player
= NULL
;
89 ReSIDBuilder
*builder
= NULL
;
91 int64_t size
= stream_Size (demux
->s
);
92 if (size
< 4 || size
> LONG_MAX
) /* We need to load the whole file for sidplay */
96 if (vlc_stream_Peek (demux
->s
, &peek
, 4) < 4)
99 /* sidplay2 can read PSID and the newer RSID formats */
100 if(memcmp(peek
,"PSID",4)!=0 && memcmp(peek
,"RSID",4)!=0)
103 uint8_t *data
= (uint8_t*) malloc(size
);
104 if (unlikely (data
==NULL
))
107 if (vlc_stream_Read (demux
->s
,data
,size
) < size
) {
112 tune
= new (std::nothrow
) SidTune(0);
113 if (unlikely (tune
==NULL
)) {
118 result
= tune
->read (data
, size
);
123 player
= new (std::nothrow
) sidplay2();
124 if (unlikely(player
==NULL
))
127 sys
= reinterpret_cast<demux_sid
*>(calloc (1, sizeof(demux_sid
)));
128 if (unlikely(sys
==NULL
))
131 sys
->player
= player
;
134 tune
->getInfo (sys
->tuneInfo
);
136 sys
->info
= player
->info();
137 sys
->config
= player
->config();
139 builder
= new (std::nothrow
) ReSIDBuilder ("ReSID");
140 if (unlikely(builder
==NULL
))
143 builder
->create (sys
->info
.maxsids
);
144 builder
->sampling (sys
->config
.frequency
);
146 sys
->config
.sidEmulation
= builder
;
147 sys
->config
.precision
= 16;
148 sys
->config
.playback
= (sys
->info
.channels
== 2 ? sid2_stereo
: sid2_mono
);
150 player
->config (sys
->config
);
152 sys
->bytes_per_frame
= sys
->info
.channels
* sys
->config
.precision
/ 8;
153 sys
->block_size
= sys
->config
.frequency
/ 10 * sys
->bytes_per_frame
;
155 es_format_Init (&fmt
, AUDIO_ES
, VLC_CODEC_S16N
);
157 fmt
.audio
.i_channels
= sys
->info
.channels
;
158 fmt
.audio
.i_bitspersample
= sys
->config
.precision
;
159 fmt
.audio
.i_rate
= sys
->config
.frequency
;
160 fmt
.audio
.i_bytes_per_frame
= sys
->bytes_per_frame
;
161 fmt
.audio
.i_frame_length
= fmt
.audio
.i_bytes_per_frame
;
162 fmt
.audio
.i_blockalign
= fmt
.audio
.i_bytes_per_frame
;
164 fmt
.i_bitrate
= fmt
.audio
.i_rate
* fmt
.audio
.i_bytes_per_frame
;
166 sys
->es
= es_out_Add (demux
->out
, &fmt
);
168 date_Init (&sys
->pts
, fmt
.audio
.i_rate
, 1);
169 date_Set(&sys
->pts
, VLC_TICK_0
);
171 sys
->tune
->selectSong (0);
172 result
= (sys
->player
->load (sys
->tune
) >=0 );
173 sys
->player
->fastForward (100);
178 demux
->pf_demux
= Demux
;
179 demux
->pf_control
= Control
;
185 msg_Err (demux
, "An error occurred during sid demuxing" );
194 static void Close (vlc_object_t
*obj
)
196 demux_t
*demux
= (demux_t
*)obj
;
197 demux_sid
*sys
= reinterpret_cast<demux_sid
*>(demux
->p_sys
);
200 delete sys
->config
.sidEmulation
;
205 static int Demux (demux_t
*demux
)
207 demux_sid
*sys
= reinterpret_cast<demux_sid
*>(demux
->p_sys
);
209 block_t
*block
= block_Alloc( sys
->block_size
);
210 if (unlikely(block
==NULL
))
211 return VLC_DEMUXER_EOF
;
213 if (!sys
->tune
->getStatus()) {
214 block_Release (block
);
215 return VLC_DEMUXER_EOF
;
218 int i_read
= sys
->player
->play ((void*)block
->p_buffer
, block
->i_buffer
);
220 block_Release (block
);
221 return VLC_DEMUXER_EOF
;
223 block
->i_buffer
= i_read
;
224 block
->i_pts
= block
->i_dts
= date_Get (&sys
->pts
);
226 es_out_SetPCR (demux
->out
, block
->i_pts
);
228 es_out_Send (demux
->out
, sys
->es
, block
);
230 date_Increment (&sys
->pts
, i_read
/ sys
->bytes_per_frame
);
232 return VLC_DEMUXER_SUCCESS
;
236 static int Control (demux_t
*demux
, int query
, va_list args
)
238 demux_sid
*sys
= reinterpret_cast<demux_sid
*>(demux
->p_sys
);
242 case DEMUX_GET_TIME
: {
243 int64_t *v
= va_arg (args
, int64_t*);
244 *v
= sys
->player
->time() * sys
->player
->timebase() * VLC_TICK_FROM_MS(10);
248 case DEMUX_GET_META
: {
249 vlc_meta_t
*p_meta
= va_arg (args
, vlc_meta_t
*);
251 /* These are specified in the sid tune class as 0 = Title, 1 = Artist, 2 = Copyright/Publisher */
252 vlc_meta_SetTitle( p_meta
, sys
->tuneInfo
.infoString
[0] );
253 vlc_meta_SetArtist( p_meta
, sys
->tuneInfo
.infoString
[1] );
254 vlc_meta_SetCopyright( p_meta
, sys
->tuneInfo
.infoString
[2] );
259 case DEMUX_GET_TITLE_INFO
:
260 if ( sys
->tuneInfo
.songs
> 1 ) {
261 input_title_t
***ppp_title
= va_arg (args
, input_title_t
***);
262 int *pi_int
= va_arg( args
, int* );
264 *pi_int
= sys
->tuneInfo
.songs
;
265 *ppp_title
= (input_title_t
**) vlc_alloc( sys
->tuneInfo
.songs
, sizeof (input_title_t
*));
267 for( int i
= 0; i
< sys
->tuneInfo
.songs
; i
++ ) {
268 (*ppp_title
)[i
] = vlc_input_title_New();
275 case DEMUX_SET_TITLE
: {
276 int i_idx
= va_arg (args
, int);
277 sys
->tune
->selectSong (i_idx
+1);
278 bool result
= (sys
->player
->load (sys
->tune
) >=0 );
282 sys
->last_title
= i_idx
;
283 sys
->title_changed
= true;
284 msg_Dbg( demux
, "set song %i", i_idx
);
289 case DEMUX_TEST_AND_CLEAR_FLAGS
: {
290 unsigned *restrict flags
= va_arg(args
, unsigned *);
292 if ((*flags
& INPUT_UPDATE_TITLE
) && sys
->title_changed
) {
293 *flags
= INPUT_UPDATE_TITLE
;
294 sys
->title_changed
= false;
300 case DEMUX_GET_TITLE
:
301 *va_arg(args
, int *) = sys
->last_title
;
304 case DEMUX_CAN_PAUSE
:
305 case DEMUX_SET_PAUSE_STATE
:
306 case DEMUX_CAN_CONTROL_PACE
:
307 case DEMUX_GET_PTS_DELAY
:
308 return demux_vaControlHelper( demux
->s
, 0, -1, 0,
309 sys
->bytes_per_frame
, query
, args
);