Hi Yann,

What about the following patch ? It will print at the end of the stream the
total number of frames and the number of frames with

- an early PTS (PTS present in at least one packet before the first non-empty
  packet)
- an initial PTS (PTS present in the first non-empty packet)
- a constant PTS through the whole frame
- at least one SCR per non-empty packet
- no two consecutive identical SCR

Is there anything else worth adding ? Maybe the number of frames with a
non-constant SCR.SOF ?

---
 drivers/media/video/uvc/uvc_video.c |  152 ++++++++++++++++++++++++++++++++++-
 drivers/media/video/uvc/uvcvideo.h  |   34 ++++++++
 2 files changed, 185 insertions(+), 1 deletions(-)

diff --git a/drivers/media/video/uvc/uvc_video.c 
b/drivers/media/video/uvc/uvc_video.c
index fc766b9..19de225 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -358,6 +358,147 @@ int uvc_commit_video(struct uvc_streaming *stream,
 }
 
 /* ------------------------------------------------------------------------
+ * Timestamp statistics
+ */
+
+static void uvc_video_stats_decode(struct uvc_streaming *stream,
+               const __u8 *data, int len)
+{
+       unsigned int header_size;
+       bool has_pts = false;
+       bool has_scr = false;
+       u16 scr_sof;
+       u32 scr_stc;
+       u32 pts;
+
+       switch (data[1] & (UVC_STREAM_PTS | UVC_STREAM_SCR)) {
+       case UVC_STREAM_PTS | UVC_STREAM_SCR:
+               header_size = 12;
+               has_pts = true;
+               has_scr = true;
+               break;
+       case UVC_STREAM_PTS:
+               header_size = 6;
+               has_pts = true;
+               break;
+       case UVC_STREAM_SCR:
+               header_size = 8;
+               has_scr = true;
+               break;
+       default:
+               header_size = 2;
+               break;
+       }
+
+       /* Check for invalid headers. */
+       if (len < header_size) {
+               stream->stats.frame.nb_invalid_headers++;
+               return;
+       }
+
+       /* Extract the timestamps. */
+       if (has_pts)
+               pts = get_unaligned_le32(&data[2]);
+
+       if (has_scr) {
+               scr_stc = get_unaligned_le32(&data[header_size - 6]);
+               scr_sof = get_unaligned_le32(&data[header_size - 2]);
+       }
+
+       /* Is PTS constant through the whole frame ? */
+       if (has_pts && stream->stats.frame.nb_pts) {
+               if (stream->stats.frame.pts != pts) {
+                       stream->stats.frame.nb_pts_diffs++;
+                       stream->stats.frame.last_pts_diff = 
stream->stats.frame.nb_packets;
+               }
+       }
+
+       if (has_pts) {
+               stream->stats.frame.nb_pts++;
+               stream->stats.frame.pts = pts;
+       }
+
+       /* Do all frames have a PTS in their first non-empty packet, or before
+        * their first empty packet ?
+        */
+       if (stream->stats.frame.size == 0) {
+               if (len > header_size)
+                       stream->stats.frame.has_initial_pts = has_pts;
+               if (len == header_size && has_pts)
+                       stream->stats.frame.has_early_pts = true;
+       }
+
+       /* Does the SCR.STC field vary through the frame ? */
+       if (has_scr && stream->stats.frame.nb_scr) {
+               if (stream->stats.frame.scr_stc != scr_stc)
+                       stream->stats.frame.nb_scr_diffs++;
+       }
+
+       if (has_scr) {
+               stream->stats.frame.nb_scr++;
+               stream->stats.frame.scr_stc = scr_stc;
+               stream->stats.frame.scr_sof = scr_sof;
+       }
+
+       if (stream->stats.frame.size == 0 && len > header_size)
+               stream->stats.frame.first_data = stream->stats.frame.nb_packets;
+
+       stream->stats.frame.size += len - header_size;
+       stream->stats.frame.nb_packets++;
+       if (len > header_size)
+               stream->stats.frame.nb_non_empty_packets++;
+
+       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_TIMESTAMP, "frame %u stats: %u/%u/%u packets "
+                 "%u/%u/%u pts (%searly %sinitial) %u/%u scr\n",
+                 stream->sequence, frame->first_data,
+                 frame->nb_non_empty_packets, frame->nb_packets,
+                 frame->nb_pts_diffs, frame->last_pts_diff, frame->nb_pts,
+                 frame->has_early_pts ? "" : "!",
+                 frame->has_initial_pts ? "" : "!",
+                 frame->nb_scr_diffs, frame->nb_scr);
+
+       stream->stats.stream.nb_frames++;
+
+       if (frame->has_early_pts)
+               stream->stats.stream.nb_pts_early++;
+       if (frame->has_initial_pts)
+               stream->stats.stream.nb_pts_initial++;
+       if (frame->last_pts_diff <= frame->first_data)
+               stream->stats.stream.nb_pts_constant++;
+       if (frame->nb_scr >= frame->nb_non_empty_packets)
+               stream->stats.stream.nb_scr_count_ok++;
+       if (frame->nb_scr_diffs + 1 == frame->nb_scr)
+               stream->stats.stream.nb_scr_diffs_ok++;
+
+       memset(&stream->stats.frame, 0, sizeof(stream->stats.frame));
+}
+
+static void uvc_video_stats_dump(struct uvc_streaming *stream)
+{
+       uvc_trace(UVC_TRACE_TIMESTAMP, "stream stats: %u frames %u early pts "
+                 "%u initial pts %u pts ok %u scr count ok %u scr diff ok\n",
+                 stream->stats.stream.nb_frames,
+                 stream->stats.stream.nb_pts_early,
+                 stream->stats.stream.nb_pts_initial,
+                 stream->stats.stream.nb_pts_constant,
+                 stream->stats.stream.nb_scr_count_ok,
+                 stream->stats.stream.nb_scr_diffs_ok);
+}
+
+static void uvc_video_stats_init(struct uvc_streaming *stream)
+{
+       memset(&stream->stats, 0, sizeof(stream->stats));
+}
+
+/* ------------------------------------------------------------------------
  * Video codecs
  */
 
