Hi, export_mov sometimes produces a green image in YUV420 mode. The attached patches should fix that. I seemed to have wrongly assumed that libquicktime can convert between all its supported colormodels, which isn't the case. It now converts to RGB if there's no conversation in libquicktime. Quite expensive, but this should always work.
Better would be finding the native colormodel of whatever codec used and converting to that. I guess with 1.1 that wouldn't be too hard. Something for my todo list. YUV422 in 1.0 probably still has that problem but there's no direct conversation to RGB for that and going via YUV420 seems quite wasteful, so I didn't bother. I killed a few signedness warnings as well and tidied things up a bit. tc-mov-green-1.0-2.diff is for the 1.0 branch tc-mov-green-1.1.diff for 1.1 stefan
--- cvs/mplayer/transcode/export/export_mov.c 2007-01-21 11:20:44.000000000 +0100 +++ tc-1.0/export/export_mov.c 2007-04-05 18:18:37.000000000 +0200 @@ -29,6 +29,7 @@ #include <stdlib.h> #include "import/magic.h" #include "transcode.h" +#include "vid_aux.h" #define MOD_NAME "export_mov.so" #define MOD_VERSION "v0.1.2 (2004-01-19)" @@ -65,21 +66,22 @@ static unsigned char** row_ptr = NULL; /* temporary buffer*/ -static char *tmp_buf; +static unsigned char *tmp_buf; /* toggle for raw frame export */ static int rawVideo = 0; static int rawAudio = 0; -/* qt colormodel */ -static int qt_cm = 0; - /* store frame dimension */ static int w = 0,h = 0; /* audio channels */ static int channels = 0; +/* colormodels */ +static int tc_cm = 0; +static int qt_cm = 0; + /* sample size */ static int bits = 0; @@ -102,7 +104,6 @@ {"info", "", "Info string (no '=' or ',' allowed) "}, {NULL, NULL, NULL}}; -#ifdef LIBQUICKTIME_000904 /* from libquicktime */ int tc_quicktime_get_timescale(double frame_rate) { @@ -115,7 +116,7 @@ timescale = (int)(frame_rate * 100 + 0.5); return timescale; } -#endif + /* print list of things. Shamelessly stolen from export_ffmpeg.c */ static int list(char *list_type) @@ -162,7 +163,7 @@ /* stolen from vid_aux.c */ /* due to a name clash between libvo and lqt, vid_aux can't be used */ -void qt_uyvytoyuy2(char *input, char *output, int width, int height) +void qt_uyvytoyuy2(unsigned char *input, unsigned char *output, int width, int height) { int i; @@ -240,7 +241,7 @@ char *qt_codec; int divx_bitrate; - + /* fetch frame size */ w = vob->ex_v_width; h = vob->ex_v_height; @@ -276,34 +277,30 @@ return(TC_EXPORT_ERROR); } - fprintf(stderr, "\n \n %i \n \n", tc_quicktime_get_timescale(vob->ex_fps)); /* set proposed video codec */ - lqt_set_video(qtfile, 1, w, h, + lqt_add_video_track(qtfile, w, h, tc_quicktime_get_timescale(vob->ex_fps) / vob->ex_fps+0.5, tc_quicktime_get_timescale(vob->ex_fps), qt_codec_info[0]); } - + /* set color model */ switch(vob->im_v_codec) { case CODEC_RGB: - quicktime_set_cmodel(qtfile, BC_RGB888); qt_cm = BC_RGB888; + qt_cm = BC_RGB888; break; case CODEC_YUV: - /*fprintf(stderr," using yuv420\n");*/ - quicktime_set_cmodel(qtfile, BC_YUV420P); qt_cm = BC_YUV420P; + qt_cm = BC_YUV420P; break; - case CODEC_YUV422: - /*fprintf(stderr," using yuv422\n"); */ - quicktime_set_cmodel(qtfile, BC_YUV422); qt_cm = BC_YUV422; + case CODEC_YUV422: + qt_cm = BC_YUV422P; break; - + case CODEC_YUY2: - /*fprintf(stderr," using yuy2\n");*/ - quicktime_set_cmodel(qtfile, BC_YUV422); qt_cm = CODEC_YUY2; + qt_cm = BC_YUV422; break; - + /* passthrough */ case CODEC_RAW_RGB: case CODEC_RAW_YUV: @@ -376,17 +373,27 @@ break; } - /* Inform user about lqts internal cs conversation */ + /* store tc and lqt colormodel */ + tc_cm = vob->im_v_codec; + + /* if cs conversation not supported for codec do conversation */ /* not required for pass through */ if (vob->im_v_codec != CODEC_RAW && vob->im_v_codec != CODEC_RAW_YUV && vob->im_v_codec != CODEC_RAW_RGB) { - if (quicktime_writes_cmodel(qtfile, qt_cm ,0) != 1) { - if (verbose_flag != TC_QUIET) - fprintf(stderr,"[%s] INFO: Colorspace conversation required you may want to try\n" - "[%s] a different mode (rgb, yuv, uyvy) to speed up encoding\n", + if (quicktime_writes_cmodel(qtfile, qt_cm, 0) != 1) { + if (verbose_flag != TC_QUIET) { + fprintf(stderr,"[%s] INFO: Colorspace not supported for this codec\n" + "[%s] converting to RGB\n", MOD_NAME, MOD_NAME); + } + + qt_cm = BC_RGB888; + lqt_set_cmodel(qtfile, 0, qt_cm); + yuv2rgb_init(24, MODE_BGR); + } else { + lqt_set_cmodel(qtfile, 0, qt_cm); } } - + /* set codec parameters */ /* tc uses kb */ divx_bitrate = vob->divxbitrate * 1000; @@ -505,7 +512,7 @@ param[j] = (char)NULL; j=-1; /* set to 0 by for loop above */ - for(i++,k=0;i<=strlen(vob->ex_profile_name), vob->ex_profile_name[i] != (char)NULL;i++,k++) { + for(i++,k=0;i<=strlen(vob->ex_profile_name) && vob->ex_profile_name[i] != (char)NULL;i++,k++) { /* try to catch bad input */ if (vob->ex_profile_name[i] == '=') { fprintf(stderr, "[%s] bad -F option found, aborting ...\n" @@ -540,8 +547,8 @@ /* alloc row pointers for frame encoding */ row_ptr = malloc (sizeof(char *) * h); - /* same for temp buffer ... used during yuy2 encoding*/ - tmp_buf = malloc (w*h*2); + /* allocate tmp buffer cs conversation */ + tmp_buf = malloc (w * h * 3); /* verbose */ fprintf(stderr,"[%s] video codec='%s' w=%d h=%d fps=%g\n", @@ -628,11 +635,14 @@ { /* video -------------------------------------------------------- */ if(param->flag == TC_VIDEO) { + unsigned char *ptr = (unsigned char *)param->buffer; + /* raw mode is easy */ if(rawVideo) { /* add divx keyframes if needed */ - if(quicktime_divx_is_key(param->buffer, param->size) == 1) quicktime_insert_keyframe(qtfile, (int)tc_get_frames_encoded, 0); - if(quicktime_write_frame(qtfile,param->buffer,param->size,0)<0) { + if(quicktime_divx_is_key(ptr, (unsigned char)param->size) == 1) + quicktime_insert_keyframe(qtfile, (int)tc_get_frames_encoded, 0); + if(quicktime_write_frame(qtfile, ptr, param->size,0)<0) { fprintf(stderr, "[%s] error writing raw video frame\n", MOD_NAME); return(TC_EXPORT_ERROR); @@ -641,11 +651,17 @@ /* encode frame */ else { - char *ptr = param->buffer; int iy,sl; - + switch(qt_cm) { case BC_RGB888: + if (tc_cm == CODEC_YUV) { + yuv2rgb((void *)tmp_buf, + ptr, ptr + w*h, ptr + (w*h*5)/4, + w, h, w*3, w, w/2); + ptr = tmp_buf; + } + /* setup row pointers for RGB: inverse! */ sl = w*3; for(iy=0;iy<h;iy++){ @@ -658,8 +674,8 @@ /* setup row pointers for YUV420P: inverse! */ row_ptr[0] = ptr; ptr = ptr + (h * w); - row_ptr[2] = ptr; - ptr = ptr + (h * w )/4; + row_ptr[2] = ptr; + ptr = ptr + (h * w) / 4; row_ptr[1] = ptr; break; @@ -667,7 +683,7 @@ case BC_YUV422: /* setup row pointers for YUV422: inverse ?*/ sl = w*2; - if (qt_cm != CODEC_YUY2){ + if (qt_cm != CODEC_YUY2) { /* convert uyvy to yuy2 */ /* find out if lqt supports uyvy byteorder */ qt_uyvytoyuy2(ptr, tmp_buf, w, h); ptr = tmp_buf; @@ -692,7 +708,7 @@ /* raw mode is easy */ if(rawAudio) { if(quicktime_write_frame(qtfile, - param->buffer,param->size,0)<0) { + (unsigned char *)param->buffer,param->size,0)<0) { fprintf(stderr, "[%s] error writing raw audio frame\n", MOD_NAME); return(TC_EXPORT_ERROR); --- cvs/mplayer/transcode/export/Makefile.am 2005-03-13 03:33:02.000000000 +0100 +++ tc-1.0/export/Makefile.am 2007-04-04 16:40:30.000000000 +0200 @@ -213,9 +213,9 @@ export_mjpeg_la_LIBADD = $(LIBJPEG_LIBS) $(LAME_LIBS) $(LIBVO_LIBS) $(AC3_LIBS) $(LIBAVCODEC_LIBS) # MODS_LIBQUICKTIME -export_mov_la_SOURCES = export_mov.c +export_mov_la_SOURCES = export_mov.c vid_aux.c export_mov_la_LDFLAGS = -module -avoid-version -export_mov_la_LIBADD = $(LIBQUICKTIME_LIBS) -lm +export_mov_la_LIBADD = $(LIBQUICKTIME_LIBS) $(LIBVO_LIBS) -lm # MODS_LZO export_lzo_la_SOURCES = export_lzo.c aud_aux.c
--- cvs/mplayer/transcode/export/export_mov.c 2007-04-05 06:22:42.000000000 +0200 +++ tc-1.1/export/export_mov.c 2007-04-05 18:05:47.000000000 +0200 @@ -32,8 +32,7 @@ #include "transcode.h" #include "import/magic.h" #include "encoder.h" -#include "aclib/imgconvert.h" - +#include "libtcvideo/tcvideo.h" #include <stdio.h> #include <stdlib.h> @@ -75,11 +74,12 @@ static int rawVideo = 0; static int rawAudio = 0; -/* qt colormodel */ +/* colormodels */ +static ImageFormat tc_cm = 0; static int qt_cm = 0; /* store frame dimension */ -static int w = 0,h = 0; +static int w = 0, h = 0; /* audio channels */ static int channels = 0; @@ -97,6 +97,8 @@ char *comments; }; +static TCVHandle tcvhandle = 0; + /* special paramters not retrievable from lqt */ struct qt_codec_list qt_param_list[] = { {"", "", ""}, @@ -265,7 +267,6 @@ /* set proposed video codec */ lqt_set_video(qtfile, 1, w, h, vob->ex_fps,qt_codec_info[0]); #else - tc_log_info(MOD_NAME, "%i\n", tc_quicktime_get_timescale(vob->ex_fps)); /* set proposed video codec */ lqt_set_video(qtfile, 1, w, h, tc_quicktime_get_timescale(vob->ex_fps) / vob->ex_fps+0.5, @@ -276,19 +277,23 @@ /* set color model */ switch(vob->im_v_codec) { case CODEC_RGB: - quicktime_set_cmodel(qtfile, BC_RGB888); qt_cm = BC_RGB888; + qt_cm = BC_RGB888; + tc_cm = IMG_RGB_DEFAULT; break; case CODEC_YUV: - quicktime_set_cmodel(qtfile, BC_YUV420P); qt_cm = BC_YUV420P; + qt_cm = BC_YUV420P; + tc_cm = IMG_YUV_DEFAULT; break; case CODEC_YUV422: - quicktime_set_cmodel(qtfile, BC_YUV422P); qt_cm = BC_YUV422P; + tc_cm = IMG_YUV422P; + qt_cm = BC_YUV422P; break; case CODEC_YUY2: - quicktime_set_cmodel(qtfile, BC_YUV422); qt_cm = BC_YUV422; + tc_cm = IMG_YUY2; + qt_cm = BC_YUV422; break; /* passthrough */ @@ -360,14 +365,26 @@ return(TC_EXPORT_ERROR); break; } - - /* Inform user about lqts internal cs conversation */ + + /* if cs conversation not supported for codec do conversation */ /* not required for pass through */ if (vob->im_v_codec != CODEC_RAW && vob->im_v_codec != CODEC_RAW_YUV && vob->im_v_codec != CODEC_RAW_RGB) { - if (quicktime_writes_cmodel(qtfile, qt_cm ,0) != 1) { - if (verbose_flag != TC_QUIET) - tc_log_info(MOD_NAME, "Colorspace conversation required you may want to try"); - tc_log_info(MOD_NAME, "a different mode (rgb, yuv, yuv422) to speed up encoding"); + if (quicktime_writes_cmodel(qtfile, qt_cm, 0) != 1) { + if (verbose_flag != TC_QUIET) { + tc_log_info(MOD_NAME,"Colorspace not supported for this codec converting to RGB"); + } + + qt_cm = BC_RGB888; + lqt_set_cmodel(qtfile, 0, qt_cm); + + tcvhandle = tcv_init(); + if (!tcvhandle) { + tc_log_warn(MOD_NAME, "image conversion init failed"); + return TC_EXPORT_ERROR; + } + + } else { + lqt_set_cmodel(qtfile, 0, qt_cm); } } @@ -608,6 +625,8 @@ { /* video -------------------------------------------------------- */ if(param->flag == TC_VIDEO) { + vob_t *vob = tc_get_vob(); + /* raw mode is easy */ if(rawVideo) { /* add divx keyframes if needed */ @@ -620,11 +639,21 @@ /* encode frame */ else { - char *ptr = param->buffer; + unsigned char *ptr = param->buffer; int iy; switch(qt_cm) { case BC_RGB888: + /* convert to rgb if unsupported */ + if (tc_cm != IMG_RGB24) { + if (!tcv_convert(tcvhandle, param->buffer, param->buffer, + vob->ex_v_width, vob->ex_v_height, + tc_cm, IMG_RGB24)) { + tc_log_warn(MOD_NAME, "image format conversion failed"); + return TC_EXPORT_ERROR; + } + } + /* setup row pointers for RGB */ for (iy = 0; iy < h; iy++) { row_ptr[iy] = ptr;