CONTENT STREAM
Android Tragedy
by Dmytro Danylyk & William Shakespeare
characters
Romeo - is the son of Montague (Developer)
Juliet - is the daughter of Capulet (Designer)
Prehistory
Montague (Developers) and Capulet (Designers) - are involved in a team feud that goes back years before any of the members were born.
once upon a time
Juliet meets Romeo on android project discussion where displaying video must take place.
"To Intent, or not to Intent, that is the question?" - Romeo
IMPLICIT INTENT
Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.parse("http://www.yourvideo.mp4"), "video/mp4"); String title = "Play this video with"; Intent chooser = Intent.createChooser(intent, title); // Verify the intent will resolve to at least one activtiy if(intent.resolveActivity(getPackageManager()) != null) { startActivity(chooser); }
"We need a custom..." - Juliet
when to intent?
- when functionality is hard to implement (send email)
- when you need social sharing (facebook, twitter)
- when you don't need extra functionality (play video)
the
tragical history of
video View
what romeo think will work
VideoView videoView = (VideoView) findViewById(R.id.videoView); videoView.setVideoPatn("http://www.yourvideo.mp4"); videoView.start();
"I forgot to tell..." - Juliet
"We need to make it draggable like in YouTube app"
"We need to display list of videos like in Instagram app"
"Could you remove black lines"
welcome to world of black pixels
what happenS when you scroll
what happenS when you animate
what happenS if you crop
why are you doing this to me?
"Surface view creates a new window, placed behind your application’s window, to manage content."
How it works?
Chestburster design pattern - make a hole in your application to inject extra functionality.
problems
- Unexpected behavior inside scrollable container
-
Unexpected behavior with animations
- No way to crop content
Texture View
when to use?
- Play Video
- Stream Camera
- Render OpenGL
Why to use?
"Texture View - does not create a separate window but behaves as a regular view."
"Because it uses hardware accelerated 2D rendering - it is so fast and efficient."
REQUIREMENTS
- API level 14
- Hardware Acceleration
quickstart
basic logic
TextureView textureView = findViewById(R.id.textureView); textureView.setSurfaceTextureListener( new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) { // all logic goes here } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { // ignore } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { return true; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { // ignore } });
video from assets
// all logic goes here Surface surface = new Surface(texture); AssetFileDescriptor afd = getAssets().openFd("big_buck_bunny.mp4"); FileDescriptor fileDescriptor = afd.getFileDescriptor(); long startOffset = afd.getStartOffset(); long length = afd.getLength(); mMediaPlayer = new MediaPlayer(); mMediaPlayer.setDataSource(fileDescriptor, startOffset, length); mMediaPlayer.setSurface(surface); 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(); } });
clean up
@Override protected void onDestroy() { super.onDestroy(); if (mMediaPlayer != null) { mMediaPlayer.stop(); mMediaPlayer.release(); mMediaPlayer = null; } }
camera
// all logic goes here mCamera = Camera.open(); if (mCamera == null) { Log.d(TAG, "Your device doesn't have camera."); return; } mCamera.setPreviewTexture(surface); mCamera.startPreview();
@Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { if (mCamera != null) { mCamera.stopPreview(); mCamera.release(); } return true; }
more info
github.com/dmytrodanylyk/dmytrodanylyk
Texture Video View
"TextureVideoView - is custom view based on android TextureView which gives you ability easily play and crop video.
why to use?
W/MediaPlayer﹕ info/warning (1, 26)
E/MediaPlayer﹕ error (1, -4)
E/MediaPlayer: error (1, -2147483648)
E/MediaPlayer﹕ start called in state 4
E/MediaPlayer﹕ error (-38, 0)
E/MediaPlayer﹕ Error (-38,0)
how it looks?
QUICKSTART
<com.dd.crop.TextureVideoView android:id="@+id/cropTextureView" android:layout_width="fill_parent" android:layout_height="wrap_content"/>
TextureVideoView cropTextureView = (TextureVideoView) findViewById(R.id.cropTextureView); // Use `setScaleType` method to crop video cropTextureView.setScaleType(TextureVideoView.ScaleType.TOP); // Use `setDataSource` method to set data source, this could be url, assets folder or path cropTextureView.setDataSource("http://www.w3schools.com/html/mov_bbb.mp4"); cropTextureView.play();
what inside?
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 = viewWidth / 2; // Calculate pivot points, int pivotPointY = viewHeight / 2; // in our case crop from center Matrix matrix = new Matrix(); matrix.setScale(scaleX, scaleY, pivotPointX, pivotPointY); mTextureView.setTransform(matrix);
more info
github.com/dmytrodanylyk/android-video-crop
Camera Issues
Prevent from appearing in Google Play
<uses-feature android:name="android.hardware.camera" android:required="true" />
Check if device has camera
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) { // This device has a Camera } else { // This device doesn't have a Camera }
Check if camera is available
Camera c = null; try { c = Camera.open(); // attempt to get a Camera instance } catch (Exception e) { // Camera is not available }
Lock activity screen orientation
<activity android:name=".CameraActivity" android:screenOrientation="portrait" />
Calculate camera orientation
void setCameraDisplayOrientation(Activity activity, int cameraId, Camera camera) { Camera.CameraInfo info = new Camera.CameraInfo(); Camera.getCameraInfo(cameraId, info); int rotation = activity.getWindowManager().getDefaultDisplay().getRotation(); int degrees = 0; switch (rotation) { case Surface.ROTATION_0: degrees = 0; break; case Surface.ROTATION_90: degrees = 90; break; case Surface.ROTATION_180: degrees = 180; break; case Surface.ROTATION_270: degrees = 270; break; } int result; if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { result = (info.orientation + degrees) % 360; result = (360 - result) % 360; // compensate the mirror 1 } else { // back-facing result = (info.orientation - degrees + 360) % 360; camera.setDisplayOrientation(result); } }
Calculate preview size
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; }
Check if feature is available before using it
// get Camera parameters Camera.Parameters params = mCamera.getParameters(); List 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); }
Don't lock camera forever, you are not alone
@Override protected void onPause() { super.onPause(); // release the camera for other applications if(mCamera != null) { mCamera.release(); mCamera = null; } }
Content Stream - Android Tragedy
By Dmytro Danylyk
Content Stream - Android Tragedy
- 4,991