diff options
Diffstat (limited to 'drivers/media/video/uvc/uvc_video.c')
| -rw-r--r-- | drivers/media/video/uvc/uvc_video.c | 125 |
1 files changed, 123 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 | ||
| 427 | size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf, | 511 | size_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, | |||
| 444 | static void uvc_video_stats_start(struct uvc_streaming *stream) | 564 | static 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 | ||
| 449 | static void uvc_video_stats_stop(struct uvc_streaming *stream) | 570 | static void uvc_video_stats_stop(struct uvc_streaming *stream) |
