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
)
75 static int Demux (demux_t
*);
76 static int Control (demux_t
*, int, va_list);
78 static int Open (vlc_object_t
*obj
)
80 demux_t
*demux
= (demux_t
*)obj
;
81 demux_sys_t
*sys
= NULL
;
85 sidplay2
*player
= NULL
;
86 ReSIDBuilder
*builder
= NULL
;
88 int64_t size
= stream_Size (demux
->s
);
89 if (size
< 4 || size
> LONG_MAX
) /* We need to load the whole file for sidplay */
93 if (vlc_stream_Peek (demux
->s
, &peek
, 4) < 4)
96 /* sidplay2 can read PSID and the newer RSID formats */
97 if(memcmp(peek
,"PSID",4)!=0 && memcmp(peek
,"RSID",4)!=0)
100 uint8_t *data
= (uint8_t*) malloc(size
);
101 if (unlikely (data
==NULL
))
104 if (vlc_stream_Read (demux
->s
,data
,size
) < size
) {
109 tune
= new (std::nothrow
) SidTune(0);
110 if (unlikely (tune
==NULL
)) {
115 result
= tune
->read (data
, size
);
120 player
= new (std::nothrow
) sidplay2();
121 if (unlikely(player
==NULL
))
124 sys
= (demux_sys_t
*) calloc (1, sizeof(demux_sys_t
));
125 if (unlikely(sys
==NULL
))
128 sys
->player
= player
;
131 tune
->getInfo (sys
->tuneInfo
);
133 sys
->info
= player
->info();
134 sys
->config
= player
->config();
136 builder
= new (std::nothrow
) ReSIDBuilder ("ReSID");
137 if (unlikely(builder
==NULL
))
140 builder
->create (sys
->info
.maxsids
);
141 builder
->sampling (sys
->config
.frequency
);
143 sys
->config
.sidEmulation
= builder
;
144 sys
->config
.precision
= 16;
145 sys
->config
.playback
= (sys
->info
.channels
== 2 ? sid2_stereo
: sid2_mono
);
147 player
->config (sys
->config
);
149 sys
->bytes_per_frame
= sys
->info
.channels
* sys
->config
.precision
/ 8;
150 sys
->block_size
= sys
->config
.frequency
/ 10 * sys
->bytes_per_frame
;
152 es_format_Init (&fmt
, AUDIO_ES
, VLC_CODEC_S16N
);
154 fmt
.audio
.i_channels
= sys
->info
.channels
;
155 fmt
.audio
.i_bitspersample
= sys
->config
.precision
;
156 fmt
.audio
.i_rate
= sys
->config
.frequency
;
157 fmt
.audio
.i_bytes_per_frame
= sys
->bytes_per_frame
;
158 fmt
.audio
.i_frame_length
= fmt
.audio
.i_bytes_per_frame
;
159 fmt
.audio
.i_blockalign
= fmt
.audio
.i_bytes_per_frame
;
161 fmt
.i_bitrate
= fmt
.audio
.i_rate
* fmt
.audio
.i_bytes_per_frame
;
163 sys
->es
= es_out_Add (demux
->out
, &fmt
);
165 date_Init (&sys
->pts
, fmt
.audio
.i_rate
, 1);
166 date_Set (&sys
->pts
, 0);
168 sys
->tune
->selectSong (0);
169 result
= (sys
->player
->load (sys
->tune
) >=0 );
170 sys
->player
->fastForward (100);
175 demux
->pf_demux
= Demux
;
176 demux
->pf_control
= Control
;
182 msg_Err (demux
, "An error occurred during sid demuxing" );
191 static void Close (vlc_object_t
*obj
)
193 demux_t
*demux
= (demux_t
*)obj
;
194 demux_sys_t
*sys
= demux
->p_sys
;
197 delete sys
->config
.sidEmulation
;
202 static int Demux (demux_t
*demux
)
204 demux_sys_t
*sys
= demux
->p_sys
;
206 block_t
*block
= block_Alloc( sys
->block_size
);
207 if (unlikely(block
==NULL
))
210 if (!sys
->tune
->getStatus()) {
211 block_Release (block
);
215 int i_read
= sys
->player
->play ((void*)block
->p_buffer
, block
->i_buffer
);
217 block_Release (block
);
220 block
->i_buffer
= i_read
;
221 block
->i_pts
= block
->i_dts
= VLC_TS_0
+ date_Get (&sys
->pts
);
223 es_out_SetPCR (demux
->out
, block
->i_pts
);
225 es_out_Send (demux
->out
, sys
->es
, block
);
227 date_Increment (&sys
->pts
, i_read
/ sys
->bytes_per_frame
);
233 static int Control (demux_t
*demux
, int query
, va_list args
)
235 demux_sys_t
*sys
= demux
->p_sys
;
239 case DEMUX_GET_TIME
: {
240 int64_t *v
= va_arg (args
, int64_t*);
241 *v
= sys
->player
->time() * sys
->player
->timebase() * (CLOCK_FREQ
/ 100);
245 case DEMUX_GET_META
: {
246 vlc_meta_t
*p_meta
= va_arg (args
, vlc_meta_t
*);
248 /* These are specified in the sid tune class as 0 = Title, 1 = Artist, 2 = Copyright/Publisher */
249 vlc_meta_SetTitle( p_meta
, sys
->tuneInfo
.infoString
[0] );
250 vlc_meta_SetArtist( p_meta
, sys
->tuneInfo
.infoString
[1] );
251 vlc_meta_SetCopyright( p_meta
, sys
->tuneInfo
.infoString
[2] );
256 case DEMUX_GET_TITLE_INFO
:
257 if ( sys
->tuneInfo
.songs
> 1 ) {
258 input_title_t
***ppp_title
= va_arg (args
, input_title_t
***);
259 int *pi_int
= va_arg( args
, int* );
261 *pi_int
= sys
->tuneInfo
.songs
;
262 *ppp_title
= (input_title_t
**) vlc_alloc( sys
->tuneInfo
.songs
, sizeof (input_title_t
*));
264 for( int i
= 0; i
< sys
->tuneInfo
.songs
; i
++ ) {
265 (*ppp_title
)[i
] = vlc_input_title_New();
272 case DEMUX_SET_TITLE
: {
273 int i_idx
= va_arg (args
, int);
274 sys
->tune
->selectSong (i_idx
+1);
275 bool result
= (sys
->player
->load (sys
->tune
) >=0 );
279 demux
->info
.i_title
= i_idx
;
280 demux
->info
.i_update
= INPUT_UPDATE_TITLE
;
281 msg_Dbg( demux
, "set song %i", i_idx
);