6 #include <libavformat/avformat.h>
7 #include <libavcodec/avcodec.h>
8 #include <libswscale/swscale.h>
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
;
28 struct ffs
*ffs_alloc(char *path
, int flags
)
31 int type
= flags
& FFS_VIDEO
? AVMEDIA_TYPE_VIDEO
: AVMEDIA_TYPE_AUDIO
;
32 int idx
= (flags
& FFS_STRIDX
) - 1;
33 AVDictionary
*opt
= NULL
;
34 ffs
= malloc(sizeof(*ffs
));
35 memset(ffs
, 0, sizeof(*ffs
));
37 if (avformat_open_input(&ffs
->fc
, path
, NULL
, NULL
))
39 if (avformat_find_stream_info(ffs
->fc
, NULL
) < 0)
41 ffs
->si
= av_find_best_stream(ffs
->fc
, type
, idx
, -1, NULL
, 0);
44 ffs
->cc
= ffs
->fc
->streams
[ffs
->si
]->codec
;
45 if (avcodec_open2(ffs
->cc
, avcodec_find_decoder(ffs
->cc
->codec_id
), &opt
))
47 ffs
->dst
= avcodec_alloc_frame();
54 void ffs_free(struct ffs
*ffs
)
57 sws_freeContext(ffs
->swsc
);
63 avcodec_close(ffs
->cc
);
65 avformat_close_input(&ffs
->fc
);
69 static AVPacket
*ffs_pkt(struct ffs
*ffs
)
71 AVPacket
*pkt
= &ffs
->pkt
;
72 while (av_read_frame(ffs
->fc
, pkt
) >= 0) {
74 if (pkt
->stream_index
== ffs
->si
) {
84 static long ts_ms(void)
87 gettimeofday(&tv
, NULL
);
88 return tv
.tv_sec
* 1000 + tv
.tv_usec
/ 1000;
91 static int wait(long ts
, int vdelay
)
94 if (nts
> ts
&& ts
+ vdelay
> nts
) {
95 usleep((ts
+ vdelay
- nts
) * 1000);
101 #define MAX(a, b) ((a) < (b) ? (b) : (a))
103 void ffs_wait(struct ffs
*ffs
)
105 AVRational
*r
= &ffs
->fc
->streams
[ffs
->si
]->r_frame_rate
;
106 int vdelay
= 1000 * r
->den
/ r
->num
;
107 if (!wait(ffs
->ts
, MAX(vdelay
, 20)))
108 ffs
->ts
+= MAX(vdelay
, 20);
110 ffs
->ts
= ts_ms(); /* out of sync */
113 /* audio/video frame offset difference */
114 int ffs_avdiff(struct ffs
*ffs
, struct ffs
*affs
)
116 return affs
->seq_all
- ffs
->seq_all
;
119 long ffs_pos(struct ffs
*ffs
, int diff
)
121 return (ffs
->si
<< 28) | (ffs
->seq
+ diff
);
124 void ffs_seek(struct ffs
*ffs
, long pos
, int perframe
)
126 long idx
= pos
>> 28;
127 long seq
= pos
& 0x00ffffff;
128 av_seek_frame(ffs
->fc
, idx
, seq
* perframe
,
129 perframe
== 1 ? AVSEEK_FLAG_FRAME
: 0);
136 void ffs_vinfo(struct ffs
*ffs
, int *w
, int *h
)
138 *h
= ffs
->cc
->height
;
142 void ffs_ainfo(struct ffs
*ffs
, int *rate
, int *bps
, int *ch
)
144 *rate
= ffs
->cc
->sample_rate
;
145 *ch
= ffs
->cc
->channels
;
149 int ffs_vdec(struct ffs
*ffs
, void **buf
)
151 AVCodecContext
*vcc
= ffs
->cc
;
152 AVPacket
*pkt
= ffs_pkt(ffs
);
156 avcodec_decode_video2(vcc
, ffs
->tmp
, &fine
, pkt
);
159 sws_scale(ffs
->swsc
, (void *) ffs
->tmp
->data
, ffs
->tmp
->linesize
,
160 0, vcc
->height
, ffs
->dst
->data
, ffs
->dst
->linesize
);
161 *buf
= (void *) ffs
->dst
->data
[0];
162 return ffs
->dst
->linesize
[0];
167 int ffs_adec(struct ffs
*ffs
, void *buf
, int blen
)
171 AVPacket tmppkt
= {0};
172 AVPacket
*pkt
= ffs_pkt(ffs
);
175 tmppkt
.size
= pkt
->size
;
176 tmppkt
.data
= pkt
->data
;
177 while (tmppkt
.size
> 0) {
178 len
= avcodec_decode_audio4(ffs
->cc
, ffs
->dst
, &got
, &tmppkt
);
185 rdec
= ffs
->dst
->linesize
[0];
186 memcpy(buf
, ffs
->dst
->data
[0], rdec
);
190 static int fbm2pixfmt(int fbm
)
192 switch (fbm
& 0x0fff) {
194 return PIX_FMT_RGB32
;
196 return PIX_FMT_RGB565
;
200 fprintf(stderr
, "ffs: unknown fb_mode()\n");
201 return PIX_FMT_RGB32
;
205 void ffs_vsetup(struct ffs
*ffs
, float zoom
, int fbm
)
207 int h
= ffs
->cc
->height
;
208 int w
= ffs
->cc
->width
;
209 int fmt
= ffs
->cc
->pix_fmt
;
210 int pixfmt
= fbm2pixfmt(fbm
);
213 ffs
->swsc
= sws_getContext(w
, h
, fmt
, w
* zoom
, h
* zoom
,
214 pixfmt
, SWS_FAST_BILINEAR
| SWS_CPU_CAPS_MMX2
,
216 ffs
->tmp
= avcodec_alloc_frame();
217 n
= avpicture_get_size(pixfmt
, w
* zoom
, h
* zoom
);
218 buf
= av_malloc(n
* sizeof(uint8_t));
219 avpicture_fill((AVPicture
*) ffs
->dst
, buf
, pixfmt
, w
* zoom
, h
* zoom
);
222 void ffs_globinit(void)
225 avformat_network_init();