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
)
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
;
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 */
99 if (vlc_stream_Peek (demux
->s
, &peek
, 4) < 4)
102 /* sidplay2 can read PSID and the newer RSID formats */
103 if(memcmp(peek
,"PSID",4)!=0 && memcmp(peek
,"RSID",4)!=0)
106 uint8_t *data
= (uint8_t*) malloc(size
);
107 if (unlikely (data
==NULL
))
110 if (vlc_stream_Read (demux
->s
,data
,size
) < size
) {
115 tune
= new (std::nothrow
) SidTune(0);
116 if (unlikely (tune
==NULL
)) {
121 result
= tune
->read (data
, size
);
126 player
= new (std::nothrow
) sidplay2();
127 if (unlikely(player
==NULL
))
130 sys
= reinterpret_cast<demux_sys_t
*>(calloc(1, sizeof(demux_sys_t
)));
131 if (unlikely(sys
==NULL
))
134 sys
->player
= player
;
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
))
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);
181 demux
->pf_demux
= Demux
;
182 demux
->pf_control
= Control
;
188 msg_Err (demux
, "An error occurred during sid demuxing" );
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
);
203 delete sys
->config
.sidEmulation
;
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
);
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
);
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);
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] );
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();
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 );
286 sys
->last_title
= i_idx
;
287 sys
->title_changed
= true;
288 msg_Dbg( demux
, "set song %i", i_idx
);
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;
304 case DEMUX_GET_TITLE
:
305 *va_arg(args
, int *) = sys
->last_title
;
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
);