Oh yes, sorry, I copy pasted it, I should have attached it to the e-mail, I am sending again the patch 2/2 since it's the only new one, the 1/2 can be found in the ML archive in an e-mail from Laurent Pinchart.

Thanks !

On 06/21/2011 08:34 PM, Alexey Fisher wrote:
hmmm... did you copy-pasted this patch?
it seems to be broken,
some lines are wrapped.

Am Montag, den 20.06.2011, 12:31 +0200 schrieb Yann Sionneau:
---
   drivers/media/video/uvc/uvc_video.c |  196
++++++++++++++++++++++++++++++++++-
   drivers/media/video/uvc/uvcvideo.h  |   39 +++++++
   2 files changed, 234 insertions(+), 1 deletions(-)

diff --git a/drivers/media/video/uvc/uvc_video.c
b/drivers/media/video/uvc/uvc_video.c
index fc766b9..feb585b 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -358,6 +358,191 @@ 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;
+
+    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;
+        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_le16(&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;
+    }
+
+    /* Do the SCR.STC and SCR.SOF fields 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) {
+        /* Expand the SOF counter to 32 bits and store its value. */
+        if (stream->stats.stream.nb_frames>  0 ||
+            stream->stats.frame.nb_scr>  0)
+            stream->stats.stream.scr_sof_count +=
+                (scr_sof - stream->stats.stream.scr_sof) % 2048;
+        stream->stats.stream.scr_sof = scr_sof;
+
+        stream->stats.frame.nb_scr++;
+        stream->stats.frame.scr_stc = scr_stc;
+        stream->stats.frame.scr_sof = scr_sof;
+
+        if (scr_sof<  stream->stats.stream.min_sof)
+            stream->stats.stream.min_sof = scr_sof;
+        if (scr_sof>  stream->stats.stream.max_sof)
+            stream->stats.stream.max_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)
+{
+    unsigned int scr_sof_freq;
+    unsigned int duration;
+    struct timespec ts;
+
+    ktime_get_ts(&ts);
+
+    ts.tv_sec -= stream->stats.stream.start_ts.tv_sec;
+    ts.tv_nsec -= stream->stats.stream.start_ts.tv_nsec;
+    if (ts.tv_nsec<  0) {
+        ts.tv_sec--;
+        ts.tv_nsec += 1000000000;
+    }
+
+    /* Compute the SCR.SOF frequency estimate. At the nominal 1kHz SOF
+     * frequency this will not overflow before more than 1h.
+     */
+    duration = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
+    if (duration != 0)
+        scr_sof_freq = stream->stats.stream.scr_sof_count * 1000
+                 / duration;
+    else
+        scr_sof_freq = 0;
+
+    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, "
+          "%u<= sof<= %u, sof freq %u.%03u kHz\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,
+          stream->stats.stream.min_sof, stream->stats.stream.max_sof,
+          scr_sof_freq / 1000, scr_sof_freq % 1000);
+}
+
+static void uvc_video_stats_init(struct uvc_streaming *stream)
+{
+    memset(&stream->stats, 0, sizeof(stream->stats));
+    stream->stats.stream.min_sof = 2048;
+}
+
+/* ------------------------------------------------------------------------
    * Video codecs
    */

