[Android] [PATCH] Add open stream feature in UI

Rafaël Carré funman at videolan.org
Sun Mar 11 01:13:08 CET 2012


Hi,

Le 10/03/2012 18:47, Edward Wang a écrit :
> ---
>  vlc-android/res/menu/media_library.xml             |    4 +
>  vlc-android/res/values/strings.xml                 |    1 +
>  vlc-android/src/org/videolan/vlc/AudioService.java |   12 ++-
>  vlc-android/src/org/videolan/vlc/Media.java        |   82 +++++++++++++++++++-
>  .../src/org/videolan/vlc/gui/MainActivity.java     |   28 +++++++
>  .../vlc/gui/audio/AudioBrowserActivity.java        |    4 +-
>  6 files changed, 122 insertions(+), 9 deletions(-)
> 
> diff --git a/vlc-android/res/menu/media_library.xml b/vlc-android/res/menu/media_library.xml
> index 06c0166..bc2ee09 100644
> --- a/vlc-android/res/menu/media_library.xml
> +++ b/vlc-android/res/menu/media_library.xml
> @@ -25,4 +25,8 @@
>          android:id="@+id/ml_menu_refresh"
>          android:icon="@drawable/ic_menu_refresh"
>          android:title="@string/refresh" />
> +    <item
> +        android:id="@+id/ml_menu_open_stream"
> +        android:icon="@android:drawable/ic_btn_speak_now"
> +        android:title="@string/open_stream" />
>  </menu>
> diff --git a/vlc-android/res/values/strings.xml b/vlc-android/res/values/strings.xml
> index 541132b..b1810ac 100644
> --- a/vlc-android/res/values/strings.xml
> +++ b/vlc-android/res/values/strings.xml
> @@ -78,4 +78,5 @@
>      <string name="track_video_info">Codec: %1$s\nResolution: %2$dx%3$d</string>
>      <string name="track_text">Subtitles track</string>
>      <string name="track_unknown">Unknown track</string>
> +    <string name="open_stream">Open Stream</string>
>  </resources>
> diff --git a/vlc-android/src/org/videolan/vlc/AudioService.java b/vlc-android/src/org/videolan/vlc/AudioService.java
> index 233c276..cd681d2 100644
> --- a/vlc-android/src/org/videolan/vlc/AudioService.java
> +++ b/vlc-android/src/org/videolan/vlc/AudioService.java
> @@ -292,7 +292,7 @@ public class AudioService extends Service {
>                  return;
>              }
>          }
> -        mLibVLC.readMedia(mCurrentMedia.getPath());
> +        mLibVLC.readMedia(mCurrentMedia.getMRL());
>          mHandler.sendEmptyMessage(SHOW_PROGRESS);
>          showNotification();
>          updateWidget(this);
> @@ -306,7 +306,7 @@ public class AudioService extends Service {
>              mCurrentMedia = mMediaList.get(index - 1);
>          else
>              return;
> -        mLibVLC.readMedia(mCurrentMedia.getPath());
> +        mLibVLC.readMedia(mCurrentMedia.getMRL());
>          mHandler.sendEmptyMessage(SHOW_PROGRESS);
>          showNotification();
>          updateWidget(this);
> @@ -418,7 +418,7 @@ public class AudioService extends Service {
>              if (mCurrentMedia != null)
>                  return mCurrentMedia.getTitle();
>              else
> -                return null;
> +                return "(null)";

Why?

>          }
>  
>          public Bitmap getCover() {

> @@ -470,6 +470,10 @@ public class AudioService extends Service {
>              for (int i = 0; i < mediaPathList.size(); i++) {
>                  String path = mediaPathList.get(i);
>                  Media media = db.getMedia(AudioService.this, path);
> +                if(media == null) {
> +                    Log.v(TAG, "Creating remote Media object for " + path);
> +                    media = new Media(AudioService.this, path);
> +                }
>                  mMediaList.add(media);
>              }
>  
> @@ -478,7 +482,7 @@ public class AudioService extends Service {
>              }
>  
>              if (mCurrentMedia != null)
> -                mLibVLC.readMedia(mCurrentMedia.getPath());
> +                mLibVLC.readMedia(mCurrentMedia.getMRL());
>              showNotification();
>          }
>  
> diff --git a/vlc-android/src/org/videolan/vlc/Media.java b/vlc-android/src/org/videolan/vlc/Media.java
> index 9f1662c..25c2cdc 100644
> --- a/vlc-android/src/org/videolan/vlc/Media.java
> +++ b/vlc-android/src/org/videolan/vlc/Media.java
> @@ -21,6 +21,8 @@
>  package org.videolan.vlc;
>  
>  import java.io.File;
> +import java.net.MalformedURLException;
> +import java.net.URL;
>  
>  import android.content.Context;
>  import android.graphics.Bitmap;
> @@ -63,6 +65,7 @@ public class Media implements Comparable<Media> {
>      private String mTrackID;
>  
>      private File mFile;
> +    private String mMRL;
>      private long mTime = 0;
>      private long mLength = 0;
>      private int mType;
> @@ -76,7 +79,10 @@ public class Media implements Comparable<Media> {
>       */
>      public Media(Context context, File file) {
>          this.mFile = file;
> -
> +        // LibVLC expects the file:///sdcard/... format, but by default
> +        // Java gives file:/sdcard, which angers LibVLC
> +        mMRL = file.toURI().toString().replace("file:/", "file:///");
> +        

I see this same code is used below, this should go into one unique place
so we don't forget to use it.

FixURI(file.toURI()) ?

>          LibVLC mLibVlc = null;
>          try {
>              mLibVlc = LibVLC.getInstance();
> @@ -112,10 +118,57 @@ public class Media implements Comparable<Media> {
>          DatabaseManager db = DatabaseManager.getInstance(context);
>          db.addMedia(this);
>      }
> +    
> +    /**
> +     * Create a new remote Media
> +     * @param file: any valid MRL that LibVLC accepts
> +     */

Thanks for highlighting this problem.

There should not be a notion of "remote Media", all medias are the same
for VLC, wether they are files or not.

That's why even for files we should use URLs (or MRLs).

And new_media() should use libvlc_media_new_location.

libvlc_media_new_path() just calls libvlc_media_new_location() with
unmodified argument if it is already an URI, else it adds file:// and
URL encodes the file path.

Since java can give us URIs already (although a bit buggy like you
noticed) then we should use them everywhere, it would be much simpler.

I will add this to my TODO list if you don't want to work on it, else I
think I and others can help you on IRC since we went through this
already in VLC some time ago (as wisely pointed out by courmisch).

> +    public Media(Context context, String _mrl) {
> +        this.mFile = null;
> +        this.mMRL = _mrl;
> +
> +        LibVLC mLibVlc = null;
> +        try {
> +            mLibVlc = LibVLC.getInstance();
> +            mType = (mLibVlc.hasVideoTrack(mMRL)) ? TYPE_VIDEO : TYPE_AUDIO;
> +            mLength = mLibVlc.getLengthFromFile(mMRL);
> +
> +            String[] array = mLibVlc.readMediaMeta(mMRL);
> +
> +            int i;
> +            for (i = 0; i < array.length; i++) {
> +                String s = array[i++];
> +                String v = array[i];
> +
> +                if (s.equals("title")) {
> +                    mTitle = v;
> +                    Log.d(TAG, "Title " + mTitle);
> +                } else if (s.equals("artist")) {
> +                    mArtist = Util.getValue(context, v, R.string.unknown_artist);
> +                    Log.d(TAG, "Artist " + mArtist);
> +                } else if (s.equals("genre")) {
> +                    mGenre = Util.getValue(context, v, R.string.unknown_genre);
> +                    Log.d(TAG, "Genre " + mGenre);
> +                } else if (s.equals("album")) {
> +                    mAlbum = Util.getValue(context, v, R.string.unknown_album);
> +                    Log.d(TAG, "Album " + mAlbum);
> +                }
> +            }
> +        } catch (LibVlcException e) {
> +            e.printStackTrace();
> +        }
> +
> +        // Add this item to database
> +        //DatabaseManager db = DatabaseManager.getInstance(context);
> +        //db.addMedia(this);
> +    }
>  
>      public Media(Context context, File file, long time, long length, int type,
>              Bitmap picture, String title, String artist, String genre, String album) {
>          mFile = file;
> +        // LibVLC expects the file:///sdcard/... format, but by default
> +        // Java gives file:/sdcard, which angers LibVLC
> +        mMRL = file.toURI().toString().replace("file:/", "file:///");
>          mTime = time;
>          mLength = length;
>          mType = type;
> @@ -134,13 +187,33 @@ public class Media implements Comparable<Media> {
>          return mTitle.toUpperCase().compareTo(
>                  another.getTitle().toUpperCase());
>      }
> +    
> +    /**
> +     * Convert to string for debugging aid
> +     */
> +    public String toString() {
> +        String buf = "";
> +        buf += "Media information:\n";
> +        buf += "Media Path: " + ((mFile == null) ? "none" : mFile.getPath());
> +        buf += "Media MRL: " + mMRL.toString();
> +        buf += "Media Title: " + mTitle;
> +        return buf;
> +    }
>  
>      public File getFile() {
>          return mFile;
>      }
>  
>      public String getPath() {
> -        return mFile.getPath();
> +        if(mFile == null) {
> +            return mMRL;
> +        } else {
> +            return mFile.getPath();
> +        }
> +    }
> +    
> +    public String getMRL() {
> +        return mMRL;
>      }
>  
>      public void updateMeta() {
> @@ -190,7 +263,10 @@ public class Media implements Comparable<Media> {
>  
>      public String getTitle() {
>          if (mTitle == null)
> -            return mFile.getName().substring(0, mFile.getName().lastIndexOf('.'));
> +            if (mFile != null)
> +                return mFile.getName().substring(0, mFile.getName().lastIndexOf('.'));
> +            else
> +                return mMRL;
>          else
>              return mTitle;
>      }

That's weird, libvlc has a fallback for when there is no title metadata
already, it should set Title to the filename or something.

Title metadata should never be NULL.

> diff --git a/vlc-android/src/org/videolan/vlc/gui/MainActivity.java b/vlc-android/src/org/videolan/vlc/gui/MainActivity.java
> index 2660948..42049a5 100644
> --- a/vlc-android/src/org/videolan/vlc/gui/MainActivity.java
> +++ b/vlc-android/src/org/videolan/vlc/gui/MainActivity.java
> @@ -20,8 +20,12 @@
>  
>  package org.videolan.vlc.gui;
>  
> +import java.util.ArrayList;
> +import java.util.List;
> +
>  import org.videolan.vlc.AudioServiceController;
>  import org.videolan.vlc.LibVLC;
> +import org.videolan.vlc.LibVlcException;
>  import org.videolan.vlc.MediaLibrary;
>  import org.videolan.vlc.R;
>  import org.videolan.vlc.gui.audio.AudioActivityGroup;
> @@ -33,10 +37,12 @@ import org.videolan.vlc.widget.AudioMiniPlayer;
>  
>  import android.app.Activity;
>  import android.app.ActivityGroup;
> +import android.app.AlertDialog;
>  import android.app.Dialog;
>  import android.app.TabActivity;
>  import android.content.BroadcastReceiver;
>  import android.content.Context;
> +import android.content.DialogInterface;
>  import android.content.Intent;
>  import android.content.IntentFilter;
>  import android.content.SharedPreferences;
> @@ -232,6 +238,28 @@ public class MainActivity extends TabActivity {
>              case R.id.ml_menu_refresh:
>                  MediaLibrary.getInstance(this).loadMediaItems(this);
>                  break;
> +            case R.id.ml_menu_open_stream:
> +                AlertDialog.Builder b = new AlertDialog.Builder(this);
> +                final android.widget.EditText input = new android.widget.EditText(this);
> +                b.setTitle("Resource MRL");
> +                b.setMessage("e.g. rtsp:// or http://");
> +                b.setView(input);
> +                b.setPositiveButton("Open", new DialogInterface.OnClickListener() {
> +                        public void onClick(DialogInterface dialog, int button) {
> +                            AudioServiceController c = AudioServiceController.getInstance();
> +                            ArrayList<String> media = new ArrayList<String>();
> +                            media.add(input.getText().toString());
> +                            c.append(media);
> +                        }
> +                    }
> +                );
> +                b.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
> +                    @Override
> +                    public void onClick(DialogInterface arg0, int arg1) {
> +                        return;
> +                    }});
> +                b.show();
> +                break;
>          }
>          return super.onOptionsItemSelected(item);
>      }
> diff --git a/vlc-android/src/org/videolan/vlc/gui/audio/AudioBrowserActivity.java b/vlc-android/src/org/videolan/vlc/gui/audio/AudioBrowserActivity.java
> index 0e9a76f..e486257 100644
> --- a/vlc-android/src/org/videolan/vlc/gui/audio/AudioBrowserActivity.java
> +++ b/vlc-android/src/org/videolan/vlc/gui/audio/AudioBrowserActivity.java
> @@ -20,6 +20,7 @@
>  
>  package org.videolan.vlc.gui.audio;
>  
> +import java.util.ArrayList;
>  import java.util.Collections;
>  import java.util.Comparator;
>  import java.util.List;
> @@ -192,8 +193,7 @@ public class AudioBrowserActivity extends Activity implements ISortable {
>          else
>              mAudioController.load(medias, start_position);
>  
> -        Intent intent = new Intent(AudioBrowserActivity.this, AudioPlayerActivity.class);
> -        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
> +        Intent intent = new Intent(AudioBrowserActivity.this, AudioPlayerActivity.class);        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

unintended?

>          startActivity(intent);
>          return super.onContextItemSelected(item);
>      }



More information about the Android mailing list