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 /* ----------------------------------------------------------------------- */
14
15 struct qt_video_priv {
16 char fcc[5];
17 int yuvsign;
18 int libencode;
19 int cmodel;
20 };
21
22 struct qt_audio_priv {
23 char fcc[5];
24 int libencode;
25 };
26
27 struct qt_handle {
28 /* libquicktime handle */
29 quicktime_t *fh;
30
31 /* format */
32 struct ng_video_fmt video;
33 struct ng_audio_fmt audio;
34
35 /* misc */
36 int lib_video;
37 int lib_audio;
38 int yuvsign;
39 int audio_sample;
40 unsigned char **rows;
41 unsigned char *data;
42 };
43
44 /* ----------------------------------------------------------------------- */
45
46 static void*
47 qt_open(char *filename, char *dummy,
48 struct ng_video_fmt *video, const void *priv_video, int fps,
49 struct ng_audio_fmt *audio, const void *priv_audio)
50 {
51 const struct qt_video_priv *pvideo = priv_video;
52 const struct qt_audio_priv *paudio = priv_audio;
53 struct qt_handle *h;
54
55 if (NULL == (h = malloc(sizeof(*h))))
56 return NULL;
57
58 memset(h,0,sizeof(*h));
59 h->video = *video;
60 h->audio = *audio;
61 if (h->video.fmtid != VIDEO_NONE) {
62 h->lib_video = pvideo->libencode;
63 h->yuvsign = pvideo->yuvsign;
64 }
65 if (h->audio.fmtid != AUDIO_NONE)
66 h->lib_audio = paudio->libencode;
67
68 if (NULL == (h->fh = quicktime_open(filename,0,1))) {
69 fprintf(stderr,"quicktime_open failed (%s)\n",filename);
70 goto fail;
71 }
72 if (h->lib_video)
73 if (NULL == (h->rows = malloc(h->video.height * sizeof(char*))))
74 goto fail;
75 if (h->yuvsign)
76 if (NULL == (h->data = malloc(h->video.height * h->video.width * 2)))
77 goto fail;
78
79 if (h->audio.fmtid != AUDIO_NONE) {
80 quicktime_set_audio(h->fh,
81 ng_afmt_to_channels[h->audio.fmtid],
82 h->audio.rate,
83 ng_afmt_to_bits[h->audio.fmtid],
84 (char*)paudio->fcc);
85 h->audio_sample = ng_afmt_to_channels[h->audio.fmtid] *
86 ng_afmt_to_bits[h->audio.fmtid] / 8;
87 if (h->lib_audio) {
88 if (!quicktime_supported_audio(h->fh, 0)) {
89 fprintf(stderr,"libquicktime: audio codec not supported\n");
90 goto fail;
91 }
92 }
93 }
94 if (h->video.fmtid != VIDEO_NONE) {
95 quicktime_set_video(h->fh,1,h->video.width,h->video.height,
96 (float)fps/1000,(char*)pvideo->fcc);
97 if (h->lib_video) {
98 quicktime_set_cmodel(h->fh,pvideo->cmodel);
99 if (!quicktime_supported_video(h->fh, 0)) {
100 fprintf(stderr,"libquicktime: video codec not supported\n");
101 goto fail;
102 }
103 }
104 }
105 quicktime_set_info(h->fh, "Dumme Bemerkungen gibt's hier umsonst.");
106 return h;
107
108 fail:
109 if (h->rows)
110 free(h->rows);
111 if (h->data)
112 free(h->data);
113 free(h);
114 return NULL;
115 }
116
117 static int
118 qt_video(void *handle, struct ng_video_buf *buf)
119 {
120 struct qt_handle *h = handle;
121 unsigned int *src,*dest;
122 int rc,i,n;
123
124 if (h->lib_video) {
125 unsigned int row,len;
126 char *line;
127
128 /* QuickTime library expects an array of pointers to image rows (RGB) */
129 len = h->video.width * 3;
130 for (row = 0, line = buf->data; row < h->video.height; row++, line += len)
131 h->rows[row] = line;
132 rc = quicktime_encode_video(h->fh, h->rows, 0);
133
134 } else if (h->yuvsign) {
135 dest = (unsigned int *)h->data;
136 src = (unsigned int *)buf->data;
137 n = buf->size / 4;
138 /* U V values are signed but Y R G B values are unsigned. */
139 for (i = 0; i < n; i++) {
140 #if BYTE_ORDER == BIG_ENDIAN
141 *(dest++) = *(src++) ^ 0x00800080;
142 #else
143 *(dest++) = *(src++) ^ 0x80008000;
144 #endif
145 }
146 rc = quicktime_write_frame(h->fh, h->data, buf->size, 0);
147
148 } else {
149 rc = quicktime_write_frame(h->fh, buf->data, buf->size, 0);
150 }
151 return rc;
152 }
153
154 static int
155 qt_audio(void *handle, struct ng_audio_buf *buf)
156 {
157 struct qt_handle *h = handle;
158 int16_t *ch[2];
159
160 if (h->lib_audio) {
161 /* FIXME: works for one channel (mono) only */
162 ch[0] = (int16_t*)buf->data;
163 return quicktime_encode_audio(h->fh, ch, NULL,
164 buf->size / h->audio_sample);
165 } else {
166 return quicktime_write_audio(h->fh, buf->data,
167 buf->size / h->audio_sample, 0);
168 }
169 }
170
171 static int
172 qt_close(void *handle)
173 {
174 struct qt_handle *h = handle;
175
176 quicktime_close(h->fh);
177 if (h->rows)
178 free(h->rows);
179 if (h->data)
180 free(h->data);
181 free(h);
182 return 0;
183 }
184
185 /* ----------------------------------------------------------------------- */
186
187 static int cmodels[] = {
188 [BC_BGR888] = VIDEO_BGR24,
189 [BC_RGB888] = VIDEO_RGB24,
190 [BC_YUV422] = VIDEO_YUYV,
191 [BC_YUV422P] = VIDEO_YUV422P,
192 [BC_YUV420P] = VIDEO_YUV420P,
193 };
194
195 static struct qt_video_priv qt_raw = {
196 fcc: QUICKTIME_RAW,
197 libencode: 0,
198 };
199 static struct qt_video_priv qt_yuv2 = {
200 fcc: QUICKTIME_YUV2,
201 yuvsign: 1,
202 libencode: 0,
203 };
204 static struct qt_video_priv qt_yv12 = {
205 fcc: QUICKTIME_YUV420,
206 libencode: 0,
207 };
208 static struct qt_video_priv qt_jpeg = {
209 fcc: QUICKTIME_JPEG,
210 libencode: 0,
211 };
212
213 static const struct ng_format_list qt_vformats[] = {
214 {
215 name: "raw",
216 ext: "mov",
217 fmtid: VIDEO_RGB24,
218 priv: &qt_raw,
219 },{
220 name: "yuv2",
221 ext: "mov",
222 fmtid: VIDEO_YUYV,
223 priv: &qt_yuv2,
224 },{
225 name: "yv12",
226 ext: "mov",
227 fmtid: VIDEO_YUV420P,
228 priv: &qt_yv12,
229 },{
230 name: "jpeg",
231 ext: "mov",
232 fmtid: VIDEO_JPEG,
233 priv: &qt_jpeg,
234 },{
235 /* EOF */
236 }
237 };
238
239 static struct qt_audio_priv qt_mono8 = {
240 fcc: QUICKTIME_RAW,
241 libencode: 0,
242 };
243 static struct qt_audio_priv qt_mono16 = {
244 fcc: QUICKTIME_TWOS,
245 libencode: 0,
246 };
247 static struct qt_audio_priv qt_stereo = {
248 fcc: QUICKTIME_TWOS,
249 libencode: 0,
250 };
251 static const struct ng_format_list qt_aformats[] = {
252 {
253 name: "mono8",
254 ext: "mov",
255 fmtid: AUDIO_U8_MONO,
256 priv: &qt_mono8,
257 },{
258 name: "mono16",
259 ext: "mov",
260 fmtid: AUDIO_S16_BE_MONO,
261 priv: &qt_mono16,
262 },{
263 name: "stereo",
264 ext: "mov",
265 fmtid: AUDIO_S16_BE_STEREO,
266 priv: &qt_stereo,
267 },{
268 /* EOF */
269 }
270 };
271
272 struct ng_writer qt_writer = {
273 name: "qt",
274 desc: "Apple QuickTime format",
275 combined: 1,
276 video: qt_vformats,
277 audio: qt_aformats,
278 wr_open: qt_open,
279 wr_video: qt_video,
280 wr_audio: qt_audio,
281 wr_close: qt_close,
282 };
283
284 /* ----------------------------------------------------------------------- */
285
286 #if 0
287 /* debug only */
288 static void dump_codecs(void)
289 {
290 lqt_codec_info_t **info;
291 int i,j;
292
293 info = lqt_query_registry(1, 1, 1, 1);
294 for (i = 0; info[i] != NULL; i++) {
295 fprintf(stderr,"lqt: %s codec: %s [%s]\n",
296 info[i]->type == LQT_CODEC_AUDIO ? "audio" : "video",
297 info[i]->name,info[i]->long_name);
298 fprintf(stderr," encode: %s\n",
299 info[i]->direction == LQT_DIRECTION_DECODE ? "no" : "yes");
300 fprintf(stderr," decode: %s\n",
301 info[i]->direction == LQT_DIRECTION_ENCODE ? "no" : "yes");
302 for (j = 0; j < info[i]->num_fourccs; j++)
303 fprintf(stderr," fcc : %s\n",info[i]->fourccs[j]);
304 for (j = 0; j < info[i]->num_encoding_colormodels; j++)
305 fprintf(stderr," cmodel: %s\n",
306 lqt_get_colormodel_string(info[i]->encoding_colormodels[j]));
307 fprintf(stderr,"\n");
308 }
309 lqt_destroy_codec_info(info);
310 }
311 #endif
312
313 static struct ng_format_list*
314 qt_list_add(struct ng_format_list* list,
315 char *name, char *desc, char *ext, int fmtid, void *priv)
316 {
317 int n;
318
319 for (n = 0; list[n].name != NULL; n++)
320 /* nothing */;
321 list = realloc(list,sizeof(struct ng_format_list)*(n+2));
322 memset(list+n,0,sizeof(struct ng_format_list)*2);
323 list[n].name = strdup(name);
324 list[n].desc = strdup(desc);
325 list[n].ext = strdup(ext);
326 list[n].fmtid = fmtid;
327 list[n].priv = priv;
328 return list;
329 }
330
331 static struct ng_format_list* video_list(void)
332 {
333 static int debug = 0;
334 lqt_codec_info_t **info;
335 struct ng_format_list *video;
336 int i,j,k,skip,fmtid;
337 unsigned int cmodel;
338 struct qt_video_priv *vp;
339
340 /* handle video encoders */
341 video = malloc(sizeof(qt_vformats));
342 memcpy(video,qt_vformats,sizeof(qt_vformats));
343 info = lqt_query_registry(0, 1, 1, 0);
344 for (i = 0; info[i] != NULL; i++) {
345 if (debug) {
346 fprintf(stderr,"\nlqt: %s codec: %s [%s]\n",
347 info[i]->type == LQT_CODEC_AUDIO ? "audio" : "video",
348 info[i]->name,info[i]->long_name);
349 for (j = 0; j < info[i]->num_fourccs; j++)
350 fprintf(stderr," fcc : %s\n",info[i]->fourccs[j]);
351 for (j = 0; j < info[i]->num_encoding_colormodels; j++)
352 fprintf(stderr," cmodel: %d [%s]\n",
353 info[i]->encoding_colormodels[j],
354 lqt_get_colormodel_string(info[i]->encoding_colormodels[j]));
355 }
356
357 /* sanity checks */
358 if (0 == info[i]->num_fourccs) {
359 if (debug)
360 fprintf(stderr," skipping, no fourcc\n");
361 continue;
362 }
363
364 /* avoid dup entries */
365 skip = 0;
366 for (j = 0; video[j].name != NULL; j++) {
367 const struct qt_video_priv *p = video[j].priv;
368 for (k = 0; k < info[i]->num_fourccs; k++)
369 if (0 == strcmp(p->fcc,info[i]->fourccs[k]))
370 skip = 1;
371 }
372 if (skip) {
373 if (debug)
374 fprintf(stderr," skipping, fourcc already in list\n");
375 continue;
376 }
377
378 /* pick colormodel */
379 fmtid = VIDEO_NONE;
380 cmodel = 0;
381 for (j = 0; j < info[i]->num_encoding_colormodels; j++) {
382 cmodel = info[i]->encoding_colormodels[j];
383 if (cmodel>= sizeof(cmodels)/sizeof(int))
384 continue;
385 if (!cmodels[cmodel])
386 continue;
387 fmtid = cmodels[cmodel];
388 break;
389 }
390 if (VIDEO_NONE == fmtid) {
391 if (debug)
392 fprintf(stderr," skipping, can't handle color model\n");
393 continue;
394 }
395
396 /* all fine */
397 if (debug)
398 fprintf(stderr," ok, using fmtid %d [%s]\n",
399 fmtid,ng_vfmt_to_desc[fmtid]);
400 vp = malloc(sizeof(*vp));
401 memset(vp,0,sizeof(*vp));
402 strcpy(vp->fcc,info[i]->fourccs[0]);
403 vp->libencode = 1;
404 vp->cmodel = cmodel;
405 video = qt_list_add(video,vp->fcc,info[i]->long_name,"mov",fmtid,vp);
406 }
407 lqt_destroy_codec_info(info);
408 return video;
409 }
410
411 static struct ng_format_list* audio_list(void)
412 {
413 static int debug = 0;
414 lqt_codec_info_t **info;
415 struct ng_format_list *audio;
416 int i,j;
417 struct qt_audio_priv *ap;
418
419 /* handle video encoders */
420 audio = malloc(sizeof(qt_aformats));
421 memcpy(audio,qt_aformats,sizeof(qt_aformats));
422 info = lqt_query_registry(1, 0, 1, 0);
423 for (i = 0; info[i] != NULL; i++) {
424 if (debug) {
425 fprintf(stderr,"\nlqt: %s codec: %s [%s]\n",
426 info[i]->type == LQT_CODEC_AUDIO ? "audio" : "video",
427 info[i]->name,info[i]->long_name);
428 for (j = 0; j < info[i]->num_fourccs; j++)
429 fprintf(stderr," fcc : %s\n",info[i]->fourccs[j]);
430 }
431
432 /* sanity checks */
433 if (0 == info[i]->num_fourccs) {
434 if (debug)
435 fprintf(stderr," skipping, no fourcc\n");
436 continue;
437 }
438
439 /* skip uncompressed formats */
440 if (0 == strcmp(info[i]->fourccs[0],QUICKTIME_RAW) ||
441 0 == strcmp(info[i]->fourccs[0],QUICKTIME_ULAW) ||
442 0 == strcmp(info[i]->fourccs[0],QUICKTIME_IMA4) || /* ??? */
443 0 == strcmp(info[i]->fourccs[0],QUICKTIME_TWOS)) {
444 if (debug)
445 fprintf(stderr," skipping, uncompressed\n");
446 continue;
447 }
448
449 /* all fine */
450 if (debug)
451 fprintf(stderr," ok\n");
452 ap = malloc(sizeof(*ap));
453 memset(ap,0,sizeof(*ap));
454 strcpy(ap->fcc,info[i]->fourccs[0]);
455 ap->libencode = 1;
456 audio = qt_list_add(audio,ap->fcc,info[i]->long_name,"mov",
457 AUDIO_S16_NATIVE_MONO,ap);
458 }
459 lqt_destroy_codec_info(info);
460 return audio;
461 }
462
463 extern void ng_plugin_init(void);
464 void ng_plugin_init(void)
465 {
466 qt_writer.video = video_list();
467 qt_writer.audio = audio_list();
468 ng_writer_register(NG_PLUGIN_MAGIC,__FILE__,&qt_writer);
469 }
470
|
This page was automatically generated by the
LXR engine.
|