Commit 6393936e authored by Mikhail Karpenko's avatar Mikhail Karpenko

Add PageNumber field to Exif and process it

This field corresponds to sensor port number
parent 11711b85
......@@ -29,8 +29,8 @@
</tool>
<tool id="org.eclipse.cdt.build.core.settings.holder.176385540" name="GNU C" superClass="org.eclipse.cdt.build.core.settings.holder">
<option id="org.eclipse.cdt.build.core.settings.holder.incpaths.1931881995" name="Include Paths" superClass="org.eclipse.cdt.build.core.settings.holder.incpaths" valueType="includePath">
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/linux-elphel/sysroots/elphel393/usr/include}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/linux-elphel/linux/source/include/elphel}&quot;"/>
<listOptionValue builtIn="false" value="&quot;${workspace_loc:/linux-elphel/sysroots/elphel393/usr/include}&quot;"/>
</option>
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1408747788" languageId="org.eclipse.cdt.core.gcc" languageName="GNU C" sourceContentType="org.eclipse.cdt.core.cSource,org.eclipse.cdt.core.cHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
</tool>
......
......@@ -25,6 +25,7 @@
<HostComputer tag="0x013c" format="ASCII" function="SERIAL"/>
<FrameNumber tag="0x83bb" format="LONG" count="1" seq="25" dlen="4"/>
<Orientation tag="0x112" format="SHORT" count="1" seq="27" dlen="2"/>
<PageNumber tag="0x129" format="SHORT" count="1" seq="28" dlen="2"/>
<ExifTag tag="0x8769" format="LONG" function="EXIFTAG"/>
<GPSTag tag="0x08825" format="LONG" function="GPSTAG"/>
</Image>
......
......@@ -173,58 +173,53 @@
#include <asm/byteorder.h>
#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
#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
//#define USEHTTP10(x)
#define USEHTTP10(x) x
// HEADER_SIZE is defined to be larger than actual header (later - with EXIF) to use compile-time buffer
//#define JPEG_HEADER_SIZE 0x26f // will not change
#define JPEG_HEADER_MAXSIZE 0x300 // will not change
#define TRAILER_SIZE 0x02
#define MAP_OPTIONS MAP_FILE | MAP_PRIVATE
//#define GLOBALPARS(x) globalPars[(x)-FRAMEPAR_GLOBALS] // should work in drivers and application
#define IMAGE_CHN_NUM 4
/** @brief the length of MakerNote buffer in @e long */
#define MAKERNOTE_LEN 16
struct file_set {
unsigned short port_num;
unsigned char sensor_num;
const char *cirbuf_fn;
int circbuf_fd;
const char *jphead_fn;
int jphead_fd;
const char *exif_dev_name;
int exif_dev_fd;
const char *exifmeta_dev_name;
int exifmeta_dev_fd;
};
static struct file_set files[IMAGE_CHN_NUM];
static struct file_set files[SENSOR_PORTS];
unsigned long * ccam_dma_buf; /* mmapped array */
char trailer[TRAILER_SIZE] = { 0xff, 0xd9 };
const char *circbuf_fnames[] = {
"/dev/circbuf0",
"/dev/circbuf1",
"/dev/circbuf2",
"/dev/circbuf3"
};
const char *jhead_fnames[] = {
"/dev/jpeghead0",
"/dev/jpeghead1",
"/dev/jpeghead2",
"/dev/jpeghead3",
};
static const char *exif_dev_names[SENSOR_PORTS] = { EXIF_DEV_NAMES };
static const char *exifmeta_dev_names[SENSOR_PORTS] = { EXIFMETA_DEV_NAMES };
const char app_args[] = "Usage:\n%s -p <port_number_1> [<port_number_2> <port_number_3> <port_number_4>]\n" \
"Start image server, bind it to ports <port_number_1> <port_number_2> <port_number_3> <port_number_4>\n" \
......@@ -262,22 +257,20 @@ const char url_args[] = "This server supports sequence of commands entered in th
" In this special mode autoexposure/white balance will not work in most cases,\n"
" camera should be set in triggered mode (TRIG=4), internal (TRIG_CONDITION=0).\n"
" No effect on free-running or \"slave\" cameras, so it is OK to send it to all.";
//int sendImage(int bufferImageData, int fd_circ, int use_Exif);
//int sendImage(int bufferImageData, int fd_circ, int use_Exif, int saveImage);
int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int saveImage);
void sendBuffer(void * buffer, int len);
//void listener_loop(int port, const char *circbuf_fname);
void listener_loop(struct file_set *fset);
void errorMsgXML(char * msg);
int framePointersXML(int fd_circ);
int metaXML(int fd_circ, int mode); /// mode: 0 - new (send headers), 1 - continue, 2 - finish
int printExifXML(int exif_page);
int framePointersXML(struct file_set *fset);
int metaXML(struct file_set *fset, int mode); /// mode: 0 - new (send headers), 1 - continue, 2 - finish
int printExifXML(int exif_page, struct file_set *fset);
int out1x1gif(void);
void waitFrameSync();
unsigned long getCurrentFrameNumber();
#define saferead255(f, d, l) read(f, d, ((l) < 256) ? (l) : 255)
int printExifXML(int exif_page)
int printExifXML(int exif_page, struct file_set *fset)
{
int indx;
long numfields = 0;
......@@ -285,8 +278,8 @@ int printExifXML(int exif_page)
int fd_exifdir;
struct exif_dir_table_t exif_dir[ExifKmlNumber]; /// store locations of the fields needed for KML generations in the Exif block
/// Create Exif directory
/// Read the size of the Exif data
/// Create Exif directory
/// Read the size of the Exif data
fd_exifdir = open(EXIFDIR_DEV_NAME, O_RDONLY);
if (fd_exifdir < 0) {
printf("<error>\"Opening %s\"</error>\n", EXIFDIR_DEV_NAME);
......@@ -317,6 +310,7 @@ int printExifXML(int exif_page)
case Exif_GPSInfo_CompassPitch: indx = Exif_GPSInfo_CompassPitch_Index; break;
case Exif_GPSInfo_CompassRollRef: indx = Exif_GPSInfo_CompassRollRef_Index; break;
case Exif_GPSInfo_CompassRoll: indx = Exif_GPSInfo_CompassRoll_Index; break;
case Exif_Image_PageNumber: indx = Exif_Image_PageNumber_Index; break;
default: indx = -1;
}
if (indx >= 0) {
......@@ -325,28 +319,29 @@ int printExifXML(int exif_page)
}
}
close(fd_exifdir);
/// Create XML files iteslf
/// Create XML files itself
long rational3[6];
long makerNote[14];
long makerNote[MAKERNOTE_LEN];
long exif_page_start;
char val[256];
int hours = 0, minutes = 0;
double seconds = 0.0;
double longitude = 0.0, latitude = 0.0, altitude = 0.0, heading = 0.0, roll = 0.0, pitch = 0.0, exposure = 0.0;
val[255] = '\0';
int fd_exif = open(EXIF_DEV_NAME, O_RDONLY);
int fd_exif = open(fset->exif_dev_name, O_RDONLY);
if (fd_exif < 0) {
printf("<error>\"Opening %s\"</error>\n", EXIF_DEV_NAME);
printf("<error>\"Opening %s\"</error>\n", fset->exif_dev_name);
return -3;
}
fset->exif_dev_fd = fd_exif;
exif_page_start = lseek(fd_exif, exif_page, SEEK_END); /// select specified Exif page
if (exif_page_start < 0) {
printf("<error>\"Exif page (%d) is out of range\"</error>\n", exif_page);
close(fd_exif);
return -1; /// Error opening Exif
}
///Image Description
///Image Description
if (exif_dir[Exif_Image_ImageDescription_Index].ltag == Exif_Image_ImageDescription) { // Exif_Image_ImageDescription is present in template
lseek(fd_exif,
exif_page_start + exif_dir[Exif_Image_ImageDescription_Index].dst,
......@@ -354,7 +349,7 @@ int printExifXML(int exif_page)
saferead255(fd_exif, val, exif_dir[Exif_Image_ImageDescription_Index].len);
printf("<ImageDescription>\"%s\"</ImageDescription>\n", val);
}
///Exif_Image_FrameNumber_Index 0x13
///Exif_Image_FrameNumber_Index 0x13
if (exif_dir[Exif_Image_FrameNumber_Index].ltag == Exif_Image_FrameNumber) { // Exif_Image_FrameNumber_Index is present in template
lseek(fd_exif,
exif_page_start + exif_dir[Exif_Image_FrameNumber_Index].dst,
......@@ -364,7 +359,7 @@ int printExifXML(int exif_page)
printf("<FrameNumber>\"%s\"</FrameNumber>\n", val);
}
///Exif_Image_Orientation_Index 0x15
///Exif_Image_Orientation_Index 0x14
if (exif_dir[Exif_Image_Orientation_Index].ltag == Exif_Image_Orientation) { // Exif_Image_Orientation_Index is present in template
lseek(fd_exif,
exif_page_start + exif_dir[Exif_Image_Orientation_Index].dst,
......@@ -375,7 +370,18 @@ int printExifXML(int exif_page)
printf("<Orientation>\"%s\"</Orientation>\n", val);
}
///DateTimeOriginal (with subseconds)
// Exif_Image_PageNumber
if (exif_dir[Exif_Image_PageNumber_Index].ltag == Exif_Image_PageNumber) { // Exif_Image_Orientation_Index is present in template
lseek(fd_exif,
exif_page_start + exif_dir[Exif_Image_PageNumber_Index].dst,
SEEK_SET);
rational3[0] = 0;
read(fd_exif, rational3, 2);
sprintf(val, "%u", __cpu_to_be16(rational3[0]));
printf("<SensorNumber>\"%s\"</SensorNumber>\n", val);
}
///DateTimeOriginal (with subseconds)
if (exif_dir[Exif_Photo_DateTimeOriginal_Index].ltag == Exif_Photo_DateTimeOriginal) {
lseek(fd_exif,
exif_page_start + exif_dir[Exif_Photo_DateTimeOriginal_Index].dst,
......@@ -392,7 +398,7 @@ int printExifXML(int exif_page)
}
printf("<DateTimeOriginal>\"%s\"</DateTimeOriginal>\n", val);
}
///Exif_Photo_ExposureTime
///Exif_Photo_ExposureTime
if (exif_dir[Exif_Photo_ExposureTime_Index].ltag == Exif_Photo_ExposureTime) { // Exif_Photo_ExposureTime is present in template
lseek(fd_exif,
exif_page_start + exif_dir[Exif_Photo_ExposureTime_Index].dst,
......@@ -403,7 +409,7 @@ int printExifXML(int exif_page)
printf("<ExposureTime>\"%s\"</ExposureTime>\n", val);
}
///Exif_Photo_MakerNote
///Exif_Photo_MakerNote
if (exif_dir[Exif_Photo_MakerNote_Index].ltag == Exif_Photo_MakerNote) { // Exif_Photo_MakerNote is present in template
lseek(fd_exif,
exif_page_start + exif_dir[Exif_Photo_MakerNote_Index].dst,
......@@ -430,8 +436,7 @@ int printExifXML(int exif_page)
printf("<MakerNote>\"%s\"</MakerNote>\n", val);
}
/// GPS measure mode
/// GPS measure mode
if (exif_dir[Exif_GPSInfo_GPSMeasureMode_Index].ltag == Exif_GPSInfo_GPSMeasureMode) {
lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_GPSMeasureMode_Index].dst,
......@@ -440,7 +445,8 @@ int printExifXML(int exif_page)
val[1] = '\0';
printf("<GPSMeasureMode>\"%s\"</GPSMeasureMode>\n", val);
}
///GPS date/time
///GPS date/time
if (exif_dir[Exif_GPSInfo_GPSDateStamp_Index].ltag == Exif_GPSInfo_GPSDateStamp) {
lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_GPSDateStamp_Index].dst,
......@@ -460,8 +466,8 @@ int printExifXML(int exif_page)
printf("<GPSDateTime>\"%s\"</GPSDateTime>\n", val);
}
/// knowing format provided from GPS - degrees and minutes only, no seconds:
///GPS Longitude
/// knowing format provided from GPS - degrees and minutes only, no seconds:
///GPS Longitude
if (exif_dir[Exif_GPSInfo_GPSLongitude_Index].ltag == Exif_GPSInfo_GPSLongitude) { // Exif_GPSInfo_GPSLongitude is present in template
lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_GPSLongitude_Index].dst,
......@@ -478,7 +484,7 @@ int printExifXML(int exif_page)
sprintf(val, "%f", longitude);
printf("<GPSLongitude>\"%s\"</GPSLongitude>\n", val);
}
///GPS Latitude
///GPS Latitude
if (exif_dir[Exif_GPSInfo_GPSLatitude_Index].ltag == Exif_GPSInfo_GPSLatitude) { // Exif_GPSInfo_GPSLatitude is present in template
lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_GPSLatitude_Index].dst,
......@@ -495,7 +501,7 @@ int printExifXML(int exif_page)
sprintf(val, "%f", latitude);
printf("<GPSLatitude>\"%s\"</GPSLatitude>\n", val);
}
///GPS Altitude
///GPS Altitude
if (exif_dir[Exif_GPSInfo_GPSAltitude_Index].ltag == Exif_GPSInfo_GPSAltitude) { // Exif_GPSInfo_GPSAltitude is present in template
lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_GPSAltitude_Index].dst,
......@@ -513,7 +519,7 @@ int printExifXML(int exif_page)
sprintf(val, "%f", altitude);
printf("<GPSAltitude>\"%s\"</GPSAltitude>\n", val);
}
///Compass Direction (magnetic)
///Compass Direction (magnetic)
if (exif_dir[Exif_GPSInfo_CompassDirection_Index].ltag == Exif_GPSInfo_CompassDirection) { // Exif_GPSInfo_CompassDirection is present in template
lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_CompassDirection_Index].dst,
......@@ -523,8 +529,8 @@ int printExifXML(int exif_page)
sprintf(val, "%f", heading);
printf("<CompassDirection>\"%s\"</CompassDirection>\n", val);
}
///Processing 'hacked' pitch and roll (made of Exif destination latitude/longitude)
///Compass Roll
///Processing 'hacked' pitch and roll (made of Exif destination latitude/longitude)
///Compass Roll
if (exif_dir[Exif_GPSInfo_CompassRoll_Index].ltag == Exif_GPSInfo_CompassRoll) { // Exif_GPSInfo_CompassRoll is present in template
lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_CompassRoll_Index].dst,
......@@ -543,7 +549,7 @@ int printExifXML(int exif_page)
printf("<CompassRoll>\"%s\"</CompassRoll>\n", val);
}
///Compass Pitch
///Compass Pitch
if (exif_dir[Exif_GPSInfo_CompassPitch_Index].ltag == Exif_GPSInfo_CompassPitch) { // Exif_GPSInfo_CompassPitch is present in template
lseek(fd_exif,
exif_page_start + exif_dir[Exif_GPSInfo_CompassPitch_Index].dst,
......@@ -565,13 +571,12 @@ int printExifXML(int exif_page)
return 0;
}
int metaXML(int fd_circ, int mode) /// mode: 0 - new (send headers), 1 - continue, 2 - finish
int metaXML(struct file_set *fset, int mode) /// mode: 0 - new (send headers), 1 - continue, 2 - finish
{
int frameParamPointer = 0;
struct interframe_params_t frame_params;
int jpeg_len, jpeg_start, buff_size, timestamp_start;
int fd_circ = fset->circbuf_fd;
if (mode == 2) { /// just close the xml file
printf("</meta>\n");
......@@ -593,18 +598,18 @@ int metaXML(int fd_circ, int mode) /// mode: 0 - new (send headers), 1 - con
return -1;
}
buff_size = lseek(fd_circ, 0, SEEK_END);
/// restore file poinetr after lseek-ing the end
/// restore file poinetr after lseek-ing the end
lseek(fd_circ, jpeg_start, SEEK_SET);
frameParamPointer = jpeg_start - 32;
if (frameParamPointer < 0) frameParamPointer += buff_size;
memcpy(&frame_params, (unsigned long* )&ccam_dma_buf[frameParamPointer >> 2], 32); /// ccam_dma_buf - global
jpeg_len=frame_params.frame_length;
/// Copy timestamp (goes after the image data)
/// Copy timestamp (goes after the image data)
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);
///TODO: Parse Exif data if available and add here
///TODO: Parse Exif data if available and add here
printf ("<frame>\n" \
"<start> 0x%x </start>\n" \
"<hash32_r> 0x%x </hash32_r>\n" \
......@@ -634,17 +639,17 @@ int metaXML(int fd_circ, int mode) /// mode: 0 - new (send headers), 1 - con
, frame_params.timestamp_usec
, (int) frame_params.signffff
);
///28-31 unsigned long timestamp_sec ; //! number of seconds since 1970 till the start of the frame exposure
///28-31 unsigned long frame_length ; //! JPEG frame length in circular buffer, bytes
/// };
///32-35 unsigned long timestamp_usec; //! number of microseconds to add
///28-31 unsigned long timestamp_sec ; //! number of seconds since 1970 till the start of the frame exposure
///28-31 unsigned long frame_length ; //! JPEG frame length in circular buffer, bytes
/// };
///32-35 unsigned long timestamp_usec; //! number of microseconds to add
if (frame_params.signffff !=0xffff) {
printf("<error>\"wrong signature (should be 0xffff)\"</error>\n");
} else {
///Put Exif data here
///Put Exif data here
printf ("<Exif>\n");
printExifXML(frame_params.meta_index);
printExifXML(frame_params.meta_index, fset);
printf ("</Exif>\n");
}
printf ("</frame>\n");
......@@ -670,7 +675,7 @@ void waitFrameSync()
close(fd_fparmsall);
}
int framePointersXML(int fd_circ)
int framePointersXML(struct file_set *fset)
{
const char ctlFileName[] = "/dev/frameparsall";
int fd_fparmsall;
......@@ -683,10 +688,10 @@ int framePointersXML(int fd_circ)
int frame8, frame_number, sensor_state, compressor_state;
char *cp_sensor_state, *cp_compressor_state;
struct framepars_all_t *frameParsAll;
struct framepars_t *framePars;
unsigned long *globalPars;
struct framepars_all_t **frameParsAll;
struct framepars_t *aframePars[SENSOR_PORTS];
unsigned long *aglobalPars[SENSOR_PORTS];
int fd_circ = fset->circbuf_fd;
fd_fparmsall = open(ctlFileName, O_RDWR);
if (fd_fparmsall < 0) { // check control OK
......@@ -695,8 +700,8 @@ int framePointersXML(int fd_circ)
return -1;
}
//! now try to mmap
frameParsAll = (struct framepars_all_t*)mmap(0, sizeof(struct framepars_all_t), PROT_READ, MAP_SHARED, fd_fparmsall, 0);
//! now try to mmap
frameParsAll = (struct framepars_all_t**)mmap(0, sizeof(struct framepars_all_t), PROT_READ, MAP_SHARED, fd_fparmsall, 0);
if ((int)frameParsAll == -1) {
frameParsAll = NULL;
printf("Error in mmap /dev/frameparsall");
......@@ -705,15 +710,16 @@ int framePointersXML(int fd_circ)
fd_fparmsall = -1;
return -1;
}
framePars = frameParsAll->framePars;
globalPars = frameParsAll->globalPars;
for (int j = 0; j < SENSOR_PORTS; j++) {
aframePars[j] = frameParsAll[j]->framePars;
aglobalPars[j] = frameParsAll[j]->globalPars;
}
// Read current sensor state - defined in c313a.h
// Read current sensor state - defined in c313a.h
frame_number = lseek(fd_fparmsall, 0, SEEK_CUR );
frame8 = frame_number & PARS_FRAMES_MASK;
// printf ("Current frame number is %d\n",frame_number);
sensor_state = framePars[frame8].pars[P_SENSOR_RUN];
compressor_state = framePars[frame8].pars[P_COMPRESSOR_RUN];
sensor_state = aframePars[fset->port_num][frame8].pars[P_SENSOR_RUN];
compressor_state = aframePars[fset->port_num][frame8].pars[P_COMPRESSOR_RUN];
cp_sensor_state = (sensor_state == 0) ?
"SENSOR_RUN_STOP" :
((sensor_state == 1) ?
......@@ -734,8 +740,8 @@ int framePointersXML(int fd_circ)
p = lseek(fd_circ, LSEEK_CIRC_PREV, SEEK_END);
nf++;
}
buf_free = GLOBALPARS(G_FREECIRCBUF);
frame_size = GLOBALPARS(G_FRAME_SIZE);
buf_free = GLOBALPARS(fset->port_num, G_FREECIRCBUF);
frame_size = GLOBALPARS(fset->port_num, G_FRAME_SIZE);
lseek(fd_circ, save_p, SEEK_SET); //! restore file pointer after temporarily moving it
buf_free = lseek(fd_circ, LSEEK_CIRC_FREE, SEEK_END); //! will change file pointer
......@@ -775,12 +781,13 @@ int framePointersXML(int fd_circ)
printf("Pragma: no-cache\r\n");
printf("\r\n");
printf(s);
//! No need to unmap?
munmap(frameParsAll, sizeof(struct framepars_all_t));
close(fd_fparmsall);
D(fprintf(stderr, ">%s< [%d bytes]\n", s, strlen(s)));
return 0;
}
//fwrite (&cbuffer[offset],1,bytesLeft,stdout);
int out1x1gif(void)
{
char s[] = "HTTP/1.0 200 OK\r\n" \
......@@ -798,7 +805,7 @@ int out1x1gif(void)
void errorMsgXML(char * msg)
{
char s[1024]; // was 701 acrtually
char s[1024];
sprintf(s, "<?xml version=\"1.0\"?>\n" \
"<frame_params>\n" \
......@@ -821,15 +828,11 @@ void errorMsgXML(char * msg)
int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int saveImage)
{
//const char HeadFileName[] = "/dev/jpeghead0";
const char ExifFileName[] = "/dev/exif_exif";
int exifDataSize = 0;
/// int exifIndexPointer=0;
int frameParamPointer = 0;
struct interframe_params_t frame_params;
/// struct frame_exif_t frame_exif; //just 8 bytes
int buff_size;
int jpeg_len; //bytes
int jpeg_len; // bytes
int jpeg_start; // bytes
int fd_head;
int fd_exif;
......@@ -841,7 +844,6 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
char * mime_type;
char * extension;
/// int metadata_start; //metadata pointer (in bytes, from the start of the ccam_dma_buf)
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));
fd_head = open(fset->jphead_fn, O_RDWR);
......@@ -850,21 +852,20 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
return -1;
}
fset->jphead_fd = fd_head;
lseek(fd_head, jpeg_start + 1, SEEK_END); /// create JPEG header, find out it's size TODO:
lseek(fd_head, jpeg_start + 1, SEEK_END); // create JPEG header, find out it's size
head_size = lseek(fd_head, 0, SEEK_END);
if (head_size > JPEG_HEADER_MAXSIZE) {
fprintf(stderr, "%s:%d: Too big JPEG header (%d > %d)", __FILE__, __LINE__, head_size, JPEG_HEADER_MAXSIZE );
close(fd_head);
return -2;
}
/*! find total buffer length (it is in defines, actually in c313a.h */
/*! find total buffer length (it is in defines, actually in c313a.h */
buff_size = lseek(fset->circbuf_fd, 0, SEEK_END);
/*! restore file poinetr after lseek-ing the end */
/*! restore file poinetr after lseek-ing the end */
lseek(fset->circbuf_fd, jpeg_start, SEEK_SET);
D(fprintf(stderr, "position (longs) = 0x%x\n", (int)lseek(fset->circbuf_fd, 0, SEEK_CUR)));
/*! now let's try mmap itself */
/// exifIndexPointer=jpeg_start-8;
/*! now let's try mmap itself */
frameParamPointer = jpeg_start - sizeof(struct interframe_params_t) + 4;
if (frameParamPointer < 0)
frameParamPointer += buff_size;
......@@ -875,17 +876,19 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
color_mode = frame_params.color;
if (frame_params.signffff != 0xffff) {
fprintf(stderr, "wrong signature signff = 0x%x \n", (int)frame_params.signffff);
#ifdef ELPHEL_DEBUG_THIS
lseek(fset->circbuf_fd, LSEEK_CIRC_STOP_COMPRESSOR, SEEK_END);
#endif
close(fd_head);
return -4;
}
if (use_Exif) {
//D(fprintf(stderr,"frame_params.meta_index=0x%x\n",(int) frame_params.meta_index));
/// read Exif to buffer:
fd_exif = open(ExifFileName, O_RDONLY);
D(fprintf(stderr,"frame_params.meta_index=0x%x\n",(int) frame_params.meta_index));
/// read Exif to buffer:
fd_exif = open(fset->exif_dev_name, O_RDONLY);
if (fd_exif < 0) { // check control OK
fprintf(stderr, "Error opening %s\n", ExifFileName);
fprintf(stderr, "Error opening %s\n", fset->exif_dev_name);
close(fd_head);
return -5;
}
......@@ -893,24 +896,24 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
if (exifDataSize < 0) exifDataSize = 0; // error from lseek;
if (!exifDataSize) close(fd_exif);
} else {
//frame_params.meta_index=0;
frame_params.meta_index=0;
fd_exif = -1;
}
///Maybe make buffer that will fit both Exif and JPEG?
//!Get metadata, update Exif and JFIF headers if ep and ed poinetrs 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?
///Maybe make buffer that will fit both Exif and JPEG?
//!Get metadata, update Exif and JFIF headers if ep and ed poinetrs 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 + 2 + exifDataSize;
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
else jpeg_this_size = head_size + exifDataSize; /// only header
if (bufferImageData) jpeg_this_size = jpeg_full_size; // header+frame
else jpeg_this_size = head_size + exifDataSize; // only header
jpeg_copy = malloc(jpeg_this_size);
if (!jpeg_copy) {
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
/// If we really want it, but don't get it - let's try more
for (i = 0; i < 10; i++) {
usleep(((jpeg_this_size & 0x3ff) + 5) * 100); // up to 0.1 sec
jpeg_copy = malloc(jpeg_this_size);
......@@ -926,21 +929,21 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
lseek(fd_head, 0, 0);
read(fd_head, &jpeg_copy[exifDataSize], head_size);
close(fd_head);
if (exifDataSize > 0) { //! insert Exif
memcpy(jpeg_copy, &jpeg_copy[exifDataSize], 2); //! copy first 2 bytes of the JFIF header before Exif
//lseek(fd_exif,frame_params.meta_index,SEEK_END); //! select meta page to use (matching frame)
read(fd_exif, &jpeg_copy[2], exifDataSize); //! Insert Exif itself
if (exifDataSize > 0) { // insert Exif
memcpy(jpeg_copy, &jpeg_copy[exifDataSize], 2); // copy first 2 bytes of the JFIF header before Exif
lseek(fd_exif,frame_params.meta_index,SEEK_END); // select meta page to use (matching frame)
read(fd_exif, &jpeg_copy[2], exifDataSize); // Insert Exif itself
close(fd_exif);
}
switch (color_mode) {
// case COLORMODE_MONO6: //! monochrome, (4:2:0),
// case COLORMODE_COLOR: //! color, 4:2:0, 18x18(old)
// case COLORMODE_MONO6: //! monochrome, (4:2:0),
// case COLORMODE_COLOR: //! color, 4:2:0, 18x18(old)
case COLORMODE_JP46: //! jp4, original (4:2:0)
case COLORMODE_JP46DC: //! jp4, dc -improved (4:2:0)
mime_type = "jp46";
extension = "jp46";
break;
// case COLORMODE_COLOR20: //! color, 4:2:0, 20x20, middle of the tile (not yet implemented)
// case COLORMODE_COLOR20: //! color, 4:2:0, 20x20, middle of the tile (not yet implemented)
case COLORMODE_JP4: //! jp4, 4 blocks, (legacy)
case COLORMODE_JP4DC: //! jp4, 4 blocks, dc -improved
case COLORMODE_JP4DIFF: //! 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
......@@ -950,15 +953,15 @@ 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)
// case COLORMODE_MONO4: //! monochrome, 4 blocks (but still with 2x2 macroblocks)
default:
mime_type = "jpeg";
extension = "jpeg";
}
// char * mime_type;
// char * extension;
/*
// 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)
......@@ -978,30 +981,12 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
else printf("Content-Disposition: inline; filename=\"elphelimg_%ld.%s\"\r\n", frame_params.timestamp_sec, extension); /// opens in browser, asks to save on right-click
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) */
// tell driver to flush CPU caches
const char *fname = "/sys/devices/soc0/elphel393-mem@0/flush_cpu_cache";
char cmd[128] = {0};
int jpeg_end;
int cmd_len;
// int fd_sys = open(fname, O_RDWR);
#ifdef ELPHEL_DEBUG_THIS
unsigned long start_time, end_time;
// if (fd_sys < 0) {
// fprintf(stderr, "unable to open sysfs entry: %s\n", fname);
// } else {
//// jpeg_end = jpeg_start + jpeg_len;
// jpeg_end = jpeg_start + (sizeof(struct interframe_params_t) - 4) * 512;
// if (jpeg_end > buff_size)
// jpeg_end -= buff_size;
// cmd_len = snprintf(cmd, 127, "%u:%d:%d", fset->sensor_num, jpeg_start, jpeg_end);
// if (write(fd_sys, cmd, cmd_len) == -1)
// fprintf(stderr, "failed to write to sysfs\n");
// close(fd_sys);
// }
start_time = lseek(fset->circbuf_fd, LSEEK_CIRC_UTIME, SEEK_END);
#endif
l = head_size + exifDataSize;
/*! JPEG image data may be split in two segments (rolled over buffer end) - process both variants */
/*! 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;
......@@ -1009,9 +994,10 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
} else { /*! single segment */
memcpy(&jpeg_copy[l], (unsigned long* )&ccam_dma_buf[jpeg_start >> 2], jpeg_len);
}
#ifdef ELPHEL_DEBUG_THIS
end_time = lseek(fset->circbuf_fd, LSEEK_CIRC_UTIME, SEEK_END);
fprintf(stderr, "memcpy time = %lu\n", end_time - start_time);
D(fprintf(stderr, "memcpy time = %lu\n", end_time - start_time));
#endif
memcpy(&jpeg_copy[jpeg_len + head_size + exifDataSize], trailer, 2);
printf("Content-Length: %d\r\n", jpeg_full_size);
printf("\r\n");
......@@ -1020,24 +1006,22 @@ int sendImage(struct file_set *fset, int bufferImageData, int use_Exif, int sav
printf("Content-Length: %d\r\n", jpeg_full_size);
printf("\r\n");
sendBuffer(jpeg_copy, head_size + exifDataSize); //JPEG+Exif
/*! JPEG image data may be split in two segments (rolled over buffer end) - process both variants */
/*! 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
/*! copy from the beginning of the frame to the end of the buffer */
/*! copy from the beginning of the frame to the end of the buffer */
sendBuffer((void*)&ccam_dma_buf[jpeg_start >> 2], buff_size - jpeg_start);
/*! copy from the beginning of the buffer to the end of the frame */
/*! copy from the beginning of the buffer to the end of the frame */
sendBuffer((void*)&ccam_dma_buf[0], jpeg_len - (buff_size - jpeg_start));
} else { // single segment
/*! copy from the beginning of the frame to the end of the frame (no buffer rollovers) */
/*! copy from the beginning of the frame to the end of the frame (no buffer rollovers) */
sendBuffer((void*)&ccam_dma_buf[jpeg_start >> 2], jpeg_len);
}
sendBuffer(trailer, 2);
}
free(jpeg_copy);
return 0;
}
/*! repeat writes to stdout until all data is sent */
void sendBuffer(void * buffer, int len)
{
......@@ -1056,13 +1040,9 @@ void sendBuffer(void * buffer, int len)
}
}
void listener_loop(struct file_set *fset)
{
char errormsg[1024];
//const char circbufFileName[] = "/dev/circbuf0";
int fd_circ;
int this_p; //! current frame pointer (bytes)
int rslt;
......@@ -1092,22 +1072,22 @@ void listener_loop(struct file_set *fset)
if (fd == -1) continue;
signal(SIGCHLD, SIG_IGN); // no zombies, please!
/*! do we need any fork at all if we now serve images to one client at a time? */
/*! do we need any fork at all if we now serve images to one client at a time? */
if (fork() == 0) {
close(res);
/*! setup stdin and stdout */
/*! setup stdin and stdout */
fflush(stdout);
fflush(stderr);
dup2(fd, 0);
dup2(fd, 1);
close(fd);
/*! We need just the first line of the GET to read parameters */
/*! We need just the first line of the GET to read parameters */
if (fgets(buf, sizeof(buf) - 1, stdin)) len = strlen(buf);
cp = buf;
strsep(&cp, "/?"); // ignore everything before first "/" or "?"
if (cp) {
//! Now cp points to the first character after the first "/" or "?" in the url
//! we need to remove everything after (and including) the first space
//! Now cp points to the first character after the first "/" or "?" in the url
//! we need to remove everything after (and including) the first space
cp1 = strchr(cp, ' ');
if (cp1) cp1[0] = '\0';
}
......@@ -1121,7 +1101,7 @@ void listener_loop(struct file_set *fset)
fflush(stdout);
_exit(0);
}
/// Process 'frame' and 'wframe' commands - theys do not need circbuf
/// Process 'frame' and 'wframe' commands - theys do not need circbuf
if ((strncmp(cp, "frame", 5) == 0) || (strncmp(cp, "wframe", 6) == 0)) {
if (strncmp(cp, "wframe", 6) == 0) waitFrameSync();
printf("HTTP/1.0 200 OK\r\n");
......@@ -1133,7 +1113,7 @@ void listener_loop(struct file_set *fset)
fflush(stdout);
_exit(0);
}
//!now process the commands one at a time, but first - open the circbuf file and setup the pointer
//!now process the commands one at a time, but first - open the circbuf file and setup the pointer
fd_circ = open(fset->cirbuf_fn, O_RDWR);
if (fd_circ < 0) { // check control OK
fprintf(stderr, "Error opening %s\n", fset->cirbuf_fn);
......@@ -1142,10 +1122,10 @@ void listener_loop(struct file_set *fset)
_exit(0);
}
fset->circbuf_fd = fd_circ;
/*! find total buffer length (it is in defines, actually in c313a.h */
/*! find total buffer length (it is in defines, actually in c313a.h */
buff_size = lseek(fd_circ, 0, SEEK_END);
fprintf(stderr, "%s: read circbuf size: %d\n", __func__, buff_size);
/*! now let's try mmap itself */
/*! now let's try mmap itself */
ccam_dma_buf = (unsigned long*)mmap(0, buff_size, PROT_READ, MAP_SHARED, fd_circ, 0);
if ((int)ccam_dma_buf == -1) {
fprintf(stderr, "Error in mmap\n");
......@@ -1156,11 +1136,9 @@ void listener_loop(struct file_set *fset)
}
this_p = lseek(fd_circ, LSEEK_CIRC_LAST, SEEK_END);
D(fprintf(stderr, "%s: current frame pointer this_p (in bytes): 0x%x\n", __func__, this_p));
//!continue with iterating through the commands
// continue with iterating through the commands
while ((cp1 = strsep(&cp, "/?&"))) {
// printf ("1->%s", cp1);
// fprintf (stderr, "1->%s",cp1);
//!if the first caracter is digit,it is a file pointer
// if the first character is a digit, it is a file pointer
if (strchr("0123456789", cp1[0])) {
this_p = lseek(fd_circ, strtol(cp1, NULL, 10), SEEK_SET);
} else if ((strcmp(cp1, "img") == 0) || (strcmp(cp1, "bimg") == 0) || (strcmp(cp1, "simg") == 0) || (strcmp(cp1, "sbimg") == 0)) {
......@@ -1189,13 +1167,13 @@ void listener_loop(struct file_set *fset)
}
fflush(stdout); //! let's not keep client waiting - anyway we've sent it all even when more commands maybe left
///multipart - always last
// multipart - always last
} else if ((strncmp(cp1, "mimg", 4) == 0) || (strncmp(cp1, "bmimg", 5) == 0) || (strncmp(cp1, "mbimg", 5) == 0)) {
if (sent2socket > 0) break; //! image/xmldata was already sent to socket, ignore
if (lseek(fd_circ, LSEEK_CIRC_READY, SEEK_END) < 0) //! here passes OK, some not ready error is later, in sendimage (make it return different numbers)
rslt = out1x1gif();
else {
//TODO:
//TODO:
buf_images = (strncmp(cp1, "mimg", 4) == 0) ? 0 : 1;
cp2 = cp1 + (buf_images ? 5 : 4);
slow = strtol(cp2, NULL, 10);
......@@ -1213,7 +1191,7 @@ void listener_loop(struct file_set *fset)
fflush(stdout);
if (rslt >= 0) for (skip = 0; skip < slow; skip++) {
this_p = lseek(fd_circ, LSEEK_CIRC_NEXT, SEEK_END);
/// If these "next" is not ready yet - wait, else - use latest image
/// If these "next" is not ready yet - wait, else - use latest image
if ((lseek(fd_circ, LSEEK_CIRC_VALID, SEEK_END) >= 0) && //! no sense to wait if the pointer is invalid
(lseek(fd_circ, LSEEK_CIRC_READY, SEEK_END) < 0) && //! or the frame is already ready
(lseek(fd_circ, LSEEK_CIRC_VALID, SEEK_END) >= 0)) //! test valid once again, after not ready - it might change
......@@ -1225,12 +1203,12 @@ void listener_loop(struct file_set *fset)
}
} else if (strcmp(cp1, "pointers") == 0) {
if (sent2socket > 0) break; //! image/xmldata was already sent to socket, ignore
framePointersXML(fd_circ); //! will restore file pointer after itself
framePointersXML(fset); //! will restore file pointer after itself
sent2socket = 3;
fflush(stdout); //! let's not keep client waiting - anyway we've sent it all even when more commands maybe left
} else if (strcmp(cp1, "meta") == 0) {
if ((sent2socket > 0) && (sent2socket != 2)) break; //! image/xmldata was already sent to socket, ignore
metaXML(fd_circ, (sent2socket > 0) ? 1 : 0); /// 0 - new (send headers), 1 - continue, 2 - finish
metaXML(fset, (sent2socket > 0) ? 1 : 0); /// 0 - new (send headers), 1 - continue, 2 - finish
sent2socket = 2;
fflush(stdout); //! let's not keep client waiting - anyway we've sent it all even when more commands maybe left
} else if (strcmp(cp1, "noexif") == 0) {
......@@ -1259,18 +1237,18 @@ void listener_loop(struct file_set *fset)
(lseek(fd_circ, LSEEK_CIRC_VALID, SEEK_END) >= 0)) //! test valid once again, after not ready - it might change
this_p = lseek(fd_circ, LSEEK_CIRC_WAIT, SEEK_END);
} else if (strcmp(cp1, "trig") == 0) {
// printf ("trig argument\n");
// printf ("trig argument\n");
int fd_fpga = open("/dev/fpgaio", O_RDWR);
// printf ("fd_fpga = 0x%x\n",fd_fpga);
// printf ("fd_fpga = 0x%x\n",fd_fpga);
if (fd_fpga >= 0) {
//int aaa;
//int aaa;
lseek(fd_fpga, 0x7b, SEEK_SET); //!TODO: remove absolute register address from user application! 32-bit registers, not bytes
//printf ("lseek()-> 0x%x\n",aaa);
//printf ("lseek()-> 0x%x\n",aaa);
long data = 1;
write(fd_fpga, &data, 4); // actually send the trigger pulse (will leave camera in single-shot mode)
//printf ("write()-> 0x%x\n",aaa);
//printf ("write()-> 0x%x\n",aaa);
close(fd_fpga);
}
} else if (strcmp(cp1, "favicon.ico") == 0) {
......@@ -1282,7 +1260,7 @@ void listener_loop(struct file_set *fset)
if (sent2socket <= 0) { //! Nothing was sent to the client so far and the command line is over. Let's return 1x1 pixel gif
out1x1gif();
} else if (sent2socket == 2) {
metaXML(fd_circ, 2); /// 0 - new (send headers), 1 - continue, 2 - finish
metaXML(fset, 2); /// 0 - new (send headers), 1 - continue, 2 - finish
}
fflush(stdout); // probably it is not needed anymore, just in case
......@@ -1341,8 +1319,11 @@ void init_file_set(struct file_set *fset, int fset_sz)
fset[i].circbuf_fd = -1;
fset[i].jphead_fn = jhead_fnames[i];
fset[i].jphead_fd = -1;
fset[i].exif_dev_name = exif_dev_names[i];
fset[i].exif_dev_fd = -1;
fset[i].exifmeta_dev_name = exifmeta_dev_names[i];
fset[i].exifmeta_dev_fd = -1;
fset[i].port_num = 0;
fset[i].sensor_num = i;
}
}
......@@ -1351,8 +1332,8 @@ int main(int argc, char *argv[])
{
int res = 0;
init_file_set(files, IMAGE_CHN_NUM);
res = parse_cmd_line(argc, (const char **)argv, files, IMAGE_CHN_NUM);
init_file_set(files, SENSOR_PORTS);
res = parse_cmd_line(argc, (const char **)argv, files, SENSOR_PORTS);
if (res < 0)
return EXIT_FAILURE;
......@@ -1363,7 +1344,7 @@ int main(int argc, char *argv[])
}
// spawn a process for each port
for (int i = 0; i < IMAGE_CHN_NUM; i++) {
for (int i = 0; i < SENSOR_PORTS; i++) {
if (fork() == 0) {
listener_loop(&files[i]);
_exit(0); // should not get here?
......
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