Subversion Repositories ipe_artfile_utils

Compare Revisions

No changes between revisions

Regard whitespace Rev 4 → Rev 5

/trunk/Makefile
File deleted
/trunk/Makefile.linux
0,0 → 1,33
 
all: ipe_artfile_unpacker ipe_artfile_packer
 
ipe_artfile_unpacker: ipe_artfile_unpacker.c ipe_artfile_unpacker_ipe16.c ipe_artfile_unpacker_ipe32.c ipe16_lzw_decoder.c ipe32_lzw_decoder.c ipe16_bmpexport.c ipe32_bmpexport.c utils.c
gcc -std=c99 -Wall -c ipe_artfile_unpacker.c -o ipe_artfile_unpacker.o
gcc -std=c99 -Wall -c ipe_artfile_unpacker_ipe16.c -o ipe_artfile_unpacker_ipe16.o
gcc -std=c99 -Wall -c ipe_artfile_unpacker_ipe32.c -o ipe_artfile_unpacker_ipe32.o
gcc -std=c99 -Wall -c ipe16_lzw_decoder.c -o ipe16_lzw_decoder.o
gcc -std=c99 -Wall -c ipe32_lzw_decoder.c -o ipe32_lzw_decoder.o
gcc -std=c99 -Wall -c ipe16_bmpexport.c -o ipe16_bmpexport.o
gcc -std=c99 -Wall -c ipe32_bmpexport.c -o ipe32_bmpexport.o
gcc -std=c99 -Wall -c utils.c -o utils.o
gcc -o ipe_artfile_unpacker ipe_artfile_unpacker.o ipe_artfile_unpacker_ipe16.o ipe_artfile_unpacker_ipe32.o ipe16_lzw_decoder.o ipe32_lzw_decoder.o ipe16_bmpexport.o ipe32_bmpexport.o utils.o
rm *.o
 
ipe_artfile_packer: ipe_artfile_packer.c ipe_artfile_packer_ipe16_ba.c ipe_artfile_packer_ipe16_pip.c ipe_artfile_packer_ipe32.c ipe16_lzw_encoder.c ipe32_lzw_encoder.c ipe16_bmpimport.c ipe32_bmpimport.c utils.c
gcc -std=c99 -Wall -c ipe_artfile_packer.c -o ipe_artfile_packer.o
gcc -std=c99 -Wall -c ipe_artfile_packer_ipe16_ba.c -o ipe_artfile_packer_ipe16_ba.o
gcc -std=c99 -Wall -c ipe_artfile_packer_ipe16_pip.c -o ipe_artfile_packer_ipe16_pip.o
gcc -std=c99 -Wall -c ipe_artfile_packer_ipe32.c -o ipe_artfile_packer_ipe32.o
gcc -std=c99 -Wall -c ipe16_lzw_encoder.c -o ipe16_lzw_encoder.o
gcc -std=c99 -Wall -c ipe32_lzw_encoder.c -o ipe32_lzw_encoder.o
gcc -std=c99 -Wall -c ipe16_bmpimport.c -o ipe16_bmpimport.o
gcc -std=c99 -Wall -c ipe32_bmpimport.c -o ipe32_bmpimport.o
gcc -std=c99 -Wall -c utils.c -o utils.o
gcc -lm -o ipe_artfile_packer ipe_artfile_packer.o ipe_artfile_packer_ipe16_ba.o ipe_artfile_packer_ipe16_pip.o ipe_artfile_packer_ipe32.o ipe16_lzw_encoder.c ipe32_lzw_encoder.o ipe16_bmpimport.o ipe32_bmpimport.o utils.o
rm *.o
 
clean:
rm -f *.o
# TODO: if [ -f ... ] then rm
rm ipe_artfile_packer
rm ipe_artfile_unpacker
/trunk/Makefile.win
0,0 → 1,40
 
all: ipe_artfile_unpacker ipe_artfile_packer ipma_frame_extractor
 