@@ -431,8 +616,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 +1051,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 +1186,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 45f01e7..40f461c 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -462,6 +462,44 @@ struct uvc_streaming {

       __u32 sequence;
       __u8 last_fid;
+
+    struct {
+        struct {
+            struct timespec start_ts;    /* Stream start timestamp */
+            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 */
+            unsigned int scr_sof_count;    /* STC.SOF counter
accumulated since stream start */
+            unsigned int scr_sof;        /* STC.SOF of the last packet */
+            unsigned int min_sof;        /* Minimum STC.SOF value */
+            unsigned int max_sof;        /* Maximum STC.SOF value */
+        } 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 {
@@ -529,6 +567,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

---
 drivers/media/video/uvc/uvc_video.c |   30 +++++++++++++++++++++---------
 drivers/media/video/uvc/uvcvideo.h  |    7 +++++--
 2 files changed, 26 insertions(+), 11 deletions(-)

diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index feb585b..c8c5967 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -436,7 +436,9 @@ static void uvc_video_stats_decode(struct uvc_streaming *stream,
 	/* Do the SCR.STC and SCR.SOF fields 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++;
+			stream->stats.frame.nb_scr_stc_diffs++;
+		if (stream->stats.frame.scr_sof != scr_sof)
+			stream->stats.frame.nb_scr_sof_diffs++;
 	}
 
 	if (has_scr) {
@@ -457,6 +459,13 @@ static void uvc_video_stats_decode(struct uvc_streaming *stream,
 			stream->stats.stream.max_sof = scr_sof;
 	}
 
+	if (has_pts) {
+		if (stream->stats.frame.nb_pts > 0  && stream->stats.stream.pts > 0)
+			stream->stats.stream.nb_pts_count +=
+			(pts - stream->stats.stream.pts);
+		stream->stats.stream.pts = pts;
+	}
+
 	if (stream->stats.frame.size == 0 && len > header_size)
 		stream->stats.frame.first_data = stream->stats.frame.nb_packets;
 
@@ -474,13 +483,15 @@ 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",
+		  "%u/%u/%u pts (%searly %sinitial) %u/%u scr.stc "
+		  "%u/%u scr.sof",
 		  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);
+		  frame->nb_scr_stc_diffs, frame->nb_scr,
+		  frame->nb_scr_sof_diffs, frame->nb_scr);
 
 	stream->stats.stream.nb_frames++;
 
@@ -492,8 +503,8 @@ static void uvc_video_stats_update(struct uvc_streaming *stream)
 		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++;
+	if (frame->nb_scr_stc_diffs + 1 == frame->nb_scr)
+		stream->stats.stream.nb_scr_stc_diffs_ok++;
 
 	memset(&stream->stats.frame, 0, sizeof(stream->stats.frame));
 }
@@ -524,16 +535,17 @@ static void uvc_video_stats_dump(struct uvc_streaming *stream)
 		scr_sof_freq = 0;
 
 	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, "
-		  "%u <= sof <= %u, sof freq %u.%03u kHz\n",
+		  "%u initial pts %u pts ok %u scr count ok %u scr.stc diff ok"
+		  " %u <= sof <= %u, sof freq %u.%03u kHz, pts count = %llu",
 		  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,
+		  stream->stats.stream.nb_scr_stc_diffs_ok,
 		  stream->stats.stream.min_sof, stream->stats.stream.max_sof,
-		  scr_sof_freq / 1000, scr_sof_freq % 1000);
+		  scr_sof_freq / 1000, scr_sof_freq % 1000,
+		  (unsigned long long)stream->stats.stream.nb_pts_count);
 }
 
 static void uvc_video_stats_init(struct uvc_streaming *stream)
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index 40f461c..6c823d7 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -471,11 +471,13 @@ struct uvc_streaming {
 			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 */
+			unsigned int nb_scr_stc_diffs_ok;	/* Number of frames with varying SCR.STC */
 			unsigned int scr_sof_count;	/* STC.SOF counter accumulated since stream start */
 			unsigned int scr_sof;		/* STC.SOF of the last packet */
 			unsigned int min_sof;		/* Minimum STC.SOF value */
 			unsigned int max_sof;		/* Maximum STC.SOF value */
+			unsigned int pts;
+			u64 nb_pts_count;
 		} stream;
 
 		struct uvc_stats_frame {
@@ -495,7 +497,8 @@ struct uvc_streaming {
 			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 */
+			unsigned int nb_scr_stc_diffs;	/* Number of SCR.STC differences inside a frame */
+			unsigned int nb_scr_sof_diffs;	/* Number of SCR.SOF differences inside a frame */
 			u16 scr_sof;			/* SCR.SOF of the last packet */
 			u32 scr_stc;			/* SCR.STC of the last packet */
 		} frame;
-- 
1.7.4.1

_______________________________________________
Linux-uvc-devel mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/linux-uvc-devel

Reply via email to