4 uint32_t get_frame_duration (struct player_data
*pd
, struct cdxl_frame
*frame
);
5 void start_timer (struct player_data
*pd
);
6 void start_audio (struct player_data
*pd
);
7 void stop_timer (struct player_data
*pd
);
8 void stop_audio (struct player_data
*pd
);
9 struct cdxl_frame
*get_next_frame(struct list
*list
, struct cdxl_frame
*frame
, int loop
);
10 void audio_callback (void *userdata
, uint8_t *stream
, int len
);
11 uint32_t timer_callback (uint32_t interval
, void *param
);
12 int do_cdxl_frame (struct player_data
*pd
);
13 int do_cdxl_audio (struct player_data
*pd
);
14 int decode_cdxl_audio (struct cdxl_file
*cdxl
, struct cdxl_frame
*frame
, int8_t **pcm
, int *alen
);
16 int main (int argc
, char *argv
[]) {
17 struct player_data pd
;
22 SDL_AudioSpec desired
;
25 int x_factor
, y_factor
;
26 int min_width
, min_height
;
28 memset(&pd
, 0, sizeof(pd
));
29 pd
.sdl_video_flags
= SDL_ANYFORMAT
|SDL_RESIZABLE
|SDL_OPENGL
;
30 init_list(&pd
.audio_list
);
36 pd
.pixel_ratio
= 0x10000;
38 if (!get_options(argc
, argv
, &pd
)) {
42 pd
.cdxl
= open_cdxl(pd
.filename
);
47 if (!setup_usleep()) {
51 if (SDL_Init(SDL_INIT_TIMER
|SDL_INIT_VIDEO
|SDL_INIT_AUDIO
) == -1) {
52 fprintf(stderr
, "Unable to init SDL: %s\n", SDL_GetError());
57 pd
.frame
= (struct cdxl_frame
*)pd
.cdxl
->list
.head
;
58 if (pd
.pixel_ratio
< 0x10000UL
) {
60 y_factor
= 0x10000UL
/ pd
.pixel_ratio
;
62 x_factor
= pd
.pixel_ratio
/ 0x10000UL
;
65 min_width
= pd
.frame
->pan
.XSize
* x_factor
;
66 min_height
= pd
.frame
->pan
.YSize
* y_factor
;
68 pd
.width
= MAX(pd
.width
, min_width
);
69 pd
.height
= MAX(pd
.height
, min_height
);
70 pd
.screen
= SDL_SetVideoMode(pd
.width
, pd
.height
, 32, pd
.sdl_video_flags
);
71 #ifdef WORDS_BIGENDIAN
72 pd
.surf
= SDL_CreateRGBSurface(SDL_SWSURFACE
,
73 pd
.frame
->pan
.XSize
, pd
.frame
->pan
.YSize
, 32,
74 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
76 pd
.surf
= SDL_CreateRGBSurface(SDL_SWSURFACE
,
77 pd
.frame
->pan
.XSize
, pd
.frame
->pan
.YSize
, 32,
78 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
80 if (!pd
.screen
|| !pd
.surf
) {
81 fprintf(stderr
, "Video initialization failed: %s\n", SDL_GetError());
85 SDL_WM_SetCaption(PROGNAME
" "VSTRING
, PROGNAME
);
87 SDL_ShowCursor((pd
.sdl_video_flags
& SDL_FULLSCREEN
) ? SDL_DISABLE
: SDL_ENABLE
);
89 GLInit(pd
.width
, pd
.height
);
92 pd
.audio_mutex
= SDL_CreateMutex();
93 pd
.audio_cond
= SDL_CreateCond();
95 if (!pd
.audio_mutex
|| !pd
.audio_cond
) {
99 memset(&desired
, 0, sizeof(desired
));
100 desired
.freq
= pd
.freq
;
101 desired
.format
= AUDIO_S8
;
102 desired
.channels
= 2;
103 desired
.samples
= 1024;
104 desired
.callback
= audio_callback
;
105 desired
.userdata
= &pd
;
106 if (SDL_OpenAudio(&desired
, NULL
) == -1) {
107 fprintf(stderr
, "Audio initialization failed: %s\n", SDL_GetError());
113 gettimeofday(&pd
.tv
, NULL
);
118 if (SDL_WaitEvent(&event
)) {
119 switch (event
.type
) {
121 if (pd
.status
!= PLAYING
) {
124 free_cdxl_frame(pd
.cdxl
, pd
.frame
);
125 t2
= pd
.tv
.tv_sec
* 1000000ULL + pd
.tv
.tv_usec
;
126 gettimeofday(&pd
.tv
, NULL
);
127 t1
= pd
.tv
.tv_sec
* 1000000ULL + pd
.tv
.tv_usec
;
128 t2
+= get_frame_duration(&pd
, pd
.frame
);
132 pd
.tv
.tv_sec
= t2
/ 1000000ULL;
133 pd
.tv
.tv_usec
= t2
% 1000000ULL;
134 pd
.frame
= get_next_frame(&pd
.cdxl
->list
, pd
.frame
, pd
.loop
);
141 if (pd
.cdxl
->has_audio
) {
142 pd
.aframe
= get_next_frame(&pd
.cdxl
->list
, pd
.aframe
, pd
.loop
);
150 switch (event
.key
.keysym
.sym
) {
156 if (pd
.status
== PLAYING
) {
162 gettimeofday(&pd
.tv
, NULL
);
176 case SDL_VIDEORESIZE
:
179 pd
.width
= MAX(event
.resize
.w
, min_width
);
180 pd
.height
= MAX(event
.resize
.h
, min_height
);
181 pd
.screen
= SDL_SetVideoMode(pd
.width
, pd
.height
, 32, pd
.sdl_video_flags
);
183 fprintf(stderr
, "Resize failed: %s\n", SDL_GetError());
186 GLInit(pd
.width
, pd
.height
);
199 if (pd
.audio_cond
) SDL_DestroyCond(pd
.audio_cond
);
200 if (pd
.audio_mutex
) SDL_DestroyMutex(pd
.audio_mutex
);
201 if (gl_init
) GLExit();
202 if (pd
.surf
) SDL_FreeSurface(pd
.surf
);
203 if (sdl_init
) SDL_Quit();
205 if (pd
.cdxl
) close_cdxl(pd
.cdxl
);
210 uint32_t get_frame_duration (struct player_data
*pd
, struct cdxl_frame
*frame
) {
215 if (frame
->audio_size
> 0) {
216 uint32_t audio_size
= frame
->audio_size
;
217 if (frame
->is_stereo
) audio_size
>>= 1;
218 usec
= audio_size
* 1000000UL / pd
->freq
;
220 usec
= 1000000UL / pd
->fps
;
225 void start_timer(struct player_data
*pd
) {
226 struct cdxl_frame
*frame
= pd
->frame
;
228 frame_ms
= (get_frame_duration(pd
, frame
) / 10000) * 10;
229 pd
->timer_id
= SDL_AddTimer(frame_ms
, timer_callback
, pd
);
232 void start_audio(struct player_data
*pd
) {
234 if (!pd
->cdxl
->has_audio
) {
237 pd
->aframe
= pd
->frame
;
239 for (i
= 0; i
< pd
->aprebuf
; i
++) {
240 pd
->aframe
= get_next_frame(&pd
->cdxl
->list
, pd
->aframe
, pd
->loop
);
246 pd
->audio_enable
= 1;
250 void stop_timer(struct player_data
*pd
) {
252 SDL_RemoveTimer(pd
->timer_id
);
257 void stop_audio(struct player_data
*pd
) {
258 if (!pd
->cdxl
->has_audio
) {
261 if (pd
->audio_enable
) {
262 struct audio_node
*anode
;
263 SDL_LockMutex(pd
->audio_mutex
);
264 while ((anode
= (struct audio_node
*)rem_head(&pd
->audio_list
))) {
265 if (anode
->pcm
) free(anode
->pcm
);
268 pd
->audio_enable
= 0;
269 SDL_CondSignal(pd
->audio_cond
);
270 SDL_UnlockMutex(pd
->audio_mutex
);
275 struct cdxl_frame
*get_next_frame(struct list
*list
, struct cdxl_frame
*frame
, int loop
) {
279 frame
= (struct cdxl_frame
*)frame
->node
.succ
;
280 if (frame
->node
.succ
) {
283 return (struct cdxl_frame
*)list
->head
;
289 void audio_callback (void *userdata
, uint8_t *stream
, int len
) {
290 struct player_data
*pd
= userdata
;
291 struct audio_node
*anode
, *next
;
292 const int8_t *source
;
293 int8_t *dest
= stream
;
299 if (!pd
->audio_enable
) {
300 memset(dest
, 0, len
);
303 SDL_LockMutex(pd
->audio_mutex
);
304 anode
= (struct audio_node
*)pd
->audio_list
.head
;
305 while (anode
->node
.succ
) {
306 next
= (struct audio_node
*)anode
->node
.succ
;
308 source
= anode
->pcm
+ anode
->apos
;
309 alen
= anode
->alen
- anode
->apos
;
310 if (alen
> len
) alen
= len
;
312 memcpy(dest
, source
, alen
);
314 memset(dest
, 0, alen
);
318 if (anode
->apos
== anode
->alen
) {
319 rem_node(&anode
->node
);
320 if (anode
->pcm
) free(anode
->pcm
);
324 SDL_UnlockMutex(pd
->audio_mutex
);
330 SDL_CondWait(pd
->audio_cond
, pd
->audio_mutex
);
331 SDL_UnlockMutex(pd
->audio_mutex
);
335 uint32_t timer_callback (uint32_t interval
, void *param
) {
336 struct player_data
*pd
= param
;
337 struct cdxl_frame
*frame
;
341 frame
= get_next_frame(&pd
->cdxl
->list
, pd
->frame
, pd
->loop
);
342 frame_ms
= (get_frame_duration(pd
, frame
) / 10000) * 10;
344 event
.type
= SDL_USEREVENT
;
346 event
.user
.data1
= NULL
;
347 event
.user
.data2
= NULL
;
348 SDL_PushEvent(&event
);
353 int do_cdxl_frame (struct player_data
*pd
) {
354 struct cdxl_frame
*frame
= pd
->frame
;
355 if (read_cdxl_frame(pd
->cdxl
, frame
) == -1) {
358 if (decode_cdxl_frame(pd
->cdxl
, frame
, pd
->surf
) == -1) {
361 GLScaleSurface(pd
->surf
, pd
->screen
, pd
->pixel_ratio
);
362 SDL_GL_SwapBuffers();
366 int do_cdxl_audio (struct player_data
*pd
) {
367 struct cdxl_frame
*frame
= pd
->aframe
;
368 if (!pd
->cdxl
->has_audio
) {
371 if (read_cdxl_frame(pd
->cdxl
, frame
) == -1) {
374 if (frame
->audio_size
> 0) {
375 struct audio_node
*anode
;
376 anode
= malloc(sizeof(*anode
));
380 if (decode_cdxl_audio(pd
->cdxl
, frame
, &anode
->pcm
, &anode
->alen
)) {
384 anode
->frame
= frame
->index
;
386 SDL_LockMutex(pd
->audio_mutex
);
387 add_tail(&pd
->audio_list
, &anode
->node
);
388 SDL_CondSignal(pd
->audio_cond
);
389 SDL_UnlockMutex(pd
->audio_mutex
);
392 struct audio_node
*anode
;
393 anode
= malloc(sizeof(*anode
));
398 anode
->alen
= pd
->freq
/ pd
->fps
;
399 if (frame
->is_stereo
) {
402 SDL_LockMutex(pd
->audio_mutex
);
403 add_tail(&pd
->audio_list
, &anode
->node
);
404 SDL_CondSignal(pd
->audio_cond
);
405 SDL_UnlockMutex(pd
->audio_mutex
);
410 int decode_cdxl_audio (struct cdxl_file
*cdxl
, struct cdxl_frame
*frame
, int8_t **pcm
, int *alen
) {
411 if (cdxl
&& frame
&& frame
->buffer
) {
413 const int8_t *src_l
= (int8_t *)frame
->buffer
+ frame
->cmap_size
+ frame
->video_size
;
414 const int8_t *src_r
= src_l
;
416 len
= samples
= frame
->audio_size
;
417 if (frame
->is_stereo
) {
433 for (i
= 0; i
< samples
; i
++) {