diff options
Diffstat (limited to 'source/blender/imbuf/intern/cineon/dpxlib.c')
-rw-r--r-- | source/blender/imbuf/intern/cineon/dpxlib.c | 625 |
1 files changed, 625 insertions, 0 deletions
diff --git a/source/blender/imbuf/intern/cineon/dpxlib.c b/source/blender/imbuf/intern/cineon/dpxlib.c new file mode 100644 index 00000000000..bb12f9307e3 --- /dev/null +++ b/source/blender/imbuf/intern/cineon/dpxlib.c @@ -0,0 +1,625 @@ +/* + * Dpx image file format library routines. + * + * Copyright 1999 - 2002 David Hodson <hodsond@acm.org> + * + * This program 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 of the License, or (at your option) + * any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "dpxfile.h" +#include "dpxlib.h" + +#include <stdio.h> +#include <math.h> +#include <stdlib.h> +#include <time.h> /* strftime() */ +#include <sys/types.h> +#ifdef WIN32 +#include <winsock.h> +#else +#include <netinet/in.h> /* htonl() */ +#endif +#include <string.h> /* memset */ +#include "cin_debug_stuff.h" +#include "logmemfile.h" + +static void +fillDpxChannelInfo(DpxFile* dpx, DpxChannelInformation* chan, int des) { + + chan->signage = 0; + chan->ref_low_data = htonl(0); + chan->ref_low_quantity = htonf(0.0); + chan->ref_high_data = htonl(1023); + chan->ref_high_quantity = htonf(2.046); + chan->designator1 = des; + chan->transfer_characteristics = 0; + chan->colourimetry = 0; + chan->bits_per_pixel = 10; + chan->packing = htons(1); + chan->encoding = 0; + chan->data_offset = 0; + chan->line_padding = htonl(0); + chan->channel_padding = htonl(0); + chan->description[0] = 0; +} + +static void +dumpDpxChannelInfo(DpxChannelInformation* chan) { + d_printf(" Signage %ld", ntohl(chan->signage)); + d_printf(" Ref low data %ld\n", ntohl(chan->ref_low_data)); + d_printf(" Ref low quantity %f\n", ntohf(chan->ref_low_quantity)); + d_printf(" Ref high data %ld\n", ntohl(chan->ref_high_data)); + d_printf(" Ref high quantity %f\n", ntohf(chan->ref_high_quantity)); + d_printf(" Designator1: %d,", chan->designator1); + d_printf(" Bits per pixel %d\n", chan->bits_per_pixel); + d_printf(" Packing: %d,", ntohs(chan->packing)); + d_printf(" Data Offset: %ld,", ntohl(chan->data_offset)); +} + +static void +fillDpxFileInfo( + DpxFile* dpx, DpxFileInformation* fileInfo, const char* filename) { + + time_t fileClock; + struct tm* fileTime; + + /* Note: always write files in network order */ + /* By the spec, it shouldn't matter, but ... */ + + fileInfo->magic_num = htonl(DPX_FILE_MAGIC); + fileInfo->offset = htonl(dpx->imageOffset); + strcpy(fileInfo->vers, "v1.0"); + fileInfo->file_size = htonl(dpx->imageOffset + + pixelsToLongs(dpx->height * dpx->width * dpx->depth) * 4); + fileInfo->ditto_key = 0; + fileInfo->gen_hdr_size = htonl( + sizeof(DpxFileInformation) + + sizeof(DpxImageInformation) + + sizeof(DpxOriginationInformation)); + fileInfo->ind_hdr_size = htonl(sizeof(DpxMPIInformation)); + fileInfo->user_data_size = 0; + strncpy(fileInfo->file_name, filename, 99); + fileInfo->file_name[99] = 0; + + fileClock = time(0); + fileTime = localtime(&fileClock); + strftime(fileInfo->create_date, 24, "%Y:%m:%d:%H:%M:%S%Z", fileTime); + /* Question: is %Z in strftime guaranteed to return 3 chars? */ + fileInfo->create_date[23] = 0; + + strcpy(fileInfo->creator, "David's DPX writer"); + fileInfo->project[0] = 0; + fileInfo->copyright[0] = 0; + fileInfo->key = 0xFFFFFFFF; /* same in any byte order */ +} + +static void +dumpDpxFileInfo(DpxFileInformation* fileInfo) { + d_printf("\n--File Information--\n"); + d_printf("Magic: %8.8lX\n", ntohl(fileInfo->magic_num)); + d_printf("Image Offset %ld\n", ntohl(fileInfo->offset)); + d_printf("Version \"%s\"\n", fileInfo->vers); + d_printf("File size %ld\n", ntohl(fileInfo->file_size)); + d_printf("Ditto key %ld\n", ntohl(fileInfo->ditto_key)); + d_printf("Generic Header size %ld\n", ntohl(fileInfo->gen_hdr_size)); + d_printf("Industry Header size %ld\n", ntohl(fileInfo->ind_hdr_size)); + d_printf("User Data size %ld\n", ntohl(fileInfo->user_data_size)); + d_printf("File name \"%s\"\n", fileInfo->file_name); + d_printf("Creation date \"%s\"\n", fileInfo->create_date); + d_printf("Creator \"%s\"\n", fileInfo->creator); + d_printf("Project \"%s\"\n", fileInfo->project); + d_printf("Copyright \"%s\"\n", fileInfo->copyright); + d_printf("Key %ld\n", ntohl(fileInfo->key)); +} + +static void +fillDpxImageInfo( + DpxFile* dpx, DpxImageInformation* imageInfo) { + imageInfo->orientation = 0; + imageInfo->channels_per_image = htons(1); + imageInfo->pixels_per_line = htonl(dpx->width); + imageInfo->lines_per_image = htonl(dpx->height); + + if (dpx->depth == 1) { + fillDpxChannelInfo(dpx, &imageInfo->channel[0], 0); + + } else if (dpx->depth == 3) { + fillDpxChannelInfo(dpx, &imageInfo->channel[0], 50); + } +} + +static void +dumpDpxImageInfo(DpxImageInformation* imageInfo) { + + int n; + int i; + d_printf("\n--Image Information--\n"); + d_printf("Image orientation %d,", ntohs(imageInfo->orientation)); + n = ntohs(imageInfo->channels_per_image); + d_printf("Channels %d\n", n); + d_printf("Pixels per line %ld\n", ntohl(imageInfo->pixels_per_line)); + d_printf("Lines per image %ld\n", ntohl(imageInfo->lines_per_image)); + for (i = 0; i < n; ++i) { + d_printf(" --Channel %d--\n", i); + dumpDpxChannelInfo(&imageInfo->channel[i]); + } +} + +static void +fillDpxOriginationInfo( + DpxFile* dpx, DpxOriginationInformation* originInfo, DpxFileInformation* fileInfo) { +} + +static void +dumpDpxOriginationInfo(DpxOriginationInformation* originInfo) { + d_printf("\n--Origination Information--\n"); + d_printf("X offset %ld\n", ntohl(originInfo->x_offset)); + d_printf("Y offset %ld\n", ntohl(originInfo->y_offset)); + d_printf("X centre %f\n", ntohf(originInfo->x_centre)); + d_printf("Y centre %f\n", ntohf(originInfo->y_centre)); + d_printf("Original X %ld\n", ntohl(originInfo->x_original_size)); + d_printf("Original Y %ld\n", ntohl(originInfo->y_original_size)); + d_printf("File name \"%s\"\n", originInfo->file_name); + d_printf("Creation time \"%s\"\n", originInfo->creation_time); + d_printf("Input device \"%s\"\n", originInfo->input_device); + d_printf("Serial number \"%s\"\n", originInfo->input_serial_number); +} + +static void +initDpxMainHeader(DpxFile* dpx, DpxMainHeader* header, const char* shortFilename) { + memset(header, 0, sizeof(DpxMainHeader)); + fillDpxFileInfo(dpx, &header->fileInfo, shortFilename); + fillDpxImageInfo(dpx, &header->imageInfo); + fillDpxOriginationInfo(dpx, &header->originInfo, &header->fileInfo); +#if 0 + fillDpxMPIInfo(dpx, &header->filmHeader); +#endif +} + +static void +dumpDpxMainHeader(DpxMainHeader* header) { + dumpDpxFileInfo(&header->fileInfo); + dumpDpxImageInfo(&header->imageInfo); + dumpDpxOriginationInfo(&header->originInfo); +#if 0 + dumpDpxMPIInformation(&header->filmHeader); +#endif +} + +static int verbose = 0; +void +dpxSetVerbose(int verbosity) { + verbose = verbosity; +} + +static void +verboseMe(DpxFile* dpx) { + + d_printf("size %d x %d x %d\n", dpx->width, dpx->height, dpx->depth); + d_printf("ImageStart %d, lineBufferLength %d, implied length %d\n", + dpx->imageOffset, dpx->lineBufferLength * 4, + dpx->imageOffset + pixelsToLongs(dpx->width * dpx->depth * dpx->height) * 4); +} + +int +dpxGetRowBytes(DpxFile* dpx, unsigned short* row, int y) { + + /* Note: this code is bizarre because DPX files can wrap */ + /* packed longwords across line boundaries!!!! */ + + size_t readLongs; + unsigned int longIndex; + int numPixels = dpx->width * dpx->depth; + int pixelIndex; + + /* only seek if not reading consecutive lines */ + /* this is not quite right yet, need to account for leftovers */ + if (y != dpx->fileYPos) { + int lineOffset = pixelsToLongs(y * dpx->width * dpx->depth) * 4; + if (verbose) d_printf("Seek in getRowBytes\n"); + if (logimage_fseek(dpx, dpx->imageOffset + lineOffset, SEEK_SET) != 0) { + if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, dpx->imageOffset + lineOffset); + return 1; + } + dpx->fileYPos = y; + } + + /* read enough longwords */ + readLongs = pixelsToLongs(numPixels - dpx->pixelBufferUsed); + if (logimage_fread(dpx->lineBuffer, 4, readLongs, dpx) != readLongs) { + if (verbose) d_printf("Couldn't read line %d length %d\n", y, readLongs * 4); + return 1; + } + ++dpx->fileYPos; + + /* convert longwords to pixels */ + pixelIndex = dpx->pixelBufferUsed; + + /* this is just strange */ + if (dpx->depth == 1) { + for (longIndex = 0; longIndex < readLongs; ++longIndex) { + unsigned int t = ntohl(dpx->lineBuffer[longIndex]); + dpx->pixelBuffer[pixelIndex] = t & 0x3ff; + t = t >> 10; + dpx->pixelBuffer[pixelIndex+1] = t & 0x3ff; + t = t >> 10; + dpx->pixelBuffer[pixelIndex+2] = t & 0x3ff; + pixelIndex += 3; + } + } else /* if (dpx->depth == 3) */ { + for (longIndex = 0; longIndex < readLongs; ++longIndex) { + unsigned int t = ntohl(dpx->lineBuffer[longIndex]); + t = t >> 2; + dpx->pixelBuffer[pixelIndex+2] = t & 0x3ff; + t = t >> 10; + dpx->pixelBuffer[pixelIndex+1] = t & 0x3ff; + t = t >> 10; + dpx->pixelBuffer[pixelIndex] = t & 0x3ff; + pixelIndex += 3; + } + } + dpx->pixelBufferUsed = pixelIndex; + + /* extract required pixels */ + for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) { + /* row[pixelIndex] = dpx->lut10[dpx->pixelBuffer[pixelIndex]]; */ + row[pixelIndex] = dpx->pixelBuffer[pixelIndex] << 6; + } + + /* save remaining pixels */ + while (pixelIndex < dpx->pixelBufferUsed) { + dpx->pixelBuffer[pixelIndex - numPixels] = dpx->pixelBuffer[pixelIndex]; + ++pixelIndex; + } + dpx->pixelBufferUsed -= numPixels; + + /* done! */ + return 0; +} + +int +dpxSetRowBytes(DpxFile* dpx, const unsigned short* row, int y) { + + /* Note: this code is bizarre because DPX files can wrap */ + /* packed longwords across line boundaries!!!! */ + + size_t writeLongs; + int longIndex; + int numPixels = dpx->width * dpx->depth; + int pixelIndex; + int pixelIndex2; + + /* only seek if not reading consecutive lines */ + /* this is not quite right yet */ + if (y != dpx->fileYPos) { + int lineOffset = pixelsToLongs(y * dpx->width * dpx->depth) * 4; + if (verbose) d_printf("Seek in getRowBytes\n"); + if (logimage_fseek(dpx, dpx->imageOffset + lineOffset, SEEK_SET) != 0) { + if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, dpx->imageOffset + lineOffset); + return 1; + } + dpx->fileYPos = y; + } + + /* put new pixels into pixelBuffer */ + for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) { + /* dpx->pixelBuffer[dpx->pixelBufferUsed + pixelIndex] = dpx->lut8[row[pixelIndex]]; */ + dpx->pixelBuffer[dpx->pixelBufferUsed + pixelIndex] = row[pixelIndex] >> 6; + } + dpx->pixelBufferUsed += numPixels; + + /* pack into longwords */ + writeLongs = dpx->pixelBufferUsed / 3; + /* process whole line at image end */ + if (dpx->fileYPos == (dpx->height - 1)) { + writeLongs = pixelsToLongs(dpx->pixelBufferUsed); + } + pixelIndex = 0; + if (dpx->depth == 1) { + for (longIndex = 0; longIndex < writeLongs; ++longIndex) { + unsigned int t = dpx->pixelBuffer[pixelIndex] | + (dpx->pixelBuffer[pixelIndex+1] << 10) | + (dpx->pixelBuffer[pixelIndex+2] << 20); + dpx->lineBuffer[longIndex] = htonl(t); + pixelIndex += 3; + } + } else { + for (longIndex = 0; longIndex < writeLongs; ++longIndex) { + unsigned int t = dpx->pixelBuffer[pixelIndex+2] << 2 | + (dpx->pixelBuffer[pixelIndex+1] << 12) | + (dpx->pixelBuffer[pixelIndex] << 22); + dpx->lineBuffer[longIndex] = htonl(t); + pixelIndex += 3; + } + } + + /* write them */ + if (fwrite(dpx->lineBuffer, 4, writeLongs, dpx->file) != writeLongs) { + if (verbose) d_printf("Couldn't write line %d length %d\n", y, writeLongs * 4); + return 1; + } + ++dpx->fileYPos; + + /* save remaining pixels */ + pixelIndex2 = 0; + while (pixelIndex < dpx->pixelBufferUsed) { + dpx->pixelBuffer[pixelIndex2] = dpx->pixelBuffer[pixelIndex]; + ++pixelIndex; + ++pixelIndex2; + } + dpx->pixelBufferUsed = pixelIndex2; + + return 0; +} + +#define LFMEMFILE 0 +#define LFREALFILE 1 + +static DpxFile* +intern_dpxOpen(int mode, const char* bytestuff, int bufsize) { + + DpxMainHeader header; + const char *filename = bytestuff; + DpxFile* dpx = (DpxFile*)malloc(sizeof(DpxFile)); + + if (dpx == 0) { + if (verbose) d_printf("Failed to malloc dpx file structure.\n"); + return 0; + } + + /* for close routine */ + dpx->file = 0; + dpx->lineBuffer = 0; + dpx->pixelBuffer = 0; + + if (mode == LFREALFILE) { + filename = bytestuff; + dpx->file = fopen(filename, "rb"); + if (dpx->file == 0) { + if (verbose) d_printf("Failed to open file \"%s\".\n", filename); + dpxClose(dpx); + return 0; + } + dpx->membuffer = 0; + dpx->memcursor = 0; + dpx->membuffersize = 0; + } else if (mode == LFMEMFILE) { + dpx->membuffer = (unsigned char *)bytestuff; + dpx->memcursor = (unsigned char *)bytestuff; + dpx->membuffersize = bufsize; + } + + dpx->reading = 1; + + if (logimage_fread(&header, sizeof(header), 1, dpx) == 0) { + if (verbose) d_printf("Not enough data for header in \"%s\".\n", filename); + dpxClose(dpx); + return 0; + } + + /* let's assume dpx files are always network order */ + if (header.fileInfo.magic_num != ntohl(DPX_FILE_MAGIC)) { + if (verbose) d_printf("Bad magic number %8.8lX in \"%s\".\n", + ntohl(header.fileInfo.magic_num), filename); + dpxClose(dpx); + return 0; + } + + if (ntohs(header.imageInfo.channel[0].packing) != 1) { + if (verbose) d_printf("Unknown packing %d\n", header.imageInfo.channel[0].packing); + dpxClose(dpx); + return 0; + } + + + dpx->width = ntohl(header.imageInfo.pixels_per_line); + dpx->height = ntohl(header.imageInfo.lines_per_image); + dpx->depth = ntohs(header.imageInfo.channels_per_image); + /* Another DPX vs Cineon wierdness */ + if (dpx->depth == 1) { + switch (header.imageInfo.channel[0].designator1) { + case 50: dpx->depth = 3; break; + case 51: dpx->depth = 4; break; + case 52: dpx->depth = 4; break; + default: break; + } + } + dpx->bitsPerPixel = 10; + /* dpx->bitsPerPixel = header.imageInfo.channel[0].bits_per_pixel; */ + dpx->imageOffset = ntohl(header.fileInfo.offset); + + dpx->lineBufferLength = pixelsToLongs(dpx->width * dpx->depth); + dpx->lineBuffer = malloc(dpx->lineBufferLength * 4); + if (dpx->lineBuffer == 0) { + if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", dpx->lineBufferLength * 4); + dpxClose(dpx); + return 0; + } + + /* could have 2 pixels left over */ + dpx->pixelBuffer = malloc((dpx->lineBufferLength * 3 + 2) * sizeof(unsigned short)); + if (dpx->pixelBuffer == 0) { + if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n", + (dpx->width * dpx->depth + 2 + 2) * sizeof(unsigned short)); + dpxClose(dpx); + return 0; + } + dpx->pixelBufferUsed = 0; + + if (logimage_fseek(dpx, dpx->imageOffset, SEEK_SET) != 0) { + if (verbose) d_printf("Couldn't seek to image data start at %d\n", dpx->imageOffset); + dpxClose(dpx); + return 0; + } + dpx->fileYPos = 0; + + logImageGetByteConversionDefaults(&dpx->params); + setupLut(dpx); + + dpx->getRow = &dpxGetRowBytes; + dpx->setRow = 0; + dpx->close = &dpxClose; + + if (verbose) { + verboseMe(dpx); + } + + return dpx; +} + +DpxFile* +dpxOpen(const char *filename) { + return intern_dpxOpen(LFREALFILE, filename, 0); +} + +DpxFile* +dpxOpenFromMem(unsigned char *buffer, unsigned int size) { + return intern_dpxOpen(LFMEMFILE, (const char *) buffer, size); +} + +int +dpxIsMemFileCineon(void *buffer) { + int magicnum = 0; + magicnum = *((int*)buffer); + if (magicnum == ntohl(DPX_FILE_MAGIC)) return 1; + else return 0; +} + +DpxFile* +dpxCreate(const char* filename, int width, int height, int depth) { + + /* Note: always write files in network order */ + /* By the spec, it shouldn't matter, but ... */ + + DpxMainHeader header; + const char* shortFilename = 0; + + DpxFile* dpx = (DpxFile*)malloc(sizeof(DpxFile)); + if (dpx == 0) { + if (verbose) d_printf("Failed to malloc dpx file structure.\n"); + return 0; + } + + memset(&header, 0, sizeof(header)); + + /* for close routine */ + dpx->file = 0; + dpx->lineBuffer = 0; + dpx->pixelBuffer = 0; + + dpx->file = fopen(filename, "wb"); + if (dpx->file == 0) { + if (verbose) d_printf("Couldn't open file %s\n", filename); + dpxClose(dpx); + return 0; + } + dpx->reading = 0; + + dpx->width = width; + dpx->height = height; + dpx->depth = depth; + dpx->bitsPerPixel = 10; + dpx->imageOffset = sizeof(DpxMainHeader); + + dpx->lineBufferLength = pixelsToLongs(dpx->width * dpx->depth); + dpx->lineBuffer = malloc(dpx->lineBufferLength * 4); + if (dpx->lineBuffer == 0) { + if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", dpx->lineBufferLength * 4); + dpxClose(dpx); + return 0; + } + + dpx->pixelBuffer = malloc((dpx->lineBufferLength * 3 + 2) * sizeof(unsigned short)); + if (dpx->pixelBuffer == 0) { + if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n", + (dpx->width * dpx->depth + 2 + 2) * sizeof(unsigned short)); + dpxClose(dpx); + return 0; + } + dpx->pixelBufferUsed = 0; + + /* find trailing part of filename */ + shortFilename = strrchr(filename, '/'); + if (shortFilename == 0) { + shortFilename = filename; + } else { + ++shortFilename; + } + initDpxMainHeader(dpx, &header, shortFilename); + + if (fwrite(&header, sizeof(header), 1, dpx->file) == 0) { + if (verbose) d_printf("Couldn't write image header\n"); + dpxClose(dpx); + return 0; + } + dpx->fileYPos = 0; + + logImageGetByteConversionDefaults(&dpx->params); + setupLut(dpx); + + dpx->getRow = 0; + dpx->setRow = &dpxSetRowBytes; + dpx->close = &dpxClose; + + return dpx; +} + +void +dpxClose(DpxFile* dpx) { + + if (dpx == 0) { + return; + } + + if (dpx->file) { + fclose(dpx->file); + dpx->file = 0; + } + + if (dpx->lineBuffer) { + free(dpx->lineBuffer); + dpx->lineBuffer = 0; + } + + if (dpx->pixelBuffer) { + free(dpx->pixelBuffer); + dpx->pixelBuffer = 0; + } + + free(dpx); +} + +void +dpxDump(const char* filename) { + + DpxMainHeader header; + FILE* file; + + file = fopen(filename, "rb"); + if (file == 0) { + d_printf("Failed to open file \"%s\".\n", filename); + return; + } + + if (fread(&header, sizeof(header), 1, file) == 0) { + d_printf("Not enough data for header in \"%s\".\n", filename); + fclose(file); + return; + } + + fclose(file); + dumpDpxMainHeader(&header); +} |