Ported from OSS to ALSA, via tinyalsa.
[fbff.git] / ffs.c
blobdcebb4519461fcc59faa2fe05d61300ea145ee28
1 #include <fcntl.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4 #include <unistd.h>
5 #include <sys/time.h>
6 #include <libavcodec/avcodec.h>
7 #include <libavformat/avformat.h>
8 #include <libswresample/swresample.h>
9 #include <libswscale/swscale.h>
10 #include "ffs.h"
12 #define FFS_SAMPLEFMT AV_SAMPLE_FMT_S16
13 #define FFS_CHLAYOUT AV_CH_LAYOUT_STEREO
15 #define MAX(a, b) ((a) < (b) ? (b) : (a))
16 #define MIN(a, b) ((a) < (b) ? (a) : (b))
18 /* ffmpeg stream */
19 struct ffs {
20 AVCodecContext *cc;
21 AVFormatContext *fc;
22 AVStream *st;
23 AVPacket pkt;
24 int si; /* stream index */
25 long ts; /* frame timestamp (ms) */
26 long pts; /* last decoded packet pts in milliseconds */
27 long dur; /* last decoded packet duration */
29 /* decoding video frames */
30 struct SwsContext *swsc;
31 struct SwrContext *swrc;
32 AVFrame *dst;
33 AVFrame *tmp;
36 static int ffs_stype(int flags)
38 if (flags & FFS_VIDEO)
39 return AVMEDIA_TYPE_VIDEO;
40 if (flags & FFS_AUDIO)
41 return AVMEDIA_TYPE_AUDIO;
42 if (flags & FFS_SUBTS)
43 return AVMEDIA_TYPE_SUBTITLE;
44 return 0;
47 struct ffs *ffs_alloc(char *path, int flags)
49 struct ffs *ffs;
50 int idx = (flags & FFS_STRIDX) - 1;
51 AVDictionary *opt = NULL;
52 ffs = malloc(sizeof(*ffs));
53 memset(ffs, 0, sizeof(*ffs));
54 ffs->si = -1;
55 if (avformat_open_input(&ffs->fc, path, NULL, NULL))
56 goto failed;
57 if (avformat_find_stream_info(ffs->fc, NULL) < 0)
58 goto failed;
59 ffs->si = av_find_best_stream(ffs->fc, ffs_stype(flags), idx, -1, NULL, 0);
60 if (ffs->si < 0)
61 goto failed;
62 ffs->cc = ffs->fc->streams[ffs->si]->codec;
63 if (avcodec_open2(ffs->cc, avcodec_find_decoder(ffs->cc->codec_id), &opt))
64 goto failed;
65 ffs->st = ffs->fc->streams[ffs->si];
66 ffs->tmp = av_frame_alloc();
67 ffs->dst = av_frame_alloc();
68 return ffs;
69 failed:
70 ffs_free(ffs);
71 return NULL;
74 void ffs_free(struct ffs *ffs)
76 if (ffs->swrc)
77 swr_free(&ffs->swrc);
78 if (ffs->swsc)
79 sws_freeContext(ffs->swsc);
80 if (ffs->dst)
81 av_free(ffs->dst);
82 if (ffs->tmp)
83 av_free(ffs->tmp);
84 if (ffs->cc)
85 avcodec_close(ffs->cc);
86 if (ffs->fc)
87 avformat_close_input(&ffs->fc);
88 free(ffs);
91 static AVPacket *ffs_pkt(struct ffs *ffs)
93 AVPacket *pkt = &ffs->pkt;
94 while (av_read_frame(ffs->fc, pkt) >= 0) {
95 if (pkt->stream_index == ffs->si) {
96 long pts = (pkt->dts == AV_NOPTS_VALUE ? 0 : pkt->dts) *
97 av_q2d(ffs->st->time_base) * 1000;
98 ffs->dur = MIN(MAX(0, pts - ffs->pts), 1000);
99 if (pts > ffs->pts || pts + 200 < ffs->pts)
100 ffs->pts = pts;
101 return pkt;
103 av_free_packet(pkt);
105 return NULL;
108 static long ts_ms(void)
110 struct timeval tv;
111 gettimeofday(&tv, NULL);
112 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
115 static int wait(long ts, int vdelay)
117 long nts = ts_ms();
118 if (nts > ts && ts + vdelay > nts) {
119 usleep((ts + vdelay - nts) * 1000);
120 return 0;
122 return 1;
125 void ffs_wait(struct ffs *ffs)
127 int vdelay = ffs->dur;
128 if (!wait(ffs->ts, MAX(vdelay, 20)))
129 ffs->ts += MAX(vdelay, 20);
130 else
131 ffs->ts = ts_ms(); /* out of sync */
134 /* audio/video frame offset difference */
135 int ffs_avdiff(struct ffs *ffs, struct ffs *affs)
137 return affs->pts - ffs->pts;
140 long ffs_pos(struct ffs *ffs)
142 return ffs->pts;
145 void ffs_seek(struct ffs *ffs, struct ffs *vffs, long pos)
147 av_seek_frame(ffs->fc, vffs->si,
148 pos / av_q2d(vffs->st->time_base) / 1000, 0);
149 ffs->ts = 0;
152 void ffs_vinfo(struct ffs *ffs, int *w, int *h)
154 *h = ffs->cc->height;
155 *w = ffs->cc->width;
158 void ffs_ainfo(struct ffs *ffs, int *rate, int *bps, int *ch)
160 *rate = ffs->cc->sample_rate;
161 *ch = av_get_channel_layout_nb_channels(FFS_CHLAYOUT);
162 *bps = 16;
165 int ffs_vdec(struct ffs *ffs, void **buf)
167 AVCodecContext *vcc = ffs->cc;
168 AVPacket *pkt = ffs_pkt(ffs);
169 int fine = 0;
170 if (!pkt)
171 return -1;
172 avcodec_decode_video2(vcc, ffs->tmp, &fine, pkt);
173 av_free_packet(pkt);
174 if (fine && buf) {
175 sws_scale(ffs->swsc, (void *) ffs->tmp->data, ffs->tmp->linesize,
176 0, vcc->height, ffs->dst->data, ffs->dst->linesize);
177 *buf = (void *) ffs->dst->data[0];
178 return ffs->dst->linesize[0];
180 return 0;
183 int ffs_sdec(struct ffs *ffs, char *buf, int blen, long *beg, long *end)
185 AVPacket *pkt = ffs_pkt(ffs);
186 AVSubtitle sub = {0};
187 AVSubtitleRect *rect;
188 int fine = 0;
189 int i;
190 if (!pkt)
191 return -1;
192 avcodec_decode_subtitle2(ffs->cc, &sub, &fine, pkt);
193 av_free_packet(pkt);
194 buf[0] = '\0';
195 if (!fine)
196 return 1;
197 rect = sub.num_rects ? sub.rects[0] : NULL;
198 if (rect && rect->text)
199 snprintf(buf, blen, "%s", sub.rects[0]->text);
200 if (rect && !rect->text && rect->ass) {
201 char *s = rect->ass;
202 for (i = 0; s && i < 9; i++)
203 s = strchr(s, ',') ? strchr(s, ',') + 1 : NULL;
204 if (s)
205 snprintf(buf, blen, "%s", s);
207 if (strchr(buf, '\n'))
208 *strchr(buf, '\n') = '\0';
209 *beg = ffs->pts + sub.start_display_time * av_q2d(ffs->st->time_base) * 1000;
210 *end = ffs->pts + sub.end_display_time * av_q2d(ffs->st->time_base) * 1000;
211 avsubtitle_free(&sub);
212 return 0;
215 static int ffs_bytespersample(ffs)
217 return av_get_bytes_per_sample(FFS_SAMPLEFMT) *
218 av_get_channel_layout_nb_channels(FFS_CHLAYOUT);
221 int ffs_adec(struct ffs *ffs, void *buf, int blen)
223 int rdec = 0;
224 AVPacket tmppkt = {0};
225 AVPacket *pkt = ffs_pkt(ffs);
226 uint8_t *out[] = {NULL};
227 if (!pkt)
228 return -1;
229 tmppkt.size = pkt->size;
230 tmppkt.data = pkt->data;
231 while (tmppkt.size > 0) {
232 int len, size;
233 len = avcodec_decode_audio4(ffs->cc, ffs->tmp, &size, &tmppkt);
234 if (len < 0)
235 break;
236 tmppkt.size -= len;
237 tmppkt.data += len;
238 if (size <= 0)
239 continue;
240 out[0] = buf + rdec;
241 len = swr_convert(ffs->swrc,
242 out, (blen - rdec) / ffs_bytespersample(ffs),
243 (void *) ffs->tmp->extended_data, ffs->tmp->nb_samples);
244 if (len > 0)
245 rdec += len * ffs_bytespersample(ffs);
247 av_free_packet(pkt);
248 return rdec;
251 static int fbm2pixfmt(int fbm)
253 switch (fbm & 0x0fff) {
254 case 0x888:
255 return PIX_FMT_RGB32;
256 case 0x565:
257 return PIX_FMT_RGB565;
258 case 0x233:
259 return PIX_FMT_RGB8;
260 default:
261 fprintf(stderr, "ffs: unknown fb_mode()\n");
262 return PIX_FMT_RGB32;
266 void ffs_vconf(struct ffs *ffs, float zoom, int fbm)
268 int h = ffs->cc->height;
269 int w = ffs->cc->width;
270 int fmt = ffs->cc->pix_fmt;
271 int pixfmt = fbm2pixfmt(fbm);
272 uint8_t *buf = NULL;
273 int n;
274 ffs->swsc = sws_getContext(w, h, fmt, w * zoom, h * zoom,
275 pixfmt, SWS_FAST_BILINEAR | SWS_CPU_CAPS_MMX2,
276 NULL, NULL, NULL);
277 n = avpicture_get_size(pixfmt, w * zoom, h * zoom);
278 buf = av_malloc(n * sizeof(uint8_t));
279 avpicture_fill((AVPicture *) ffs->dst, buf, pixfmt, w * zoom, h * zoom);
282 void ffs_aconf(struct ffs *ffs)
284 int rate, bps, ch;
285 ffs_ainfo(ffs, &rate, &bps, &ch);
286 ffs->swrc = swr_alloc_set_opts(NULL,
287 FFS_CHLAYOUT, FFS_SAMPLEFMT, rate,
288 ffs->cc->channel_layout, ffs->cc->sample_fmt, ffs->cc->sample_rate,
289 0, NULL);
290 swr_init(ffs->swrc);
293 void ffs_globinit(void)
295 av_register_all();
296 avformat_network_init();
299 long ffs_duration(struct ffs *ffs)
301 if (ffs->st->duration != AV_NOPTS_VALUE)
302 return ffs->st->duration * av_q2d(ffs->st->time_base) * 1000;
303 if (ffs->fc->duration > 0)
304 return ffs->fc->duration / (AV_TIME_BASE / 1000);
305 return 0;