Java tutorial
/* * MainActivity.java * Copyright (c) 2012 Jacek Marchwicki * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.ffmpegtest; import java.io.File; import java.util.HashMap; import java.util.Locale; import android.animation.ObjectAnimator; import android.annotation.TargetApi; import android.app.Activity; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.ActivityInfo; import android.database.Cursor; import android.database.MatrixCursor; import android.graphics.PixelFormat; import android.graphics.RectF; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.provider.BaseColumns; import android.support.v4.widget.SimpleCursorAdapter; import android.view.View; import android.view.View.OnClickListener; import android.view.Window; import android.view.WindowManager; import android.view.animation.AccelerateDecelerateInterpolator; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.Button; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.Spinner; import com.appunite.ffmpeg.FFmpegDisplay; import com.appunite.ffmpeg.FFmpegError; import com.appunite.ffmpeg.FFmpegListener; import com.appunite.ffmpeg.FFmpegPlayer; import com.appunite.ffmpeg.FFmpegStreamInfo; import com.appunite.ffmpeg.FFmpegStreamInfo.CodecType; import com.appunite.ffmpeg.FFmpegSurfaceView; import com.appunite.ffmpeg.FFmpegSurfaceView.ScaleType; import com.appunite.ffmpeg.NotPlayingException; import com.ffmpegtest.helpers.PropertyDestinationRect; import com.ffmpegtest.helpers.RectEvaluator; public class VideoActivity extends Activity implements OnClickListener, FFmpegListener, OnSeekBarChangeListener, OnItemSelectedListener { private static final String[] PROJECTION = new String[] { "title", BaseColumns._ID }; private static final int PROJECTION_ID = 1; private static boolean sIsSurfaceView = true; private FFmpegPlayer mMpegPlayer; protected boolean mPlay = false; private View mControlsView; private View mLoadingView; private SeekBar mSeekBar; private View mVideoView; private Button mPlayPauseButton; private boolean mTracking = false; private View mStreamsView; private Spinner mLanguageSpinner; private int mLanguageSpinnerSelectedPosition = 0; private Spinner mSubtitleSpinner; private int mSubtitleSpinnerSelectedPosition = 0; private SimpleCursorAdapter mLanguageAdapter; private SimpleCursorAdapter mSubtitleAdapter; private int mAudioStreamNo = FFmpegPlayer.UNKNOWN_STREAM; private int mSubtitleStreamNo = FFmpegPlayer.NO_STREAM; private View mScaleButton; @Override public void onCreate(Bundle savedInstanceState) { this.getWindow().requestFeature(Window.FEATURE_NO_TITLE); getWindow().setFormat(PixelFormat.RGB_565); getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DITHER); super.onCreate(savedInstanceState); this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); this.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); this.getWindow().setBackgroundDrawable(null); this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); if (sIsSurfaceView) this.setContentView(R.layout.video_surfaceview); else this.setContentView(R.layout.video_view); mSeekBar = (SeekBar) this.findViewById(R.id.seek_bar); mSeekBar.setOnSeekBarChangeListener(this); mPlayPauseButton = (Button) this.findViewById(R.id.play_pause); mPlayPauseButton.setOnClickListener(this); mScaleButton = this.findViewById(R.id.scale_type); mScaleButton.setOnClickListener(this); mControlsView = this.findViewById(R.id.controls); mStreamsView = this.findViewById(R.id.streams); mLoadingView = this.findViewById(R.id.loading_view); mLanguageSpinner = (Spinner) this.findViewById(R.id.language_spinner); mSubtitleSpinner = (Spinner) this.findViewById(R.id.subtitle_spinner); mLanguageAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_spinner_item, null, PROJECTION, new int[] { android.R.id.text1 }, 0); mLanguageAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); mLanguageSpinner.setAdapter(mLanguageAdapter); mLanguageSpinner.setOnItemSelectedListener(this); mSubtitleAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_spinner_item, null, PROJECTION, new int[] { android.R.id.text1 }, 0); mSubtitleAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); mSubtitleSpinner.setAdapter(mSubtitleAdapter); mSubtitleSpinner.setOnItemSelectedListener(this); mVideoView = this.findViewById(R.id.video_view); ((FFmpegSurfaceView) mVideoView).setScaleType(ScaleType.CENTER_INSIDE, false); mMpegPlayer = new FFmpegPlayer((FFmpegDisplay) mVideoView, this); mMpegPlayer.setMpegListener(this); setDataSource(); } @Override protected void onPause() { super.onPause(); }; @Override protected void onResume() { super.onResume(); } @Override protected void onDestroy() { super.onDestroy(); this.mMpegPlayer.setMpegListener(null); this.mMpegPlayer.stop(); stop(); } private void setDataSource() { HashMap<String, String> params = new HashMap<String, String>(); // set font for ass File assFont = new File(Environment.getExternalStorageDirectory(), "DroidSansFallback.ttf"); params.put("ass_default_font_path", assFont.getAbsolutePath()); Intent intent = getIntent(); String url = intent.getStringExtra(AppConstants.VIDEO_PLAY_ACTION_EXTRA_URL); if (url == null) { throw new IllegalArgumentException( String.format("\"%s\" did not provided", AppConstants.VIDEO_PLAY_ACTION_EXTRA_URL)); } if (intent.hasExtra(AppConstants.VIDEO_PLAY_ACTION_EXTRA_ENCRYPTION_KEY)) { params.put("aeskey", intent.getStringExtra(AppConstants.VIDEO_PLAY_ACTION_EXTRA_ENCRYPTION_KEY)); } this.mPlayPauseButton.setBackgroundResource(android.R.drawable.ic_media_play); this.mPlayPauseButton.setEnabled(true); mPlay = false; mMpegPlayer.setDataSource(url, params, FFmpegPlayer.UNKNOWN_STREAM, mAudioStreamNo, mSubtitleStreamNo); } @Override public void onClick(View v) { int viewId = v.getId(); switch (viewId) { case R.id.play_pause: resumePause(); return; case R.id.scale_type: swapScaleType(); return; default: throw new RuntimeException(); } } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) private void swapScaleType() { FFmpegSurfaceView view = (FFmpegSurfaceView) mVideoView; FFmpegSurfaceView.ScaleType scaleType = view.getScaleType(); ScaleType newScaleType; if (ScaleType.CENTER_INSIDE.equals(scaleType)) { newScaleType = ScaleType.CENTER_CROP; } else if (ScaleType.CENTER_CROP.equals(scaleType)) { newScaleType = ScaleType.FIT_XY; } else { newScaleType = ScaleType.CENTER_INSIDE; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { view.setScaleType(newScaleType, true); RectF dst = new RectF(); view.calculateRect(dst, newScaleType); ObjectAnimator anim = ObjectAnimator.ofObject(view, "destinationRect", new RectEvaluator(), dst); anim.setInterpolator(new AccelerateDecelerateInterpolator()); anim.start(); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { view.setScaleType(newScaleType, true); RectF dst = new RectF(); view.calculateRect(dst, newScaleType); ObjectAnimator anim = ObjectAnimator.ofObject(view, new PropertyDestinationRect(), new RectEvaluator(), dst); anim.setInterpolator(new AccelerateDecelerateInterpolator()); anim.start(); } else { view.setScaleType(newScaleType, false); } } @Override public void onFFUpdateTime(int currentTimeS, int videoDurationS, boolean isFinished) { if (!mTracking) { mSeekBar.setMax(videoDurationS); mSeekBar.setProgress(currentTimeS); } if (isFinished) { new AlertDialog.Builder(this).setTitle(R.string.dialog_end_of_video_title) .setMessage(R.string.dialog_end_of_video_message).setCancelable(true).show(); } } @Override public void onFFDataSourceLoaded(FFmpegError err, FFmpegStreamInfo[] streams) { if (err != null) { String format = getResources().getString(R.string.main_could_not_open_stream); String message = String.format(format, err.getMessage()); Builder builder = new AlertDialog.Builder(VideoActivity.this); builder.setTitle(R.string.app_name).setMessage(message) .setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { VideoActivity.this.finish(); } }).show(); return; } mPlayPauseButton.setBackgroundResource(android.R.drawable.ic_media_play); mPlayPauseButton.setEnabled(true); this.mControlsView.setVisibility(View.VISIBLE); this.mStreamsView.setVisibility(View.VISIBLE); this.mLoadingView.setVisibility(View.GONE); this.mVideoView.setVisibility(View.VISIBLE); MatrixCursor audio = new MatrixCursor(PROJECTION); MatrixCursor subtitles = new MatrixCursor(PROJECTION); subtitles.addRow(new Object[] { "None", FFmpegPlayer.NO_STREAM }); for (FFmpegStreamInfo streamInfo : streams) { CodecType mediaType = streamInfo.getMediaType(); Locale locale = streamInfo.getLanguage(); String languageName = locale == null ? getString(R.string.unknown) : locale.getDisplayLanguage(); if (FFmpegStreamInfo.CodecType.AUDIO.equals(mediaType)) { audio.addRow(new Object[] { languageName, streamInfo.getStreamNumber() }); } else if (FFmpegStreamInfo.CodecType.SUBTITLE.equals(mediaType)) { subtitles.addRow(new Object[] { languageName, streamInfo.getStreamNumber() }); } } mLanguageAdapter.swapCursor(audio); mSubtitleAdapter.swapCursor(subtitles); } private void displaySystemMenu(boolean visible) { if (Build.VERSION.SDK_INT >= 14) { displaySystemMenu14(visible); } else if (Build.VERSION.SDK_INT >= 11) { displaySystemMenu11(visible); } } @SuppressWarnings("deprecation") @TargetApi(11) private void displaySystemMenu11(boolean visible) { if (visible) { this.mVideoView.setSystemUiVisibility(View.STATUS_BAR_VISIBLE); } else { this.mVideoView.setSystemUiVisibility(View.STATUS_BAR_HIDDEN); } } @TargetApi(14) private void displaySystemMenu14(boolean visible) { if (visible) { this.mVideoView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); } else { this.mVideoView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE); } } public void resumePause() { this.mPlayPauseButton.setEnabled(false); if (mPlay) { mMpegPlayer.pause(); } else { mMpegPlayer.resume(); displaySystemMenu(true); } mPlay = !mPlay; } @Override public void onFFResume(NotPlayingException result) { this.mPlayPauseButton.setBackgroundResource(android.R.drawable.ic_media_pause); this.mPlayPauseButton.setEnabled(true); displaySystemMenu(false); mPlay = true; } @Override public void onFFPause(NotPlayingException err) { this.mPlayPauseButton.setBackgroundResource(android.R.drawable.ic_media_play); this.mPlayPauseButton.setEnabled(true); mPlay = false; } private void stop() { this.mControlsView.setVisibility(View.GONE); this.mStreamsView.setVisibility(View.GONE); this.mLoadingView.setVisibility(View.VISIBLE); this.mVideoView.setVisibility(View.INVISIBLE); } @Override public void onFFStop() { } @Override public void onFFSeeked(NotPlayingException result) { // if (result != null) // throw new RuntimeException(result); } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { mMpegPlayer.seek(progress); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { mTracking = true; } @Override public void onStopTrackingTouch(SeekBar seekBar) { mTracking = false; } private void setDataSourceAndResumeState() { int progress = mSeekBar.getProgress(); setDataSource(); mMpegPlayer.seek(progress); mMpegPlayer.resume(); } @Override public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) { Cursor c = (Cursor) parentView.getItemAtPosition(position); if (parentView == mLanguageSpinner) { if (mLanguageSpinnerSelectedPosition != position) { mLanguageSpinnerSelectedPosition = position; mAudioStreamNo = c.getInt(PROJECTION_ID); setDataSourceAndResumeState(); } } else if (parentView == mSubtitleSpinner) { if (mSubtitleSpinnerSelectedPosition != position) { mSubtitleSpinnerSelectedPosition = position; mSubtitleStreamNo = c.getInt(PROJECTION_ID); setDataSourceAndResumeState(); } } else { throw new RuntimeException(); } } @Override public void onNothingSelected(AdapterView<?> parentView) { // if (parentView == languageSpinner) { // audioStream = null; // } else if (parentView == subtitleSpinner) { // subtitleStream = null; // } else { // throw new RuntimeException(); // } // play(); } }