Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
E
elphel-apps-camogm
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Elphel
elphel-apps-camogm
Commits
d28b8a87
Commit
d28b8a87
authored
Jun 23, 2016
by
Mikhail Karpenko
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Create JPEG file names from Exif data
parent
13e03a7d
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
387 additions
and
142 deletions
+387
-142
Doxyfile
Doxyfile
+1
-1
Makefile
Makefile
+2
-2
camogm.c
camogm.c
+8
-3
camogm.h
camogm.h
+23
-0
camogm_jpeg.c
camogm_jpeg.c
+19
-3
camogm_kml.c
camogm_kml.c
+3
-3
camogm_mov.c
camogm_mov.c
+3
-3
camogm_ogm.c
camogm_ogm.c
+3
-3
camogm_read.c
camogm_read.c
+301
-124
camogm_read.h
camogm_read.h
+24
-0
No files found.
Doxyfile
View file @
d28b8a87
...
...
@@ -714,7 +714,7 @@ WARNINGS = YES
# will automatically be disabled.
# The default value is: YES.
WARN_IF_UNDOCUMENTED =
YES
WARN_IF_UNDOCUMENTED =
NO
# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
# potential errors in the documentation, such as not documenting some parameters
...
...
Makefile
View file @
d28b8a87
...
...
@@ -17,9 +17,9 @@ PROGS = camogm
PHPFILES
=
camogmstate.php
SRCS
=
camogm.c camogm_ogm.c camogm_jpeg.c camogm_mov.c camogm_kml.c
SRCS
=
camogm.c camogm_ogm.c camogm_jpeg.c camogm_mov.c camogm_kml.c
camogm_read.c
OBJS
=
camogm.o camogm_ogm.o camogm_jpeg.o camogm_mov.o camogm_kml.o
OBJS
=
camogm.o camogm_ogm.o camogm_jpeg.o camogm_mov.o camogm_kml.o
camogm_read.o
CFLAGS
+=
-Wall
-I
$(ELPHEL_KERNEL_DIR)
/include/elphel
#CFLAGS += -Wall -I$(INCDIR) -I$(ELPHEL_KERNEL_DIR)/include/elphel
...
...
camogm.c
View file @
d28b8a87
...
...
@@ -123,16 +123,17 @@
#include <sys/mman.h>
/* mmap */
#include <sys/ioctl.h>
#include <c313a.h>
//
#include <c313a.h>
#include <exifa.h>
#include <asm/byteorder.h>
#include <ogg/ogg.h> // has to be before ogmstreams.h
#include "ogmstreams.h"
//
#include <ogg/ogg.h> // has to be before ogmstreams.h
//
#include "ogmstreams.h"
#include "camogm_ogm.h"
#include "camogm_jpeg.h"
#include "camogm_mov.h"
#include "camogm_kml.h"
#include "camogm_read.h"
#include "camogm.h"
#define COMMAND_LOOP_DELAY 500000 //0.5sec
...
...
@@ -1343,6 +1344,10 @@ int parse_cmd(camogm_state *state, FILE* npipe)
state
->
rawdev
.
rawdev_path
[
0
]
=
'\0'
;
}
return
28
;
}
else
if
(
strcmp
(
cmd
,
"rawdev_read"
)
==
0
)
{
if
(
state
->
rawdev_op
)
camogm_read
(
state
);
return
29
;
}
return
-
1
;
...
...
camogm.h
View file @
d28b8a87
...
...
@@ -32,6 +32,9 @@
//#include "camogm_exif.h"
#include <exifa.h>
#include <c313a.h>
#include <ogg/ogg.h> // has to be before ogmstreams.h
#include "ogmstreams.h" // move it to <>?
/*
...
...
@@ -78,6 +81,25 @@
/** @brief Maximum length of file or raw device path */
#define ELPHEL_PATH_MAX 300
/**
* @struct rawdev_buffer
* @brief Holds pointers related to raw device buffer operation
* @var rawdv_buffer::rawdev_fd
* File descriptor of open raw device
* @var rawdev_buffer::rawdev_path
* A string containing full path to raw device
* @var rawdev_buffer::overrun
* The number of times the buffer has overrun during current work session
* @var rawdev_buffer::start_pos
* The start position of raw device buffer
* @var rawdev_buffer::end_pos
* The end position of raw device buffer
* @var rawdev_buffer::curr_pos
* Current read position in raw device buffer
* @var rawdev_buffer::file_start
* Pointer to the beginning of current file. This pointer is set during raw device reading and
* updated every time new file is found.
*/
typedef
struct
{
int
rawdev_fd
;
char
rawdev_path
[
ELPHEL_PATH_MAX
];
...
...
@@ -85,6 +107,7 @@ typedef struct {
uint64_t
start_pos
;
uint64_t
end_pos
;
uint64_t
curr_pos
;
uint64_t
file_start
;
}
rawdev_buffer
;
typedef
struct
{
...
...
camogm_jpeg.c
View file @
d28b8a87
...
...
@@ -57,11 +57,11 @@
//#include <sys/mman.h> /* mmap */
//#include <sys/ioctl.h>
#include <c313a.h>
//
#include <c313a.h>
#include <asm/byteorder.h>
#include <ogg/ogg.h> // has to be before ogmstreams.h
#include "ogmstreams.h" // move it to <>?
//
#include <ogg/ogg.h> // has to be before ogmstreams.h
//
#include "ogmstreams.h" // move it to <>?
#include "camogm_jpeg.h"
...
...
@@ -119,6 +119,17 @@ int camogm_start_jpeg(camogm_state *state)
return
0
;
}
void
dump_chunk
(
struct
iovec
*
vec
)
{
unsigned
char
*
ptr
=
vec
->
iov_base
;
for
(
int
i
=
0
;
i
<
vec
->
iov_len
;
i
++
)
{
printf
(
"0x%02x "
,
ptr
[
i
]);
if
(
i
%
15
==
0
)
printf
(
"
\n
"
);
}
}
/**
* @brief Write single JPEG frame
*
...
...
@@ -144,6 +155,11 @@ int camogm_frame_jpeg(camogm_state *state)
l
+=
chunks_iovec
[
i
].
iov_len
;
}
printf
(
"0 chunk dump:
\n
"
);
dump_chunk
(
&
chunks_iovec
[
0
]);
printf
(
"1 chunk dump
\n
"
);
dump_chunk
(
&
chunks_iovec
[
1
]);
sprintf
(
state
->
path
,
"%s%010ld_%06ld.jpeg"
,
state
->
path_prefix
,
state
->
this_frame_params
[
port
].
timestamp_sec
,
state
->
this_frame_params
[
port
].
timestamp_usec
);
if
(((
state
->
ivf
=
open
(
state
->
path
,
O_RDWR
|
O_CREAT
,
0777
)))
<
0
)
{
D0
(
fprintf
(
debug_file
,
"Error opening %s for writing, returned %d, errno=%d
\n
"
,
state
->
path
,
state
->
ivf
,
errno
));
...
...
camogm_kml.c
View file @
d28b8a87
...
...
@@ -55,12 +55,12 @@
#include <sys/mman.h>
/* mmap */
#include <sys/ioctl.h>
#include <c313a.h>
//
#include <c313a.h>
#include <asm/byteorder.h>
#include <ogg/ogg.h> // has to be before ogmstreams.h
#include "ogmstreams.h" // move it to <>?
//
#include <ogg/ogg.h> // has to be before ogmstreams.h
//
#include "ogmstreams.h" // move it to <>?
#include "camogm_kml.h"
...
...
camogm_mov.c
View file @
d28b8a87
...
...
@@ -58,12 +58,12 @@
#include <sys/mman.h>
/* mmap */
#include <sys/ioctl.h>
#include <c313a.h>
//
#include <c313a.h>
#include <asm/byteorder.h>
#include <ogg/ogg.h> // has to be before ogmstreams.h
#include "ogmstreams.h" // move it to <>?
//
#include <ogg/ogg.h> // has to be before ogmstreams.h
//
#include "ogmstreams.h" // move it to <>?
#include "camogm_mov.h"
...
...
camogm_ogm.c
View file @
d28b8a87
...
...
@@ -51,11 +51,11 @@
#include <sys/mman.h>
/* mmap */
#include <sys/ioctl.h>
#include <c313a.h>
//
#include <c313a.h>
#include <asm/byteorder.h>
#include <ogg/ogg.h> // has to be before ogmstreams.h
#include "ogmstreams.h" // move it to <>?
//
#include <ogg/ogg.h> // has to be before ogmstreams.h
//
#include "ogmstreams.h" // move it to <>?
#include "camogm_ogm.h"
...
...
camogm_read.c
View file @
d28b8a87
...
...
@@ -27,17 +27,25 @@
#include <string.h>
#include <linux/limits.h>
#include <netinet/in.h>
#include <errno.h>
#include <time.h>
#include <ctype.h>
#include <asm/byteorder.h>
#include "camogm.h"
#include "camogm
_read
.h"
/** @brief Offset in Exif where TIFF header starts */
#define TIFF_HDR_OFFSET 12
/** @brief Separator character between seconds and microseconds in JPEG file name */
#define SUBSEC_SEPARATOR '.'
/** @brief The size of read buffer in bytes. The data will be read from disk in blocks of this size */
#define PHY_BLK_SZ 4096
/** @brief Include or exclude file start and stop markers from resulting file. This must be set to 1 for JPEG files */
#define INCLUDE_MARKERS 1
/** @brief File starting marker on a raw device. It corresponds to SOI JPEG marker */
static
const
unsigned
char
elphelst
[]
=
{
0xff
,
0xd8
};
static
unsigned
char
elphelst
[]
=
{
0xff
,
0xd8
};
/** @brief File ending marker on a raw device. It corresponds to EOI JPEG marker */
static
const
unsigned
char
elphelen
[]
=
{
0xff
,
0xd9
};
static
unsigned
char
elphelen
[]
=
{
0xff
,
0xd9
};
static
const
struct
iovec
elphel_st
=
{
.
iov_base
=
elphelst
,
.
iov_len
=
sizeof
(
elphelst
)
...
...
@@ -104,6 +112,68 @@ enum file_ops {
WRITE_STOP
};
/**
* @brief Exif data format table.
*
* This table is used to convert Exif data format to its byte length and then calculate the length
* of a record in Image File Directory. The data format value 0 does not exist thus the first
* element of the array is 0 too which gives zero length field. Exif data format can one of the
* following:
* Value | Format | Bytes/Components
* ------|-------------------|-----------------
* 1 | unsigned byte | 1
* 2 | ascii string | 1
* 3 | unsigned short | 2
* 4 | unsigned long | 4
* 5 | unsigned rational | 8
* 6 | signed byte | 1
* 7 | undefined | 1
* 8 | signed short | 2
* 9 | signed long | 4
* 10 | signed rational | 8
* 11 | signed float | 4
* 12 | double float | 8
*/
const
unsigned
char
exif_data_fmt
[]
=
{
0
,
1
,
1
,
2
,
4
,
8
,
1
,
1
,
2
,
4
,
8
,
4
,
8
};
/**
* @struct ifd_entry
* @brief Represents a single Image File Directory record
* @var ifd_entry::tag
* Exif tag number
* @var ifd_entry::format
* Data format in the record
* @var ifd_entry::len
* The number of components in the record
* @var ifd_entry::offset
* The data value or offset to the data
*/
struct
ifd_entry
{
unsigned
short
tag
;
unsigned
short
format
;
unsigned
long
len
;
unsigned
long
offset
;
};
/**
* @struct tiff_hdr
* @brief TIFF header structure
* @var tiff_hdr::byte_order
* Motorola (MM) or Inter (II) byte order
* @var tiff_hdr::mark
* Tag mark
* @var tiff_hdr::offset
* Offset to first IFD
*/
struct
tiff_hdr
{
unsigned
short
byte_order
;
unsigned
short
mark
;
unsigned
long
offset
;
};
/**
* @struct file_opts
* @brief This structure holds data associated with currently opened file.
...
...
@@ -120,37 +190,9 @@ enum file_ops {
*/
struct
file_opts
{
FILE
*
fh
;
char
path_prefix
[
NAME_MAX
];
char
file_name
[
PATH_MAX
];
unsigned
int
file_cntr
;
int
file_state
;
};
/**
* @struct dev_opts
* @brief This structure holds data associated with raw storage device.
* @var dev_opts::dev_name
* Contains full path to raw storage device
* @var dev_opts::verbose
* Indicates vebosity level, just a flag as for now
* @var dev_opts::fd
* Contains file descriptor
* @var dev_opts::start_pos
* Contains start pointer for raw device storage, used when starting position does not coincide with
* the beginning of device file
* @var dev_opts::end_pos
* Contains end pointer for raw device storage, used when end position does not coincide with
* the end of device file
* @var dev_opts::curr_pos
* Contains current read pointer for raw device storage
*/
struct
dev_opts
{
char
dev_name
[
PATH_MAX
];
int
verbose
;
int
fd
;
uint64_t
start_pos
;
uint64_t
end_pos
;
uint64_t
curr_pos
;
camogm_state
*
state
;
};
/**
...
...
@@ -166,19 +208,6 @@ struct crb_ptrs {
struct
iovec
second_buff
;
};
void
print_array
(
const
struct
iovec
*
buff
)
{
const
int
spl
=
8
;
unsigned
char
*
a
=
buff
->
iov_base
;
for
(
int
i
=
0
;
i
<
buff
->
iov_len
;
i
++
)
{
if
(
i
%
spl
==
0
)
printf
(
"
\n
"
);
printf
(
"0x%02x "
,
a
[
i
]);
}
printf
(
"
\n
"
);
}
/**
* @brief Find pattern in a data buffer
*
...
...
@@ -190,7 +219,7 @@ void print_array(const struct iovec *buff)
* @param[in] pt_sz size of the pattern array
* @return the index in data buffer where pattern matches or error code from #match_result if it was not found
*/
int
find_marker
(
const
unsigned
char
*
restrict
buff_ptr
,
ssize_t
buff_sz
,
const
unsigned
char
*
restrict
pattern
,
ssize_t
pt_sz
)
static
int
find_marker
(
const
unsigned
char
*
restrict
buff_ptr
,
ssize_t
buff_sz
,
const
unsigned
char
*
restrict
pattern
,
ssize_t
pt_sz
)
{
int
ret
=
MATCH_NOT_FOUND
;
int
j
=
0
;
...
...
@@ -213,38 +242,191 @@ int find_marker(const unsigned char * restrict buff_ptr, ssize_t buff_sz, const
if
(
j
>
0
)
{
// partial match found in the end of data buffer, we need more data for further comparison
ret
=
MATCH_PARTIAL
;
fprintf
(
stderr
,
"Match partial; j = %d, loop conter = %d
\n
"
,
j
,
i
);
}
return
ret
;
}
/**
* @brief Converts byte order for all fields in #ifd_entry structure
* @param[in,out] ifd a pointer to a structure which should be converted
* @return None
*/
void
ifd_byte_order
(
struct
ifd_entry
*
ifd
)
{
unsigned
long
offset
;
ifd
->
tag
=
__be16_to_cpu
(
ifd
->
tag
);
ifd
->
format
=
__be16_to_cpu
(
ifd
->
format
);
ifd
->
len
=
__be32_to_cpu
(
ifd
->
len
);
ifd
->
offset
=
__be32_to_cpu
(
ifd
->
offset
);
if
(
exif_data_fmt
[
ifd
->
format
]
==
2
)
{
ifd
->
offset
=
(
ifd
->
offset
>>
16
)
&
0xffff
;
}
}
/**
* @brief Convert byte order for all fields in #tiff_hdr structure
* @param[in,out] ifd a pointer to a structure which should be converted
* @return None
*/
void
hdr_byte_order
(
struct
tiff_hdr
*
hdr
)
{
hdr
->
byte_order
=
__be16_to_cpu
(
hdr
->
byte_order
);
hdr
->
mark
=
__be16_to_cpu
(
hdr
->
mark
);
hdr
->
offset
=
__be32_to_cpu
(
hdr
->
offset
);
}
/**
* @brief Read a string from Exif for a given record. This function is intended for
* reading date and time from Exif and it omits any non-digit symbols from resulting string.
* Spaces and tabs are converted to underscores. Terminating null byte is not added to the resulting string.
* @param[in] state a pointer to a structure containing current state
* @param[in] ifd Exif image file directory record containing string offset
* @param[out] buff buffer for the string
* @return The number of bytes placed to the read buffer
*/
size_t
exif_get_text
(
camogm_state
*
state
,
struct
ifd_entry
*
ifd
,
unsigned
char
*
buff
)
{
size_t
j
=
0
;
size_t
sz
=
ifd
->
len
*
exif_data_fmt
[
ifd
->
format
];
uint64_t
curr_pos
=
state
->
rawdev
.
file_start
+
TIFF_HDR_OFFSET
+
ifd
->
offset
;
unsigned
char
read_buff
[
MAX_EXIF_SIZE
]
=
{
0
};
lseek64
(
state
->
rawdev
.
rawdev_fd
,
curr_pos
,
SEEK_SET
);
read
(
state
->
rawdev
.
rawdev_fd
,
read_buff
,
sz
);
for
(
int
i
=
0
;
i
<
sz
;
i
++
)
{
if
(
isdigit
(
read_buff
[
i
]))
buff
[
j
++
]
=
read_buff
[
i
];
else
if
(
isblank
(
read_buff
[
i
]))
buff
[
j
++
]
=
'_'
;
}
return
j
;
}
/**
* @brief Create JPEG file name from Exif data
*
* This function reads Exif data from file, extracts PageNumber, DateTimeOriginal and
* SubSecTimeOriginal fields and assembles a file name in the following format:
*
* NN_YYYYMMDD_HHMMSS.UUUUUU.jpeg
*
* where NN is PageNumber; YYYY, MM and DD are year, month and date extracted from DateTimeOriginal
* field; HH, MM and SS are hours, minutes and seconds extracted from DateTimeOriginal field; UUUUUU is us
* value extracted from SubSecTimeOriginal field. The function assumes that <e> name buffer is big enough
* to hold the file name in the format shown above including the terminating null byte.
* @param[in] state a pointer to a structure containing current state
* @param[out] name resulting file name
* @return 0 if file name was successfully created and negative value otherwise
*/
static
int
make_fname
(
camogm_state
*
state
,
char
*
name
)
{
int
process
=
2
;
size_t
sz
=
0
;
uint32_t
data32
;
uint16_t
num_entries
=
0
;
uint64_t
curr_pos
;
uint64_t
subifd_offset
=
0
;
struct
tiff_hdr
hdr
;
struct
ifd_entry
ifd
;
struct
ifd_entry
ifd_page_num
;
struct
ifd_entry
ifd_date_time
;
struct
ifd_entry
ifd_subsec
;
unsigned
char
read_buff
[
TIFF_HDR_OFFSET
]
=
{
0
};
uint64_t
save_pos
=
lseek64
(
state
->
rawdev
.
rawdev_fd
,
0
,
SEEK_CUR
);
if
(
name
==
NULL
)
return
-
1
;
curr_pos
=
state
->
rawdev
.
file_start
;
lseek64
(
state
->
rawdev
.
rawdev_fd
,
curr_pos
,
SEEK_SET
);
if
(
read
(
state
->
rawdev
.
rawdev_fd
,
read_buff
,
sizeof
(
read_buff
))
<=
0
)
{
lseek64
(
state
->
rawdev
.
rawdev_fd
,
save_pos
,
SEEK_SET
);
return
-
1
;
}
if
(
read_buff
[
2
]
==
0xff
&&
read_buff
[
3
]
==
0xe1
)
{
// get IFD0 offset from TIFF header
read
(
state
->
rawdev
.
rawdev_fd
,
&
hdr
,
sizeof
(
struct
tiff_hdr
));
hdr_byte_order
(
&
hdr
);
curr_pos
=
state
->
rawdev
.
file_start
+
TIFF_HDR_OFFSET
+
hdr
.
offset
;
lseek64
(
state
->
rawdev
.
rawdev_fd
,
curr_pos
,
SEEK_SET
);
// process IFD0 and SubIFD fields
do
{
read
(
state
->
rawdev
.
rawdev_fd
,
&
num_entries
,
sizeof
(
num_entries
));
num_entries
=
__be16_to_cpu
(
num_entries
);
for
(
int
i
=
0
;
i
<
num_entries
;
i
++
)
{
read
(
state
->
rawdev
.
rawdev_fd
,
&
ifd
,
sizeof
(
struct
ifd_entry
));
ifd_byte_order
(
&
ifd
);
switch
(
ifd
.
tag
)
{
case
Exif_Image_PageNumber
:
ifd_page_num
=
ifd
;
break
;
case
Exif_Photo_DateTimeOriginal
&
0xffff
:
ifd_date_time
=
ifd
;
break
;
case
Exif_Image_ExifTag
:
subifd_offset
=
ifd
.
offset
;
break
;
case
Exif_Photo_SubSecTimeOriginal
&
0xffff
:
ifd_subsec
=
ifd
;
break
;
}
}
// ensure that IFD0 finished correctly (0x00000000 in the end), set file pointer to SubIFD and
// process remaining fields
read
(
state
->
rawdev
.
rawdev_fd
,
&
data32
,
sizeof
(
data32
));
process
-=
(
subifd_offset
==
0
||
data32
!=
0
)
?
2
:
1
;
curr_pos
=
state
->
rawdev
.
file_start
+
TIFF_HDR_OFFSET
+
subifd_offset
;
lseek64
(
state
->
rawdev
.
rawdev_fd
,
curr_pos
,
SEEK_SET
);
}
while
(
process
>
0
);
// assemble file name from collected Exif fields
if
(
ifd_page_num
.
len
!=
0
)
{
sz
=
sprintf
(
name
,
"%02u_"
,
ifd_page_num
.
offset
);
}
if
(
ifd_date_time
.
len
!=
0
)
{
sz
+=
exif_get_text
(
state
,
&
ifd_date_time
,
name
+
sz
);
}
if
(
ifd_subsec
.
len
!=
0
)
{
name
[
sz
++
]
=
SUBSEC_SEPARATOR
;
sz
+=
exif_get_text
(
state
,
&
ifd_subsec
,
name
+
sz
);
}
sprintf
(
name
+
sz
,
".jpeg"
);
}
else
{
// a fallback option in case exif is not found - randomly generate file name
int
num
;
srand
(
time
(
NULL
));
num
=
rand
();
sprintf
(
name
,
"%010d.jpeg"
,
num
);
D3
(
fprintf
(
debug_file
,
"Exif marker is not found not found, using randomly generated file name: %s
\n
"
,
name
));
}
lseek64
(
state
->
rawdev
.
rawdev_fd
,
save_pos
,
SEEK_SET
);
return
0
;
}
/**
* @brief Create new file name string and open a file
* @param[in] f_op pointer to a structure holding information about currently opened file
* @return \e FILE_OK if file was successfully opened and \e FILE_OPEN_ERR otherwise
* @todo retrieve time stamp and use it in file name
*/
int
start_new_file
(
struct
file_opts
*
f_op
)
static
int
start_new_file
(
struct
file_opts
*
f_op
)
{
int
ret
;
static
int
name_ind
=
1
;
if
(
f_op
->
path_prefix
[
strlen
(
f_op
->
path_prefix
)
-
1
]
==
'/'
)
ret
=
sprintf
(
f_op
->
file_name
,
"%s%d.jpeg"
,
f_op
->
path_prefix
,
name_ind
);
else
ret
=
sprintf
(
f_op
->
file_name
,
"%s%c%d.jpeg"
,
f_op
->
path_prefix
,
'/'
,
name_ind
);
name_ind
++
;
if
(
ret
>
0
)
{
f_op
->
fh
=
fopen
(
f_op
->
file_name
,
"w"
);
if
(
f_op
->
fh
==
NULL
)
ret
=
FILE_OPEN_ERR
;
else
ret
=
FILE_OK
;
}
else
{
ret
=
FILE_OPEN_ERR
;
int
err
;
char
file_name
[
ELPHEL_PATH_MAX
]
=
{
0
};
make_fname
(
f_op
->
state
,
file_name
);
if
((
f_op
->
fh
=
fopen
(
file_name
,
"w"
))
==
NULL
)
{
err
=
errno
;
D0
(
fprintf
(
debug_file
,
"Error opening %s for writing
\n
"
,
file_name
));
D0
(
fprintf
(
debug_file
,
"%s
\n
"
,
strerror
(
err
)));
return
-
CAMOGM_FRAME_FILE_ERR
;
}
return
ret
;
return
FILE_OK
;
}
/**
...
...
@@ -257,7 +439,7 @@ int start_new_file(struct file_opts *f_op)
* @param[in] crbp pointer to a structure which will store two cross border pointers
* @return a constant of #match_result type
*/
int
check_edge_case
(
const
struct
iovec
*
from
,
const
struct
iovec
*
to
,
const
struct
iovec
*
marker
,
struct
crb_ptrs
*
crbp
)
static
int
check_edge_case
(
const
struct
iovec
*
from
,
const
struct
iovec
*
to
,
const
struct
iovec
*
marker
,
struct
crb_ptrs
*
crbp
)
{
unsigned
char
*
start_ptr
=
from
->
iov_base
+
from
->
iov_len
-
marker
->
iov_len
;
unsigned
char
*
end_ptr
=
from
->
iov_base
+
from
->
iov_len
;
...
...
@@ -285,8 +467,6 @@ int check_edge_case(const struct iovec *from, const struct iovec *to, const stru
return
MATCH_NOT_FOUND
;
}
fprintf
(
stderr
,
"First array checked, %d bytes of marker processed
\n
"
,
bytes_processed
);
// search for the second part of marker in the beginning of *to* array
start_ptr
=
to
->
iov_base
;
end_ptr
=
to
->
iov_base
+
(
marker
->
iov_len
-
bytes_processed
);
...
...
@@ -301,8 +481,6 @@ int check_edge_case(const struct iovec *from, const struct iovec *to, const stru
crbp
->
second_buff
.
iov_base
=
to
->
iov_base
;
crbp
->
second_buff
.
iov_len
=
marker
->
iov_len
-
bytes_processed
;
fprintf
(
stderr
,
"Second array checked, match found
\n
"
);
return
MATCH_FOUND
;
}
...
...
@@ -313,14 +491,13 @@ int check_edge_case(const struct iovec *from, const struct iovec *to, const stru
* @param[in] to end pointer to data buffer
* @return a constant of #file_result type
*/
int
write_buffer
(
struct
file_opts
*
f_op
,
unsigned
char
*
from
,
unsigned
char
*
to
)
static
int
write_buffer
(
struct
file_opts
*
f_op
,
unsigned
char
*
from
,
unsigned
char
*
to
)
{
int
ret
=
FILE_OK
;
int
len
;
unsigned
int
sz
;
sz
=
to
-
from
;
fprintf
(
stderr
,
"%s: sz = %d, file state = %d
\n
"
,
__func__
,
sz
,
f_op
->
file_state
);
switch
(
f_op
->
file_state
)
{
case
WRITE_RUNNING
:
len
=
fwrite
(
from
,
sz
,
1
,
f_op
->
fh
);
...
...
@@ -332,7 +509,6 @@ int write_buffer(struct file_opts *f_op, unsigned char *from, unsigned char *to)
case
WRITE_START
:
if
(
start_new_file
(
f_op
)
==
FILE_OK
)
{
len
=
fwrite
(
from
,
sz
,
1
,
f_op
->
fh
);
fprintf
(
stderr
,
"Starting new file %s
\n
"
,
f_op
->
file_name
);
if
(
len
!=
1
)
{
perror
(
__func__
);
ret
=
FILE_WR_ERR
;
...
...
@@ -362,42 +538,42 @@ int write_buffer(struct file_opts *f_op, unsigned char *from, unsigned char *to)
return
ret
;
}
/**
* @brief Extract JPEG files from raw device buffer
*
* Data from raw device is read to a buffer in #PHY_BLK_SZ blocks. The buffer is
* analyzed for JPEG markers and then the data from buffer is written to a file.
* @param[in] state a pointer to a structure containing current state
* @return 0 if files were extracted successfully and negative error code otherwise
*/
int
camogm_read
(
camogm_state
*
state
)
{
const
int
include_markers
=
INCLUDE_MARKERS
;
int
process
;
int
zero_cross
;
int
file_op
;
ssize_t
rd
;
int
err
;
int
pos_start
,
pos_stop
;
int
buff_processed
;
int
file_pos_saved
;
ssize_t
rd
;
unsigned
char
buff
[
PHY_BLK_SZ
];
unsigned
char
next_buff
[
PHY_BLK_SZ
];
struct
dev_opts
d_opts
;
unsigned
char
*
save_from
=
NULL
;
unsigned
char
*
save_to
=
NULL
;
struct
file_opts
f_opts
;
unsigned
char
*
save_from
;
unsigned
char
*
save_to
;
uint64_t
dev_curr_pos
=
0
;
uint64_t
include_st_marker
,
include_en_marker
;
d_opts
.
curr_pos
=
0
;
d_opts
.
verbose
=
0
;
f_opts
.
fh
=
NULL
;
f_opts
.
file_cntr
=
0
;
memset
(
&
f_opts
,
0
,
sizeof
(
struct
file_opts
));
f_opts
.
file_state
=
WRITE_STOP
;
if
(
parse_cmd_opts
(
argc
,
argv
,
&
f_opts
,
&
d_opts
)
<
0
)
{
print_help
();
return
EXIT_FAILURE
;
}
d_opts
.
fd
=
open
(
d_opts
.
dev_name
,
O_RDONLY
);
if
(
d_opts
.
fd
<
0
)
{
perror
(
"Can not open device: "
);
return
EXIT_FAILURE
;
}
f_opts
.
state
=
state
;
if
(
d_opts
.
verbose
)
{
printf
(
"Open block device %s
\n
"
,
d_opts
.
dev_name
);
printf
(
"Start reading from %lu to %lu
\n
"
,
d_opts
.
start_pos
,
d_opts
.
end_pos
);
state
->
rawdev
.
rawdev_fd
=
open
(
state
->
rawdev
.
rawdev_path
,
O_RDONLY
);
if
(
state
->
rawdev
.
rawdev_fd
<
0
)
{
D0
(
perror
(
__func__
));
D0
(
fprintf
(
debug_file
,
"Error opening raw device %s
\n
"
,
state
->
rawdev
.
rawdev_path
));
return
-
CAMOGM_FRAME_FILE_ERR
;
}
if
(
include_markers
)
{
...
...
@@ -407,45 +583,39 @@ int camogm_read(camogm_state *state)
include_st_marker
=
0
;
include_en_marker
=
0
;
}
process
=
1
;
zero_cross
=
0
;
file_op
=
FILE_OK
;
while
(
process
)
{
rd
=
read
(
d_opts
.
fd
,
buff
,
sizeof
(
buff
));
fprintf
(
stderr
,
"read %ld bytes from %lu to %lu
\n
"
,
rd
,
d_opts
.
curr_pos
,
d_opts
.
curr_pos
+
rd
)
;
if
((
rd
>
0
)
&&
(
d
_opts
.
curr_pos
+
rd
>
d_opts
.
end_pos
))
{
rd
=
read
(
state
->
rawdev
.
rawdev_
fd
,
buff
,
sizeof
(
buff
));
err
=
errno
;
if
((
rd
>
0
)
&&
(
d
ev_curr_pos
+
rd
>
state
->
rawdev
.
end_pos
))
{
// read pointer jumped over the raw storage buffer end, truncate excessive data
if
(
d_opts
.
verbose
)
{
fprintf
(
stderr
,
"End of raw storage buffer is reached, will start from beginning
\n
"
);
fprintf
(
stderr
,
"
\t
start_pos = %lu, curr_pos = %lu, end_pos = %lu
\n
"
,
d_opts
.
start_pos
,
d_opts
.
curr_pos
,
d_opts
.
end_pos
);
}
rd
=
d_opts
.
end_pos
-
d_opts
.
curr_pos
;
D3
(
fprintf
(
stderr
,
"End of raw storage buffer is reached, will start from the beginning
\n
"
));
rd
=
state
->
rawdev
.
end_pos
-
dev_curr_pos
;
zero_cross
=
1
;
lseek64
(
d_opts
.
fd
,
d_opts
.
start_pos
,
SEEK_SET
);
d
_opts
.
curr_pos
=
d_opts
.
start_pos
;
lseek64
(
state
->
rawdev
.
rawdev_fd
,
state
->
rawdev
.
start_pos
,
SEEK_SET
);
d
ev_curr_pos
=
state
->
rawdev
.
start_pos
;
if
(
rd
==
0
)
{
continue
;
}
}
else
if
(
rd
<
0
)
{
// read error or read pointer exceeded raw storage capacity, close files and terminate
process
=
0
;
if
(
d_opts
.
verbose
)
{
fprintf
(
stderr
,
"read() was unsuccessful:
\n
"
);
fprintf
(
stderr
,
"
\t
start_pos = %lu, curr_pos = %lu, end_pos = %lu
\n
"
,
d_opts
.
start_pos
,
d_opts
.
curr_pos
,
d_opts
.
end_pos
);
}
D0
(
fprintf
(
stderr
,
"Raw device read was unsuccessful: %s
\n
"
,
strerror
(
err
)));
}
else
if
(
rd
==
0
)
{
// end of device file reached
if
(
d_opts
.
verbose
)
{
fprintf
(
stderr
,
"End of raw storage device file is reached, will start from beginning
\n
"
);
}
D3
(
fprintf
(
stderr
,
"End of raw storage device file is reached, will start from the beginning
\n
"
));
zero_cross
=
1
;
lseek64
(
d_opts
.
fd
,
d_opts
.
start_pos
,
SEEK_SET
);
d
_opts
.
curr_pos
=
d_opts
.
start_pos
;
lseek64
(
state
->
rawdev
.
rawdev_fd
,
state
->
rawdev
.
start_pos
,
SEEK_SET
);
d
ev_curr_pos
=
state
->
rawdev
.
start_pos
;
}
if
(
process
)
{
save_from
=
buff
;
save_to
=
buff
+
rd
;
buff_processed
=
0
;
file_pos_saved
=
0
;
do
{
// process data in read buffer
fprintf
(
stderr
,
"Searching start marker from %p to %p
\n
"
,
save_from
,
save_to
);
...
...
@@ -467,6 +637,9 @@ int camogm_read(camogm_state *state)
f_opts
.
file_state
==
WRITE_STOP
)
{
// not writing, start marker found - start writing
f_opts
.
file_state
=
WRITE_START
;
if
(
file_pos_saved
==
0
)
state
->
rawdev
.
file_start
=
dev_curr_pos
+
pos_start
;
fprintf
(
stderr
,
"File start position: %llu
\n
"
,
state
->
rawdev
.
file_start
);
save_from
=
save_from
+
pos_start
+
elphel_st
.
iov_len
;
file_op
=
write_buffer
(
&
f_opts
,
save_from
-
include_st_marker
,
save_to
);
buff_processed
=
1
;
...
...
@@ -486,6 +659,8 @@ int camogm_read(camogm_state *state)
f_opts
.
file_state
==
WRITE_RUNNING
)
{
// writing in progress, start marker following stop marker found - this indicates a new file
f_opts
.
file_state
=
WRITE_STOP
;
state
->
rawdev
.
file_start
=
dev_curr_pos
+
pos_start
;
file_pos_saved
=
1
;
save_to
=
save_from
+
pos_stop
;
file_op
=
write_buffer
(
&
f_opts
,
save_from
,
save_to
+
include_en_marker
);
save_from
=
save_from
+
pos_start
;
...
...
@@ -507,15 +682,17 @@ int camogm_read(camogm_state *state)
.
iov_base
=
save_from
,
.
iov_len
=
save_to
-
save_from
};
ssize_t
next_rd
=
read
(
d_opts
.
fd
,
next_buff
,
sizeof
(
next_buff
));
fprintf
(
stderr
,
"process MATCH_PARTIAL pos_start: read %
l
d
\n
"
,
next_rd
);
ssize_t
next_rd
=
read
(
state
->
rawdev
.
rawdev_
fd
,
next_buff
,
sizeof
(
next_buff
));
fprintf
(
stderr
,
"process MATCH_PARTIAL pos_start: read %d
\n
"
,
next_rd
);
next_chunk
.
iov_len
=
next_rd
;
d
_opts
.
curr_pos
+=
next_rd
;
d
ev_
curr_pos
+=
next_rd
;
result
=
check_edge_case
(
&
curr_chunk
,
&
next_chunk
,
&
elphel_st
,
&
field_markers
);
fprintf
(
stderr
,
"process MATCH_PARTIAL: check edge case, result = %d
\n
"
,
result
);
if
(
result
==
MATCH_FOUND
&&
f_opts
.
file_state
==
WRITE_STOP
)
{
fprintf
(
stderr
,
"process MATCH_PARTIAL: match found
\n
"
);
f_opts
.
file_state
=
WRITE_START
;
state
->
rawdev
.
file_start
=
dev_curr_pos
+
pos_start
;
fprintf
(
stderr
,
"File start position: %llu
\n
"
,
state
->
rawdev
.
file_start
);
if
(
include_markers
)
{
unsigned
char
*
from
=
field_markers
.
first_buff
.
iov_base
;
unsigned
char
*
to
=
from
+
field_markers
.
first_buff
.
iov_len
;
...
...
@@ -545,10 +722,10 @@ int camogm_read(camogm_state *state)
.
iov_base
=
save_from
,
.
iov_len
=
save_to
-
save_from
};
ssize_t
next_rd
=
read
(
d_opts
.
fd
,
next_buff
,
sizeof
(
next_buff
));
ssize_t
next_rd
=
read
(
state
->
rawdev
.
rawdev_
fd
,
next_buff
,
sizeof
(
next_buff
));
fprintf
(
stderr
,
"process MATCH_PARTIAL pos_stop: read %ld
\n
"
,
next_rd
);
next_chunk
.
iov_len
=
next_rd
;
d
_opts
.
curr_pos
+=
next_rd
;
d
ev_
curr_pos
+=
next_rd
;
result
=
check_edge_case
(
&
curr_chunk
,
&
next_chunk
,
&
elphel_en
,
&
field_markers
);
fprintf
(
stderr
,
"process MATCH_PARTIAL: check edge case, result = %d
\n
"
,
result
);
if
(
result
==
MATCH_FOUND
)
{
...
...
@@ -585,20 +762,20 @@ int camogm_read(camogm_state *state)
if
(
file_op
!=
FILE_OK
)
{
process
=
0
;
}
d
_opts
.
curr_pos
+=
rd
;
d
ev_
curr_pos
+=
rd
;
}
}
fprintf
(
stderr
,
"
\n
%d files read from %s
\n
"
,
f_opts
.
file_cntr
,
d_opts
.
dev_name
);
fprintf
(
stderr
,
"
\n
%d files read from %s
\n
"
,
f_opts
.
file_cntr
,
state
->
rawdev
.
rawdev_path
);
if
(
close
(
d_opts
.
fd
)
!=
0
)
{
if
(
close
(
state
->
rawdev
.
rawdev_
fd
)
!=
0
)
{
perror
(
"Unable to close raw device: "
);
return
EXIT_FAILURE
;
return
-
CAMOGM_FRAME_FILE_ERR
;
}
if
(
f_opts
.
fh
!=
NULL
&&
fclose
(
f_opts
.
fh
)
!=
0
)
{
perror
(
"Unable to close data file: "
);
return
EXIT_FAILURE
;
return
-
CAMOGM_FRAME_FILE_ERR
;
}
return
EXIT_SUCCESS
;
return
0
;
}
camogm_read.h
0 → 100644
View file @
d28b8a87
/** @file camogm_read.h
* @brief Provides reading data written to raw device storage and saving the data to a device with file system.
* @copyright Copyright (C) 2016 Elphel, Inc.
*
* <b>License:</b>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _CAMOGM_READ_H
#define _CAMOGM_READ_H
#include "camogm.h"
int
camogm_read
(
camogm_state
*
state
);
#endif
/* _CAMOGM_READ_H */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment