show basic status
[fbff.git] / fbff.c
blob06f388666a5f12337228c51b36a62057cdde05a0
1 #include <fcntl.h>
2 #include <pty.h>
3 #include <stdint.h>
4 #include <termios.h>
5 #include <unistd.h>
6 #include <alsa/asoundlib.h>
7 #include <libavformat/avformat.h>
8 #include <libavcodec/avcodec.h>
9 #include <libswscale/swscale.h>
10 #include "draw.h"
12 #define ZOOM 1
13 #define ZOOM2 1
15 static AVFormatContext *fc;
16 static AVFrame *frame;
17 static struct SwsContext *swsc;
19 static int vsi = -1; /* video stream index */
20 static AVCodecContext *vcc; /* video codec context */
21 static AVCodec *vc; /* video codec */
23 static int asi = -1; /* audio stream index */
24 static AVCodecContext *acc; /* audio codec context */
25 static AVCodec *ac; /* audio codec */
27 static snd_pcm_t *alsa;
28 static int bps; /* bytes per sample */
29 static int arg;
30 static struct termios termios;
31 static uint64_t pts;
33 static void init_streams(void)
35 int i;
36 for (i = 0; i < fc->nb_streams; i++) {
37 if (fc->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO)
38 vsi = i;
39 if (fc->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO)
40 asi = i;
42 if (vsi != -1) {
43 vcc = fc->streams[vsi]->codec;
44 vc = avcodec_find_decoder(vcc->codec_id);
45 avcodec_open(vcc, vc);
47 if (asi != -1) {
48 acc = fc->streams[asi]->codec;
49 ac = avcodec_find_decoder(acc->codec_id);
50 avcodec_open(acc, ac);
54 static void draw_frame(void)
56 fbval_t buf[1 << 14];
57 int r, c;
58 int nr = MIN(vcc->height * ZOOM, fb_rows() / ZOOM2);
59 int nc = MIN(vcc->width * ZOOM, fb_cols() / ZOOM2);
60 int i;
61 for (r = 0; r < nr; r++) {
62 unsigned char *row = frame->data[0] + r * frame->linesize[0];
63 for (c = 0; c < nc; c++) {
64 fbval_t v = fb_color(row[c * 3],
65 row[c * 3 + 1],
66 row[c * 3 + 2]);
67 for (i = 0; i < ZOOM2; i++)
68 buf[c * ZOOM2 + i] = v;
70 for (i = 0; i < ZOOM2; i++)
71 fb_set(r * ZOOM2 + i, 0, buf, nc * ZOOM2);
75 static void decode_video_frame(AVFrame *main_frame, AVPacket *packet)
77 int fine = 0;
78 avcodec_decode_video2(vcc, main_frame, &fine, packet);
79 if (fine) {
80 sws_scale(swsc, main_frame->data, main_frame->linesize,
81 0, vcc->height, frame->data, frame->linesize);
82 draw_frame();
86 #define AUDIOBUFSIZE (1 << 20)
88 static void decode_audio_frame(AVPacket *pkt)
90 char buf[AUDIOBUFSIZE];
91 AVPacket tmppkt;
92 tmppkt.size = pkt->size;
93 tmppkt.data = pkt->data;
94 while (tmppkt.size > 0) {
95 int size = sizeof(buf);
96 int len = avcodec_decode_audio3(acc, (int16_t *) buf,
97 &size, &tmppkt);
98 if (len < 0)
99 break;
100 if (size <= 0)
101 continue;
102 if (snd_pcm_writei(alsa, buf, size / bps) < 0)
103 snd_pcm_prepare(alsa);
104 tmppkt.size -= len;
105 tmppkt.data += len;
108 static int readkey(void)
110 char b;
111 if (read(STDIN_FILENO, &b, 1) <= 0)
112 return -1;
113 return b;
116 static int ffarg(void)
118 int n = arg;
119 arg = 0;
120 return n ? n : 1;
123 static int ffpos(void)
125 int idx = vsi != -1 ? vsi : asi;
126 double base = av_q2d(fc->streams[idx]->time_base);
127 return pts * 1000.0 * base / 1000.0;
130 static int fflen(void)
132 int idx = vsi != -1 ? vsi : asi;
133 double base = av_q2d(fc->streams[idx]->time_base);
134 return fc->streams[idx]->duration * 1000.0 * base / 1000.0;
137 static void ffjmp(int n)
139 int t = ffpos() + n;
140 av_seek_frame(fc, -1, t * AV_TIME_BASE, AVSEEK_FLAG_ANY);
143 static void printinfo(void)
145 int loc = (int64_t) ffpos() * 1000 / fflen();
146 int pos = ffpos();
147 printf("fbff: %3d.%d%% %8ds\r", loc / 10, loc % 10, pos);
148 fflush(stdout);
151 #define SHORTJMP (1 << 3)
152 #define NORMJMP (SHORTJMP << 4)
153 #define LONGJMP (NORMJMP << 4)
155 static int execkey(void)
157 int c;
158 while ((c = readkey()) != -1) {
159 switch (c) {
160 case 'q':
161 return 1;
162 case 'l':
163 ffjmp(ffarg() * SHORTJMP);
164 break;
165 case 'h':
166 ffjmp(-ffarg() * SHORTJMP);
167 break;
168 case 'j':
169 ffjmp(ffarg() * NORMJMP);
170 break;
171 case 'k':
172 ffjmp(-ffarg() * NORMJMP);
173 break;
174 case 'J':
175 ffjmp(ffarg() * LONGJMP);
176 break;
177 case 'K':
178 ffjmp(-ffarg() * LONGJMP);
179 break;
180 case 'i':
181 printinfo();
182 break;
183 case 27:
184 arg = 0;
185 break;
186 default:
187 if (isdigit(c))
188 arg = arg * 10 + c - '0';
191 return 0;
194 static void read_frames(void)
196 AVFrame *main_frame = avcodec_alloc_frame();
197 AVPacket pkt;
198 uint8_t *buf;
199 int n = AUDIOBUFSIZE;
200 if (vcc)
201 n = avpicture_get_size(PIX_FMT_RGB24, vcc->width * ZOOM,
202 vcc->height * ZOOM);
203 buf = av_malloc(n * sizeof(uint8_t));
204 if (vcc)
205 avpicture_fill((AVPicture *) frame, buf, PIX_FMT_RGB24,
206 vcc->width * ZOOM, vcc->height * ZOOM);
207 while (av_read_frame(fc, &pkt) >= 0) {
208 if (pts < pkt.pts)
209 pts = pkt.pts;
210 if (vcc && pkt.stream_index == vsi)
211 decode_video_frame(main_frame, &pkt);
212 if (acc && pkt.stream_index == asi)
213 decode_audio_frame(&pkt);
214 av_free_packet(&pkt);
215 if (execkey())
216 break;
218 av_free(buf);
219 av_free(main_frame);
222 #define ALSADEV "default"
224 static void alsa_init(void)
226 int format = SND_PCM_FORMAT_S16_LE;
227 if (snd_pcm_open(&alsa, ALSADEV, SND_PCM_STREAM_PLAYBACK, 0) < 0)
228 return;
229 snd_pcm_set_params(alsa, format, SND_PCM_ACCESS_RW_INTERLEAVED,
230 acc->channels, acc->sample_rate, 1, 500000);
231 bps = acc->channels * snd_pcm_format_physical_width(format) / 8;
232 snd_pcm_prepare(alsa);
235 static void alsa_close(void)
237 snd_pcm_close(alsa);
240 static void term_setup(void)
242 struct termios newtermios;
243 tcgetattr(STDIN_FILENO, &termios);
244 newtermios = termios;
245 cfmakeraw(&newtermios);
246 tcsetattr(STDIN_FILENO, TCSAFLUSH, &newtermios);
247 fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
250 static void term_cleanup(void)
252 tcsetattr(STDIN_FILENO, 0, &termios);
255 int main(int argc, char *argv[])
257 if (argc < 2) {
258 printf("usage: %s filename\n", argv[0]);
259 return 1;
261 av_register_all();
262 if (av_open_input_file(&fc, argv[1], NULL, 0, NULL))
263 return 1;
264 if (av_find_stream_info(fc) < 0)
265 return 1;
266 init_streams();
267 frame = avcodec_alloc_frame();
268 if (acc)
269 alsa_init();
270 if (vcc) {
271 swsc = sws_getContext(vcc->width, vcc->height, vcc->pix_fmt,
272 vcc->width * ZOOM, vcc->height * ZOOM,
273 PIX_FMT_RGB24, SWS_FAST_BILINEAR | SWS_CPU_CAPS_MMX2,
274 NULL, NULL, NULL);
275 fb_init();
278 term_setup();
279 read_frames();
280 term_cleanup();
282 if (vcc) {
283 fb_free();
284 sws_freeContext(swsc);
285 avcodec_close(vcc);
287 if (acc) {
288 alsa_close();
289 avcodec_close(acc);
291 av_free(frame);
292 av_close_input_file(fc);
293 return 0;