I'm downloading MP4 files from a Web app to a file on my mobile device. Since the files tend to be large, I want to start playing them as soon as I get some data, rather than wait until the whole file has been downloaded, so I've come up with the following scheme:
- Download the first 1 MB of data to a file on my SD card.
- Start the video player.
- Download the remaining data in 1 MB chunks, appending the new data to the original file.
More precisely, the code does the following:
Create a FileOutputstream named out that writes to "/storage/sdcard/tmpAttachment" Fetch up to 1 MB from the server and write it to /storage/sdcard/tmpAttachment start the video player and have it start playing from the beginning of /storage/sdcard/tmpAttachment while (more data) Fetch next 1 MB chunk and write to out endwhile
The actual code is as follows:
File file = new File(Environment.getExternalStorageDirectory() + "/tmpAttachment");
if (file.exists() && !file.delete()) { //Delete the old file if it exists
postRes = mContext.getString(R.string.message_view_dynamic_content_delete_error);
mHandler.post(mUpdateResults);
return;
}
FileOutputStream out = new FileOutputStream(file);
reply = Utility.doFetchSegment(mAccount, mMessage.getFrom()[0].getAddress() + Utility.BLANK + contentPointers[i] + Utility.BLANK + "0", "https://" + contentServerName + ":" + contentServerPort, mAccount.getEmail(), contentServerPassword, true, out, null);
if (reply[0].equals("13")) {
Uri attachmentUri = Uri.fromFile(file);
attachmentViewIntent = new Intent(mContext, ECSVideoViewer.class);
try {
ECSVideoViewer.actionECSVideoViewer(mContext, attachmentUri);
} catch (Exception e) {
postRes = mContext.getString(R.string.message_view_dynamic_content_fetch_error) + e;
mHandler.post(mUpdateResults);
e.printStackTrace();
}
while (!fPtr.equals(contentLen)) {
reply = Utility.doFetchSegment(mAccount, mMessage.getFrom()[0].getAddress() + Utility.BLANK + contentPointers[i] + Utility.BLANK + fPtr, "https://" + contentServerName + ":" + contentServerPort, mAccount.getEmail(), contentServerPassword, true, out, null);
if (reply[0].equals("13")) {
fPtr = reply[1].substring(reply[1].indexOf("pointer=") + "pointer=".length(), reply[1].indexOf(", t"));
} else {
postRes = reply[1];
mHandler.post(mUpdateResults);
out.close();
return;
}
}
The code for ECSVideoViewer.java is as follows:
public class ECSVideoViewer extends Activity {
private static final String EXTRA_PATH = "path";
/**
* TODO: Set the path variable to a streaming video URL or a local media
* file path.
*/
private static VideoView mVideoView;
public static void actionECSVideoViewer(Context context, Uri uri) {
Intent i = new Intent(context, ECSVideoViewer.class);
i.putExtra(EXTRA_PATH, uri.getEncodedPath());
context.startActivity(i);
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.videoview);
mVideoView = (VideoView) findViewById(R.id.surface_view);
String path = getIntent().getStringExtra(EXTRA_PATH);
mVideoView.setVideoURI(Uri.parse(path));
mVideoView.setMediaController(new MediaController(this));
mVideoView.setOnErrorListener(new OnErrorListener() {
public boolean onError (MediaPlayer mp, int what, int extra) {
mVideoView.getCurrentPosition();
mVideoView.getBufferPercentage();
mVideoView.getDuration();
return true;
}
});
mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion (MediaPlayer mp) {
mVideoView.pause();
}
});
mVideoView.requestFocus();
mVideoView.start();
}
public static void resume() {
mVideoView.resume();
}
public static void play() {
mVideoView.start();
}
public static int getCurrentPosition() {
return mVideoView.getCurrentPosition();
}
public static int getBufferPercentage() {
return mVideoView.getBufferPercentage();
}
public static int getDuration() {
return mVideoView.getDuration();
}
public static boolean isPlaying() {
return mVideoView.isPlaying();
}
}
The video starts playing OK, after loading the first block and while the next one is getting loaded, but for some reason, the player stops and throws an error when it tries to read the second 1 MB block of downloaded data, returning MEDIA_ERROR_UNKNOWN and MEDIA_ERROR_IO. Can anyone see what I'm doing wrong?