/* Convert input audio bits, endians and channels */ int SpeexEncoder::read_samples(FILE *fin, int frame_size, int bits, int channels, int lsb, short * input, spx_int32_t *size) { unsigned char in[MAX_FRAME_BYTES * 2]; int i; short *s; int nb_read; if (size && *size <= 0) { return 0; } /*Read input audio*/ if (size) *size -= bits / 8 * channels*frame_size; nb_read = fread(in, 1, bits / 8 * channels* frame_size, fin); nb_read /= bits / 8 * channels; /*fprintf (stderr, "%d\n", nb_read);*/ if (nb_read == 0) return 0; s = (short*)in; if (bits == 8) { /* Convert 8->16 bits */ for (i = frame_size*channels - 1; i >= 0; i--) { s[i] = (in[i] << 8) ^ 0x8000; } } else { /* convert to our endian format */ for (i = 0; i<frame_size*channels; i++) { if (lsb) s[i] = le_short(s[i]); else s[i] = be_short(s[i]); } } /* FIXME: This is probably redundent now */ /* copy to float input buffer */ for (i = 0; i<frame_size*channels; i++) { input[i] = (short)s[i]; } for (i = nb_read*channels; i<frame_size*channels; i++) { input[i] = 0; } return nb_read; }
void write_wav_header(FILE *file, int rate, int channels, int format, int size) { char ch[5]; celt_int32 itmp; celt_int16 stmp; ch[4]=0; fprintf (file, "RIFF"); itmp = 0x7fffffff; fwrite(&itmp, 4, 1, file); fprintf (file, "WAVEfmt "); itmp = le_int(16); fwrite(&itmp, 4, 1, file); stmp = le_short(1); fwrite(&stmp, 2, 1, file); stmp = le_short(channels); fwrite(&stmp, 2, 1, file); itmp = le_int(rate); fwrite(&itmp, 4, 1, file); itmp = le_int(rate*channels*2); fwrite(&itmp, 4, 1, file); stmp = le_short(2*channels); fwrite(&stmp, 2, 1, file); stmp = le_short(16); fwrite(&stmp, 2, 1, file); fprintf (file, "data"); itmp = le_int(0x7fffffff); fwrite(&itmp, 4, 1, file); }
int read_wav_header(FILE *file, int *rate, int *channels, int *format, celt_int32 *size) { char ch[5]; celt_int32 itmp; celt_int16 stmp; celt_int32 bpersec; celt_int16 balign; int skip_bytes; int i; ch[4]=0; #if 0 fread(ch, 1, 4, file); if (strcmp(ch, "RIFF")!=0) { fseek(file, 0, SEEK_SET); return 0; } fread(&itmp, 4, 1, file); *size = le_int(itmp-36); fread(ch, 1, 4, file); if (strcmp(ch, "WAVE")!=0) { fprintf (stderr, "RIFF file is not a WAVE file\n"); return -1; } #endif fread(ch, 1, 4, file); while (strcmp(ch, "fmt ")!=0) { fread(&itmp, 4, 1, file); itmp = le_int(itmp); /*fprintf (stderr, "skip=%d\n", itmp);*/ /*strange way of seeking, but it works even for pipes*/ for (i=0;i<itmp;i++) fgetc(file); /*fseek(file, itmp, SEEK_CUR);*/ fread(ch, 1, 4, file); if (feof(file)) { fprintf (stderr, "Corrupted WAVE file: no \"fmt \"\n"); return -1; } } /*if (strcmp(ch, "fmt ")!=0) { fprintf (stderr, "Corrupted WAVE file: no \"fmt \"\n"); return -1; }*/ fread(&itmp, 4, 1, file); itmp = le_int(itmp); skip_bytes=itmp-16; /*fprintf (stderr, "skip=%d\n", skip_bytes);*/ fread(&stmp, 2, 1, file); stmp = le_short(stmp); if (stmp!=1) { fprintf (stderr, "Only PCM encoding is supported\n"); return -1; } fread(&stmp, 2, 1, file); stmp = le_short(stmp); *channels = stmp; if (stmp>2) { fprintf (stderr, "Only mono and (intensity) stereo supported\n"); return -1; } fread(&itmp, 4, 1, file); itmp = le_int(itmp); *rate = itmp; fread(&itmp, 4, 1, file); bpersec = le_int(itmp); fread(&stmp, 2, 1, file); balign = le_short(stmp); fread(&stmp, 2, 1, file); stmp = le_short(stmp); if (stmp!=16 && stmp!=8) { fprintf (stderr, "Only 8/16-bit linear supported\n"); return -1; } *format=stmp; if (bpersec!=*rate**channels*stmp/8) { fprintf (stderr, "Corrupted header: ByteRate mismatch\n"); return -1; } if (balign!=*channels*stmp/8) { fprintf (stderr, "Corrupted header: BlockAlign mismatch\n"); return -1; } /*strange way of seeking, but it works even for pipes*/ if (skip_bytes>0) for (i=0;i<skip_bytes;i++) fgetc(file); /*fseek(file, skip_bytes, SEEK_CUR);*/ fread(ch, 1, 4, file); while (strcmp(ch, "data")!=0) { fread(&itmp, 4, 1, file); itmp = le_int(itmp); /*strange way of seeking, but it works even for pipes*/ for (i=0;i<itmp;i++) fgetc(file); /*fseek(file, itmp, SEEK_CUR);*/ fread(ch, 1, 4, file); if (feof(file)) { fprintf (stderr, "Corrupted WAVE file: no \"data\"\n"); return -1; } } /*Ignore this for now*/ fread(&itmp, 4, 1, file); itmp = le_int(itmp); *size=itmp; return 1; }
void *read_tga(const char *filename, int *width, int *height) { struct tga_header { char id_length; char color_map_type; char data_type_code; unsigned char color_map_origin[2]; unsigned char color_map_length[2]; char color_map_depth; unsigned char x_origin[2]; unsigned char y_origin[2]; unsigned char width[2]; unsigned char height[2]; char bits_per_pixel; char image_descriptor; } header; int i, color_map_size, pixels_size; FILE *f; size_t read; void *pixels; f = fopen(filename, "rb"); if (!f) { fprintf(stderr, "Unable to open %s for reading\n", filename); return NULL; } read = fread(&header, 1, sizeof(header), f); if (read != sizeof(header)) { fprintf(stderr, "%s has incomplete tga header\n", filename); fclose(f); return NULL; } if (header.data_type_code != 2) { fprintf(stderr, "%s is not an uncompressed RGB tga file\n", filename); fclose(f); return NULL; } if (header.bits_per_pixel != 24) { fprintf(stderr, "%s is not a 24-bit uncompressed RGB tga file\n", filename); fclose(f); return NULL; } for (i = 0; i < header.id_length; ++i) if (getc(f) == EOF) { fprintf(stderr, "%s has incomplete id string\n", filename); fclose(f); return NULL; } color_map_size = le_short(header.color_map_length) * (header.color_map_depth/8); for (i = 0; i < color_map_size; ++i) if (getc(f) == EOF) { fprintf(stderr, "%s has incomplete color map\n", filename); fclose(f); return NULL; } *width = le_short(header.width); *height = le_short(header.height); pixels_size = *width * *height * (header.bits_per_pixel/8); pixels = malloc(pixels_size); read = fread(pixels, 1, pixels_size, f); if (read != pixels_size) { fprintf(stderr, "%s has incomplete image\n", filename); fclose(f); free(pixels); return NULL; } return pixels; }
/* Convert input audio bits, endians and channels */ static int read_samples(FILE *fin,int frame_size, int bits, int channels, int lsb, short * input, char *buff, celt_int32 *size) { short s[MAX_FRAME_SIZE]; unsigned char *in = (unsigned char*)s; int i; int nb_read; if (size && *size<=0) { return 0; } /*Read input audio*/ if (size) *size -= bits/8*channels*frame_size; if (buff) { for (i=0;i<12;i++) in[i]=buff[i]; nb_read = fread(in+12,1,bits/8*channels*frame_size-12, fin) + 12; if (size) *size += 12; } else { nb_read = fread(in,1,bits/8*channels* frame_size, fin); } nb_read /= bits/8*channels; /*fprintf (stderr, "%d\n", nb_read);*/ if (nb_read==0) return 0; if(bits==8) { /* Convert 8->16 bits */ for(i=frame_size*channels-1;i>=0;i--) { s[i]=(in[i]<<8)^0x8000; } } else { /* convert to our endian format */ for(i=0;i<frame_size*channels;i++) { if(lsb) s[i]=le_short(s[i]); else s[i]=be_short(s[i]); } } /* FIXME: This is probably redundent now */ /* copy to float input buffer */ for (i=0;i<frame_size*channels;i++) { input[i]=s[i]; } for (i=nb_read*channels;i<frame_size*channels;i++) { input[i]=0; } return nb_read; }
int main(int argc, char **argv) { int c; int option_index = 0; char *inFile, *outFile; FILE *fin, *fout=NULL; short out[MAX_FRAME_SIZE]; short output[MAX_FRAME_SIZE]; int frame_size=0, granule_frame_size=0; void *st=NULL; CELTMode *mode=NULL; int packet_count=0; int stream_init = 0; int quiet = 0; ogg_int64_t page_granule=0, last_granule=0; int skip_samples=0, page_nb_packets; struct option long_options[] = { {"help", no_argument, NULL, 0}, {"quiet", no_argument, NULL, 0}, {"version", no_argument, NULL, 0}, {"version-short", no_argument, NULL, 0}, {"rate", required_argument, NULL, 0}, {"mono", no_argument, NULL, 0}, {"stereo", no_argument, NULL, 0}, {"packet-loss", required_argument, NULL, 0}, {0, 0, 0, 0} }; ogg_sync_state oy; ogg_page og; ogg_packet op; ogg_stream_state os; int enh_enabled; int nframes=2; int print_bitrate=0; int close_in=0; int eos=0; int forceMode=-1; int audio_size=0; float loss_percent=-1; int channels=-1; int rate=0; int extra_headers=0; int wav_format=0; int lookahead=0; int celt_serialno = -1; int firstpacket = 1; enh_enabled = 1; /*Process options*/ while(1) { c = getopt_long (argc, argv, "hvV", long_options, &option_index); if (c==-1) break; switch(c) { case 0: if (strcmp(long_options[option_index].name,"help")==0) { usage(); exit(0); } else if (strcmp(long_options[option_index].name,"quiet")==0) { quiet = 1; } else if (strcmp(long_options[option_index].name,"version")==0) { version(); exit(0); } else if (strcmp(long_options[option_index].name,"version-short")==0) { version_short(); exit(0); } else if (strcmp(long_options[option_index].name,"mono")==0) { channels=1; } else if (strcmp(long_options[option_index].name,"stereo")==0) { channels=2; } else if (strcmp(long_options[option_index].name,"rate")==0) { rate=atoi (optarg); } else if (strcmp(long_options[option_index].name,"packet-loss")==0) { loss_percent = atof(optarg); } break; case 'h': usage(); exit(0); break; case 'v': version(); exit(0); break; case 'V': print_bitrate=1; break; case '?': usage(); exit(1); break; } } if (argc-optind!=2 && argc-optind!=1) { usage(); exit(1); } inFile=argv[optind]; if (argc-optind==2) outFile=argv[optind+1]; else outFile = ""; wav_format = strlen(outFile)>=4 && ( strcmp(outFile+strlen(outFile)-4,".wav")==0 || strcmp(outFile+strlen(outFile)-4,".WAV")==0); /*Open input file*/ if (strcmp(inFile, "-")==0) { #if defined WIN32 || defined _WIN32 _setmode(_fileno(stdin), _O_BINARY); #endif fin=stdin; } else { fin = fopen(inFile, "rb"); if (!fin) { perror(inFile); exit(1); } close_in=1; } /*Init Ogg data struct*/ ogg_sync_init(&oy); /*Main decoding loop*/ while (1) { char *data; int i, nb_read; /*Get the ogg buffer for writing*/ data = ogg_sync_buffer(&oy, 200); /*Read bitstream from input file*/ nb_read = fread(data, sizeof(char), 200, fin); ogg_sync_wrote(&oy, nb_read); /*Loop for all complete pages we got (most likely only one)*/ while (ogg_sync_pageout(&oy, &og)==1) { if (stream_init == 0) { ogg_stream_init(&os, ogg_page_serialno(&og)); stream_init = 1; } if (ogg_page_serialno(&og) != os.serialno) { /* so all streams are read. */ ogg_stream_reset_serialno(&os, ogg_page_serialno(&og)); } /*Add page to the bitstream*/ ogg_stream_pagein(&os, &og); page_granule = ogg_page_granulepos(&og); page_nb_packets = ogg_page_packets(&og); if (page_granule>0 && frame_size) { /* FIXME: shift the granule values if --force-* is specified */ skip_samples = frame_size*(page_nb_packets*granule_frame_size*nframes - (page_granule-last_granule))/granule_frame_size; if (ogg_page_eos(&og)) skip_samples = -skip_samples; /*else if (!ogg_page_bos(&og)) skip_samples = 0;*/ } else { skip_samples = 0; } /*printf ("page granulepos: %d %d %d\n", skip_samples, page_nb_packets, (int)page_granule);*/ last_granule = page_granule; /*Extract all available packets*/ while (!eos && ogg_stream_packetout(&os, &op) == 1 && op.bytes>=8) { if (!memcmp(op.packet, "CELT ", 8)) { celt_serialno = os.serialno; } if (celt_serialno == -1 || os.serialno != celt_serialno) break; /*If first packet, process as CELT header*/ if (packet_count==0) { st = process_header(&op, enh_enabled, &frame_size, &granule_frame_size, &rate, &nframes, forceMode, &channels, &lookahead, &extra_headers, quiet, &mode); if (!st) exit(1); if (!nframes) nframes=1; fout = out_file_open(outFile, rate, &channels); } else if (packet_count==1) { if (!quiet) print_comments((char*)op.packet, op.bytes); } else if (packet_count<=1+extra_headers) { /* Ignore extra headers */ } else { int lost=0; if (loss_percent>0 && 100*((float)rand())/RAND_MAX<loss_percent) lost=1; /*End of stream condition*/ if (op.e_o_s && os.serialno == celt_serialno) /* don't care for anything except celt eos */ eos=1; { int ret; /*Decode frame*/ if (!lost) ret = celt_decode(st, (unsigned char*)op.packet, op.bytes, output); else ret = celt_decode(st, NULL, 0, output); /*for (i=0;i<frame_size*channels;i++) printf ("%d\n", (int)output[i]);*/ if (ret!=0) { fprintf (stderr, "Decoding error: corrupted stream?\n"); break; } if (print_bitrate) { celt_int32 tmp=op.bytes; char ch=13; fputc (ch, stderr); fprintf (stderr, "Bitrate in use: %d bytes/packet ", tmp); } /*Convert to short and save to output file*/ if (strlen(outFile)!=0) { for (i=0;i<frame_size*channels;i++) out[i]=le_short(output[i]); } else { for (i=0;i<frame_size*channels;i++) out[i]=output[i]; } { int frame_offset = 0; int new_frame_size = frame_size; /*printf ("packet %d %d\n", packet_no, skip_samples);*/ /*fprintf (stderr, "packet %d %d %d\n", packet_no, skip_samples, lookahead);*/ if (firstpacket == 1) { /*printf ("chopping first packet\n");*/ new_frame_size -= lookahead; frame_offset = lookahead; firstpacket = 0; } if (new_frame_size>0) { #if defined WIN32 || defined _WIN32 if (strlen(outFile)==0) WIN_Play_Samples (out+frame_offset*channels, sizeof(short) * new_frame_size*channels); else #endif fwrite(out+frame_offset*channels, sizeof(short), new_frame_size*channels, fout); audio_size+=sizeof(short)*new_frame_size*channels; } } } } packet_count++; } } if (feof(fin)) break; } if (fout && wav_format) { if (fseek(fout,4,SEEK_SET)==0) { int tmp; tmp = le_int(audio_size+36); fwrite(&tmp,4,1,fout); if (fseek(fout,32,SEEK_CUR)==0) { tmp = le_int(audio_size); fwrite(&tmp,4,1,fout); } else { fprintf (stderr, "First seek worked, second didn't\n"); } } else { fprintf (stderr, "Cannot seek on wave file, size will be incorrect\n"); } } if (st) { celt_decoder_destroy(st); celt_mode_destroy(mode); } else { fprintf (stderr, "This doesn't look like a CELT file\n"); } if (stream_init) ogg_stream_clear(&os); ogg_sync_clear(&oy); #if defined WIN32 || defined _WIN32 if (strlen(outFile)==0) WIN_Audio_close (); #endif if (close_in) fclose(fin); if (fout != NULL) fclose(fout); return 0; }
int AudioStreamPlaybackSpeex::mix(int16_t *p_buffer, int p_frames) { //printf("update, loops %i, read ofs %i\n", (int)loops, read_ofs); //printf("playing %i, paused %i\n", (int)playing, (int)paused); if (!active || !playing || !data.size()) return 0; /* if (read_ofs >= data.size()) { if (loops) { reload(); ++loop_count; } else { return; }; }; */ int todo = p_frames; if (todo < page_size) { return 0; }; int eos = 0; while (todo > page_size) { int ret = 0; while ((todo > page_size && packets_available && !eos) || (ret = ogg_sync_pageout(&oy, &og)) == 1) { if (!packets_available) { /*Add page to the bitstream*/ ogg_stream_pagein(&os, &og); page_granule = ogg_page_granulepos(&og); page_nb_packets = ogg_page_packets(&og); packet_no = 0; if (page_granule > 0 && frame_size) { skip_samples = page_nb_packets * frame_size * nframes - (page_granule - last_granule); if (ogg_page_eos(&og)) skip_samples = -skip_samples; /*else if (!ogg_page_bos(&og)) skip_samples = 0;*/ } else { skip_samples = 0; } last_granule = page_granule; packets_available = true; } /*Extract all available packets*/ while (todo > page_size && !eos) { if (ogg_stream_packetout(&os, &op) != 1) { packets_available = false; break; } packet_no++; /*End of stream condition*/ if (op.e_o_s) eos = 1; /*Copy Ogg packet to Speex bitstream*/ speex_bits_read_from(&bits, (char *)op.packet, op.bytes); for (int j = 0; j != nframes; j++) { int16_t *out = p_buffer; int ret; /*Decode frame*/ ret = speex_decode_int(st, &bits, out); /*for (i=0;i<frame_size*channels;i++) printf ("%d\n", (int)output[i]);*/ if (ret == -1) { printf("decode returned -1\n"); break; }; if (ret == -2) { OS::get_singleton()->printerr("Decoding error: corrupted stream?\n"); break; } if (speex_bits_remaining(&bits) < 0) { OS::get_singleton()->printerr("Decoding overflow: corrupted stream?\n"); break; } //if (channels==2) // speex_decode_stereo_int(output, frame_size, &stereo); /*Convert to short and save to output file*/ for (int i = 0; i < frame_size * stream_channels; i++) { out[i] = le_short(out[i]); } { int new_frame_size = frame_size; /*printf ("packet %d %d\n", packet_no, skip_samples);*/ if (packet_no == 1 && j == 0 && skip_samples > 0) { /*printf ("chopping first packet\n");*/ new_frame_size -= skip_samples; } if (packet_no == page_nb_packets && skip_samples < 0) { int packet_length = nframes * frame_size + skip_samples; new_frame_size = packet_length - j * frame_size; if (new_frame_size < 0) new_frame_size = 0; if (new_frame_size > frame_size) new_frame_size = frame_size; /*printf ("chopping end: %d %d %d\n", new_frame_size, packet_length, packet_no);*/ } p_buffer += new_frame_size * stream_channels; todo -= new_frame_size; } } }; }; //todo = get_todo(); //todo is still greater than page size, can write more if (todo > page_size || eos) { if (read_ofs < data.size()) { //char *buf; int nb_read = MIN(data.size() - read_ofs, READ_CHUNK); /*Get the ogg buffer for writing*/ char *ogg_dst = ogg_sync_buffer(&oy, nb_read); /*Read bitstream from input file*/ copymem(ogg_dst, &data[read_ofs], nb_read); read_ofs += nb_read; ogg_sync_wrote(&oy, nb_read); } else { if (loops) { reload(); ++loop_count; //break; } else { playing = false; unload(); break; }; } }; }; return p_frames - todo; };
opus_int64 audio_write(float *pcm, int channels, int frame_size, FILE *fout, SpeexResamplerState *resampler, int *skip, shapestate *shapemem, int file, opus_int64 maxout) { opus_int64 sampout=0; int i,ret,tmp_skip; unsigned out_len; short *out; float *buf; float *output; out=alloca(sizeof(short)*MAX_FRAME_SIZE*channels); buf=alloca(sizeof(float)*MAX_FRAME_SIZE*channels); maxout=maxout<0?0:maxout; do { if (skip){ tmp_skip = (*skip>frame_size) ? (int)frame_size : *skip; *skip -= tmp_skip; } else { tmp_skip = 0; } if (resampler){ unsigned in_len; output=buf; in_len = frame_size-tmp_skip; out_len = 1024<maxout?1024:maxout; speex_resampler_process_interleaved_float(resampler, pcm+channels*tmp_skip, &in_len, buf, &out_len); pcm += channels*(in_len+tmp_skip); frame_size -= in_len+tmp_skip; } else { output=pcm+channels*tmp_skip; out_len=frame_size-tmp_skip; frame_size=0; } /*Convert to short and save to output file*/ if (shapemem){ shape_dither_toshort(shapemem,out,output,out_len,channels); }else{ for (i=0;i<(int)out_len*channels;i++) out[i]=(short)float2int(fmaxf(-32768,fminf(output[i]*32768.f,32767))); } if ((le_short(1)!=1)&&file){ for (i=0;i<(int)out_len*channels;i++) out[i]=le_short(out[i]); } if(maxout>0) { #if defined WIN32 || defined _WIN32 if(!file){ ret=WIN_Play_Samples (out, sizeof(short) * channels * (out_len<maxout?out_len:maxout)); if(ret>0)ret/=sizeof(short)*channels; else fprintf(stderr, "Error playing audio.\n"); }else #elif defined HAVE_LIBSNDIO if(!file){ ret=sio_write (hdl, out, sizeof(short) * channels * (out_len<maxout?out_len:maxout)); if(ret>0)ret/=sizeof(short)*channels; else fprintf(stderr, "Error playing audio.\n"); }else #endif ret=fwrite(out, 2*channels, out_len<maxout?out_len:maxout, fout); sampout+=ret; maxout-=ret; } } while (frame_size>0 && maxout>0); return sampout; }
// Read a tga file into a buffer for use as an OpenGL texture. // Original code by Joe Groff, modified to handle alpha channels. void *readTga(const char *filename, int *width, int *height, int *alpha) { // TGA header for loading things into. struct tga_header { char id_length; char color_map_type; char data_type_code; unsigned char color_map_origin[2]; unsigned char color_map_length[2]; char color_map_depth; unsigned char x_origin[2]; unsigned char y_origin[2]; unsigned char width[2]; unsigned char height[2]; char bits_per_pixel; char image_descriptor; } header; int color_map_size, pixels_size; FILE *f; size_t read; void *pixels; // Try to open the file. f = fopen(filename, "rb"); if(!f) { fprintf(stderr, "Unable to open %s for reading\n", filename); return NULL; } // Check for valid header data. read = fread(&header, 1, sizeof(header), f); if(read != sizeof(header)) { fprintf(stderr, "%s has incomplete tga header\n", filename); fclose(f); return NULL; } if(header.data_type_code != 2) { fprintf( stderr, "%s is not an uncompressed RGB tga file\n", filename ); fclose(f); return NULL; } if((header.bits_per_pixel != 32) && (header.bits_per_pixel != 24)) { fprintf( stderr, "%s is not 24/32-bit uncompressed RGB/A tga file.\n", filename ); fclose(f); return NULL; } // Return to the outside if an alpha channel is present. if(header.bits_per_pixel == 32) { *alpha = 1; } else { *alpha = 0; } // Only handling non-palleted images. color_map_size = le_short(header.color_map_length) * (header.color_map_depth/8); if(color_map_size > 0) { fprintf( stderr, "%s is colormapped, cannot handle that.\n", filename ); fclose(f); return NULL; } // Set return width/height values and calculate image size. *width = le_short(header.width); *height = le_short(header.height); pixels_size = *width * *height * (header.bits_per_pixel / 8); pixels = malloc(pixels_size); // Read image. read = fread(pixels, 1, pixels_size, f); if(read != pixels_size) { fprintf(stderr, "%s has incomplete image\n", filename); fclose(f); free(pixels); return NULL; } return pixels; }
char *Texture::read_tga(const char *filename, int& width, int& height, int& depth)/*{{{*/ { struct tga_header { char id_length; char color_map_type; char data_type_code; unsigned char color_map_origin[2]; unsigned char color_map_length[2]; char color_map_depth; unsigned char x_origin[2]; unsigned char y_origin[2]; unsigned char width[2]; unsigned char height[2]; char bits_per_pixel; char image_descriptor; } header; int i, color_map_size; FILE *f; size_t read; char *pixels; f = fopen(filename, "rb"); if (!f) { fprintf(stderr, "Unable to open %s for reading\n", filename); return NULL; } read = fread(&header, 1, sizeof(header), f); if (read != sizeof(header)) { fprintf(stderr, "%s has incomplete tga header\n", filename); fclose(f); return NULL; } if (header.data_type_code != 2) { fprintf(stderr, "%s is not an uncompressed RGB tga file\n", filename); fclose(f); return NULL; } if (header.bits_per_pixel != 24 and header.bits_per_pixel != 32) { fprintf(stderr, "%s is not a 24-bit or 32-bit uncompressed RGB tga file but %i\n", filename, header.bits_per_pixel); fclose(f); return NULL; } for (i = 0; i < header.id_length; ++i) if (getc(f) == EOF) { fprintf(stderr, "%s has incomplete id string\n", filename); fclose(f); return NULL; } color_map_size = le_short(header.color_map_length) * (header.color_map_depth/8); for (i = 0; i < color_map_size; ++i) if (getc(f) == EOF) { fprintf(stderr, "%s has incomplete color map\n", filename); fclose(f); return NULL; } width = le_short(header.width); height = le_short(header.height); depth = (header.bits_per_pixel/8); unsigned int pixels_size = width * height * depth; pixels = new char[pixels_size]; read = fread(pixels, 1, pixels_size, f); if (read != pixels_size) { fprintf(stderr, "%s has incomplete image\n", filename); fclose(f); delete [] pixels; return NULL; } return pixels; }