Control the playback speed of video in android - android

I am using a VideoView to play a video file kept in res/raw. I couldnt find a way to control the playback speed of the video. Basically i want to reduce and increase the playback while moving a scroll bar. Is there any work around for implementing this?

you can use this but it works on api 23 and above
mVideo.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
//works only from api 23
PlaybackParams myPlayBackParams = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
myPlayBackParams = new PlaybackParams();
myPlayBackParams.setSpeed(0.8f); //you can set speed here
mp.setPlaybackParams(myPlayBackParams);
}
}
});

No, you cannot change the playback rate by simply using VideoView. VideoView and MediaPlayer only provide limited media functions.
You have to use some third party library, e.g., PVPlayer, and implement that yourself.
That's also why good media players on Android are so valuable:)

I want to say than Mk Kamal's solution have an unexpected side effect: calling setPlaybackParams in OnPreparedListener will force VideoView to repeat the latest played video when the app was returned from the background.
I don't know is it a bug or a feature, but I found a way to avoid such behavior:
private float speed = 0.8f;
private final MediaPlayer.OnInfoListener listener = (mp, what, extra) -> {
if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
mp.setPlaybackParams(mp.getPlaybackParams().setSpeed(speed));
return true;
}
return false;
};
videoView.setOnPreparedListener(
mp -> {
mp.setOnInfoListener(listener);
}
);
MEDIA_INFO_VIDEO_RENDERING_START will be sent only if the palyer was already started.
And I want to emphasize that getPlaybackParams is annotated as #NonNull, so it's not necessary to create a new PlaybackParams object.

Kotlin variant, API above 23
val playerView = itemView.findViewById<VideoView>(R.id.videoview)
playerView.setVideoURI(Uri.parse("android.resource://" + context.packageName + "/" + R.raw.123.mp4))
playerView.setOnPreparedListener { mediaPlayer ->
playerView.seekTo(1) // for video preview
mediaPlayer.playbackParams = mediaPlayer.playbackParams.apply {
speed = 0.6f
}
playerView.start()
}

DicePlayer works perfectly on my Asus Transformer.
It has a speed control onscreen display.
I'm not sure what res/raw is though.

Related

ExoPlayer - play 10 files one after another

I have 10 video i need to play, once one is done, the next one starts to play.
I'm using Google's ExoPlayer, I use the example in the DEMO # GitHub.
I can play 1 video but if i try to play the next one, it wont start.
If i try to reInit the player, and the start playing again, it crashes.
private void loadvideo() {
Uri uri = Uri.parse(VIDEO_LIBRARY_URL + currentVideo + ".mp4");
sampleSource = new FrameworkSampleSource(this, uri, null, 2);
// 1. Instantiate the player.
// 2. Construct renderers.
videoRenderer = new MediaCodecVideoTrackRenderer(sampleSource, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource);
// 3. Inject the renderers through prepare.
player.prepare(videoRenderer, audioRenderer);
// 4. Pass the surface to the video renderer.
surface = surfaceView.getHolder().getSurface();
player.sendMessage(videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, surface);
// 5. Start playback.
player.setPlayWhenReady(true);
player.addListener(new ExoPlayer.Listener() {
#Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
Log.d(TAG, "onPlayerStateChanged + " + playbackState);
if (playbackState == ExoPlayer.STATE_ENDED) {
currentVideo++;
loadNextVideo();
}
}
#Override
public void onPlayWhenReadyCommitted() {
}
#Override
public void onPlayerError(ExoPlaybackException error) {
}
});
}
What am i doing wrong?
How can i play videos continuity?
Thanks.
You can reuse the ExoPlayer up until the point that you call release(), and then it should no longer be used.
To change the media that it is currently playing, you essentially need to perform the following steps:
// ...enable autoplay...
player.stop();
player.seekTo(0L);
player.prepare(renderers);
Creating the renderers is a little bit more involved, but that's the flow you should follow and the player should be able to play back to back videos.
I'm using Exoplayer change mp4 video success. I use the example in the DEMO.
1.DEMO project in DemoPlayer.java:
private final RendererBuilder rendererBuilder;
//remove final,then modify that:
private RendererBuilder rendererBuilder;
//and add the set method:
public void setRendererBuilder(RendererBuilder rendererBuilder){
this.rendererBuilder = rendererBuilder;
}
//finally,add stop method
public void stop(){
player.stop();
}
2.DEMO project in PlayerActivity.java:
add method:
private void changeVideo(){
player.stop();
player.seekTo(0L);
//you must change your contentUri before invoke getRendererBuilder();
player.setRendererBuilder(getRendererBuilder());
player.prepare();
playerNeedsPrepare = false;
}
remember change param contentUri before invoke changeVideo method.
Use ConcatenatingMediaSource to play files in sequence.
For example, for playing 2 media Uris (firstVideoUri and secondVideoUri), use this code:
MediaSource firstSource =
new ExtractorMediaSource.Factory(...).createMediaSource(firstVideoUri);
MediaSource secondSource =
new ExtractorMediaSource.Factory(...).createMediaSource(secondVideoUri);
ConcatenatingMediaSource concatenatedSource =
new ConcatenatingMediaSource(firstSourceTwice, secondSource);
And then use concatenatedSource to play media files sequentially.
OK, Answering my own question.
on the example, google init the ExoPlayer at OnResume().
i had to re-init for every video like that:
player = ExoPlayer.Factory.newInstance(2, 1000, 5000);
if someone has a better idea, please let me know.
There is another solution, you could refer to ConcatenatingMediaSource to achieve auto play next media.
In Demo App example :
1. Launch ExoPlayer
2. Select Playlists
3. Choose Cats->Dogs

