2

currently I'm working on an application that's supposed to download videos onto its internal storage (unfortunately they do NOT have a sd card) and simply play them. What I've tried so far is:

Standard VideoView, set the /data/data/.../file.mp4 as path - did not work. Use MediaPlayer with a SurfaceView, use path or file descriptor - did not work.

What I'm having here right now is a slightly modded version of the VideoView, which has the following changes:

        if(mUri != null)
        {
            mMediaPlayer.setDataSource(mContext, mUri);
        }
        else
        {
            mMediaPlayer.setDataSource(mFd);
        }

Also a setFD method allowing me to set my File Descriptor. This is way easier and cleaner - imo - than putting the whole MediaPlayer/SurfaceView into my activity. The problem is the following:

The file in the internal storage is created like this:

                FileInputStream fis = openFileInput(Downloader.TMP_FILENAME);
                FileOutputStream fos = openFileOutput(Downloader.FILENAME
                        + ext, Context.MODE_WORLD_READABLE);
                byte[] buf = new byte[2048];
                while (fis.read(buf) > 0) {
                    fos.write(buf);
                }
                fis.close();
                fos.close();
                deleteFile(Downloader.TMP_FILENAME);
                Log.d(TAG, "Replacement done!");

Basically it's reading a temporary file (as I don't want to overwrite the currently played one.. but that doesn't really matter) and writing it (after onCompletion) into the new file, afterwards deleting the temporary file.

I've tested it on 3 different Android versions and devices so far: - Tablet with Android 2.2 - Nexus 7 with Android 4.2 - HTC Sensation with Android 4.1.2

It simply did not work. It plays lets say the first 100ms of the video incl. sound then a popup pops up and logcat is telling me:

12-19 14:33:48.074: W/MediaPlayer(5560): info/warning (3, 0)
12-19 14:33:48.074: I/MediaPlayer(5560): Info (3,0)
12-19 14:33:48.394: E/MediaPlayer(5560): error (1, -1007)
12-19 14:33:48.394: E/MediaPlayer(5560): Error (1,-1007)

But I really have no idea what this is supposed to mean. I've searched for it in the whole internet, all I found was "use WORLD_READABLE, it will solve the problem!" or "just use the file descriptor, seems to not care about permissions!". But for me, it does not work.

I'd really appreciate any help.

EDIT:

            FileInputStream fid = new FileInputStream((getFilesDir() + "/"
                    + Downloader.FILENAME + ext)));

            mVideoView.setVideoFD(fid.getFD());

This is how I add the File Descriptor to the MediaPlayer.

After reencoding the file, this is what I get:

12-19 15:06:45.664: E/MediaPlayer(7616): Unable to to create media player
12-19 15:06:45.664: W/System.err(7616): java.io.IOException: setDataSourceFD failed.: status=0x80000000
12-19 15:06:45.664: W/System.err(7616):     at android.media.MediaPlayer.setDataSource(Native Method)
12-19 15:06:45.664: W/System.err(7616):     at android.media.MediaPlayer.setDataSource(MediaPlayer.java:976)

This is how I download it from my webserver:

