Bizarre Invalidate behaviour - android

I have a custom viewgroup (Custom2) inside a custom viewgroup (Custom1).
Custom1 has an imageview displaying a RectShape Shapedrawable and two textviews.
I set an onClickListener in Custom2 which removes the imageview using this.removeViewAt(0) and creates a new TextureView, then calling this.addView (mTextureView, 0) and finally invalidate. I then get the textureview to play a video using mediaplayer.
Here is the code:
public void setToTextureView() {
//TextureView when not debugging
TextureView View;
View = (TextureView) new TextureView(mContext);
View.setLayoutParams(new LayoutParams(600, 500));
this.removeViewAt(0);
this.addView(View, 0);
View.invalidate();
Log.d("Debug", "Invalidate Called");
View.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Surface mSurface = new Surface(surface);
MediaPlayer mMediaPlayer = new MediaPlayer(); //Debug MediaPlayer issues by setting ItemToDebug = "MediaPlayer"
try {
mMediaPlayer.setDataSource(mContext, Uri.parse("android.resource://" + mContext.getPackageName() + "/" + R.raw.t));
if (ItemToDebug.equals("MediaPlayer")) {
Log.d("MediaPlayer", "Data source set");
}
mMediaPlayer.setSurface(mSurface);
if (ItemToDebug.equals("MediaPlayer")) {
Log.d("MediaPLayer", "Surface set");
}
mMediaPlayer.prepare();
if (ItemToDebug.equals("MediaPlayer")) {
Log.d("MediaPLayer", "Prepared");
}
} catch (IOException e) {
Log.d("IOException", e.getMessage());
}
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
if (ItemToDebug.equals("MediaPlayer")) {
Log.d("Debug", "Media Player Prepared");
}
mp.start();
}
});
}
Now, I notice bizarrely that the ImageView disappears and an empty space appears (of the correct size) when I click the view, but no video plays, although the code appears to execute fine upto invalidate();
However, I can then get the TextureView to get a surfaceTexture and play the video when I interrupt the program and go back in (i.e by pressing the button that takes you to the screen with all the open programs, and selecting my activity again.)
I don't have a good understanding of exactly what is happening but I am pretty sure that no SurfaceTexture is being created because onAttached() isn't being called.
Does anybody know what might be going on?
Cheers,
J

The view disappears, I need to call requestLayout() in order to draw something else there.

Related

android app with multiple media players in same activity - how to use efficiently

I am creating an android activity that will have many mediaplayers inside. The activity will have many mediaplayer objects and if i could describe it its like a
4 X 1 grid of media players. I created the 4X1 grid by using TextureView class's in android.
so the xml layout for the activity looks like this more or less:
<TextureView
android:id="#+id/surface_one"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextureView
android:id="#+id/surface_two"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextureView
android:id="#+id/surface_three"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextureView
android:id="#+id/surface_four"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
So each textureView will be the surface where the MediaPlayers will play there video.
programatically i've set up SurfaceTextureListener's so that i know when the surface is available like this for each one:
TextureView tv1 = (TextureView)findViewById(R.id.surface_one);
tv1.setSurfaceTextureListener(new SurfaceListener_1());
and likewise for the rest. here is how i would do the second texture view setup:
TextureView tv2 = (TextureView)findViewById(R.id.surface_two);
tv2.setSurfaceTextureListener(new SurfaceListener_2());
Then in code i am creating 4 MediaPlayer Objects and setting there surface like this for mediaplayer #1:
private class SurfaceListener_1 implements TextureView.SurfaceTextureListener {
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Surface sfc = new Surface(surface);
try {
m_mp1 = new MediaPlayer();
m_mp1.setSurface(sfc); //critical , here i am adding the surface so the media player can play on it
m_mp1.setDataSource(m_context, m_videoUri_one);
m_mp1.prepareAsync();
m_mp1.setLooping(true);
m_mp1.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
video1Prepared = true;
}
});
m_mp1.setOnErrorListener(new MediaPlayer.OnErrorListener(){
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
return true;
}
});
} catch (Exception e) {
e.printStackTrace();
}
finally {
//release the surface as its now set in the media player
if(sfc!=null)
sfc.release();
}
}
//...... the rest of the call backs not important...
and for the other media players i repeat the same thing so that they all have surfaces to play on. here is how i would do mediaplayer # 2:
private class SurfaceListener_2 implements TextureView.SurfaceTextureListener {
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Surface sfc = new Surface(surface);
try {
m_mp2 = new MediaPlayer();
m_mp2.setSurface(sfc); //critical , here i am adding the surface so the media player can play on it
m_mp2.setDataSource(m_context, m_videoUri_two);
m_mp2.prepareAsync();
m_mp2.setLooping(true);
m_mp2.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
video2Prepared = true;
}
});
m_mp2.setOnErrorListener(new MediaPlayer.OnErrorListener(){
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
return true;
}
});
} catch (Exception e) {
e.printStackTrace();
}
finally {
//release the surface as its now set in the media player
if(sfc!=null)
sfc.release();
}
}
//...... the rest of the call backs not important...
so in the end what i have created is 4 surfaces where i can play a video. All 4 media players play different video files.
Once all the media players are prepared, i call their start() method on all of them and they play at the same time.
The issue i am facing is that this can be cpu intensive. On some devices i can get a ANR or the app just gets slow to respond.
The media file i am playing is a MP4 and the size of the media files are all about 9 MB.
Is there anything you can recommend so that i can be more cpu efficient in this already heavy task ? For example, can i get the GPU to help ?
Or if i change media type will that make it more efficient ? the video's do not have sound there only visual if that helps.

