Commit 6bae3b5b authored by Andrey Filippov's avatar Andrey Filippov

adding tiff-16 to indexed bmp conversion for preview

parent eba89b11
......@@ -34,21 +34,23 @@
#include <elphel/c313a.h>
#include <elphel/exifa.h>
#include <elphel/x393_devices.h>
#include <byteswap.h>
// change to 0 when done
#define ELPHEL_DEBUG 0
#if ELPHEL_DEBUG
#define ELPHEL_DEBUG_THIS 1
#define ELPHEL_DEBUG_THIS 1
#else
#define ELPHEL_DEBUG_THIS 0
#define ELPHEL_DEBUG_THIS 0
#endif
//#define D1(x) fprintf(stderr, "%s:%d:%s: ", __FILE__, __LINE__, __FUNCTION__); x
#define D1(x)
#if ELPHEL_DEBUG_THIS
#define D(x) fprintf(stderr, "%s:%d:%s: ", __FILE__, __LINE__, __FUNCTION__); x
#define D(x) fprintf(stderr, "%s:%d:%s: ", __FILE__, __LINE__, __FUNCTION__); x
#else
#define D(x)
#define D(x)
#endif
/** @brief HEADER_SIZE is defined to be larger than actual header (with EXIF) to use compile-time buffer */
......@@ -105,6 +107,13 @@ struct file_set {
int sensor_port;
int timestamp_name;
int base_chn;
// data to convert TIFF to 8-bit uncompressed bmp for quick preview
// int tiff_mn;
// int tiff_mx;
// int tiff_palette;
// int tiff_telem; // o - none,>0 - skip first rows, <0 - skip last rows
// int tiff_convert;// !=0 - convert TIFF-16 to 8 bits BMP
// TODO - add calculation of min/max through histograms (OK to apply in next runs)
};
static struct file_set files[SENSOR_PORTS];
......@@ -195,7 +204,8 @@ const char url_args[] = "This server supports sequence of commands entered in th
// path to file containing serial number
static const char path_to_serial[] = "/sys/devices/soc0/elphel393-init/serial";
int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int saveImage);
int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int saveImage,
int tiff_convert, int tiff_mn, int tiff_mx, int tiff_palette, int tiff_telem);
void sendBuffer(void * buffer, int len);
void listener_loop(struct file_set *fset);
void errorMsgXML(char * msg);
......@@ -1051,6 +1061,264 @@ void errorMsgXML(char * msg)
printf("%s",s);
}
/**
* Generate bmp header
* @param buffer pointer to the output budder, or null. If null - will only calculate the buffer size in bytes
* @param width image width (should be multiple of 4 )!
* @param height image height (should be multiple of 4 )!
* @param palette 0 - white hot, 1 - black hot, 2 - color
* @param telem >0 top telemetry lines, <0 - bottom telemetry lines
* @return header length
*/
int getBmpHeader(
uint8_t * buffer,
int width,
int height,
int palette,
int telem
)
{
int bitmap_size = 0;
int filesize;
const unsigned int palette012[][256]={ // msb is 0: 0x00rrggbb
{0x000000,0x010101,0x020202,0x030303,0x040404,0x050505,0x060606,0x070707,
0x080808,0x090909,0x0a0a0a,0x0b0b0b,0x0c0c0c,0x0d0d0d,0x0e0e0e,0x0f0f0f,
0x101010,0x111111,0x121212,0x131313,0x141414,0x151515,0x161616,0x171717,
0x181818,0x191919,0x1a1a1a,0x1b1b1b,0x1c1c1c,0x1d1d1d,0x1e1e1e,0x1f1f1f,
0x202020,0x212121,0x222222,0x232323,0x242424,0x252525,0x262626,0x272727,
0x282828,0x292929,0x2a2a2a,0x2b2b2b,0x2c2c2c,0x2d2d2d,0x2e2e2e,0x2f2f2f,
0x303030,0x313131,0x323232,0x333333,0x343434,0x353535,0x363636,0x373737,
0x383838,0x393939,0x3a3a3a,0x3b3b3b,0x3c3c3c,0x3d3d3d,0x3e3e3e,0x3f3f3f,
0x404040,0x414141,0x424242,0x434343,0x444444,0x454545,0x464646,0x474747,
0x484848,0x494949,0x4a4a4a,0x4b4b4b,0x4c4c4c,0x4d4d4d,0x4e4e4e,0x4f4f4f,
0x505050,0x515151,0x525252,0x535353,0x545454,0x555555,0x565656,0x575757,
0x585858,0x595959,0x5a5a5a,0x5b5b5b,0x5c5c5c,0x5d5d5d,0x5e5e5e,0x5f5f5f,
0x606060,0x616161,0x626262,0x636363,0x646464,0x656565,0x666666,0x676767,
0x686868,0x696969,0x6a6a6a,0x6b6b6b,0x6c6c6c,0x6d6d6d,0x6e6e6e,0x6f6f6f,
0x707070,0x717171,0x727272,0x737373,0x747474,0x757575,0x767676,0x777777,
0x787878,0x797979,0x7a7a7a,0x7b7b7b,0x7c7c7c,0x7d7d7d,0x7e7e7e,0x7f7f7f,
0x808080,0x818181,0x828282,0x838383,0x848484,0x858585,0x868686,0x878787,
0x888888,0x898989,0x8a8a8a,0x8b8b8b,0x8c8c8c,0x8d8d8d,0x8e8e8e,0x8f8f8f,
0x909090,0x919191,0x929292,0x939393,0x949494,0x959595,0x969696,0x979797,
0x989898,0x999999,0x9a9a9a,0x9b9b9b,0x9c9c9c,0x9d9d9d,0x9e9e9e,0x9f9f9f,
0xa0a0a0,0xa1a1a1,0xa2a2a2,0xa3a3a3,0xa4a4a4,0xa5a5a5,0xa6a6a6,0xa7a7a7,
0xa8a8a8,0xa9a9a9,0xaaaaaa,0xababab,0xacacac,0xadadad,0xaeaeae,0xafafaf,
0xb0b0b0,0xb1b1b1,0xb2b2b2,0xb3b3b3,0xb4b4b4,0xb5b5b5,0xb6b6b6,0xb7b7b7,
0xb8b8b8,0xb9b9b9,0xbababa,0xbbbbbb,0xbcbcbc,0xbdbdbd,0xbebebe,0xbfbfbf,
0xc0c0c0,0xc1c1c1,0xc2c2c2,0xc3c3c3,0xc4c4c4,0xc5c5c5,0xc6c6c6,0xc7c7c7,
0xc8c8c8,0xc9c9c9,0xcacaca,0xcbcbcb,0xcccccc,0xcdcdcd,0xcecece,0xcfcfcf,
0xd0d0d0,0xd1d1d1,0xd2d2d2,0xd3d3d3,0xd4d4d4,0xd5d5d5,0xd6d6d6,0xd7d7d7,
0xd8d8d8,0xd9d9d9,0xdadada,0xdbdbdb,0xdcdcdc,0xdddddd,0xdedede,0xdfdfdf,
0xe0e0e0,0xe1e1e1,0xe2e2e2,0xe3e3e3,0xe4e4e4,0xe5e5e5,0xe6e6e6,0xe7e7e7,
0xe8e8e8,0xe9e9e9,0xeaeaea,0xebebeb,0xececec,0xededed,0xeeeeee,0xefefef,
0xf0f0f0,0xf1f1f1,0xf2f2f2,0xf3f3f3,0xf4f4f4,0xf5f5f5,0xf6f6f6,0xf7f7f7,
0xf8f8f8,0xf9f9f9,0xfafafa,0xfbfbfb,0xfcfcfc,0xfdfdfd,0xfefefe,0xffffff},
{0xffffff,0xfefefe,0xfdfdfd,0xfcfcfc,0xfbfbfb,0xfafafa,0xf9f9f9,0xf8f8f8,
0xf7f7f7,0xf6f6f6,0xf5f5f5,0xf4f4f4,0xf3f3f3,0xf2f2f2,0xf1f1f1,0xf0f0f0,
0xefefef,0xeeeeee,0xededed,0xececec,0xebebeb,0xeaeaea,0xe9e9e9,0xe8e8e8,
0xe7e7e7,0xe6e6e6,0xe5e5e5,0xe4e4e4,0xe3e3e3,0xe2e2e2,0xe1e1e1,0xe0e0e0,
0xdfdfdf,0xdedede,0xdddddd,0xdcdcdc,0xdbdbdb,0xdadada,0xd9d9d9,0xd8d8d8,
0xd7d7d7,0xd6d6d6,0xd5d5d5,0xd4d4d4,0xd3d3d3,0xd2d2d2,0xd1d1d1,0xd0d0d0,
0xcfcfcf,0xcecece,0xcdcdcd,0xcccccc,0xcbcbcb,0xcacaca,0xc9c9c9,0xc8c8c8,
0xc7c7c7,0xc6c6c6,0xc5c5c5,0xc4c4c4,0xc3c3c3,0xc2c2c2,0xc1c1c1,0xc0c0c0,
0xbfbfbf,0xbebebe,0xbdbdbd,0xbcbcbc,0xbbbbbb,0xbababa,0xb9b9b9,0xb8b8b8,
0xb7b7b7,0xb6b6b6,0xb5b5b5,0xb4b4b4,0xb3b3b3,0xb2b2b2,0xb1b1b1,0xb0b0b0,
0xafafaf,0xaeaeae,0xadadad,0xacacac,0xababab,0xaaaaaa,0xa9a9a9,0xa8a8a8,
0xa7a7a7,0xa6a6a6,0xa5a5a5,0xa4a4a4,0xa3a3a3,0xa2a2a2,0xa1a1a1,0xa0a0a0,
0x9f9f9f,0x9e9e9e,0x9d9d9d,0x9c9c9c,0x9b9b9b,0x9a9a9a,0x999999,0x989898,
0x979797,0x969696,0x959595,0x949494,0x939393,0x929292,0x919191,0x909090,
0x8f8f8f,0x8e8e8e,0x8d8d8d,0x8c8c8c,0x8b8b8b,0x8a8a8a,0x898989,0x888888,
0x878787,0x868686,0x858585,0x848484,0x838383,0x828282,0x818181,0x808080,
0x7f7f7f,0x7e7e7e,0x7d7d7d,0x7c7c7c,0x7b7b7b,0x7a7a7a,0x797979,0x787878,
0x777777,0x767676,0x757575,0x747474,0x737373,0x727272,0x717171,0x707070,
0x6f6f6f,0x6e6e6e,0x6d6d6d,0x6c6c6c,0x6b6b6b,0x6a6a6a,0x696969,0x686868,
0x676767,0x666666,0x656565,0x646464,0x636363,0x626262,0x616161,0x606060,
0x5f5f5f,0x5e5e5e,0x5d5d5d,0x5c5c5c,0x5b5b5b,0x5a5a5a,0x595959,0x585858,
0x575757,0x565656,0x555555,0x545454,0x535353,0x525252,0x515151,0x505050,
0x4f4f4f,0x4e4e4e,0x4d4d4d,0x4c4c4c,0x4b4b4b,0x4a4a4a,0x494949,0x484848,
0x474747,0x464646,0x454545,0x444444,0x434343,0x424242,0x414141,0x404040,
0x3f3f3f,0x3e3e3e,0x3d3d3d,0x3c3c3c,0x3b3b3b,0x3a3a3a,0x393939,0x383838,
0x373737,0x363636,0x353535,0x343434,0x333333,0x323232,0x313131,0x303030,
0x2f2f2f,0x2e2e2e,0x2d2d2d,0x2c2c2c,0x2b2b2b,0x2a2a2a,0x292929,0x282828,
0x272727,0x262626,0x252525,0x242424,0x232323,0x222222,0x212121,0x202020,
0x1f1f1f,0x1e1e1e,0x1d1d1d,0x1c1c1c,0x1b1b1b,0x1a1a1a,0x191919,0x181818,
0x171717,0x161616,0x151515,0x141414,0x131313,0x121212,0x111111,0x101010,
0x0f0f0f,0x0e0e0e,0x0d0d0d,0x0c0c0c,0x0b0b0b,0x0a0a0a,0x090909,0x080808,
0x070707,0x060606,0x050505,0x040404,0x030303,0x020202,0x010101,0x000000},
{0x000000,0x000011,0x000021,0x00002a,0x000031,0x000038,0x00003f,0x000046,
0x00004d,0x000053,0x010057,0x02005b,0x03005f,0x040063,0x060067,0x07006a,
0x09006e,0x0b0073,0x0d0075,0x0d0076,0x100078,0x13007a,0x16007c,0x19007e,
0x1c0081,0x1f0083,0x220085,0x260087,0x290089,0x2c008a,0x30008c,0x33008e,
0x37008e,0x390090,0x3c0092,0x3e0093,0x410094,0x440095,0x460096,0x490096,
0x4c0097,0x4f0097,0x510097,0x540098,0x570099,0x5b0099,0x5d009a,0x61009b,
0x64009b,0x66009b,0x6a009b,0x6d009c,0x6f009c,0x71009d,0x74009d,0x77009d,
0x7a009d,0x7e009d,0x80009d,0x83009d,0x86009d,0x88009d,0x8a009d,0x8d009d,
0x90009c,0x94009c,0x96009b,0x99009b,0x9b009b,0x9d009b,0xa0009b,0xa3009b,
0xa5009b,0xa7009a,0xa90099,0xaa0099,0xad0099,0xaf0198,0xb00198,0xb10197,
0xb30196,0xb50295,0xb60295,0xb80395,0xba0495,0xba0494,0xbc0593,0xbe0692,
0xbf0692,0xc00791,0xc10890,0xc20a8f,0xc30a8e,0xc40c8d,0xc60d8b,0xc60e8a,
0xc81088,0xca1286,0xca1385,0xcb1484,0xcd1681,0xce187f,0xcf187c,0xd01a79,
0xd11c77,0xd21c75,0xd31e72,0xd42170,0xd4226d,0xd52469,0xd72665,0xd82763,
0xd92a60,0xda2c5c,0xdb2f58,0xdc2f53,0xdd314e,0xde3348,0xdf3443,0xdf363d,
0xe03838,0xe03932,0xe23b2d,0xe33d27,0xe43f21,0xe4411d,0xe5431b,0xe54518,
0xe64616,0xe74814,0xe84a12,0xe84c10,0xe94d0e,0xea4e0c,0xeb500b,0xeb510a,
0xeb5309,0xec5508,0xec5708,0xed5907,0xed5b06,0xee5c06,0xee5d05,0xef5f04,
0xef6104,0xef6204,0xf06403,0xf16603,0xf16603,0xf16803,0xf16a02,0xf16b02,
0xf26c01,0xf26e01,0xf36f01,0xf37101,0xf47300,0xf47500,0xf47600,0xf47800,
0xf57b00,0xf57d00,0xf57f00,0xf68100,0xf68200,0xf78400,0xf78600,0xf88800,
0xf88800,0xf88a00,0xf88c00,0xf98d00,0xf98e00,0xf99000,0xf99100,0xf99300,
0xfa9500,0xfb9700,0xfb9900,0xfb9c00,0xfc9e00,0xfca000,0xfda200,0xfda400,
0xfda600,0xfda800,0xfdab00,0xfdad00,0xfdae00,0xfeb000,0xfeb200,0xfeb300,
0xfeb500,0xfeb700,0xfeb900,0xfeba00,0xfebc00,0xfebe00,0xfec000,0xfec200,
0xfec400,0xfec500,0xfec700,0xfec901,0xfeca01,0xfecb01,0xfecd02,0xfece03,
0xfecf04,0xfed106,0xfed409,0xfed50a,0xfed70b,0xfed90d,0xffda0e,0xffdb10,
0xffdc14,0xffdd17,0xffde1c,0xffe020,0xffe223,0xffe227,0xffe42b,0xffe530,
0xffe636,0xffe73c,0xffe942,0xffea47,0xffeb4d,0xffed53,0xffee59,0xffee60,
0xffef67,0xfff06d,0xfff174,0xfff17b,0xfff284,0xfff28c,0xfff493,0xfff499,
0xfff5a0,0xfff5a7,0xfff6af,0xfff7b5,0xfff8bb,0xfff8c1,0xfff9c6,0xfff9cb,
0xfffad1,0xfffbd7,0xfffcdd,0xfffde3,0xfffde8,0xfffeed,0xfffef2,0xffffff}
};
const char bmp_template[] =
{'B', 'M', // 0x00: (2 bytes) "BM"
0x00, 0x00, 0x00, 0x00, // 0x02: (4 bytes) size of the BMP file
0x00, 0x00, // 0x06: (2 bytes) Reserved, can be 0
0x00, 0x00, // 0x08: (2 bytes) Reserved, can be 0
0x7a, 0x04, 0x00, 0x00, // 0x0a: (4 bytes) offset to the bitmap (here fixed size 0x47a)
0x6c, 0x00, 0x00, 0x00, // 0x0e: (4 bytes) DIB header 108 bytes (BITMAPV4HEADER)
0x00, 0x00, 0x00, 0x00, // 0x12: (4 bytes) image width, signed (negative - right-to-left)
0x00, 0x00, 0x00, 0x00, // 0x16: (4 bytes) image height, signed (negative - top-to-bottom)
0x01, 0x00, // 0x1a: (2 bytes) number of color planes == 1
0x08, 0x00, // 0x1c: (2 bytes) number of bits per pixel = 8
0x00, 0x00, 0x00, 0x00, // 0x1e: (4 bytes) compression method
0x00, 0x00, 0x00, 0x00, // 0x22: (4 bytes) image size (bitmap length 0x50000 for 640x512)
0x13, 0x0b, 0x00, 0x00, // 0x26: (4 bytes) horizontal pixels per meter (was 72 ppi)
0x13, 0x0b, 0x00, 0x00, // 0x2a: (4 bytes) vertical pixels per meter (was 72 ppi)
0x00, 0x01, 0x00, 0x00, // 0x2e: (4 bytes) number of colors
0x00, 0x01, 0x00, 0x00, // 0x32: (4 bytes) number of important colors
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // was some junk I did not understand,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // probably a shorter (core) header may be used
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00};
if (buffer) {
if (palette < 0) {
palette = 0;
} else if (palette > 2){
palette = 2;
}
if (telem){
if (telem > 0){
height -= telem;
} else {
height += telem;
}
}
D(fprintf(stderr, "Filling BMP header: %p, palette=%d\n",buffer, palette));
bitmap_size = width * height;
filesize = bitmap_size + sizeof(bmp_template) + sizeof(palette012[0]);
height = -height; // change to normal direction
D(fprintf(stderr, "bitmap_size = %d (0x%x), filesize = %d (0x%x), height= %d(0x%x)\n",bitmap_size,bitmap_size,filesize,filesize,height,height ));
memcpy(buffer, bmp_template, sizeof(bmp_template));
D(fprintf(stderr, "buffer[0..3]=0x%x 0x%x 0x%x 0x%x\n",buffer[0],buffer[1],buffer[2],buffer[3]));
D(fprintf(stderr, "buffer+sizeof(bmp_template)=%p, palette012[palette] = %p, sizeof(palette012[0])=%d, sizeof(palette012) = %d\n",
(buffer+sizeof(bmp_template)), palette012[palette], sizeof(palette012[0]), sizeof(palette012[0])));
memcpy(buffer+sizeof(bmp_template), palette012[palette], sizeof(palette012[0]));
D(fprintf(stderr, "buffer[palette...]=0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
buffer[sizeof(bmp_template)+0],buffer[sizeof(bmp_template)+1],buffer[sizeof(bmp_template)+2],buffer[sizeof(bmp_template)+3],
buffer[sizeof(bmp_template)+4],buffer[sizeof(bmp_template)+5],buffer[sizeof(bmp_template)+6],buffer[sizeof(bmp_template)+7]));
memcpy(buffer + 0x02, &filesize, 4);
memcpy(buffer + 0x22, &bitmap_size, 4);
memcpy(buffer + 0x12, &width, 4);
memcpy(buffer + 0x16, &height, 4);
D(fprintf(stderr, "buffer[2..5]=0x%x 0x%x 0x%x 0x%x\n",buffer[2],buffer[3],buffer[4],buffer[5]));
}
D(fprintf(stderr, "BMP header size: %d (0x%x) bytes\n",
sizeof(bmp_template) + sizeof(palette012[0]),
sizeof(bmp_template) + sizeof(palette012[0])));
return sizeof(bmp_template) + sizeof(palette012[0]);
}
/**
* Convert 16-bit big-endian tiff to 8-bit by mapping [mn,mx] range to [0,255] skipping
* telemetry (top lines if >0 or bottom lines if < 0. Offset is modified to process two
* halves of the file when wrapped around in the cirbuf.
* @param dst pointer to the destination buffer (byte per entry)
* @param src pointer to the source buffer (in circbuf, big-endian u16 per entry)
* @param offs offset (in pixels) in file for split images
* @param len number of pixels to copy
* @param mn minimal input pixel value to be mapped to 0
* @param mx maximal input pixel value to be mapped to 255
* @param width - image width in pixels
* @param height - full image height, including telemetry
* @param telem telemetry lines (>0 - top, <0 - bottom)
* @return pointer in the output buffer after the last copied
*/
uint8_t * convertImage (
uint8_t * dst,
uint16_t * src,
int * offs,
int len,
int mn,
int mx,
int width,
int height,
int telem){
uint16_t pix16;
int ipix;
uint8_t * pix8;
int iscale;
int start_pix = 0; // index in src to start copying
int end_pix = len; // index in src to end copying
if (telem > 0) {
if (*offs < telem * width) {
start_pix = telem * width - *offs;
}
} else if (telem < 0){
if (*offs +len > width * (height+telem)){
end_pix = width * (height+telem) - *offs;
}
}
D(fprintf(stderr, "convertImage(): telem= %d, start_pix=%d, end_pix=%d \n", telem,start_pix,end_pix));
iscale = 0x7f800000/(mx - mn);
D(fprintf(stderr, "convertImage(): *offs= %d, len=%d, mn=%d, mx=%d, width=%d, height=%d,telem=%d, iscale=%d(0x%x)\n",
*offs, len,mn,mx,width,height,telem,iscale,iscale));
for (; start_pix < end_pix; start_pix++) {
// pix16 = src[start_pix];
// __bswap_16 (pix16);
// ipix = pix16;
ipix = __bswap_16 (src[start_pix]);
pix8 = 0;
if (ipix >= mx){
pix8 = 255;
} else if (ipix >= mn){
pix8 = (((ipix - mn) * iscale) >> 23) & 0xff;
}
#if 0//ELPHEL_DEBUG_THIS
if ((start_pix >=164160) && (start_pix < 164164)){
D(fprintf(stderr, "start_pix=%d(0x%x), src[start_pix] = %d(0x%x), ipix=%d(0x%x), ((ipix - mn) * iscale)=%d(0x%x), pix8= %d(0x%x)\n",
start_pix,start_pix,src[start_pix],src[start_pix], ipix,ipix, ((ipix - mn) * iscale), ((ipix - mn) * iscale), pix8,pix8));
}
#endif
*dst = pix8;
dst++;
}
*offs = end_pix; // index in the whole image (including telem)
D(fprintf(stderr, "convertImage()->: *offs= %d\n",*offs));
return dst;
}
/**
* @brief Read, prepare and send single image file
*
......@@ -1061,9 +1329,24 @@ void errorMsgXML(char * msg)
* @param[in] bufferImageData write image data to buffer before sending
* @param[in] use_Exif flag indicating that Exif should be used
* @param[in] saveImage open file save dialog in web browser
* @param[in] tiff_convert convert image to 8-bit BMP
* @param[in] tiff_mn value to map to output 0
* @param[in] tiff_mx value to map to output 255
* @param[in] tiff_palette 0 - hot white, 1 - hot black, 2 - color
* @param[in] tiff_telem 0 - convert all lines,>0 skip first lines, < 0 - skip last lines
*
* @return 0 if file was successfully sent and negative error code otherwise
*/
int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int saveImage)
int sendImage(struct file_set *fset,
int bufferImageData,
int use_Exif,
int saveImage,
int tiff_convert,
int tiff_mn,
int tiff_mx,
int tiff_palette,
int tiff_telem)
{
int exifDataSize = 0;
int frameParamPointer = 0;
......@@ -1079,9 +1362,12 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
char * mime_type;
char * extension;
int timestamp_start;
int width;
int height;
uint8_t * out_ptr; // output pointer between the two-part BMP generation from the 16-bit TIFF
int tiff_offs;
jpeg_start = lseek(fset->circbuf_fd, 0, SEEK_CUR); //get the current read pointer
D(fprintf(stderr, "jpeg_start (long) = 0x%x\n", jpeg_start));
D(fprintf(stderr, "jpeg_start (long) = 0x%x, bufferImageData=%d\n", jpeg_start,bufferImageData));
#if 0
if (fset->jphead_fd<0)
......@@ -1114,6 +1400,18 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
memcpy(&frame_params, (unsigned long*)&ccam_dma_buf[frameParamPointer >> 2], sizeof(struct interframe_params_t) - 4);
jpeg_len = frame_params.frame_length;
color_mode = frame_params.color;
width = frame_params.width;
height = frame_params.height;
if (tiff_convert){
bufferImageData = 1; // OK even if tiff_convert will be disabled below
}
// disable convert if not COLORMODE_RAW
if (color_mode != COLORMODE_RAW) {
tiff_convert = 0;
}
if (frame_params.signffff != 0xffff) {
fprintf(stderr, "wrong signature signff = 0x%x \n", (int)frame_params.signffff);
for (i=0; i< sizeof(struct interframe_params_t)/4;i++){
......@@ -1154,56 +1452,77 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
timestamp_start=jpeg_start+((jpeg_len+CCAM_MMAP_META+3) & (~0x1f)) + 32 - CCAM_MMAP_META_SEC; // magic shift - should index first byte of the time stamp
if (timestamp_start >= buff_size) timestamp_start-=buff_size;
memcpy (&(frame_params.timestamp_sec), (unsigned long * ) &ccam_dma_buf[timestamp_start>>2],8);
if (color_mode == COLORMODE_RAW) {
if (fset->tiff_dev_fd <0)
fset->tiff_dev_fd = open(fset->tiff_dev_name, O_RDONLY);
if (fset->tiff_dev_fd < 0) { // check control OK
fprintf(stderr, "Error opening %s\n", fset->tiff_dev_name);
close(fset->jphead_fd);
fset->jphead_fd = -1;
return -5;
}
exifDataSize = lseek(fset->tiff_dev_fd, 1, SEEK_END); // at the beginning of page 1 - position == page length
if (exifDataSize < 0) exifDataSize = 0; // error from lseek;
if (!exifDataSize){
close(fset->tiff_dev_fd);
fset->tiff_dev_fd = -1;
}
} else if (use_Exif) {
D(fprintf(stderr,"frame_params.meta_index=0x%x\n",(int) frame_params.meta_index));
// read Exif to buffer:
if (fset->exif_dev_fd <0)
fset->exif_dev_fd = open(fset->exif_dev_name, O_RDONLY);
if (fset->exif_dev_fd < 0) { // check control OK
fprintf(stderr, "Error opening %s\n", fset->exif_dev_name);
close(fset->jphead_fd);
fset->jphead_fd = -1;
return -5;
}
exifDataSize = lseek(fset->exif_dev_fd, 1, SEEK_END); // at the beginning of page 1 - position == page length
if (exifDataSize < 0) exifDataSize = 0; // error from lseek;
if (!exifDataSize){
close(fset->exif_dev_fd);
fset->exif_dev_fd = -1;
}
D(fprintf(stderr, "sendImage(): tiff_convert=0x%x, color_mode=0x%x, bufferImageData=0x%x\n",tiff_convert,color_mode,bufferImageData));
D(fprintf(stderr, "sendImage(): tiff_palette=%d, tiff_mn=%d, tiff_mx=%d, tiff_telem=%d\n",tiff_palette, tiff_mn, tiff_mx, tiff_telem));
if (tiff_convert) {
exifDataSize = getBmpHeader( // bitmap header and palette
NULL, // void * buffer,
width, // int width,
height, // int height,
tiff_palette,
tiff_telem);
D(fprintf(stderr, "exifDataSize=0x%x\n",exifDataSize));
} else {
frame_params.meta_index=0;
fset->exif_dev_fd = -1;
if (color_mode == COLORMODE_RAW) {
if (fset->tiff_dev_fd <0)
fset->tiff_dev_fd = open(fset->tiff_dev_name, O_RDONLY);
D(fprintf(stderr, "open(%s) -> %x\n",fset->tiff_dev_name,fset->tiff_dev_fd));
if (fset->tiff_dev_fd < 0) { // check control OK
fprintf(stderr, "Error opening %s\n", fset->tiff_dev_name);
close(fset->jphead_fd);
fset->jphead_fd = -1;
return -5;
}
exifDataSize = lseek(fset->tiff_dev_fd, 1, SEEK_END); // at the beginning of page 1 - position == page length
if (exifDataSize < 0) exifDataSize = 0; // error from lseek;
if (!exifDataSize){
close(fset->tiff_dev_fd);
fset->tiff_dev_fd = -1;
}
} else if (use_Exif) {
D(fprintf(stderr,"frame_params.meta_index=0x%x\n",(int) frame_params.meta_index));
// read Exif to buffer:
if (fset->exif_dev_fd <0)
fset->exif_dev_fd = open(fset->exif_dev_name, O_RDONLY);
if (fset->exif_dev_fd < 0) { // check control OK
fprintf(stderr, "Error opening %s\n", fset->exif_dev_name);
close(fset->jphead_fd);
fset->jphead_fd = -1;
return -5;
}
exifDataSize = lseek(fset->exif_dev_fd, 1, SEEK_END); // at the beginning of page 1 - position == page length
if (exifDataSize < 0) exifDataSize = 0; // error from lseek;
if (!exifDataSize){
close(fset->exif_dev_fd);
fset->exif_dev_fd = -1;
}
} else {
frame_params.meta_index=0;
fset->exif_dev_fd = -1;
}
}
// Maybe make buffer that will fit both Exif and JPEG?
// Get metadata, update Exif and JFIF headers if ep and ed pointers are non-zero (NULL will generate files with JFIF-only headers)
// Now we always malloc buffer, before - only for bimg, using fixed-size header buffer - was it faster?
jpeg_full_size = jpeg_len + head_size + exifDataSize + ((head_size > 0) ? 2 : 0);
jpeg_full_size = (tiff_convert? (jpeg_len/2): jpeg_len) + head_size + exifDataSize + ((head_size > 0) ? 2 : 0);
// jpeg_len is the FPGA-generated image data, in convert mode number of pixels is half that
// fprintf(stderr, "jpeg_len = 0x%x, head_size = 0x%x, exifDataSize = 0x%x, jpeg_full_size = 0x%x\n",
// jpeg_len, head_size, exifDataSize, jpeg_full_size);
if (bufferImageData) jpeg_this_size = jpeg_full_size; // header+frame
if (bufferImageData) jpeg_this_size = jpeg_full_size; // header+frame always with tiff_convert
else jpeg_this_size = head_size + exifDataSize; // only header
D(fprintf(stderr, "jpeg_full_size=%d (0x%x)\n",jpeg_full_size,jpeg_full_size));
D(fprintf(stderr, "jpeg_this_size=%d (0x%x)\n",jpeg_this_size,jpeg_this_size));
jpeg_copy = malloc(jpeg_this_size);
if (!jpeg_copy) {
D(fprintf(stderr, "Malloc error allocating %d (0x%x) bytes\n",jpeg_this_size,jpeg_this_size));
syslog(LOG_ERR, "%s:%d malloc (%d) failed", __FILE__, __LINE__, jpeg_this_size);
// If we really want it, but don't get it - let's try more
for (i = 0; i < 10; i++) {
......@@ -1218,11 +1537,24 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
}
}
if (color_mode == COLORMODE_RAW) {
lseek(fset->tiff_dev_fd, frame_params.meta_index,SEEK_END); // select meta page to use (matching frame)
read (fset->tiff_dev_fd, &jpeg_copy[0], exifDataSize); // Read Tiff header
D(fprintf(stderr, "Allocated %d (0x%x) bytes to buffer image, tiff_convert=%d\n",jpeg_this_size,jpeg_this_size, tiff_convert));
// copy header
if (tiff_convert) { // BMP mode
getBmpHeader( // bitmap header and palette
(uint8_t *) &jpeg_copy[0], // uint8_t * buffer,
width, // int width,
height, // int height,
tiff_palette, // int palette,
tiff_telem);
D(fprintf(stderr, "BMP mode: exifDataSize-> %d jpeg_copy[0..3]=0x%02x 0x%02x 0x%02x 0x%02x\n",exifDataSize, jpeg_copy[0], jpeg_copy[1], jpeg_copy[2], jpeg_copy[3]));
} else if (color_mode == COLORMODE_RAW) {
int ipos, iread;
ipos=lseek(fset->tiff_dev_fd, frame_params.meta_index,SEEK_END); // select meta page to use (matching frame)
iread=read (fset->tiff_dev_fd, &jpeg_copy[0], exifDataSize); // Read Tiff header
close(fset->tiff_dev_fd);
D(fprintf(stderr, "fset->tiff_dev_fd = 0x%x, ipos=0x%x, iread=0x%x, meta_index=0x%x\n",fset->tiff_dev_fd, ipos, iread, frame_params.meta_index));
fset->tiff_dev_fd = -1;
D(fprintf(stderr, "TIFF mode: exifDataSize-> %d jpeg_copy[0..3]=0x%02x 0x%02x 0x%02x 0x%02x\n",exifDataSize, jpeg_copy[0], jpeg_copy[1], jpeg_copy[2], jpeg_copy[3]));
} else {
lseek(fset->jphead_fd, 0, 0);
read(fset->jphead_fd, &jpeg_copy[exifDataSize], head_size);
......@@ -1240,8 +1572,13 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
// case COLORMODE_MONO6: //! monochrome, (4:2:0),
// case COLORMODE_COLOR: //! color, 4:2:0, 18x18(old)
case COLORMODE_RAW: // jp4, original (4:2:0)
mime_type = "tiff";
extension = "tiff";
if (tiff_convert) {
mime_type = "bmp";
extension = "bmp";
} else {
mime_type = "tiff";
extension = "tiff";
}
break;
case COLORMODE_JP46: // jp4, original (4:2:0)
case COLORMODE_JP46DC: // jp4, dc -improved (4:2:0)
......@@ -1258,29 +1595,12 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
mime_type = "jp4";
extension = "jp4";
break;
// case COLORMODE_MONO4: //! monochrome, 4 blocks (but still with 2x2 macroblocks)
default:
mime_type = "jpeg";
extension = "jpeg";
}
// char * mime_type;
// char * extension;
/*
#define COLORMODE_MONO6 0 // monochrome, (4:2:0),
#define COLORMODE_COLOR 1 // color, 4:2:0, 18x18(old)
#define COLORMODE_JP46 2 // jp4, original (4:2:0)
#define COLORMODE_JP46DC 3 // jp4, dc -improved (4:2:0)
#define COLORMODE_COLOR20 4 // color, 4:2:0, 20x20, middle of the tile (not yet implemented)
#define COLORMODE_JP4 5 // jp4, 4 blocks, (legacy)
#define COLORMODE_JP4DC 6 // jp4, 4 blocks, dc -improved
#define COLORMODE_JP4DIFF 7 // jp4, 4 blocks, differential red := (R-G1), blue:=(B-G1), green=G1, green2 (G2-G1). G1 is defined by Bayer shift, any pixel can be used
#define COLORMODE_JP4HDR 8 // jp4, 4 blocks, differential HDR: red := (R-G1), blue:=(B-G1), green=G1, green2 (high gain)=G2) (G1 and G2 - diagonally opposite)
#define COLORMODE_JP4DIFF2 9 // jp4, 4 blocks, differential, divide differences by 2: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (G2-G1)/2
#define COLORMODE_JP4HDR2 10 // jp4, 4 blocks, differential HDR: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (high gain)=G2),
#define COLORMODE_MONO4 14 // monochrome, 4 blocks (but still with 2x2 macroblocks)
#define COLORMODE_RAW 15 // raw 8/16-bit data in scanline order, bypassing compressor
*/
D(fprintf(stderr, "MIME = '%s', extension = '%s',bufferImageData=%df\n",mime_type, extension,bufferImageData));
printf("Content-Type: image/%s\r\n", mime_type);
if (saveImage) {
printf("Content-Disposition: attachment; filename=\"%s%ld_%06d_%d.%s\"\r\n", // does not open, asks for filename to save
......@@ -1289,22 +1609,63 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
printf("Content-Disposition: inline; filename=\"%s%ld_%06d_%d.%s\"\r\n", // opens in browser, asks to save on right-click
fset->timestamp_name?"":"elphelimg_", frame_params.timestamp_sec, frame_params.timestamp_usec, fset->sensor_port + fset->base_chn, extension);
}
if (bufferImageData) { /* Buffer the whole file before sending over the network to make sure it will not be corrupted if the circular buffer will be overrun) */
// bufferImageData - always with tiff_convert
if (bufferImageData) { // Buffer the whole file before sending over the network to make sure it will not be corrupted if the circular buffer will be overrun)
#if ELPHEL_DEBUG_THIS
unsigned long start_time, end_time;
start_time = lseek(fset->circbuf_fd, LSEEK_CIRC_UTIME, SEEK_END);
#endif
l = head_size + exifDataSize;
tiff_offs = 0;
/* JPEG image data may be split in two segments (rolled over buffer end) - process both variants */
if ((jpeg_start + jpeg_len) > buff_size) { // two segments
memcpy(&jpeg_copy[l], (unsigned long* )&ccam_dma_buf[jpeg_start >> 2], buff_size - jpeg_start);
l += buff_size - jpeg_start;
memcpy(&jpeg_copy[l], (unsigned long* )&ccam_dma_buf[0], jpeg_len - (buff_size - jpeg_start));
D1(fprintf(stderr, "Two parts (buffered), jpeg_start (long) = 0x%x\n", jpeg_start));
D(fprintf(stderr, "Two-part image, l=%0x%x, tiff_convert=%d\n",l,tiff_convert));
if (tiff_convert) {
// first part
out_ptr = convertImage (
(uint8_t * ) &jpeg_copy[l], // uint8_t * dst,
(uint16_t *) &ccam_dma_buf[jpeg_start >> 2], // src,
&tiff_offs, // int * offs,
(jpeg_len - (buff_size - jpeg_start))/2, // int len,// in pixels - number of pixels to copy
tiff_mn, // int mn,
tiff_mx, // int mx,
width, // int width,
height, // int height,
tiff_telem); // int telem);
// second part
convertImage (
out_ptr, // uint8_t * dst, continue from where stopped
(uint16_t *)( &ccam_dma_buf[0], jpeg_len - (buff_size - jpeg_start)), // src,
&tiff_offs, // int * offs,
(jpeg_len - (buff_size - jpeg_start))/2, // int len,// in pixels - number of pixels to copy
tiff_mn, // int mn,
tiff_mx, // int mx,
width, // int width,
height, // int height,
tiff_telem); // int telem);
} else {
memcpy(&jpeg_copy[l], (unsigned long* )&ccam_dma_buf[jpeg_start >> 2], buff_size - jpeg_start);
l += buff_size - jpeg_start;
memcpy(&jpeg_copy[l], (unsigned long* )&ccam_dma_buf[0], jpeg_len - (buff_size - jpeg_start));
}
D1(fprintf(stderr, "Two parts (buffered), jpeg_start (long) = 0x%x\n", jpeg_start));
} else { /* single segment */
memcpy(&jpeg_copy[l], (unsigned long* )&ccam_dma_buf[jpeg_start >> 2], jpeg_len);
D1(fprintf(stderr, "One part (buffered), jpeg_start (long) = 0x%x, buff_size = 0x%x\n", jpeg_start, buff_size));
D(fprintf(stderr, "One-part image, l=%0x%x, tiff_convert=%d\n",l,tiff_convert));
if (tiff_convert) {
convertImage (
(uint8_t * ) &jpeg_copy[l], // uint8_t * dst,
(uint16_t *) &ccam_dma_buf[jpeg_start >> 2], // src,
&tiff_offs, // int * offs,
jpeg_len/2, // int len,// in pixels - number of pixels to copy
tiff_mn, // int mn,
tiff_mx, // int mx,
width, // int width,
height, // int height,
tiff_telem); // int telem);
} else {
memcpy(&jpeg_copy[l], (unsigned long* )&ccam_dma_buf[jpeg_start >> 2], jpeg_len);
}
D1(fprintf(stderr, "One part (buffered), jpeg_start (long) = 0x%x, buff_size = 0x%x\n", jpeg_start, buff_size));
}
#if ELPHEL_DEBUG_THIS
end_time = lseek(fset->circbuf_fd, LSEEK_CIRC_UTIME, SEEK_END);
......@@ -1376,7 +1737,7 @@ void listener_loop(struct file_set *fset)
int suggest_save_images = 0;
char buf [1024];
int len = 0;
char * cp, *cp1, *cp2;
char * cp, *cp1, *cp2, *cpeq;
int slow, skip; // reduce frame rate by slow
int base_chn;
int sent2socket = -1; // 1 - img, 2 - meta, 3 - pointers
......@@ -1385,6 +1746,12 @@ void listener_loop(struct file_set *fset)
int one = 1;
int buff_size;
int frame_number,compressed_frame_number;
int iv;
int tiff_convert=0 ; // - convert tiff to bmp for preview
int tiff_mn= 20000;
int tiff_mx= 22000;
int tiff_palette = 0;
int tiff_telem = 0; // 0 - none,>0 - skip first rows, <0 - skip last rows
memset((char*)&sock, 0, sizeof(sock));
sock.sin_port = htons(fset->port_num);
......@@ -1412,6 +1779,7 @@ void listener_loop(struct file_set *fset)
/* We need just the first line of the GET to read parameters */
if (fgets(buf, sizeof(buf) - 1, stdin)) len = strlen(buf);
cp = buf;
tiff_convert = 0;
strsep(&cp, "/?"); // ignore everything before first "/" or "?"
if (cp) {
// Now cp points to the first character after the first "/" or "?" in the url
......@@ -1491,12 +1859,14 @@ void listener_loop(struct file_set *fset)
_exit(0);
}
this_p = lseek(fset->circbuf_fd, LSEEK_CIRC_LAST, SEEK_END);
D(fprintf(stderr, "\n"));
D(fprintf(stderr, "%s: current frame pointer this_p (in bytes): 0x%x\n", __func__, this_p));
// continue with iterating through the commands
while ((cp1 = strsep(&cp, "/?&"))) {
// if the first character is a digit, it is a file pointer
if (strchr("0123456789", cp1[0])) {
this_p = lseek(fset->circbuf_fd, strtol(cp1, NULL, 10), SEEK_SET);
// should simg &sbimg be always buffered???
} else if ((strcmp(cp1, "img") == 0) || (strcmp(cp1, "bimg") == 0) || (strcmp(cp1, "simg") == 0) || (strcmp(cp1, "sbimg") == 0)) {
// fprintf(stderr, "%s: processing img command\n", __func__);
if (sent2socket > 0) break; // image/xmldata was already sent to socket, ignore
......@@ -1519,7 +1889,8 @@ void listener_loop(struct file_set *fset)
buf_images = ((strcmp(cp1, "img") == 0) || (strcmp(cp1, "simg") == 0)) ? 0 : 1;
suggest_save_images = ((strcmp(cp1, "simg") == 0) || (strcmp(cp1, "sbimg") == 0)) ? 1 : 0;
// fprintf(stderr, "%s: sending image\n", __func__);
rslt = sendImage(fset, buf_images, exif_enable, suggest_save_images); // verify driver that file pointer did not move
rslt = sendImage(fset, buf_images, exif_enable, suggest_save_images, // verify driver that file pointer did not move
tiff_convert, tiff_mn, tiff_mx, tiff_palette, tiff_telem);
}
sent2socket = 1;
if (rslt < 0) {
......@@ -1552,7 +1923,8 @@ void listener_loop(struct file_set *fset)
rslt = 0;
while (rslt >= 0) {
printf("\r\n--ElphelMultipartJPEGBoundary\r\n");
rslt = sendImage(fset, buf_images, exif_enable, 0); // verify driver that file pointer did not move
rslt = sendImage(fset, buf_images, exif_enable, 0, // verify driver that file pointer did not move
tiff_convert, tiff_mn, tiff_mx, tiff_palette, tiff_telem);
fflush(stdout);
if (rslt >= 0) for (skip = 0; skip < slow; skip++) {
this_p = lseek(fset->circbuf_fd, LSEEK_CIRC_NEXT, SEEK_END);
......@@ -1587,6 +1959,32 @@ void listener_loop(struct file_set *fset)
cp2 = cp1 + 4;
base_chn = strtol(cp2, NULL, 10);
fset->base_chn = base_chn;
} else if (strncmp(cp1, "tiff_", 5) == 0) { // combined several parameters starting with "tiff_"
// all these commands end with "=<value>"
cpeq = strchr(cp1,'='); // char *
D(fprintf(stderr, "got 'tiff_' in '%s'\n",cp1));
if (cpeq) { // ignore if there is no "=" in the token
iv = strtol(cpeq+1, NULL, 10);
D(fprintf(stderr, "iv=%d\n",iv));
if (strncmp(cp1, "tiff_mn", 7) == 0) {
tiff_mn = iv;
D(fprintf(stderr, "tiff_mn=%d'\n",tiff_mn));
} else if (strncmp(cp1, "tiff_mx", 7) == 0) {
tiff_mx = iv;
D(fprintf(stderr, "tiff_mx=%d'\n",tiff_mx));
} else if (strncmp(cp1, "tiff_palette", 12) == 0) {
tiff_palette = iv;
D(fprintf(stderr, "tiff_palette=%d'\n",tiff_palette));
} else if (strncmp(cp1, "tiff_telem", 10) == 0) {
tiff_telem = iv;
D(fprintf(stderr, "tiff_telem=%d'\n",tiff_telem));
}
}
if (strncmp(cp1, "tiff_convert", 12) == 0) {
tiff_convert = 1;
D(fprintf(stderr, "tiff_convert=%d'\n",tiff_convert));
}
} else if (strcmp(cp1, "noexif") == 0) {
exif_enable = 0;
} else if (strcmp(cp1, "exif") == 0) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment