In love with Git and IntelliJ IDEA. Big fun of stackoverflow with more than 4000 reputation. Author of technical articles for androidweekly.net, mobile.tutsplus.com, blog.lemberg.co.uk.
William Shakespeare, Romeo and Juliet
(re-factored)
"Surface view creates a new window, placed behind your application’s window, to manage content."
"Texture View - does not create a separate window but behaves as a regular view. This key difference allows a texture view to be moved, transformed, animated, etc."
"Because it uses hardware accelerated 2D rendering - it is so fast and efficient."
AndroidManifest.xml
<uses-sdk android:minSdkVersion="14"
android:targetSdkVersion="14"/>
texture_video_simple.xml
<TextureView
android:id="@+id/textureView"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
public class CameraSimpleActivity extends Activity
implements TextureView.SurfaceTextureListener {
// Log tag
private static final String TAG = VideoAssetActivity.class.getName();
// Asset video file name.
private static final String FILE_NAME = "big_buck_bunny.mp4";
// MediaPlayer instance to control playback of video file.
private MediaPlayer mMediaPlayer;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.texture_video_simple);
initView();
}
private void initView() {
TextureView textureView = findViewById(R.id.textureView);
textureView.setSurfaceTextureListener(this);
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i2) {
// ignore
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
// ignore
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
return true;
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i2) {
Surface surface = new Surface(surfaceTexture);
AssetFileDescriptor afd = getAssets().openFd(FILE_NAME);
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setDataSource(
afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
mMediaPlayer.setSurface(surface);
mMediaPlayer.setLooping(true);
mMediaPlayer.prepareAsync();
// Play video when the media source is ready for playback.
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
}
}
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/rootView">
<TextureView
android:id="@+id/textureView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</FrameLayout>
initView();
mTextureView = (TextureView)findViewById(R.id.textureView); mTextureView.setSurfaceTextureListener(this);
FrameLayout rootView = (FrameLayout) findViewById(R.id.rootView); rootView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent motionEvent) { switch (motionEvent.getAction()) { case MotionEvent.ACTION_UP: updateTextureViewSize(
motionEvent.getX(),
motionEvent.getY()); break; } return true; } });
private void updateTextureViewSize(float viewWidth, float viewHeight) { mTextureView.setLayoutParams(new FrameLayout.LayoutParams(
(int)viewWidth, (int)viewHeight)); }
To crop video we need to know original video size
// Original video size
private float mVideoWidth;
private float mVideoHeight;
Call this method to initialize mVideoWidth and mVideoHeight variables
private void calculateVideoSize() {
AssetFileDescriptor afd = getAssets().openFd(FILE_NAME);
MediaMetadataRetriever metaRetriever
= new MediaMetadataRetriever();
metaRetriever.setDataSource(afd.getFileDescriptor(),
afd.getStartOffset(), afd.getLength());
String height = metaRetriever.extractMetadata(
MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
String width = metaRetriever.extractMetadata(
MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
mVideoHeight = Float.parseFloat(height);
mVideoWidth = Float.parseFloat(width);
}
Change updateTextureViewSize method
private void updateTextureViewSize(float viewWidth, float viewHeight) {
float scaleX = 1.0f;
float scaleY = 1.0f;
if (mVideoWidth > viewWidth && mVideoHeight > viewHeight) {
scaleX = mVideoWidth / viewWidth;
scaleY = mVideoHeight / viewHeight;
} else if (mVideoWidth < viewWidth && mVideoHeight < viewHeight) {
scaleY = viewWidth / mVideoWidth;
scaleX = viewHeight / mVideoHeight;
} else if (viewWidth > mVideoWidth) {
scaleY = (viewWidth / mVideoWidth) / (viewHeight / mVideoHeight);
} else if (viewHeight > mVideoHeight) {
scaleX = (viewHeight / mVideoHeight) / (viewWidth / mVideoWidth);
}
int pivotPointX = (int) (viewWidth / 2); // Calculate pivot points,
int pivotPointY = (int) (viewHeight / 2;) // in our case crop from center
Matrix matrix = new Matrix();
matrix.setScale(scaleX, scaleY, pivotPointX, pivotPointY);
mTextureView.setTransform(matrix);
mTextureView.setLayoutParams(new FrameLayout.LayoutParams((int) viewWidth, (int) viewHeight));
AndroidManifest.xml
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="14"/> <uses-feature android:name="android.hardware.camera"/>
<uses-permission android:name="android.permission.CAMERA"/>
public class CameraSimpleActivity extends Activity
implements TextureView.SurfaceTextureListener {
// Log tag
private static final String TAG = CameraSimpleActivity.class.getName();
private Camera mCamera;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextureView textureView = new TextureView(this);
textureView.setSurfaceTextureListener(this);
setContentView(textureView);
}
@Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { Log.d(TAG, "SurfaceTexture width: " + width + " height: " + height); mCamera = Camera.open();
try { mCamera.setPreviewTexture(surface); mCamera.startPreview(); } catch (IOException e) { Log.d(TAG, e.getMessage()); } }
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
// Ignored, Camera does all the work for us
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
// Invoked every time there's a new Camera preview frame
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
}
return true;
}
<uses-feature android:name="android.hardware.camera" android:required="true" />
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
// This device has a Camera
} else {
// This device doesn't have a Camera
}
Camera c = null; try { c = Camera.open(); // attempt to get a Camera instance }catch (Exception e){
// Camera is not available }
<activity
android:name=".CameraActivity"
android:screenOrientation="landscape"/>
private Camera.Size getBestPreviewSize( int requiredWidth,
int requiredHeight, Camera.Parameters parameters) {
Camera.Size result = null;
for (Camera.Size currentSize : parameters.getSupportedPreviewSizes()) {
if (currentSize.width <= requiredWidth
&& currentSize.height <= requiredHeight) {
if (result == null) {
result = currentSize;
} else {
int resultArea = result.width * result.height;
int newArea = currentSize.width * currentSize.height;
if (newArea > resultArea) {
result = currentSize;
}
}
}
return result;
}
// get Camera parameters
Camera.Parameters params = mCamera.getParameters();
List<String> focusModes = params.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
// Auto-focus mode is supported
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
// set Camera parameters
mCamera.setParameters(params);
}
@Override
protected void onPause() {
// release the camera for other applications
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}