Supporting formats of non-multiple of 16 widths on Android.
This is an updated version of perkj's issue (https://webrtc-codereview.appspot.com/44129004/) which was reverted due to libjingle_peerconnection_android_unittest crashing on Nexus 9. It crashed because there was old test code still assuming the width was multiple of 16 (which was only a problem on devices with non-16 widths). BUG=4522 R=glaznev@webrtc.org, magjed@webrtc.org Review URL: https://webrtc-codereview.appspot.com/45109004 Cr-Commit-Position: refs/heads/master@{#9029}
This commit is contained in:
parent
a51e8f490c
commit
09a9ea8886
@ -260,7 +260,7 @@ public class VideoCapturerAndroidTest extends ActivityTestCase {
|
|||||||
assertTrue(observer.WaitForCapturerToStart());
|
assertTrue(observer.WaitForCapturerToStart());
|
||||||
observer.WaitForNextCapturedFrame();
|
observer.WaitForNextCapturedFrame();
|
||||||
// Check the frame size.
|
// Check the frame size.
|
||||||
assertEquals((format.width*format.height*3)/2, observer.frameSize());
|
assertEquals(format.frameSize(), observer.frameSize());
|
||||||
capturer.stopCapture();
|
capturer.stopCapture();
|
||||||
}
|
}
|
||||||
capturer.dispose();
|
capturer.dispose();
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "webrtc/base/json.h"
|
#include "webrtc/base/json.h"
|
||||||
#include "webrtc/base/timeutils.h"
|
#include "webrtc/base/timeutils.h"
|
||||||
#include "webrtc/base/thread.h"
|
#include "webrtc/base/thread.h"
|
||||||
|
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
@ -93,12 +94,16 @@ class AndroidVideoCapturer::FrameFactory : public cricket::VideoFrameFactory {
|
|||||||
if (!apply_rotation_ || captured_frame->rotation == kVideoRotation_0) {
|
if (!apply_rotation_ || captured_frame->rotation == kVideoRotation_0) {
|
||||||
DCHECK(captured_frame->fourcc == cricket::FOURCC_YV12);
|
DCHECK(captured_frame->fourcc == cricket::FOURCC_YV12);
|
||||||
const uint8_t* y_plane = static_cast<uint8_t*>(captured_frame_.data);
|
const uint8_t* y_plane = static_cast<uint8_t*>(captured_frame_.data);
|
||||||
const int y_stride = captured_frame->width;
|
|
||||||
const uint8_t* v_plane = y_plane +
|
// Android guarantees that the stride is a multiple of 16.
|
||||||
captured_frame->width * captured_frame->height;
|
// http://developer.android.com/reference/android/hardware/Camera.Parameters.html#setPreviewFormat%28int%29
|
||||||
const int uv_stride = (captured_frame->width + 1) / 2;
|
int y_stride;
|
||||||
const int uv_height = (captured_frame->height + 1) / 2;
|
int uv_stride;
|
||||||
const uint8_t* u_plane = v_plane + uv_stride * uv_height;
|
webrtc::Calc16ByteAlignedStride(captured_frame->width, &y_stride,
|
||||||
|
&uv_stride);
|
||||||
|
const uint8_t* v_plane = y_plane + y_stride * captured_frame->height;
|
||||||
|
const uint8_t* u_plane =
|
||||||
|
v_plane + uv_stride * webrtc::AlignInt(captured_frame->height, 2) / 2;
|
||||||
|
|
||||||
// Create a WrappedI420Buffer and bind the |no_longer_used| callback
|
// Create a WrappedI420Buffer and bind the |no_longer_used| callback
|
||||||
// to the static method ReturnFrame. The |delegate_| is bound as an
|
// to the static method ReturnFrame. The |delegate_| is bound as an
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
package org.webrtc;
|
package org.webrtc;
|
||||||
|
|
||||||
import static java.lang.Math.abs;
|
import static java.lang.Math.abs;
|
||||||
|
import static java.lang.Math.ceil;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.ImageFormat;
|
import android.graphics.ImageFormat;
|
||||||
@ -264,6 +265,11 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba
|
|||||||
public final int height;
|
public final int height;
|
||||||
public final int maxFramerate;
|
public final int maxFramerate;
|
||||||
public final int minFramerate;
|
public final int minFramerate;
|
||||||
|
// TODO(hbos): If VideoCapturerAndroid.startCapture is updated to support
|
||||||
|
// other image formats then this needs to be updated and
|
||||||
|
// VideoCapturerAndroid.getSupportedFormats need to return CaptureFormats of
|
||||||
|
// all imageFormats.
|
||||||
|
public final int imageFormat = ImageFormat.YV12;
|
||||||
|
|
||||||
public CaptureFormat(int width, int height, int minFramerate,
|
public CaptureFormat(int width, int height, int minFramerate,
|
||||||
int maxFramerate) {
|
int maxFramerate) {
|
||||||
@ -272,6 +278,33 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba
|
|||||||
this.minFramerate = minFramerate;
|
this.minFramerate = minFramerate;
|
||||||
this.maxFramerate = maxFramerate;
|
this.maxFramerate = maxFramerate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculates the frame size of this capture format.
|
||||||
|
public int frameSize() {
|
||||||
|
return frameSize(width, height, imageFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculates the frame size of the specified image format. Currently only
|
||||||
|
// supporting ImageFormat.YV12. The YV12's stride is the closest rounded up
|
||||||
|
// multiple of 16 of the width and width and height are always even.
|
||||||
|
// Android guarantees this:
|
||||||
|
// http://developer.android.com/reference/android/hardware/Camera.Parameters.html#setPreviewFormat%28int%29
|
||||||
|
public static int frameSize(int width, int height, int imageFormat) {
|
||||||
|
if (imageFormat != ImageFormat.YV12) {
|
||||||
|
throw new UnsupportedOperationException("Don't know how to calculate "
|
||||||
|
+ "the frame size of non-YV12 image formats.");
|
||||||
|
}
|
||||||
|
int yStride = roundUp(width, 16);
|
||||||
|
int uvStride = roundUp(yStride / 2, 16);
|
||||||
|
int ySize = yStride * height;
|
||||||
|
int uvSize = uvStride * height / 2;
|
||||||
|
return ySize + uvSize * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rounds up |x| to the closest value that is a multiple of |alignment|.
|
||||||
|
private static int roundUp(int x, int alignment) {
|
||||||
|
return (int)ceil(x / (double)alignment) * alignment;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getSupportedFormatsAsJson(int id) throws JSONException {
|
private static String getSupportedFormatsAsJson(int id) throws JSONException {
|
||||||
@ -312,13 +345,6 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba
|
|||||||
|
|
||||||
List<Camera.Size> supportedSizes = parameters.getSupportedPreviewSizes();
|
List<Camera.Size> supportedSizes = parameters.getSupportedPreviewSizes();
|
||||||
for (Camera.Size size : supportedSizes) {
|
for (Camera.Size size : supportedSizes) {
|
||||||
if (size.width % 16 != 0) {
|
|
||||||
// If the width is not a multiple of 16, the frames received from the
|
|
||||||
// camera will have a stride != width when YV12 is used. Since we
|
|
||||||
// currently only support tightly packed images, we simply ignore
|
|
||||||
// those resolutions.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
formatList.add(new CaptureFormat(size.width, size.height,
|
formatList.add(new CaptureFormat(size.width, size.height,
|
||||||
range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
|
range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
|
||||||
range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]));
|
range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]));
|
||||||
@ -359,9 +385,6 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba
|
|||||||
if (frameObserver == null) {
|
if (frameObserver == null) {
|
||||||
throw new RuntimeException("frameObserver not set.");
|
throw new RuntimeException("frameObserver not set.");
|
||||||
}
|
}
|
||||||
if (width % 16 != 0) {
|
|
||||||
throw new RuntimeException("width must be a multiple of 16." );
|
|
||||||
}
|
|
||||||
if (cameraThreadHandler != null) {
|
if (cameraThreadHandler != null) {
|
||||||
throw new RuntimeException("Camera has already been started.");
|
throw new RuntimeException("Camera has already been started.");
|
||||||
}
|
}
|
||||||
@ -444,6 +467,9 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba
|
|||||||
Camera.Size pictureSize = getPictureSize(parameters, width, height);
|
Camera.Size pictureSize = getPictureSize(parameters, width, height);
|
||||||
parameters.setPictureSize(pictureSize.width, pictureSize.height);
|
parameters.setPictureSize(pictureSize.width, pictureSize.height);
|
||||||
parameters.setPreviewSize(width, height);
|
parameters.setPreviewSize(width, height);
|
||||||
|
// TODO(hbos): If other ImageFormats are to be supported then
|
||||||
|
// CaptureFormat needs to be updated (currently hard-coded to say YV12,
|
||||||
|
// getSupportedFormats only returns YV12).
|
||||||
int format = ImageFormat.YV12;
|
int format = ImageFormat.YV12;
|
||||||
parameters.setPreviewFormat(format);
|
parameters.setPreviewFormat(format);
|
||||||
camera.setParameters(parameters);
|
camera.setParameters(parameters);
|
||||||
@ -685,14 +711,14 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba
|
|||||||
throw new RuntimeException("camera already set.");
|
throw new RuntimeException("camera already set.");
|
||||||
|
|
||||||
this.camera = camera;
|
this.camera = camera;
|
||||||
int newframeSize =
|
int newFrameSize = CaptureFormat.frameSize(width, height, format);
|
||||||
width * height * ImageFormat.getBitsPerPixel(format) / 8;
|
|
||||||
int numberOfEnquedCameraBuffers = 0;
|
int numberOfEnquedCameraBuffers = 0;
|
||||||
if (newframeSize != frameSize) {
|
if (newFrameSize != frameSize) {
|
||||||
// Create new frames and add to the camera.
|
// Create new frames and add to the camera.
|
||||||
// The old frames will be released when frames are returned.
|
// The old frames will be released when frames are returned.
|
||||||
for (int i = 0; i < numCaptureBuffers; ++i) {
|
for (int i = 0; i < numCaptureBuffers; ++i) {
|
||||||
Frame frame = new Frame(newframeSize);
|
Frame frame = new Frame(newFrameSize);
|
||||||
cameraFrames.add(frame);
|
cameraFrames.add(frame);
|
||||||
this.camera.addCallbackBuffer(frame.data());
|
this.camera.addCallbackBuffer(frame.data());
|
||||||
}
|
}
|
||||||
@ -706,7 +732,7 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
frameSize = newframeSize;
|
frameSize = newFrameSize;
|
||||||
Log.d(TAG, "queueCameraBuffers enqued " + numberOfEnquedCameraBuffers
|
Log.d(TAG, "queueCameraBuffers enqued " + numberOfEnquedCameraBuffers
|
||||||
+ " buffers of size " + frameSize + ".");
|
+ " buffers of size " + frameSize + ".");
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user