add q command to exit
[fbff.git] / fbff.c
blob5129b5ca41baab348c22ae5bb69fe06d466b49c0
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 count;
30 static struct termios termios;
32 static void init_streams(void)
34 int i;
35 for (i = 0; i < fc->nb_streams; i++) {
36 if (fc->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO)
37 vsi = i;
38 if (fc->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO)
39 asi = i;
41 if (vsi != -1) {
42 vcc = fc->streams[vsi]->codec;
43 vc = avcodec_find_decoder(vcc->codec_id);
44 avcodec_open(vcc, vc);
46 if (asi != -1) {
47 acc = fc->streams[asi]->codec;
48 ac = avcodec_find_decoder(acc->codec_id);
49 avcodec_open(acc, ac);
53 static void draw_frame(void)
55 fbval_t buf[1 << 14];
56 int r, c;
57 int nr = MIN(vcc->height * ZOOM, fb_rows() / ZOOM2);
58 int nc = MIN(vcc->width * ZOOM, fb_cols() / ZOOM2);
59 int i;
60 for (r = 0; r < nr; r++) {
61 unsigned char *row = frame->data[0] + r * frame->linesize[0];
62 for (c = 0; c < nc; c++) {
63 fbval_t v = fb_color(row[c * 3],
64 row[c * 3 + 1],
65 row[c * 3 + 2]);
66 for (i = 0; i < ZOOM2; i++)
67 buf[c * ZOOM2 + i] = v;
69 for (i = 0; i < ZOOM2; i++)
70 fb_set(r * ZOOM2 + i, 0, buf, nc * ZOOM2);
74 static void decode_video_frame(AVFrame *main_frame, AVPacket *packet)
76 int fine = 0;
77 avcodec_decode_video2(vcc, main_frame, &fine, packet);
78 if (fine) {
79 sws_scale(swsc, main_frame->data, main_frame->linesize,
80 0, vcc->height, frame->data, frame->linesize);
81 draw_frame();
85 #define AUDIOBUFSIZE (1 << 20)
87 static void decode_audio_frame(AVPacket *pkt)
89 char buf[AUDIOBUFSIZE];
90 AVPacket tmppkt;
91 tmppkt.size = pkt->size;
92 tmppkt.data = pkt->data;
93 while (tmppkt.size > 0) {
94 int size = sizeof(buf);
95 int len = avcodec_decode_audio3(acc, (int16_t *) buf,
96 &size, &tmppkt);
97 if (len < 0)
98 break;
99 if (size <= 0)
100 continue;
101 if (snd_pcm_writei(alsa, buf, size / bps) < 0)
102 snd_pcm_prepare(alsa);
103 tmppkt.size -= len;
104 tmppkt.data += len;
107 static int readkey(void)
109 char b;
110 if (read(STDIN_FILENO, &b, 1) <= 0)
111 return -1;
112 return b;
115 static int execkey(void)
117 int c;
118 while ((c = readkey()) != -1) {
119 switch (c) {
120 case 'q':
121 return 1;
122 case 27:
123 count = 0;
124 break;
125 default:
126 if (isdigit(c))
127 count = count * 10 + c - '0';
130 return 0;
133 static void read_frames(void)
135 AVFrame *main_frame = avcodec_alloc_frame();
136 AVPacket pkt;
137 uint8_t *buf;
138 int n = AUDIOBUFSIZE;
139 if (vcc)
140 n = avpicture_get_size(PIX_FMT_RGB24, vcc->width * ZOOM,
141 vcc->height * ZOOM);
142 buf = av_malloc(n * sizeof(uint8_t));
143 if (vcc)
144 avpicture_fill((AVPicture *) frame, buf, PIX_FMT_RGB24,
145 vcc->width * ZOOM, vcc->height * ZOOM);
146 while (av_read_frame(fc, &pkt) >= 0) {
147 if (vcc && pkt.stream_index == vsi)
148 decode_video_frame(main_frame, &pkt);
149 if (acc && pkt.stream_index == asi)
150 decode_audio_frame(&pkt);
151 av_free_packet(&pkt);
152 if (execkey())
153 break;
155 av_free(buf);
156 av_free(main_frame);
159 #define ALSADEV "default"
161 static void alsa_init(void)
163 int format = SND_PCM_FORMAT_S16_LE;
164 if (snd_pcm_open(&alsa, ALSADEV, SND_PCM_STREAM_PLAYBACK, 0) < 0)
165 return;
166 snd_pcm_set_params(alsa, format, SND_PCM_ACCESS_RW_INTERLEAVED,
167 acc->channels, acc->sample_rate, 1, 500000);
168 bps = acc->channels * snd_pcm_format_physical_width(format) / 8;
169 snd_pcm_prepare(alsa);
172 static void alsa_close(void)
174 snd_pcm_close(alsa);
177 static void term_setup(void)
179 struct termios newtermios;
180 tcgetattr(STDIN_FILENO, &termios);
181 newtermios = termios;
182 cfmakeraw(&newtermios);
183 tcsetattr(STDIN_FILENO, TCSAFLUSH, &newtermios);
184 fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
187 static void term_cleanup(void)
189 tcsetattr(STDIN_FILENO, 0, &termios);
192 int main(int argc, char *argv[])
194 if (argc < 2) {
195 printf("usage: %s filename\n", argv[0]);
196 return 1;
198 av_register_all();
199 if (av_open_input_file(&fc, argv[1], NULL, 0, NULL))
200 return 1;
201 if (av_find_stream_info(fc) < 0)
202 return 1;
203 init_streams();
204 frame = avcodec_alloc_frame();
205 if (acc)
206 alsa_init();
207 if (vcc) {
208 swsc = sws_getContext(vcc->width, vcc->height, vcc->pix_fmt,
209 vcc->width * ZOOM, vcc->height * ZOOM,
210 PIX_FMT_RGB24, SWS_FAST_BILINEAR | SWS_CPU_CAPS_MMX2,
211 NULL, NULL, NULL);
212 fb_init();
215 term_setup();
216 read_frames();
217 term_cleanup();
219 if (vcc) {
220 fb_free();
221 sws_freeContext(swsc);
222 avcodec_close(vcc);
224 if (acc) {
225 alsa_close();
226 avcodec_close(acc);
228 av_free(frame);
229 av_close_input_file(fc);
230 return 0;