OLD | NEW |
1 /* | 1 /* |
2 * libjingle | 2 * libjingle |
3 * Copyright 2015 Google Inc. | 3 * Copyright 2015 Google Inc. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions are met: | 6 * modification, are permitted provided that the following conditions are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright notice, | 8 * 1. Redistributions of source code must retain the above copyright notice, |
9 * this list of conditions and the following disclaimer. | 9 * this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright notice, | 10 * 2. Redistributions in binary form must reproduce the above copyright notice, |
(...skipping 551 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
562 final long captureTimeNs = | 562 final long captureTimeNs = |
563 TimeUnit.MILLISECONDS.toNanos(SystemClock.elapsedRealtime()); | 563 TimeUnit.MILLISECONDS.toNanos(SystemClock.elapsedRealtime()); |
564 | 564 |
565 captureBuffersCount += videoBuffers.numCaptureBuffersAvailable(); | 565 captureBuffersCount += videoBuffers.numCaptureBuffersAvailable(); |
566 int rotation = getDeviceOrientation(); | 566 int rotation = getDeviceOrientation(); |
567 if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { | 567 if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { |
568 rotation = 360 - rotation; | 568 rotation = 360 - rotation; |
569 } | 569 } |
570 rotation = (info.orientation + rotation) % 360; | 570 rotation = (info.orientation + rotation) % 360; |
571 // Mark the frame owning |data| as used. | 571 // Mark the frame owning |data| as used. |
572 final ByteBuffer buffer = videoBuffers.reserveByteBuffer(data, captureTimeNs
); | 572 // Note that since data is directBuffer, |
573 if (buffer != null) { | 573 // data.length >= videoBuffers.frameSize. |
| 574 if (videoBuffers.reserveByteBuffer(data, captureTimeNs)) { |
574 cameraFramesCount++; | 575 cameraFramesCount++; |
575 frameObserver.OnFrameCaptured(buffer, captureFormat.width, captureFormat.h
eight, | 576 frameObserver.OnFrameCaptured(data, videoBuffers.frameSize, captureFormat.
width, |
576 rotation, captureTimeNs); | 577 captureFormat.height, rotation, captureTimeNs); |
577 } else { | 578 } else { |
578 Logging.w(TAG, "reserveByteBuffer failed - dropping frame."); | 579 Logging.w(TAG, "reserveByteBuffer failed - dropping frame."); |
579 } | 580 } |
580 } | 581 } |
581 | 582 |
582 // Class used for allocating and bookkeeping video frames. All buffers are | 583 // Class used for allocating and bookkeeping video frames. All buffers are |
583 // direct allocated so that they can be directly used from native code. This c
lass is | 584 // direct allocated so that they can be directly used from native code. This c
lass is |
584 // not thread-safe, and enforces single thread use. | 585 // not thread-safe, and enforces single thread use. |
585 private static class FramePool { | 586 private static class FramePool { |
586 // Thread that all calls should be made on. | 587 // Thread that all calls should be made on. |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
648 checkIsOnValidThread(); | 649 checkIsOnValidThread(); |
649 this.camera = null; | 650 this.camera = null; |
650 queuedBuffers.clear(); | 651 queuedBuffers.clear(); |
651 // Frames in |pendingBuffers| need to be kept alive until they are returne
d. | 652 // Frames in |pendingBuffers| need to be kept alive until they are returne
d. |
652 Logging.d(TAG, "stopReturnBuffersToCamera called." | 653 Logging.d(TAG, "stopReturnBuffersToCamera called." |
653 + (pendingBuffers.isEmpty() ? | 654 + (pendingBuffers.isEmpty() ? |
654 " All buffers have been returned." | 655 " All buffers have been returned." |
655 : " Pending buffers: " + pendingFramesTimeStamps() + ".")); | 656 : " Pending buffers: " + pendingFramesTimeStamps() + ".")); |
656 } | 657 } |
657 | 658 |
658 // Returns the reserved byte buffer, or null on failure. | 659 public boolean reserveByteBuffer(byte[] data, long timeStamp) { |
659 public ByteBuffer reserveByteBuffer(byte[] data, long timeStamp) { | |
660 checkIsOnValidThread(); | 660 checkIsOnValidThread(); |
661 final ByteBuffer buffer = queuedBuffers.remove(data); | 661 final ByteBuffer buffer = queuedBuffers.remove(data); |
662 if (buffer == null) { | 662 if (buffer == null) { |
663 // Frames might be posted to |onPreviewFrame| with the previous format w
hile changing | 663 // Frames might be posted to |onPreviewFrame| with the previous format w
hile changing |
664 // capture format in |startPreviewOnCameraThread|. Drop these old frames
. | 664 // capture format in |startPreviewOnCameraThread|. Drop these old frames
. |
665 Logging.w(TAG, "Received callback buffer from previous configuration wit
h length: " | 665 Logging.w(TAG, "Received callback buffer from previous configuration wit
h length: " |
666 + (data == null ? "null" : data.length)); | 666 + (data == null ? "null" : data.length)); |
667 return null; | 667 return false; |
668 } | 668 } |
669 if (buffer.capacity() != frameSize) { | 669 if (buffer.capacity() != frameSize) { |
670 throw new IllegalStateException("Callback buffer has unexpected frame si
ze"); | 670 throw new IllegalStateException("Callback buffer has unexpected frame si
ze"); |
671 } | 671 } |
672 if (pendingBuffers.containsKey(timeStamp)) { | 672 if (pendingBuffers.containsKey(timeStamp)) { |
673 Logging.e(TAG, "Timestamp already present in pending buffers - they need
to be unique"); | 673 Logging.e(TAG, "Timestamp already present in pending buffers - they need
to be unique"); |
674 return null; | 674 return false; |
675 } | 675 } |
676 pendingBuffers.put(timeStamp, buffer); | 676 pendingBuffers.put(timeStamp, buffer); |
677 if (queuedBuffers.isEmpty()) { | 677 if (queuedBuffers.isEmpty()) { |
678 Logging.v(TAG, "Camera is running out of capture buffers." | 678 Logging.v(TAG, "Camera is running out of capture buffers." |
679 + " Pending buffers: " + pendingFramesTimeStamps()); | 679 + " Pending buffers: " + pendingFramesTimeStamps()); |
680 } | 680 } |
681 return buffer; | 681 return true; |
682 } | 682 } |
683 | 683 |
684 public void returnBuffer(long timeStamp) { | 684 public void returnBuffer(long timeStamp) { |
685 checkIsOnValidThread(); | 685 checkIsOnValidThread(); |
686 final ByteBuffer returnedFrame = pendingBuffers.remove(timeStamp); | 686 final ByteBuffer returnedFrame = pendingBuffers.remove(timeStamp); |
687 if (returnedFrame == null) { | 687 if (returnedFrame == null) { |
688 throw new RuntimeException("unknown data buffer with time stamp " | 688 throw new RuntimeException("unknown data buffer with time stamp " |
689 + timeStamp + "returned?!?"); | 689 + timeStamp + "returned?!?"); |
690 } | 690 } |
691 | 691 |
(...skipping 23 matching lines...) Expand all Loading... |
715 } | 715 } |
716 | 716 |
717 // Interface used for providing callbacks to an observer. | 717 // Interface used for providing callbacks to an observer. |
718 interface CapturerObserver { | 718 interface CapturerObserver { |
719 // Notify if the camera have been started successfully or not. | 719 // Notify if the camera have been started successfully or not. |
720 // Called on a Java thread owned by VideoCapturerAndroid. | 720 // Called on a Java thread owned by VideoCapturerAndroid. |
721 abstract void OnCapturerStarted(boolean success); | 721 abstract void OnCapturerStarted(boolean success); |
722 | 722 |
723 // Delivers a captured frame. Called on a Java thread owned by | 723 // Delivers a captured frame. Called on a Java thread owned by |
724 // VideoCapturerAndroid. | 724 // VideoCapturerAndroid. |
725 abstract void OnFrameCaptured(ByteBuffer buffer, int width, int height, int
rotation, | 725 abstract void OnFrameCaptured(byte[] data, int length, int width, int height
, |
726 long timeStamp); | 726 int rotation, long timeStamp); |
727 | 727 |
728 // Requests an output format from the video capturer. Captured frames | 728 // Requests an output format from the video capturer. Captured frames |
729 // by the camera will be scaled/or dropped by the video capturer. | 729 // by the camera will be scaled/or dropped by the video capturer. |
730 // Called on a Java thread owned by VideoCapturerAndroid. | 730 // Called on a Java thread owned by VideoCapturerAndroid. |
731 abstract void OnOutputFormatRequest(int width, int height, int fps); | 731 abstract void OnOutputFormatRequest(int width, int height, int fps); |
732 } | 732 } |
733 | 733 |
734 // An implementation of CapturerObserver that forwards all calls from | 734 // An implementation of CapturerObserver that forwards all calls from |
735 // Java to the C layer. | 735 // Java to the C layer. |
736 static class NativeObserver implements CapturerObserver { | 736 static class NativeObserver implements CapturerObserver { |
737 private final long nativeCapturer; | 737 private final long nativeCapturer; |
738 | 738 |
739 public NativeObserver(long nativeCapturer) { | 739 public NativeObserver(long nativeCapturer) { |
740 this.nativeCapturer = nativeCapturer; | 740 this.nativeCapturer = nativeCapturer; |
741 } | 741 } |
742 | 742 |
743 @Override | 743 @Override |
744 public void OnCapturerStarted(boolean success) { | 744 public void OnCapturerStarted(boolean success) { |
745 nativeCapturerStarted(nativeCapturer, success); | 745 nativeCapturerStarted(nativeCapturer, success); |
746 } | 746 } |
747 | 747 |
748 @Override | 748 @Override |
749 public void OnFrameCaptured(ByteBuffer buffer, int width, int height, int ro
tation, | 749 public void OnFrameCaptured(byte[] data, int length, int width, int height, |
750 long timeStamp) { | 750 int rotation, long timeStamp) { |
751 nativeOnFrameCaptured(nativeCapturer, buffer, width, height, rotation, tim
eStamp); | 751 nativeOnFrameCaptured(nativeCapturer, data, length, width, height, rotatio
n, timeStamp); |
752 } | 752 } |
753 | 753 |
754 @Override | 754 @Override |
755 public void OnOutputFormatRequest(int width, int height, int fps) { | 755 public void OnOutputFormatRequest(int width, int height, int fps) { |
756 nativeOnOutputFormatRequest(nativeCapturer, width, height, fps); | 756 nativeOnOutputFormatRequest(nativeCapturer, width, height, fps); |
757 } | 757 } |
758 | 758 |
759 private native void nativeCapturerStarted(long nativeCapturer, | 759 private native void nativeCapturerStarted(long nativeCapturer, |
760 boolean success); | 760 boolean success); |
761 private native void nativeOnFrameCaptured(long nativeCapturer, | 761 private native void nativeOnFrameCaptured(long nativeCapturer, |
762 ByteBuffer buffer, int width, int height, int rotation, long timeStamp); | 762 byte[] data, int length, int width, int height, int rotation, long timeS
tamp); |
763 private native void nativeOnOutputFormatRequest(long nativeCapturer, | 763 private native void nativeOnOutputFormatRequest(long nativeCapturer, |
764 int width, int height, int fps); | 764 int width, int height, int fps); |
765 } | 765 } |
766 } | 766 } |
OLD | NEW |