wxr
2020-06-15 b8e94316e41eba72d927d5ca7d931b26139ee8ff
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
/*****************************************************************************
 * MediaList.java
 *****************************************************************************
 * Copyright © 2013 VLC authors and VideoLAN
 * Copyright © 2013 Edward Wang
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/
package org.videolan.libvlc;
 
import java.util.ArrayList;
 
import android.os.Bundle;
 
/**
 * Java/JNI wrapper for the libvlc_media_list_t structure.
 */
public class MediaList {
    private static final String TAG = "VLC/LibVLC/MediaList";
 
    /* Since the libvlc_media_t is not created until the media plays, we have
     * to cache them here. */
    private class MediaHolder {
        Media m;
        boolean noVideo; // default false
        boolean noHardwareAcceleration; // default false
 
        public MediaHolder(Media media) {
            m = media; noVideo = false; noHardwareAcceleration = false;
        }
        public MediaHolder(Media m_, boolean noVideo_, boolean noHardwareAcceleration_) {
            m = m_; noVideo = noVideo_; noHardwareAcceleration = noHardwareAcceleration_;
        }
    }
 
    /* TODO: add locking */
    private ArrayList<MediaHolder> mInternalList;
    private LibVLC mLibVLC; // Used to create new objects that require a libvlc instance
    private EventHandler mEventHandler;
 
    public MediaList(LibVLC libVLC) {
        mEventHandler = new EventHandler(); // used in init() below to fire events at the correct targets
        mInternalList = new ArrayList<MediaHolder>();
        mLibVLC = libVLC;
    }
 
    /**
     * Adds a media URI to the media list.
     *
     * @param mrl
     *            The MRL to add. Must be a location and not a path.
     *            {@link LibVLC#PathToURI(String)} can be used to convert a path
     *            to a MRL.
     */
    public void add(String mrl) {
        add(new Media(mLibVLC, mrl));
    }
    public void add(Media media) {
        add(media, false, false);
    }
    public void add(Media media, boolean noVideo) {
        add(media, noVideo, false);
    }
    public void add(Media media, boolean noVideo, boolean noHardwareAcceleration) {
        mInternalList.add(new MediaHolder(media, noVideo, noHardwareAcceleration));
        signal_list_event(EventHandler.CustomMediaListItemAdded, mInternalList.size() - 1, media.getLocation());
    }
 
    /**
     * Clear the media list. (remove all media)
     */
    public void clear() {
        // Signal to observers of media being deleted.
        for(int i = 0; i < mInternalList.size(); i++) {
            signal_list_event(EventHandler.CustomMediaListItemDeleted, i, mInternalList.get(i).m.getLocation());
        }
        mInternalList.clear();
    }
 
    private boolean isValid(int position) {
        return position >= 0 && position < mInternalList.size();
    }
 
    /**
     * This function checks the currently playing media for subitems at the given
     * position, and if any exist, it will expand them at the same position
     * and replace the current media.
     *
     * @param position The position to expand
     * @return -1 if no subitems were found, 0 if subitems were expanded
     */
    public int expandMedia(int position) {
        ArrayList<String> children = new ArrayList<String>();
        int ret = expandMedia(mLibVLC, position, children);
        if(ret == 0) {
            mEventHandler.callback(EventHandler.CustomMediaListExpanding, new Bundle());
            this.remove(position);
            for(String mrl : children) {
                this.insert(position, mrl);
            }
            mEventHandler.callback(EventHandler.CustomMediaListExpandingEnd, new Bundle());
        }
        return ret;
    }
    private native int expandMedia(LibVLC libvlc_instance, int position, ArrayList<String> children);
 
    public void loadPlaylist(String mrl) {
        ArrayList<String> items = new ArrayList<String>();
        loadPlaylist(mLibVLC, mrl, items);
        this.clear();
        for(String item : items) {
            this.add(item);
        }
    }
    private native void loadPlaylist(LibVLC libvlc_instance, String mrl, ArrayList<String> items);
 
    public void insert(int position, String mrl) {
        insert(position, new Media(mLibVLC, mrl));
    }
    public void insert(int position, Media media) {
        mInternalList.add(position, new MediaHolder(media));
        signal_list_event(EventHandler.CustomMediaListItemAdded, position, media.getLocation());
    }
 
    /**
     * Move a media from one position to another
     *
     * @param startPosition start position
     * @param endPosition end position
     * @throws IndexOutOfBoundsException
     */
    public void move(int startPosition, int endPosition) {
        if (!(isValid(startPosition)
              && endPosition >= 0 && endPosition <= mInternalList.size()))
            throw new IndexOutOfBoundsException("Indexes out of range");
 
        MediaHolder toMove = mInternalList.get(startPosition);
        mInternalList.remove(startPosition);
        if (startPosition >= endPosition)
            mInternalList.add(endPosition, toMove);
        else
            mInternalList.add(endPosition - 1, toMove);
        Bundle b = new Bundle();
        b.putInt("index_before", startPosition);
        b.putInt("index_after", endPosition);
        mEventHandler.callback(EventHandler.CustomMediaListItemMoved, b);
    }
 
    public void remove(int position) {
        if (!isValid(position))
            return;
        String uri = mInternalList.get(position).m.getLocation();
        mInternalList.remove(position);
        signal_list_event(EventHandler.CustomMediaListItemDeleted, position, uri);
    }
 
    public int size() {
        return mInternalList.size();
    }
 
    public Media getMedia(int position) {
        if (!isValid(position))
            return null;
        return mInternalList.get(position).m;
    }
 
    /**
     * @param position The index of the media in the list
     * @return null if not found
     */
    public String getMRL(int position) {
        if (!isValid(position))
            return null;
        return mInternalList.get(position).m.getLocation();
    }
 
    public String[] getMediaOptions(int position) {
        boolean noHardwareAcceleration = mLibVLC.getHardwareAcceleration() == 0;
        boolean noVideo = false;
        if (isValid(position))
        {
            if (!noHardwareAcceleration)
                noHardwareAcceleration = mInternalList.get(position).noHardwareAcceleration;
            noVideo = mInternalList.get(position).noVideo;
        }
        ArrayList<String> options = new ArrayList<String>();
 
        if (!noHardwareAcceleration) {
            /*
             * Set higher caching values if using iomx decoding, since some omx
             * decoders have a very high latency, and if the preroll data isn't
             * enough to make the decoder output a frame, the playback timing gets
             * started too soon, and every decoded frame appears to be too late.
             * On Nexus One, the decoder latency seems to be 25 input packets
             * for 320x170 H.264, a few packets less on higher resolutions.
             * On Nexus S, the decoder latency seems to be about 7 packets.
             */
            options.add(":file-caching=1500");
            options.add(":network-caching=1500");
            options.add(":codec=mediacodec,iomx,all");
        }
        if (noVideo)
            options.add(":no-video");
 
        return options.toArray(new String[options.size()]);
    }
 
    public EventHandler getEventHandler() {
        return mEventHandler;
    }
 
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("LibVLC Media List: {");
        for(int i = 0; i < size(); i++) {
            sb.append(((Integer)i).toString());
            sb.append(": ");
            sb.append(getMRL(i));
            sb.append(", ");
        }
        sb.append("}");
        return sb.toString();
    }
 
    private void signal_list_event(int event, int position, String uri) {
        Bundle b = new Bundle();
        b.putString("item_uri", uri);
        b.putInt("item_index", position);
        mEventHandler.callback(event, b);
    }
}