使用第三方库录制视频时TextureView预览拉伸问题求助
Hey there, let's work through this camera preview stretching issue you're hitting! This is a super common pain point when integrating third-party camera libraries, especially with TextureView-based previews. Let's break down the root cause and actionable fixes step by step.
Root Cause
The stretching happens because the aspect ratio of your camera's preview resolution doesn't match the aspect ratio of your AutoFitTextureView. When the two ratios don't align, the system will stretch the preview to fill the view, leading to that distorted look in your screenshots.
Step 1: Verify Camera Preview Resolution
First, you need to confirm what resolution the camera is actually using for preview. Most third-party libraries let you access or set the preview size—look for code that deals with Camera.Parameters (for legacy camera) or CameraCharacteristics (for CameraX).
- Print out all supported preview sizes for your camera, then pick one that matches your device's screen aspect ratio (or the closest possible). For example, if your device has a 16:9 screen, prioritize preview sizes like 1920x1080, 1280x720, etc.
- If the library hardcodes a preview size, check if you can override it to a ratio that fits your screen.
Step 2: Fix AutoFitTextureView's Aspect Ratio Logic
Let's refine your AutoFitTextureView—the onMeasure method is critical here. If it's not calculating the view size correctly based on the camera's preview ratio, you'll get stretching. Here's a corrected version that handles both portrait and landscape orientations properly:
public class AutoFitTextureView extends TextureView { private int mRatioWidth = 0; private int mRatioHeight = 0; public AutoFitTextureView(Context context) { this(context, null); } public AutoFitTextureView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio * calculated from the parameters. Note that the actual sizes of parameters don't matter, that * is, calling setAspectRatio(2, 3) is the same as calling setAspectRatio(4, 6). * * @param width Relative horizontal size * @param height Relative vertical size */ public void setAspectRatio(int width, int height) { if (width < 0 || height < 0) { throw new IllegalArgumentException("Size cannot be negative."); } mRatioWidth = width; mRatioHeight = height; requestLayout(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); if (0 == mRatioWidth || 0 == mRatioHeight) { setMeasuredDimension(width, height); } else { // Calculate the correct size to maintain the preview aspect ratio if (width < height * mRatioWidth / mRatioHeight) { setMeasuredDimension(width, width * mRatioHeight / mRatioWidth); } else { setMeasuredDimension(height * mRatioWidth / mRatioHeight, height); } } } }
Key fixes here:
- The ratio is based on the camera's preview size (e.g., if preview is 1920x1080, pass
1920and1080tosetAspectRatio), not the screen's orientation. - The
onMeasurelogic ensures the view scales to fit the parent while preserving the exact preview ratio—no stretching, just letterboxing if needed.
Step 3: Link Camera Preview Size to AutoFitTextureView
Once you have the correct preview resolution from the camera, make sure to pass its width and height to AutoFitTextureView.setAspectRatio() after initializing the camera. For example:
// After getting the camera's preview size (e.g., from library callback or parameters) Size previewSize = cameraPreview.getPreviewSize(); autoFitTextureView.setAspectRatio(previewSize.getWidth(), previewSize.getHeight());
If the third-party library doesn't expose the preview size directly, you might need to dig into its source code to find where it sets the camera parameters, or add a listener to capture the preview size when it's initialized.
Step 4: Handle Screen Rotation
When the device rotates, you need to re-calculate the view size to maintain the aspect ratio. Add this to your Activity/Fragment:
@Override public void onConfigurationChanged(@NonNull Configuration newConfig) { super.onConfigurationChanged(newConfig); // Re-set the aspect ratio with the current camera preview size Size previewSize = cameraPreview.getPreviewSize(); if (previewSize != null) { autoFitTextureView.setAspectRatio(previewSize.getWidth(), previewSize.getHeight()); } }
This ensures the view adjusts correctly when switching between portrait and landscape.
Debugging Tips
- Log the camera preview size and the measured size of your AutoFitTextureView to confirm their ratios match. For example:
If the ratios are the same, stretching should be gone.Log.d("CameraPreview", "Preview ratio: " + previewSize.getWidth() + "/" + previewSize.getHeight()); Log.d("AutoFitView", "View ratio: " + autoFitTextureView.getMeasuredWidth() + "/" + autoFitTextureView.getMeasuredHeight()); - If the library uses a fixed preview size that doesn't match your screen, check if it has an API to customize the preview resolution (many libraries let you pass a preferred ratio or size).
内容的提问来源于stack exchange,提问作者Pritesh Vishwakarma