ipe_artfile_unpacker: ipe_artfile_unpacker.c ipe_artfile_unpacker_ipe16.c ipe_artfile_unpacker_ipe32.c ipe16_lzw_decoder.c ipe32_lzw_decoder.c ipe16_bmpexport.c ipe32_bmpexport.c utils.c
gcc -std=c99 -Wall -c ipe_artfile_unpacker.c -o ipe_artfile_unpacker.o
gcc -std=c99 -Wall -c ipe_artfile_unpacker_ipe16.c -o ipe_artfile_unpacker_ipe16.o
gcc -std=c99 -Wall -c ipe_artfile_unpacker_ipe32.c -o ipe_artfile_unpacker_ipe32.o
gcc -std=c99 -Wall -c ipe16_lzw_decoder.c -o ipe16_lzw_decoder.o
gcc -std=c99 -Wall -c ipe32_lzw_decoder.c -o ipe32_lzw_decoder.o
gcc -std=c99 -Wall -c ipe16_bmpexport.c -o ipe16_bmpexport.o
gcc -std=c99 -Wall -c ipe32_bmpexport.c -o ipe32_bmpexport.o
gcc -std=c99 -Wall -c utils.c -o utils.o
gcc -o ipe_artfile_unpacker ipe_artfile_unpacker.o ipe_artfile_unpacker_ipe16.o ipe_artfile_unpacker_ipe32.o ipe16_lzw_decoder.o ipe32_lzw_decoder.o ipe16_bmpexport.o ipe32_bmpexport.o utils.o
del *.o
 
ipe_artfile_packer: ipe_artfile_packer.c ipe_artfile_packer_ipe16_ba.c ipe_artfile_packer_ipe16_pip.c ipe_artfile_packer_ipe32.c ipe16_lzw_encoder.c ipe32_lzw_encoder.c ipe16_bmpimport.c ipe32_bmpimport.c utils.c
gcc -std=c99 -Wall -c ipe_artfile_packer.c -o ipe_artfile_packer.o
gcc -std=c99 -Wall -c ipe_artfile_packer_ipe16_ba.c -o ipe_artfile_packer_ipe16_ba.o
gcc -std=c99 -Wall -c ipe_artfile_packer_ipe16_pip.c -o ipe_artfile_packer_ipe16_pip.o
gcc -std=c99 -Wall -c ipe_artfile_packer_ipe32.c -o ipe_artfile_packer_ipe32.o
gcc -std=c99 -Wall -c ipe16_lzw_encoder.c -o ipe16_lzw_encoder.o
gcc -std=c99 -Wall -c ipe32_lzw_encoder.c -o ipe32_lzw_encoder.o
gcc -std=c99 -Wall -c ipe16_bmpimport.c -o ipe16_bmpimport.o
gcc -std=c99 -Wall -c ipe32_bmpimport.c -o ipe32_bmpimport.o
gcc -std=c99 -Wall -c utils.c -o utils.o
gcc -lm -o ipe_artfile_packer ipe_artfile_packer.o ipe_artfile_packer_ipe16_ba.o ipe_artfile_packer_ipe16_pip.o ipe_artfile_packer_ipe32.o ipe16_lzw_encoder.c ipe32_lzw_encoder.o ipe16_bmpimport.o ipe32_bmpimport.o utils.o
del *.o
 
# Can only be compiled for Windows, because it requires "Video for Windows"!
ipma_frame_extractor: ipma_frame_extractor.c
gcc -std=c99 -Wall -c ipma_frame_extractor.c -o ipma_frame_extractor.o
gcc -lm -o ipma_frame_extractor ipma_frame_extractor.o -lVfw32 -lOle32
del *.o
 
clean:
del *.o
# TODO: if [ -f ... ] then rm
del ipe_artfile_packer.exe
del ipe_artfile_unpacker.exe
del ipma_frame_extractor.exe
/trunk/ipe_artfile_unpacker_ipe16.c
177,7 → 177,7
}
 
