fbff: change process group if TERM_PGID is defined
[fbff.git] / ffs.c
blobfe4cb749d0134f3acbc15fdda5208668c85e254b
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 <libavutil/imgutils.h>
9 #include <libavutil/opt.h>
10 #include <libswresample/swresample.h>
11 #include <libswscale/swscale.h>
12 #include "ffs.h"
14 #define FFS_SAMPLEFMT AV_SAMPLE_FMT_S16
15 #define FFS_CHLAYOUT AV_CH_LAYOUT_STEREO
16 #define FFS_CHCNT 2
18 #define MAX(a, b) ((a) < (b) ? (b) : (a))
19 #define MIN(a, b) ((a) < (b) ? (a) : (b))
21 /* ffmpeg stream */
22 struct ffs {
23 AVCodecContext *cc;
24 AVFormatContext *fc;
25 AVStream *st;
26 AVPacket pkt; /* used in ffs_pkt() */
27 int si; /* stream index */
28 long ts; /* frame timestamp (ms) */
29 long pts; /* last decoded packet pts in milliseconds */
30 long dur; /* last decoded packet duration */
31 struct SwsContext *swsc;
32 struct SwrContext *swrc;
33 AVFrame *dst; /* used in ffs_vdec() */
34 AVFrame *tmp; /* used in ffs_recv() */
37 static int ffs_stype(int flags)
39 if (flags & FFS_VIDEO)
40 return AVMEDIA_TYPE_VIDEO;
41 if (flags & FFS_AUDIO)
42 return AVMEDIA_TYPE_AUDIO;
43 if (flags & FFS_SUBTS)
44 return AVMEDIA_TYPE_SUBTITLE;
45 return 0;
48 struct ffs *ffs_alloc(char *path, int flags)
50 struct ffs *ffs;
51 int idx = (flags & FFS_STRIDX) - 1;
52 AVDictionary *opt = NULL;
53 const AVCodec *dec = NULL;
54 ffs = malloc(sizeof(*ffs));
55 memset(ffs, 0, sizeof(*ffs));
56 ffs->si = -1;
57 if (avformat_open_input(&ffs->fc, path, NULL, NULL))
58 goto failed;
59 if (avformat_find_stream_info(ffs->fc, NULL) < 0)
60 goto failed;
61 ffs->si = av_find_best_stream(ffs->fc, ffs_stype(flags), idx, -1, NULL, 0);
62 if (ffs->si < 0)
63 goto failed;
64 dec = avcodec_find_decoder(ffs->fc->streams[ffs->si]->codecpar->codec_id);
65 if (dec == NULL)
66 goto failed;
67 ffs->cc = avcodec_alloc_context3(dec);
68 if (ffs->cc == NULL)
69 goto failed;
70 avcodec_parameters_to_context(ffs->cc, ffs->fc->streams[ffs->si]->codecpar);
71 if (avcodec_open2(ffs->cc, avcodec_find_decoder(ffs->cc->codec_id), &opt))
72 goto failed;
73 ffs->st = ffs->fc->streams[ffs->si];
74 ffs->tmp = av_frame_alloc();
75 ffs->dst = av_frame_alloc();
76 return ffs;
77 failed:
78 ffs_free(ffs);
79 return NULL;
82 void ffs_free(struct ffs *ffs)
84 if (ffs->swrc)
85 swr_free(&ffs->swrc);
86 if (ffs->swsc)
87 sws_freeContext(ffs->swsc);
88 if (ffs->dst)
89 av_free(ffs->dst);
90 if (ffs->tmp)
91 av_free(ffs->tmp);
92 if (ffs->cc)
93 avcodec_close(ffs->cc);
94 if (ffs->fc)
95 avformat_close_input(&ffs->fc);
96 free(ffs);
99 static AVPacket *ffs_pkt(struct ffs *ffs)
101 AVPacket *pkt = &ffs->pkt;
102 while (av_read_frame(ffs->fc, pkt) >= 0) {
103 if (pkt->stream_index == ffs->si) {
104 long pts = (pkt->dts == AV_NOPTS_VALUE ? 0 : pkt->dts) *
105 av_q2d(ffs->st->time_base) * 1000;
106 ffs->dur = MIN(MAX(0, pts - ffs->pts), 1000);
107 if (pts > ffs->pts || pts + 200 < ffs->pts)
108 ffs->pts = pts;
109 return pkt;
111 av_packet_unref(pkt);
113 return NULL;
116 static AVFrame *ffs_recv(struct ffs *ffs)
118 AVCodecContext *vcc = ffs->cc;
119 AVPacket *pkt = NULL;
120 int errcnt = 0;
121 int ret;
122 while (1) {
123 if ((ret = avcodec_receive_frame(vcc, ffs->tmp)) == 0)
124 return ffs->tmp;
125 if (ret < 0 && ret != AVERROR(EAGAIN))
126 return NULL;
127 if ((pkt = ffs_pkt(ffs)) == NULL)
128 return NULL;
129 if ((ret = avcodec_send_packet(vcc, pkt)) < 0) {
130 av_packet_unref(pkt);
131 if (ret == AVERROR(EOF) || errcnt++ == 3)
132 return NULL;
134 av_packet_unref(pkt);
136 return NULL;
139 static long ts_ms(void)
141 struct timeval tv;
142 gettimeofday(&tv, NULL);
143 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
146 static int wait(long ts, int vdelay)
148 long nts = ts_ms();
149 if (nts > ts && ts + vdelay > nts) {
150 usleep((ts + vdelay - nts) * 1000);
151 return 0;
153 return 1;
156 void ffs_wait(struct ffs *ffs)
158 int vdelay = ffs->dur;
159 if (!wait(ffs->ts, MAX(vdelay, 20)))
160 ffs->ts += MAX(vdelay, 20);
161 else
162 ffs->ts = ts_ms(); /* out of sync */
165 /* audio/video frame offset difference */
166 int ffs_avdiff(struct ffs *ffs, struct ffs *affs)
168 return affs->pts - ffs->pts;
171 long ffs_pos(struct ffs *ffs)
173 return ffs->pts;
176 void ffs_seek(struct ffs *ffs, struct ffs *vffs, long pos)
178 av_seek_frame(ffs->fc, vffs->si,
179 pos / av_q2d(vffs->st->time_base) / 1000, 0);
180 ffs->ts = 0;
183 void ffs_vinfo(struct ffs *ffs, int *w, int *h)
185 *h = ffs->cc->height;
186 *w = ffs->cc->width;
189 void ffs_ainfo(struct ffs *ffs, int *rate, int *bps, int *ch)
191 *rate = ffs->cc->sample_rate;
192 *ch = FFS_CHCNT;
193 *bps = 16;
196 int ffs_vdec(struct ffs *ffs, void **buf)
198 AVFrame *tmp = ffs_recv(ffs);
199 AVFrame *dst = ffs->dst;
200 if (tmp == NULL)
201 return -1;
202 if (buf) {
203 sws_scale(ffs->swsc, (void *) tmp->data, tmp->linesize,
204 0, ffs->cc->height, dst->data, dst->linesize);
205 *buf = (void *) dst->data[0];
206 return dst->linesize[0];
208 return 0;
211 int ffs_sdec(struct ffs *ffs, char *buf, int blen, long *beg, long *end)
213 AVPacket *pkt = ffs_pkt(ffs);
214 AVSubtitle sub = {0};
215 AVSubtitleRect *rect;
216 int fine = 0;
217 int i;
218 if (!pkt)
219 return -1;
220 avcodec_decode_subtitle2(ffs->cc, &sub, &fine, pkt);
221 av_packet_unref(pkt);
222 buf[0] = '\0';
223 if (!fine)
224 return 1;
225 rect = sub.num_rects ? sub.rects[0] : NULL;
226 if (rect && rect->text)
227 snprintf(buf, blen, "%s", sub.rects[0]->text);
228 if (rect && !rect->text && rect->ass) {
229 char *s = rect->ass;
230 for (i = 0; s && i < 9; i++)
231 s = strchr(s, ',') ? strchr(s, ',') + 1 : NULL;
232 if (s)
233 snprintf(buf, blen, "%s", s);
235 if (strchr(buf, '\n'))
236 *strchr(buf, '\n') = '\0';
237 *beg = ffs->pts + sub.start_display_time * av_q2d(ffs->st->time_base) * 1000;
238 *end = ffs->pts + sub.end_display_time * av_q2d(ffs->st->time_base) * 1000;
239 avsubtitle_free(&sub);
240 return 0;
243 static int ffs_bytespersample(struct ffs *ffs)
245 return av_get_bytes_per_sample(FFS_SAMPLEFMT) * FFS_CHCNT;
248 int ffs_adec(struct ffs *ffs, void *buf, int blen)
250 AVFrame *tmp = ffs_recv(ffs);
251 uint8_t *out[] = {buf};
252 int len;
253 if (tmp == NULL)
254 return -1;
255 len = swr_convert(ffs->swrc, out, blen / ffs_bytespersample(ffs),
256 (void *) tmp->extended_data, tmp->nb_samples);
257 return len > 0 ? len * ffs_bytespersample(ffs) : 0;
260 static int fbm2pixfmt(int fbm)
262 switch (fbm & 0x0fff) {
263 case 0x888:
264 return AV_PIX_FMT_RGB32;
265 case 0x565:
266 return AV_PIX_FMT_RGB565;
267 case 0x233:
268 return AV_PIX_FMT_RGB8;
269 default:
270 fprintf(stderr, "ffs: unknown fb_mode()\n");
271 return AV_PIX_FMT_RGB32;
275 void ffs_vconf(struct ffs *ffs, float zoom, int fbm)
277 int h = ffs->cc->height;
278 int w = ffs->cc->width;
279 int fmt = ffs->cc->pix_fmt;
280 int pixfmt = fbm2pixfmt(fbm);
281 uint8_t *buf = NULL;
282 int n;
283 ffs->swsc = sws_getContext(w, h, fmt, w * zoom, h * zoom,
284 pixfmt, SWS_FAST_BILINEAR,
285 NULL, NULL, NULL);
286 n = av_image_get_buffer_size(pixfmt, w * zoom, h * zoom, 8);
287 buf = av_malloc(n * sizeof(uint8_t));
288 av_image_fill_arrays(ffs->dst->data, ffs->dst->linesize, buf,
289 pixfmt, w * zoom, h * zoom, 8);
292 void ffs_aconf(struct ffs *ffs)
294 int rate, bps, ch;
295 ffs_ainfo(ffs, &rate, &bps, &ch);
296 ffs->swrc = swr_alloc();
297 av_opt_set_int(ffs->swrc, "in_channel_layout", ffs->cc->channel_layout, 0);
298 /* av_opt_set_int(ffs->swrc, "in_channel_layout", ffs->cc->ch_layout, 0); */
299 av_opt_set_int(ffs->swrc, "in_sample_rate", ffs->cc->sample_rate, 0);
300 av_opt_set_sample_fmt(ffs->swrc, "in_sample_fmt", ffs->cc->sample_fmt, 0);
301 av_opt_set_int(ffs->swrc, "out_channel_layout", FFS_CHLAYOUT, 0);
302 av_opt_set_int(ffs->swrc, "out_sample_rate", rate, 0);
303 av_opt_set_sample_fmt(ffs->swrc, "out_sample_fmt", FFS_SAMPLEFMT, 0);
304 swr_init(ffs->swrc);
307 void ffs_globinit(void)
311 long ffs_duration(struct ffs *ffs)
313 if (ffs->st->duration != AV_NOPTS_VALUE)
314 return ffs->st->duration * av_q2d(ffs->st->time_base) * 1000;
315 if (ffs->fc->duration > 0)
316 return ffs->fc->duration / (AV_TIME_BASE / 1000);
317 return 0;