I'm having an annoying problem with playing a video in TextureView from raw or assets folder... or even from the external storage. The code in the fragment looks something like this
public class MainFragment extends Fragment implements TextureView.SurfaceTextureListener, MediaPlayer.OnBufferingUpdateListener,
MediaPlayer.OnCompletionListener, MediaPlayer.OnPreparedListener, MediaPlayer.OnVideoSizeChangedListener {
private ParallaxAdapter mAdapter;
private MediaPlayer mMediaPlayer;
private MediaPlayer mMediaPlayer2;
private TextureView tv;
private TextureView tv2;
private ImageView imageview;
private TextureView mTexture;
String path;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstance) {
super.onCreateView(inflater, container, savedInstance);
View v = inflater.inflate(R.layout.view_fragment, container, false);
path = getArguments().getString("path");
Log.d("Fragment","" + path);
String tag = getArguments().getString("Tag");
imageview = (ImageView) v.findViewById(R.id.imageView);
if (tag == "image") {
imageview.setImageResource(getArguments().getInt("image"));
} else if (tag == "video") {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inDither = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmapThumb = ThumbnailUtils.createVideoThumbnail(path, MediaStore.Images.Thumbnails.FULL_SCREEN_KIND);
imageview.setImageBitmap(bitmapThumb);
tv = (TextureView) v.findViewById(R.id.textureView);
tv.setSurfaceTextureListener(this);
}
return v;
}
public void setAdapter(ParallaxAdapter Adapter) {
mAdapter = Adapter;
}
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Surface s = new Surface(surface);
try {
MediaPlayer mp = new MediaPlayer();
mp.setDataSource(path);
mp.setSurface(s);
mp.prepare();
mp.setOnBufferingUpdateListener(this);
mp.setOnCompletionListener(this);
mp.setOnPreparedListener(this);
mp.setOnVideoSizeChangedListener(this);
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp.setVolume(0, 0);
mMediaPlayer.setLooping(true);
mMediaPlayer.start();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
It looks like the MediaPlayer cannot find the file from raw:
defpath = "android.resource://" + getPackageName() + "/" + R.raw.video;
or from assets:
AssetFileDescriptor afd = getAssets().openFd(FILE_NAME);
mp.setDataSource(afd.getFileDescriptor());
and i've tried to copy the assets to the sdcard with some codes from this discussion: android-how-to-copy-files-from-assets-folder-to-sdcard
but if I copy it, the file is somehow corrupt. I cannot even play it with the normal VideoPlayer in my device.
It is not a codec error! If I put the video into my device like on a USB and set the path and it's working with all 3 test videos. The manifest has read and write permission. And the VideoView makes even more problems with the ViewPager and paths.
Hopefully I'm just making some kind of stupid mistake... Thank you!
Only because you can play the video with the default video player of your device doesn't mean it's not a codec problem or another detail it doesn't like about it.
What I' missing here is a MediaPlayer.OnErrorListener
If you get something like
/MediaPlayer﹕ error (1, -2147483648), which indicates a MEDIA_ERROR_UNKNOWN with the extra info MEDIA_ERROR_SYSTEM (-2147483648) - low-level system error it's probably a video issue.
You could take a look at the video metadata with ffmpeg:
ffmpeg -i video.mp4
Check for:
Codec
Metadata (e.g. video is rotated)
Video width/height too big
Didn't get a reasonable error message for any of these.
Here's the official info: Supported Media Formats which doesn't help much IMHO
Related
// Play video when the media source is ready for playback.
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mMediaPlayer.start();
// mMediaPlayer.getDuration();
MediaMetadataRetriever mMMR = new MediaMetadataRetriever();
mMMR.setDataSource(FILE_NAME, new HashMap<String, String>());
String time = mMMR.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
Bitmap bitmap;
int fps = 24;
int deltaT= (int)1/fps;
for (int time_ms=1;time_ms<Integer.valueOf(time)*1000;time_ms+=24){
bitmap = mMMR.getFrameAtTime(5000);
if (bitmap==null) break;
}
}
});
I tried to connect MediaMetadataRetriever but then the video is not played.
It is interesting how to implement it in an asynchronous way: video is playing and on the background we taking a picture for instance on 5 seconds of video?
TextureView has SurfaceTexture. You can use this function in the 5s loop:
Bitmap bitmap = SurfaceTexture.getBitmap([with,height])
I manage to play a live stream from a url such as this
rtsp://192.168.0.18:554/user=admin&password=&channel=1&stream=0.sdp?
But I want to download this stream into a temporary file and then play it locally so that I can make it seems like the buffering time is short (around 2-4 seconds delay maybe)
Is it possible to do this with rtsp? or do I have to use http?Because this url only works on rtsp protocol
If so,a bit of example would help me alot
Example of my codes
cA.mPlayer1 = new MediaPlayer();
try {
cA.mPlayer1.setDataSource("rtsp://192.168.0.18:554/user=admin&password=&channel=1&stream=0.sdp?");
cA.mPlayer1.prepareAsync();
cA.mPlayer1.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
cA.mPlayer1.start();
Toast.makeText(getBaseContext(), "Connecting...", Toast.LENGTH_LONG).show();
}
});
} catch (IOException e) {
e.printStackTrace();
}
cA.mCallback1 = new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
cA.mPlayer1.setDisplay(surfaceHolder);
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
}
};
final SurfaceView surfaceView1 =
(SurfaceView) findViewById(R.id.surfaceView1);
// Configure the Surface View.
surfaceView1.setKeepScreenOn(true);
// Configure the Surface Holder and register the callback.
SurfaceHolder holder1 = surfaceView1.getHolder();
holder1.addCallback(cA.mCallback1);
holder1.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
you can not use MediaPlayer to save a Raw stream in file . you can use one of these :
use 'vlc' to save the stream like this:
https://wiki.videolan.org/Documentation:Streaming_HowTo/Receive_and_Save_a_Stream/
or use 'VLC lib' for android that can downloaded from :
https://github.com/mrmaffen/vlc-android-sdk
use FFMPEG library to record RTSP recording locally in sd card :
1- Capture or decode the RAW frames from live stream and pass them to ffmpeg and save them to sdcard in .h264 format.
2- Then again pick .h264 raw file and decode the file using ffmpeg, and save the file with extention .mp4 into sd card.
3- delete the .h264 file programmatically, and save only .mp4, or which format you want.
Try .mp4 playback.
https://stackoverflow.com/a/24586256/6502368
i have a problem when i try to play a video in format hd with class MediaPlayer in android (it gives me black display but it plays sound)... it doesn't work with hd video but it works with not hd videos... i would wanto to know what you think about this and if there is a way to fix the problem.
this is my code...
SingletonMedia singletonMedia = SingletonMedia.getIstance();
final MediaPlayer player = new MediaPlayer();
//String uri = singletonMedia.listaMedia.get(currentMedia).url;
//MediaPlayer player = MediaPlayer.create(getActivity(), Uri.parse(uri));
SurfaceHolder mHolder;
SurfaceView mPreview;
mPreview = (SurfaceView) getActivity().findViewById(R.id.surfaceView);
//mPreview.setVisibility(View.VISIBLE);
mHolder = mPreview.getHolder();
try {
Log.w(null, singletonMedia.listaMedia.get(currentMedia).url);
player.setDataSource(singletonMedia.listaMedia.get(currentMedia).url);
}
catch (Exception e) {
Log.w(null, "Entrato nell'eccezione del setDataSource nel Fragment: "+e.getMessage());
}
player.setDisplay(mHolder);
try {
player.prepare();
} catch (Exception e) {
Log.w(null, "Entrato nell'eccezione del prepare nel Fragment: " + e.getMessage());
}
player.start();
thanks in advance for help.
is there a way to play hd videos in android?
You should find out the encoding format of your hd video. Android os does not support too many formats. MediaPlayer can play video with format h264 even if video is hd. If encoding foramt is h264, you should try another device.
Or you should make sure your play operation be started after SurfaceView.surfaceCreated.
I need to play a live stream on devices with 2.x and greater versions. This states that it's impossible to play live streams on devices with Android 2.x.
What're my options here ? Especially I'm interested in streaming audio - what format should i pick and in conjunction with which protocol ?
P.S. I've tried Vitamio - don't want to make customers download third party libraries.
UPD
How come I can play this stream "http://188.138.112.71:9018/" ?
try this example for RTSP streaming (the url should support RTSP) for video change the code to support just audio
public class MultimediaActivity extends Activity {
private static final String RTSP = "rtsp://url here";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.multimedia);
//***VideoView to video element inside Multimedia.xml file
VideoView videoView = (VideoView) findViewById(R.id.video);
Log.v("Video", "***Video to Play:: " + RTSP);
MediaController mc = new MediaController(this);
mc.setAnchorView(videoView);
Uri video = Uri.parse(RTSP);
videoView.setMediaController(mc);
videoView.setVideoURI(video);
videoView.start();
}
}
EDIT:
Live Audio streaming using MediaPlayer in Android
Live Audio streaming in android, from 1.6 sdk onwards is become so easy. In setDataSource() API directly pass the url and audio will play without any issues.
The complete code snippet is,
public class AudioStream extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String url = "http://www.songblasts.com/songs/hindi/t/three-idiots/01-Aal_Izz_Well-(SongsBlasts.Com).mp3";
MediaPlayer mp = new MediaPlayer();
try {
mp.setDataSource(url);
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp.prepare();
mp.start();
} catch (Exception e) {
Log.i("Exception", "Exception in streaming mediaplayer e = " + e);
}
}
}
You can use RTSP protocol which is supported by Android native media player.
player = new MediaPlayer();
player.reset();
player.setDataSource(intent.getStringExtra("Path"));
player.prepare();
player.setOnPreparedListener(new OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
player.start();
}
});
Where path would be your rtsp audio streaming url.
I'm trying to provide my users with the ability to use either external or internal storage. I'm displaying both images and videos (of a scientific nature). When storing the media on the SD card, all is fine. But when I store the media internally, only the images will display. No matter what I try I get various errors when trying to load and display the media stored under the applicationcontext.getFilesDir().
Is there a trick to setting a videoview's content to such a file?
Can a ContentResolver help me?
On a related note, is it considered bad form to assume that external storage exists?
Thanks in advance,
Sid
Below is one version that fails with "Cannot play video. Sorry, this video cannot be played". But I have many other modes of failure. I can copy the internal video to temp storage (external) and play it, so this copy to internal does indeed create a valid movie. It only fails when I try to play it directly from the internal storage.
videoFile = new File(this.getFilesDir() + File.separator + "test.mp4");
InputStream data = res.openRawResource(R.raw.moviegood);
try {
OutputStream myOutputStream = new FileOutputStream(videoFile);
byte[] buffer = new byte[8192];
int length;
while ( (length = data.read(buffer)) > 0 ) {
myOutputStream.write(buffer);
}
//Close the streams
myOutputStream.flush();
myOutputStream.close();
data.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
vview.setKeepScreenOn(true);
vview.setVideoPath(videoFile.getAbsolutePath());
vview.start();
MediaPlayer requires that the file being played has world-readable permissions. You can view the permissions of the file with the following command in adb shell:
ls -al /data/data/com.mypackage/myfile
You will probably see "-rw------", which means that only the owner (your app, not MediaPlayer) has read/write permissions.
Note: Your phone must be rooted in order to use the ls command without specifying the file (in the internal memory).
If your phone is rooted, you can add world-read permissions in adb shell with the following command:
chmod o+r /data/data/com.mypackage/myfile
If you need to modify these permissions programmatically (requires rooted phone!), you can use the following command in your app code:
Runtime.getRuntime().exec("chmod o+r /data/data/com.mypackage/myfile");
Which is basically a linux command. See https://help.ubuntu.com/community/FilePermissions for more on chmod.
EDIT: Found another simple approach here (useful for those without rooted phones). Since the application owns the file, it can create a file descriptor and pass that to mediaPlayer.setDataSource():
FileInputStream fileInputStream = new FileInputStream("/data/data/com.mypackage/myfile");
mediaPlayer.setDataSource(fileInputStream.getFD());
This approach avoids the permission issue completely.
You can use:
videoView.setVideoURI(Uri.parse(file.getAbsolutePath()));
if the file is world readable
Or you can use a content provider
For detail check this tutorial
public class AndroidVideoViewExample extends Activity {
private VideoView myVideoView;
private int position = 0;
private ProgressDialog progressDialog;
private MediaController mediaControls;
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// set the main layout of the activity
setContentView(R.layout.activity_main);
//set the media controller buttons
if (mediaControls == null) {
mediaControls = new MediaController(AndroidVideoViewExample.this);
}
//initialize the VideoView
myVideoView = (VideoView) findViewById(R.id.video_view);
// create a progress bar while the video file is loading
progressDialog = new ProgressDialog(AndroidVideoViewExample.this);
// set a title for the progress bar
progressDialog.setTitle("JavaCodeGeeks Android Video View Example");
// set a message for the progress bar
progressDialog.setMessage("Loading...");
//set the progress bar not cancelable on users' touch
progressDialog.setCancelable(false);
// show the progress bar
progressDialog.show();
try {
//set the media controller in the VideoView
myVideoView.setMediaController(mediaControls);
//set the uri of the video to be played
myVideoView.setVideoURI(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.kitkat));
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
myVideoView.requestFocus();
//we also set an setOnPreparedListener in order to know when the video file is ready for playback
myVideoView.setOnPreparedListener(new OnPreparedListener() {
public void onPrepared(MediaPlayer mediaPlayer) {
// close the progress bar and play the video
progressDialog.dismiss();
//if we have a position on savedInstanceState, the video playback should start from here
myVideoView.seekTo(position);
if (position == 0) {
myVideoView.start();
} else {
//if we come from a resumed activity, video playback will be paused
myVideoView.pause();
}
}
});
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
//we use onSaveInstanceState in order to store the video playback position for orientation change
savedInstanceState.putInt("Position", myVideoView.getCurrentPosition());
myVideoView.pause();
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
//we use onRestoreInstanceState in order to play the video playback from the stored position
position = savedInstanceState.getInt("Position");
myVideoView.seekTo(position);
}
}
I posted a custom VideoView implementation there.
The VideoView implementation has the setVideoFD(FileDescriptor fd) method and solves this issue.
I came across this thread with the same problem, I'm downloading my videos from the web to the internal storage, turns out when saving you can specify the RW mode, i.e change from PRIVATE to WORLD_READABLE
URL url = new URL(_url);
InputStream input = null;
FileOutputStream output = null;
try {
String outputName = "video.mp4";
input = url.openConnection().getInputStream();
output = c.openFileOutput(outputName, Context.MODE_WORLD_READABLE);
int read;
byte[] data = new byte[5120]; //5MB byte array
while ((read = input.read(data)) != -1)
output.write(data, 0, read);
return true;
} finally {
if (output != null)
output.close();
if (input != null)
input.close();
}
}
You can't just play it directly.
You need to implement a ContentProvider then pass the defined Uri to setVideoUri(uri) method.