1 #include "config.h"
2
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <pthread.h>
7 #include <quicktime/quicktime.h>
8 #include <quicktime/colormodels.h>
9 #include <quicktime/lqt.h>
10
11 #include "grab-ng.h"
12
13 #define AUDIO_SIZE (64*1024)
14
15 /* ----------------------------------------------------------------------- */
16
17 static int fmtid_to_cmodel[VIDEO_FMT_COUNT] = {
18 [ VIDEO_RGB24 ] = BC_RGB888,
19 [ VIDEO_BGR24 ] = BC_BGR888,
20 [ VIDEO_YUYV ] = BC_YUV422,
21 [ VIDEO_YUV420P ] = BC_YUV420P,
22 };
23
24 /* ----------------------------------------------------------------------- */
25
26 struct qt_handle {
27 /* libquicktime handle */
28 quicktime_t *qt;
29
30 /* format */
31 struct ng_video_fmt vfmt;
32 struct ng_audio_fmt afmt;
33
34 /* misc video */
35 unsigned char **rows;
36 int rate;
37
38 /* misc audio */
39 int channels;
40 int16_t *left,*right;
41 long long bps;
42 };
43
44 static void* qt_open(char *moviename)
45 {
46 struct qt_handle *h;
47 char *str;
48 int i;
49
50 if (NULL == (h = malloc(sizeof(*h))))
51 return NULL;
52 memset(h,0,sizeof(*h));
53
54 /* open file */
55 h->qt = quicktime_open(moviename,1,0);
56 if (NULL == h->qt) {
57 fprintf(stderr,"ERROR: can't open file: %s\n",moviename);
58 free(h);
59 return NULL;
60 }
61
62 if (ng_debug) {
63 /* print misc info */
64 fprintf(stderr,"quicktime movie %s:\n",moviename);
65 str = quicktime_get_copyright(h->qt);
66 if (str)
67 fprintf(stderr," copyright: %s\n",str);
68 str = quicktime_get_name(h->qt);
69 if (str)
70 fprintf(stderr," name: %s\n",str);
71 str = quicktime_get_info(h->qt);
72 if (str)
73 fprintf(stderr," info: %s\n",str);
74
75 /* print video info */
76 if (quicktime_has_video(h->qt)) {
77 fprintf(stderr," video: %d track(s)\n",quicktime_video_tracks(h->qt));
78 for (i = 0; i < quicktime_video_tracks(h->qt); i++) {
79 fprintf(stderr,
80 " track #%d\n"
81 " width : %d\n"
82 " height: %d\n"
83 " depth : %d bit\n"
84 " rate : %.2f fps\n"
85 " codec : %s\n",
86 i+1,
87 quicktime_video_width(h->qt,i),
88 quicktime_video_height(h->qt,i),
89 quicktime_video_depth(h->qt,i),
90 quicktime_frame_rate(h->qt,i),
91 quicktime_video_compressor(h->qt,i));
92 }
93 }
94
95 /* print audio info */
96 if (quicktime_has_audio(h->qt)) {
97 fprintf(stderr," audio: %d track(s)\n",quicktime_audio_tracks(h->qt));
98 for (i = 0; i < quicktime_audio_tracks(h->qt); i++) {
99 fprintf(stderr,
100 " track #%d\n"
101 " rate : %ld Hz\n"
102 " bits : %d\n"
103 " chans : %d\n"
104 " codec : %s\n",
105 i+1,
106 quicktime_sample_rate(h->qt,i),
107 quicktime_audio_bits(h->qt,i),
108 quicktime_track_channels(h->qt,i),
109 quicktime_audio_compressor(h->qt,i));
110 }
111 }
112 }
113
114 /* video format */
115 if (!quicktime_has_video(h->qt)) {
116 if (ng_debug)
117 fprintf(stderr,"qt: no video stream\n");
118 } else if (!quicktime_supported_video(h->qt,0)) {
119 if (ng_debug)
120 fprintf(stderr,"qt: unsupported video codec\n");
121 } else {
122 h->vfmt.width = quicktime_video_width(h->qt,0);
123 h->vfmt.height = quicktime_video_height(h->qt,0);
124 h->rate = quicktime_frame_rate(h->qt,0);
125 }
126
127 /* audio format */
128 if (!quicktime_has_audio(h->qt)) {
129 if (ng_debug)
130 fprintf(stderr,"qt: no audio stream\n");
131 } else if (!quicktime_supported_audio(h->qt,0)) {
132 if (ng_debug)
133 fprintf(stderr,"qt: unsupported audio codec\n");
134 } else {
135 h->channels = quicktime_track_channels(h->qt,0);
136 h->afmt.fmtid = (h->channels > 1) ?
137 AUDIO_S16_NATIVE_STEREO : AUDIO_S16_NATIVE_MONO;
138 h->afmt.rate = quicktime_sample_rate(h->qt,0);
139 }
140
141 return h;
142 }
143
144 static struct ng_video_fmt* qt_vfmt(void *handle, int *vfmt, int vn)
145 {
146 struct qt_handle *h = handle;
147 int i;
148
149 for (i = 0; i < vn; i++) {
150 if (ng_debug)
151 fprintf(stderr,"qt: trying: %d [%s]\n",
152 vfmt[i],ng_vfmt_to_desc[vfmt[i]]);
153 if (0 == fmtid_to_cmodel[vfmt[i]])
154 continue;
155 if (!quicktime_reads_cmodel(h->qt,fmtid_to_cmodel[vfmt[i]],0))
156 continue;
157 quicktime_set_cmodel(h->qt, fmtid_to_cmodel[vfmt[i]]);
158 h->vfmt.fmtid = vfmt[i];
159 break;
160 }
161 h->vfmt.bytesperline = (h->vfmt.width*ng_vfmt_to_depth[h->vfmt.fmtid]) >> 3;
162 return &h->vfmt;
163 }
164
165 static struct ng_audio_fmt* qt_afmt(void *handle)
166 {
167 struct qt_handle *h = handle;
168
169 return h->afmt.fmtid ? &h->afmt : NULL;
170 }
171
172 static struct ng_video_buf* qt_vdata(void *handle, unsigned int drop)
173 {
174 struct qt_handle *h = handle;
175 struct ng_video_buf *buf;
176 unsigned int i;
177
178 if (quicktime_video_position(h->qt,0) >= quicktime_video_length(h->qt,0))
179 return NULL;
180
181 buf = ng_malloc_video_buf(&h->vfmt,h->vfmt.bytesperline*h->vfmt.height);
182 if (!h->rows)
183 h->rows = malloc(h->vfmt.height * sizeof(char*));
184 switch (fmtid_to_cmodel[h->vfmt.fmtid]) {
185 case BC_RGB888:
186 case BC_BGR888:
187 for (i = 0; i < h->vfmt.height; i++)
188 h->rows[i] = buf->data + h->vfmt.width * 3 * i;
189 break;
190 case BC_YUV422:
191 for (i = 0; i < h->vfmt.height; i++)
192 h->rows[i] = buf->data+ h->vfmt.width * 2 * i;
193 break;
194 case BC_YUV420P:
195 h->rows[0] = buf->data;
196 h->rows[1] = buf->data + h->vfmt.width*h->vfmt.height;
197 h->rows[2] = buf->data + h->vfmt.width*h->vfmt.height*5/4;
198 break;
199 default:
200 BUG_ON(1,"unknown cmodel");
201 }
202
203 /* drop frames */
204 for (i = 0; i < drop; i++)
205 quicktime_read_frame(h->qt,buf->data,0);
206
207 buf->info.seq = quicktime_video_position(h->qt,0);
208 buf->info.ts = (long long) buf->info.seq * 1000000000 / h->rate;
209 lqt_decode_video(h->qt, h->rows, 0);
210 return buf;
211 }
212
213 static struct ng_audio_buf* qt_adata(void *handle)
214 {
215 struct qt_handle *h = handle;
216 struct ng_audio_buf *buf;
217 int16_t *dest;
218 long pos;
219 int i;
220
221 if (quicktime_audio_position(h->qt,0) >= quicktime_audio_length(h->qt,0))
222 return NULL;
223
224 buf = ng_malloc_audio_buf(&h->afmt,AUDIO_SIZE);
225 dest = (int16_t*)buf->data;
226
227 pos = quicktime_audio_position(h->qt,0);
228 buf->info.ts = (long long) pos * 1000000000 / h->afmt.rate;
229 if (h->channels > 1) {
230 /* stereo: two channels => interlaved samples */
231 if (!h->left)
232 h->left = malloc(AUDIO_SIZE/2);
233 if (!h->right)
234 h->right = malloc(AUDIO_SIZE/2);
235 quicktime_set_audio_position(h->qt,pos,0);
236 quicktime_decode_audio(h->qt,h->left,NULL,AUDIO_SIZE/4,0);
237 quicktime_set_audio_position(h->qt,pos,1);
238 quicktime_decode_audio(h->qt,h->right,NULL,AUDIO_SIZE/4,1);
239 for (i = 0; i < AUDIO_SIZE/4; i++) {
240 dest[2*i+0] = h->left[i];
241 dest[2*i+1] = h->right[i];
242 }
243 } else {
244 /* mono */
245 quicktime_decode_audio(h->qt,dest,NULL,AUDIO_SIZE/2,0);
246 }
247 return buf;
248 }
249
250 static int64_t qt_frame_time(void *handle)
251 {
252 struct qt_handle *h = handle;
253
254 return 1000000000 / h->rate;
255 }
256
257 static int qt_close(void *handle)
258 {
259 struct qt_handle *h = handle;
260
261 quicktime_close(h->qt);
262 if (h->rows)
263 free(h->rows);
264 free(h);
265 return 0;
266 }
267
268 /* ----------------------------------------------------------------------- */
269
270 struct ng_reader qt_reader = {
271 name: "qt",
272 desc: "Apple QuickTime format",
273
274 magic: { "moov", "mdat" },
275 moff: { 4, 4 },
276 mlen: { 4, 4 },
277
278 rd_open: qt_open,
279 rd_vfmt: qt_vfmt,
280 rd_afmt: qt_afmt,
281 rd_vdata: qt_vdata,
282 rd_adata: qt_adata,
283 frame_time: qt_frame_time,
284 rd_close: qt_close,
285 };
286
287 extern void ng_plugin_init(void);
288 void ng_plugin_init(void)
289 {
290 ng_reader_register(NG_PLUGIN_MAGIC,__FILE__,&qt_reader);
291 }
292
|
This page was automatically generated by the
LXR engine.
|