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