1 /*
2 * export_mov.c
3 *
4 * Copyright (C) Thomas Oestreich - June 2001
5 * Copyright (C) (2002) Christian Vogelgsang
6 * <Vogelgsang@informatik.uni-erlangen.de> (extension for all codecs supported
7 * by quicktime4linux
8 * <stefanscheffler@gmx.net> 2004 fixes & features
9 * Copyright (C) ken@hero.com 2001 (initial module author)
10 *
11 * This file is part of transcode, a video stream processing tool
12 *
13 * transcode is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2, or (at your option)
16 * any later version.
17 *
18 * transcode is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with GNU Make; see the file COPYING. If not, write to
25 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
26 */
27
28 #define MOD_NAME "export_mov.so"
29 #define MOD_VERSION "v0.1.2 (2004-01-19)"
30 #define MOD_CODEC "(video) * | (audio) *"
31
32 #include "transcode.h"
33 #include "import/magic.h"
34 #include "encoder.h"
35 #include "libtc/optstr.h"
36 #include "libtcvideo/tcvideo.h"
37 #include <stdio.h>
38 #include <stdlib.h>
39
40 /* verbose flag */
41 static int verbose_flag=TC_QUIET;
42
43 /* set encoder capabilities */
44 static int capability_flag=
45 /* audio formats */
46 TC_CAP_PCM| /* pcm audio */
47 /* video formats */
48 TC_CAP_RGB| /* rgb frames */
49 TC_CAP_YUV| /* YUV 4:2:0 */
50 TC_CAP_YUY2|
51 TC_CAP_VID|
52 TC_CAP_YUV422; /* YUV 4:2:2 */
53
54 #define MOD_PRE mov
55 #include "export_def.h"
56
57 #include <quicktime.h>
58 #include <colormodels.h>
59 #include <lqt.h>
60
61 #define QT_LIST_AUDIO "audio codec"
62 #define QT_LIST_VIDEO "video codec"
63 #define QT_LIST_PARM "parameters"
64
65 /* exported quicktime file */
66 static quicktime_t *qtfile = NULL;
67
68 /* row pointer for source frames */
69 static unsigned char** row_ptr = NULL;
70
71 /* temporary buffer */
72 static uint8_t *tmp_buf;
73
74 /* toggle for raw frame export */
75 static int rawVideo = 0;
76 static int rawAudio = 0;
77
78 /* colormodels */
79 static ImageFormat tc_cm = 0;
80 static int qt_cm = 0;
81
82 /* store frame dimension */
83 static int w = 0, h = 0;
84
85 /* audio channels */
86 static int channels = 0;
87
88 /* sample size */
89 static int bits = 0;
90
91 /* encode audio buffers */
92 static int16_t* audbuf0 = NULL;
93 static int16_t* audbuf1 = NULL;
94
95 struct qt_codec_list {
96 char *name;
97 char *internal_name;
98 char *comments;
99 };
100
101 static TCVHandle tcvhandle = 0;
102
103 /* special paramters not retrievable from lqt */
104 struct qt_codec_list qt_param_list[] = {
105 {"", "", ""},
106 {"Special Parameters:", "", ""},
107 {"copyright", "", "Copyright string (no '=' or ',' allowed)"},
108 {"name", "", "Name string (no '=' or ',' allowed) "},
109 {"info", "", "Info string (no '=' or ',' allowed) "},
110 {NULL, NULL, NULL}};
111
112 #ifdef LIBQUICKTIME_000904
113 /* from libquicktime */
tc_quicktime_get_timescale(double frame_rate)114 static int tc_quicktime_get_timescale(double frame_rate)
115 {
116 int timescale = 600;
117 /* Encode the 29.97, 23.976, 59.94 framerates */
118 if(frame_rate - (int)frame_rate != 0)
119 timescale = (int)(frame_rate * 1001 + 0.5);
120 else
121 if((600 / frame_rate) - (int)(600 / frame_rate) != 0)
122 timescale = (int)(frame_rate * 100 + 0.5);
123 return timescale;
124 }
125 #endif
126
127 /* print list of things. Shamelessly stolen from export_ffmpeg.c */
list(char * list_type)128 static int list(char *list_type)
129 {
130 int cod = 0;
131 int i = 0;
132
133 lqt_codec_info_t ** qi = NULL;
134
135
136 if (strcmp(list_type, QT_LIST_VIDEO) == 0) {
137 qi = lqt_query_registry(0, 1, 1, 0);
138 } else if (strcmp(list_type, QT_LIST_AUDIO) == 0) {
139 qi = lqt_query_registry(1, 0, 1, 0);
140 } else {
141 qi = lqt_query_registry(1, 1, 1, 0);
142 }
143
144 tc_log_info(MOD_NAME, "List of supported %s:", list_type);
145 tc_log_info(MOD_NAME, "Name comments");
146 tc_log_info(MOD_NAME, "--------------- "
147 "-----------------------------------");
148 while (qi[cod] != NULL) {
149 if (strcmp(list_type, QT_LIST_PARM) == 0) {
150 tc_log_info(MOD_NAME, "%s:", qi[cod]->name);
151 for(i = 0; i < qi[cod]->num_encoding_parameters; i++) {
152 if (qi[cod]->encoding_parameters[i].type != LQT_PARAMETER_SECTION) {
153 tc_log_info(MOD_NAME, " %-23s %s",
154 qi[cod]->encoding_parameters[i].name,
155 qi[cod]->encoding_parameters[i].real_name);
156 }
157 }
158 } else {
159 tc_log_info(MOD_NAME, "%-23s %s",
160 qi[cod]->name,
161 qi[cod]->description);
162 }
163 cod++;
164 }
165
166 return 1;
167 }
168
169 /* ------------------------------------------------------------
170 *
171 * open outputfile
172 *
173 * ------------------------------------------------------------*/
174
175 MOD_open
176 {
177 if(param->flag == TC_VIDEO)
178 return(0);
179
180 if(param->flag == TC_AUDIO)
181 return(0);
182
183 return(TC_EXPORT_ERROR);
184 }
185
186 /* ------------------------------------------------------------
187 *
188 * init codec
189 *
190 * ------------------------------------------------------------*/
191
192 MOD_init
193 {
194
195 int list_was_called = 0;
196
197 /* for codec parameters */
198 int jpeg_quality = 0;
199 int div3_bitrate_tolerance = 500000;
200 int vorbis_max_bitrate = 192;
201 int vorbis_min_bitrate = 128;
202
203 /* overwriting empty parameters now saves trouble later */
204 if (vob->ex_v_fcc == NULL) vob->ex_v_fcc = "";
205 if (vob->ex_a_fcc == NULL) vob->ex_a_fcc = "";
206 if (vob->ex_profile_name == NULL) vob->ex_profile_name = "";
207
208 if (!strcasecmp(vob->ex_v_fcc, "list")) list_was_called = list(QT_LIST_VIDEO);
209 if (!strcasecmp(vob->ex_a_fcc, "list")) list_was_called = list(QT_LIST_AUDIO);
210 if (!strcasecmp(vob->ex_profile_name, "list")) {
211 int i;
212
213 list_was_called = list(QT_LIST_PARM);
214
215 /* list special paramters at the end */
216 for(i = 0; qt_param_list[i].name != NULL; i++) {
217 tc_log_info(MOD_NAME, " %-23s %s",
218 qt_param_list[i].name,
219 qt_param_list[i].comments);
220 }
221 }
222
223 if (list_was_called) {
224 return(TC_EXPORT_ERROR);
225 }
226 /* video setup -------------------------------------------------- */
227 if(param->flag == TC_VIDEO) {
228
229 lqt_codec_info_t ** qt_codec_info = NULL;
230
231 char *qt_codec;
232 int divx_bitrate;
233
234 /* fetch frame size */
235 w = vob->ex_v_width;
236 h = vob->ex_v_height;
237
238 /* fetch qt codec from -F switch */
239 qt_codec = tc_strdup(vob->ex_v_fcc);
240
241 /* open target file for writing */
242 if(NULL == (qtfile = quicktime_open((char *)vob->video_out_file, 0, 1)) ){
243 tc_log_warn(MOD_NAME, "error opening qt file '%s'",
244 vob->video_out_file);
245 return(TC_EXPORT_ERROR);
246 }
247
248 /* set qt codecs */
249 /* not needed for passthrough*/
250 if (vob->im_v_codec != CODEC_RAW && vob->im_v_codec != CODEC_RAW_YUV && vob->im_v_codec != CODEC_RAW_RGB) {
251 if(qt_codec == NULL || strlen(qt_codec)==0) {
252 /* default */
253 qt_codec = "mjpa";
254 if (verbose_flag != TC_QUIET) {
255 tc_log_info(MOD_NAME, "Empty qt codec name. Switching to %s use '-F list'"
256 " to get a list of supported codec.", qt_codec);
257 }
258 }
259
260 /* check if we can encode with this codec */
261 qt_codec_info = lqt_find_video_codec_by_name(qt_codec);
262 if (!qt_codec_info) {
263 tc_log_warn(MOD_NAME, "qt video codec '%s' not supported!", qt_codec);
264 return(TC_EXPORT_ERROR);
265 }
266
267 #if !defined(LIBQUICKTIME_000904)
268 /* set proposed video codec */
269 lqt_set_video(qtfile, 1, w, h, vob->ex_fps,qt_codec_info[0]);
270 #else
271 /* set proposed video codec */
272 lqt_set_video(qtfile, 1, w, h,
273 tc_quicktime_get_timescale(vob->ex_fps) / vob->ex_fps+0.5,
274 tc_quicktime_get_timescale(vob->ex_fps), qt_codec_info[0]);
275 #endif
276 }
277
278 /* set color model */
279 switch(vob->im_v_codec) {
280 case CODEC_RGB:
281 qt_cm = BC_RGB888;
282 tc_cm = IMG_RGB_DEFAULT;
283 break;
284
285 case CODEC_YUV:
286 qt_cm = BC_YUV420P;
287 tc_cm = IMG_YUV_DEFAULT;
288 break;
289
290 case CODEC_YUV422:
291 tc_cm = IMG_YUV422P;
292 qt_cm = BC_YUV422P;
293 break;
294
295 case CODEC_YUY2:
296 tc_cm = IMG_YUY2;
297 qt_cm = BC_YUV422;
298 break;
299
300 /* passthrough */
301 case CODEC_RAW_RGB:
302 case CODEC_RAW_YUV:
303 case CODEC_RAW:
304 /* set out output codec to input codec */
305 if(qt_codec == NULL || strlen(qt_codec)==0) {
306 switch (vob->v_codec_flag) {
307 case TC_CODEC_MJPEG:
308 quicktime_set_video(qtfile, 1, w, h, vob->ex_fps,"jpeg");
309 break;
310
311 case TC_CODEC_MPEG:
312 quicktime_set_video(qtfile, 1, w, h, vob->ex_fps,"mpeg");
313 break;
314
315 case TC_CODEC_DV:
316 quicktime_set_video(qtfile, 1, w, h, vob->ex_fps,"dvc ");
317 break;
318
319 case TC_CODEC_SVQ1:
320 quicktime_set_video(qtfile, 1, w, h, vob->ex_fps,"SVQ1");
321 break;
322
323 case TC_CODEC_SVQ3:
324 quicktime_set_video(qtfile, 1, w, h, vob->ex_fps,"SVQ3");
325 break;
326
327 case TC_CODEC_YUV420P:
328 quicktime_set_video(qtfile, 1, w, h, vob->ex_fps,"yv12");
329 break;
330
331 case TC_CODEC_RGB:
332 quicktime_set_video(qtfile, 1, w, h, vob->ex_fps,"raw ");
333 break;
334
335 case TC_CODEC_YUV2: /* test this */
336 quicktime_set_video(qtfile, 1, w, h, vob->ex_fps,"yuv2");
337 break;
338
339 case TC_CODEC_DIVX3:
340 case TC_CODEC_DIVX4:
341 case TC_CODEC_DIVX5:
342 quicktime_set_video(qtfile, 1, w, h, vob->ex_fps,"DIVX");
343 break;
344
345 default:
346 tc_log_warn(MOD_NAME, "codec '%lx' not supported for pass-through",
347 vob->v_codec_flag);
348 tc_log_warn(MOD_NAME, " If you really know what you are doing you can force");
349 tc_log_warn(MOD_NAME, " a codec via -F <vc>, '-F list' returns a list");
350 return(TC_EXPORT_ERROR);
351 break;
352 }
353 }
354 else {
355 tc_log_warn(MOD_NAME,"Overriding the output codec is almost never a good idea");
356 quicktime_set_video(qtfile, 1, w, h, vob->ex_fps,qt_codec);
357 }
358
359 rawVideo = 1;
360 break;
361
362 default:
363 /* unsupported internal format */
364 tc_log_warn(MOD_NAME, "unsupported internal video format %x",
365 vob->ex_v_codec);
366 return(TC_EXPORT_ERROR);
367 break;
368 }
369
370 /* if cs conversation not supported for codec do conversation */
371 /* not required for pass through */
372 if (vob->im_v_codec != CODEC_RAW && vob->im_v_codec != CODEC_RAW_YUV && vob->im_v_codec != CODEC_RAW_RGB) {
373 if (quicktime_writes_cmodel(qtfile, qt_cm, 0) != 1) {
374 if (verbose_flag != TC_QUIET) {
375 tc_log_info(MOD_NAME,"Colorspace not supported for this codec converting to RGB");
376 }
377
378 qt_cm = BC_RGB888;
379 lqt_set_cmodel(qtfile, 0, qt_cm);
380
381 tcvhandle = tcv_init();
382 if (!tcvhandle) {
383 tc_log_warn(MOD_NAME, "image conversion init failed");
384 return TC_EXPORT_ERROR;
385 }
386
387 } else {
388 lqt_set_cmodel(qtfile, 0, qt_cm);
389 }
390 }
391
392 /* set codec parameters */
393 /* tc uses kb */
394 divx_bitrate = vob->divxbitrate * 1000;
395 /* if max bitrate > bitrate use difference for bitrate tolerance */
396 if (vob->video_max_bitrate > vob->divxbitrate) div3_bitrate_tolerance = (vob->video_max_bitrate - vob->divxbitrate) * 1000;
397
398
399 /* Audio */
400 /* must be changed when it's changed in lqt; "bit_rate" conflicts with ffmpeg video codec */
401 if (strcmp(qt_codec,"ffmpeg_mp2") == 0||
402 strcmp(qt_codec,"ffmpeg_mp3") == 0||
403 strcmp(qt_codec,"ffmpeg_ac3") == 0)
404 quicktime_set_parameter(qtfile, "bit_rate", &vob->mp3bitrate);
405
406 if (strcmp(qt_codec,"lame") == 0)
407 quicktime_set_parameter(qtfile, "mp3_bitrate", &vob->mp3bitrate);
408
409 /* have to check this */
410 if (strcmp(qt_codec,"vorbis") == 0) {
411 quicktime_set_parameter(qtfile, "vorbis_bitrate", &vob->mp3bitrate);
412 quicktime_set_parameter(qtfile, "vorbis_max_bitrate", &vorbis_max_bitrate);
413 quicktime_set_parameter(qtfile, "vorbis_min_bitrate", &vorbis_min_bitrate);
414 quicktime_set_parameter(qtfile, "vorbis_vbr", &vob->a_vbr);
415 }
416
417 /* Video */
418 /* jpeg_quality == 0-100 ; tc quality setting (-Q) == 1-5 */
419 jpeg_quality = 20 * vob->divxquality;
420
421 if (strcmp(qt_codec,"mjpa") == 0||
422 strcmp(qt_codec,"jpeg") == 0)
423 quicktime_set_parameter(qtfile, "jpeg_quality", &jpeg_quality);
424
425 /* looks terrible :/ */
426 if (strcmp(qt_codec,"ffmpeg_mjpg") == 0||
427 strcmp(qt_codec,"ffmpeg_h263p") == 0||
428 strcmp(qt_codec,"ffmpeg_h263") == 0||
429 strcmp(qt_codec,"ffmpeg_msmpeg4v3") == 0||
430 strcmp(qt_codec,"ffmpeg_msmpeg4v2") == 0||
431 strcmp(qt_codec,"ffmpeg_msmpeg4v1") == 0||
432 strcmp(qt_codec,"ffmpeg_msmpg1") == 0||
433 strcmp(qt_codec,"ffmpeg_mpg4") == 0){
434
435 int min_bitrate = 0;
436
437 quicktime_set_parameter(qtfile, "flags_gray", &vob->decolor); /* set format different for this */
438
439 switch (vob->decolor) {
440 case 1:
441 quicktime_set_parameter(qtfile, "aspect_ratio_info", "Square");
442 break;
443
444 case 2:
445 quicktime_set_parameter(qtfile, "aspect_ratio_info", "4:3");
446 break;
447
448 case 3:
449 quicktime_set_parameter(qtfile, "aspect_ratio_info", "16:9");
450 break;
451
452 default:
453 tc_log_warn(MOD_NAME, "Given aspect ratio not supported, using default");
454 break;
455 }
456
457 quicktime_set_parameter(qtfile, "flags_gray", &vob->decolor);
458 quicktime_set_parameter(qtfile, "bit_rate", &vob->divxbitrate);
459 quicktime_set_parameter(qtfile, "bit_rate_tolerance", &div3_bitrate_tolerance);
460
461 min_bitrate = vob->divxbitrate - div3_bitrate_tolerance;
462 quicktime_set_parameter(qtfile, "rc_max_rate", &vob->video_max_bitrate);
463 quicktime_set_parameter(qtfile, "qmax", &vob->max_quantizer);
464 quicktime_set_parameter(qtfile, "qmin", &vob->min_quantizer);
465
466
467 if (!strcmp(qt_codec,"ffmpeg_mjpg"))
468 quicktime_set_parameter(qtfile, "gob_size", &vob->divxkeyframes);
469 }
470
471 if (strcmp(vob->ex_v_fcc,"opendivx") == 0) {
472 quicktime_set_parameter(qtfile, "divx_bitrate", &divx_bitrate);
473 quicktime_set_parameter(qtfile, "divx_rc_period", &vob->rc_period);
474 quicktime_set_parameter(qtfile, "divx_rc_reaction_period", &vob->rc_reaction_period);
475 quicktime_set_parameter(qtfile, "divx_rc_reaction_ratio", &vob->rc_reaction_ratio);
476 quicktime_set_parameter(qtfile, "divx_max_key_interval", &vob->divxkeyframes);
477 quicktime_set_parameter(qtfile, "divx_min_quantizer", &vob->min_quantizer);
478 quicktime_set_parameter(qtfile, "divx_max_quantizer", &vob->max_quantizer);
479 quicktime_set_parameter(qtfile, "divx_quantizer", &vob->min_quantizer);
480 quicktime_set_parameter(qtfile, "divx_quality", &vob->quality);
481 }
482
483 if (strcmp(qt_codec,"rtjpeg") == 0)
484 quicktime_set_parameter(qtfile, "rtjpeg_quality", &jpeg_quality);
485
486
487 /* set extended parameters */
488 if (vob->ex_profile_name != NULL) {
489 int i;
490 char meta[128];
491
492 if (optstr_get(vob->ex_profile_name, "copyright", "%128[^:]", meta) > 0) {
493 quicktime_set_copyright(qtfile, meta);
494 }
495 if(optstr_get(vob->ex_profile_name, "name", "%128[^:]", meta) > 0) {
496 quicktime_set_name(qtfile, meta);
497 }
498 if(optstr_get(vob->ex_profile_name, "info", "%128[^:]", meta) > 0) {
499 quicktime_set_name(qtfile, meta);
500 }
501
502 for (i = 0; i < (* qt_codec_info)->num_encoding_parameters; i++) {
503 lqt_parameter_info_t param = (* qt_codec_info)->encoding_parameters[i];
504
505 if (param.type == LQT_PARAMETER_INT) {
506 int val;
507 if (optstr_get(vob->ex_profile_name, param.name, "%i", &val) > 0) {
508 lqt_set_video_parameter(qtfile, 0, param.name, &val);
509 }
510 }
511 else if (param.type == LQT_PARAMETER_FLOAT) {
512 float val;
513 if (optstr_get(vob->ex_profile_name, param.name, "%f", &val) > 0) {
514 lqt_set_video_parameter(qtfile, 0, param.name, &val);
515 }
516 }
517 else if (param.type == LQT_PARAMETER_STRING || param.type == LQT_PARAMETER_STRINGLIST) {
518 char val[128];
519 if (optstr_get(vob->ex_profile_name, param.name, "%128[^:]", val) > 0) {
520 lqt_set_video_parameter(qtfile, 0, param.name, val);
521 }
522 }
523 }
524 }
525
526 /* alloc row pointers for frame encoding */
527 row_ptr = malloc (sizeof(char *) * h);
528
529 /* same for temp buffer ... used during yuy2/yv12 encoding */
530 tmp_buf = malloc (w*h*2);
531
532 /* verbose */
533 tc_log_info(MOD_NAME, "video codec='%s' w=%d h=%d fps=%g",
534 qt_codec,w,h,vob->ex_fps);
535
536 return(0);
537 }
538
539 /* audio setup -------------------------------------------------- */
540 if(param->flag == TC_AUDIO){
541 const char *qt_codec;
542 lqt_codec_info_t ** qt_codec_info = 0;
543
544 /* no audio setup if we don't have any channels (size == 0 might be better?)*/
545 if(vob->dm_chan==0) return 0;
546
547 /* check given audio format */
548 if((vob->dm_chan!=1)&&(vob->dm_chan!=2)) {
549 tc_log_warn(MOD_NAME, "Only mono or stereo audio supported");
550 return(TC_EXPORT_ERROR);
551 }
552 channels = vob->dm_chan;
553 bits = vob->dm_bits;
554
555 /* fetch qt codec from -F switch */
556 qt_codec = vob->ex_a_fcc;
557 if(qt_codec == NULL || strlen(qt_codec)==0) {
558 qt_codec = "ima4";
559 if (verbose_flag != TC_QUIET) {
560 tc_log_info(MOD_NAME, "empty qt codec name - switching to %s"
561 " use '-F ,list'", qt_codec);
562 tc_log_info(MOD_NAME, "to get a list of supported codec");
563 }
564 }
565
566
567 /* check encoder mode */
568 switch(vob->im_a_codec) {
569 case CODEC_PCM:
570 /* allocate sample buffers */
571 audbuf0 = (int16_t*)malloc(vob->ex_a_size);
572 audbuf1 = (int16_t*)malloc(vob->ex_a_size);
573
574 /* need to encode audio */
575 rawAudio = 0;
576 break;
577
578 default:
579 /* unsupported internal format */
580 tc_log_warn(MOD_NAME, "unsupported internal audio format %x",
581 vob->ex_v_codec);
582 return(TC_EXPORT_ERROR);
583 break;
584 }
585
586 qt_codec_info = lqt_find_audio_codec_by_name(qt_codec);
587 if (!qt_codec_info){
588 tc_log_warn(MOD_NAME, "qt audio codec '%s' unsupported",
589 qt_codec);
590 return(TC_EXPORT_ERROR);
591 }
592
593 /* setup audio parameters */
594 lqt_set_audio(qtfile,channels,vob->a_rate,bits,qt_codec_info[0]);
595
596 /* verbose */
597 tc_log_info(MOD_NAME, "audio codec='%s' bits=%d chan=%d rate=%d",
598 qt_codec,bits,channels,vob->a_rate);
599 return(0);
600 }
601
602 return(TC_EXPORT_ERROR);
603 }
604
605 /* ------------------------------------------------------------
606 *
607 * encode and export frame
608 *
609 * ------------------------------------------------------------*/
610
611
612 MOD_encode
613 {
614 /* video -------------------------------------------------------- */
615 if(param->flag == TC_VIDEO) {
616 vob_t *vob = tc_get_vob();
617
618 /* raw mode is easy */
619 if(rawVideo) {
620 /* add divx keyframes if needed */
621 if(quicktime_divx_is_key(param->buffer, param->size) == 1) quicktime_insert_keyframe(qtfile, (int)tc_get_frames_encoded(), 0);
622 if(quicktime_write_frame(qtfile,param->buffer,param->size,0)<0) {
623 tc_log_warn(MOD_NAME, "error writing raw video frame");
624 return(TC_EXPORT_ERROR);
625 }
626 }
627
628 /* encode frame */
629 else {
630 uint8_t *ptr = param->buffer;
631 int iy;
632
633 switch(qt_cm) {
634 case BC_RGB888:
635 /* convert to rgb if unsupported */
636 if (tc_cm != IMG_RGB24) {
637 if (!tcv_convert(tcvhandle, param->buffer, param->buffer,
638 vob->ex_v_width, vob->ex_v_height,
639 tc_cm, IMG_RGB24)) {
640 tc_log_warn(MOD_NAME, "image format conversion failed");
641 return TC_EXPORT_ERROR;
642 }
643 }
644
645 /* setup row pointers for RGB */
646 for (iy = 0; iy < h; iy++) {
647 row_ptr[iy] = ptr;
648 ptr += w*3;
649 }
650 break;
651 case BC_YUV420P:
652 /* setup row pointers for YUV420P */
653 row_ptr[0] = ptr;
654 ptr = ptr + (h * w);
655 /* note, quicktime wants YV12 so we reverse the planes */
656 row_ptr[2] = ptr;
657 ptr = ptr + (h * w) / 4;
658 row_ptr[1] = ptr;
659 break;
660 case BC_YUV422P:
661 /* setup row pointers for YUV422P */
662 row_ptr[0] = ptr;
663 ptr = ptr + (h * w);
664 row_ptr[1] = ptr;
665 ptr = ptr + (h * w) / 2;
666 row_ptr[2] = ptr;
667 break;
668 case BC_YUV422:
669 /* setup row pointers for YUY2 */
670 for (iy = 0; iy < h; iy++) {
671 row_ptr[iy] = ptr;
672 ptr += w*2;
673 }
674 break;
675 }
676
677 if(quicktime_encode_video(qtfile, row_ptr, 0)<0) {
678 tc_log_warn(MOD_NAME, "error encoding video frame");
679 return(TC_EXPORT_ERROR);
680 }
681 }
682
683 return(0);
684 }
685 /* audio -------------------------------------------------------- */
686 if(param->flag == TC_AUDIO){
687 /* raw mode is easy */
688 if(rawAudio) {
689 if(quicktime_write_frame(qtfile,
690 param->buffer,param->size,0)<0) {
691 tc_log_warn(MOD_NAME, "error writing raw audio frame");
692 return(TC_EXPORT_ERROR);
693 }
694 }
695 /* encode audio */
696 else {
697 int s,t;
698 int16_t *aptr[2] = { audbuf0, audbuf1 };
699
700 /* calc number of samples */
701 int samples = param->size;
702
703 /* no audio */
704 if (samples == 0) return 0;
705
706 if(bits==16)
707 samples >>= 1;
708 if(channels==2)
709 samples >>= 1;
710
711 /* fill audio buffer */
712 if(bits==8) {
713 /* UNTESTED: please verify :) */
714 if(channels==1) {
715 for(s=0;s<samples;s++)
716 audbuf0[s] = ((((int16_t)param->buffer[s]) << 8)-0x8000);
717 }
718 else /* stereo */ {
719 for(s=0,t=0;s<samples;s++,t+=2) {
720 audbuf0[s] = ((((int16_t)param->buffer[t]) << 8)-0x8000);
721 audbuf1[s] = ((((int16_t)param->buffer[t+1]) << 8)-0x8000);
722 }
723 }
724 }
725 else /* 16 bit */ {
726 if(channels==1) {
727 aptr[0] = (int16_t *)param->buffer;
728 }
729 else /* stereo */ {
730 /* decouple channels */
731 for(s=0,t=0;s<samples;s++,t+=2) {
732 audbuf0[s] = ((int16_t *)param->buffer)[t];
733 audbuf1[s] = ((int16_t *)param->buffer)[t+1];
734 }
735 }
736 }
737
738 /* encode audio samples */
739 if ((quicktime_encode_audio(qtfile, aptr, NULL, samples)<0)){
740 tc_log_warn(MOD_NAME, "error encoding audio frame");
741 return(TC_EXPORT_ERROR);
742 }
743 }
744
745 return(0);
746 }
747
748 return(TC_EXPORT_ERROR);
749 }
750
751
752 /* ------------------------------------------------------------
753 *
754 * stop encoder
755 *
756 * ------------------------------------------------------------*/
757
758 MOD_stop
759 {
760
761 if(param->flag == TC_VIDEO) {
762 /* free row pointers */
763 if(row_ptr!=NULL)
764 free(row_ptr);
765 return(0);
766 }
767
768 if(param->flag == TC_AUDIO) {
769 /* free audio buffers */
770 if(audbuf0!=NULL)
771 free(audbuf0);
772 if(audbuf1!=NULL)
773 free(audbuf1);
774 return(0);
775 }
776
777 return(TC_EXPORT_ERROR);
778 }
779
780 /* ------------------------------------------------------------
781 *
782 * close outputfile
783 *
784 * ------------------------------------------------------------*/
785
786 MOD_close
787 {
788 if(param->flag == TC_VIDEO){
789 /* close quicktime file */
790 quicktime_close(qtfile);
791 qtfile=NULL;
792 return(0);
793 }
794
795 if(param->flag == TC_AUDIO) {
796 return(0);
797 }
798
799 return(TC_EXPORT_ERROR);
800
801 }
802