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
)
77 static int Demux (demux_t
*);
78 static int Control (demux_t
*, int, va_list);
80 static int Open (vlc_object_t
*obj
)
82 demux_t
*demux
= (demux_t
*)obj
;
83 demux_sys_t
*sys
= NULL
;
87 sidplay2
*player
= NULL
;
88 ReSIDBuilder
*builder
= NULL
;
90 int64_t size
= stream_Size (demux
->s
);
91 if (size
< 4 || size
> LONG_MAX
) /* We need to load the whole file for sidplay */
95 if (vlc_stream_Peek (demux
->s
, &peek
, 4) < 4)
98 /* sidplay2 can read PSID and the newer RSID formats */
99 if(memcmp(peek
,"PSID",4)!=0 && memcmp(peek
,"RSID",4)!=0)
102 uint8_t *data
= (uint8_t*) malloc(size
);
103 if (unlikely (data
==NULL
))
106 if (vlc_stream_Read (demux
->s
,data
,size
) < size
) {
111 tune
= new (std::nothrow
) SidTune(0);
112 if (unlikely (tune
==NULL
)) {
117 result
= tune
->read (data
, size
);
122 player
= new (std::nothrow
) sidplay2();
123 if (unlikely(player
==NULL
))
126 sys
= (demux_sys_t
*) calloc (1, sizeof(demux_sys_t
));
127 if (unlikely(sys
==NULL
))
130 sys
->player
= player
;
133 tune
->getInfo (sys
->tuneInfo
);
135 sys
->info
= player
->info();
136 sys
->config
= player
->config();
138 builder
= new (std::nothrow
) ReSIDBuilder ("ReSID");
139 if (unlikely(builder
==NULL
))
142 builder
->create (sys
->info
.maxsids
);
143 builder
->sampling (sys
->config
.frequency
);
145 sys
->config
.sidEmulation
= builder
;
146 sys
->config
.precision
= 16;
147 sys
->config
.playback
= (sys
->info
.channels
== 2 ? sid2_stereo
: sid2_mono
);
149 player
->config (sys
->config
);
151 sys
->bytes_per_frame
= sys
->info
.channels
* sys
->config
.precision
/ 8;
152 sys
->block_size
= sys
->config
.frequency
/ 10 * sys
->bytes_per_frame
;
154 es_format_Init (&fmt
, AUDIO_ES
, VLC_CODEC_S16N
);
156 fmt
.audio
.i_channels
= sys
->info
.channels
;
157 fmt
.audio
.i_bitspersample
= sys
->config
.precision
;
158 fmt
.audio
.i_rate
= sys
->config
.frequency
;
159 fmt
.audio
.i_bytes_per_frame
= sys
->bytes_per_frame
;
160 fmt
.audio
.i_frame_length
= fmt
.audio
.i_bytes_per_frame
;
161 fmt
.audio
.i_blockalign
= fmt
.audio
.i_bytes_per_frame
;
163 fmt
.i_bitrate
= fmt
.audio
.i_rate
* fmt
.audio
.i_bytes_per_frame
;
165 sys
->es
= es_out_Add (demux
->out
, &fmt
);
167 date_Init (&sys
->pts
, fmt
.audio
.i_rate
, 1);
168 date_Set (&sys
->pts
, 0);
170 sys
->tune
->selectSong (0);
171 result
= (sys
->player
->load (sys
->tune
) >=0 );
172 sys
->player
->fastForward (100);
177 demux
->pf_demux
= Demux
;
178 demux
->pf_control
= Control
;
184 msg_Err (demux
, "An error occurred during sid demuxing" );
193 static void Close (vlc_object_t
*obj
)
195 demux_t
*demux
= (demux_t
*)obj
;
196 demux_sys_t
*sys
= (demux_sys_t
*)demux
->p_sys
;
199 delete sys
->config
.sidEmulation
;
204 static int Demux (demux_t
*demux
)
206 demux_sys_t
*sys
= (demux_sys_t
*)demux
->p_sys
;
208 block_t
*block
= block_Alloc( sys
->block_size
);
209 if (unlikely(block
==NULL
))
212 if (!sys
->tune
->getStatus()) {
213 block_Release (block
);
217 int i_read
= sys
->player
->play ((void*)block
->p_buffer
, block
->i_buffer
);
219 block_Release (block
);
222 block
->i_buffer
= i_read
;
223 block
->i_pts
= block
->i_dts
= VLC_TS_0
+ date_Get (&sys
->pts
);
225 es_out_SetPCR (demux
->out
, block
->i_pts
);
227 es_out_Send (demux
->out
, sys
->es
, block
);
229 date_Increment (&sys
->pts
, i_read
/ sys
->bytes_per_frame
);
235 static int Control (demux_t
*demux
, int query
, va_list args
)
237 demux_sys_t
*sys
= (demux_sys_t
*)demux
->p_sys
;
241 case DEMUX_GET_TIME
: {
242 int64_t *v
= va_arg (args
, int64_t*);
243 *v
= sys
->player
->time() * sys
->player
->timebase() * (CLOCK_FREQ
/ 100);
247 case DEMUX_GET_META
: {
248 vlc_meta_t
*p_meta
= va_arg (args
, vlc_meta_t
*);
250 /* These are specified in the sid tune class as 0 = Title, 1 = Artist, 2 = Copyright/Publisher */
251 vlc_meta_SetTitle( p_meta
, sys
->tuneInfo
.infoString
[0] );
252 vlc_meta_SetArtist( p_meta
, sys
->tuneInfo
.infoString
[1] );
253 vlc_meta_SetCopyright( p_meta
, sys
->tuneInfo
.infoString
[2] );
258 case DEMUX_GET_TITLE_INFO
:
259 if ( sys
->tuneInfo
.songs
> 1 ) {
260 input_title_t
***ppp_title
= va_arg (args
, input_title_t
***);
261 int *pi_int
= va_arg( args
, int* );
263 *pi_int
= sys
->tuneInfo
.songs
;
264 *ppp_title
= (input_title_t
**) vlc_alloc( sys
->tuneInfo
.songs
, sizeof (input_title_t
*));
266 for( int i
= 0; i
< sys
->tuneInfo
.songs
; i
++ ) {
267 (*ppp_title
)[i
] = vlc_input_title_New();
274 case DEMUX_SET_TITLE
: {
275 int i_idx
= va_arg (args
, int);
276 sys
->tune
->selectSong (i_idx
+1);
277 bool result
= (sys
->player
->load (sys
->tune
) >=0 );
281 sys
->last_title
= i_idx
;
282 demux
->info
.i_update
= INPUT_UPDATE_TITLE
;
283 msg_Dbg( demux
, "set song %i", i_idx
);
288 case DEMUX_GET_TITLE
:
289 *va_arg(args
, int *) = sys
->last_title
;