1

Actuellement, je travaille sur une application qui est censée télécharger des vidéos sur son stockage interne (malheureusement, ils n'ont PAS de carte SD) et simplement les lire. Ce que j'ai essayé jusqu'ici est:Android, VideoView, stockage interne

Standard VideoView, définissez le fichier /data/data/.../file.mp4 comme chemin - ne fonctionnait pas. Utilisez MediaPlayer avec un SurfaceView, utilisez le chemin d'accès ou le descripteur de fichier - n'a pas fonctionné.

Ce que je vais avoir ici maintenant est une version légèrement modded du VideoView, qui présente les modifications suivantes:

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

également une méthode setFD me permettant de définir mon descripteur de fichier. C'est beaucoup plus facile et plus propre que de mettre tout MediaPlayer/SurfaceView dans mon activité. Le problème est le suivant:

Le fichier dans la mémoire interne est créée comme ceci:

   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!"); 

Fondamentalement, il lit un fichier temporaire (que je ne veux pas écraser celui qui est actuellement joué .. mais cela n'a pas vraiment d'importance) et l'écriture (après onCompletion) dans le nouveau fichier, après la suppression du fichier temporaire.

Je l'ai testé sur 3 différentes versions Android et appareils à ce jour: - Tablet avec Android 2.2 - Nexus 7 avec Android 4.2 - HTC Sensation avec Android 4.1.2

Il ne fonctionnait tout simplement pas . Il joue laisse dire les premières 100ms de la vidéo incl. son, puis une fenêtre contextuelle et logcat pops me dit:

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) 

Mais je ne sais vraiment pas ce que cela est censé signifier. Je l'ai cherché dans tout Internet, tout ce que j'ai trouvé était "utiliser WORLD_READABLE, ça va résoudre le problème!" ou "juste utiliser le descripteur de fichier, ne semble pas se soucier des autorisations!". Mais pour moi, ça ne marche pas.

J'apprécierais vraiment toute aide.

EDIT:

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

      mVideoView.setVideoFD(fid.getFD()); 

Voici comment ajouter le descripteur de fichier au MediaPlayer.

Après réencoder le fichier, voici ce que je reçois:

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) 

Voilà comment je le télécharger depuis mon serveur web:

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(); 

Après l'avoir téléchargé, sur l'auditeur onDownloadFinished , J'exécute le code suivant:

   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!"); 

Des idées sur ce qui pourrait éventuellement aller mal? Ma seule autre idée serait que c'est à cause de la chose de stockage interne .. mais le message d'erreur dit quelque chose d'autre?

Répondre

1

Trouvé la solution. Chaque façon dont je l'ai testé travaillé probablement, parce que toutes les erreurs que je recevais est venu de « faux fichiers multimédia téléchargés » ...

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

était tout simplement un manque «0, curRead » - tout fonctionne maintenant. C'est évidemment parce que read() peut toujours retourner moins de BUFFER_SIZE et ensuite écrire 0-bytes dans le reste ou quelque chose ...

Merci!

1

L'erreur -1007 signifie MEDIA_ERROR_MALFORMED. Cela signifie que le fichier que vous essayez de lire n'est pas conforme à la spécification de fichier figurant dans la documentation officielle. Quelque chose ne va pas dans le média que vous recevez ou dans votre méthode de sauvegarde. Personnellement, votre méthode de sauvegarde me semble bien, donc je devine que le fichier source lui-même est le problème.

+0

Merci pour votre réponse. Voici comment je le télécharge depuis Internet: URLConnection c = mFile.openConnection(); c.connect(); InputStream est = c.getInputStream(); alors simplement lire/écrire sur un autre Stream .. Je vais essayer de le ré-encoder pour correspondre aux standards Android, même si je pensais que je l'avais déjà fait. – damian

+0

Mh pas sûr si c'est parce que j'ai ré-encodé le fichier d'exemple mais maintenant je reçois: 12-19 15: 06: 45.664: W/System.err (7616): java.io.IOException: setDataSourceFD échoué: état = 0x80000000 – damian

+0

Cela semble être une erreur commune, également liée aux formats de fichiers: http://stackoverflow.com/questions/9657280/mediaplayer-setdatasource-causes-ioexception-for-valid-file et http://stackoverflow.com/questions/9625680/mediaplayer-setdatasource-better-to-use-path-ou-filedescriptor –

Questions connexes