Play audio and video at the same time in Android

I'm trying to play two different files at the same time.
I have tried to find players and tried to extend the default player achieving the same but couldn't get success in that. so please help me with it, by letting me know what's the best way to play audio file and video at the same time?
The reason I'm taking separate files is to save space, because the app will be localized, having multiple audio files for each language instead of having multiple videos saves space. That's important because android doesn't allow the download of app size above 50MB.
Any help in this would be extremely helpful. And providing me code for this would be a great help.
Thanks in advance.
You can handle this with Audio Focus. Two or more Android apps can play audio to the same output stream simultaneously. The system mixes everything together. While this is technically impressive, it can be very aggravating to a user. To avoid every music app playing at the same time, Android introduces the idea of audio focus. Only one app can hold audio focus at a time.
When your app needs to output audio, it should request audio focus. When it has focus, it can play sound. However, after you acquire audio focus you may not be able to keep it until you’re done playing. Another app can request focus, which preempts your hold on audio focus. If that happens your app should pause playing or lower its volume to let users hear the new audio source more easily.
Beginning with Android 8.0 (API level 26), when you call requestAudioFocus() you must supply an AudioFocusRequest parameter. To release audio focus, call the method abandonAudioFocusRequest() which also takes an AudioFocusRequest as its argument. The same AudioFocusRequest instance should be used when requesting and abandoning focus.
To create an AudioFocusRequest, use an AudioFocusRequest.Builder. Since a focus request must always specify the type of the request, the type is included in the constructor for the builder. Use the builder's methods to set the other fields of the request.
The following example shows how to use an AudioFocusRequest.Builder to build an AudioFocusRequest and request and abandon audio focus:
audioManager = (AudioManager) Context.getSystemService(Context.AUDIO_SERVICE);
playbackAttributes = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_GAME)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build();
focusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
.setAudioAttributes(playbackAttributes)
.setAcceptsDelayedFocusGain(true)
.setOnAudioFocusChangeListener(afChangeListener, handler)
.build();
mediaPlayer = new MediaPlayer();
final Object focusLock = new Object();
boolean playbackDelayed = false;
boolean playbackNowAuthorized = false;
// ...
int res = audioManager.requestAudioFocus(focusRequest);
synchronized(focusLock) {
if (res == AudioManager.AUDIOFOCUS_REQUEST_FAILED) {
playbackNowAuthorized = false;
} else if (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
playbackNowAuthorized = true;
playbackNow();
} else if (res == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) {
playbackDelayed = true;
playbackNowAuthorized = false;
}
}
// ...
#Override
public void onAudioFocusChange(int focusChange) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
if (playbackDelayed || resumeOnFocusGain) {
synchronized(focusLock) {
playbackDelayed = false;
resumeOnFocusGain = false;
}
playbackNow();
}
break;
case AudioManager.AUDIOFOCUS_LOSS:
synchronized(focusLock) {
resumeOnFocusGain = false;
playbackDelayed = false;
}
pausePlayback();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
synchronized(focusLock) {
resumeOnFocusGain = true;
playbackDelayed = false;
}
pausePlayback();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
// ... pausing or ducking depends on your app
break;
}
}
}
Hope this helps! Also you can check Android's official documentation. If this doesn't help, you can check this site and this site for more documentation.
To play audio: Audio Track reference
To play video: Media Player reference
And now you could start on the main thread by showing in a Video View the video you want, and when is the time to play the sound you start playing the Audio Track. The tricky part will be to syncronize the audio with the video

