2 * fbff - a small ffmpeg-based framebuffer/oss media player
4 * Copyright (C) 2009-2011 Ali Gholami Rudi
6 * This program is released under GNU GPL version 2.
19 #include <sys/soundcard.h>
21 #include <libavcodec/avcodec.h>
30 static int frame_jmp
= 1; /* the changes to pos_cur for each frame */
31 static int afd
; /* oss fd */
34 static struct termios termios
;
37 static float zoom
= 1;
38 static int magnify
= 0;
40 static int fullscreen
= 0;
45 static struct ffs
*affs
; /* audio ffmpeg stream */
46 static struct ffs
*vffs
; /* video ffmpeg stream */
48 static void draw_frame(fbval_t
*img
, int linelen
)
54 ffs_vinfo(vffs
, &w
, &h
);
55 nr
= MIN(h
* zoom
, fb_rows() / magnify
);
56 nc
= MIN(w
* zoom
, fb_cols() / magnify
);
57 cb
= just
? fb_cols() - nc
* magnify
: 0;
58 for (r
= 0; r
< nr
; r
++) {
59 fbval_t
*row
= (void *) img
+ r
* linelen
;
61 fb_set(r
, cb
, row
, nc
);
64 for (c
= 0; c
< nc
; c
++)
65 for (i
= 0; i
< magnify
; i
++)
66 buf
[c
* magnify
+ i
] = row
[c
];
67 for (i
= 0; i
< magnify
; i
++)
68 fb_set(r
* magnify
+ i
, cb
, buf
, nc
* magnify
);
72 #define ABUFSZ (1 << 18)
76 static char a_buf
[BUFS
][ABUFSZ
];
77 static int a_len
[BUFS
];
80 static int a_conswait(void)
82 return a_cons
== a_prod
;
85 static int a_prodwait(void)
87 return ((a_prod
+ 1) & (BUFS
- 1)) == a_cons
;
90 static void a_doreset(int pause
)
93 while (audio
&& a_reset
)
97 static int readkey(void)
100 if (read(STDIN_FILENO
, &b
, 1) <= 0)
105 static void waitkey(void)
107 struct pollfd ufds
[1];
108 ufds
[0].fd
= STDIN_FILENO
;
109 ufds
[0].events
= POLLIN
;
113 static int ffarg(void)
120 static void ffjmp(int n
, int rel
)
122 struct ffs
*ffs
= video
? vffs
: affs
;
123 long pos
= ffs_pos(ffs
, n
);
126 ffs_seek(affs
, pos
, frame_jmp
);
128 ffs_seek(vffs
, pos
, frame_jmp
);
131 static void printinfo(void)
133 struct ffs
*ffs
= video
? vffs
: affs
;
134 printf("fbff: %8lx\r", ffs_pos(ffs
, 0));
138 #define JMP1 (1 << 5)
139 #define JMP2 (JMP1 << 3)
140 #define JMP3 (JMP2 << 5)
142 static void execkey(void)
145 while ((c
= readkey()) != -1) {
151 ffjmp(ffarg() * JMP1
, 1);
154 ffjmp(-ffarg() * JMP1
, 1);
157 ffjmp(ffarg() * JMP2
, 1);
160 ffjmp(-ffarg() * JMP2
, 1);
163 ffjmp(ffarg() * JMP3
, 1);
166 ffjmp(-ffarg() * JMP3
, 1);
177 cmd
= cmd
? FF_PLAY
: FF_PAUSE
;
184 arg
= arg
* 10 + c
- '0';
189 static int is_vsync(void)
191 int cur
= ffs_seq(affs
, 0);
192 int all
= ffs_seq(affs
, 1);
193 int ratio
= all
? (all
- cur
) * 1024 / all
: 512;
194 int avdiff
= BUFS
* 4 * ratio
/ 1024;
195 return ffs_seq(vffs
, 1) + avdiff
< ffs_seq(affs
, 1);
198 static void mainloop(void)
200 while (cmd
!= FF_EXIT
) {
202 if (cmd
== FF_PAUSE
) {
207 while (audio
&& !a_prodwait()) {
208 int ret
= ffs_adec(affs
, a_buf
[a_prod
], ABUFSZ
);
213 a_prod
= (a_prod
+ 1) & (BUFS
- 1);
216 if (video
&& (!audio
|| is_vsync())) {
217 int ignore
= jump
&& !(ffs_seq(vffs
, 0) % (jump
+ 1));
219 int ret
= ffs_vdec(vffs
, ignore
? NULL
: &buf
);
223 draw_frame((void *) buf
, ret
);
232 static void oss_init(void)
235 afd
= open("/dev/dsp", O_RDWR
);
237 fprintf(stderr
, "cannot open /dev/dsp\n");
240 ffs_ainfo(affs
, &rate
, &bps
, &ch
);
241 ioctl(afd
, SOUND_PCM_WRITE_RATE
, &rate
);
242 ioctl(afd
, SOUND_PCM_WRITE_CHANNELS
, &ch
);
243 ioctl(afd
, SOUND_PCM_WRITE_BITS
, &bps
);
246 static void oss_close(void)
251 static void *process_audio(void *dat
)
255 while (!a_reset
&& (a_conswait() || cmd
== FF_PAUSE
)) {
266 write(afd
, a_buf
[a_cons
], a_len
[a_cons
]);
267 a_cons
= (a_cons
+ 1) & (BUFS
- 1);
274 static void term_setup(void)
276 struct termios newtermios
;
277 tcgetattr(STDIN_FILENO
, &termios
);
278 newtermios
= termios
;
279 newtermios
.c_lflag
&= ~ICANON
;
280 newtermios
.c_lflag
&= ~ECHO
;
281 tcsetattr(STDIN_FILENO
, TCSAFLUSH
, &newtermios
);
282 fcntl(STDIN_FILENO
, F_SETFL
, fcntl(STDIN_FILENO
, F_GETFL
) | O_NONBLOCK
);
285 static void term_cleanup(void)
287 tcsetattr(STDIN_FILENO
, 0, &termios
);
290 static void sigcont(int sig
)
295 static char *usage
= "usage: fbff [options] file\n"
297 " -m x magnify the screen by repeating pixels\n"
298 " -z x zoom the screen using ffmpeg\n"
299 " -j x jump every x video frames; for slow machines\n"
300 " -f start full screen\n"
301 " -v video only playback\n"
302 " -a audio only playback\n"
303 " -t use time based seeking; only if the default does't work\n"
304 " -R adjust the video to the right of the screen\n\n";
306 static void read_args(int argc
, char *argv
[])
310 if (!strcmp(argv
[i
], "-m"))
311 magnify
= atoi(argv
[++i
]);
312 if (!strcmp(argv
[i
], "-z"))
313 zoom
= atof(argv
[++i
]);
314 if (!strcmp(argv
[i
], "-j"))
315 jump
= atoi(argv
[++i
]);
316 if (!strcmp(argv
[i
], "-f"))
318 if (!strcmp(argv
[i
], "-a"))
320 if (!strcmp(argv
[i
], "-v"))
322 if (!strcmp(argv
[i
], "-t"))
323 frame_jmp
= 1024 / 32;
324 if (!strcmp(argv
[i
], "-h"))
326 if (!strcmp(argv
[i
], "-R"))
332 int main(int argc
, char *argv
[])
335 char *path
= argv
[argc
- 1];
337 printf("usage: %s [options] filename\n", argv
[0]);
340 read_args(argc
, argv
);
342 if (video
&& !(vffs
= ffs_alloc(path
, 1)))
344 if (audio
&& !(affs
= ffs_alloc(path
, 0)))
346 if (!video
&& !audio
)
349 pthread_create(&a_thread
, NULL
, process_audio
, NULL
);
353 ffs_vinfo(vffs
, &w
, &h
);
355 magnify
= fb_cols() / w
/ zoom
;
357 zoom
= (float) fb_cols() / w
/ magnify
;
358 ffs_vsetup(vffs
, zoom
, FFMPEG_PIXFMT
);
361 signal(SIGCONT
, sigcont
);
370 pthread_join(a_thread
, NULL
);