Index: import/import_im.c =================================================================== RCS file: /cvstc/transcode/import/import_im.c,v --- import/import_im.c 4 Jul 2005 07:23:01 -0000 1.14 +++ import/import_im.c 17 Jul 2007 09:24:24 -0000 @@ -1,32 +1,46 @@ /* * import_im.c * - * Copyright (C) Thomas Östreich - June 2001 + * Copyright (C) Thomas Oestreich - June 2001 + * port to MagickWand API: + * Copyright (C) Francesco Romani - July 2007 * * This file is part of transcode, a video stream processing tool - * + * * transcode is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. - * + * * transcode is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ #define MOD_NAME "import_im.so" -#define MOD_VERSION "v0.0.4 (2003-09-15)" +#define MOD_VERSION "v0.1.0 (2007-07-17)" #define MOD_CODEC "(video) RGB" +/* Note: because of ImageMagick bogosity, this must be included first, so + * we can undefine the PACKAGE_* symbols it splats into our namespace */ +#include +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION + #include "transcode.h" +#include +#include + static int verbose_flag = TC_QUIET; static int capability_flag = TC_CAP_RGB | TC_CAP_VID; @@ -37,276 +51,258 @@ #include #include -/* transcode defines these as well as ImageMagick. */ -#undef PACKAGE_NAME -#undef PACKAGE_TARNAME -#undef PACKAGE_VERSION -#undef PACKAGE_STRING -#include +static char *head = NULL, *tail = NULL; +static int first_frame = 0, last_frame = 0, current_frame = 0, pad = 0; +static int width = 0, height = 0; +static MagickWand *wand = NULL; -extern int errno; +static int TCHandleMagickError(MagickWand *wand) +{ + ExceptionType severity; + const char *description = MagickGetException(wand, &severity); + + tc_log_error(MOD_NAME, "%s", description); -char - *head = NULL, - *tail = NULL; + MagickRelinquishMemory((void*)description); + return TC_IMPORT_ERROR; +} -int - first_frame = 0, - last_frame = 0, - current_frame = 0, - pad = 0; - -/* ------------------------------------------------------------ +/* ------------------------------------------------------------ * * open stream * * ------------------------------------------------------------*/ + +/* I suspect we have a lot of potential memleaks in here -- FRomani */ MOD_open { - int - result, - string_length; - - long - sret; - - char - *regex, - *frame, - *filename; - - char - printfspec[20]; - - regex_t - preg; - - regmatch_t - pmatch[4]; - - if(param->flag == TC_AUDIO) { - return(TC_IMPORT_OK); - } - - if(param->flag == TC_VIDEO) { - - param->fd = NULL; + int result, string_length; + long sret; + char *regex, *frame, *filename; + char printfspec[20]; + regex_t preg; + regmatch_t pmatch[4]; - // get the frame name and range - regex = "\\(.\\+[-._]\\)\\?\\([0-9]\\+\\)\\([-._].\\+\\)\\?"; - result = regcomp(&preg, regex, 0); - if (result) { - perror("ERROR: Regex compile failed.\n"); - return(TC_IMPORT_ERROR); + if (param->flag == TC_AUDIO) { + return TC_IMPORT_OK; } - result = regexec(&preg, vob->video_in_file, 4, pmatch, 0); - if (result) { - fprintf(stderr, "Regex match failed: no image sequence\n"); - string_length = strlen(vob->video_in_file) + 1; - if ((head = malloc(string_length)) == NULL) { - perror("filename head"); - return(TC_IMPORT_ERROR); - } - strlcpy(head, vob->video_in_file, string_length); - tail = malloc(1); - tail[0] = 0; - first_frame = -1; - last_frame = 0x7fffffff; - } - else { - // split the name into head, frame number, and tail - string_length = pmatch[1].rm_eo - pmatch[1].rm_so + 1; - if ((head = malloc(string_length)) == NULL) { - perror("filename head"); - return(TC_IMPORT_ERROR); - } - strlcpy(head, vob->video_in_file, string_length); + if (param->flag == TC_VIDEO) { + param->fd = NULL; - string_length = pmatch[2].rm_eo - pmatch[2].rm_so + 1; - if ((frame = malloc(string_length)) == NULL) { - perror("filename frame"); - return(TC_IMPORT_ERROR); + // get the frame name and range + regex = "\\(.\\+[-._]\\)\\?\\([0-9]\\+\\)\\([-._].\\+\\)\\?"; + result = regcomp(&preg, regex, 0); + if (result) { + tc_log_perror(MOD_NAME, "ERROR: Regex compile failed.\n"); + return TC_IMPORT_ERROR; } - strlcpy(frame, vob->video_in_file + pmatch[2].rm_so, string_length); - // If the frame number is padded with zeros, record how many digits - // are actually being used. - if (frame[0] == '0') { - pad = pmatch[2].rm_eo - pmatch[2].rm_so; + result = regexec(&preg, vob->video_in_file, 4, pmatch, 0); + if (result) { + tc_log_warn(MOD_NAME, "Regex match failed: no image sequence"); + string_length = strlen(vob->video_in_file) + 1; + head = tc_malloc(string_length); + if (head == NULL) { + tc_log_perror(MOD_NAME, "filename head"); + return TC_IMPORT_ERROR; + } + strlcpy(head, vob->video_in_file, string_length); + tail = tc_malloc(1); /* URGH -- FRomani */ + tail[0] = 0; + first_frame = -1; + last_frame = 0x7fffffff; + } else { + // split the name into head, frame number, and tail + string_length = pmatch[1].rm_eo - pmatch[1].rm_so + 1; + head = tc_malloc(string_length); + if (head == NULL) { + tc_log_perror(MOD_NAME, "filename head"); + return TC_IMPORT_ERROR; + } + strlcpy(head, vob->video_in_file, string_length); + + string_length = pmatch[2].rm_eo - pmatch[2].rm_so + 1; + frame = tc_malloc(string_length); + if (frame == NULL) { + tc_log_perror(MOD_NAME, "filename frame"); + return TC_IMPORT_ERROR; + } + strlcpy(frame, vob->video_in_file + pmatch[2].rm_so, string_length); + + // If the frame number is padded with zeros, record how many digits + // are actually being used. + if (frame[0] == '0') { + pad = pmatch[2].rm_eo - pmatch[2].rm_so; + } + first_frame = atoi(frame); + + string_length = pmatch[3].rm_eo - pmatch[3].rm_so + 1; + tail = tc_malloc(string_length); + if (tail == NULL) { + tc_log_perror(MOD_NAME, "filename tail"); + return TC_IMPORT_ERROR; + } + strlcpy(tail, vob->video_in_file + pmatch[3].rm_so, string_length); + + // find the last frame by trying to open files + last_frame = first_frame; + filename = tc_malloc(strlen(head) + pad + strlen(tail) + 1); + /* why remalloc frame? */ + /* frame = malloc(pad + 1); */ + do { + last_frame++; + tc_snprintf(printfspec, sizeof(printfspec), "%%s%%0%dd%%s", pad); + string_length = strlen(head) + pad + strlen(tail) + 1; + sret = tc_snprintf(filename, string_length, printfspec, head, + last_frame, tail); + if (sret < 0) + return TC_IMPORT_ERROR; + } while (close(open(filename, O_RDONLY)) != -1); /* URGH -- Fromani */ + last_frame--; + tc_free(filename); + tc_free(frame); } - first_frame = atoi(frame); - string_length = pmatch[3].rm_eo - pmatch[3].rm_so + 1; - if ((tail = malloc(string_length)) == NULL) { - perror("filename tail"); - return(TC_IMPORT_ERROR); - } - strlcpy(tail, vob->video_in_file + pmatch[3].rm_so, string_length); + current_frame = first_frame; - // find the last frame by trying to open files - last_frame = first_frame; - filename = malloc(strlen(head) + pad + strlen(tail) + 1); - /* why remalloc frame? */ - /* frame = malloc(pad + 1); */ - do { - last_frame++; - snprintf(printfspec, sizeof(printfspec), "%%s%%0%dd%%s", pad); - string_length = strlen(head) + pad + strlen(tail) + 1; - sret = snprintf(filename, string_length, printfspec, head, - last_frame, tail); - if (tc_test_string(__FILE__, __LINE__, string_length, sret, errno)) - return(TC_IMPORT_ERROR); - } while (close(open(filename, O_RDONLY)) != -1); - last_frame--; - free(filename); - free(frame); - } + width = vob->im_v_width; + height = vob->im_v_height; - current_frame = first_frame; + MagickWandGenesis(); + wand = NewMagickWand(); - // initialize ImageMagick - InitializeMagick(""); + if (wand == NULL) { + tc_log_error(MOD_NAME, "cannot create magick wand"); + return TC_IMPORT_ERROR; + } + MagickResetIterator(wand); /* this needs to be done once */ - return(TC_IMPORT_OK); - } + return TC_IMPORT_OK; + } - return(TC_IMPORT_ERROR); + return TC_IMPORT_ERROR; } -/* ------------------------------------------------------------ +/* ------------------------------------------------------------ * * decode stream * * ------------------------------------------------------------*/ -MOD_decode { - - ExceptionInfo - exception_info; - - ImageInfo - *image_info; +MOD_decode +{ + char *filename = NULL, *frame = NULL; + int string_length; + MagickBooleanType status; - Image - *image; - - PixelPacket - *pixel_packet; - - char - *filename = NULL, - *frame = NULL, - *framespec = NULL; - - int - column, - row, - string_length; - - - if (current_frame > last_frame) - return(TC_IMPORT_ERROR); - - // build the filename for the current frame - string_length = strlen(head) + pad + strlen(tail) + 1; - filename = malloc(string_length); - if (pad) { - frame = malloc(pad+1); - framespec = malloc(10); - snprintf(framespec, 10, "%%0%dd", pad); - snprintf(frame, pad+1, framespec, current_frame); - free(framespec); - frame[pad] = '\0'; - } - else if (first_frame >= 0) { - frame = malloc(10); - snprintf(frame, 10, "%d", current_frame); + if (param->flag == TC_AUDIO) { + return TC_IMPORT_OK; } - strlcpy(filename, head, string_length); - if (frame != NULL) { - strlcat(filename, frame, string_length); - free(frame); - frame = NULL; - } - strlcat(filename, tail, string_length); - // Have ImageMagick open the file and read in the image data. - GetExceptionInfo(&exception_info); - image_info=CloneImageInfo((ImageInfo *) NULL); - (void) strlcpy(image_info->filename, filename, MaxTextExtent); - image=ReadImage(image_info,&exception_info); - if (image == (Image *) NULL) { - MagickError(exception_info.severity, - exception_info.reason, - exception_info.description); - // skip - return (TC_IMPORT_ERROR); - } + if (param->flag == TC_VIDEO) { + if (current_frame > last_frame) + return TC_IMPORT_ERROR; + + // build the filename for the current frame + string_length = strlen(head) + pad + strlen(tail) + 1; + filename = tc_malloc(string_length); + if (pad) { + char framespec[10]; + frame = tc_malloc(pad+1); + tc_snprintf(framespec, 10, "%%0%dd", pad); + tc_snprintf(frame, pad+1, framespec, current_frame); + frame[pad] = '\0'; + } else if (first_frame >= 0) { + frame = tc_malloc(10); + tc_snprintf(frame, 10, "%d", current_frame); + } + strlcpy(filename, head, string_length); + if (frame != NULL) { + strlcat(filename, frame, string_length); + tc_free(frame); + frame = NULL; + } + strlcat(filename, tail, string_length); - /* - * Copy the pixels into a buffer in RGB order - */ - pixel_packet = GetImagePixels(image, 0, 0, image->columns, image->rows); - for (row = 0; row < image->rows; row++) { - for (column = 0; column < image->columns; column++) { - /* - * The bit-shift 8 in the following lines is to convert - * 16-bit-per-channel images that may be read by ImageMagick - * into the 8-bit-per-channel images that transcode uses. - * The bit-shift is still valid for 8-bit-per-channel images - * because when ImageMagick handles 8-bit images it still uses - * unsigned shorts, but stores the same 8-bit value in both - * the low and high byte. - */ - param->buffer[(row * image->columns + column) * 3 + 0] = - (char) (pixel_packet[(image->rows - row - 1) * image->columns + - column].blue >> 8); - param->buffer[(row * image->columns + column) * 3 + 1] = - (char) (pixel_packet[(image->rows - row - 1) * image->columns + - column].green >> 8); - param->buffer[(row * image->columns + column) * 3 + 2] = - (char) (pixel_packet[(image->rows - row - 1) * image->columns + - column].red >> 8); + ClearMagickWand(wand); + /* + * This avoids IM to buffer all read images. + * I'm quite sure that this can be done in a smarter way, + * but I haven't yet figured out how. -- FRomani + */ + + status = MagickReadImage(wand, filename); + if (status == MagickFalse) { + return TCHandleMagickError(wand); } - } - if (current_frame == first_frame) - param->attributes |= TC_FRAME_IS_KEYFRAME; + MagickSetLastIterator(wand); + + status = MagickGetImagePixels(wand, + 0, 0, width, height, + "RGB", CharPixel, + param->buffer); + /* param->size already set correctly by caller */ + if (status == MagickFalse) { + return TCHandleMagickError(wand); + } - current_frame++; + if (current_frame == first_frame) + param->attributes |= TC_FRAME_IS_KEYFRAME; - // How do we do this? The next line is not right (segfaults) - // I can't find a DestroyPixelPacket() method. - //free(pixel_packet); - DestroyImage(image); - DestroyImageInfo(image_info); - DestroyExceptionInfo(&exception_info); - free(filename); + current_frame++; + + tc_free(filename); - return(TC_IMPORT_OK); + return TC_IMPORT_OK; + } + return TC_IMPORT_ERROR; } -/* ------------------------------------------------------------ +/* ------------------------------------------------------------ * * close stream * * ------------------------------------------------------------*/ MOD_close -{ - if (param->fd != NULL) pclose(param->fd); - if (head != NULL) free(head); - if (tail != NULL) free(tail); - - DestroyMagick(); +{ + if (param->flag == TC_AUDIO) { + return TC_IMPORT_OK; + } - return(TC_IMPORT_OK); + if (param->flag == TC_VIDEO) { + if (param->fd != NULL) + pclose(param->fd); + if (head != NULL) + tc_free(head); + if (tail != NULL) + tc_free(tail); + + if (wand != NULL) { + DestroyMagickWand(wand); + MagickWandTerminus(); + wand = NULL; + } + return TC_IMPORT_OK; + } + return TC_IMPORT_ERROR; } +/*************************************************************************/ +/* + * Local variables: + * c-file-style: "stroustrup" + * c-file-offsets: ((case-label . *) (statement-case-intro . *)) + * indent-tabs-mode: nil + * End: + * + * vim: expandtab shiftwidth=4: + */ Index: import/import_imlist.c =================================================================== RCS file: /cvstc/transcode/import/import_imlist.c,v --- import/import_imlist.c 4 Jul 2005 07:23:01 -0000 1.10 +++ import/import_imlist.c 17 Jul 2007 09:24:24 -0000 @@ -1,59 +1,69 @@ /* * import_imlist.c * - * Copyright (C) Thomas Östreich - February 2002 + * Copyright (C) Thomas Oestreich - February 2002 + * port to MagickWand API: + * Copyright (C) Francesco Romani - July 2007 * * This file is part of transcode, a video stream processing tool - * + * * transcode is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. - * + * * transcode is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ #define MOD_NAME "import_imlist.so" -#define MOD_VERSION "v0.0.2 (2003-11-13)" +#define MOD_VERSION "v0.1.0 (2007-07-17)" #define MOD_CODEC "(video) RGB" +/* Note: because of ImageMagick bogosity, this must be included first, so + * we can undefine the PACKAGE_* symbols it splats into our namespace */ +#include +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION + #include "transcode.h" +#include +#include + static int verbose_flag = TC_QUIET; -static int capability_flag = TC_CAP_RGB | TC_CAP_VID | TC_CAP_AUD; +static int capability_flag = TC_CAP_RGB|TC_CAP_VID; #define MOD_PRE imlist #include "import_def.h" -// transcode defines this as well as ImageMagick. -#undef PACKAGE_NAME -#undef PACKAGE_TARNAME -#undef PACKAGE_VERSION -#undef PACKAGE_STRING - -#include +static int TCHandleMagickError(MagickWand *wand) +{ + ExceptionType severity; + const char *description = MagickGetException(wand, &severity); + tc_log_error(MOD_NAME, "%s", description); -int - first_frame = 0, - last_frame = 0, - current_frame = 0, - pad = 0; + MagickRelinquishMemory((void*)description); + return TC_IMPORT_ERROR; +} -static FILE *fd; -static char buffer[PATH_MAX+2]; - +static int width = 0, height = 0; +static FILE *fd = NULL; +static MagickWand *wand = NULL; -/* ------------------------------------------------------------ +/* ------------------------------------------------------------ * * open stream * @@ -61,127 +71,125 @@ MOD_open { - if(param->flag == TC_AUDIO) { - return(TC_IMPORT_OK); - } - - if(param->flag == TC_VIDEO) { - - param->fd = NULL; - - if((fd = fopen(vob->video_in_file, "r"))==NULL) return(TC_IMPORT_ERROR); - - // initialize ImageMagick - InitializeMagick(""); - - return(TC_IMPORT_OK); - } - - return(TC_IMPORT_ERROR); + if (param->flag == TC_AUDIO) { + return(TC_IMPORT_OK); + } + + if (param->flag == TC_VIDEO) { + param->fd = NULL; + + width = vob->im_v_width; + height = vob->im_v_height; + + fd = fopen(vob->video_in_file, "r"); + if (fd == NULL) { + return TC_IMPORT_ERROR; + } + + MagickWandGenesis(); + wand = NewMagickWand(); + + if (wand == NULL) { + tc_log_error(MOD_NAME, "cannot create magick wand"); + return TC_IMPORT_ERROR; + } + + return TC_IMPORT_OK; + } + + return TC_IMPORT_ERROR; } -/* ------------------------------------------------------------ +/* ------------------------------------------------------------ * * decode stream * * ------------------------------------------------------------*/ -MOD_decode { +MOD_decode +{ + char filename[PATH_MAX+1]; + MagickBooleanType status; + + if (param->flag == TC_AUDIO) { + return TC_IMPORT_OK; + } + + if (param->flag == TC_VIDEO) { + // read a filename from the list + if (fgets(filename, PATH_MAX, fd) == NULL) { + return TC_IMPORT_ERROR; + } + filename[PATH_MAX] = '\0'; /* enforce */ + + ClearMagickWand(wand); + /* + * This avoids IM to buffer all read images. + * I'm quite sure that this can be done in a smarter way, + * but I haven't yet figured out how. -- FRomani + */ + + status = MagickReadImage(wand, filename); + if (status == MagickFalse) { + return TCHandleMagickError(wand); + } - ExceptionInfo - exception_info; + MagickSetLastIterator(wand); - ImageInfo - *image_info; + status = MagickGetImagePixels(wand, + 0, 0, width, height, + "RGB", CharPixel, + param->buffer); + if (status == MagickFalse) { + return TCHandleMagickError(wand); + } - Image - *image; - - PixelPacket - *pixel_packet; - - char - *filename = NULL; - - int - column, - row, n; - - if(param->flag == TC_AUDIO) return(TC_IMPORT_OK); - - // read a filename from the list - if(fgets (buffer, PATH_MAX, fd)==NULL) return(TC_IMPORT_ERROR); - - filename = buffer; - - n=strlen(filename); - if(n<2) return(TC_IMPORT_ERROR); - filename[n-1]='\0'; - - // Have ImageMagick open the file and read in the image data. - GetExceptionInfo(&exception_info); - image_info=CloneImageInfo((ImageInfo *) NULL); - (void) strlcpy(image_info->filename, filename, MaxTextExtent); - - image=ReadImage(image_info, &exception_info); - if (image == (Image *) NULL) { - MagickError(exception_info.severity, exception_info.reason, - exception_info.description); - // skipping - return TC_IMPORT_OK; - } - - /* - * Copy the pixels into a buffer in RGB order - */ - pixel_packet = GetImagePixels(image, 0, 0, image->columns, image->rows); - for (row = 0; row < image->rows; row++) { - for (column = 0; column < image->columns; column++) { - param->buffer[(row * image->columns + column) * 3 + 0] = - pixel_packet[(image->rows - row - 1) * image->columns + - column].blue; - param->buffer[(row * image->columns + column) * 3 + 1] = - pixel_packet[(image->rows - row - 1) * image->columns + - column].green; - param->buffer[(row * image->columns + column) * 3 + 2] = - pixel_packet[(image->rows - row - 1) * image->columns + - column].red; - } - } - - param->attributes |= TC_FRAME_IS_KEYFRAME; - - // How do we do this? The next line is not right (segfaults) - // I can't find a DestroyPixelPacket() method. - //free(pixel_packet); - DestroyImage(image); - DestroyImageInfo(image_info); - DestroyExceptionInfo(&exception_info); + param->attributes |= TC_FRAME_IS_KEYFRAME; - return(TC_IMPORT_OK); + return TC_IMPORT_OK; + } + return TC_IMPORT_ERROR; } -/* ------------------------------------------------------------ +/* ------------------------------------------------------------ * * close stream * * ------------------------------------------------------------*/ MOD_close -{ +{ + if (param->flag == TC_AUDIO) { + return TC_IMPORT_OK; + } + + if (param->flag == TC_VIDEO) { + if (fd != NULL) { + fclose(fd); + fd = NULL; + } + + if (wand != NULL) { + DestroyMagickWand(wand); + MagickWandTerminus(); + wand = NULL; + } - if(param->flag == TC_VIDEO) { - - if(fd != NULL) fclose(fd); fd = NULL; - - // This is very necessary - DestroyMagick(); - - return(TC_IMPORT_OK); - } - - if(param->flag == TC_AUDIO) return(TC_IMPORT_OK); - - return(TC_IMPORT_ERROR); + return TC_IMPORT_OK; + } + + return TC_IMPORT_ERROR; } + +/*************************************************************************/ + +/* + * Local variables: + * c-file-style: "stroustrup" + * c-file-offsets: ((case-label . *) (statement-case-intro . *)) + * indent-tabs-mode: nil + * End: + * + * vim: expandtab shiftwidth=4: + */