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

-- 
Regards,
        Alexey

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

Reply via email to