6 #include <alsa/asoundlib.h>
7 #include <libavformat/avformat.h>
8 #include <libavcodec/avcodec.h>
9 #include <libswscale/swscale.h>
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 */
30 static struct termios termios
;
33 static void init_streams(void)
36 for (i
= 0; i
< fc
->nb_streams
; i
++) {
37 if (fc
->streams
[i
]->codec
->codec_type
== CODEC_TYPE_VIDEO
)
39 if (fc
->streams
[i
]->codec
->codec_type
== CODEC_TYPE_AUDIO
)
43 vcc
= fc
->streams
[vsi
]->codec
;
44 vc
= avcodec_find_decoder(vcc
->codec_id
);
45 avcodec_open(vcc
, vc
);
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)
58 int nr
= MIN(vcc
->height
* ZOOM
, fb_rows() / ZOOM2
);
59 int nc
= MIN(vcc
->width
* ZOOM
, fb_cols() / ZOOM2
);
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],
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
)
78 avcodec_decode_video2(vcc
, main_frame
, &fine
, packet
);
80 sws_scale(swsc
, main_frame
->data
, main_frame
->linesize
,
81 0, vcc
->height
, frame
->data
, frame
->linesize
);
86 #define AUDIOBUFSIZE (1 << 20)
88 static void decode_audio_frame(AVPacket
*pkt
)
90 char buf
[AUDIOBUFSIZE
];
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
,
102 if (snd_pcm_writei(alsa
, buf
, size
/ bps
) < 0)
103 snd_pcm_prepare(alsa
);
108 static int readkey(void)
111 if (read(STDIN_FILENO
, &b
, 1) <= 0)
116 static void waitkey(void)
118 struct pollfd ufds
[1];
119 ufds
[0].fd
= STDIN_FILENO
;
120 ufds
[0].events
= POLLIN
;
124 static int ffarg(void)
131 static int ffpos(void)
133 int idx
= vsi
!= -1 ? vsi
: asi
;
134 double base
= av_q2d(fc
->streams
[idx
]->time_base
);
135 return pts
* 1000.0 * base
/ 1000.0;
138 static int fflen(void)
140 return fc
->duration
/ AV_TIME_BASE
;
143 static void ffjmp(int n
, int rel
)
145 int t
= MAX(0, MIN(fflen(), rel
? ffpos() + n
: n
));
146 av_seek_frame(fc
, -1, t
* AV_TIME_BASE
, AVSEEK_FLAG_ANY
);
149 static void printinfo(void)
151 int loc
= (int64_t) ffpos() * 1000 / fflen();
153 printf("fbff: %3d.%d%% %8ds\r", loc
/ 10, loc
% 10, pos
);
157 #define SHORTJMP (1 << 3)
158 #define NORMJMP (SHORTJMP << 4)
159 #define LONGJMP (NORMJMP << 4)
165 static int execkey(void)
168 while ((c
= readkey()) != -1) {
173 ffjmp(ffarg() * SHORTJMP
, 1);
176 ffjmp(-ffarg() * SHORTJMP
, 1);
179 ffjmp(ffarg() * NORMJMP
, 1);
182 ffjmp(-ffarg() * NORMJMP
, 1);
185 ffjmp(ffarg() * LONGJMP
, 1);
188 ffjmp(-ffarg() * LONGJMP
, 1);
192 ffjmp(ffarg() * fflen() / 100, 0);
206 arg
= arg
* 10 + c
- '0';
212 static void read_frames(void)
214 AVFrame
*main_frame
= avcodec_alloc_frame();
217 int n
= AUDIOBUFSIZE
;
219 n
= avpicture_get_size(PIX_FMT_RGB24
, vcc
->width
* ZOOM
,
221 buf
= av_malloc(n
* sizeof(uint8_t));
223 avpicture_fill((AVPicture
*) frame
, buf
, PIX_FMT_RGB24
,
224 vcc
->width
* ZOOM
, vcc
->height
* ZOOM
);
225 while (av_read_frame(fc
, &pkt
) >= 0) {
226 if (pts
< pkt
.pts
&& pkt
.pts
< (1ull << 60))
228 if (vcc
&& pkt
.stream_index
== vsi
)
229 decode_video_frame(main_frame
, &pkt
);
230 if (acc
&& pkt
.stream_index
== asi
)
231 decode_audio_frame(&pkt
);
232 av_free_packet(&pkt
);
237 while (readkey() != 'p')
247 #define ALSADEV "default"
249 static void alsa_init(void)
251 int format
= SND_PCM_FORMAT_S16_LE
;
252 if (snd_pcm_open(&alsa
, ALSADEV
, SND_PCM_STREAM_PLAYBACK
, 0) < 0)
254 snd_pcm_set_params(alsa
, format
, SND_PCM_ACCESS_RW_INTERLEAVED
,
255 acc
->channels
, acc
->sample_rate
, 1, 500000);
256 bps
= acc
->channels
* snd_pcm_format_physical_width(format
) / 8;
257 snd_pcm_prepare(alsa
);
260 static void alsa_close(void)
265 static void term_setup(void)
267 struct termios newtermios
;
268 tcgetattr(STDIN_FILENO
, &termios
);
269 newtermios
= termios
;
270 cfmakeraw(&newtermios
);
271 tcsetattr(STDIN_FILENO
, TCSAFLUSH
, &newtermios
);
272 fcntl(STDIN_FILENO
, F_SETFL
, fcntl(STDIN_FILENO
, F_GETFL
) | O_NONBLOCK
);
275 static void term_cleanup(void)
277 tcsetattr(STDIN_FILENO
, 0, &termios
);
280 int main(int argc
, char *argv
[])
283 printf("usage: %s filename\n", argv
[0]);
287 if (av_open_input_file(&fc
, argv
[1], NULL
, 0, NULL
))
289 if (av_find_stream_info(fc
) < 0)
292 frame
= avcodec_alloc_frame();
296 swsc
= sws_getContext(vcc
->width
, vcc
->height
, vcc
->pix_fmt
,
297 vcc
->width
* ZOOM
, vcc
->height
* ZOOM
,
298 PIX_FMT_RGB24
, SWS_FAST_BILINEAR
| SWS_CPU_CAPS_MMX2
,
309 sws_freeContext(swsc
);
317 av_close_input_file(fc
);