rev |
line source |
nuclear@0
|
1 #include <stdio.h>
|
nuclear@0
|
2 #include <libavcodec/avcodec.h>
|
nuclear@0
|
3 #include <libavformat/avformat.h>
|
nuclear@0
|
4 #include <libswscale/swscale.h>
|
nuclear@0
|
5 #include "vid.h"
|
nuclear@0
|
6
|
nuclear@0
|
7 struct video_file {
|
nuclear@0
|
8 AVFormatContext *avctx;
|
nuclear@0
|
9 AVCodecContext *cctx;
|
nuclear@0
|
10 AVCodec *codec;
|
nuclear@0
|
11 int vstream, audio_stream;
|
nuclear@0
|
12 struct SwsContext *sws;
|
nuclear@0
|
13
|
nuclear@0
|
14 AVFrame *frm, *rgbfrm;
|
nuclear@0
|
15 };
|
nuclear@0
|
16
|
nuclear@0
|
17 struct video_file *vid_open(const char *fname)
|
nuclear@0
|
18 {
|
nuclear@0
|
19 static int initialized;
|
nuclear@0
|
20 struct video_file *vf;
|
nuclear@0
|
21 int i;
|
nuclear@0
|
22
|
nuclear@0
|
23 if(!initialized) {
|
nuclear@0
|
24 av_register_all();
|
nuclear@0
|
25 initialized = 1;
|
nuclear@0
|
26 }
|
nuclear@0
|
27
|
nuclear@0
|
28 if(!(vf = malloc(sizeof *vf))) {
|
nuclear@0
|
29 fprintf(stderr, "open_video(%s): failed to allocate memory: %s\n", fname, strerror(errno));
|
nuclear@0
|
30 return 0;
|
nuclear@0
|
31 }
|
nuclear@0
|
32 memset(vf, 0, sizeof *vf);
|
nuclear@0
|
33
|
nuclear@0
|
34 if(av_open_input_file(&vf->avctx, fname, 0, 0, 0) != 0) {
|
nuclear@0
|
35 fprintf(stderr, "open_video(%s): failed to open file\n", fname);
|
nuclear@0
|
36 vid_close(vf);
|
nuclear@0
|
37 return 0;
|
nuclear@0
|
38 }
|
nuclear@0
|
39
|
nuclear@0
|
40 if(av_find_stream_info(vf->avctx) < 0) {
|
nuclear@0
|
41 fprintf(stderr, "open_video(%s): failed to find stream info\n", fname);
|
nuclear@0
|
42 vid_close(vf);
|
nuclear@0
|
43 return 0;
|
nuclear@0
|
44 }
|
nuclear@0
|
45
|
nuclear@0
|
46 vf->vstream = -1;
|
nuclear@0
|
47 for(i=0; i<vf->avctx->nb_streams; i++) {
|
nuclear@0
|
48 if(vf->avctx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
|
nuclear@0
|
49 vf->vstream = i;
|
nuclear@0
|
50 break;
|
nuclear@0
|
51 }
|
nuclear@0
|
52 }
|
nuclear@0
|
53 if(vf->vstream == -1) {
|
nuclear@0
|
54 fprintf(stderr, "open_video(%s): didn't find a video stream\n", fname);
|
nuclear@0
|
55 vid_close(vf);
|
nuclear@0
|
56 return 0;
|
nuclear@0
|
57 }
|
nuclear@0
|
58 vf->cctx = vf->avctx->streams[vf->vstream]->codec;
|
nuclear@0
|
59
|
nuclear@0
|
60 if(!(vf->codec = avcodec_find_decoder(vf->cctx->codec_id))) {
|
nuclear@0
|
61 fprintf(stderr, "open_video(%s): unsupported codec\n", fname);
|
nuclear@0
|
62 vid_close(vf);
|
nuclear@0
|
63 return 0;
|
nuclear@0
|
64 }
|
nuclear@0
|
65
|
nuclear@0
|
66 if(avcodec_open(vf->cctx, vf->codec) < 0) {
|
nuclear@0
|
67 fprintf(stderr, "open_video(%s): failed to open codec\n", fname);
|
nuclear@0
|
68 vid_close(vf);
|
nuclear@0
|
69 return 0;
|
nuclear@0
|
70 }
|
nuclear@0
|
71
|
nuclear@0
|
72 if(!(vf->frm = avcodec_alloc_frame()) || !(vf->rgbfrm = avcodec_alloc_frame())) {
|
nuclear@0
|
73 fprintf(stderr, "open_video(%s): failed to allocate frame\n", fname);
|
nuclear@0
|
74 vid_close(vf);
|
nuclear@0
|
75 return 0;
|
nuclear@0
|
76 }
|
nuclear@0
|
77
|
nuclear@0
|
78 vf->sws = sws_getContext(vf->cctx->width, vf->cctx->height, vf->cctx->pix_fmt,
|
nuclear@0
|
79 vf->cctx->width, vf->cctx->height, PIX_FMT_RGB32, SWS_POINT, 0, 0, 0);
|
nuclear@0
|
80 if(!vf->sws) {
|
nuclear@0
|
81 fprintf(stderr, "open_video(%s): failed to allocate sws context\n", fname);
|
nuclear@0
|
82 vid_close(vf);
|
nuclear@0
|
83 return 0;
|
nuclear@0
|
84 }
|
nuclear@0
|
85
|
nuclear@0
|
86
|
nuclear@0
|
87 printf("using codec: %s\n", vf->codec->name);
|
nuclear@0
|
88 printf("fps: %f (%u usec frame interval)\n", vid_fps(vf), vid_frame_interval(vf));
|
nuclear@0
|
89 printf("size: %dx%d\n", vid_frame_width(vf), vid_frame_height(vf));
|
nuclear@0
|
90
|
nuclear@0
|
91 return vf;
|
nuclear@0
|
92 }
|
nuclear@0
|
93
|
nuclear@0
|
94 void vid_close(struct video_file *vf)
|
nuclear@0
|
95 {
|
nuclear@0
|
96 if(!vf) return;
|
nuclear@0
|
97
|
nuclear@0
|
98 /* TODO how do we deallocate sws contexts? */
|
nuclear@0
|
99 if(vf->rgbfrm) av_free(vf->rgbfrm);
|
nuclear@0
|
100 if(vf->frm) av_free(vf->frm);
|
nuclear@0
|
101 if(vf->cctx) avcodec_close(vf->cctx);
|
nuclear@0
|
102 if(vf->avctx) av_close_input_file(vf->avctx);
|
nuclear@0
|
103 free(vf);
|
nuclear@0
|
104 }
|
nuclear@0
|
105
|
nuclear@0
|
106
|
nuclear@0
|
107 float vid_fps(struct video_file *vf)
|
nuclear@0
|
108 {
|
nuclear@0
|
109 float inv_tb = (float)vf->cctx->time_base.den / (float)vf->cctx->time_base.num;
|
nuclear@0
|
110 return inv_tb / (float)vf->cctx->ticks_per_frame;
|
nuclear@0
|
111 }
|
nuclear@0
|
112
|
nuclear@0
|
113 unsigned int vid_frame_interval(struct video_file *vf)
|
nuclear@0
|
114 {
|
nuclear@0
|
115 float fps = vid_fps(vf);
|
nuclear@0
|
116 return 1000000 / fps;
|
nuclear@0
|
117 }
|
nuclear@0
|
118
|
nuclear@0
|
119 int vid_frame_width(struct video_file *vf)
|
nuclear@0
|
120 {
|
nuclear@0
|
121 return vf->cctx->width;
|
nuclear@0
|
122 }
|
nuclear@0
|
123
|
nuclear@0
|
124 int vid_frame_height(struct video_file *vf)
|
nuclear@0
|
125 {
|
nuclear@0
|
126 return vf->cctx->height;
|
nuclear@0
|
127 }
|
nuclear@0
|
128
|
nuclear@0
|
129 size_t vid_frame_size(struct video_file *vf)
|
nuclear@0
|
130 {
|
nuclear@0
|
131 return vf->cctx->width * vf->cctx->height * 4;
|
nuclear@0
|
132 }
|
nuclear@0
|
133
|
nuclear@0
|
134 int vid_get_frame(struct video_file *vf, uint32_t *img)
|
nuclear@0
|
135 {
|
nuclear@0
|
136 AVPacket packet;
|
nuclear@0
|
137 int frame_done = 0;
|
nuclear@0
|
138 AVPicture *rgbfrm = (AVPicture*)vf->rgbfrm;
|
nuclear@0
|
139 AVPicture *frm = (AVPicture*)vf->frm;
|
nuclear@0
|
140
|
nuclear@0
|
141 avpicture_fill((AVPicture*)vf->rgbfrm, (uint8_t*)img, PIX_FMT_RGB32, vf->cctx->width, vf->cctx->height);
|
nuclear@0
|
142
|
nuclear@0
|
143 while(av_read_frame(vf->avctx, &packet) >= 0) {
|
nuclear@0
|
144 if(packet.stream_index == vf->vstream) {
|
nuclear@0
|
145 avcodec_decode_video2(vf->cctx, vf->frm, &frame_done, &packet);
|
nuclear@0
|
146
|
nuclear@0
|
147 if(frame_done) {
|
nuclear@0
|
148 sws_scale(vf->sws, frm->data, frm->linesize, 0, vf->cctx->height, rgbfrm->data, rgbfrm->linesize);
|
nuclear@0
|
149 av_free_packet(&packet);
|
nuclear@0
|
150 return 0;
|
nuclear@0
|
151 }
|
nuclear@0
|
152 }
|
nuclear@0
|
153 av_free_packet(&packet);
|
nuclear@0
|
154 }
|
nuclear@0
|
155
|
nuclear@0
|
156 return -1;
|
nuclear@0
|
157 }
|