@@ -431,8 +572,13 @@ static int uvc_video_decode_start(struct uvc_streaming 
*stream,
        /* 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.
@@ -861,6 +1007,8 @@ static void uvc_uninit_video(struct uvc_streaming *stream, 
int free_buffers)
        struct urb *urb;
        unsigned int i;
 
+       uvc_video_stats_dump(stream);
+
        for (i = 0; i < UVC_URBS; ++i) {
                urb = stream->urb[i];
                if (urb == NULL)
@@ -994,6 +1142,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_init(stream);
+
        if (intf->num_altsetting > 1) {
                struct usb_host_endpoint *best_ep = NULL;
                unsigned int best_psize = 3 * 1024;
diff --git a/drivers/media/video/uvc/uvcvideo.h 
b/drivers/media/video/uvc/uvcvideo.h
index 20107fd..6ec6c53 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -495,6 +495,39 @@ struct uvc_streaming {
 
        __u32 sequence;
        __u8 last_fid;
+
+       struct {
+               struct {
+                       unsigned int nb_frames;         /* Number of frames */
+                       unsigned int nb_pts_constant;   /* Number of frames 
with constant PTS */
+                       unsigned int nb_pts_early;      /* Number of frames 
with early PTS */
+                       unsigned int nb_pts_initial;    /* Number of frames 
with initial PTS */
+                       unsigned int nb_scr_count_ok;   /* Number of frames 
with at least one SCR per non empty packet */
+                       unsigned int nb_scr_diffs_ok;   /* Number of frames 
with varying SCR.STC */
+               } stream;
+
+               struct uvc_stats_frame {
+                       unsigned int size;              /* Number of bytes 
captured */
+                       unsigned int first_data;        /* Index of the first 
non-empty packet */
+
+                       unsigned int nb_packets;        /* Number of packets */
+                       unsigned int nb_non_empty_packets;      /* Number of 
non-empty packets */
+                       unsigned int nb_invalid_headers;/* Number of packets 
with an invalid header */
+                       unsigned int nb_errors;         /* Number of packets 
with the error bit set */
+
+                       unsigned int nb_pts;            /* Number of packets 
with a PTS timestamp */
+                       unsigned int nb_pts_diffs;      /* Number of PTS 
differences inside a frame */
+                       unsigned int last_pts_diff;     /* Index of the last 
PTS difference */
+                       bool has_initial_pts;           /* Whether the first 
non-empty packet has a PTS */
+                       bool has_early_pts;             /* Whether a PTS is 
present before the first non-empty packet */
+                       u32 pts;                        /* PTS of the last 
packet */
+
+                       unsigned int nb_scr;            /* Number of packets 
with a SCR timestamp */
+                       unsigned int nb_scr_diffs;      /* Number of SCR.STC 
differences inside a frame */
+                       u16 scr_sof;                    /* SCR.SOF of the last 
packet */
+                       u32 scr_stc;                    /* SCR.STC of the last 
packet */
+               } frame;
+       } stats;
 };
 
 enum uvc_device_state {
@@ -566,6 +599,7 @@ struct uvc_driver {
 #define UVC_TRACE_SUSPEND      (1 << 8)
 #define UVC_TRACE_STATUS       (1 << 9)
 #define UVC_TRACE_VIDEO                (1 << 10)
+#define UVC_TRACE_TIMESTAMP    (1 << 11)
 
 #define UVC_WARN_MINMAX                0
 #define UVC_WARN_PROBE_DEF     1
-- 
Regards,

Laurent Pinchart

_______________________________________________
Linux-uvc-devel mailing list
Linux-uvc-devel@lists.berlios.de
https://lists.berlios.de/mailman/listinfo/linux-uvc-devel

Reply via email to