if (strlen(szDestFolder) > 0) {
char szAbsoluteBitmapFilename[MAX_FILE];
char szAbsoluteBitmapFilename[MAX_FILE+1];
sprintf(szAbsoluteBitmapFilename, "%s/%s", szDestFolder, szBitmapFilename);
FILE* fobBitmap = fopen(szAbsoluteBitmapFilename, "wb");
if (!fobBitmap) {
260,7 → 260,7
}
 
if (strlen(szDestFolder) > 0) {
char szAbsoluteBitmapFilename[MAX_FILE];
char szAbsoluteBitmapFilename[MAX_FILE+1];
sprintf(szAbsoluteBitmapFilename, "%s/%s", szDestFolder, szBitmapFilename);
FILE* fobBitmap = fopen(szAbsoluteBitmapFilename, "wb");
if (!fobBitmap) {
/trunk/ipe_artfile_unpacker_ipe32.c
166,7 → 166,7
}
 
if (strlen(szDestFolder) > 0) {
char szAbsoluteBitmapFilename[MAX_FILE];
char szAbsoluteBitmapFilename[MAX_FILE+1];
sprintf(szAbsoluteBitmapFilename, "%s/%s", szDestFolder, szBitmapFilename);
FILE* fobBitmap = fopen(szAbsoluteBitmapFilename, "wb");
if (!fobBitmap) {
/trunk/ipma_frame_extractor.c
0,0 → 1,484
/**
* IPMA video frame extractor by Daniel Marschall, ViaThinkSoft (C) 2022
* Supports codecs IPMA and IP20
* Revision: 2022-01-15
* License: Apache 2.0
**/
 
#define VERSION "2022-01-15"
 
#define _CRT_SECURE_NO_WARNINGS
// #define VISUAL_STUDIO_TEST
 
#include <windows.h>
#include <vfw.h>
#include <stdio.h>
#include <stdbool.h>
 
#ifndef VISUAL_STUDIO_TEST
#include <getopt.h>
#endif
 
#define LZ_MIN_BITS 9
#define LZ_MAX_BITS 12
 
#define LZ_MAX_CODE 4095 /* Largest 12 bit code */
#define NO_SUCH_CODE 4098 /* Impossible code = empty */
 
#define CLEAR_CODE 256
#define END_CODE 257
#define FIRST_CODE 258
 
bool dirExists(const char* dirName_in) {
DWORD ftyp = GetFileAttributesA(dirName_in);
if (ftyp == INVALID_FILE_ATTRIBUTES)
return false; //something is wrong with your path!
 
if (ftyp & FILE_ATTRIBUTE_DIRECTORY)
return true; // this is a directory!
 
return false; // this is not a directory!
}
 
typedef struct tagIpe16LZWDecoder {
int running_code;
int running_bits;
int max_code_plus_one;
int shift_state;
unsigned long shift_data;
unsigned char stack[LZ_MAX_CODE + 1];
unsigned int suffix[LZ_MAX_CODE + 1];
unsigned int prefix[LZ_MAX_CODE + 1];
} Ipe16LZWDecoder;
 
void ipe16lzw_init_decoder(Ipe16LZWDecoder* decoder) {
decoder->running_code = FIRST_CODE;
decoder->running_bits = LZ_MIN_BITS;
decoder->max_code_plus_one = 1 << decoder->running_bits;
decoder->shift_state = 0;
decoder->shift_data = 0;
 
int i;
for (i = 0; i <= LZ_MAX_CODE; i++) {
decoder->prefix[i] = NO_SUCH_CODE;
}
}
 
int ipe16lzw_read_code(unsigned char** inFile, Ipe16LZWDecoder* decoder) {
int code;
unsigned char next_byte;
static int code_masks[] = {
0x0000, 0x0001, 0x0003, 0x0007,
0x000f, 0x001f, 0x003f, 0x007f,
0x00ff, 0x01ff, 0x03ff, 0x07ff,
0x0fff
};
 
while (decoder->shift_state < decoder->running_bits) {
next_byte = **inFile;
*inFile = *inFile + 1;
decoder->shift_data |=
((unsigned long)next_byte) << decoder->shift_state;
decoder->shift_state += 8;
}
 
code = decoder->shift_data & code_masks[decoder->running_bits];
 
decoder->shift_data >>= decoder->running_bits;
decoder->shift_state -= decoder->running_bits;
 
if (++decoder->running_code > decoder->max_code_plus_one
&& decoder->running_bits < LZ_MAX_BITS) {
decoder->max_code_plus_one <<= 1;
decoder->running_bits++;
}
 
return code;
}
 
static int ipe16lzw_trace_prefix(unsigned int* prefix, int code, int clear_code) {
int i = 0;
 
while (code > clear_code && i++ <= LZ_MAX_CODE) {
code = prefix[code];
}
return code;
}
 
// Difference between ipma_lzw_decode and ipe16lzw_decode: At ipma_lzw_decode, inFile is "unsigned char**" and not "FILE*"
// We don't do unsigned, because we want to have <0 as error result
/*unsigned*/ int ipma_lzw_decode(unsigned char** inFile, Ipe16LZWDecoder* decoder, unsigned char* output, int outputLength) {
int i = 0, j;
int current_code;
int current_prefix;
int stack_ptr = 0;
int prev_code = NO_SUCH_CODE;
unsigned char* stack;
unsigned int* prefix;
unsigned int* suffix;
unsigned int bytes_written = 0;
 
ipe16lzw_init_decoder(decoder);
 
prefix = decoder->prefix;
suffix = decoder->suffix;
stack = decoder->stack;
 
/* Pop the stack */
while (stack_ptr != 0 && i < outputLength) {
output[i++] = stack[--stack_ptr];
//if (i > bytes_written) bytes_written = i;
++bytes_written;
}
 
while (i < outputLength) {
current_code = ipe16lzw_read_code(inFile, decoder);
 
if (current_code == END_CODE) {
if (i != outputLength - 1) // || decoder->pixel_count != 0
return -1; /* unexpected eof */
i++;
}
else if (current_code == CLEAR_CODE) {
for (j = 0; j <= LZ_MAX_CODE; j++) {
prefix[j] = NO_SUCH_CODE;
}
decoder->running_code = FIRST_CODE;
decoder->running_bits = LZ_MIN_BITS;
decoder->max_code_plus_one = 1 << decoder->running_bits;
prev_code = NO_SUCH_CODE;
}
else {
if (current_code < CLEAR_CODE) {
output[i++] = current_code;
//if (i > bytes_written) bytes_written = i;
++bytes_written;
}
else {
if ((current_code < 0) || (current_code > LZ_MAX_CODE))
return -2; /* image defect */
if (prefix[current_code] == NO_SUCH_CODE) {
if (current_code == decoder->running_code - 2) {
current_prefix = prev_code;
suffix[decoder->running_code - 2]
= stack[stack_ptr++]
= ipe16lzw_trace_prefix(prefix, prev_code, CLEAR_CODE);
}
else {
return -3; /* image defect */
}
}
else {
current_prefix = current_code;
}
j = 0;
while (j++ <= LZ_MAX_CODE && current_prefix > CLEAR_CODE && current_prefix <= LZ_MAX_CODE) {
stack[stack_ptr++] = suffix[current_prefix];
current_prefix = prefix[current_prefix];
}
if (j >= LZ_MAX_CODE || current_prefix > LZ_MAX_CODE)
return -4; /* image defect */
 
stack[stack_ptr++] = current_prefix;
 
while (stack_ptr != 0 && i < outputLength) {
output[i++] = stack[--stack_ptr];
//if (i > bytes_written) bytes_written = i;
++bytes_written;
}
}
if (prev_code != NO_SUCH_CODE) {
if ((decoder->running_code < 2) ||
(decoder->running_code > LZ_MAX_CODE + 2))
return -5; /* image defect */
prefix[decoder->running_code - 2] = prev_code;
 
if (current_code == decoder->running_code - 2) {
suffix[decoder->running_code - 2]
= ipe16lzw_trace_prefix(prefix, prev_code, CLEAR_CODE);
}
else {
suffix[decoder->running_code - 2]
= ipe16lzw_trace_prefix(prefix, current_code, CLEAR_CODE);
}
}
prev_code = current_code;
}
}
 
return bytes_written;
}
 
#define BMP_LINE_PADDING 4
#define BI_SIGNATURE 0x4D42
 
// Difference between ipma_write_bmp and ipe16_write_bmp: At ipma_write_bmp, the imagedata is bottom-down, and the palette is a RGBA-structure and not a RGB-structure
void ipma_write_bmp(FILE* output, unsigned int width, unsigned int height, unsigned char* imagedata, size_t imagedata_len, RGBQUAD *pal, int numColors) {
 
// Each line must be padded to a multiple of 4
int pad = (BMP_LINE_PADDING - (width % BMP_LINE_PADDING)) % BMP_LINE_PADDING;
int newwidth = width + pad;
int newsize = newwidth * height;
unsigned char* padded_imagedata = (unsigned char*)malloc(newsize);
if (padded_imagedata == NULL) return;
unsigned int i;
for (i = 0; i < height; ++i) {
int offset = newwidth * i;
memcpy(&padded_imagedata[offset], imagedata, width);
memset(&padded_imagedata[offset + width], 0, pad);
imagedata += width;
}
 
BITMAPFILEHEADER bfh;
bfh.bfType = BI_SIGNATURE;
bfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * numColors + newsize;
bfh.bfReserved1 = 0;
bfh.bfReserved2 = 0;
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * numColors;
fwrite(&bfh, sizeof(bfh), 1, output);
 
BITMAPINFOHEADER bih;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = width;
bih.biHeight = height; // (positive = "bottom-up"-Bitmap)
bih.biPlanes = 1;
bih.biBitCount = 8;
bih.biCompression = BI_RGB;
bih.biSizeImage = 0;
bih.biXPelsPerMeter = 0;
bih.biYPelsPerMeter = 0;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
fwrite(&bih, sizeof(bih), 1, output);
 
// Color table
fwrite(pal, sizeof(RGBQUAD) * numColors, 1, output);
 
// Image data
fwrite(padded_imagedata, newsize, 1, output);
 
free(padded_imagedata);
}
 
 
typedef struct tagBitmapInfoAndPalette {
BITMAPINFOHEADER bi;
RGBQUAD pal[256];
} BitmapInfoAndPalette;
 
bool ipma_export_frames_bmp(char* filename, char* outdir)
{
PAVIFILE pFile;
int res;
PAVISTREAM pStream1;
AVISTREAMINFOA asi1;
 
if (!CreateDirectoryA(outdir, NULL)) {
// Also happens if the directory already exists...
//printf("ERROR: Could not create directory %s\n", outdir);
//return false;
}
 
if (!dirExists(outdir)) {
fprintf(stderr, "ERROR: Directory couldn't be created! %s\n", outdir);
return 1;
}
 
res = AVIFileOpenA(&pFile, filename, OF_SHARE_DENY_WRITE, 0L);
if (res == AVIERR_FILEOPEN) {
printf("ERROR: AVIFileOpenA(%s) returns AVIERR_FILEOPEN. Does the file exist?\n", filename);
return false;
}
if (res != 0) {
printf("ERROR: AVIFileOpenA(%s) returns %d\n", filename, res);
return false;
}
 
res = AVIFileGetStream(pFile, &pStream1, streamtypeVIDEO, 0);
if (res == AVIERR_NODATA) {
printf("ERROR: AVIFileGetStream returns AVIERR_NODATA\n");
AVIFileRelease(pFile);
return false;
}
if (res == AVIERR_MEMORY) {
printf("ERROR: AVIFileGetStream returns AVIERR_MEMORY\n");
AVIFileRelease(pFile);
return false;
}
if (res != 0) {
printf("ERROR: AVIFileGetStream returns %d\n", res);
AVIFileRelease(pFile);
return false;
}
 
 
res = AVIStreamInfoA(pStream1, &asi1, sizeof(asi1));
if (res != 0) {
printf("ERROR: AVIStreamInfoA returns %d\n", res);
AVIStreamRelease(pStream1);
AVIFileRelease(pFile);
return false;
}
 
 
// The official handler name is "ipma", but some AVI files also use "IPMA"
int ipmaVersion = 0;
//if (asi1.fccHandler == mmioFOURCC('i', 'p', 'm', 'a')) ipmaVersion = 1;
if ((tolower(((asi1.fccHandler >> 0) & 0xFF)) == 'i') &&
(tolower(((asi1.fccHandler >> 8) & 0xFF)) == 'p') &&
(tolower(((asi1.fccHandler >> 16) & 0xFF)) == 'm') &&
(tolower(((asi1.fccHandler >> 24) & 0xFF)) == 'a'))
{
ipmaVersion = 1;
}
 
// The official handler name is "IP20", but all AVI files use "ip20"
//if (asi1.fccHandler == mmioFOURCC('I', 'P', '2', '0')) ipmaVersion = 2;
if ((tolower(((asi1.fccHandler >> 0) & 0xFF)) == 'i') &&
(tolower(((asi1.fccHandler >> 8) & 0xFF)) == 'p') &&
(tolower(((asi1.fccHandler >> 16) & 0xFF)) == '2') &&
(tolower(((asi1.fccHandler >> 24) & 0xFF)) == '0'))
{
ipmaVersion = 2;
}
 
if (ipmaVersion == 0) {
printf("ERROR: Not an IPMA or IP20 AVI file!\n");
AVIStreamRelease(pStream1);
AVIFileRelease(pFile);
return false;
}
 
 
int framesWritten = 0;
for (int i = 0; 1; i++) {
BitmapInfoAndPalette* pstrf = (BitmapInfoAndPalette*)malloc(sizeof(BitmapInfoAndPalette));
if (pstrf == NULL) return false;
LONG strf_siz = sizeof(BitmapInfoAndPalette);
ZeroMemory(pstrf, strf_siz);
 
//res = pStream1->ReadFormat(i, (LPVOID)pstrf, &strf_siz);
res = AVIStreamReadFormat(pStream1, i, (LPVOID)pstrf, &strf_siz);
if (res != 0) {
printf("ERROR: Read format info failed\n");
AVIStreamRelease(pStream1);
AVIFileRelease(pFile);
return false;
}
 
 
if (((ipmaVersion == 1) && (asi1.fccHandler != mmioFOURCC('I', 'p', 'm', 'a'))) &&
((ipmaVersion == 2) && (asi1.fccHandler != mmioFOURCC('I', 'p', '2', '0'))))
{
// biCompression is case-sensitive and must be "Ipma" or "Ip20"
if (ipmaVersion == 1) printf("ERROR: biCompression is not Ipma!\n");
if (ipmaVersion == 2) printf("ERROR: biCompression is not Ip20!\n");
AVIStreamRelease(pStream1);
AVIFileRelease(pFile);
return false;
}
 
int bufsiz_uncompressed = pstrf->bi.biSizeImage;
int bufsiz_compressed = pstrf->bi.biSizeImage * 1000; // for some reason, compressed can sometimes be larger than uncompressed, so we multiply by 1000
if (bufsiz_uncompressed != (asi1.rcFrame.right - asi1.rcFrame.left) * (asi1.rcFrame.bottom - asi1.rcFrame.top)) {
printf("WARNING: biSizeImage != rectWidth * rectHeight\n");
}
unsigned char* buffer_uncompressed = (unsigned char*)malloc(bufsiz_uncompressed);
if (buffer_uncompressed == NULL) return false;
unsigned char* buffer_compressed = (unsigned char*)malloc(bufsiz_compressed);
if (buffer_compressed == NULL) return false;
 
 
LONG plBytes = 0;
LONG plSamples = 0;
//res = pStream1->Read(i, 1, buffer_compressed, bufsiz_compressed, &plBytes, &plSamples);
res = AVIStreamRead(pStream1, i, 1, buffer_compressed, bufsiz_compressed, &plBytes, &plSamples);
if ((res != 0) || (plSamples == 0)) break;
 
Ipe16LZWDecoder* pdecoder = (Ipe16LZWDecoder*)malloc(sizeof(Ipe16LZWDecoder));
if (pdecoder == NULL) return false;
ZeroMemory(pdecoder, sizeof(Ipe16LZWDecoder));
unsigned char* work_buffer_compressed = buffer_compressed;
int plBytesUncompressed = ipma_lzw_decode(&work_buffer_compressed, pdecoder, buffer_uncompressed, bufsiz_uncompressed);
free(pdecoder);
if (plBytesUncompressed < 0) printf("WARNING: LZW Error %d at frame %d\n", plBytesUncompressed, i);
if (plBytesUncompressed != bufsiz_uncompressed) printf("WARNING: piBytesUncompressed != bufsiz_uncompressed\n");
if (plBytesUncompressed > 0) {
char filnam[MAX_PATH];
if (AVIStreamIsKeyFrame(pStream1, i)) {
sprintf(filnam, "%s\\frame_%05d_key.bmp", outdir, i);
} else {
sprintf(filnam, "%s\\frame_%05d.bmp", outdir, i);
}
FILE* fh2 = fopen(filnam, "wb+");
ipma_write_bmp(fh2, pstrf->bi.biWidth, pstrf->bi.biHeight, buffer_uncompressed, plBytesUncompressed, &pstrf->pal[0], 256);
fclose(fh2);
framesWritten++;
}
 
free(pstrf);
free(buffer_compressed);
free(buffer_uncompressed);
}
 
printf("%s: %d frames written to %s\n", filename, framesWritten, outdir);
 
AVIStreamRelease(pStream1);
AVIFileRelease(pFile);
return true;
}
 
void print_syntax() {
fprintf(stderr, "Syntax: -o <outputdir> -i <avifile>\n");
}
 
int main(int argc, char* argv[]) {
char filename[MAX_PATH];
char outdir[MAX_PATH];
 
#ifndef VISUAL_STUDIO_TEST
int c;
 
#define PRINT_SYNTAX { print_syntax(); return 0; }
 
while ((c = getopt(argc, argv, "Vi:o:")) != -1) {
switch (c) {
case 'V':
fprintf(stdout, "IPMA video frame extractor, revision %s\n", VERSION);
return 0;
case 'i':
strcpy(filename, optarg);
break;
case 'o':
strcpy(outdir, optarg);
break;
case '?':
PRINT_SYNTAX;
break;
}
}
if (optind < argc) PRINT_SYNTAX;
 
if (strlen(filename) == 0) PRINT_SYNTAX;
if (strlen(outdir) == 0) PRINT_SYNTAX;
 
FILE* fhTest = fopen(filename, "rb");
if (!fhTest) {
fprintf(stderr, "FATAL: Cannot open %s\n", filename);
return 1;
}
fclose(fhTest);
 
#else
strcpy(filename, "D:\\test\\AVI_TEST.avi");
strcpy(outdir, "D:\\test\\AVI_TEST");
#endif
 
if (CoInitialize(NULL) != 0) return 1;
 
bool res = ipma_export_frames_bmp(filename, outdir);
 
CoUninitialize();
 
return res ? 0 : 1;
}
/trunk/ipma_frame_extractor.exe
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property