Best practices for audio streaming

I'm writing an application to play audio from remote server. I tried several ways to implement streaming audio, but they all are not good enough for me.
That's what I've tried:
Naive using of MediaPlayer
Something like:
MediaPlayer player = new MediaPlayer();
player.setDataSource(context, Uri.parse("http://whatever.com/track.mp3"));
player.prepare();
player.start();
(or prepareAsync, no matter)
But standard MediaPlayer is quite unstable when playing remote content. It is often falls or stops playback and I can't process this. On the other side, I want to implement media caching. But I haven't found any way to get buffered content from MediaPlayer to save it somewhere on device.
Implementing custom buffering
Then there became an idea to download media file by chunks, combine them into one local file and play this file. Downloading the whole file can be slow because of bad connection, so it will be fine to download enough initially piece, then start playback and continue downloading and appending local file. Besides, we get caching functionality.
Sounds like a plan, but it didn't always work. It works perfectly on HTC Sensation XE but didn't on 4.1 tablet playback stopped after finishing this initial piece. Don't know, why is so. I've asked question about this, but received no answers.
Using two MediaPlayers
I've created two MediaPlayer instances and tried to make them change each other. The logic is following:
Start downloading initial piece of media
When it is downloaded, start playback via currentMediaPlayer. The rest of media continues
downloading
When downloaded piece is almost played (1 sec before finish), prepare secondaryMediaPlayer with the same source file (as it was appended during playback)
261 ms before finish of currentMediaPlayer – pause it, start secondary, set secondary as current, schedule preparing of next secondary player.
The source:
private static final String FILE_NAME="local.mp3";
private static final String URL = ...;
private static final long FILE_SIZE = 7084032;
private static final long PREPARE_NEXT_PLAYER_OFFSET = 1000;
private static final int START_NEXT_OFFSET = 261;
private static final int INIT_PERCENTAGE = 3;
private MediaPlayer mPlayer;
private MediaPlayer mSecondaryPlayer;
private Handler mHandler = new Handler();
public void startDownload() {
mDownloader = new Mp3Downloader(FILE_NAME, URL, getExternalCacheDir());
mDownloader.setDownloadListener(mInitDownloadListener);
mDownloader.startDownload();
}
private Mp3Downloader.DownloadListener mInitDownloadListener = new Mp3Downloader.DownloadListener() {
public void onDownloaded(long bytes) {
int percentage = Math.round(bytes * 100f / FILE_SIZE);
// Start playback when appropriate piece of media downloaded
if (percentage >= INIT_PERCENTAGE) {
mPlayer = new MediaPlayer();
try {
mPlayer.setDataSource(mDownloader.getDownloadingFile().getAbsolutePath());
mPlayer.prepare();
mPlayer.start();
mHandler.postDelayed(prepareSecondaryPlayerRunnable, mPlayer.getDuration() - PREPARE_NEXT_PLAYER_OFFSET);
mHandler.postDelayed(startNextPlayerRunnable, mPlayer.getDuration() - START_NEXT_OFFSET);
} catch (IOException e) {
Log.e(e);
}
mDownloader.setDownloadListener(null);
}
}
};
// Starting to prepare secondary MediaPlayer
private Runnable prepareSecondaryPlayerRunnable = new Runnable() {
public void run() {
mSecondaryPlayer = new MediaPlayer();
try {
mSecondaryPlayer.setDataSource(mDownloader.getDownloadingFile().getAbsolutePath());
mSecondaryPlayer.prepare();
mSecondaryPlayer.seekTo(mPlayer.getDuration() - START_NEXT_OFFSET);
} catch (IOException e) {
Log.e(e);
}
}
};
// Starting secondary MediaPlayer playback, scheduling creating next MediaPlayer
private Runnable startNextPlayerRunnable = new Runnable() {
public void run() {
mSecondaryPlayer.start();
mHandler.postDelayed(prepareSecondaryPlayerRunnable, mSecondaryPlayer.getDuration() - mPlayer.getCurrentPosition() - PREPARE_NEXT_PLAYER_OFFSET);
mHandler.postDelayed(startNextPlayerRunnable, mSecondaryPlayer.getDuration() - mPlayer.getCurrentPosition() - START_NEXT_OFFSET);
mPlayer.pause();
mPlayer.release();
mPlayer = mSecondaryPlayer;
}
};
Again – sounds, like a plan, but works not perfectly. The moments of switching MediaPlayers are quite hearable. Here I have opposite situation: on 4.1 tablet it's ok, but on HTC Sensation there are evident lags.
I also tried to implement different download techniques. I've implemented download by 10Kb chunks and by MP3 frames. I don't know exactly, but it seems that in case of MP3 frames seekTo and start work better. But it's just a feeling, I don't know explanation.
StreamingMediaPlayer
I saw to this word several times while googling, and found this implementation: https://code.google.com/p/mynpr/source/browse/trunk/mynpr/src/com/webeclubbin/mynpr/StreamingMediaPlayer.java?r=18
It is a solution everybody use?
If yes, it's sad, because it is not working good for me too. And I don't see any fresh ideas in implementation.
So, the question
How do you guys implement audio streaming in your applications? I don't beleive I am the only person who faced problems like this. There should be some good practices.
In my case I use FFMPEG with OpenSL ES. The disadvantage is complexity. You must be familiar with a lot of things: JNI, OpenSL, FFMPEG. It's also hard to debug(comparing with pure java android app). In your case I suggest you to try low level Media API. The only thing is lack of examples. But there is a unit test which shows how you can handle audio(you need to change InputStream reference - line 82).

