aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2011-11-03 11:30:17 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-12-11 08:22:08 -0500
commit25738cbd72db53ca1c326bf94915d41086cb4297 (patch)
treedfff4075245deb1af2a13c6998771632a965313d
parent7bc5edb00bbd02449576289a50d2900f58e7187a (diff)
[media] uvcvideo: Extract timestamp-related statistics
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/uvc/uvc_video.c125
-rw-r--r--drivers/media/video/uvc/uvcvideo.h23
2 files changed, 146 insertions, 2 deletions
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index 1908dd859433..513ba30f8d57 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -365,6 +365,11 @@ static void uvc_video_stats_decode(struct uvc_streaming *stream,
365 const __u8 *data, int len) 365 const __u8 *data, int len)
366{ 366{
367 unsigned int header_size; 367 unsigned int header_size;
368 bool has_pts = false;
369 bool has_scr = false;
370 u16 uninitialized_var(scr_sof);
371 u32 uninitialized_var(scr_stc);
372 u32 uninitialized_var(pts);
368 373
369 if (stream->stats.stream.nb_frames == 0 && 374 if (stream->stats.stream.nb_frames == 0 &&
370 stream->stats.frame.nb_packets == 0) 375 stream->stats.frame.nb_packets == 0)
@@ -373,12 +378,16 @@ static void uvc_video_stats_decode(struct uvc_streaming *stream,
373 switch (data[1] & (UVC_STREAM_PTS | UVC_STREAM_SCR)) { 378 switch (data[1] & (UVC_STREAM_PTS | UVC_STREAM_SCR)) {
374 case UVC_STREAM_PTS | UVC_STREAM_SCR: 379 case UVC_STREAM_PTS | UVC_STREAM_SCR:
375 header_size = 12; 380 header_size = 12;
381 has_pts = true;
382 has_scr = true;
376 break; 383 break;
377 case UVC_STREAM_PTS: 384 case UVC_STREAM_PTS:
378 header_size = 6; 385 header_size = 6;
386 has_pts = true;
379 break; 387 break;
380 case UVC_STREAM_SCR: 388 case UVC_STREAM_SCR:
381 header_size = 8; 389 header_size = 8;
390 has_scr = true;
382 break; 391 break;
383 default: 392 default:
384 header_size = 2; 393 header_size = 2;
@@ -391,6 +400,63 @@ static void uvc_video_stats_decode(struct uvc_streaming *stream,
391 return; 400 return;
392 } 401 }
393 402
403 /* Extract the timestamps. */
404 if (has_pts)
405 pts = get_unaligned_le32(&data[2]);
406
407 if (has_scr) {
408 scr_stc = get_unaligned_le32(&data[header_size - 6]);
409 scr_sof = get_unaligned_le16(&data[header_size - 2]);
410 }
411
412 /* Is PTS constant through the whole frame ? */
413 if (has_pts && stream->stats.frame.nb_pts) {
414 if (stream->stats.frame.pts != pts) {
415 stream->stats.frame.nb_pts_diffs++;
416 stream->stats.frame.last_pts_diff =
417 stream->stats.frame.nb_packets;
418 }
419 }
420
421 if (has_pts) {
422 stream->stats.frame.nb_pts++;
423 stream->stats.frame.pts = pts;
424 }
425
426 /* Do all frames have a PTS in their first non-empty packet, or before
427 * their first empty packet ?
428 */
429 if (stream->stats.frame.size == 0) {
430 if (len > header_size)
431 stream->stats.frame.has_initial_pts = has_pts;
432 if (len == header_size && has_pts)
433 stream->stats.frame.has_early_pts = true;
434 }
435
436 /* Do the SCR.STC and SCR.SOF fields vary through the frame ? */
437 if (has_scr && stream->stats.frame.nb_scr) {
438 if (stream->stats.frame.scr_stc != scr_stc)
439 stream->stats.frame.nb_scr_diffs++;
440 }
441
442 if (has_scr) {
443 /* Expand the SOF counter to 32 bits and store its value. */
444 if (stream->stats.stream.nb_frames > 0 ||
445 stream->stats.frame.nb_scr > 0)
446 stream->stats.stream.scr_sof_count +=
447 (scr_sof - stream->stats.stream.scr_sof) % 2048;
448 stream->stats.stream.scr_sof = scr_sof;
449
450 stream->stats.frame.nb_scr++;
451 stream->stats.frame.scr_stc = scr_stc;
452 stream->stats.frame.scr_sof = scr_sof;
453
454 if (scr_sof < stream->stats.stream.min_sof)
455 stream->stats.stream.min_sof = scr_sof;
456 if (scr_sof > stream->stats.stream.max_sof)
457 stream->stats.stream.max_sof = scr_sof;
458 }
459
394 /* Record the first non-empty packet number. */ 460 /* Record the first non-empty packet number. */
395 if (stream->stats.frame.size == 0 && len > header_size) 461 if (stream->stats.frame.size == 0 && len > header_size)
396 stream->stats.frame.first_data = stream->stats.frame.nb_packets; 462 stream->stats.frame.first_data = stream->stats.frame.nb_packets;
@@ -411,9 +477,16 @@ static void uvc_video_stats_update(struct uvc_streaming *stream)
411{ 477{
412 struct uvc_stats_frame *frame = &stream->stats.frame; 478 struct uvc_stats_frame *frame = &stream->stats.frame;
413 479
414 uvc_trace(UVC_TRACE_STATS, "frame %u stats: %u/%u/%u packets\n", 480 uvc_trace(UVC_TRACE_STATS, "frame %u stats: %u/%u/%u packets, "
481 "%u/%u/%u pts (%searly %sinitial), %u/%u scr, "
482 "last pts/stc/sof %u/%u/%u\n",
415 stream->sequence, frame->first_data, 483 stream->sequence, frame->first_data,
416 frame->nb_packets - frame->nb_empty, frame->nb_packets); 484 frame->nb_packets - frame->nb_empty, frame->nb_packets,
485 frame->nb_pts_diffs, frame->last_pts_diff, frame->nb_pts,
486 frame->has_early_pts ? "" : "!",
487 frame->has_initial_pts ? "" : "!",
488 frame->nb_scr_diffs, frame->nb_scr,
489 frame->pts, frame->scr_stc, frame->scr_sof);
417 490
418 stream->stats.stream.nb_frames++; 491 stream->stats.stream.nb_frames++;
419 stream->stats.stream.nb_packets += stream->stats.frame.nb_packets; 492 stream->stats.stream.nb_packets += stream->stats.frame.nb_packets;
@@ -421,14 +494,47 @@ static void uvc_video_stats_update(struct uvc_streaming *stream)
421 stream->stats.stream.nb_errors += stream->stats.frame.nb_errors; 494 stream->stats.stream.nb_errors += stream->stats.frame.nb_errors;
422 stream->stats.stream.nb_invalid += stream->stats.frame.nb_invalid; 495 stream->stats.stream.nb_invalid += stream->stats.frame.nb_invalid;
423 496
497 if (frame->has_early_pts)
498 stream->stats.stream.nb_pts_early++;
499 if (frame->has_initial_pts)
500 stream->stats.stream.nb_pts_initial++;
501 if (frame->last_pts_diff <= frame->first_data)
502 stream->stats.stream.nb_pts_constant++;
503 if (frame->nb_scr >= frame->nb_packets - frame->nb_empty)
504 stream->stats.stream.nb_scr_count_ok++;
505 if (frame->nb_scr_diffs + 1 == frame->nb_scr)
506 stream->stats.stream.nb_scr_diffs_ok++;
507
424 memset(&stream->stats.frame, 0, sizeof(stream->stats.frame)); 508 memset(&stream->stats.frame, 0, sizeof(stream->stats.frame));
425} 509}
426 510
427size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf, 511size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf,
428 size_t size) 512 size_t size)
429{ 513{
514 unsigned int scr_sof_freq;
515 unsigned int duration;
516 struct timespec ts;
430 size_t count = 0; 517 size_t count = 0;
431 518
519 ts.tv_sec = stream->stats.stream.stop_ts.tv_sec
520 - stream->stats.stream.start_ts.tv_sec;
521 ts.tv_nsec = stream->stats.stream.stop_ts.tv_nsec
522 - stream->stats.stream.start_ts.tv_nsec;
523 if (ts.tv_nsec < 0) {
524 ts.tv_sec--;
525 ts.tv_nsec += 1000000000;
526 }
527
528 /* Compute the SCR.SOF frequency estimate. At the nominal 1kHz SOF
529 * frequency this will not overflow before more than 1h.
530 */
531 duration = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
532 if (duration != 0)
533 scr_sof_freq = stream->stats.stream.scr_sof_count * 1000
534 / duration;
535 else
536 scr_sof_freq = 0;
537
432 count += scnprintf(buf + count, size - count, 538 count += scnprintf(buf + count, size - count,
433 "frames: %u\npackets: %u\nempty: %u\n" 539 "frames: %u\npackets: %u\nempty: %u\n"
434 "errors: %u\ninvalid: %u\n", 540 "errors: %u\ninvalid: %u\n",
@@ -437,6 +543,20 @@ size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf,
437 stream->stats.stream.nb_empty, 543 stream->stats.stream.nb_empty,
438 stream->stats.stream.nb_errors, 544 stream->stats.stream.nb_errors,
439 stream->stats.stream.nb_invalid); 545 stream->stats.stream.nb_invalid);
546 count += scnprintf(buf + count, size - count,
547 "pts: %u early, %u initial, %u ok\n",
548 stream->stats.stream.nb_pts_early,
549 stream->stats.stream.nb_pts_initial,
550 stream->stats.stream.nb_pts_constant);
551 count += scnprintf(buf + count, size - count,
552 "scr: %u count ok, %u diff ok\n",
553 stream->stats.stream.nb_scr_count_ok,
554 stream->stats.stream.nb_scr_diffs_ok);
555 count += scnprintf(buf + count, size - count,
556 "sof: %u <= sof <= %u, freq %u.%03u kHz\n",
557 stream->stats.stream.min_sof,
558 stream->stats.stream.max_sof,
559 scr_sof_freq / 1000, scr_sof_freq % 1000);
440 560
441 return count; 561 return count;
442} 562}
@@ -444,6 +564,7 @@ size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf,
444static void uvc_video_stats_start(struct uvc_streaming *stream) 564static void uvc_video_stats_start(struct uvc_streaming *stream)
445{ 565{
446 memset(&stream->stats, 0, sizeof(stream->stats)); 566 memset(&stream->stats, 0, sizeof(stream->stats));
567 stream->stats.stream.min_sof = 2048;
447} 568}
448 569
449static void uvc_video_stats_stop(struct uvc_streaming *stream) 570static void uvc_video_stats_stop(struct uvc_streaming *stream)
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index f9ee62ed0150..e4d4b6d02024 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -364,6 +364,18 @@ struct uvc_stats_frame {
364 unsigned int nb_empty; /* Number of empty packets */ 364 unsigned int nb_empty; /* Number of empty packets */
365 unsigned int nb_invalid; /* Number of packets with an invalid header */ 365 unsigned int nb_invalid; /* Number of packets with an invalid header */
366 unsigned int nb_errors; /* Number of packets with the error bit set */ 366 unsigned int nb_errors; /* Number of packets with the error bit set */
367
368 unsigned int nb_pts; /* Number of packets with a PTS timestamp */
369 unsigned int nb_pts_diffs; /* Number of PTS differences inside a frame */
370 unsigned int last_pts_diff; /* Index of the last PTS difference */
371 bool has_initial_pts; /* Whether the first non-empty packet has a PTS */
372 bool has_early_pts; /* Whether a PTS is present before the first non-empty packet */
373 u32 pts; /* PTS of the last packet */
374
375 unsigned int nb_scr; /* Number of packets with a SCR timestamp */
376 unsigned int nb_scr_diffs; /* Number of SCR.STC differences inside a frame */
377 u16 scr_sof; /* SCR.SOF of the last packet */
378 u32 scr_stc; /* SCR.STC of the last packet */
367}; 379};
368 380
369struct uvc_stats_stream { 381struct uvc_stats_stream {
@@ -376,6 +388,17 @@ struct uvc_stats_stream {
376 unsigned int nb_empty; /* Number of empty packets */ 388 unsigned int nb_empty; /* Number of empty packets */
377 unsigned int nb_invalid; /* Number of packets with an invalid header */ 389 unsigned int nb_invalid; /* Number of packets with an invalid header */
378 unsigned int nb_errors; /* Number of packets with the error bit set */ 390 unsigned int nb_errors; /* Number of packets with the error bit set */
391
392 unsigned int nb_pts_constant; /* Number of frames with constant PTS */
393 unsigned int nb_pts_early; /* Number of frames with early PTS */
394 unsigned int nb_pts_initial; /* Number of frames with initial PTS */
395
396 unsigned int nb_scr_count_ok; /* Number of frames with at least one SCR per non empty packet */
397 unsigned int nb_scr_diffs_ok; /* Number of frames with varying SCR.STC */
398 unsigned int scr_sof_count; /* STC.SOF counter accumulated since stream start */
399 unsigned int scr_sof; /* STC.SOF of the last packet */
400 unsigned int min_sof; /* Minimum STC.SOF value */
401 unsigned int max_sof; /* Maximum STC.SOF value */
379}; 402};
380 403
381struct uvc_streaming { 404struct uvc_streaming {