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,711