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
13e75796
Commit
13e75796
authored
May 26, 2016
by
Mikhail Karpenko
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Write markers in the start and end of each file
parent
173e7331
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
202 additions
and
45 deletions
+202
-45
camogm.c
camogm.c
+50
-1
camogm.h
camogm.h
+15
-1
camogm_jpeg.c
camogm_jpeg.c
+136
-42
camogm_jpeg.h
camogm_jpeg.h
+1
-1
No files found.
camogm.c
View file @
13e75796
...
@@ -113,6 +113,7 @@
...
@@ -113,6 +113,7 @@
#include <sys/socket.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <linux/limits.h>
#include <linux/limits.h>
#include <linux/fs.h>
//#include <ctype.h>
//#include <ctype.h>
//#include <getopt.h>
//#include <getopt.h>
#include <time.h>
#include <time.h>
...
@@ -230,6 +231,7 @@ void camogm_set_start_after_timestamp(camogm_state *state, double d);
...
@@ -230,6 +231,7 @@ void camogm_set_start_after_timestamp(camogm_state *state, double d);
void
camogm_set_max_frames
(
camogm_state
*
state
,
int
d
);
void
camogm_set_max_frames
(
camogm_state
*
state
,
int
d
);
void
camogm_set_frames_per_chunk
(
camogm_state
*
state
,
int
d
);
void
camogm_set_frames_per_chunk
(
camogm_state
*
state
,
int
d
);
uint64_t
get_disk_size
(
const
char
*
name
);
//!======================================================================================================
//!======================================================================================================
void
put_uint16
(
void
*
buf
,
u_int16_t
val
)
void
put_uint16
(
void
*
buf
,
u_int16_t
val
)
...
@@ -323,6 +325,11 @@ void camogm_init(camogm_state *state, unsigned int port, char *pipe_name)
...
@@ -323,6 +325,11 @@ void camogm_init(camogm_state *state, unsigned int port, char *pipe_name)
state
->
port_num
=
port
;
state
->
port_num
=
port
;
state
->
pipe_name
=
pipe_name
;
state
->
pipe_name
=
pipe_name
;
state
->
rawdev
.
start_pos
=
RAWDEV_START_OFFSET
;
state
->
rawdev
.
end_pos
=
state
->
rawdev
.
start_pos
;
state
->
rawdev
.
curr_pos
=
state
->
rawdev
.
start_pos
;
state
->
rawdev
.
overrun
=
0
;
state
->
rawdev_op
=
0
;
}
}
...
@@ -732,7 +739,7 @@ int camogm_stop(camogm_state *state)
...
@@ -732,7 +739,7 @@ int camogm_stop(camogm_state *state)
switch
(
state
->
format
)
{
switch
(
state
->
format
)
{
case
CAMOGM_FORMAT_NONE
:
rslt
=
0
;
break
;
case
CAMOGM_FORMAT_NONE
:
rslt
=
0
;
break
;
case
CAMOGM_FORMAT_OGM
:
rslt
=
camogm_end_ogm
(
state
);
break
;
case
CAMOGM_FORMAT_OGM
:
rslt
=
camogm_end_ogm
(
state
);
break
;
case
CAMOGM_FORMAT_JPEG
:
rslt
=
camogm_end_jpeg
();
break
;
case
CAMOGM_FORMAT_JPEG
:
rslt
=
camogm_end_jpeg
(
state
);
break
;
case
CAMOGM_FORMAT_MOV
:
rslt
=
camogm_end_mov
(
state
);
break
;
case
CAMOGM_FORMAT_MOV
:
rslt
=
camogm_end_mov
(
state
);
break
;
/// default: return 0; // do nothing
/// default: return 0; // do nothing
}
}
...
@@ -838,6 +845,23 @@ void camogm_set_prefix(camogm_state *state, const char * p)
...
@@ -838,6 +845,23 @@ void camogm_set_prefix(camogm_state *state, const char * p)
{
{
strncpy
(
state
->
path_prefix
,
p
,
sizeof
(
state
->
path_prefix
)
-
1
);
strncpy
(
state
->
path_prefix
,
p
,
sizeof
(
state
->
path_prefix
)
-
1
);
state
->
path_prefix
[
sizeof
(
state
->
path_prefix
)
-
1
]
=
'\0'
;
state
->
path_prefix
[
sizeof
(
state
->
path_prefix
)
-
1
]
=
'\0'
;
// check if we are going to write to raw device
if
(
strncmp
(
"/dev/"
,
state
->
path_prefix
,
5
)
==
0
)
{
state
->
rawdev
.
end_pos
=
get_disk_size
(
state
->
path_prefix
);
if
(
state
->
rawdev
.
end_pos
==
0
)
{
state
->
rawdev_op
=
0
;
state
->
rawdev
.
end_pos
=
state
->
rawdev
.
start_pos
;
state
->
path_prefix
[
0
]
=
'\0'
;
printf
(
"ERROR: unable to initiate raw device operation
\n
"
);
}
else
{
printf
(
"WARNING: raw device write initiated
\n
"
);
state
->
rawdev_op
=
1
;
/* debug code follows */
state
->
rawdev
.
end_pos
=
state
->
rawdev
.
start_pos
+
10485760
;
// 10Mib size
}
}
else
{
state
->
rawdev_op
=
0
;
}
}
}
void
camogm_set_timescale
(
camogm_state
*
state
,
double
d
)
//! set timescale, default=1,000,000
void
camogm_set_timescale
(
camogm_state
*
state
,
double
d
)
//! set timescale, default=1,000,000
...
@@ -1511,6 +1535,31 @@ int listener_loop(camogm_state *state)
...
@@ -1511,6 +1535,31 @@ int listener_loop(camogm_state *state)
return
EXIT_SUCCESS
;
return
EXIT_SUCCESS
;
}
}
/**
* @brief Return disk size in bytes
*
* This function reads disk size using ioctl call.
* @param name pointer to disk name string
* @return disk size in bytes if it was read correctly and 0 otherwise
*/
uint64_t
get_disk_size
(
const
char
*
name
)
{
int
fd
;
uint64_t
dev_sz
;
if
((
fd
=
open
(
name
,
O_RDONLY
))
<
0
)
{
perror
(
__func__
);
return
0
;
}
if
(
ioctl
(
fd
,
BLKGETSIZE64
,
&
dev_sz
)
<
0
)
{
perror
(
__func__
);
return
0
;
}
close
(
fd
);
return
dev_sz
;
}
int
main
(
int
argc
,
char
*
argv
[])
int
main
(
int
argc
,
char
*
argv
[])
{
{
const
char
usage
[]
=
"This program allows recording of the video/images acquired by Elphel camera to the storage media.
\n
"
\
const
char
usage
[]
=
"This program allows recording of the video/images acquired by Elphel camera to the storage media.
\n
"
\
...
...
camogm.h
View file @
13e75796
...
@@ -72,6 +72,18 @@
...
@@ -72,6 +72,18 @@
#define Exif_GPSInfo_CompassRoll_Index 0x10
#define Exif_GPSInfo_CompassRoll_Index 0x10
#define ExifKmlNumber 0x11
#define ExifKmlNumber 0x11
*/
*/
/** @brief Offset from the beginning of raw device buffer. Must be aligned to physical sector size */
#define RAWDEV_START_OFFSET 1024
typedef
struct
{
int
rawdev_fd
;
uint64_t
start_pos
;
uint64_t
end_pos
;
uint64_t
curr_pos
;
uint32_t
overrun
;
}
rawdev_buffer
;
typedef
struct
{
typedef
struct
{
int
segment_duration
;
int
segment_duration
;
int
segment_length
;
int
segment_length
;
...
@@ -158,8 +170,10 @@ typedef struct {
...
@@ -158,8 +170,10 @@ typedef struct {
int
kml_last_uts
;
//! last generated kml file timestamp, microseconds
int
kml_last_uts
;
//! last generated kml file timestamp, microseconds
struct
exif_dir_table_t
kml_exif
[
ExifKmlNumber
];
//! store locations of the fields needed for KML generations in the Exif block
struct
exif_dir_table_t
kml_exif
[
ExifKmlNumber
];
//! store locations of the fields needed for KML generations in the Exif block
unsigned
int
port_num
;
// sensor port this state assigned to
unsigned
int
port_num
;
// sensor port this state
is
assigned to
char
*
pipe_name
;
// command pipe name for this sensor port
char
*
pipe_name
;
// command pipe name for this sensor port
int
rawdev_op
;
// flag indicating writing to raw device
rawdev_buffer
rawdev
;
// contains pointers to raw device buffer
}
camogm_state
;
}
camogm_state
;
extern
int
debug_level
;
extern
int
debug_level
;
...
...
camogm_jpeg.c
View file @
13e75796
...
@@ -34,35 +34,54 @@
...
@@ -34,35 +34,54 @@
*! Initial release of camogm - program to record video/image to the camera hard drive (or other storage)
*! Initial release of camogm - program to record video/image to the camera hard drive (or other storage)
*!
*!
*/
*/
#define LARGEFILES64_SOURCE
//!Not all are needed, just copied from the camogm.c
//!Not all are needed, just copied from the camogm.c
#include <unistd.h>
#include <unistd.h>
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <signal.h>
//
#include <signal.h>
#include <fcntl.h>
#include <fcntl.h>
#include <sys/uio.h>
#include <sys/uio.h>
#include <errno.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/socket.h>
//
#include <sys/socket.h>
#include <sys/stat.h>
//
#include <sys/stat.h>
//#include <ctype.h>
//#include <ctype.h>
//#include <getopt.h>
//#include <getopt.h>
#include <time.h>
//
#include <time.h>
#include <string.h>
#include <string.h>
#include <netinet/in.h>
/*little <-> big endian ?*/
#include <netinet/in.h>
/*little <-> big endian ?*/
#include <sys/mman.h>
/* mmap */
//
#include <sys/mman.h> /* mmap */
#include <sys/ioctl.h>
//
#include <sys/ioctl.h>
#include <c313a.h>
#include <c313a.h>
#include <asm/byteorder.h>
#include <asm/byteorder.h>
#include <assert.h>
#include <ogg/ogg.h> // has to be before ogmstreams.h
#include <ogg/ogg.h> // has to be before ogmstreams.h
#include "ogmstreams.h" // move it to <>?
#include "ogmstreams.h" // move it to <>?
#include "camogm_jpeg.h"
#include "camogm_jpeg.h"
/** @brief Size of iovec structures holding data to be written */
#define IOVEC_SIZE 10
/** @brief Start of file marker, contains "elphelst" string in ASCII symbols */
const
unsigned
char
elphelst
[]
=
{
0x65
,
0x6c
,
0x70
,
0x68
,
0x65
,
0x6c
,
0x73
,
0x74
};
/** @brief End of file marker, contains "elphelen" string in ASCII symbols */
const
unsigned
char
elphelen
[]
=
{
0x65
,
0x6c
,
0x70
,
0x68
,
0x65
,
0x6c
,
0x65
,
0x6e
};
static
struct
iovec
start_marker
=
{
.
iov_base
=
elphelst
,
.
iov_len
=
sizeof
(
elphelst
)
};
static
struct
iovec
end_marker
=
{
.
iov_base
=
elphelen
,
.
iov_len
=
sizeof
(
elphelen
)
};
//! may add something - called first time format is changed to this one (only once) recording is stopped
//! may add something - called first time format is changed to this one (only once) recording is stopped
int
camogm_init_jpeg
(
void
)
int
camogm_init_jpeg
(
void
)
{
{
...
@@ -78,58 +97,133 @@ int camogm_start_jpeg(camogm_state *state)
...
@@ -78,58 +97,133 @@ int camogm_start_jpeg(camogm_state *state)
char
*
slash
;
char
*
slash
;
int
rslt
;
int
rslt
;
strcpy
(
state
->
path
,
state
->
path_prefix
);
//!make state->path a directory name (will be replaced when the frames will be written)
if
(
!
state
->
rawdev_op
)
{
slash
=
strrchr
(
state
->
path
,
'/'
);
strcpy
(
state
->
path
,
state
->
path_prefix
);
//!make state->path a directory name (will be replaced when the frames will be written)
D2
(
fprintf
(
debug_file
,
"camogm_start_jpeg
\n
"
));
slash
=
strrchr
(
state
->
path
,
'/'
);
if
(
slash
)
{
D2
(
fprintf
(
debug_file
,
"camogm_start_jpeg
\n
"
));
D3
(
fprintf
(
debug_file
,
"Full path %s
\n
"
,
state
->
path
));
if
(
slash
)
{
slash
[
0
]
=
'\0'
;
//! truncate path to the directory name
D3
(
fprintf
(
debug_file
,
"Full path %s
\n
"
,
state
->
path
));
D3
(
fprintf
(
debug_file
,
"directory path %s
\n
"
,
state
->
path
));
slash
[
0
]
=
'\0'
;
//! truncate path to the directory name
rslt
=
mkdir
(
state
->
path
,
0777
);
D3
(
fprintf
(
debug_file
,
"directory path %s
\n
"
,
state
->
path
));
D3
(
fprintf
(
debug_file
,
"mkdir (%s, 0777) returned %d, errno=%d
\n
"
,
state
->
path
,
rslt
,
errno
));
rslt
=
mkdir
(
state
->
path
,
0777
);
if
((
rslt
<
0
)
&&
(
errno
!=
EEXIST
))
{
// already exists is OK
D3
(
fprintf
(
debug_file
,
"mkdir (%s, 0777) returned %d, errno=%d
\n
"
,
state
->
path
,
rslt
,
errno
));
D0
(
fprintf
(
debug_file
,
"Error creating directory %s, errno=%d
\n
"
,
state
->
path
,
errno
));
if
((
rslt
<
0
)
&&
(
errno
!=
EEXIST
))
{
// already exists is OK
D0
(
fprintf
(
debug_file
,
"Error creating directory %s, errno=%d
\n
"
,
state
->
path
,
errno
));
return
-
CAMOGM_FRAME_FILE_ERR
;
}
}
}
else
{
state
->
ivf
=
open
(
state
->
path_prefix
,
O_RDWR
);
if
(
state
->
ivf
<
0
)
{
D0
(
perror
(
__func__
));
D0
(
fprintf
(
debug_file
,
"Error opening raw device %s
\n
"
,
state
->
path
));
return
-
CAMOGM_FRAME_FILE_ERR
;
return
-
CAMOGM_FRAME_FILE_ERR
;
}
}
D0
(
fprintf
(
debug_file
,
"Open raw device %s; start_pos = %llu, end_pos = %llu, curr_pos = %llu
\n
"
,
state
->
path
,
state
->
rawdev
.
start_pos
,
state
->
rawdev
.
end_pos
,
state
->
rawdev
.
curr_pos
));
lseek64
(
state
->
ivf
,
state
->
rawdev
.
curr_pos
,
SEEK_SET
);
}
}
return
0
;
return
0
;
}
}
int
camogm_frame_jpeg
(
camogm_state
*
state
)
int
camogm_frame_jpeg
(
camogm_state
*
state
)
{
{
int
i
,
j
;
int
i
,
j
,
split_index
;
// int fd
;
int
chunks_used
=
state
->
chunk_index
-
1
;
ssize_t
iovlen
,
l
;
ssize_t
iovlen
,
l
;
struct
iovec
chunks_iovec
[
7
];
struct
iovec
chunks_iovec
[
8
];
unsigned
char
*
split_ptr
=
NULL
;
long
split_cntr
;
long
total_len
;
const
uint64_t
storage_sz
=
state
->
rawdev
.
end_pos
-
state
->
rawdev
.
start_pos
;
l
=
0
;
if
(
!
state
->
rawdev_op
)
{
for
(
i
=
0
;
i
<
(
state
->
chunk_index
)
-
1
;
i
++
)
{
l
=
0
;
chunks_iovec
[
i
].
iov_base
=
state
->
packetchunks
[
i
+
1
].
chunk
;
for
(
i
=
0
;
i
<
(
state
->
chunk_index
)
-
1
;
i
++
)
{
chunks_iovec
[
i
].
iov_len
=
state
->
packetchunks
[
i
+
1
].
bytes
;
chunks_iovec
[
i
].
iov_base
=
state
->
packetchunks
[
i
+
1
].
chunk
;
l
+=
chunks_iovec
[
i
].
iov_len
;
chunks_iovec
[
i
].
iov_len
=
state
->
packetchunks
[
i
+
1
].
bytes
;
}
l
+=
chunks_iovec
[
i
].
iov_len
;
}
sprintf
(
state
->
path
,
"%s%010ld_%06ld.jpeg"
,
state
->
path_prefix
,
state
->
this_frame_params
.
timestamp_sec
,
state
->
this_frame_params
.
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
));
return
-
CAMOGM_FRAME_FILE_ERR
;
}
iovlen
=
writev
(
state
->
ivf
,
chunks_iovec
,
(
state
->
chunk_index
)
-
1
);
if
(
iovlen
<
l
)
{
j
=
errno
;
D0
(
fprintf
(
debug_file
,
"writev error %d (returned %d, expected %d)
\n
"
,
j
,
iovlen
,
l
));
close
(
state
->
ivf
);
return
-
CAMOGM_FRAME_FILE_ERR
;
}
close
(
state
->
ivf
);
}
else
{
D0
(
fprintf
(
debug_file
,
"
\n
%s: current pointers start_pos = %llu, end_pos = %llu, curr_pos = %llu, data in buffer %d
\n
"
,
__func__
,
state
->
rawdev
.
start_pos
,
state
->
rawdev
.
end_pos
,
state
->
rawdev
.
curr_pos
,
l
));
l
=
0
;
split_index
=
-
1
;
for
(
int
i
=
0
,
total_len
=
0
;
i
<
state
->
chunk_index
-
1
;
i
++
)
{
total_len
+=
state
->
packetchunks
[
i
+
1
].
bytes
;
if
(
total_len
+
state
->
rawdev
.
curr_pos
>
state
->
rawdev
.
end_pos
)
{
split_index
=
i
;
chunks_used
++
;
D0
(
fprintf
(
debug_file
,
"
\n
>>> raw storage roll over detected
\n
"
));
break
;
}
}
chunks_iovec
[
0
]
=
start_marker
;
for
(
int
i
=
1
;
i
<
chunks_used
;
i
++
)
{
if
(
i
==
split_index
)
{
// one of the chunks rolls over the end of the raw storage, split it into two segments and
// use additional chunk in chunks_iovec for this additional segment
split_cntr
=
state
->
rawdev
.
end_pos
-
(
l
+
state
->
rawdev
.
curr_pos
);
split_ptr
=
state
->
packetchunks
[
i
].
chunk
+
split_cntr
;
sprintf
(
state
->
path
,
"%s%010ld_%06ld.jpeg"
,
state
->
path_prefix
,
state
->
this_frame_params
.
timestamp_sec
,
state
->
this_frame_params
.
timestamp_usec
);
// be careful with indexes here
// if ((devfd = open("/dev/fpgaio", O_RDWR))<0) {printf("error opening /dev/fpgaio\r\n"); return -1;}
chunks_iovec
[
i
].
iov_base
=
state
->
packetchunks
[
i
].
chunk
;
//_1__12_Error opening /tmp/z/video1195147018_273452.jpeg for writing
chunks_iovec
[
i
].
iov_len
=
split_cntr
;
l
+=
chunks_iovec
[
i
].
iov_len
;
chunks_iovec
[
++
i
].
iov_base
=
split_ptr
+
1
;
chunks_iovec
[
i
].
iov_len
=
state
->
packetchunks
[
i
].
bytes
-
split_cntr
;
l
+=
chunks_iovec
[
i
].
iov_len
;
}
else
{
chunks_iovec
[
i
].
iov_base
=
state
->
packetchunks
[
i
].
chunk
;
chunks_iovec
[
i
].
iov_len
=
state
->
packetchunks
[
i
].
bytes
;
l
+=
chunks_iovec
[
i
].
iov_len
;
}
}
assert
(
chunks_used
<
IOVEC_SIZE
);
// consider start_marker here and increment chunks_used
chunks_iovec
[
chunks_used
++
]
=
end_marker
;
if
(((
state
->
ivf
=
open
(
state
->
path
,
O_RDWR
|
O_CREAT
,
0777
)))
<
0
)
{
/* debug code follows */
D0
(
fprintf
(
debug_file
,
"Error opening %s for writing, returned %d, errno=%d
\n
"
,
state
->
path
,
state
->
ivf
,
errno
));
fprintf
(
debug_file
,
"
\n
=== raw device write, iovec dump ===
\n
"
);
return
-
CAMOGM_FRAME_FILE_ERR
;
fprintf
(
debug_file
,
"split_cntr = %ld; split_ptr = %p; split_index = %d
\n
"
,
split_cntr
,
split_ptr
,
split_index
);
}
for
(
int
i
=
0
;
i
<
chunks_used
;
i
++
)
{
fprintf
(
debug_file
,
"i = %d; iov_base = %p; iov_len = %u
\n
"
,
i
,
chunks_iovec
[
i
].
iov_base
,
chunks_iovec
[
i
].
iov_len
);
}
fprintf
(
debug_file
,
"total len = %d
\n
======
\n
"
,
l
);
/* end of debug code */
iovlen
=
writev
(
state
->
ivf
,
chunks_iovec
,
(
state
->
chunk_index
)
-
1
);
iovlen
=
writev
(
state
->
ivf
,
chunks_iovec
,
chunks_used
);
if
(
iovlen
<
l
)
{
if
(
iovlen
<
l
)
{
j
=
errno
;
j
=
errno
;
D0
(
fprintf
(
debug_file
,
"writev error %d (returned %d, expected %d)
\n
"
,
j
,
iovlen
,
l
));
D0
(
fprintf
(
debug_file
,
"writev error %d (returned %d, expected %d)
\n
"
,
j
,
iovlen
,
l
));
close
(
state
->
ivf
);
return
-
CAMOGM_FRAME_FILE_ERR
;
return
-
CAMOGM_FRAME_FILE_ERR
;
}
state
->
rawdev
.
curr_pos
+=
l
;
if
(
state
->
rawdev
.
curr_pos
>
state
->
rawdev
.
end_pos
)
state
->
rawdev
.
curr_pos
=
state
->
rawdev
.
curr_pos
-
state
->
rawdev
.
end_pos
+
state
->
rawdev
.
start_pos
;
D0
(
fprintf
(
debug_file
,
"%d bytes written, curr_pos = %llu
\n
"
,
l
,
state
->
rawdev
.
curr_pos
));
}
}
close
(
state
->
ivf
);
return
0
;
return
0
;
}
}
int
camogm_end_jpeg
(
void
)
int
camogm_end_jpeg
(
camogm_state
*
state
)
{
{
close
(
state
->
ivf
);
D0
(
fprintf
(
debug_file
,
"Closing raw device %s
\n
"
,
state
->
path_prefix
));
return
0
;
return
0
;
}
}
camogm_jpeg.h
View file @
13e75796
...
@@ -6,7 +6,7 @@
...
@@ -6,7 +6,7 @@
int
camogm_init_jpeg
(
void
);
int
camogm_init_jpeg
(
void
);
int
camogm_start_jpeg
(
camogm_state
*
state
);
int
camogm_start_jpeg
(
camogm_state
*
state
);
int
camogm_frame_jpeg
(
camogm_state
*
state
);
int
camogm_frame_jpeg
(
camogm_state
*
state
);
int
camogm_end_jpeg
(
void
);
int
camogm_end_jpeg
(
camogm_state
*
state
);
void
camogm_free_jpeg
(
void
);
void
camogm_free_jpeg
(
void
);
#endif
/* _CAMOGM_JPEG_H */
#endif
/* _CAMOGM_JPEG_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