Мне необходимо сохранять файлы, которые играет медиа плеер в кэш в папку. С простыми звуковыми файлами нет проблем. Есть программа и класс, который это делает. Причём делает странным способом, но работает.
Большие проблемы с видео файлами.
Во-первых я хотел пойти по лёгкому пути и использовать мега вещь ExoPlayer от компании гудл. Но он не играет мой файл и по всей видимости много других
https://github.com/google/ExoPlayer/issues/19
Во-вторых я попробовал сделать свой стриминг в папку по тому же принципу, как и музыку. Вот мой код:
Этот класс стартует скачивание:
/**
* Download the url stream to a temporary location and then call the setDataSource
* for that local file
*/
public void downloadAudioIncrement(String mediaUrl) throws IOException {
URLConnection cn = new URL(mediaUrl).openConnection();
path=mediaUrl;
cn.connect();
sizef=cn.getContentLength();
InputStream stream = cn.getInputStream();
if (stream == null) {
Log.e(getClass().getName(), "Unable to create InputStream for mediaUrl:" + mediaUrl);
}
downloadingMediaFile = new File(mContext.getCacheDir(),"downloadingMedia.dat");
// Just in case a prior deletion failed because our code crashed or something, we also delete any previously
// downloaded file to ensure we start fresh. If you use this code, always delete
// no longer used downloads else you'll quickly fill up your hard disk memory. Of course, you can also
// store any previously downloaded file in a separate data cache for instant replay if you wanted as well.
if (downloadingMediaFile.exists()) {
downloadingMediaFile.delete();
}
FileOutputStream out = new FileOutputStream(downloadingMediaFile);
byte buf] = new byte[16384];
int totalBytesRead = 0, incrementalBytesRead = 0;
do {
int numread = stream.read(buf);
if (numread <= 0)
break;
out.write(buf, 0, numread);
totalBytesRead += numread;
incrementalBytesRead += numread;
totalKbRead = totalBytesRead/1000;
testMediaBuffer();
//fireDataLoadUpdate();
} while (validateNotInterrupted());
stream.close();
if (validateNotInterrupted()) {
// fireDataFullyLoaded();
}
}
И постоянно запускает класс testMediaBuffer(). Который вот:
/**
* Test whether we need to transfer buffered data to the MediaPlayer.
* Interacting with MediaPlayer on non-main UI thread can causes crashes to so perform this using a Handler.
*/
private void testMediaBuffer() {
Runnable updater = new Runnable() {
public void run() {
if (mMediaPlayer == null) {
// Only create the MediaPlayer once we have the minimum buffered data
if ( totalKbRead >= INTIAL_KB_BUFFER) {
try {
//mUri=Uri.parse(path);
openVideo();
} catch (Exception e) {
Log.e(getClass().getName(), "Error copying buffered conent.", e);
}
}
} else if ((totalKbRead - pfile) >= 4000){
// NOTE: The media player has stopped at the end so transfer any existing buffered data
// We test for < 1second of data because the media player can stop when there is still
// a few milliseconds of data left to play
transferBufferToMediaPlayer();
}
}
};
handler.post(updater);
}
И до этих пор всё нормально работает, но класс transferBufferToMediaPlayer(), который запускается тогда когда скаченный буфер превысит тот что был скачен до этого на 4мб, дропает звук и видео в момент подмены файла.
И как этот дроп обойти я не понимаю. По закомментированному видно, что здесь была война. Может, есть у кого предположения или опыт создания видео плеера со стримингом в папку? Вот код этого класса:
/**
* Transfer buffered data to the MediaPlayer.
* NOTE: Interacting with a MediaPlayer on a non-main UI thread can cause thread-lock and crashes so
* this method should always be called using a Handler.
*/
private void transferBufferToMediaPlayer() {
try {
// First determine if we need to restart the player after transferring data...e.g. perhaps the user pressed pause
boolean wasPlaying = mMediaPlayer.isPlaying();
// Copy the currently downloaded content to a new buffered File. Store the old File for deleting later.
File oldBufferedFile = new File(mContext.getCacheDir(),"playingMedia" + counter + ".dat");
File bufferedFile = new File(mContext.getCacheDir(),"playingMedia" + (counter++) + ".dat");
// This may be the last buffered File so ask that it be delete on exit. If it's already deleted, then this won't mean anything. If you want to
// keep and track fully downloaded files for later use, write caching code and please send me a copy.
bufferedFile.deleteOnExit();
moveFile(downloadingMediaFile,bufferedFile);
// Pause the current player now as we are about to create and start a new one. So far (Android v1.5),
// this always happens so quickly that the user never realized we've stopped the player and started a new one
mMediaPlayer.pause();
int curPosition = mMediaPlayer.getCurrentPosition();
//mMediaPlayer.release();
//mMediaPlayer=null;
// Create a new MediaPlayer rather than try to re-prepare the prior one.
FileInputStream fis = new FileInputStream(bufferedFile);
mMediaPlayer.reset();
//mMediaPlayer = new MediaPlayer();
/*if (mAudioSession != 0) {
mMediaPlayer.setAudioSessionId(mAudioSession);
} else {
mAudioSession = mMediaPlayer.getAudioSessionId();
}
setListeners();*/
pfile=bufferedFile.length()/1024;
mMediaPlayer.setDataSource(fis.getFD());
//mMediaPlayer.setSurface(new Surface (sf));
// mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.prepare();
// we don't set the target state here either, but preserve the
// target state that was there before.
// mCurrentState = STATE_PREPARING;
//attachMediaController();
mMediaPlayer.seekTo(curPosition);
//mMediaPlayer.start();
// Restart if at end of prior buffered content or mediaPlayer was previously playing.
// NOTE: We test for < 1second of data because the media player can stop when there is still
// a few milliseconds of data left to play
/*boolean atEndOfFile = (totalKbRead - pfile) >= 1000;
if (wasPlaying || atEndOfFile){
mMediaPlayer.start();
}*/
// Lastly delete the previously playing buffered File as it's no longer needed.
oldBufferedFile.delete();
}catch (Exception e) {
Log.e(getClass().getName(), "Error -------------------------------------------------------", e);
}
}