diff options
author | Alexey Fisher <bug-track@fisher-privat.net> | 2011-11-03 18:40:08 +0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-12-11 17:22:08 +0400 |
commit | 7bc5edb00bbd02449576289a50d2900f58e7187a (patch) | |
tree | fe0dc70fcceed75d72e10fc9869ecd90f7b8c057 /drivers/media/video/uvc/uvc_video.c | |
parent | edbaa39842793fc4ac6603b277f2ad76f2057a45 (diff) | |
download | linux-7bc5edb00bbd02449576289a50d2900f58e7187a.tar.xz |
[media] uvcvideo: Extract video stream statistics
Export the statistics through debugfs.
Signed-off-by: Alexey Fisher <bug-track@fisher-privat.net>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/uvc/uvc_video.c')
-rw-r--r-- | drivers/media/video/uvc/uvc_video.c | 109 |
1 files changed, 107 insertions, 2 deletions
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index a57f81341849..1908dd859433 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -358,6 +358,100 @@ static int uvc_commit_video(struct uvc_streaming *stream, } /* ------------------------------------------------------------------------ + * Stream statistics + */ + +static void uvc_video_stats_decode(struct uvc_streaming *stream, + const __u8 *data, int len) +{ + unsigned int header_size; + + if (stream->stats.stream.nb_frames == 0 && + stream->stats.frame.nb_packets == 0) + ktime_get_ts(&stream->stats.stream.start_ts); + + switch (data[1] & (UVC_STREAM_PTS | UVC_STREAM_SCR)) { + case UVC_STREAM_PTS | UVC_STREAM_SCR: + header_size = 12; + break; + case UVC_STREAM_PTS: + header_size = 6; + break; + case UVC_STREAM_SCR: + header_size = 8; + break; + default: + header_size = 2; + break; + } + + /* Check for invalid headers. */ + if (len < header_size || data[0] < header_size) { + stream->stats.frame.nb_invalid++; + return; + } + + /* Record the first non-empty packet number. */ + if (stream->stats.frame.size == 0 && len > header_size) + stream->stats.frame.first_data = stream->stats.frame.nb_packets; + + /* Update the frame size. */ + stream->stats.frame.size += len - header_size; + + /* Update the packets counters. */ + stream->stats.frame.nb_packets++; + if (len > header_size) + stream->stats.frame.nb_empty++; + + if (data[1] & UVC_STREAM_ERR) + stream->stats.frame.nb_errors++; +} + +static void uvc_video_stats_update(struct uvc_streaming *stream) +{ + struct uvc_stats_frame *frame = &stream->stats.frame; + + uvc_trace(UVC_TRACE_STATS, "frame %u stats: %u/%u/%u packets\n", + stream->sequence, frame->first_data, + frame->nb_packets - frame->nb_empty, frame->nb_packets); + + stream->stats.stream.nb_frames++; + stream->stats.stream.nb_packets += stream->stats.frame.nb_packets; + stream->stats.stream.nb_empty += stream->stats.frame.nb_empty; + stream->stats.stream.nb_errors += stream->stats.frame.nb_errors; + stream->stats.stream.nb_invalid += stream->stats.frame.nb_invalid; + + memset(&stream->stats.frame, 0, sizeof(stream->stats.frame)); +} + +size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf, + size_t size) +{ + size_t count = 0; + + count += scnprintf(buf + count, size - count, + "frames: %u\npackets: %u\nempty: %u\n" + "errors: %u\ninvalid: %u\n", + stream->stats.stream.nb_frames, + stream->stats.stream.nb_packets, + stream->stats.stream.nb_empty, + stream->stats.stream.nb_errors, + stream->stats.stream.nb_invalid); + + return count; +} + +static void uvc_video_stats_start(struct uvc_streaming *stream) +{ + memset(&stream->stats, 0, sizeof(stream->stats)); +} + +static void uvc_video_stats_stop(struct uvc_streaming *stream) +{ + ktime_get_ts(&stream->stats.stream.stop_ts); +} + +/* ------------------------------------------------------------------------ * Video codecs */ @@ -406,16 +500,23 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, * - bHeaderLength value must be at least 2 bytes (see above) * - bHeaderLength value can't be larger than the packet size. */ - if (len < 2 || data[0] < 2 || data[0] > len) + if (len < 2 || data[0] < 2 || data[0] > len) { + stream->stats.frame.nb_invalid++; return -EINVAL; + } fid = data[1] & UVC_STREAM_FID; /* Increase the sequence number regardless of any buffer states, so * that discontinuous sequence numbers always indicate lost frames. */ - if (stream->last_fid != fid) + if (stream->last_fid != fid) { stream->sequence++; + if (stream->sequence) + uvc_video_stats_update(stream); + } + + uvc_video_stats_decode(stream, data, len); /* Store the payload FID bit and return immediately when the buffer is * NULL. @@ -860,6 +961,8 @@ static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers) struct urb *urb; unsigned int i; + uvc_video_stats_stop(stream); + for (i = 0; i < UVC_URBS; ++i) { urb = stream->urb[i]; if (urb == NULL) @@ -999,6 +1102,8 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags) stream->bulk.skip_payload = 0; stream->bulk.payload_size = 0; + uvc_video_stats_start(stream); + if (intf->num_altsetting > 1) { struct usb_host_endpoint *best_ep = NULL; unsigned int best_psize = 3 * 1024; |