Playing video in TextureView crash when resuming from onPause

If I pause my activity, on returning I get a crash
Caused by: java.lang.IllegalStateException
at android.media.MediaPlayer.prepareAsync(Native Method)
I want to be able to return to exactly where the video left off and continue from there. I also want it to survive orientations, which it is not doing right now. Thanks for any hint on how to accomplish this. I am not using ExoPlayer because I want to stay with API 14, instead of bumping to API-16 and lose some users.
My setup is Activity -> Fragment {TextureView}. In portrait the fragment is half of the screen; in landscape the fragment is fullscreen.
code snippet
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
surface = new Surface(surfaceTexture);
playVideoNow();
}
private void playVideoNow() {
if(null== textureView || null==surface || null==mCurrVideo) return;
try {
final String url = mCurrVideo.getUrl();
mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(getContext(), Uri.parse(url));
mediaPlayer.setSurface(surface);
mediaPlayer.setLooping(false);
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer player) {
mediaPlayer.start();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
playVideoNow() is called from multiple possible places such as onResume on BroadcastReceiver, hence the checks to see if everything is in order. Also the

android mediaplayer does not play video, only audio when rotating surfaceview

Edit: My issue not solved yet!
Hello stackoverflow friends.
I wrote a video player which can play my recorded videos. But there was rotating 90 degree problem when showing. I used from mediaRecorder.setOrientationHint(int degree) ,but I guess My video player ignores the composition matrix in video during palyback( according to setOrientationHint documentation),Because this method hasn’t any effect on rotation. Finally I decided directly in my video player editing surfaceView by rotating canvas matrix. But this way has this issue which cant show my video in surface view. Only I can hear voice without any showing! How can I resolve this issue?
If there are other ways for rotating my video in surfaceView I want know about those ways. I searched a lot for rotating but I couldnt get any success.
This is most importants piece of my code.
public class VideoPlayerActivity extends Activity implements
SurfaceHolder.Callback
{
private SurfaceView mPreview;
private SurfaceHolder holder;
private MediaPlayer mPlayer;
//-------------------------------------------
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.video_player);
InitializeUI();
}
//------------------------------------------
private void InitializeUI()
{
mPreview = (SurfaceView) findViewById(R.id.surface_view);
holder = mPreview.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_NORMAL);
}
//------------------------------------------
private void playVideo(Integer Media)
{
try {
Canvas canvas=holder.lockCanvas();
Matrix mat=canvas.getMatrix();
mat.postRotate(90);
canvas.setMatrix(mat);
holder.unlockCanvasAndPost(canvas);
mPlayer.reset();
mPlayer.setDataSource(ArrayManager.array_for_playing.get(SDcard.icurrentIndex).getPath());
mPlayer.setDisplay(holder);
mPlayer.prepare();
mPlayer.start();
}
catch (Exception e)
{
Log.e("video player", "error: " + e.getMessage(), e);
}
}
//------------------------------------------
#Override
public void surfaceCreated(SurfaceHolder holder)
{
if(ArrayManager.array_for_playing != null)
if(SDcard.icurrentIndex != -1)
playVideo(SDcard.icurrentIndex);
}
.
.
.
}
You have to recreate your Media Player (mPlayer).
Just reuse your holder

VideoView is not displayed on a Fragment

