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
86dd9391
Commit
86dd9391
authored
Mar 29, 2017
by
Mikhail Karpenko
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
WIP: Write aligned frames to block device
parent
d9fcca99
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
708 additions
and
53 deletions
+708
-53
Makefile
src/Makefile
+1
-1
camogm.c
src/camogm.c
+16
-12
camogm.h
src/camogm.h
+10
-1
camogm_align.c
src/camogm_align.c
+516
-0
camogm_align.h
src/camogm_align.h
+82
-0
camogm_jpeg.c
src/camogm_jpeg.c
+83
-39
No files found.
src/Makefile
View file @
86dd9391
...
@@ -11,7 +11,7 @@ IMAGES = $(GUIDIR)/images/filebrowser-01.gif $(GUIDIR)/images/filebrowser-bo
...
@@ -11,7 +11,7 @@ IMAGES = $(GUIDIR)/images/filebrowser-01.gif $(GUIDIR)/images/filebrowser-bo
$(GUIDIR)
/images/rec_folder.png
$(GUIDIR)
/images/up_folder.gif
$(GUIDIR)
/images/play_audio.png
$(GUIDIR)
/images/hdd.png
$(GUIDIR)
/images/rec_folder.png
$(GUIDIR)
/images/up_folder.gif
$(GUIDIR)
/images/play_audio.png
$(GUIDIR)
/images/hdd.png
SRCS
=
camogm.c camogm_ogm.c camogm_jpeg.c camogm_mov.c camogm_kml.c camogm_read.c index_list.c
SRCS
=
camogm.c camogm_ogm.c camogm_jpeg.c camogm_mov.c camogm_kml.c camogm_read.c index_list.c
camogm_align.c
TEST_SRC
=
camogm_test.c
TEST_SRC
=
camogm_test.c
OBJS
=
$
(
SRCS:.c
=
.o
)
OBJS
=
$
(
SRCS:.c
=
.o
)
...
...
src/camogm.c
View file @
86dd9391
...
@@ -514,8 +514,7 @@ int sendImageFrame(camogm_state *state)
...
@@ -514,8 +514,7 @@ int sendImageFrame(camogm_state *state)
int
port
=
state
->
port_num
;
int
port
=
state
->
port_num
;
struct
timeval
start_time
,
end_time
;
struct
timeval
start_time
,
end_time
;
D6
(
fprintf
(
debug_file
,
"last_error_code = %d
\n
"
,
state
->
last_error_code
));
// start_time = get_fpga_time(state->fd_fparmsall[port], port);
start_time
=
get_fpga_time
(
state
->
fd_fparmsall
[
port
],
port
);
// This is probably needed only for Quicktime (not to exceed already allocated frame index)
// This is probably needed only for Quicktime (not to exceed already allocated frame index)
if
(
!
state
->
rawdev_op
&&
(
state
->
frameno
>=
(
state
->
max_frames
)))
{
if
(
!
state
->
rawdev_op
&&
(
state
->
frameno
>=
(
state
->
max_frames
)))
{
...
@@ -646,12 +645,14 @@ int sendImageFrame(camogm_state *state)
...
@@ -646,12 +645,14 @@ int sendImageFrame(camogm_state *state)
/* 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 */
state
->
packetchunks
[
state
->
chunk_index
].
bytes
=
state
->
jpeg_len
-
(
state
->
circ_buff_size
[
port
]
-
state
->
cirbuf_rp
[
port
]);
state
->
packetchunks
[
state
->
chunk_index
].
bytes
=
state
->
jpeg_len
-
(
state
->
circ_buff_size
[
port
]
-
state
->
cirbuf_rp
[
port
]);
state
->
packetchunks
[
state
->
chunk_index
++
].
chunk
=
(
unsigned
char
*
)
&
ccam_dma_buf
[
state
->
port_num
][
0
];
state
->
packetchunks
[
state
->
chunk_index
++
].
chunk
=
(
unsigned
char
*
)
&
ccam_dma_buf
[
state
->
port_num
][
0
];
state
->
writer_params
.
segments
=
2
;
}
else
{
// single segment
}
else
{
// single segment
D3
(
fprintf
(
debug_file
,
"_11_"
));
D3
(
fprintf
(
debug_file
,
"_11_"
));
/* 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) */
state
->
packetchunks
[
state
->
chunk_index
].
bytes
=
state
->
jpeg_len
;
state
->
packetchunks
[
state
->
chunk_index
].
bytes
=
state
->
jpeg_len
;
state
->
packetchunks
[
state
->
chunk_index
++
].
chunk
=
(
unsigned
char
*
)
&
ccam_dma_buf
[
state
->
port_num
][
state
->
cirbuf_rp
[
port
]
>>
2
];
state
->
packetchunks
[
state
->
chunk_index
++
].
chunk
=
(
unsigned
char
*
)
&
ccam_dma_buf
[
state
->
port_num
][
state
->
cirbuf_rp
[
port
]
>>
2
];
state
->
writer_params
.
segments
=
1
;
}
}
D3
(
fprintf
(
debug_file
,
"
\t
cirbuf_rp = 0x%x
\t
"
,
state
->
cirbuf_rp
[
port
]));
D3
(
fprintf
(
debug_file
,
"
\t
cirbuf_rp = 0x%x
\t
"
,
state
->
cirbuf_rp
[
port
]));
D3
(
fprintf
(
debug_file
,
"_12_"
));
D3
(
fprintf
(
debug_file
,
"_12_"
));
...
@@ -687,16 +688,16 @@ int sendImageFrame(camogm_state *state)
...
@@ -687,16 +688,16 @@ int sendImageFrame(camogm_state *state)
}
}
D3
(
fprintf
(
debug_file
,
"cirbuf_rp to next frame = 0x%x
\n
"
,
state
->
cirbuf_rp
[
port
]));
D3
(
fprintf
(
debug_file
,
"cirbuf_rp to next frame = 0x%x
\n
"
,
state
->
cirbuf_rp
[
port
]));
end_time
=
get_fpga_time
(
state
->
fd_fparmsall
[
port
],
port
);
//
end_time = get_fpga_time(state->fd_fparmsall[port], port);
unsigned
int
mbps
;
// write speed, MB/s
//
unsigned int mbps; // write speed, MB/s
unsigned
long
long
time_diff
;
// time elapsed, in microseconds
//
unsigned long long time_diff; // time elapsed, in microseconds
time_diff
=
((
end_time
.
tv_sec
*
1000000
+
end_time
.
tv_usec
)
-
(
start_time
.
tv_sec
*
1000000
+
start_time
.
tv_usec
));
//
time_diff = ((end_time.tv_sec * 1000000 + end_time.tv_usec) - (start_time.tv_sec * 1000000 + start_time.tv_usec));
mbps
=
((
double
)
state
->
rawdev
.
last_jpeg_size
/
(
double
)
1048576
)
/
((
double
)
time_diff
/
(
double
)
1000000
);
//
mbps = ((double)state->rawdev.last_jpeg_size / (double)1048576) / ((double)time_diff / (double)1000000);
D6
(
fprintf
(
debug_file
,
"Frame start time: %ld:%ld; frame end time: %ld:%ld; last frame size: %lu
\n
"
,
//
D6(fprintf(debug_file, "Frame start time: %ld:%ld; frame end time: %ld:%ld; last frame size: %lu\n",
start_time
.
tv_sec
,
start_time
.
tv_usec
,
//
start_time.tv_sec, start_time.tv_usec,
end_time
.
tv_sec
,
end_time
.
tv_usec
,
//
end_time.tv_sec, end_time.tv_usec,
state
->
rawdev
.
last_jpeg_size
));
//
state->rawdev.last_jpeg_size));
D6
(
fprintf
(
debug_file
,
"Write speed: %d MB/s
\n
"
,
mbps
));
//
D6(fprintf(debug_file, "Write speed: %d MB/s\n", mbps));
return
0
;
return
0
;
}
}
...
@@ -880,6 +881,9 @@ void get_disk_info(camogm_state *state)
...
@@ -880,6 +881,9 @@ void get_disk_info(camogm_state *state)
}
}
if
(
get_disk_range
(
state
->
rawdev
.
rawdev_path
,
&
rng
)
==
0
)
{
if
(
get_disk_range
(
state
->
rawdev
.
rawdev_path
,
&
rng
)
==
0
)
{
state
->
writer_params
.
lba_start
=
rng
.
from
;
state
->
writer_params
.
lba_end
=
rng
.
to
;
state
->
writer_params
.
lba_current
=
state
->
writer_params
.
lba_start
;
set_disk_range
(
&
rng
);
set_disk_range
(
&
rng
);
}
else
{
}
else
{
D0
(
fprintf
(
debug_file
,
"ERROR: unable to get disk size and starting sector
\n
"
));
D0
(
fprintf
(
debug_file
,
"ERROR: unable to get disk size and starting sector
\n
"
));
...
...
src/camogm.h
View file @
86dd9391
...
@@ -27,7 +27,6 @@
...
@@ -27,7 +27,6 @@
#include <elphel/c313a.h>
#include <elphel/c313a.h>
#include <elphel/x393_devices.h>
#include <elphel/x393_devices.h>
#define CAMOGM_FRAME_NOT_READY 1 ///< frame pointer valid, but not yet acquired
#define CAMOGM_FRAME_NOT_READY 1 ///< frame pointer valid, but not yet acquired
#define CAMOGM_FRAME_INVALID 2 ///< invalid frame pointer
#define CAMOGM_FRAME_INVALID 2 ///< invalid frame pointer
#define CAMOGM_FRAME_CHANGED 3 ///< frame parameters have changed
#define CAMOGM_FRAME_CHANGED 3 ///< frame parameters have changed
...
@@ -150,6 +149,16 @@ struct writer_params {
...
@@ -150,6 +149,16 @@ struct writer_params {
int
last_ret_val
;
///< error value return during last frame recording (if any occurred)
int
last_ret_val
;
///< error value return during last frame recording (if any occurred)
bool
exit_thread
;
///< flag indicating that the writing thread should terminate
bool
exit_thread
;
///< flag indicating that the writing thread should terminate
int
state
;
///< the state of disk writing thread
int
state
;
///< the state of disk writing thread
int
segments
;
///< the number of segments in frame
struct
iovec
*
data_chunks
;
///< a set of vectors pointing to aligned frame data buffers
struct
iovec
prev_rem_vect
;
///< vector pointing to the remainder of the previous frame
unsigned
char
*
rem_buff
;
///< buffer containing the unaligned remainder of the current frame
unsigned
char
*
prev_rem_buff
;
///< buffer containing the unaligned remainder of the previous frame
unsigned
char
*
common_buff
;
///< buffer for aligned JPEG header
uint64_t
lba_start
;
///< disk starting LBA
uint64_t
lba_current
;
///< current write position in LBAs
uint64_t
lba_end
;
///< disk last LBA
};
};
/**
/**
* @struct camogm_state
* @struct camogm_state
...
...
src/camogm_align.c
0 → 100644
View file @
86dd9391
/** @file camogm_align.c
* @brief Provides frame alignment functions use for recording to block device.
* @copyright Copyright (C) 2017 Elphel, Inc.
*
* @par <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/>.
*/
/** @brief This define is needed to use lseek64 and should be set before includes */
#define _LARGEFILE64_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/uio.h>
#include "camogm_align.h"
static
unsigned
char
app15
[
ALIGNMENT_SIZE
]
=
{
0xff
,
0xef
};
static
inline
size_t
get_size_from
(
const
struct
iovec
*
vects
,
int
index
,
size_t
offset
,
int
all
);
static
inline
size_t
align_bytes_num
(
size_t
data_len
,
size_t
align_len
);
static
inline
void
vectcpy
(
struct
iovec
*
dest
,
void
*
src
,
size_t
len
);
static
inline
void
vectshrink
(
struct
iovec
*
vec
,
size_t
len
);
static
inline
unsigned
char
*
vectrpos
(
struct
iovec
*
vec
,
size_t
offset
);
static
void
dev_dbg
(
const
char
*
prefix
,
const
char
*
format
,
...);
static
void
remap_vectors
(
camogm_state
*
state
,
struct
iovec
*
chunks
);
static
size_t
get_blocks_num
(
struct
iovec
*
sgl
,
size_t
n_elem
);
/* debug functions */
static
int
check_chunks
(
struct
iovec
*
vects
);
/** Replace debug function with the same name from driver code with debug macro to reduce changes */
static
void
dev_dbg
(
const
char
*
prefix
,
const
char
*
format
,
...)
{
va_list
args
;
va_start
(
args
,
format
);
D6
(
vfprintf
(
debug_file
,
format
,
args
));
va_end
(
args
);
}
/** Copy @e len bytes from buffer pointed by @e src vector to buffer pointed by @e dest vector */
static
inline
void
vectcpy
(
struct
iovec
*
dest
,
void
*
src
,
size_t
len
)
{
unsigned
char
*
d
=
(
unsigned
char
*
)
dest
->
iov_base
;
memcpy
(
d
+
dest
->
iov_len
,
src
,
len
);
dest
->
iov_len
+=
len
;
}
/** Shrink vector length by @len bytes */
static
inline
void
vectshrink
(
struct
iovec
*
vec
,
size_t
len
)
{
if
(
vec
->
iov_len
>=
len
)
{
vec
->
iov_len
-=
len
;
}
}
/** This helper function is used to position a pointer @e offset bytes from the end
* of a buffer. */
static
inline
unsigned
char
*
vectrpos
(
struct
iovec
*
vec
,
size_t
offset
)
{
return
(
unsigned
char
*
)
vec
->
iov_base
+
(
vec
->
iov_len
-
offset
);
}
/** Calculate the size of current frame in bytes starting from vector and offset given */
static
inline
size_t
get_size_from
(
const
struct
iovec
*
vects
,
int
index
,
size_t
offset
,
int
all
)
{
int
i
;
size_t
total
=
0
;
if
(
index
>=
MAX_DATA_CHUNKS
||
offset
>
vects
[
index
].
iov_len
)
{
return
0
;
}
for
(
i
=
index
;
i
<
MAX_DATA_CHUNKS
;
i
++
)
{
if
(
i
==
CHUNK_REM
&&
all
==
EXCLUDE_REM
)
/* remainder should not be processed */
continue
;
if
(
i
==
index
)
total
+=
vects
[
i
].
iov_len
-
offset
;
else
total
+=
vects
[
i
].
iov_len
;
}
return
total
;
}
/** Return the number of bytes needed to align @e data_len to @e align_len boundary */
static
inline
size_t
align_bytes_num
(
size_t
data_len
,
size_t
align_len
)
{
size_t
rem
=
data_len
%
align_len
;
if
(
rem
==
0
)
return
0
;
else
return
align_len
-
rem
;
}
static
void
remap_vectors
(
camogm_state
*
state
,
struct
iovec
*
chunks
)
{
int
chunk_index
=
1
;
if
(
state
->
exif
>
0
)
{
chunks
[
CHUNK_LEADER
].
iov_base
=
(
void
*
)
state
->
packetchunks
[
chunk_index
].
chunk
;
chunks
[
CHUNK_LEADER
].
iov_len
=
state
->
packetchunks
[
chunk_index
++
].
bytes
;
chunks
[
CHUNK_EXIF
].
iov_base
=
(
void
*
)
state
->
packetchunks
[
chunk_index
].
chunk
;
chunks
[
CHUNK_EXIF
].
iov_len
=
state
->
packetchunks
[
chunk_index
++
].
bytes
;
chunks
[
CHUNK_HEADER
].
iov_base
=
(
void
*
)
state
->
packetchunks
[
chunk_index
].
chunk
;
chunks
[
CHUNK_HEADER
].
iov_len
=
state
->
packetchunks
[
chunk_index
++
].
bytes
;
}
else
{
chunks
[
CHUNK_LEADER
].
iov_base
=
(
void
*
)
state
->
packetchunks
[
chunk_index
].
chunk
;
chunks
[
CHUNK_LEADER
].
iov_len
=
JPEG_MARKER_LEN
;
chunks
[
CHUNK_HEADER
].
iov_base
=
(
void
*
)(
state
->
packetchunks
[
chunk_index
].
chunk
+
JPEG_MARKER_LEN
);
chunks
[
CHUNK_HEADER
].
iov_len
=
state
->
packetchunks
[
chunk_index
++
].
bytes
-
JPEG_MARKER_LEN
;
}
chunks
[
CHUNK_DATA_0
].
iov_base
=
(
void
*
)
state
->
packetchunks
[
chunk_index
].
chunk
;
chunks
[
CHUNK_DATA_0
].
iov_len
=
state
->
packetchunks
[
chunk_index
++
].
bytes
;
if
(
state
->
writer_params
.
segments
==
2
)
{
chunks
[
CHUNK_DATA_0
].
iov_base
=
(
void
*
)
state
->
packetchunks
[
chunk_index
].
chunk
;
chunks
[
CHUNK_DATA_0
].
iov_len
=
state
->
packetchunks
[
chunk_index
++
].
bytes
;
}
chunks
[
CHUNK_TRAILER
].
iov_base
=
(
void
*
)
state
->
packetchunks
[
chunk_index
].
chunk
;
chunks
[
CHUNK_TRAILER
].
iov_len
=
state
->
packetchunks
[
chunk_index
].
bytes
;
/* some data may be left from previous frame, copy it to special buffer */
if
(
chunks
[
CHUNK_REM
].
iov_len
!=
0
)
{
vectcpy
(
&
state
->
writer_params
.
prev_rem_vect
,
chunks
[
CHUNK_REM
].
iov_base
,
chunks
[
CHUNK_REM
].
iov_len
);
vectshrink
(
&
chunks
[
CHUNK_REM
],
chunks
[
CHUNK_REM
].
iov_len
);
}
}
/** Debug function, checks frame alignment */
static
int
check_chunks
(
struct
iovec
*
vects
)
{
int
i
;
int
ret
=
0
;
size_t
sz
=
0
;
for
(
i
=
0
;
i
<
MAX_DATA_CHUNKS
;
i
++
)
{
if
(
i
!=
CHUNK_REM
)
{
sz
+=
vects
[
i
].
iov_len
;
if
((
vects
[
i
].
iov_len
%
ALIGNMENT_SIZE
)
!=
0
)
{
dev_dbg
(
NULL
,
"ERROR: unaligned write from slot %d, length %u
\n
"
,
i
,
vects
[
i
].
iov_len
);
ret
=
-
1
;
}
}
dev_dbg
(
NULL
,
"chunk[%d]: ptr = %p, size = %d
\n
"
,
i
,
vects
[
i
].
iov_base
,
vects
[
i
].
iov_len
);
}
if
((
sz
%
PHY_BLOCK_SIZE
)
!=
0
)
{
dev_dbg
(
NULL
,
"ERROR: total length of the transaction is not aligned to sector boundary, total length %u
\n
"
,
sz
);
ret
=
-
1
;
}
else
{
dev_dbg
(
NULL
,
"===== frame is OK =====
\n
"
);
}
return
ret
;
}
/** Calculate the number of blocks this frame will occupy. The frame must be aligned to block size */
static
size_t
get_blocks_num
(
struct
iovec
*
sgl
,
size_t
n_elem
)
{
int
num
;
size_t
total
=
0
;
for
(
num
=
0
;
num
<
n_elem
;
num
++
)
{
total
+=
sgl
[
num
].
iov_len
;
}
return
total
/
PHY_BLOCK_SIZE
;
}
int
init_align_buffers
(
camogm_state
*
state
)
{
state
->
writer_params
.
data_chunks
=
(
struct
iovec
*
)
malloc
(
MAX_DATA_CHUNKS
*
sizeof
(
struct
iovec
));
if
(
state
->
writer_params
.
data_chunks
==
NULL
)
{
return
-
1
;
}
state
->
writer_params
.
common_buff
=
(
unsigned
char
*
)
malloc
(
COMMON_BUFF_SZ
);
if
(
state
->
writer_params
.
common_buff
==
NULL
)
{
deinit_align_buffers
(
state
);
return
-
1
;
}
state
->
writer_params
.
rem_buff
=
(
unsigned
char
*
)
malloc
(
REM_BUFF_SZ
);
if
(
state
->
writer_params
.
rem_buff
==
NULL
)
{
deinit_align_buffers
(
state
);
return
-
1
;
}
state
->
writer_params
.
prev_rem_buff
=
(
unsigned
char
*
)
malloc
(
REM_BUFF_SZ
);
if
(
state
->
writer_params
.
prev_rem_buff
==
NULL
)
{
deinit_align_buffers
(
state
);
return
-
1
;
}
state
->
writer_params
.
data_chunks
[
CHUNK_COMMON
].
iov_base
=
(
void
*
)
state
->
writer_params
.
common_buff
;
state
->
writer_params
.
data_chunks
[
CHUNK_COMMON
].
iov_len
=
0
;
state
->
writer_params
.
data_chunks
[
CHUNK_REM
].
iov_base
=
(
void
*
)
state
->
writer_params
.
rem_buff
;
state
->
writer_params
.
data_chunks
[
CHUNK_REM
].
iov_len
=
0
;
state
->
writer_params
.
prev_rem_vect
.
iov_base
=
(
void
*
)
state
->
writer_params
.
prev_rem_buff
;
state
->
writer_params
.
prev_rem_vect
.
iov_len
=
0
;
return
0
;
}
void
deinit_align_buffers
(
camogm_state
*
state
)
{
struct
writer_params
*
params
=
&
state
->
writer_params
;
if
(
params
->
data_chunks
)
{
free
(
params
->
data_chunks
);
params
->
data_chunks
=
NULL
;
}
if
(
params
->
common_buff
)
{
free
(
params
->
common_buff
);
params
->
common_buff
=
NULL
;
}
if
(
params
->
rem_buff
)
{
free
(
params
->
rem_buff
);
params
->
rem_buff
=
NULL
;
}
if
(
params
->
prev_rem_buff
)
{
free
(
params
->
prev_rem_buff
);
params
->
prev_rem_buff
=
NULL
;
}
}
/** Align current frame to disk sector boundary and each individual buffer to #ALIGNMENT_SIZE boundary */
void
align_frame
(
camogm_state
*
state
)
{
const
char
*
dev
=
NULL
;
unsigned
char
*
src
;
size_t
len
,
total_sz
,
data_len
;
struct
iovec
*
chunks
=
state
->
writer_params
.
data_chunks
;
struct
iovec
*
cbuff
=
&
chunks
[
CHUNK_COMMON
];
struct
iovec
*
rbuff
=
&
state
->
writer_params
.
prev_rem_vect
;
remap_vectors
(
state
,
chunks
);
total_sz
=
get_size_from
(
chunks
,
0
,
0
,
INCLUDE_REM
)
+
rbuff
->
iov_len
;
if
(
total_sz
<
PHY_BLOCK_SIZE
)
{
/* the frame length is less than sector size, delay this frame */
if
(
rbuff
->
iov_len
!=
0
)
{
/* some data may be left from previous frame */
vectcpy
(
&
chunks
[
CHUNK_REM
],
rbuff
->
iov_base
,
rbuff
->
iov_len
);
vectshrink
(
rbuff
,
rbuff
->
iov_len
);
}
dev_dbg
(
dev
,
"frame size is less than sector size: %u bytes; delay recording
\n
"
,
total_sz
);
vectcpy
(
&
chunks
[
CHUNK_REM
],
chunks
[
CHUNK_LEADER
].
iov_base
,
chunks
[
CHUNK_LEADER
].
iov_len
);
vectshrink
(
&
chunks
[
CHUNK_LEADER
],
chunks
[
CHUNK_LEADER
].
iov_len
);
vectcpy
(
&
chunks
[
CHUNK_REM
],
chunks
[
CHUNK_EXIF
].
iov_base
,
chunks
[
CHUNK_EXIF
].
iov_len
);
vectshrink
(
&
chunks
[
CHUNK_EXIF
],
chunks
[
CHUNK_EXIF
].
iov_len
);
vectcpy
(
&
chunks
[
CHUNK_REM
],
chunks
[
CHUNK_HEADER
].
iov_base
,
chunks
[
CHUNK_HEADER
].
iov_len
);
vectshrink
(
&
chunks
[
CHUNK_HEADER
],
chunks
[
CHUNK_HEADER
].
iov_len
);
vectcpy
(
&
chunks
[
CHUNK_REM
],
chunks
[
CHUNK_DATA_0
].
iov_base
,
chunks
[
CHUNK_DATA_0
].
iov_len
);
vectshrink
(
&
chunks
[
CHUNK_DATA_0
],
chunks
[
CHUNK_DATA_0
].
iov_len
);
vectcpy
(
&
chunks
[
CHUNK_REM
],
chunks
[
CHUNK_DATA_1
].
iov_base
,
chunks
[
CHUNK_DATA_1
].
iov_len
);
vectshrink
(
&
chunks
[
CHUNK_DATA_1
],
chunks
[
CHUNK_DATA_1
].
iov_len
);
vectcpy
(
&
chunks
[
CHUNK_REM
],
chunks
[
CHUNK_TRAILER
].
iov_base
,
chunks
[
CHUNK_TRAILER
].
iov_len
);
vectshrink
(
&
chunks
[
CHUNK_TRAILER
],
chunks
[
CHUNK_TRAILER
].
iov_len
);
return
;
}
/* copy remainder of previous frame to the beginning of common buffer */
if
(
rbuff
->
iov_len
!=
0
)
{
len
=
rbuff
->
iov_len
;
dev_dbg
(
dev
,
"copy %u bytes from REM to common buffer
\n
"
,
len
);
vectcpy
(
cbuff
,
rbuff
->
iov_base
,
len
);
vectshrink
(
rbuff
,
rbuff
->
iov_len
);
}
/* copy JPEG marker */
len
=
chunks
[
CHUNK_LEADER
].
iov_len
;
vectcpy
(
cbuff
,
chunks
[
CHUNK_LEADER
].
iov_base
,
len
);
vectshrink
(
&
chunks
[
CHUNK_LEADER
],
chunks
[
CHUNK_LEADER
].
iov_len
);
/* copy Exif if present */
if
(
chunks
[
CHUNK_EXIF
].
iov_len
!=
0
)
{
len
=
chunks
[
CHUNK_EXIF
].
iov_len
;
dev_dbg
(
dev
,
"copy %u bytes from EXIF to common buffer
\n
"
,
len
);
vectcpy
(
cbuff
,
chunks
[
CHUNK_EXIF
].
iov_base
,
len
);
vectshrink
(
&
chunks
[
CHUNK_EXIF
],
chunks
[
CHUNK_EXIF
].
iov_len
);
}
/* align common buffer to ALIGNMENT boundary, APP15 marker should be placed before header data */
data_len
=
cbuff
->
iov_len
+
chunks
[
CHUNK_HEADER
].
iov_len
;
len
=
align_bytes_num
(
data_len
,
ALIGNMENT_SIZE
);
if
(
len
<
(
JPEG_MARKER_LEN
+
JPEG_SIZE_LEN
)
&&
len
!=
0
)
{
/* the number of bytes needed for alignment is less than the length of the marker itself, increase the number of stuffing bytes */
len
+=
ALIGNMENT_SIZE
;
}
dev_dbg
(
dev
,
"total number of stuffing bytes in APP15 marker: %u
\n
"
,
len
);
app15
[
3
]
=
len
-
JPEG_MARKER_LEN
;
vectcpy
(
cbuff
,
app15
,
len
);
/* copy JPEG header */
len
=
chunks
[
CHUNK_HEADER
].
iov_len
;
dev_dbg
(
dev
,
"copy %u bytes from HEADER to common buffer
\n
"
,
len
);
vectcpy
(
cbuff
,
chunks
[
CHUNK_HEADER
].
iov_base
,
len
);
vectshrink
(
&
chunks
[
CHUNK_HEADER
],
chunks
[
CHUNK_HEADER
].
iov_len
);
/* check if there is enough data to continue - JPEG data length can be too short */
len
=
get_size_from
(
chunks
,
CHUNK_DATA_0
,
0
,
EXCLUDE_REM
);
if
(
len
<
PHY_BLOCK_SIZE
)
{
size_t
num
=
align_bytes_num
(
cbuff
->
iov_len
,
PHY_BLOCK_SIZE
);
dev_dbg
(
dev
,
"jpeg data is too short, delay this frame
\n
"
);
if
(
len
>=
num
)
{
/* there is enough data to align common buffer to sector boundary */
if
(
num
>=
chunks
[
CHUNK_DATA_0
].
iov_len
)
{
vectcpy
(
cbuff
,
chunks
[
CHUNK_DATA_0
].
iov_base
,
chunks
[
CHUNK_DATA_0
].
iov_len
);
num
-=
chunks
[
CHUNK_DATA_0
].
iov_len
;
vectshrink
(
&
chunks
[
CHUNK_DATA_0
],
chunks
[
CHUNK_DATA_0
].
iov_len
);
}
else
{
src
=
vectrpos
(
&
chunks
[
CHUNK_DATA_0
],
num
);
vectcpy
(
cbuff
,
chunks
[
CHUNK_DATA_0
].
iov_base
,
num
);
vectshrink
(
&
chunks
[
CHUNK_DATA_0
],
num
);
num
=
0
;
}
if
(
num
>=
chunks
[
CHUNK_DATA_1
].
iov_len
)
{
vectcpy
(
cbuff
,
chunks
[
CHUNK_DATA_1
].
iov_base
,
chunks
[
CHUNK_DATA_1
].
iov_len
);
num
-=
chunks
[
CHUNK_DATA_1
].
iov_len
;
vectshrink
(
&
chunks
[
CHUNK_DATA_1
],
chunks
[
CHUNK_DATA_1
].
iov_len
);
}
else
{
src
=
vectrpos
(
&
chunks
[
CHUNK_DATA_1
],
num
);
vectcpy
(
cbuff
,
chunks
[
CHUNK_DATA_1
].
iov_base
,
num
);
vectshrink
(
&
chunks
[
CHUNK_DATA_1
],
num
);
num
=
0
;
}
if
(
num
>=
chunks
[
CHUNK_TRAILER
].
iov_len
)
{
vectcpy
(
cbuff
,
chunks
[
CHUNK_TRAILER
].
iov_base
,
chunks
[
CHUNK_TRAILER
].
iov_len
);
num
-=
chunks
[
CHUNK_TRAILER
].
iov_len
;
vectshrink
(
&
chunks
[
CHUNK_TRAILER
],
chunks
[
CHUNK_TRAILER
].
iov_len
);
}
else
{
src
=
vectrpos
(
&
chunks
[
CHUNK_TRAILER
],
num
);
vectcpy
(
cbuff
,
chunks
[
CHUNK_TRAILER
].
iov_base
,
num
);
vectshrink
(
&
chunks
[
CHUNK_TRAILER
],
num
);
num
=
0
;
}
}
else
{
/* there is not enough data to align common buffer to sector boundary, truncate common buffer */
data_len
=
cbuff
->
iov_len
%
PHY_BLOCK_SIZE
;
src
=
vectrpos
(
cbuff
,
data_len
);
vectcpy
(
&
chunks
[
CHUNK_REM
],
src
,
data_len
);
vectshrink
(
cbuff
,
data_len
);
}
vectcpy
(
&
chunks
[
CHUNK_REM
],
chunks
[
CHUNK_DATA_0
].
iov_base
,
chunks
[
CHUNK_DATA_0
].
iov_len
);
vectshrink
(
&
chunks
[
CHUNK_DATA_0
],
chunks
[
CHUNK_DATA_0
].
iov_len
);
vectcpy
(
&
chunks
[
CHUNK_REM
],
chunks
[
CHUNK_DATA_1
].
iov_base
,
chunks
[
CHUNK_DATA_1
].
iov_len
);
vectshrink
(
&
chunks
[
CHUNK_DATA_1
],
chunks
[
CHUNK_DATA_1
].
iov_len
);
vectcpy
(
&
chunks
[
CHUNK_REM
],
chunks
[
CHUNK_TRAILER
].
iov_base
,
chunks
[
CHUNK_TRAILER
].
iov_len
);
vectshrink
(
&
chunks
[
CHUNK_TRAILER
],
chunks
[
CHUNK_TRAILER
].
iov_len
);
return
;
}
/* align frame to sector size boundary; total size could have changed by the moment - recalculate */
total_sz
=
get_size_from
(
chunks
,
0
,
0
,
INCLUDE_REM
);
len
=
total_sz
%
PHY_BLOCK_SIZE
;
dev_dbg
(
dev
,
"number of bytes crossing sector boundary: %u
\n
"
,
len
);
if
(
len
!=
0
)
{
if
(
len
>=
(
chunks
[
CHUNK_DATA_1
].
iov_len
+
chunks
[
CHUNK_TRAILER
].
iov_len
))
{
/* current frame is not split or the second part of JPEG data is too short */
data_len
=
len
-
chunks
[
CHUNK_DATA_1
].
iov_len
-
chunks
[
CHUNK_TRAILER
].
iov_len
;
src
=
vectrpos
(
&
chunks
[
CHUNK_DATA_0
],
data_len
);
vectcpy
(
&
chunks
[
CHUNK_REM
],
src
,
data_len
);
vectshrink
(
&
chunks
[
CHUNK_DATA_0
],
data_len
);
vectcpy
(
&
chunks
[
CHUNK_REM
],
chunks
[
CHUNK_DATA_1
].
iov_base
,
chunks
[
CHUNK_DATA_1
].
iov_len
);
vectshrink
(
&
chunks
[
CHUNK_DATA_1
],
chunks
[
CHUNK_DATA_1
].
iov_len
);
vectcpy
(
&
chunks
[
CHUNK_REM
],
chunks
[
CHUNK_TRAILER
].
iov_base
,
chunks
[
CHUNK_TRAILER
].
iov_len
);
vectshrink
(
&
chunks
[
CHUNK_TRAILER
],
chunks
[
CHUNK_TRAILER
].
iov_len
);
}
else
if
(
len
>=
chunks
[
CHUNK_TRAILER
].
iov_len
)
{
/* there is enough data in second part to align the frame */
data_len
=
len
-
chunks
[
CHUNK_TRAILER
].
iov_len
;
src
=
vectrpos
(
&
chunks
[
CHUNK_DATA_1
],
data_len
);
vectcpy
(
&
chunks
[
CHUNK_REM
],
src
,
data_len
);
vectshrink
(
&
chunks
[
CHUNK_DATA_1
],
data_len
);
vectcpy
(
&
chunks
[
CHUNK_REM
],
chunks
[
CHUNK_TRAILER
].
iov_base
,
chunks
[
CHUNK_TRAILER
].
iov_len
);
vectshrink
(
&
chunks
[
CHUNK_TRAILER
],
chunks
[
CHUNK_TRAILER
].
iov_len
);
}
else
{
/* the trailing marker is split by sector boundary, copy (PHY_BLOCK_SIZE - 1) bytes from
* JPEG data block(s) to remainder buffer and then add trailing marker */
data_len
=
PHY_BLOCK_SIZE
-
(
chunks
[
CHUNK_TRAILER
].
iov_len
-
len
);
if
(
data_len
>=
chunks
[
CHUNK_DATA_1
].
iov_len
)
{
size_t
cut_len
=
data_len
-
chunks
[
CHUNK_DATA_1
].
iov_len
;
src
=
vectrpos
(
&
chunks
[
CHUNK_DATA_0
],
cut_len
);
vectcpy
(
&
chunks
[
CHUNK_REM
],
src
,
cut_len
);
vectshrink
(
&
chunks
[
CHUNK_DATA_0
],
cut_len
);
vectcpy
(
&
chunks
[
CHUNK_REM
],
chunks
[
CHUNK_DATA_1
].
iov_base
,
chunks
[
CHUNK_DATA_1
].
iov_len
);
vectshrink
(
&
chunks
[
CHUNK_DATA_1
],
chunks
[
CHUNK_DATA_1
].
iov_len
);
vectcpy
(
&
chunks
[
CHUNK_REM
],
chunks
[
CHUNK_TRAILER
].
iov_base
,
chunks
[
CHUNK_TRAILER
].
iov_len
);
vectshrink
(
&
chunks
[
CHUNK_TRAILER
],
chunks
[
CHUNK_TRAILER
].
iov_len
);
}
else
{
src
=
vectrpos
(
&
chunks
[
CHUNK_DATA_1
],
data_len
);
vectcpy
(
&
chunks
[
CHUNK_REM
],
src
,
data_len
);
vectshrink
(
&
chunks
[
CHUNK_DATA_1
],
data_len
);
vectcpy
(
&
chunks
[
CHUNK_REM
],
chunks
[
CHUNK_TRAILER
].
iov_base
,
chunks
[
CHUNK_TRAILER
].
iov_len
);
vectshrink
(
&
chunks
[
CHUNK_TRAILER
],
chunks
[
CHUNK_TRAILER
].
iov_len
);
}
}
}
else
{
/* the frame is aligned to sector boundary but some buffers may be not */
chunks
[
CHUNK_ALIGN
].
iov_base
=
vectrpos
(
cbuff
,
0
);
// chunks[CHUNK_ALIGN].iov_dma = cbuff->iov_dma + cbuff->iov_len;
chunks
[
CHUNK_ALIGN
].
iov_len
=
0
;
if
(
chunks
[
CHUNK_DATA_1
].
iov_len
==
0
)
{
data_len
=
chunks
[
CHUNK_DATA_0
].
iov_len
%
ALIGNMENT_SIZE
;
src
=
vectrpos
(
&
chunks
[
CHUNK_DATA_0
],
data_len
);
vectcpy
(
&
chunks
[
CHUNK_ALIGN
],
src
,
data_len
);
vectshrink
(
&
chunks
[
CHUNK_DATA_0
],
data_len
);
}
else
{
data_len
=
chunks
[
CHUNK_DATA_1
].
iov_len
%
ALIGNMENT_SIZE
;
src
=
vectrpos
(
&
chunks
[
CHUNK_DATA_1
],
data_len
);
vectcpy
(
&
chunks
[
CHUNK_ALIGN
],
src
,
data_len
);
vectshrink
(
&
chunks
[
CHUNK_DATA_1
],
data_len
);
}
vectcpy
(
&
chunks
[
CHUNK_ALIGN
],
chunks
[
CHUNK_TRAILER
].
iov_base
,
chunks
[
CHUNK_TRAILER
].
iov_len
);
vectshrink
(
&
chunks
[
CHUNK_TRAILER
],
chunks
[
CHUNK_TRAILER
].
iov_len
);
}
/* debug sanity check, should not happen */
if
(
cbuff
->
iov_len
>=
COMMON_BUFF_SZ
)
{
dev_dbg
(
NULL
,
"ERROR: the number of bytes copied to common buffer exceeds its size
\n
"
);
}
check_chunks
(
chunks
);
}
/** Discard buffer pointers which makes the command slot marked as empty */
void
reset_chunks
(
struct
iovec
*
vects
,
int
all
)
{
int
i
;
for
(
i
=
0
;
i
<
MAX_DATA_CHUNKS
;
i
++
)
{
if
(
i
!=
CHUNK_REM
)
vects
[
i
].
iov_len
=
0
;
}
if
(
all
)
{
vects
[
CHUNK_REM
].
iov_len
=
0
;
}
}
/** Calculate and update LBA offsets, do not count remainder buffer. Return 1 if file position should be reset to the start */
int
update_lba
(
camogm_state
*
state
)
{
int
ret
=
0
;
size_t
total_sz
;
struct
iovec
*
chunks
=
state
->
writer_params
.
data_chunks
;
total_sz
=
get_blocks_num
(
chunks
,
MAX_DATA_CHUNKS
-
1
);
if
(
state
->
writer_params
.
lba_current
+
total_sz
<=
state
->
writer_params
.
lba_end
)
{
state
->
writer_params
.
lba_current
+=
total_sz
;
}
else
{
state
->
writer_params
.
lba_current
=
state
->
writer_params
.
lba_start
;
ret
=
1
;
}
return
ret
;
}
/** Go through all data buffers and pick only mapped ones excluding remainder buffer */
int
get_data_buffers
(
camogm_state
*
state
,
struct
iovec
*
mapped
,
size_t
mapped_sz
)
{
int
ret
=
0
;
struct
iovec
*
all
=
state
->
writer_params
.
data_chunks
;
if
(
mapped_sz
<=
0
)
return
ret
;
for
(
int
i
=
0
,
j
=
0
;
i
<
MAX_DATA_CHUNKS
;
i
++
)
{
if
(
i
!=
CHUNK_REM
&&
all
[
i
].
iov_len
!=
0
)
{
if
(
j
<
mapped_sz
)
{
mapped
[
j
++
]
=
all
[
i
];
ret
=
j
;
}
else
{
ret
=
-
1
;
break
;
}
}
}
return
ret
;
}
/** Prepare the last remaining block of data for recording, return the number of bytes ready for recording */
int
prep_last_block
(
camogm_state
*
state
)
{
int
ret
=
0
;
size_t
stuff_len
;
unsigned
char
*
src
;
struct
iovec
*
cvect
=
&
state
->
writer_params
.
data_chunks
[
CHUNK_COMMON
];
struct
iovec
*
rvect
=
&
state
->
writer_params
.
data_chunks
[
CHUNK_REM
];
if
(
rvect
->
iov_len
!=
0
)
{
stuff_len
=
PHY_BLOCK_SIZE
-
rvect
->
iov_len
;
src
=
vectrpos
(
rvect
,
0
);
memset
(
src
,
0
,
stuff_len
);
rvect
->
iov_len
+=
stuff_len
;
ret
=
rvect
->
iov_len
;
vectcpy
(
cvect
,
rvect
->
iov_base
,
rvect
->
iov_len
);
vectshrink
(
rvect
,
rvect
->
iov_len
);
}
return
ret
;
}
off64_t
lba_to_offset
(
uint64_t
lba
)
{
return
lba
*
PHY_BLOCK_SIZE
;
}
src/camogm_align.h
0 → 100644
View file @
86dd9391
/** @file camogm_align.h
* @brief Provides frame alignment functions use for recording to block device.
* @copyright Copyright (C) 2017 Elphel, Inc.
*
* @par <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_ALIGN_H
#define _CAMOGM_ALIGN_H
#include <unistd.h>
#include <sys/types.h>
#include "camogm.h"
#define PHY_BLOCK_SIZE 512 ///< Physical disk block size
#define JPEG_MARKER_LEN 2 ///< The size in bytes of JPEG marker
#define JPEG_SIZE_LEN 2 ///< The size in bytes of JPEG marker length field
#define INCLUDE_REM 1 ///< Include REM buffer to total size calculation
#define EXCLUDE_REM 0 ///< Exclude REM buffer from total size calculation
#define MAX_DATA_CHUNKS 9 ///< An array or JPEG frame chunks contains pointers to JPEG leading marker,
///< JPEG header, Exif data if present, stuffing bytes chunk which aligns
///< the frame size to disk sector boundary, JPEG data which
///< can be split into two chunks, align buffers, JPEG
///< trailing marker, and pointer to a buffer containing the remainder of a
///< frame. Nine chunks of data in total.
#define ALIGNMENT_SIZE 32 ///< Align buffers length to this amount of bytes
/** Common buffer should be large enough to contain JPEG header, Exif, some alignment bytes and remainder from previous frame */
#define COMMON_BUFF_SZ MAX_EXIF_SIZE + JPEG_HEADER_MAXSIZE + ALIGNMENT_SIZE + 2 * PHY_BLOCK_SIZE
#define REM_BUFF_SZ 2 * PHY_BLOCK_SIZE
///** This structure holds raw device buffer pointers */
//struct drv_pointers {
// uint64_t lba_start; ///< raw buffer starting LBA
// uint64_t lba_end; ///< raw buffer ending LBA
// uint64_t lba_write; ///< current write pointer inside raw buffer
// uint16_t wr_count; ///< the number of LBA to write next time
//};
/** Container structure for frame buffers */
//struct frame_buffers {
// struct fvec exif_buff; ///< Exif buffer
// struct fvec jpheader_buff; ///< JPEG header buffer
// struct fvec trailer_buff; ///< buffer for trailing marker
// struct fvec common_buff; ///< common buffer where other parts are combined
// struct fvec rem_buff; ///< remainder from previous frame
//};
/** Symbolic names for slots in buffer pointers. Buffer alignment function relies on the order of these names, so
* new names can be added but the overall order should not be changed */
enum
{
CHUNK_LEADER
,
///< pointer to JPEG leading marker
CHUNK_EXIF
,
///< pointer to Exif buffer
CHUNK_HEADER
,
///< pointer to JPEG header data excluding leading marker
CHUNK_COMMON
,
///< pointer to common buffer
CHUNK_DATA_0
,
///< pointer to JPEG data
CHUNK_DATA_1
,
///< pointer to the second half of JPEG data if a frame crosses circbuf boundary
CHUNK_TRAILER
,
///< pointer to JPEG trailing marker
CHUNK_ALIGN
,
///< pointer to buffer where the second part of JPEG data should be aligned
CHUNK_REM
///< pointer to buffer containing the remainder of current frame. It will be recorded during next transaction
};
int
init_align_buffers
(
camogm_state
*
state
);
void
deinit_align_buffers
(
camogm_state
*
state
);
void
align_frame
(
camogm_state
*
state
);
void
reset_chunks
(
struct
iovec
*
vects
,
int
all
);
int
update_lba
(
camogm_state
*
state
);
int
get_data_buffers
(
camogm_state
*
state
,
struct
iovec
*
mapped
,
size_t
all_sz
);
int
prep_last_block
(
camogm_state
*
state
);
off64_t
lba_to_offset
(
uint64_t
lba
);
#endif
/* _CAMOGM_ALIGN_H */
src/camogm_jpeg.c
View file @
86dd9391
...
@@ -32,12 +32,15 @@
...
@@ -32,12 +32,15 @@
#include "camogm_jpeg.h"
#include "camogm_jpeg.h"
#include "camogm_read.h"
#include "camogm_read.h"
#include "camogm_align.h"
/** State file record format. It includes device path in /dev, starting, current and ending LBAs */
/** State file record format. It includes device path in /dev, starting, current and ending LBAs */
#define STATE_FILE_FORMAT "%s\t%llu\t%llu\t%llu\n"
#define STATE_FILE_FORMAT "%s\t%llu\t%llu\t%llu\n"
/* forward declarations */
/* forward declarations */
static
void
*
jpeg_writer
(
void
*
thread_args
);
static
void
*
jpeg_writer
(
void
*
thread_args
);
static
int
save_state_file
(
const
rawdev_buffer
*
rawdev
,
uint64_t
current_pos
);
static
int
open_state_file
(
const
rawdev_buffer
*
rawdev
,
uint64_t
*
current_pos
);
/** Get starting and endign LBAs of the partition specified as raw device buffer */
/** Get starting and endign LBAs of the partition specified as raw device buffer */
static
int
get_disk_range
(
struct
range
*
range
)
static
int
get_disk_range
(
struct
range
*
range
)
...
@@ -96,12 +99,12 @@ static int find_state(FILE *f, uint64_t *pos, const rawdev_buffer *rawdev)
...
@@ -96,12 +99,12 @@ static int find_state(FILE *f, uint64_t *pos, const rawdev_buffer *rawdev)
}
}
/** Read state from file and restore disk write pointer */
/** Read state from file and restore disk write pointer */
static
int
open_state_file
(
const
rawdev_buffer
*
rawdev
)
static
int
open_state_file
(
const
rawdev_buffer
*
rawdev
,
uint64_t
*
current_pos
)
{
{
int
fd
,
len
;
int
fd
,
len
;
FILE
*
f
;
FILE
*
f
;
int
ret
=
0
;
int
ret
=
0
;
uint64_t
curr
_pos
;
uint64_t
lba
_pos
;
char
buff
[
SMALL_BUFF_LEN
]
=
{
0
};
char
buff
[
SMALL_BUFF_LEN
]
=
{
0
};
if
(
strlen
(
rawdev
->
state_path
)
==
0
)
{
if
(
strlen
(
rawdev
->
state_path
)
==
0
)
{
...
@@ -110,15 +113,9 @@ static int open_state_file(const rawdev_buffer *rawdev)
...
@@ -110,15 +113,9 @@ static int open_state_file(const rawdev_buffer *rawdev)
f
=
fopen
(
rawdev
->
state_path
,
"r"
);
f
=
fopen
(
rawdev
->
state_path
,
"r"
);
if
(
f
!=
NULL
)
{
if
(
f
!=
NULL
)
{
if
(
find_state
(
f
,
&
curr_pos
,
rawdev
)
!=
-
1
)
{
if
(
find_state
(
f
,
&
lba_pos
,
rawdev
)
!=
-
1
)
{
fd
=
open
(
SYSFS_AHCI_LBA_CURRENT
,
O_WRONLY
);
*
current_pos
=
lba_pos
;
if
(
fd
>=
0
)
{
D0
(
fprintf
(
debug_file
,
"Got starting LBA from state file: %llu
\n
"
,
lba_pos
));
len
=
snprintf
(
buff
,
SMALL_BUFF_LEN
,
"%llu"
,
curr_pos
);
write
(
fd
,
buff
,
len
+
1
);
close
(
fd
);
}
else
{
ret
=
-
1
;
}
}
}
fclose
(
f
);
fclose
(
f
);
}
else
{
}
else
{
...
@@ -129,12 +126,11 @@ static int open_state_file(const rawdev_buffer *rawdev)
...
@@ -129,12 +126,11 @@ static int open_state_file(const rawdev_buffer *rawdev)
}
}
/** Save current position of the disk write pointer */
/** Save current position of the disk write pointer */
static
int
save_state_file
(
const
rawdev_buffer
*
rawdev
)
static
int
save_state_file
(
const
rawdev_buffer
*
rawdev
,
uint64_t
current_pos
)
{
{
int
ret
=
0
;
int
ret
=
0
;
FILE
*
f
;
FILE
*
f
;
struct
range
range
;
struct
range
range
;
uint64_t
curr_pos
;
if
(
strlen
(
rawdev
->
state_path
)
==
0
)
{
if
(
strlen
(
rawdev
->
state_path
)
==
0
)
{
return
ret
;
return
ret
;
...
@@ -143,21 +139,13 @@ static int save_state_file(const rawdev_buffer *rawdev)
...
@@ -143,21 +139,13 @@ static int save_state_file(const rawdev_buffer *rawdev)
return
-
1
;
return
-
1
;
}
}
// get raw device buffer current postion on disk, this position indicates where recording has stopped
f
=
fopen
(
SYSFS_AHCI_LBA_CURRENT
,
"r"
);
if
(
f
==
NULL
)
{
return
-
1
;
}
fscanf
(
f
,
"%llu
\n
"
,
&
curr_pos
);
fclose
(
f
);
// save pointers to a regular file
// save pointers to a regular file
f
=
fopen
(
rawdev
->
state_path
,
"w"
);
f
=
fopen
(
rawdev
->
state_path
,
"w"
);
if
(
f
==
NULL
)
{
if
(
f
==
NULL
)
{
return
-
1
;
return
-
1
;
}
}
fprintf
(
f
,
"Device
\t\t
Start LBA
\t
Current LBA
\t
End LBA
\n
"
);
fprintf
(
f
,
"Device
\t\t
Start LBA
\t
Current LBA
\t
End LBA
\n
"
);
fprintf
(
f
,
STATE_FILE_FORMAT
,
rawdev
->
rawdev_path
,
range
.
from
,
curr_pos
,
range
.
to
);
fprintf
(
f
,
STATE_FILE_FORMAT
,
rawdev
->
rawdev_path
,
range
.
from
,
curr
ent
_pos
,
range
.
to
);
fflush
(
f
);
fflush
(
f
);
fsync
(
fileno
(
f
));
fsync
(
fileno
(
f
));
fclose
(
f
);
fclose
(
f
);
...
@@ -198,6 +186,12 @@ int camogm_init_jpeg(camogm_state *state)
...
@@ -198,6 +186,12 @@ int camogm_init_jpeg(camogm_state *state)
D0
(
fprintf
(
debug_file
,
"Can not start writer thread: %s
\n
"
,
strerror
(
ret_val
)));
D0
(
fprintf
(
debug_file
,
"Can not start writer thread: %s
\n
"
,
strerror
(
ret_val
)));
ret
=
-
1
;
ret
=
-
1
;
}
}
ret_val
=
init_align_buffers
(
state
);
if
(
ret_val
!=
0
)
{
D0
(
fprintf
(
debug_file
,
"Can not initialize alignment buffers
\n
"
));
ret
=
-
1
;
}
}
}
return
ret
;
return
ret
;
...
@@ -221,6 +215,8 @@ void camogm_free_jpeg(camogm_state *state)
...
@@ -221,6 +215,8 @@ void camogm_free_jpeg(camogm_state *state)
pthread_mutex_unlock
(
&
state
->
writer_params
.
writer_mutex
);
pthread_mutex_unlock
(
&
state
->
writer_params
.
writer_mutex
);
pthread_join
(
state
->
writer_params
.
writer_thread
,
NULL
);
pthread_join
(
state
->
writer_params
.
writer_thread
,
NULL
);
state
->
writer_params
.
exit_thread
=
false
;
state
->
writer_params
.
exit_thread
=
false
;
deinit_align_buffers
(
state
);
}
}
/** Calculate the total length of current frame */
/** Calculate the total length of current frame */
...
@@ -247,6 +243,7 @@ int camogm_start_jpeg(camogm_state *state)
...
@@ -247,6 +243,7 @@ int camogm_start_jpeg(camogm_state *state)
{
{
char
*
slash
;
char
*
slash
;
int
rslt
;
int
rslt
;
off64_t
offset
;
if
(
!
state
->
rawdev_op
)
{
if
(
!
state
->
rawdev_op
)
{
strcpy
(
state
->
path
,
state
->
path_prefix
);
// make state->path a directory name (will be replaced when the frames will be written)
strcpy
(
state
->
path
,
state
->
path_prefix
);
// make state->path a directory name (will be replaced when the frames will be written)
...
@@ -264,16 +261,18 @@ int camogm_start_jpeg(camogm_state *state)
...
@@ -264,16 +261,18 @@ int camogm_start_jpeg(camogm_state *state)
}
}
}
}
}
else
{
}
else
{
// if (open_state_file(&state->rawdev
) != 0) {
if
(
open_state_file
(
&
state
->
rawdev
,
&
state
->
writer_params
.
lba_current
)
!=
0
)
{
// D0(fprintf(debug_file, "Could not set write pointer via sysfs
, recording will start from the beginning of partition: "
D0
(
fprintf
(
debug_file
,
"Could not get write pointer from state file
, recording will start from the beginning of partition: "
//
"%s\n", state->rawdev.rawdev_path));
"%s
\n
"
,
state
->
rawdev
.
rawdev_path
));
//
}
}
state
->
writer_params
.
blockdev_fd
=
open
(
state
->
rawdev
.
rawdev_path
,
O_WRONLY
);
state
->
writer_params
.
blockdev_fd
=
open
(
state
->
rawdev
.
rawdev_path
,
O_WRONLY
);
if
(
state
->
writer_params
.
blockdev_fd
<
0
)
{
if
(
state
->
writer_params
.
blockdev_fd
<
0
)
{
D0
(
fprintf
(
debug_file
,
"Error opening block device: %s
\n
"
,
state
->
rawdev
.
rawdev_path
));
D0
(
fprintf
(
debug_file
,
"Error opening block device: %s
\n
"
,
state
->
rawdev
.
rawdev_path
));
return
-
CAMOGM_FRAME_FILE_ERR
;
return
-
CAMOGM_FRAME_FILE_ERR
;
}
}
D6
(
fprintf
(
debug_file
,
"Open block device: %s
\n
"
,
state
->
rawdev
.
rawdev_path
));
offset
=
lba_to_offset
(
state
->
writer_params
.
lba_current
-
state
->
writer_params
.
lba_start
);
lseek64
(
state
->
writer_params
.
blockdev_fd
,
offset
,
SEEK_SET
);
D6
(
fprintf
(
debug_file
,
"Open block device: %s, offset in bytes: %llu
\n
"
,
state
->
rawdev
.
rawdev_path
,
offset
));
}
}
return
0
;
return
0
;
...
@@ -325,6 +324,15 @@ int camogm_frame_jpeg(camogm_state *state)
...
@@ -325,6 +324,15 @@ int camogm_frame_jpeg(camogm_state *state)
while
(
state
->
writer_params
.
data_ready
)
while
(
state
->
writer_params
.
data_ready
)
pthread_cond_wait
(
&
state
->
writer_params
.
main_cond
,
&
state
->
writer_params
.
writer_mutex
);
pthread_cond_wait
(
&
state
->
writer_params
.
main_cond
,
&
state
->
writer_params
.
writer_mutex
);
D6
(
fprintf
(
debug_file
,
"_13a_"
));
D6
(
fprintf
(
debug_file
,
"_13a_"
));
D6
(
fprintf
(
debug_file
,
"
\n
"
));
align_frame
(
state
);
if
(
update_lba
(
state
)
==
1
)
{
D0
(
fprintf
(
debug_file
,
"The end of block device reached, continue recording from start
\n
"
));
}
D6
(
fprintf
(
debug_file
,
"Block device positions: start = %llu, current = %llu, end = %llu
\n
"
,
state
->
writer_params
.
lba_start
,
state
->
writer_params
.
lba_current
,
state
->
writer_params
.
lba_end
));
// proceed if last frame was recorded without errors
// proceed if last frame was recorded without errors
if
(
state
->
writer_params
.
last_ret_val
==
0
)
{
if
(
state
->
writer_params
.
last_ret_val
==
0
)
{
state
->
writer_params
.
data_ready
=
true
;
state
->
writer_params
.
data_ready
=
true
;
...
@@ -336,8 +344,8 @@ int camogm_frame_jpeg(camogm_state *state)
...
@@ -336,8 +344,8 @@ int camogm_frame_jpeg(camogm_state *state)
}
}
// update statistics
// update statistics
state
->
rawdev
.
last_jpeg_size
=
camogm_get_jpeg_size
(
state
);
//
state->rawdev.last_jpeg_size = camogm_get_jpeg_size(state);
state
->
rawdev
.
total_rec_len
+=
state
->
rawdev
.
last_jpeg_size
;
//
state->rawdev.total_rec_len += state->rawdev.last_jpeg_size;
}
}
return
0
;
return
0
;
...
@@ -353,15 +361,36 @@ int camogm_frame_jpeg(camogm_state *state)
...
@@ -353,15 +361,36 @@ int camogm_frame_jpeg(camogm_state *state)
int
camogm_end_jpeg
(
camogm_state
*
state
)
int
camogm_end_jpeg
(
camogm_state
*
state
)
{
{
int
ret
=
0
;
int
ret
=
0
;
int
bytes
;
ssize_t
iovlen
;
struct
frame_data
fdata
=
{
0
};
struct
frame_data
fdata
=
{
0
};
if
(
state
->
rawdev_op
)
{
if
(
state
->
rawdev_op
)
{
// write any remaining data, do not use writer thread as there can be only one block left CHUNK_REM buffer
pthread_mutex_lock
(
&
state
->
writer_params
.
writer_mutex
);
bytes
=
prep_last_block
(
state
);
if
(
bytes
>
0
)
{
D6
(
fprintf
(
debug_file
,
"Write last block of data, size = %d
\n
"
,
bytes
));
// the remaining data block is placed in CHUNK_COMMON buffer, write just this buffer
iovlen
=
writev
(
state
->
writer_params
.
blockdev_fd
,
&
state
->
writer_params
.
data_chunks
[
CHUNK_COMMON
],
1
);
if
(
iovlen
<
bytes
)
{
D0
(
fprintf
(
debug_file
,
"writev error: %s (returned %i, expected %i)
\n
"
,
strerror
(
errno
),
iovlen
,
bytes
));
state
->
writer_params
.
last_ret_val
=
-
CAMOGM_FRAME_FILE_ERR
;
}
else
{
// update statistic, just one block written
state
->
writer_params
.
lba_current
+=
1
;
state
->
rawdev
.
total_rec_len
+=
bytes
;
}
reset_chunks
(
state
->
writer_params
.
data_chunks
,
1
);
}
pthread_mutex_unlock
(
&
state
->
writer_params
.
writer_mutex
);
D6
(
fprintf
(
debug_file
,
"Closing block device %s
\n
"
,
state
->
rawdev
.
rawdev_path
));
D6
(
fprintf
(
debug_file
,
"Closing block device %s
\n
"
,
state
->
rawdev
.
rawdev_path
));
ret
=
close
(
state
->
writer_params
.
blockdev_fd
);
ret
=
close
(
state
->
writer_params
.
blockdev_fd
);
if
(
ret
==
-
1
)
if
(
ret
==
-
1
)
D0
(
fprintf
(
debug_file
,
"Error: %s
\n
"
,
strerror
(
errno
)));
D0
(
fprintf
(
debug_file
,
"Error: %s
\n
"
,
strerror
(
errno
)));
// save_state_file(&state->rawdev
);
save_state_file
(
&
state
->
rawdev
,
state
->
writer_params
.
lba_current
);
}
}
return
ret
;
return
ret
;
}
}
...
@@ -395,25 +424,40 @@ void *jpeg_writer(void *thread_args)
...
@@ -395,25 +424,40 @@ void *jpeg_writer(void *thread_args)
if
(
params
->
data_ready
)
{
if
(
params
->
data_ready
)
{
l
=
0
;
l
=
0
;
state
->
writer_params
.
last_ret_val
=
0
;
state
->
writer_params
.
last_ret_val
=
0
;
for
(
int
i
=
0
;
i
<
(
state
->
chunk_index
)
-
1
;
i
++
)
{
// for (int i = 0; i < (state->chunk_index) - 1; i++) {
chunks_iovec
[
i
].
iov_base
=
state
->
packetchunks
[
i
+
1
].
chunk
;
// chunks_iovec[i].iov_base = state->packetchunks[i + 1].chunk;
chunks_iovec
[
i
].
iov_len
=
state
->
packetchunks
[
i
+
1
].
bytes
;
// chunks_iovec[i].iov_len = state->packetchunks[i + 1].bytes;
l
+=
chunks_iovec
[
i
].
iov_len
;
// l += chunks_iovec[i].iov_len;
}
// }
chunk_index
=
state
->
chunk_index
;
// chunk_index = state->chunk_index;
iovlen
=
writev
(
state
->
writer_params
.
blockdev_fd
,
chunks_iovec
,
chunk_index
-
1
);
chunk_index
=
get_data_buffers
(
state
,
&
chunks_iovec
,
FILE_CHUNKS_NUM
);
if
(
iovlen
<
l
)
{
if
(
chunk_index
>
0
)
{
D0
(
fprintf
(
debug_file
,
"writev error: %s (returned %li, expected %li)
\n
"
,
strerror
(
errno
),
iovlen
,
l
));
for
(
int
i
=
0
;
i
<
chunk_index
;
i
++
)
l
+=
chunks_iovec
[
i
].
iov_len
;
iovlen
=
writev
(
state
->
writer_params
.
blockdev_fd
,
chunks_iovec
,
chunk_index
);
if
(
iovlen
<
l
)
{
D0
(
fprintf
(
debug_file
,
"writev error: %s (returned %i, expected %i)
\n
"
,
strerror
(
errno
),
iovlen
,
l
));
state
->
writer_params
.
last_ret_val
=
-
CAMOGM_FRAME_FILE_ERR
;
}
else
{
// update statistic
state
->
rawdev
.
last_jpeg_size
=
l
;
state
->
rawdev
.
total_rec_len
+=
state
->
rawdev
.
last_jpeg_size
;
D6
(
fprintf
(
debug_file
,
"Current position in block device: %lld
\n
"
,
lseek64
(
state
->
writer_params
.
blockdev_fd
,
0
,
SEEK_CUR
)));
}
}
else
{
D0
(
fprintf
(
debug_file
,
"data vector mapping error: %d)
\n
"
,
chunk_index
));
state
->
writer_params
.
last_ret_val
=
-
CAMOGM_FRAME_FILE_ERR
;
state
->
writer_params
.
last_ret_val
=
-
CAMOGM_FRAME_FILE_ERR
;
}
}
// release main thread
// release main thread
reset_chunks
(
state
->
writer_params
.
data_chunks
,
0
);
params
->
data_ready
=
false
;
params
->
data_ready
=
false
;
pthread_cond_signal
(
&
params
->
main_cond
);
pthread_cond_signal
(
&
params
->
main_cond
);
}
}
}
}
params
->
state
=
STATE_STOPPED
;
params
->
state
=
STATE_STOPPED
;
pthread_mutex_unlock
(
&
state
->
writer_params
.
writer_mutex
);
pthread_mutex_unlock
(
&
state
->
writer_params
.
writer_mutex
);
D5
(
fprintf
(
debug_file
,
"Exit from recording thread
\n
"
));
return
NULL
;
return
NULL
;
}
}
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