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 *****************************************************************************/
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()) {
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
);