3 * @brief Game Music Emu demux module for VLC media player
5 /*****************************************************************************
6 * Copyright © 2010 Rémi Denis-Courmont
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
31 #include <vlc_common.h>
32 #include <vlc_input.h>
33 #include <vlc_demux.h>
34 #include <vlc_plugin.h>
38 static int Open (vlc_object_t
*);
39 static void Close (vlc_object_t
*);
43 set_description ("Game Music Emu")
44 set_category (CAT_INPUT
)
45 set_subcategory (SUBCAT_INPUT_DEMUX
)
46 set_capability ("demux", 10)
47 set_callbacks (Open
, Close
)
60 input_title_t
**titlev
;
65 static int Demux (demux_t
*);
66 static int Control (demux_t
*, int, va_list);
67 static gme_err_t
ReaderStream (void *, void *, int);
68 static gme_err_t
ReaderBlock (void *, void *, int);
70 static int Open (vlc_object_t
*obj
)
72 demux_t
*demux
= (demux_t
*)obj
;
75 if (vlc_stream_GetSize(demux
->s
, &size
))
77 if (size
> LONG_MAX
/* too big for GME */)
82 if (vlc_stream_Peek (demux
->s
, &peek
, 4) < 4)
85 const char *type
= gme_identify_header (peek
);
88 msg_Dbg (obj
, "detected file type %s", type
);
93 data
= vlc_stream_Block (demux
->s
, 1 << 24);
99 demux_sys_t
*sys
= malloc (sizeof (*sys
));
100 if (unlikely(sys
== NULL
))
103 sys
->emu
= gme_new_emu (gme_identify_extension (type
), RATE
);
104 if (sys
->emu
== NULL
)
111 gme_load_custom (sys
->emu
, ReaderBlock
, data
->i_buffer
, data
);
116 gme_load_custom (sys
->emu
, ReaderStream
, size
, demux
->s
);
118 gme_start_track (sys
->emu
, sys
->track_id
= 0);
121 es_format_Init (&fmt
, AUDIO_ES
, VLC_CODEC_S16N
);
122 fmt
.audio
.i_rate
= RATE
;
123 fmt
.audio
.i_bytes_per_frame
= 4;
124 fmt
.audio
.i_frame_length
= 4;
125 fmt
.audio
.i_channels
= 2;
126 fmt
.audio
.i_blockalign
= 4;
127 fmt
.audio
.i_bitspersample
= 16;
128 fmt
.i_bitrate
= RATE
* 4;
130 sys
->es
= es_out_Add (demux
->out
, &fmt
);
131 date_Init (&sys
->pts
, RATE
, 1);
132 date_Set (&sys
->pts
, 0);
135 unsigned n
= gme_track_count (sys
->emu
);
136 sys
->titlev
= vlc_alloc (n
, sizeof (*sys
->titlev
));
137 if (unlikely(sys
->titlev
== NULL
))
140 for (unsigned i
= 0; i
< n
; i
++)
142 input_title_t
*title
= vlc_input_title_New ();
143 sys
->titlev
[i
] = title
;
144 if (unlikely(title
== NULL
))
148 if (gme_track_info (sys
->emu
, &infos
, i
))
150 msg_Dbg (obj
, "track %u: %s %d ms", i
, infos
->song
, infos
->length
);
151 if (infos
->length
!= -1)
152 title
->i_length
= infos
->length
* INT64_C(1000);
154 title
->psz_name
= strdup (infos
->song
);
155 gme_free_info (infos
);
159 demux
->pf_demux
= Demux
;
160 demux
->pf_control
= Control
;
166 static void Close (vlc_object_t
*obj
)
168 demux_t
*demux
= (demux_t
*)obj
;
169 demux_sys_t
*sys
= demux
->p_sys
;
171 for (unsigned i
= 0, n
= sys
->titlec
; i
< n
; i
++)
172 vlc_input_title_Delete (sys
->titlev
[i
]);
174 gme_delete (sys
->emu
);
179 static gme_err_t
ReaderStream (void *data
, void *buf
, int length
)
183 if (vlc_stream_Read (s
, buf
, length
) < length
)
187 static gme_err_t
ReaderBlock (void *data
, void *buf
, int length
)
189 block_t
*block
= data
;
191 int max
= __MIN (length
, (int)block
->i_buffer
);
192 memcpy (buf
, block
->p_buffer
, max
);
193 block
->i_buffer
-= max
;
194 block
->p_buffer
+= max
;
200 #define SAMPLES (RATE / 10)
202 static int Demux (demux_t
*demux
)
204 demux_sys_t
*sys
= demux
->p_sys
;
207 if (gme_track_ended (sys
->emu
))
209 msg_Dbg (demux
, "track %u ended", sys
->track_id
);
210 if (++sys
->track_id
>= (unsigned)gme_track_count (sys
->emu
))
213 demux
->info
.i_update
|= INPUT_UPDATE_TITLE
;
214 gme_start_track (sys
->emu
, sys
->track_id
);
218 block_t
*block
= block_Alloc (2 * 2 * SAMPLES
);
219 if (unlikely(block
== NULL
))
222 gme_err_t ret
= gme_play (sys
->emu
, 2 * SAMPLES
, (void *)block
->p_buffer
);
225 block_Release (block
);
226 msg_Err (demux
, "%s", ret
);
230 block
->i_pts
= block
->i_dts
= VLC_TS_0
+ date_Get (&sys
->pts
);
231 es_out_SetPCR (demux
->out
, block
->i_pts
);
232 es_out_Send (demux
->out
, sys
->es
, block
);
233 date_Increment (&sys
->pts
, SAMPLES
);
238 static int Control (demux_t
*demux
, int query
, va_list args
)
240 demux_sys_t
*sys
= demux
->p_sys
;
245 *va_arg (args
, bool *) = true;
248 case DEMUX_GET_POSITION
:
250 double *pos
= va_arg (args
, double *);
252 if (unlikely(sys
->track_id
>= sys
->titlec
)
253 || (sys
->titlev
[sys
->track_id
]->i_length
== 0))
257 int offset
= gme_tell (sys
->emu
);
259 *pos
= (double)offset
260 / (double)(sys
->titlev
[sys
->track_id
]->i_length
/ 1000);
265 case DEMUX_SET_POSITION
:
267 double pos
= va_arg (args
, double);
269 if (unlikely(sys
->track_id
>= sys
->titlec
)
270 || (sys
->titlev
[sys
->track_id
]->i_length
== 0))
273 int seek
= (sys
->titlev
[sys
->track_id
]->i_length
/ 1000) * pos
;
274 if (gme_seek (sys
->emu
, seek
))
279 case DEMUX_GET_LENGTH
:
281 int64_t *v
= va_arg (args
, int64_t *);
283 if (unlikely(sys
->track_id
>= sys
->titlec
)
284 || (sys
->titlev
[sys
->track_id
]->i_length
== 0))
286 *v
= sys
->titlev
[sys
->track_id
]->i_length
;
292 int64_t *v
= va_arg (args
, int64_t *);
293 *v
= gme_tell (sys
->emu
) * INT64_C(1000);
299 int64_t v
= va_arg (args
, int64_t) / 1000;
300 if (v
> INT_MAX
|| gme_seek (sys
->emu
, v
))
305 case DEMUX_GET_TITLE_INFO
:
307 input_title_t
***titlev
= va_arg (args
, input_title_t
***);
308 int *titlec
= va_arg (args
, int *);
309 *(va_arg (args
, int *)) = 0; /* Title offset */
310 *(va_arg (args
, int *)) = 0; /* Chapter offset */
312 unsigned n
= sys
->titlec
;
313 *titlev
= vlc_alloc (n
, sizeof (**titlev
));
314 if (unlikely(*titlev
== NULL
))
317 for (unsigned i
= 0; i
< n
; i
++)
318 (*titlev
)[i
] = vlc_input_title_Duplicate (sys
->titlev
[i
]);
322 case DEMUX_SET_TITLE
:
324 int track_id
= va_arg (args
, int);
325 if (track_id
>= gme_track_count (sys
->emu
))
327 gme_start_track (sys
->emu
, track_id
);
328 demux
->info
.i_update
|= INPUT_UPDATE_TITLE
;
329 sys
->track_id
= track_id
;
333 case DEMUX_GET_TITLE
:
334 *va_arg(args
, int *) = sys
->track_id
;