问题
I have found that the CameraPreview is displayed in a small area when I use the PreviewFrameLayout
and is stretched when I use the aspect ratio and the FrameLayout
.
Here is the code that I currently use to set the Camera Preview and the FrameLayout size:
private Size getOptimalPreviewSize(Activity currentActivity,
List<Size> sizes, double targetRatio) {
// Use a very small tolerance because we want an exact match.
final double ASPECT_TOLERANCE = 0.001;
if (sizes == null) return null;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
// Because of bugs of overlay and layout, we sometimes will try to
// layout the viewfinder in the portrait orientation and thus get the
// wrong size of mSurfaceView. When we change the preview size, the
// new overlay will be created before the old one closed, which causes
// an exception. For now, just get the screen size
Display display = currentActivity.getWindowManager().getDefaultDisplay();
int targetHeight = Math.min(display.getHeight(), display.getWidth());
if (targetHeight <= 0) {
// We don't know the size of SurfaceView, use screen height
targetHeight = display.getHeight();
}
// Try to find an size match aspect ratio and size
for (Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
// Cannot find the one match the aspect ratio. This should not happen.
// Ignore the requirement.
if (optimalSize == null) {
Log.w(TAG, "No preview size match the aspect ratio");
minDiff = Double.MAX_VALUE;
for (Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
//this is what I really want to use:
private Size getDesiredPictureSize(List<Size> supportedSizeList)
{
//Resolution is widthxheight
Size result=null;
final int minArea=500*500;
final int maxArea=1000*1000;
for(Size size:supportedSizeList)
{
if(size.width*size.height>minArea && size.width*size.height<maxArea)
{
if(result==null)
result=size;
else
{
int resultArea=result.width*result.height;
int sizeArea=size.width*size.height;
if(resultArea<sizeArea)
{
result=size;
}
}
}
}
return result;
}
//I am just testing with this method:
private Size getBestPictureSize(List<Size> supportedSizeList)
{
Size result=null;
for(Size size:supportedSizeList)
{
if(result==null)
result=size;
int resultArea=result.width*result.height;
int sizeArea=size.width*size.height;
if(resultArea<sizeArea)
result=size;
}
return result;
}
List<Size> supportedPictureSizes=mParameters.getSupportedPictureSizes();
List<Size> supportedPreviewSizes=mParameters.getSupportedPreviewSizes();
Log.d(TAG,"Setting picture size");
mPictureSize=getBestPictureSize(supportedPictureSizes);
Log.d(TAG,"The Picture Width: "+mPictureSize.width+" The Picture Height: "+mPictureSize.height);
double targetRatio=(double)mPictureSize.width/mPictureSize.height;
mPreviewSize=getOptimalPreviewSize(this,supportedPreviewSizes, targetRatio);
Log.d(TAG, "The Preview Width:"+mPreviewSize.width+" Preview Height: "+mPreviewSize.height);
double ratio=(double)mPreviewSize.width/mPreviewSize.height;
Log.d(TAG,"Picture Ratio: "+targetRatio);
Log.d(TAG, "Preview Ratio: "+ratio);
int new_width=0, new_height=0;
if(getResources().getConfiguration().orientation==Configuration.ORIENTATION_PORTRAIT)
{
if((double)previewFrame.getWidth()/previewFrame.getHeight()<ratio)
{
new_width=(int)(Math.round(previewFrame.getHeight()*ratio));
new_height=getWindowManager().getDefaultDisplay().getHeight();
}
else
{
new_width=getWindowManager().getDefaultDisplay().getHeight();
new_height=(int)Math.round((double)new_width/ratio);
}
}
if(getResources().getConfiguration().orientation==Configuration.ORIENTATION_LANDSCAPE)
{
if((double)previewFrame.getWidth()/previewFrame.getHeight()<ratio)
{
new_width=(int)(Math.round(previewFrame.getHeight()*ratio));
new_height=getWindowManager().getDefaultDisplay().getHeight();
}
else
{
new_width=getWindowManager().getDefaultDisplay().getWidth();
new_height=(int)Math.round((double)new_width/ratio);
}
}
//Should I set the size of the container first???
mParameters.setPictureSize(mPictureSize.width, mPictureSize.height);
mParameters.setPreviewSize(mPreviewSize.width,mPreviewSize.height);
previewFrame.setLayoutParams(new RelativeLayout.LayoutParams(new_width, new_height));
I found that using the PreviewFrameLayout
from AOSP displayed my CDamera Preview in a box and not full-screen,details of my use of PreviewFrameLayout can be found at Camera Preview does not appear full screen(displayed in a box)
回答1:
First of all, if you use FrameLayout in your xml to host previewFrame, you should also call
previewFrame.setLayoutParams(new FrameLayout.LayoutParams(new_width, new_height));
Next, you can see that whether getResources().getConfiguration().orientation
==Configuration.ORIENTATION_PORTRAIT
or Configuration.ORIENTATION_LANDSCAPE
, you do the same calculations, so this orientation is not relevant at all.
Finally, you should set the camera orientation when the screen is rotated.
I believe that you can find a [working example here] (https://stackoverflow.com/a/19448369/192373).
来源:https://stackoverflow.com/questions/21255172/camera-preview-stretched-when-using-framelayout