We connect our cameras with FPD-Link and we found the capture may be stopped when debug message showed that like the below messages:
[ 141.640765] tegra194-vi5 15c10000.vi: video_name: vi-output, tevi-ar0144 32-003d, corr_err: discarding frame 0, flags: 32, err_data 162
[ 143.470167] tegra194-vi5 15c10000.vi: video_name: vi-output, tevi-ar0144 35-003f, corr_err: discarding frame 0, flags: 96, err_data 4194405
[ 144.018509] tegra194-vi5 15c10000.vi: video_name: vi-output, tevi-ar0144 35-003f, corr_err: discarding frame 0, flags: 32, err_data 165
[ 144.326463] tegra194-vi5 15c10000.vi: video_name: vi-output, tevi-ar0144 35-003f, corr_err: discarding frame 0, flags: 32, err_data 165
[ 145.435507] tegra194-vi5 15c10000.vi: video_name: vi-output, tevi-ar0144 35-003d, corr_err: discarding frame 0, flags: 32, err_data 165
[ 146.290995] tegra194-vi5 15c10000.vi: video_name: vi-output, tevi-ar0144 35-003d, corr_err: discarding frame 0, flags: 32, err_data 165
[ 465.539995] tegra194-vi5 15c10000.vi: video_name: vi-output, tevi-ar0144 34-003f, corr_err: discarding frame 0, flags: 32, err_data 164
[ 465.984803] tegra194-vi5 15c10000.vi: video_name: vi-output, tevi-ar0144 34-003f, corr_err: discarding frame 0, flags: 32, err_data 164
When it stopped capturing, we must relaunch GStreamer and make it restart capture images from our cameras.
check the error codes and we guess it captured incomplete data from our cameras and make it stop capturing:
struct capture_status {
uint8_t src_stream;
uint8_t virtual_channel;
uint16_t frame_id;
uint32_t status;
...
uint64_t sof_timestamp;
uint64_t eof_timestamp;
uint32_t err_data;
/* Channel encountered uncorrectable error and must be reset */
#define CAPTURE_STATUS_FLAG_CHANNEL_IN_ERROR U32_C(1U << 0)
/*
* Spurious data was received before frame start.
* Can be badly corrupted frame or some random bits.
* This error doesn't have effect on captured frame
*/
#define CAPTURE_STATUS_FLAG_ERROR_CSIMUX_STREAM_SPURIOUS U32_C(1U << 1)
/*
* Illegal data packet was encountered and dropped by CSIMUX.
* This error may have no effect on capture result or trigger other error if
* frame got corrupted.
*/
#define CAPTURE_STATUS_FLAG_ERROR_CSIMUX_FIFO_BADPKT U32_C(1U << 2)
#define CAPTURE_STATUS_FLAG_ERROR_CSIMUX_FRAME_FORCE_FE U32_C(1U << 3)
#define CAPTURE_STATUS_FLAG_ERROR_CSIMUX_FRAME_ECC_SINGLE_BIT_ERR U32_C(1U << 4)
#define CAPTURE_STATUS_FLAG_ERROR_CSIMUX_FRAME U32_C(1U << 5)
#define CAPTURE_STATUS_FLAG_ERROR_CSIMUX_FRAME_CSI_FAULT U32_C(1U << 6)
/*
* One or more frames could not be matched and got lost before captured
* frame.
* This error doesn't have effect on captured frame
*/
#define CAPTURE_STATUS_FLAG_ERROR_CHANSEL_NO_MATCH U32_C(1U << 7)
/* Frame not finished */
#define CAPTURE_STATUS_FLAG_ERROR_ATOMP_FRAME_TRUNCATED U32_C(1U << 8)
/* Frame data not written */
#define CAPTURE_STATUS_FLAG_ERROR_ATOMP_FRAME_TOSSED U32_C(1U << 9)
uint32_t flags;
} __CAPTURE_IVC_ALIGN;
We modified ‘goto done’ in vi5_fpos.c and tried to ignore the error codes like below:
static void vi5_capture_dequeue(struct tegra_channel *chan,
struct tegra_channel_buffer *buf)
{
int err = 0;
int vi_port = 0;
int gang_prev_frame_id = 0;
unsigned long flags;
struct tegra_mc_vi *vi = chan->vi;
struct vb2_v4l2_buffer *vb = &buf->buf;
struct timespec ts;
struct capture_descriptor *descr = NULL;
for(vi_port = 0; vi_port < chan->valid_ports; vi_port++) {
descr = &chan->request[vi_port][buf->capture_descr_index[vi_port]];
if (buf->vb2_state != VB2_BUF_STATE_ACTIVE)
goto rel_buf;
/* Dequeue a frame and check its capture status */
err = vi_capture_status(chan->tegra_vi_channel[vi_port], CAPTURE_TIMEOUT_MS);
if (err) {
if (err == -ETIMEDOUT) {
dev_err(vi->dev,
"video_name: %s, uncorr_err: request timed out after %d ms\n",
chan->video->name, CAPTURE_TIMEOUT_MS);
} else {
dev_err(vi->dev, "uncorr_err: request err %d\n", err);
}
goto uncorr_err;
} else if (descr->status.status != CAPTURE_STATUS_SUCCESS) {
if ((descr->status.flags
& CAPTURE_STATUS_FLAG_CHANNEL_IN_ERROR) != 0) {
chan->queue_error = true;
dev_err(vi->dev, "uncorr_err: flags %d, err_data %d\n",
descr->status.flags, descr->status.err_data);
} else {
dev_warn(vi->dev,
"video_name: %s, corr_err: discarding frame %d, flags: %d, "
"err_data %d\n",
chan->video->name, descr->status.frame_id, descr->status.flags,
descr->status.err_data);
buf->vb2_state = VB2_BUF_STATE_REQUEUEING;
//goto done;
}
} else if (!vi_port) {
gang_prev_frame_id = descr->status.frame_id;
} else if (descr->status.frame_id != gang_prev_frame_id) {
dev_err(vi->dev, "frame_id out of sync: ch2 %d vs ch1 %d\n",
gang_prev_frame_id, descr->status.frame_id);
goto uncorr_err;
}
spin_lock_irqsave(&chan->capture_state_lock, flags);
if (chan->capture_state != CAPTURE_ERROR) {
chan->capture_reqs_enqueued -= 1;
chan->capture_state = CAPTURE_GOOD;
}
spin_unlock_irqrestore(&chan->capture_state_lock, flags);
}
wake_up_interruptible(&chan->start_wait);
/* Read SOF from capture descriptor */
ts = ns_to_timespec((s64)descr->status.sof_timestamp);
trace_tegra_channel_capture_frame("sof", ts);
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)
/* update time stamp of the buffer */
vb->timestamp.tv_sec = ts.tv_sec;
vb->timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
#else
vb->vb2_buf.timestamp = descr->status.sof_timestamp;
#endif
buf->vb2_state = VB2_BUF_STATE_DONE;
/* Read EOF from capture descriptor */
ts = ns_to_timespec((s64)descr->status.eof_timestamp);
trace_tegra_channel_capture_frame("eof", ts);
//done:
goto rel_buf;
uncorr_err:
spin_lock_irqsave(&chan->capture_state_lock, flags);
chan->capture_state = CAPTURE_ERROR;
spin_unlock_irqrestore(&chan->capture_state_lock, flags);
buf->vb2_state = VB2_BUF_STATE_ERROR;
rel_buf:
vi5_release_buffer(chan, buf);
}
We found it actually improved the appeared frequency of the problem but it still may cause stop capturing we cannot relaunch Gstreamer!
We would like to resolve the problem of stopping capture and make it keeps working even if it captures errors. How could we avoid stopping capture?