Log.i(TAG, "Opening remote connection to " + mFile.getHost()
                + mFile.getPath());
        URLConnection c = mFile.openConnection();
        c.connect();
        final long lastModified = c.getLastModified();
        final String mExtension;
        if (c.getHeaderField("Content-Disposition") != null) {
            final String mFilename = c
                    .getHeaderField("Content-Disposition").split("=")[1];
            Log.i("Downloader", "Filename is " + mFilename
                    + ", split length is " + mFilename.split("\\.").length);
            mExtension = mFilename.split("\\.")[mFilename
                    .split("\\.").length - 1];
        } else {
            mExtension = "mp4";
        }

        InputStream is = c.getInputStream();

        Log.i(TAG, "Creating temporary local file");
        // create local temporary file
        FileOutputStream fos = mContext.openFileOutput(TMP_FILENAME,
                Context.MODE_WORLD_READABLE);

        // start reading
        byte[] buf = new byte[BUFFER_SIZE];
        int bytesRead = 0;
        int curRead = 0;
        Log.i(TAG, "Starting download.. to " + TMP_FILENAME);
        if (mDownloadChangeListener != null)
            mDownloadChangeListener.onDownloadStart();

        while ((curRead = is.read(buf)) > -1) {
            fos.write(buf);
            bytesRead += curRead;
        }
        Log.i(TAG, "Read " + bytesRead + " bytes in total.");
        Log.i(TAG, "Download finished!");
        // end of stream, tell app to rename file.
        if (mDownloadChangeListener != null)
            mDownloadChangeListener.onDownloadFinished(TMP_FILENAME,
                    mExtension);

        is.close();
        fos.close();

After downloading it, on the onDownloadFinished listener, I execute the following code:

                FileInputStream fis = openFileInput(Downloader.TMP_FILENAME);
                FileOutputStream fos = openFileOutput(Downloader.FILENAME
                        + ext, Context.MODE_WORLD_WRITEABLE);
                byte[] buf = new byte[2048];
                while (fis.read(buf) > 0) {
                    fos.write(buf);
                }
                fis.close();
                fos.close();
                deleteFile(Downloader.TMP_FILENAME);
                Log.d(TAG, "Replacement done!");

Any ideas what could possibly go wrong? My only other idea would be that it's because of the internal storage-thing.. but the error message says something else?

damian
  • 2,001
  • 20
  • 38

2 Answers2

2

Error -1007 stands for MEDIA_ERROR_MALFORMED. It means that the file you're trying to play doesn't conform to the file specification put down in the official documentation. Something is either wrong with the media you're receiving, or in your method of saving it.

Personally, your method of saving it looks fine to me, so I'm guessing that the source file itself is the problem.

Raghav Sood
  • 81,899
  • 22
  • 187
  • 195
  • Thanks for your answer. This is how I download it from the internet: URLConnection c = mFile.openConnection(); c.connect(); InputStream is = c.getInputStream(); then simply read/write to another Stream.. I'll try to re-encode it to match the Android standards, even tho I thought I already did that. – damian Dec 19 '12 at 13:58
  • Mh not sure if it's because I've reencoded the example file but now I'm getting: 12-19 15:06:45.664: W/System.err(7616): java.io.IOException: setDataSourceFD failed.: status=0x80000000 – damian Dec 19 '12 at 14:07
  • This seems to be a common error, also related to file formats: http://stackoverflow.com/questions/9657280/mediaplayer-setdatasource-causes-ioexception-for-valid-file and http://stackoverflow.com/questions/9625680/mediaplayer-setdatasource-better-to-use-path-or-filedescriptor – Raghav Sood Dec 19 '12 at 14:11
  • Well I'm not really sure why it did not accept my file then. I've taken a look at the "allowed" codecs http://developer.android.com/guide/appendix/media-formats.html, tried MPEG-4/MP3 combination but did not work.. I'm on Ubuntu and I don't really know how I should encode my video and with which codecs – damian Dec 19 '12 at 14:18
  • Maybe something is wrong with your file headers. See if you can find a standard or demo video file from some open source project and try with that. – Raghav Sood Dec 19 '12 at 14:19
  • If I play the same video from /res/raw via mVideoView.setVideoURI(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.test)); it works.. any ideas? I'll update my post with more code about downloading.. – damian Dec 19 '12 at 14:51
2

Found the solution. Every way I've tested worked probably, because all errors I received came from "wrong downloaded media files"...

while((curRead = in.read(buf)) {
   out.write(buf);
}

Was simply missing a ",0 ,curRead" - all working now. It's obviously because read() can always return less than BUFFER_SIZE and then writes 0-bytes into the rest or something...

Thanks!

damian
  • 2,001
  • 20
  • 38