vhook watermark patch by (Marcus Engene: ffmpeg, engene se)
[libav.git] / ffplay.c
CommitLineData
01310af2
FB
1/*
2 * FFplay : Simple Media Player based on the ffmpeg libraries
3 * Copyright (c) 2003 Fabrice Bellard
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#define HAVE_AV_CONFIG_H
01310af2
FB
20#include "avformat.h"
21
22#include "cmdutils.h"
23
24#include <SDL.h>
25#include <SDL_thread.h>
26
31319a8c
FB
27#ifdef CONFIG_WIN32
28#undef main /* We don't want SDL to override our main() */
29#endif
30
3ca4b654
MN
31#ifdef CONFIG_OS2
32#define INCL_DOS
33 #include <os2.h>
34 #include <stdio.h>
35
36 void MorphToPM()
37 {
38 PPIB pib;
39 PTIB tib;
40
41 DosGetInfoBlocks(&tib, &pib);
42
43 // Change flag from VIO to PM:
44 if (pib->pib_ultype==2) pib->pib_ultype = 3;
45 }
46#endif
47
01310af2
FB
48#if defined(__linux__)
49#define HAVE_X11
50#endif
51
52#ifdef HAVE_X11
53#include <X11/Xlib.h>
54#endif
55
638c9d91
FB
56//#define DEBUG_SYNC
57
01310af2
FB
58#define MAX_VIDEOQ_SIZE (5 * 256 * 1024)
59#define MAX_AUDIOQ_SIZE (5 * 16 * 1024)
60
638c9d91
FB
61/* SDL audio buffer size, in samples. Should be small to have precise
62 A/V sync as SDL does not have hardware buffer fullness info. */
63#define SDL_AUDIO_BUFFER_SIZE 1024
64
65/* no AV sync correction is done if below the AV sync threshold */
7e0140cb 66#define AV_SYNC_THRESHOLD 0.01
638c9d91
FB
67/* no AV correction is done if too big error */
68#define AV_NOSYNC_THRESHOLD 10.0
69
70/* maximum audio speed change to get correct sync */
71#define SAMPLE_CORRECTION_PERCENT_MAX 10
72
73/* we use about AUDIO_DIFF_AVG_NB A-V differences to make the average */
74#define AUDIO_DIFF_AVG_NB 20
75
01310af2
FB
76/* NOTE: the size must be big enough to compensate the hardware audio buffersize size */
77#define SAMPLE_ARRAY_SIZE (2*65536)
78
79typedef struct PacketQueue {
80 AVPacketList *first_pkt, *last_pkt;
81 int nb_packets;
82 int size;
83 int abort_request;
84 SDL_mutex *mutex;
85 SDL_cond *cond;
86} PacketQueue;
87
88#define VIDEO_PICTURE_QUEUE_SIZE 1
89
90typedef struct VideoPicture {
638c9d91 91 double pts; /* presentation time stamp for this picture */
01310af2
FB
92 SDL_Overlay *bmp;
93 int width, height; /* source height & width */
94 int allocated;
95} VideoPicture;
96
97enum {
98 AV_SYNC_AUDIO_MASTER, /* default choice */
99 AV_SYNC_VIDEO_MASTER,
638c9d91 100 AV_SYNC_EXTERNAL_CLOCK, /* synchronize to an external clock */
01310af2
FB
101};
102
103typedef struct VideoState {
104 SDL_Thread *parse_tid;
105 SDL_Thread *video_tid;
638c9d91 106 AVInputFormat *iformat;
01310af2
FB
107 int no_background;
108 int abort_request;
109 int paused;
416e3508 110 int last_paused;
72ea344b 111 int seek_req;
3ba1438d 112 int seek_flags;
72ea344b 113 int64_t seek_pos;
01310af2
FB
114 AVFormatContext *ic;
115 int dtg_active_format;
116
117 int audio_stream;
118
119 int av_sync_type;
638c9d91
FB
120 double external_clock; /* external clock base */
121 int64_t external_clock_time;
122
123 double audio_clock;
124 double audio_diff_cum; /* used for AV difference average computation */
125 double audio_diff_avg_coef;
126 double audio_diff_threshold;
127 int audio_diff_avg_count;
01310af2
FB
128 AVStream *audio_st;
129 PacketQueue audioq;
130 int audio_hw_buf_size;
131 /* samples output by the codec. we reserve more space for avsync
132 compensation */
133 uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
7fea94ce 134 unsigned int audio_buf_size; /* in bytes */
01310af2
FB
135 int audio_buf_index; /* in bytes */
136 AVPacket audio_pkt;
137 uint8_t *audio_pkt_data;
138 int audio_pkt_size;
01310af2
FB
139
140 int show_audio; /* if true, display audio samples */
141 int16_t sample_array[SAMPLE_ARRAY_SIZE];
142 int sample_array_index;
5e0257e3 143 int last_i_start;
01310af2 144
638c9d91
FB
145 double frame_timer;
146 double frame_last_pts;
147 double frame_last_delay;
148 double video_clock;
01310af2
FB
149 int video_stream;
150 AVStream *video_st;
151 PacketQueue videoq;
638c9d91
FB
152 double video_last_P_pts; /* pts of the last P picture (needed if B
153 frames are present) */
154 double video_current_pts; /* current displayed pts (different from
155 video_clock if frame fifos are used) */
156 int64_t video_current_pts_time; /* time at which we updated
157 video_current_pts - used to
158 have running video pts */
01310af2
FB
159 VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE];
160 int pictq_size, pictq_rindex, pictq_windex;
161 SDL_mutex *pictq_mutex;
162 SDL_cond *pictq_cond;
163
b514ed3c
MN
164 SDL_mutex *video_decoder_mutex;
165 SDL_mutex *audio_decoder_mutex;
166
01310af2
FB
167 // QETimer *video_timer;
168 char filename[1024];
169 int width, height, xleft, ytop;
170} VideoState;
171
172void show_help(void);
638c9d91 173static int audio_write_get_buf_size(VideoState *is);
01310af2
FB
174
175/* options specified by the user */
176static AVInputFormat *file_iformat;
61890b02 177static AVImageFormat *image_format;
01310af2
FB
178static const char *input_filename;
179static int fs_screen_width;
180static int fs_screen_height;
181static int screen_width = 640;
182static int screen_height = 480;
183static int audio_disable;
184static int video_disable;
185static int display_disable;
186static int show_status;
638c9d91 187static int av_sync_type = AV_SYNC_AUDIO_MASTER;
72ea344b 188static int64_t start_time = AV_NOPTS_VALUE;
e26a8335 189static int debug = 0;
0c9bbaec 190static int debug_mv = 0;
bba04f1e 191static int step = 0;
c62c07d3 192static int thread_count = 1;
6387c3e6 193static int workaround_bugs = 1;
6fc5b059 194static int fast = 0;
178fcca8
MN
195static int lowres = 0;
196static int idct = FF_IDCT_AUTO;
01310af2
FB
197
198/* current context */
199static int is_full_screen;
200static VideoState *cur_stream;
5e0257e3 201static int64_t audio_callback_time;
01310af2
FB
202
203#define FF_ALLOC_EVENT (SDL_USEREVENT)
204#define FF_REFRESH_EVENT (SDL_USEREVENT + 1)
638c9d91 205#define FF_QUIT_EVENT (SDL_USEREVENT + 2)
01310af2
FB
206
207SDL_Surface *screen;
208
209/* packet queue handling */
210static void packet_queue_init(PacketQueue *q)
211{
212 memset(q, 0, sizeof(PacketQueue));
213 q->mutex = SDL_CreateMutex();
214 q->cond = SDL_CreateCond();
215}
216
72ea344b 217static void packet_queue_flush(PacketQueue *q)
01310af2
FB
218{
219 AVPacketList *pkt, *pkt1;
220
221 for(pkt = q->first_pkt; pkt != NULL; pkt = pkt1) {
222 pkt1 = pkt->next;
223 av_free_packet(&pkt->pkt);
da6c4573 224 av_freep(&pkt);
01310af2 225 }
72ea344b
FB
226 q->last_pkt = NULL;
227 q->first_pkt = NULL;
228 q->nb_packets = 0;
229 q->size = 0;
230}
231
232static void packet_queue_end(PacketQueue *q)
233{
234 packet_queue_flush(q);
01310af2
FB
235 SDL_DestroyMutex(q->mutex);
236 SDL_DestroyCond(q->cond);
237}
238
239static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
240{
241 AVPacketList *pkt1;
242
72ea344b
FB
243 /* duplicate the packet */
244 if (av_dup_packet(pkt) < 0)
245 return -1;
246
01310af2
FB
247 pkt1 = av_malloc(sizeof(AVPacketList));
248 if (!pkt1)
249 return -1;
250 pkt1->pkt = *pkt;
251 pkt1->next = NULL;
252
72ea344b 253
01310af2
FB
254 SDL_LockMutex(q->mutex);
255
256 if (!q->last_pkt)
257
258 q->first_pkt = pkt1;
259 else
260 q->last_pkt->next = pkt1;
261 q->last_pkt = pkt1;
262 q->nb_packets++;
263 q->size += pkt1->pkt.size;
264 /* XXX: should duplicate packet data in DV case */
265 SDL_CondSignal(q->cond);
266
267 SDL_UnlockMutex(q->mutex);
268 return 0;
269}
270
271static void packet_queue_abort(PacketQueue *q)
272{
273 SDL_LockMutex(q->mutex);
274
275 q->abort_request = 1;
276
277 SDL_CondSignal(q->cond);
278
279 SDL_UnlockMutex(q->mutex);
280}
281
282/* return < 0 if aborted, 0 if no packet and > 0 if packet. */
283static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
284{
285 AVPacketList *pkt1;
286 int ret;
287
288 SDL_LockMutex(q->mutex);
289
290 for(;;) {
291 if (q->abort_request) {
292 ret = -1;
293 break;
294 }
295
296 pkt1 = q->first_pkt;
297 if (pkt1) {
298 q->first_pkt = pkt1->next;
299 if (!q->first_pkt)
300 q->last_pkt = NULL;
301 q->nb_packets--;
302 q->size -= pkt1->pkt.size;
303 *pkt = pkt1->pkt;
304 av_free(pkt1);
305 ret = 1;
306 break;
307 } else if (!block) {
308 ret = 0;
309 break;
310 } else {
311 SDL_CondWait(q->cond, q->mutex);
312 }
313 }
314 SDL_UnlockMutex(q->mutex);
315 return ret;
316}
317
318static inline void fill_rectangle(SDL_Surface *screen,
319 int x, int y, int w, int h, int color)
320{
321 SDL_Rect rect;
322 rect.x = x;
323 rect.y = y;
324 rect.w = w;
325 rect.h = h;
326 SDL_FillRect(screen, &rect, color);
327}
328
329#if 0
330/* draw only the border of a rectangle */
331void fill_border(VideoState *s, int x, int y, int w, int h, int color)
332{
333 int w1, w2, h1, h2;
334
335 /* fill the background */
336 w1 = x;
337 if (w1 < 0)
338 w1 = 0;
339 w2 = s->width - (x + w);
340 if (w2 < 0)
341 w2 = 0;
342 h1 = y;
343 if (h1 < 0)
344 h1 = 0;
345 h2 = s->height - (y + h);
346 if (h2 < 0)
347 h2 = 0;
348 fill_rectangle(screen,
349 s->xleft, s->ytop,
350 w1, s->height,
351 color);
352 fill_rectangle(screen,
353 s->xleft + s->width - w2, s->ytop,
354 w2, s->height,
355 color);
356 fill_rectangle(screen,
357 s->xleft + w1, s->ytop,
358 s->width - w1 - w2, h1,
359 color);
360 fill_rectangle(screen,
361 s->xleft + w1, s->ytop + s->height - h2,
362 s->width - w1 - w2, h2,
363 color);
364}
365#endif
366
367static void video_image_display(VideoState *is)
368{
369 VideoPicture *vp;
370 float aspect_ratio;
371 int width, height, x, y;
372 SDL_Rect rect;
373
374 vp = &is->pictq[is->pictq_rindex];
375 if (vp->bmp) {
376 /* XXX: use variable in the frame */
72ea344b
FB
377 if (is->video_st->codec.sample_aspect_ratio.num == 0)
378 aspect_ratio = 0;
379 else
380 aspect_ratio = av_q2d(is->video_st->codec.sample_aspect_ratio)
381 * is->video_st->codec.width / is->video_st->codec.height;;
01310af2
FB
382 if (aspect_ratio <= 0.0)
383 aspect_ratio = (float)is->video_st->codec.width /
384 (float)is->video_st->codec.height;
385 /* if an active format is indicated, then it overrides the
386 mpeg format */
387#if 0
388 if (is->video_st->codec.dtg_active_format != is->dtg_active_format) {
389 is->dtg_active_format = is->video_st->codec.dtg_active_format;
390 printf("dtg_active_format=%d\n", is->dtg_active_format);
391 }
392#endif
393#if 0
394 switch(is->video_st->codec.dtg_active_format) {
395 case FF_DTG_AFD_SAME:
396 default:
397 /* nothing to do */
398 break;
399 case FF_DTG_AFD_4_3:
400 aspect_ratio = 4.0 / 3.0;
401 break;
402 case FF_DTG_AFD_16_9:
403 aspect_ratio = 16.0 / 9.0;
404 break;
405 case FF_DTG_AFD_14_9:
406 aspect_ratio = 14.0 / 9.0;
407 break;
408 case FF_DTG_AFD_4_3_SP_14_9:
409 aspect_ratio = 14.0 / 9.0;
410 break;
411 case FF_DTG_AFD_16_9_SP_14_9:
412 aspect_ratio = 14.0 / 9.0;
413 break;
414 case FF_DTG_AFD_SP_4_3:
415 aspect_ratio = 4.0 / 3.0;
416 break;
417 }
418#endif
419
420 /* XXX: we suppose the screen has a 1.0 pixel ratio */
421 height = is->height;
422 width = ((int)rint(height * aspect_ratio)) & -3;
423 if (width > is->width) {
424 width = is->width;
425 height = ((int)rint(width / aspect_ratio)) & -3;
426 }
427 x = (is->width - width) / 2;
428 y = (is->height - height) / 2;
429 if (!is->no_background) {
430 /* fill the background */
431 // fill_border(is, x, y, width, height, QERGB(0x00, 0x00, 0x00));
432 } else {
433 is->no_background = 0;
434 }
435 rect.x = is->xleft + x;
436 rect.y = is->xleft + y;
437 rect.w = width;
438 rect.h = height;
439 SDL_DisplayYUVOverlay(vp->bmp, &rect);
440 } else {
441#if 0
442 fill_rectangle(screen,
443 is->xleft, is->ytop, is->width, is->height,
444 QERGB(0x00, 0x00, 0x00));
445#endif
446 }
447}
448
449static inline int compute_mod(int a, int b)
450{
451 a = a % b;
452 if (a >= 0)
453 return a;
454 else
455 return a + b;
456}
457
458static void video_audio_display(VideoState *s)
459{
460 int i, i_start, x, y1, y, ys, delay, n, nb_display_channels;
461 int ch, channels, h, h2, bgcolor, fgcolor;
462 int16_t time_diff;
463
464 /* compute display index : center on currently output samples */
465 channels = s->audio_st->codec.channels;
466 nb_display_channels = channels;
5e0257e3
FB
467 if (!s->paused) {
468 n = 2 * channels;
469 delay = audio_write_get_buf_size(s);
470 delay /= n;
471
472 /* to be more precise, we take into account the time spent since
473 the last buffer computation */
474 if (audio_callback_time) {
475 time_diff = av_gettime() - audio_callback_time;
476 delay += (time_diff * s->audio_st->codec.sample_rate) / 1000000;
477 }
478
479 delay -= s->width / 2;
480 if (delay < s->width)
481 delay = s->width;
482 i_start = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE);
483 s->last_i_start = i_start;
484 } else {
485 i_start = s->last_i_start;
01310af2
FB
486 }
487
01310af2
FB
488 bgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
489 fill_rectangle(screen,
490 s->xleft, s->ytop, s->width, s->height,
491 bgcolor);
492
493 fgcolor = SDL_MapRGB(screen->format, 0xff, 0xff, 0xff);
494
495 /* total height for one channel */
496 h = s->height / nb_display_channels;
497 /* graph height / 2 */
498 h2 = (h * 9) / 20;
499 for(ch = 0;ch < nb_display_channels; ch++) {
500 i = i_start + ch;
501 y1 = s->ytop + ch * h + (h / 2); /* position of center line */
502 for(x = 0; x < s->width; x++) {
503 y = (s->sample_array[i] * h2) >> 15;
504 if (y < 0) {
505 y = -y;
506 ys = y1 - y;
507 } else {
508 ys = y1;
509 }
510 fill_rectangle(screen,
511 s->xleft + x, ys, 1, y,
512 fgcolor);
513 i += channels;
514 if (i >= SAMPLE_ARRAY_SIZE)
515 i -= SAMPLE_ARRAY_SIZE;
516 }
517 }
518
519 fgcolor = SDL_MapRGB(screen->format, 0x00, 0x00, 0xff);
520
521 for(ch = 1;ch < nb_display_channels; ch++) {
522 y = s->ytop + ch * h;
523 fill_rectangle(screen,
524 s->xleft, y, s->width, 1,
525 fgcolor);
526 }
527 SDL_UpdateRect(screen, s->xleft, s->ytop, s->width, s->height);
528}
529
530/* display the current picture, if any */
531static void video_display(VideoState *is)
532{
533 if (is->audio_st && is->show_audio)
534 video_audio_display(is);
535 else if (is->video_st)
536 video_image_display(is);
537}
538
539static Uint32 sdl_refresh_timer_cb(Uint32 interval, void *opaque)
540{
541 SDL_Event event;
542 event.type = FF_REFRESH_EVENT;
543 event.user.data1 = opaque;
544 SDL_PushEvent(&event);
545 return 0; /* 0 means stop timer */
546}
547
548/* schedule a video refresh in 'delay' ms */
549static void schedule_refresh(VideoState *is, int delay)
550{
551 SDL_AddTimer(delay, sdl_refresh_timer_cb, is);
552}
553
638c9d91
FB
554/* get the current audio clock value */
555static double get_audio_clock(VideoState *is)
556{
557 double pts;
558 int hw_buf_size, bytes_per_sec;
559 pts = is->audio_clock;
560 hw_buf_size = audio_write_get_buf_size(is);
561 bytes_per_sec = 0;
562 if (is->audio_st) {
563 bytes_per_sec = is->audio_st->codec.sample_rate *
564 2 * is->audio_st->codec.channels;
565 }
566 if (bytes_per_sec)
567 pts -= (double)hw_buf_size / bytes_per_sec;
568 return pts;
569}
570
571/* get the current video clock value */
572static double get_video_clock(VideoState *is)
573{
574 double delta;
04108619 575 if (is->paused) {
72ea344b
FB
576 delta = 0;
577 } else {
578 delta = (av_gettime() - is->video_current_pts_time) / 1000000.0;
579 }
638c9d91
FB
580 return is->video_current_pts + delta;
581}
582
583/* get the current external clock value */
584static double get_external_clock(VideoState *is)
585{
586 int64_t ti;
587 ti = av_gettime();
588 return is->external_clock + ((ti - is->external_clock_time) * 1e-6);
589}
590
591/* get the current master clock value */
592static double get_master_clock(VideoState *is)
593{
594 double val;
595
72ea344b
FB
596 if (is->av_sync_type == AV_SYNC_VIDEO_MASTER) {
597 if (is->video_st)
598 val = get_video_clock(is);
599 else
600 val = get_audio_clock(is);
601 } else if (is->av_sync_type == AV_SYNC_AUDIO_MASTER) {
602 if (is->audio_st)
603 val = get_audio_clock(is);
604 else
605 val = get_video_clock(is);
606 } else {
638c9d91 607 val = get_external_clock(is);
72ea344b 608 }
638c9d91
FB
609 return val;
610}
611
72ea344b 612/* seek in the stream */
3ba1438d 613static void stream_seek(VideoState *is, int64_t pos, int rel)
72ea344b
FB
614{
615 is->seek_pos = pos;
616 is->seek_req = 1;
3ba1438d 617 is->seek_flags = rel < 0 ? AVSEEK_FLAG_BACKWARD : 0;
72ea344b
FB
618}
619
620/* pause or resume the video */
621static void stream_pause(VideoState *is)
622{
623 is->paused = !is->paused;
624 if (is->paused) {
625 is->video_current_pts = get_video_clock(is);
626 }
627}
628
01310af2
FB
629/* called to display each frame */
630static void video_refresh_timer(void *opaque)
631{
632 VideoState *is = opaque;
633 VideoPicture *vp;
638c9d91
FB
634 double actual_delay, delay, sync_threshold, ref_clock, diff;
635
01310af2
FB
636
637 if (is->video_st) {
638 if (is->pictq_size == 0) {
639 /* if no picture, need to wait */
7e0140cb 640 schedule_refresh(is, 1);
01310af2 641 } else {
638c9d91 642 /* dequeue the picture */
01310af2 643 vp = &is->pictq[is->pictq_rindex];
638c9d91
FB
644
645 /* update current video pts */
646 is->video_current_pts = vp->pts;
647 is->video_current_pts_time = av_gettime();
648
649 /* compute nominal delay */
650 delay = vp->pts - is->frame_last_pts;
651 if (delay <= 0 || delay >= 1.0) {
652 /* if incorrect delay, use previous one */
653 delay = is->frame_last_delay;
654 }
655 is->frame_last_delay = delay;
656 is->frame_last_pts = vp->pts;
657
658 /* update delay to follow master synchronisation source */
659 if (((is->av_sync_type == AV_SYNC_AUDIO_MASTER && is->audio_st) ||
660 is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK)) {
661 /* if video is slave, we try to correct big delays by
662 duplicating or deleting a frame */
663 ref_clock = get_master_clock(is);
664 diff = vp->pts - ref_clock;
665
666 /* skip or repeat frame. We take into account the
667 delay to compute the threshold. I still don't know
668 if it is the best guess */
669 sync_threshold = AV_SYNC_THRESHOLD;
670 if (delay > sync_threshold)
671 sync_threshold = delay;
672 if (fabs(diff) < AV_NOSYNC_THRESHOLD) {
673 if (diff <= -sync_threshold)
674 delay = 0;
675 else if (diff >= sync_threshold)
676 delay = 2 * delay;
677 }
678 }
679
680 is->frame_timer += delay;
681 /* compute the REAL delay (we need to do that to avoid
682 long term errors */
683 actual_delay = is->frame_timer - (av_gettime() / 1000000.0);
684 if (actual_delay < 0.010) {
685 /* XXX: should skip picture */
686 actual_delay = 0.010;
687 }
01310af2 688 /* launch timer for next picture */
638c9d91
FB
689 schedule_refresh(is, (int)(actual_delay * 1000 + 0.5));
690
691#if defined(DEBUG_SYNC)
692 printf("video: delay=%0.3f actual_delay=%0.3f pts=%0.3f A-V=%f\n",
693 delay, actual_delay, vp->pts, -diff);
694#endif
01310af2
FB
695
696 /* display picture */
697 video_display(is);
698
699 /* update queue size and signal for next picture */
700 if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE)
701 is->pictq_rindex = 0;
702
703 SDL_LockMutex(is->pictq_mutex);
704 is->pictq_size--;
705 SDL_CondSignal(is->pictq_cond);
706 SDL_UnlockMutex(is->pictq_mutex);
707 }
708 } else if (is->audio_st) {
709 /* draw the next audio frame */
710
711 schedule_refresh(is, 40);
712
713 /* if only audio stream, then display the audio bars (better
714 than nothing, just to test the implementation */
715
716 /* display picture */
717 video_display(is);
718 } else {
719 schedule_refresh(is, 100);
720 }
721 if (show_status) {
722 static int64_t last_time;
723 int64_t cur_time;
724 int aqsize, vqsize;
638c9d91 725 double av_diff;
01310af2
FB
726
727 cur_time = av_gettime();
728 if (!last_time || (cur_time - last_time) >= 500 * 1000) {
729 aqsize = 0;
730 vqsize = 0;
731 if (is->audio_st)
732 aqsize = is->audioq.size;
733 if (is->video_st)
734 vqsize = is->videoq.size;
638c9d91
FB
735 av_diff = 0;
736 if (is->audio_st && is->video_st)
737 av_diff = get_audio_clock(is) - get_video_clock(is);
738 printf("%7.2f A-V:%7.3f aq=%5dKB vq=%5dKB \r",
739 get_master_clock(is), av_diff, aqsize / 1024, vqsize / 1024);
01310af2
FB
740 fflush(stdout);
741 last_time = cur_time;
742 }
743 }
744}
745
746/* allocate a picture (needs to do that in main thread to avoid
747 potential locking problems */
748static void alloc_picture(void *opaque)
749{
750 VideoState *is = opaque;
751 VideoPicture *vp;
01310af2
FB
752
753 vp = &is->pictq[is->pictq_windex];
754
755 if (vp->bmp)
756 SDL_FreeYUVOverlay(vp->bmp);
757
61890b02 758#if 0
01310af2 759 /* XXX: use generic function */
61890b02 760 /* XXX: disable overlay if no hardware acceleration or if RGB format */
01310af2
FB
761 switch(is->video_st->codec.pix_fmt) {
762 case PIX_FMT_YUV420P:
763 case PIX_FMT_YUV422P:
764 case PIX_FMT_YUV444P:
765 case PIX_FMT_YUV422:
766 case PIX_FMT_YUV410P:
767 case PIX_FMT_YUV411P:
768 is_yuv = 1;
769 break;
770 default:
771 is_yuv = 0;
772 break;
773 }
01310af2 774#endif
61890b02
FB
775 vp->bmp = SDL_CreateYUVOverlay(is->video_st->codec.width,
776 is->video_st->codec.height,
777 SDL_YV12_OVERLAY,
778 screen);
01310af2
FB
779 vp->width = is->video_st->codec.width;
780 vp->height = is->video_st->codec.height;
781
782 SDL_LockMutex(is->pictq_mutex);
783 vp->allocated = 1;
784 SDL_CondSignal(is->pictq_cond);
785 SDL_UnlockMutex(is->pictq_mutex);
786}
787
638c9d91 788static int queue_picture(VideoState *is, AVFrame *src_frame, double pts)
01310af2
FB
789{
790 VideoPicture *vp;
791 int dst_pix_fmt;
792 AVPicture pict;
01310af2
FB
793
794 /* wait until we have space to put a new picture */
795 SDL_LockMutex(is->pictq_mutex);
796 while (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE &&
797 !is->videoq.abort_request) {
798 SDL_CondWait(is->pictq_cond, is->pictq_mutex);
799 }
800 SDL_UnlockMutex(is->pictq_mutex);
801
802 if (is->videoq.abort_request)
803 return -1;
804
805 vp = &is->pictq[is->pictq_windex];
806
807 /* alloc or resize hardware picture buffer */
808 if (!vp->bmp ||
809 vp->width != is->video_st->codec.width ||
810 vp->height != is->video_st->codec.height) {
811 SDL_Event event;
812
813 vp->allocated = 0;
814
815 /* the allocation must be done in the main thread to avoid
816 locking problems */
817 event.type = FF_ALLOC_EVENT;
818 event.user.data1 = is;
819 SDL_PushEvent(&event);
820
821 /* wait until the picture is allocated */
822 SDL_LockMutex(is->pictq_mutex);
823 while (!vp->allocated && !is->videoq.abort_request) {
824 SDL_CondWait(is->pictq_cond, is->pictq_mutex);
825 }
826 SDL_UnlockMutex(is->pictq_mutex);
827
828 if (is->videoq.abort_request)
829 return -1;
830 }
831
638c9d91 832 /* if the frame is not skipped, then display it */
01310af2
FB
833 if (vp->bmp) {
834 /* get a pointer on the bitmap */
835 SDL_LockYUVOverlay (vp->bmp);
836
837 dst_pix_fmt = PIX_FMT_YUV420P;
838 pict.data[0] = vp->bmp->pixels[0];
839 pict.data[1] = vp->bmp->pixels[2];
840 pict.data[2] = vp->bmp->pixels[1];
841
842 pict.linesize[0] = vp->bmp->pitches[0];
843 pict.linesize[1] = vp->bmp->pitches[2];
844 pict.linesize[2] = vp->bmp->pitches[1];
01310af2 845 img_convert(&pict, dst_pix_fmt,
638c9d91 846 (AVPicture *)src_frame, is->video_st->codec.pix_fmt,
01310af2
FB
847 is->video_st->codec.width, is->video_st->codec.height);
848 /* update the bitmap content */
849 SDL_UnlockYUVOverlay(vp->bmp);
850
638c9d91 851 vp->pts = pts;
01310af2
FB
852
853 /* now we can update the picture count */
854 if (++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE)
855 is->pictq_windex = 0;
856 SDL_LockMutex(is->pictq_mutex);
857 is->pictq_size++;
858 SDL_UnlockMutex(is->pictq_mutex);
859 }
638c9d91
FB
860 return 0;
861}
862
863/* compute the exact PTS for the picture if it is omitted in the stream */
864static int output_picture2(VideoState *is, AVFrame *src_frame, double pts1)
865{
866 double frame_delay, pts;
867
868 pts = pts1;
869
01310af2 870 if (pts != 0) {
638c9d91 871 /* update video clock with pts, if present */
01310af2
FB
872 is->video_clock = pts;
873 } else {
72ea344b
FB
874 pts = is->video_clock;
875 }
876 /* update video clock for next frame */
c0df9d75 877 frame_delay = av_q2d(is->video_st->codec.time_base);
72ea344b
FB
878 /* for MPEG2, the frame can be repeated, so we update the
879 clock accordingly */
880 if (src_frame->repeat_pict) {
881 frame_delay += src_frame->repeat_pict * (frame_delay * 0.5);
01310af2 882 }
72ea344b 883 is->video_clock += frame_delay;
638c9d91
FB
884
885#if defined(DEBUG_SYNC) && 0
886 {
887 int ftype;
888 if (src_frame->pict_type == FF_B_TYPE)
889 ftype = 'B';
890 else if (src_frame->pict_type == FF_I_TYPE)
891 ftype = 'I';
892 else
893 ftype = 'P';
894 printf("frame_type=%c clock=%0.3f pts=%0.3f\n",
72ea344b 895 ftype, pts, pts1);
638c9d91
FB
896 }
897#endif
72ea344b 898 return queue_picture(is, src_frame, pts);
01310af2
FB
899}
900
901static int video_thread(void *arg)
902{
903 VideoState *is = arg;
904 AVPacket pkt1, *pkt = &pkt1;
72ea344b 905 int len1, got_picture;
c6b1edc9 906 AVFrame *frame= avcodec_alloc_frame();
01310af2
FB
907 double pts;
908
909 for(;;) {
910 while (is->paused && !is->videoq.abort_request) {
911 SDL_Delay(10);
912 }
913 if (packet_queue_get(&is->videoq, pkt, 1) < 0)
914 break;
638c9d91
FB
915 /* NOTE: ipts is the PTS of the _first_ picture beginning in
916 this packet, if any */
72ea344b 917 pts = 0;
61c1d8e2 918 if (pkt->dts != AV_NOPTS_VALUE)
c0df9d75 919 pts = av_q2d(is->video_st->time_base)*pkt->dts;
72ea344b 920
b514ed3c 921 SDL_LockMutex(is->video_decoder_mutex);
72ea344b
FB
922 len1 = avcodec_decode_video(&is->video_st->codec,
923 frame, &got_picture,
924 pkt->data, pkt->size);
b514ed3c 925 SDL_UnlockMutex(is->video_decoder_mutex);
fb966f99
MN
926// if (len1 < 0)
927// break;
72ea344b
FB
928 if (got_picture) {
929 if (output_picture2(is, frame, pts) < 0)
930 goto the_end;
01310af2 931 }
01310af2 932 av_free_packet(pkt);
bba04f1e
WH
933 if (step)
934 if (cur_stream)
935 stream_pause(cur_stream);
01310af2
FB
936 }
937 the_end:
c6b1edc9 938 av_free(frame);
01310af2
FB
939 return 0;
940}
941
942/* copy samples for viewing in editor window */
943static void update_sample_display(VideoState *is, short *samples, int samples_size)
944{
945 int size, len, channels;
946
947 channels = is->audio_st->codec.channels;
948
949 size = samples_size / sizeof(short);
950 while (size > 0) {
951 len = SAMPLE_ARRAY_SIZE - is->sample_array_index;
952 if (len > size)
953 len = size;
954 memcpy(is->sample_array + is->sample_array_index, samples, len * sizeof(short));
955 samples += len;
956 is->sample_array_index += len;
957 if (is->sample_array_index >= SAMPLE_ARRAY_SIZE)
958 is->sample_array_index = 0;
959 size -= len;
960 }
961}
962
01310af2
FB
963/* return the new audio buffer size (samples can be added or deleted
964 to get better sync if video or external master clock) */
965static int synchronize_audio(VideoState *is, short *samples,
638c9d91 966 int samples_size1, double pts)
01310af2 967{
638c9d91 968 int n, samples_size;
01310af2
FB
969 double ref_clock;
970
971 n = 2 * is->audio_st->codec.channels;
638c9d91 972 samples_size = samples_size1;
01310af2 973
01310af2 974 /* if not master, then we try to remove or add samples to correct the clock */
01310af2 975 if (((is->av_sync_type == AV_SYNC_VIDEO_MASTER && is->video_st) ||
638c9d91
FB
976 is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK)) {
977 double diff, avg_diff;
01310af2 978 int wanted_size, min_size, max_size, nb_samples;
638c9d91
FB
979
980 ref_clock = get_master_clock(is);
981 diff = get_audio_clock(is) - ref_clock;
01310af2 982
638c9d91
FB
983 if (diff < AV_NOSYNC_THRESHOLD) {
984 is->audio_diff_cum = diff + is->audio_diff_avg_coef * is->audio_diff_cum;
985 if (is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) {
986 /* not enough measures to have a correct estimate */
987 is->audio_diff_avg_count++;
988 } else {
989 /* estimate the A-V difference */
990 avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef);
991
992 if (fabs(avg_diff) >= is->audio_diff_threshold) {
993 wanted_size = samples_size + ((int)(diff * is->audio_st->codec.sample_rate) * n);
994 nb_samples = samples_size / n;
995
996 min_size = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX)) / 100) * n;
997 max_size = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX)) / 100) * n;
998 if (wanted_size < min_size)
999 wanted_size = min_size;
1000 else if (wanted_size > max_size)
1001 wanted_size = max_size;
1002
1003 /* add or remove samples to correction the synchro */
1004 if (wanted_size < samples_size) {
1005 /* remove samples */
1006 samples_size = wanted_size;
1007 } else if (wanted_size > samples_size) {
1008 uint8_t *samples_end, *q;
1009 int nb;
1010
1011 /* add samples */
1012 nb = (samples_size - wanted_size);
1013 samples_end = (uint8_t *)samples + samples_size - n;
1014 q = samples_end + n;
1015 while (nb > 0) {
1016 memcpy(q, samples_end, n);
1017 q += n;
1018 nb -= n;
1019 }
1020 samples_size = wanted_size;
1021 }
1022 }
1023#if 0
1024 printf("diff=%f adiff=%f sample_diff=%d apts=%0.3f vpts=%0.3f %f\n",
1025 diff, avg_diff, samples_size - samples_size1,
1026 is->audio_clock, is->video_clock, is->audio_diff_threshold);
1027#endif
01310af2 1028 }
638c9d91
FB
1029 } else {
1030 /* too big difference : may be initial PTS errors, so
1031 reset A-V filter */
1032 is->audio_diff_avg_count = 0;
1033 is->audio_diff_cum = 0;
01310af2
FB
1034 }
1035 }
1036
01310af2
FB
1037 return samples_size;
1038}
1039
1040/* decode one audio frame and returns its uncompressed size */
1041static int audio_decode_frame(VideoState *is, uint8_t *audio_buf, double *pts_ptr)
1042{
1043 AVPacket *pkt = &is->audio_pkt;
72ea344b 1044 int n, len1, data_size;
01310af2
FB
1045 double pts;
1046
1047 for(;;) {
72ea344b 1048 /* NOTE: the audio packet can contain several frames */
01310af2 1049 while (is->audio_pkt_size > 0) {
b514ed3c 1050 SDL_LockMutex(is->audio_decoder_mutex);
01310af2
FB
1051 len1 = avcodec_decode_audio(&is->audio_st->codec,
1052 (int16_t *)audio_buf, &data_size,
1053 is->audio_pkt_data, is->audio_pkt_size);
b514ed3c 1054 SDL_UnlockMutex(is->audio_decoder_mutex);
72ea344b
FB
1055 if (len1 < 0) {
1056 /* if error, we skip the frame */
1057 is->audio_pkt_size = 0;
01310af2 1058 break;
72ea344b
FB
1059 }
1060
01310af2
FB
1061 is->audio_pkt_data += len1;
1062 is->audio_pkt_size -= len1;
72ea344b
FB
1063 if (data_size <= 0)
1064 continue;
1065 /* if no pts, then compute it */
1066 pts = is->audio_clock;
1067 *pts_ptr = pts;
1068 n = 2 * is->audio_st->codec.channels;
1069 is->audio_clock += (double)data_size /
1070 (double)(n * is->audio_st->codec.sample_rate);
638c9d91 1071#if defined(DEBUG_SYNC)
72ea344b
FB
1072 {
1073 static double last_clock;
1074 printf("audio: delay=%0.3f clock=%0.3f pts=%0.3f\n",
1075 is->audio_clock - last_clock,
1076 is->audio_clock, pts);
1077 last_clock = is->audio_clock;
01310af2 1078 }
72ea344b
FB
1079#endif
1080 return data_size;
01310af2
FB
1081 }
1082
72ea344b
FB
1083 /* free the current packet */
1084 if (pkt->data)
01310af2 1085 av_free_packet(pkt);
72ea344b
FB
1086
1087 if (is->paused || is->audioq.abort_request) {
1088 return -1;
1089 }
1090
01310af2
FB
1091 /* read next packet */
1092 if (packet_queue_get(&is->audioq, pkt, 1) < 0)
1093 return -1;
1094 is->audio_pkt_data = pkt->data;
1095 is->audio_pkt_size = pkt->size;
72ea344b
FB
1096
1097 /* if update the audio clock with the pts */
1098 if (pkt->pts != AV_NOPTS_VALUE) {
c0df9d75 1099 is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts;
72ea344b 1100 }
01310af2
FB
1101 }
1102}
1103
638c9d91
FB
1104/* get the current audio output buffer size, in samples. With SDL, we
1105 cannot have a precise information */
1106static int audio_write_get_buf_size(VideoState *is)
01310af2 1107{
638c9d91 1108 return is->audio_hw_buf_size - is->audio_buf_index;
01310af2
FB
1109}
1110
1111
1112/* prepare a new audio buffer */
1113void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
1114{
1115 VideoState *is = opaque;
1116 int audio_size, len1;
1117 double pts;
1118
1119 audio_callback_time = av_gettime();
1120
1121 while (len > 0) {
1122 if (is->audio_buf_index >= is->audio_buf_size) {
1123 audio_size = audio_decode_frame(is, is->audio_buf, &pts);
1124 if (audio_size < 0) {
1125 /* if error, just output silence */
1126 is->audio_buf_size = 1024;
1127 memset(is->audio_buf, 0, is->audio_buf_size);
1128 } else {
1129 if (is->show_audio)
1130 update_sample_display(is, (int16_t *)is->audio_buf, audio_size);
1131 audio_size = synchronize_audio(is, (int16_t *)is->audio_buf, audio_size,
1132 pts);
1133 is->audio_buf_size = audio_size;
1134 }
1135 is->audio_buf_index = 0;
1136 }
1137 len1 = is->audio_buf_size - is->audio_buf_index;
1138 if (len1 > len)
1139 len1 = len;
1140 memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);
1141 len -= len1;
1142 stream += len1;
1143 is->audio_buf_index += len1;
1144 }
1145}
1146
1147
1148/* open a given stream. Return 0 if OK */
1149static int stream_component_open(VideoState *is, int stream_index)
1150{
1151 AVFormatContext *ic = is->ic;
1152 AVCodecContext *enc;
1153 AVCodec *codec;
1154 SDL_AudioSpec wanted_spec, spec;
1155
1156 if (stream_index < 0 || stream_index >= ic->nb_streams)
1157 return -1;
1158 enc = &ic->streams[stream_index]->codec;
1159
01310af2
FB
1160 /* prepare audio output */
1161 if (enc->codec_type == CODEC_TYPE_AUDIO) {
1162 wanted_spec.freq = enc->sample_rate;
1163 wanted_spec.format = AUDIO_S16SYS;
638c9d91
FB
1164 /* hack for AC3. XXX: suppress that */
1165 if (enc->channels > 2)
1166 enc->channels = 2;
01310af2
FB
1167 wanted_spec.channels = enc->channels;
1168 wanted_spec.silence = 0;
638c9d91 1169 wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
01310af2
FB
1170 wanted_spec.callback = sdl_audio_callback;
1171 wanted_spec.userdata = is;
638c9d91
FB
1172 if (SDL_OpenAudio(&wanted_spec, &spec) < 0) {
1173 fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());
01310af2 1174 return -1;
638c9d91 1175 }
01310af2
FB
1176 is->audio_hw_buf_size = spec.size;
1177 }
1178
1179 codec = avcodec_find_decoder(enc->codec_id);
13d1512c
MN
1180 enc->debug_mv = debug_mv;
1181 enc->debug = debug;
6387c3e6 1182 enc->workaround_bugs = workaround_bugs;
178fcca8 1183 enc->lowres = lowres;
61846e9a 1184 if(lowres) enc->flags |= CODEC_FLAG_EMU_EDGE;
178fcca8 1185 enc->idct_algo= idct;
6fc5b059 1186 if(fast) enc->flags2 |= CODEC_FLAG2_FAST;
01310af2
FB
1187 if (!codec ||
1188 avcodec_open(enc, codec) < 0)
1189 return -1;
2450cff2 1190#if defined(HAVE_THREADS)
c62c07d3
MN
1191 if(thread_count>1)
1192 avcodec_thread_init(enc, thread_count);
1193#endif
1194 enc->thread_count= thread_count;
638c9d91 1195 switch(enc->codec_type) {
01310af2
FB
1196 case CODEC_TYPE_AUDIO:
1197 is->audio_stream = stream_index;
1198 is->audio_st = ic->streams[stream_index];
1199 is->audio_buf_size = 0;
1200 is->audio_buf_index = 0;
638c9d91
FB
1201
1202 /* init averaging filter */
1203 is->audio_diff_avg_coef = exp(log(0.01) / AUDIO_DIFF_AVG_NB);
1204 is->audio_diff_avg_count = 0;
1205 /* since we do not have a precise anough audio fifo fullness,
1206 we correct audio sync only if larger than this threshold */
1207 is->audio_diff_threshold = 2.0 * SDL_AUDIO_BUFFER_SIZE / enc->sample_rate;
1208
01310af2
FB
1209 memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
1210 packet_queue_init(&is->audioq);
1211 SDL_PauseAudio(0);
1212 break;
1213 case CODEC_TYPE_VIDEO:
1214 is->video_stream = stream_index;
1215 is->video_st = ic->streams[stream_index];
1216
638c9d91
FB
1217 is->frame_last_delay = 40e-3;
1218 is->frame_timer = (double)av_gettime() / 1000000.0;
638c9d91
FB
1219 is->video_current_pts_time = av_gettime();
1220
01310af2
FB
1221 packet_queue_init(&is->videoq);
1222 is->video_tid = SDL_CreateThread(video_thread, is);
1223 break;
1224 default:
1225 break;
1226 }
1227 return 0;
1228}
1229
1230static void stream_component_close(VideoState *is, int stream_index)
1231{
1232 AVFormatContext *ic = is->ic;
1233 AVCodecContext *enc;
1234
1235 enc = &ic->streams[stream_index]->codec;
1236
1237 switch(enc->codec_type) {
1238 case CODEC_TYPE_AUDIO:
1239 packet_queue_abort(&is->audioq);
1240
1241 SDL_CloseAudio();
1242
1243 packet_queue_end(&is->audioq);
1244 break;
1245 case CODEC_TYPE_VIDEO:
1246 packet_queue_abort(&is->videoq);
1247
1248 /* note: we also signal this mutex to make sure we deblock the
1249 video thread in all cases */
1250 SDL_LockMutex(is->pictq_mutex);
1251 SDL_CondSignal(is->pictq_cond);
1252 SDL_UnlockMutex(is->pictq_mutex);
1253
1254 SDL_WaitThread(is->video_tid, NULL);
1255
1256 packet_queue_end(&is->videoq);
1257 break;
1258 default:
1259 break;
1260 }
1261
1262 avcodec_close(enc);
1263 switch(enc->codec_type) {
1264 case CODEC_TYPE_AUDIO:
1265 is->audio_st = NULL;
1266 is->audio_stream = -1;
1267 break;
1268 case CODEC_TYPE_VIDEO:
1269 is->video_st = NULL;
1270 is->video_stream = -1;
1271 break;
1272 default:
1273 break;
1274 }
1275}
1276
d0526ecf
FB
1277void dump_stream_info(AVFormatContext *s)
1278{
1279 if (s->track != 0)
1280 fprintf(stderr, "Track: %d\n", s->track);
1281 if (s->title[0] != '\0')
1282 fprintf(stderr, "Title: %s\n", s->title);
1283 if (s->author[0] != '\0')
1284 fprintf(stderr, "Author: %s\n", s->author);
1285 if (s->album[0] != '\0')
1286 fprintf(stderr, "Album: %s\n", s->album);
1287 if (s->year != 0)
1288 fprintf(stderr, "Year: %d\n", s->year);
1289 if (s->genre[0] != '\0')
1290 fprintf(stderr, "Genre: %s\n", s->genre);
1291}
1292
416e3508
FB
1293/* since we have only one decoding thread, we can use a global
1294 variable instead of a thread local variable */
1295static VideoState *global_video_state;
1296
1297static int decode_interrupt_cb(void)
1298{
1299 return (global_video_state && global_video_state->abort_request);
1300}
01310af2
FB
1301
1302/* this thread gets the stream from the disk or the network */
1303static int decode_thread(void *arg)
1304{
1305 VideoState *is = arg;
1306 AVFormatContext *ic;
72ea344b 1307 int err, i, ret, video_index, audio_index, use_play;
01310af2 1308 AVPacket pkt1, *pkt = &pkt1;
61890b02 1309 AVFormatParameters params, *ap = &params;
01310af2
FB
1310
1311 video_index = -1;
1312 audio_index = -1;
1313 is->video_stream = -1;
1314 is->audio_stream = -1;
1315
416e3508
FB
1316 global_video_state = is;
1317 url_set_interrupt_cb(decode_interrupt_cb);
1318
61890b02
FB
1319 memset(ap, 0, sizeof(*ap));
1320 ap->image_format = image_format;
72ea344b
FB
1321 ap->initial_pause = 1; /* we force a pause when starting an RTSP
1322 stream */
1323
61890b02 1324 err = av_open_input_file(&ic, is->filename, is->iformat, 0, ap);
638c9d91
FB
1325 if (err < 0) {
1326 print_error(is->filename, err);
1327 ret = -1;
1328 goto fail;
1329 }
01310af2 1330 is->ic = ic;
72ea344b
FB
1331#ifdef CONFIG_NETWORK
1332 use_play = (ic->iformat == &rtsp_demux);
1333#else
1334 use_play = 0;
1335#endif
1336 if (!use_play) {
1337 err = av_find_stream_info(ic);
1338 if (err < 0) {
1339 fprintf(stderr, "%s: could not find codec parameters\n", is->filename);
1340 ret = -1;
1341 goto fail;
1342 }
2536c5fd 1343 ic->pb.eof_reached= 0; //FIXME hack, ffplay maybe shouldnt use url_feof() to test for the end
638c9d91 1344 }
72ea344b
FB
1345
1346 /* if seeking requested, we execute it */
1347 if (start_time != AV_NOPTS_VALUE) {
1348 int64_t timestamp;
1349
1350 timestamp = start_time;
1351 /* add the stream start time */
1352 if (ic->start_time != AV_NOPTS_VALUE)
1353 timestamp += ic->start_time;
3ba1438d 1354 ret = av_seek_frame(ic, -1, timestamp, AVSEEK_FLAG_BACKWARD);
72ea344b
FB
1355 if (ret < 0) {
1356 fprintf(stderr, "%s: could not seek to position %0.3f\n",
1357 is->filename, (double)timestamp / AV_TIME_BASE);
1358 }
1359 }
1360
1361 /* now we can begin to play (RTSP stream only) */
1362 av_read_play(ic);
1363
1364 if (use_play) {
1365 err = av_find_stream_info(ic);
1366 if (err < 0) {
1367 fprintf(stderr, "%s: could not find codec parameters\n", is->filename);
1368 ret = -1;
1369 goto fail;
1370 }
1371 }
1372
01310af2
FB
1373 for(i = 0; i < ic->nb_streams; i++) {
1374 AVCodecContext *enc = &ic->streams[i]->codec;
1375 switch(enc->codec_type) {
1376 case CODEC_TYPE_AUDIO:
1377 if (audio_index < 0 && !audio_disable)
1378 audio_index = i;
1379 break;
1380 case CODEC_TYPE_VIDEO:
1381 if (video_index < 0 && !video_disable)
1382 video_index = i;
1383 break;
1384 default:
1385 break;
1386 }
1387 }
1388 if (show_status) {
1389 dump_format(ic, 0, is->filename, 0);
d0526ecf 1390 dump_stream_info(ic);
01310af2
FB
1391 }
1392
1393 /* open the streams */
1394 if (audio_index >= 0) {
1395 stream_component_open(is, audio_index);
1396 }
1397
1398 if (video_index >= 0) {
1399 stream_component_open(is, video_index);
1400 } else {
1401 if (!display_disable)
1402 is->show_audio = 1;
1403 }
1404
1405 if (is->video_stream < 0 && is->audio_stream < 0) {
638c9d91
FB
1406 fprintf(stderr, "%s: could not open codecs\n", is->filename);
1407 ret = -1;
01310af2
FB
1408 goto fail;
1409 }
1410
1411 for(;;) {
1412 if (is->abort_request)
1413 break;
400738b1 1414#ifdef CONFIG_NETWORK
416e3508
FB
1415 if (is->paused != is->last_paused) {
1416 is->last_paused = is->paused;
72ea344b
FB
1417 if (is->paused)
1418 av_read_pause(ic);
1419 else
1420 av_read_play(ic);
416e3508
FB
1421 }
1422 if (is->paused && ic->iformat == &rtsp_demux) {
1423 /* wait 10 ms to avoid trying to get another packet */
1424 /* XXX: horrible */
1425 SDL_Delay(10);
1426 continue;
1427 }
400738b1 1428#endif
72ea344b
FB
1429 if (is->seek_req) {
1430 /* XXX: must lock decoder threads */
3ba1438d 1431 ret = av_seek_frame(is->ic, -1, is->seek_pos, is->seek_flags);
72ea344b
FB
1432 if (ret < 0) {
1433 fprintf(stderr, "%s: error while seeking\n", is->ic->filename);
e6c0297f
MN
1434 }else{
1435 if (is->audio_stream >= 0) {
1436 packet_queue_flush(&is->audioq);
1437 }
1438 if (is->video_stream >= 0) {
1439 packet_queue_flush(&is->videoq);
b514ed3c 1440 SDL_LockMutex(is->video_decoder_mutex);
93e1a0a9 1441 avcodec_flush_buffers(&ic->streams[video_index]->codec);
b514ed3c 1442 SDL_UnlockMutex(is->video_decoder_mutex);
e6c0297f 1443 }
72ea344b
FB
1444 }
1445 is->seek_req = 0;
1446 }
416e3508 1447
01310af2
FB
1448 /* if the queue are full, no need to read more */
1449 if (is->audioq.size > MAX_AUDIOQ_SIZE ||
0c904df2
MN
1450 is->videoq.size > MAX_VIDEOQ_SIZE ||
1451 url_feof(&ic->pb)) {
01310af2
FB
1452 /* wait 10 ms */
1453 SDL_Delay(10);
1454 continue;
1455 }
72ea344b 1456 ret = av_read_frame(ic, pkt);
01310af2 1457 if (ret < 0) {
6e1f8725
RS
1458 if (url_feof(&ic->pb) && url_ferror(&ic->pb) == 0) {
1459 SDL_Delay(100); /* wait for user event */
1460 continue;
1461 } else
1462 break;
01310af2
FB
1463 }
1464 if (pkt->stream_index == is->audio_stream) {
1465 packet_queue_put(&is->audioq, pkt);
1466 } else if (pkt->stream_index == is->video_stream) {
1467 packet_queue_put(&is->videoq, pkt);
1468 } else {
1469 av_free_packet(pkt);
1470 }
1471 }
1472 /* wait until the end */
1473 while (!is->abort_request) {
1474 SDL_Delay(100);
1475 }
1476
638c9d91 1477 ret = 0;
01310af2 1478 fail:
416e3508
FB
1479 /* disable interrupting */
1480 global_video_state = NULL;
1481
01310af2
FB
1482 /* close each stream */
1483 if (is->audio_stream >= 0)
1484 stream_component_close(is, is->audio_stream);
1485 if (is->video_stream >= 0)
1486 stream_component_close(is, is->video_stream);
638c9d91
FB
1487 if (is->ic) {
1488 av_close_input_file(is->ic);
1489 is->ic = NULL; /* safety */
1490 }
416e3508
FB
1491 url_set_interrupt_cb(NULL);
1492
638c9d91
FB
1493 if (ret != 0) {
1494 SDL_Event event;
1495
1496 event.type = FF_QUIT_EVENT;
1497 event.user.data1 = is;
1498 SDL_PushEvent(&event);
1499 }
01310af2
FB
1500 return 0;
1501}
1502
638c9d91 1503static VideoState *stream_open(const char *filename, AVInputFormat *iformat)
01310af2
FB
1504{
1505 VideoState *is;
1506
1507 is = av_mallocz(sizeof(VideoState));
1508 if (!is)
1509 return NULL;
1510 pstrcpy(is->filename, sizeof(is->filename), filename);
638c9d91 1511 is->iformat = iformat;
01310af2
FB
1512 if (screen) {
1513 is->width = screen->w;
1514 is->height = screen->h;
1515 }
1516 is->ytop = 0;
1517 is->xleft = 0;
1518
1519 /* start video display */
1520 is->pictq_mutex = SDL_CreateMutex();
1521 is->pictq_cond = SDL_CreateCond();
b514ed3c
MN
1522
1523 is->audio_decoder_mutex = SDL_CreateMutex();
1524 is->video_decoder_mutex = SDL_CreateMutex();
01310af2
FB
1525
1526 /* add the refresh timer to draw the picture */
1527 schedule_refresh(is, 40);
1528
638c9d91 1529 is->av_sync_type = av_sync_type;
01310af2
FB
1530 is->parse_tid = SDL_CreateThread(decode_thread, is);
1531 if (!is->parse_tid) {
1532 av_free(is);
1533 return NULL;
1534 }
1535 return is;
1536}
1537
1538static void stream_close(VideoState *is)
1539{
1540 VideoPicture *vp;
1541 int i;
1542 /* XXX: use a special url_shutdown call to abort parse cleanly */
1543 is->abort_request = 1;
1544 SDL_WaitThread(is->parse_tid, NULL);
1545
1546 /* free all pictures */
1547 for(i=0;i<VIDEO_PICTURE_QUEUE_SIZE; i++) {
1548 vp = &is->pictq[i];
1549 if (vp->bmp) {
1550 SDL_FreeYUVOverlay(vp->bmp);
1551 vp->bmp = NULL;
1552 }
1553 }
1554 SDL_DestroyMutex(is->pictq_mutex);
1555 SDL_DestroyCond(is->pictq_cond);
b514ed3c
MN
1556 SDL_DestroyMutex(is->audio_decoder_mutex);
1557 SDL_DestroyMutex(is->video_decoder_mutex);
01310af2
FB
1558}
1559
638c9d91
FB
1560void stream_cycle_channel(VideoState *is, int codec_type)
1561{
1562 AVFormatContext *ic = is->ic;
1563 int start_index, stream_index;
1564 AVStream *st;
1565
1566 if (codec_type == CODEC_TYPE_VIDEO)
1567 start_index = is->video_stream;
1568 else
1569 start_index = is->audio_stream;
1570 if (start_index < 0)
1571 return;
1572 stream_index = start_index;
1573 for(;;) {
1574 if (++stream_index >= is->ic->nb_streams)
1575 stream_index = 0;
1576 if (stream_index == start_index)
1577 return;
1578 st = ic->streams[stream_index];
1579 if (st->codec.codec_type == codec_type) {
1580 /* check that parameters are OK */
1581 switch(codec_type) {
1582 case CODEC_TYPE_AUDIO:
1583 if (st->codec.sample_rate != 0 &&
1584 st->codec.channels != 0)
1585 goto the_end;
1586 break;
1587 case CODEC_TYPE_VIDEO:
1588 goto the_end;
1589 default:
1590 break;
1591 }
1592 }
1593 }
1594 the_end:
1595 stream_component_close(is, start_index);
1596 stream_component_open(is, stream_index);
1597}
1598
1599
01310af2
FB
1600void toggle_full_screen(void)
1601{
1602 int w, h, flags;
1603 is_full_screen = !is_full_screen;
1604 if (!fs_screen_width) {
1605 /* use default SDL method */
1606 SDL_WM_ToggleFullScreen(screen);
1607 } else {
1608 /* use the recorded resolution */
1609 flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
1610 if (is_full_screen) {
1611 w = fs_screen_width;
1612 h = fs_screen_height;
1613 flags |= SDL_FULLSCREEN;
1614 } else {
1615 w = screen_width;
1616 h = screen_height;
1617 flags |= SDL_RESIZABLE;
1618 }
1619 screen = SDL_SetVideoMode(w, h, 0, flags);
1620 cur_stream->width = w;
1621 cur_stream->height = h;
1622 }
1623}
1624
1625void toggle_pause(void)
1626{
1627 if (cur_stream)
1628 stream_pause(cur_stream);
bba04f1e
WH
1629 step = 0;
1630}
1631
1632void step_to_next_frame(void)
1633{
1634 if (cur_stream) {
1635 if (cur_stream->paused)
1636 cur_stream->paused=0;
1637 cur_stream->video_current_pts = get_video_clock(cur_stream);
1638 }
1639 step = 1;
01310af2
FB
1640}
1641
1642void do_exit(void)
1643{
1644 if (cur_stream) {
1645 stream_close(cur_stream);
1646 cur_stream = NULL;
1647 }
1648 if (show_status)
1649 printf("\n");
1650 SDL_Quit();
1651 exit(0);
1652}
1653
1654void toggle_audio_display(void)
1655{
1656 if (cur_stream) {
1657 cur_stream->show_audio = !cur_stream->show_audio;
1658 }
1659}
1660
1661/* handle an event sent by the GUI */
1662void event_loop(void)
1663{
1664 SDL_Event event;
a11d11aa 1665 double incr, pos, frac;
01310af2
FB
1666
1667 for(;;) {
1668 SDL_WaitEvent(&event);
1669 switch(event.type) {
1670 case SDL_KEYDOWN:
1671 switch(event.key.keysym.sym) {
1672 case SDLK_ESCAPE:
1673 case SDLK_q:
1674 do_exit();
1675 break;
1676 case SDLK_f:
1677 toggle_full_screen();
1678 break;
1679 case SDLK_p:
1680 case SDLK_SPACE:
1681 toggle_pause();
1682 break;
bba04f1e
WH
1683 case SDLK_s: //S: Step to next frame
1684 step_to_next_frame();
1685 break;
01310af2 1686 case SDLK_a:
638c9d91
FB
1687 if (cur_stream)
1688 stream_cycle_channel(cur_stream, CODEC_TYPE_AUDIO);
1689 break;
1690 case SDLK_v:
1691 if (cur_stream)
1692 stream_cycle_channel(cur_stream, CODEC_TYPE_VIDEO);
1693 break;
1694 case SDLK_w:
01310af2
FB
1695 toggle_audio_display();
1696 break;
72ea344b
FB
1697 case SDLK_LEFT:
1698 incr = -10.0;
1699 goto do_seek;
1700 case SDLK_RIGHT:
1701 incr = 10.0;
1702 goto do_seek;
1703 case SDLK_UP:
1704 incr = 60.0;
1705 goto do_seek;
1706 case SDLK_DOWN:
1707 incr = -60.0;
1708 do_seek:
1709 if (cur_stream) {
1710 pos = get_master_clock(cur_stream);
1711 pos += incr;
3ba1438d 1712 stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), incr);
72ea344b
FB
1713 }
1714 break;
01310af2
FB
1715 default:
1716 break;
1717 }
1718 break;
a11d11aa
MB
1719 case SDL_MOUSEBUTTONDOWN:
1720 if (cur_stream) {
1721 int ns, hh, mm, ss;
1722 int tns, thh, tmm, tss;
1723 tns = cur_stream->ic->duration/1000000LL;
1724 thh = tns/3600;
1725 tmm = (tns%3600)/60;
1726 tss = (tns%60);
1727 frac = (double)event.button.x/(double)cur_stream->width;
1728 ns = frac*tns;
1729 hh = ns/3600;
1730 mm = (ns%3600)/60;
1731 ss = (ns%60);
1732 fprintf(stderr, "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d) \n", frac*100,
1733 hh, mm, ss, thh, tmm, tss);
3ba1438d 1734 stream_seek(cur_stream, (int64_t)(cur_stream->ic->start_time+frac*cur_stream->ic->duration), 0);
a11d11aa
MB
1735 }
1736 break;
01310af2
FB
1737 case SDL_VIDEORESIZE:
1738 if (cur_stream) {
1739 screen = SDL_SetVideoMode(event.resize.w, event.resize.h, 0,
1740 SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL);
1741 cur_stream->width = event.resize.w;
1742 cur_stream->height = event.resize.h;
1743 }
1744 break;
1745 case SDL_QUIT:
638c9d91 1746 case FF_QUIT_EVENT:
01310af2
FB
1747 do_exit();
1748 break;
1749 case FF_ALLOC_EVENT:
1750 alloc_picture(event.user.data1);
1751 break;
1752 case FF_REFRESH_EVENT:
1753 video_refresh_timer(event.user.data1);
1754 break;
1755 default:
1756 break;
1757 }
1758 }
1759}
1760
1761void opt_width(const char *arg)
1762{
1763 screen_width = atoi(arg);
1764}
1765
1766void opt_height(const char *arg)
1767{
1768 screen_height = atoi(arg);
1769}
1770
1771static void opt_format(const char *arg)
1772{
1773 file_iformat = av_find_input_format(arg);
1774 if (!file_iformat) {
1775 fprintf(stderr, "Unknown input format: %s\n", arg);
1776 exit(1);
1777 }
1778}
61890b02
FB
1779
1780static void opt_image_format(const char *arg)
1781{
1782 AVImageFormat *f;
1783
1784 for(f = first_image_format; f != NULL; f = f->next) {
1785 if (!strcmp(arg, f->name))
1786 break;
1787 }
1788 if (!f) {
1789 fprintf(stderr, "Unknown image format: '%s'\n", arg);
1790 exit(1);
1791 }
1792 image_format = f;
1793}
1794
400738b1 1795#ifdef CONFIG_NETWORK
416e3508
FB
1796void opt_rtp_tcp(void)
1797{
1798 /* only tcp protocol */
1799 rtsp_default_protocols = (1 << RTSP_PROTOCOL_RTP_TCP);
1800}
400738b1 1801#endif
416e3508 1802
638c9d91
FB
1803void opt_sync(const char *arg)
1804{
1805 if (!strcmp(arg, "audio"))
1806 av_sync_type = AV_SYNC_AUDIO_MASTER;
1807 else if (!strcmp(arg, "video"))
1808 av_sync_type = AV_SYNC_VIDEO_MASTER;
1809 else if (!strcmp(arg, "ext"))
1810 av_sync_type = AV_SYNC_EXTERNAL_CLOCK;
1811 else
1812 show_help();
1813}
1814
72ea344b
FB
1815void opt_seek(const char *arg)
1816{
1817 start_time = parse_date(arg, 1);
1818}
1819
e26a8335
WH
1820static void opt_debug(const char *arg)
1821{
1822 debug = atoi(arg);
1823}
1824
0c9bbaec
WH
1825static void opt_vismv(const char *arg)
1826{
1827 debug_mv = atoi(arg);
1828}
c62c07d3
MN
1829
1830static void opt_thread_count(const char *arg)
1831{
1832 thread_count= atoi(arg);
2450cff2 1833#if !defined(HAVE_THREADS)
c62c07d3
MN
1834 fprintf(stderr, "Warning: not compiled with thread support, using thread emulation\n");
1835#endif
1836}
0c9bbaec 1837
01310af2 1838const OptionDef options[] = {
e26a8335 1839 { "h", 0, {(void*)show_help}, "show help" },
01310af2
FB
1840 { "x", HAS_ARG, {(void*)opt_width}, "force displayed width", "width" },
1841 { "y", HAS_ARG, {(void*)opt_height}, "force displayed height", "height" },
638c9d91
FB
1842#if 0
1843 /* disabled as SDL/X11 does not support it correctly on application launch */
1844 { "fs", OPT_BOOL, {(void*)&is_full_screen}, "force full screen" },
1845#endif
01310af2
FB
1846 { "an", OPT_BOOL, {(void*)&audio_disable}, "disable audio" },
1847 { "vn", OPT_BOOL, {(void*)&video_disable}, "disable video" },
72ea344b 1848 { "ss", HAS_ARG, {(void*)&opt_seek}, "seek to a given position in seconds", "pos" },
01310af2
FB
1849 { "nodisp", OPT_BOOL, {(void*)&display_disable}, "disable graphical display" },
1850 { "f", HAS_ARG, {(void*)opt_format}, "force format", "fmt" },
61890b02 1851 { "img", HAS_ARG, {(void*)opt_image_format}, "force image format", "img_fmt" },
01310af2 1852 { "stats", OPT_BOOL | OPT_EXPERT, {(void*)&show_status}, "show status", "" },
e26a8335 1853 { "debug", HAS_ARG | OPT_EXPERT, {(void*)opt_debug}, "print specific debug info", "" },
6387c3e6 1854 { "bug", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&workaround_bugs}, "workaround bugs", "" },
0c9bbaec 1855 { "vismv", HAS_ARG | OPT_EXPERT, {(void*)opt_vismv}, "visualize motion vectors", "" },
6fc5b059 1856 { "fast", OPT_BOOL | OPT_EXPERT, {(void*)&fast}, "non spec compliant optimizations", "" },
178fcca8
MN
1857 { "lowres", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&lowres}, "", "" },
1858 { "idct", OPT_INT | HAS_ARG | OPT_EXPERT, {(void*)&idct}, "set idct algo", "algo" },
400738b1 1859#ifdef CONFIG_NETWORK
416e3508 1860 { "rtp_tcp", OPT_EXPERT, {(void*)&opt_rtp_tcp}, "force RTP/TCP protocol usage", "" },
400738b1 1861#endif
c62c07d3
MN
1862 { "sync", HAS_ARG | OPT_EXPERT, {(void*)opt_sync}, "set audio-video sync. type (type=audio/video/ext)", "type" },
1863 { "threads", HAS_ARG | OPT_EXPERT, {(void*)opt_thread_count}, "thread count", "count" },
01310af2
FB
1864 { NULL, },
1865};
1866
1867void show_help(void)
1868{
02d504a7
FB
1869 printf("ffplay version " FFMPEG_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
1870 "usage: ffplay [options] input_file\n"
01310af2
FB
1871 "Simple media player\n");
1872 printf("\n");
02d504a7
FB
1873 show_help_options(options, "Main options:\n",
1874 OPT_EXPERT, 0);
1875 show_help_options(options, "\nAdvanced options:\n",
1876 OPT_EXPERT, OPT_EXPERT);
01310af2
FB
1877 printf("\nWhile playing:\n"
1878 "q, ESC quit\n"
1879 "f toggle full screen\n"
1880 "p, SPC pause\n"
638c9d91
FB
1881 "a cycle audio channel\n"
1882 "v cycle video channel\n"
1883 "w show audio waves\n"
72ea344b
FB
1884 "left/right seek backward/forward 10 seconds\n"
1885 "down/up seek backward/forward 1 minute\n"
a11d11aa 1886 "mouse click seek to percentage in file corresponding to fraction of width\n"
01310af2
FB
1887 );
1888 exit(1);
1889}
1890
1891void parse_arg_file(const char *filename)
1892{
e8d83e1c
MN
1893 if (!strcmp(filename, "-"))
1894 filename = "pipe:";
01310af2
FB
1895 input_filename = filename;
1896}
1897
1898/* Called from the main */
1899int main(int argc, char **argv)
1900{
638c9d91 1901 int flags, w, h;
01310af2
FB
1902
1903 /* register all codecs, demux and protocols */
1904 av_register_all();
1905
3ca4b654
MN
1906 #ifdef CONFIG_OS2
1907 MorphToPM(); // Morph the VIO application to a PM one to be able to use Win* functions
1908
1909 // Make stdout and stderr unbuffered
1910 setbuf( stdout, NULL );
1911 setbuf( stderr, NULL );
1912 #endif
1913
01310af2
FB
1914 parse_options(argc, argv, options);
1915
1916 if (!input_filename)
1917 show_help();
1918
1919 if (display_disable) {
1920 video_disable = 1;
1921 }
31319a8c
FB
1922 flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
1923#ifndef CONFIG_WIN32
1924 flags |= SDL_INIT_EVENTTHREAD; /* Not supported on win32 */
1925#endif
01310af2 1926 if (SDL_Init (flags)) {
05ab0b76 1927 fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
01310af2
FB
1928 exit(1);
1929 }
1930
1931 if (!display_disable) {
01310af2
FB
1932#ifdef HAVE_X11
1933 /* save the screen resolution... SDL should allow full screen
1934 by resizing the window */
1935 {
1936 Display *dpy;
1937 dpy = XOpenDisplay(NULL);
1938 if (dpy) {
1939 fs_screen_width = DisplayWidth(dpy, DefaultScreen(dpy));
1940 fs_screen_height = DisplayHeight(dpy, DefaultScreen(dpy));
1941 XCloseDisplay(dpy);
1942 }
1943 }
1944#endif
638c9d91
FB
1945 flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
1946 if (is_full_screen && fs_screen_width) {
1947 w = fs_screen_width;
1948 h = fs_screen_height;
1949 flags |= SDL_FULLSCREEN;
1950 } else {
1951 w = screen_width;
1952 h = screen_height;
1953 flags |= SDL_RESIZABLE;
1954 }
1955 screen = SDL_SetVideoMode(w, h, 0, flags);
1956 if (!screen) {
1957 fprintf(stderr, "SDL: could not set video mode - exiting\n");
1958 exit(1);
1959 }
1960 SDL_WM_SetCaption("FFplay", "FFplay");
01310af2
FB
1961 }
1962
1963 SDL_EventState(SDL_ACTIVEEVENT, SDL_IGNORE);
1964 SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
1965 SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
1966 SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
1967
638c9d91 1968 cur_stream = stream_open(input_filename, file_iformat);
01310af2
FB
1969
1970 event_loop();
1971
1972 /* never returns */
1973
1974 return 0;
1975}