ffs: wait at least 1/50s between video frames
[fbff.git] / ffs.c
blobefabb64de891a4e96c2d5131f5b1f79e88183e70
1 #include <fcntl.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4 #include <unistd.h>
5 #include <sys/time.h>
6 #include <libavformat/avformat.h>
7 #include <libavcodec/avcodec.h>
8 #include <libswscale/swscale.h>
9 #include "ffs.h"
11 /* ffmpeg stream */
12 struct ffs {
13 AVCodecContext *cc;
14 AVFormatContext *fc;
15 AVPacket pkt;
16 int si; /* stream index */
17 long ts; /* frame timestamp (ms) */
18 long seq; /* current position in this stream */
19 long seq_all; /* seen packets after ffs_seek() */
20 long seq_cur; /* decoded packet after ffs_seek() */
22 /* decoding video frames */
23 struct SwsContext *swsc;
24 AVFrame *dst;
25 AVFrame *tmp;
28 struct ffs *ffs_alloc(char *path, int video)
30 struct ffs *ffs;
31 int codec_type = video ? CODEC_TYPE_VIDEO : CODEC_TYPE_AUDIO;
32 int i;
33 ffs = malloc(sizeof(*ffs));
34 memset(ffs, 0, sizeof(*ffs));
35 ffs->si = -1;
36 if (av_open_input_file(&ffs->fc, path, NULL, 0, NULL))
37 goto failed;
38 if (av_find_stream_info(ffs->fc) < 0)
39 goto failed;
40 for (i = 0; i < ffs->fc->nb_streams; i++)
41 if (ffs->fc->streams[i]->codec->codec_type == codec_type)
42 ffs->si = i;
43 if (ffs->si == -1)
44 goto failed;
45 ffs->cc = ffs->fc->streams[ffs->si]->codec;
46 avcodec_open(ffs->cc, avcodec_find_decoder(ffs->cc->codec_id));
47 return ffs;
48 failed:
49 ffs_free(ffs);
50 return NULL;
53 void ffs_free(struct ffs *ffs)
55 if (ffs->swsc)
56 sws_freeContext(ffs->swsc);
57 if (ffs->dst)
58 av_free(ffs->dst);
59 if (ffs->tmp)
60 av_free(ffs->tmp);
61 if (ffs->cc)
62 avcodec_close(ffs->cc);
63 if (ffs->fc)
64 av_close_input_file(ffs->fc);
65 free(ffs);
68 static AVPacket *ffs_pkt(struct ffs *ffs)
70 AVPacket *pkt = &ffs->pkt;
71 while (av_read_frame(ffs->fc, pkt) >= 0) {
72 ffs->seq_all++;
73 if (pkt->stream_index == ffs->si) {
74 ffs->seq_cur++;
75 ffs->seq++;
76 return pkt;
78 av_free_packet(pkt);
80 return NULL;
83 static long ts_ms(void)
85 struct timeval tv;
86 gettimeofday(&tv, NULL);
87 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
90 static void wait(long ts, int vdelay)
92 int nts = ts_ms();
93 if (ts + vdelay > nts)
94 usleep((ts + vdelay - nts) * 1000);
97 void ffs_wait(struct ffs *ffs)
99 long ts = ts_ms();
100 if (ts && ffs->ts) {
101 AVRational *r = &ffs->fc->streams[ffs->si]->time_base;
102 int vdelay = 1000 * r->num / r->den;
103 wait(ffs->ts, vdelay < 20 ? 20 : vdelay);
105 ffs->ts = ts_ms();
108 long ffs_pos(struct ffs *ffs, int diff)
110 return (ffs->si << 28) | (ffs->seq + diff);
113 void ffs_seek(struct ffs *ffs, long pos, int perframe)
115 long idx = pos >> 28;
116 long seq = pos & 0x0fffffff;
117 av_seek_frame(ffs->fc, idx, seq * perframe,
118 perframe == 1 ? AVSEEK_FLAG_FRAME : 0);
119 ffs->seq = seq;
120 ffs->seq_all = 0;
121 ffs->seq_cur = 0;
122 ffs->ts = 0;
125 long ffs_seq(struct ffs *ffs, int all)
127 return all ? ffs->seq_all : ffs->seq_cur;
130 void ffs_vinfo(struct ffs *ffs, int *w, int *h)
132 *h = ffs->cc->height;
133 *w = ffs->cc->width;
136 void ffs_ainfo(struct ffs *ffs, int *rate, int *bps, int *ch)
138 *rate = ffs->cc->sample_rate;
139 *ch = ffs->cc->channels;
140 *bps = 16;
143 int ffs_vdec(struct ffs *ffs, char **buf)
145 AVCodecContext *vcc = ffs->cc;
146 AVPacket *pkt = ffs_pkt(ffs);
147 int fine = 0;
148 if (!pkt)
149 return -1;
150 avcodec_decode_video2(vcc, ffs->tmp, &fine, pkt);
151 av_free_packet(pkt);
152 if (fine && buf) {
153 sws_scale(ffs->swsc, ffs->tmp->data, ffs->tmp->linesize,
154 0, vcc->height, ffs->dst->data, ffs->dst->linesize);
155 *buf = (void *) ffs->dst->data[0];
156 return ffs->dst->linesize[0];
158 return 0;
161 int ffs_adec(struct ffs *ffs, char *buf, int blen)
163 int rdec = 0;
164 AVPacket tmppkt;
165 AVPacket *pkt = ffs_pkt(ffs);
166 if (!pkt)
167 return -1;
168 tmppkt.size = pkt->size;
169 tmppkt.data = pkt->data;
170 while (tmppkt.size > 0) {
171 int size = blen - rdec;
172 int len = avcodec_decode_audio3(ffs->cc, (int16_t *) (buf + rdec),
173 &size, &tmppkt);
174 if (len < 0)
175 break;
176 tmppkt.size -= len;
177 tmppkt.data += len;
178 if (size > 0)
179 rdec += size;
181 av_free_packet(pkt);
182 return rdec;
185 void ffs_vsetup(struct ffs *ffs, float zoom, int pixfmt)
187 int h = ffs->cc->height;
188 int w = ffs->cc->width;
189 int fmt = ffs->cc->pix_fmt;
190 uint8_t *buf = NULL;
191 int n;
192 ffs->swsc = sws_getContext(w, h, fmt, w * zoom, h * zoom,
193 pixfmt, SWS_FAST_BILINEAR | SWS_CPU_CAPS_MMX2,
194 NULL, NULL, NULL);
195 ffs->dst = avcodec_alloc_frame();
196 ffs->tmp = avcodec_alloc_frame();
197 n = avpicture_get_size(pixfmt, w * zoom, h * zoom);
198 buf = av_malloc(n * sizeof(uint8_t));
199 avpicture_fill((AVPicture *) ffs->dst, buf, pixfmt, w * zoom, h * zoom);
202 void ffs_globinit(void)
204 av_register_all();