I have a problem in running a video in Samsung S3(Android 4.1.1), the issue seems to be because the videoview is on a fragment because if I put it on and activity, it works.
Also I found out that if I turn on the GPU hardware acceleration on, the video works.
I have also a game made by drawing on a SurfaceView and that view doesn't work as well(only with GPU on)... The rest of the app content is displayed as it supposed to (buttons and other layouts).
I tested the app on Nexus S and on the emulator and it works fine, also on other devices..
Does anyone know what the problem could be?
Thank you!
And here is the code:
public class VideoFragment extends Fragment implements MediaPlayer.OnCompletionListener,
MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener {
private Video mVideo;
private VideoView mVideoView;
// The video position
private int mPosition;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View fragmentView = inflater.inflate(R.layout.screen_video, container, false);
mVideoView = (VideoView) fragmentView.findViewById(R.id.VideoView);
return fragmentView;
}
#Override
public void onPause() {
super.onPause();
// Pause the video if it is playing
if (mVideoView.isPlaying()) {
mVideoView.pause();
}
// Save the current video position
mPosition = mVideoView.getCurrentPosition();
}
#Override
public void onResume() {
super.onResume();
mVideoView.setOnCompletionListener(this);
mVideoView.setOnPreparedListener(this);
mVideoView.setOnErrorListener(this);
mVideoView.setKeepScreenOn(true);
// Initialize the media controller
MediaController mediaController = new MediaController(getActivity());
mediaController.setMediaPlayer(mVideoView);
// Set-up the video view
mVideoView.setMediaController(mediaController);
mVideoView.requestFocus();
mVideoView.setVideoPath(mVideo.getUrl());
if (mVideoView != null) {
// Restore the video position
mVideoView.seekTo(mPosition);
mVideoView.requestFocus();
}
}
#Override
public void onDestroy() {
super.onDestroy();
// Clean-up
if (mVideoView != null) {
mVideoView.stopPlayback();
mVideoView = null;
}
}
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
Log.e("VIDEO PLAY", "end video play");
}
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
// Start the video view
mediaPlayer.start();
Log.e("VIDEO PLAY", "video ready for playback");
}
#Override
public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
Log.e("VIDEO PLAY", "error: " + i);
return true;
}
}
I don't think it's something related to context(Application or Activity).. because on all other devices the Video and the games are displayed..
Thanks for the help!
I have a similar problem, and i solved it changing:
MediaController mediaController = new MediaController(getActivity().getApplicationContext());
to this (In a fragmet):
MediaController mediaController = new MediaController(getActivity());
Hope this helps,...
EDIT
Look at this class
http://code.google.com/p/sinaweibo-honeycomb/source/browse/branches/sinaweibo-merged/src/com/lenovo/dll/SinaWeibo/VideoFragment.java?r=71
If hardware acceleration fixes your issue then I would enable it for that view/window on that device.
In general I've found that when code works on one device but not another it is typically caused by one of the following problems:
Bug in the manufacturer's API implementation
Different interpretation of the API by the manufacturer
Concurrency problem (e.g. race condition, improper synchronization) in your own code that happens to trigger more frequently on a particular device
As far as I can tell you seem to be using the UI thread appropriately so I would imagine your issue falls into one of the first two categories and you'll just need to work around it.
Move MediaController mediaController = new MediaController(getActivity()) from onResume() to onCreateView.

How to detect when VideoView starts playing (Android)?

Here's the problem, I want to change play button to pause button when the video stream starts playing in videoview but I don't know how to detect that event?
There is a great article about MediaPlayer in here - http://www.malmstein.com/blog/2014/08/09/how-to-use-a-textureview-to-display-a-video-with-custom-media-player-controls/
You can set infoListener on your VideoView
setOnInfoListener(new MediaPlayer.OnInfoListener() {
#Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
// Here the video starts
return true;
}
return false;
}
I ended up using VideoView.setOnPreparedListener. This was enough to cover my problem (play button drawable change to pause)
accepted answer here is not 100% accurate.
sometimes onprepared is call 3 seconds before first frame is being rendered. i suggest having a callback on that event (MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START)
mMediaPlayer.setOnInfoListener(new MediaPlayer.OnInfoListener() {
#Override
public boolean onInfo(MediaPlayer mediaPlayer, int i, int i1) {
if (i == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START){
//first frame was bufered - do your stuff here
}
return false;
}
});
see media info documantaion for more callbacks of info/warning:
https://developer.android.com/reference/android/media/MediaPlayer.html#MEDIA_INFO_VIDEO_RENDERING_START
As far as I know, there is no event sent when video start playing in VideoView, but I can think of two options:
Create a version of VideoView by yourself, that sends event in those cases.
Use MediaController (which is default in VideoView)
If you want to follow option one - you can get the source of VideoView from here
isPlaying() can be called to test whether the MediaPlayer object is in the Started
Android MediaPlayer.isPlaying()
Another way to detect if videoview started is using videoView.getCurrentPosition(). getCurrentPosition() returns 0 if streaming not started.
protected Runnable playingCheck = new Runnable() {
public void run() {
while (true) {
if (vw.getCurrentPosition() != 0) {
// do what you want when playing started
break;
} else {
try {
Thread.sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
Then call:
new Thread(playingCheck).start();
Please try this :
final Handler h = new Handler();
h.postDelayed( new Runnable() {
public void run() {
if (videoView.getCurrentPosition() != 0) {
((ProgressBar) rootView.findViewById(R.id.pgStreaming)).setVisibility(View.GONE);
} else {
h.postDelayed(this, 250);
}
}
}, 250);

Categories

Resources