Seamless video Loop with VideoView

I have the following code to take a video as a raw resource, start the video and loop it but I need the video to loop seamlessly as of now when it comes to an end of the clip and starts the clip again the transition between causes a flicker for a split second, which I really can't have for my app.
public class Example extends Activity {
VideoView vv;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
vv = (VideoView)findViewById(R.id.VideoView01);
//Video Loop
vv.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
vv.start(); //need to make transition seamless.
}
});
Uri uri = Uri.parse("android.resource://com.example/"
+ R.raw.video);
vv.setVideoURI(uri);
vv.requestFocus();
vv.start();
}
}
The clip is only 22 seconds long but was created to be seamless so it is possible to work without the delay.
Try this it will work 100%
VideoView videoView;<---write this in outside of method or else declare it as final variable.
videoView.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.setLooping(true);
}
});
In Kotlin simply use
videoView.setOnPreparedListener { it.isLooping = true }
Not sure if this helps years later, but I used
vv.start();
vv.setOnCompletionListener ( new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
vv.start();
}
});
and it has a seamless loop
The pause is for the underlying MediaPlayer to refresh its buffers. How long that will take will depend on a number of factors, many of which are outside your control (e.g., speed of CPU, speed of on-board flash storage).
One you can control is to get your video out of the resource and into the filesystem. Resources are stored in the APK, which is a ZIP file, so extracting the video this way probably takes extra time.
You may need to switch away from VideoView and use a SurfaceView with two MediaPlayers, alternating between them -- one is playing while the next is preparing, so when the playing one ends you can switch to the new player. I have not tried this, and so I do not know what the ramifications might be. However, I know that this technique is frequently used for audio playback to transition from one clip to another.
Little late, but any reason that you can't use the following?
MediaPlayer.setLooping(true);
If you are using Kotlin
videoView.setOnPreparedListener(object : MediaPlayer.OnPreparedListener {
override fun onPrepared(mp: MediaPlayer?) {
//Start Playback
videoView.start()
//Loop Video
mp!!.isLooping = true;
Log.i(TAG, "Video Started");
}
});
Using Arrow Expression short form
videoView.setOnPreparedListener { mp ->
//Start Playback
videoView.start()
//Loop Video
mp!!.isLooping = true;
Log.i(TAG, "Video Started");
};
Answer to this is to remove the audio from the video and convert that to a .ogg file which can be looped seamlessly and then use the video without audio to loop round and this works.
Here is answer friends, you must use vv.resume in setOnCompletionListener class
[https://stackoverflow.com/a/27606389/3414469][1]

Android MediaPlayer is preparing too long

Hey,
I'm using MediaPlayer to play a regular ShoutCast stream. The code is straightforward with prepareAsync() and a handler to start the playback. While it works flawlessly with some streams like DI.FM or ETN.FM (http://u10.di.fm:80/di_progressive), with others (http://mp3.wpsu.org:8000/) it won't go past the prepare state. No other listeners are called either.
//Uri streamUri = Uri.parse("http://u10.di.fm:80/di_progressive"); /* works */
Uri streamUri = Uri.parse("http://mp3.wpsu.org:8000/"); /* stuck on prepare state */
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(this.getBaseContext(), streamUri);
mediaPlayer.prepareAsync();
Any feedback is appreciated!
I think that there are some compatibility problems with the server end.
This is rather strange since the emulator handles it ok in my case - just not on my Froyo Galaxy S, even though it is the same API version.
It could be a codec issue, http streaming issue, I do not know.
But all the servers that fail tend to be old ones, with "Copyright 1998 - 2004" at the bottom... Not exactly recent or up to date you would think.
One potential workaround (which I have not tried yet) would be to use the StreamProxy, which would also make your code compatible with 2.1 and possibly earlier versions too. At the cost of extra work, extra code, and without doubt extra bugs...
In case you are not aware of it, there is another player bug report for 2.2 which may be relevant too:
Basic streaming audio works in 2.1 but not in 2.2
I'm facing an issue when MP "hangs" at preparing state too long (stream) and i'm trying to stop it using reset(). This causes MP to hang and thus my whole app freezes. Seems like there is no way to stop MP at preparing state. Im thinking on use prepare() wrapped in thread instead of prepareAsync(). Then i'll be able to kill that thread. As for now i did it in following way:
private void actionCancel(){
try {
mp.setDataSource(new String());
} catch (Exception e) {
e.printStackTrace();
android.util.Log.d(TAG,"actionCancel(): mp.setDataSource() exception");
mp.reset();
}
}
and it works 4me.
Additionally i have a following counter:
#Override
public void onBufferingUpdate(final MediaPlayer mp, final int percent) {
if (!mp.isPlaying()){
// android.util.Log.d(TAG,"onBufferingUpdate(): onBufferingUpdateCount = "+onBufferingUpdateCount);
if (onBufferingUpdateCount>MAX_BUFFERING_UPDATES_AT_PREPARING_STATE)
restartMP();
onBufferingUpdateCount++;
return;
}
}
i'd discover this listener always triggers at preparing state. So if it triggers more than 10 times and MP is still not playing i'm just restarting it:
private void restartMP(){
if (mp!=null)
if (mpState==MediaPlayerState.Preparing)
actionCancel();
else
mp.reset();
else
mp = new MediaPlayer();
mpState = MediaPlayerState.Idle;
onBufferingUpdateCount=0;
//isRequestCancelled=false;
requestTrackInfoStartedAt=0;
requestPlay();
}
note MediaPlayerState is my custom enum which has "Preparing" value. Also mpState is a class property/field which holds current MediaPlayerState state. Before starting prepareAsync() im setting mpState to MediaPlayerState.Preparing after it completes im setting it to MediaPlayerState.Started or other corresponding value.

Categories

Resources