Commit bd6acc3548ce4666792ec956fdaea3fb59c51f00

Authored by Imanol-Mikel Barba Sabariego
1 parent 30f316ce

WIP con streaming... aun no va

res/layout/main_activity.xml
... ... @@ -11,16 +11,14 @@
11 11  
12 12 <ImageButton
13 13 android:id="@+id/button"
14   - android:layout_width="256dp"
15   - android:layout_height="256dp"
  14 + android:layout_width="192dip"
  15 + android:layout_height="192dip"
16 16 android:layout_centerHorizontal="true"
17 17 android:layout_centerVertical="true"
18 18 android:background="@drawable/startbuttontoggle"
19 19 android:contentDescription="@string/startbuttondescription"
20 20 android:focusable="false"
21 21 android:focusableInTouchMode="false"
22   - android:maxHeight="@dimen/lesize"
23   - android:maxWidth="@dimen/lesize"
24 22 android:scaleType="fitCenter" />
25 23  
26 24 <TextView
... ...
res/values/strings.xml
... ... @@ -29,5 +29,6 @@
29 29 <string name="alertVitamioNotInstalled">Alerta! Llibreries de Vitamio no instal·lades!</string>
30 30 <string name="alertLogoDescription">Alerta!</string>
31 31 <string name="itemType">Item type</string>
  32 + <string name="buffering_text">Buffering...</string>
32 33  
33 34 </resources>
34 35 \ No newline at end of file
... ...
src/com/upc/pbe/upcnews/Directoris.java
... ... @@ -6,8 +6,6 @@ import java.util.ArrayList;
6 6 import java.util.concurrent.ExecutionException;
7 7  
8 8 import android.app.Activity;
9   -import android.app.DownloadManager;
10   -import android.content.Context;
11 9 import android.content.Intent;
12 10 import android.os.Bundle;
13 11 import android.util.Log;
... ... @@ -61,12 +59,10 @@ public class Directoris extends Activity implements OnItemClickListener
61 59 }
62 60 catch (InterruptedException e)
63 61 {
64   - // TODO Auto-generated catch block
65 62 e.printStackTrace();
66 63 }
67 64 catch (ExecutionException e)
68 65 {
69   - // TODO Auto-generated catch block
70 66 e.printStackTrace();
71 67 }
72 68 catch (IOException e)
... ... @@ -106,8 +102,7 @@ public class Directoris extends Activity implements OnItemClickListener
106 102 ArrayList<ParentList> m3u8parsed = p.parseFile(playlist);
107 103 Log.d(TAG, "Parsing completat");
108 104 //Creem un gestor HLS
109   - DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
110   - HLS h = new HLS(m3u8parsed,((UpcApp)getApplication()).getLocalPath(), manager);
  105 + HLS h = new HLS(m3u8parsed,((UpcApp)getApplication()).getLocalPath());
111 106 ((UpcApp)getApplication()).setHLS(h);
112 107 //Iniciem la reproduccio
113 108 Intent mIntent = new Intent(this, VideoActivity.class);
... ... @@ -142,12 +137,10 @@ public class Directoris extends Activity implements OnItemClickListener
142 137 }
143 138 catch (InterruptedException e1)
144 139 {
145   - // TODO Auto-generated catch block
146 140 e1.printStackTrace();
147 141 }
148 142 catch (ExecutionException e1)
149 143 {
150   - // TODO Auto-generated catch block
151 144 e1.printStackTrace();
152 145 }
153 146 }
... ...
src/com/upc/pbe/upcnews/HLS.java
1 1 package com.upc.pbe.upcnews;
2 2  
  3 +import io.vov.vitamio.widget.VideoView;
  4 +
  5 +import java.io.BufferedInputStream;
3 6 import java.io.File;
  7 +import java.io.FileOutputStream;
4 8 import java.io.IOException;
  9 +import java.net.MalformedURLException;
  10 +import java.net.URL;
5 11 import java.util.ArrayList;
6 12  
7   -import android.app.DownloadManager;
8   -import android.app.DownloadManager.Request;
  13 +import android.app.AlertDialog;
9 14 import android.content.Context;
10 15 import android.net.TrafficStats;
11   -import android.net.Uri;
  16 +import android.os.AsyncTask;
12 17 import android.util.Log;
  18 +import android.view.LayoutInflater;
  19 +import android.widget.Toast;
13 20  
14 21 //Gestor del protocol HTTP Live Streaming
15 22 public class HLS
16 23 {
17   -
  24 + private static long TRIGGER_PLAY;
18 25 private static final String TAG = "HLS";
19 26 private ArrayList<ParentList> videos;
20 27 private ArrayList<Segment> segments;
... ... @@ -24,11 +31,15 @@ public class HLS
24 31 private int currentSegment;
25 32 private boolean endReached;
26 33 private String localFolder;
27   - private DownloadManager dm;
28 34 private BandwidthMeasurer bm;
  35 + private boolean started;
  36 + private boolean ended;
  37 + private long totalDownloaded;
  38 + private VideoView video;
  39 + private VideoActivity vActivity;
29 40  
30 41  
31   - public HLS(ArrayList<ParentList> parsed, String localFolder, DownloadManager manager)
  42 + public HLS(ArrayList<ParentList> parsed, String localFolder)
32 43 {
33 44 // Neteja el directori i inicialitza les variables
34 45 File dir = new File(localFolder);
... ... @@ -45,8 +56,47 @@ public class HLS
45 56 endReached = false;
46 57 this.localFolder = localFolder;
47 58 bm = new BandwidthMeasurer();
  59 + started = ended = false;
  60 + totalDownloaded = 0;
48 61 }
49 62  
  63 + public void setBufferSize()
  64 + {
  65 + /*
  66 + * Supondremos todos los segmentos de misma duración
  67 + */
  68 + if(qualities.get(currentQuality).getQuality() == -1)
  69 + {
  70 + /*
  71 + * No nos dicen la calidad, la pondremos al conocer la longitud del primer segmento
  72 + */
  73 + TRIGGER_PLAY = -1;
  74 + }
  75 + else
  76 + {
  77 + //15 segundos de cancha para empezar
  78 + TRIGGER_PLAY = (long) (15 * qualities.get(currentQuality).getQuality()/8e3);
  79 + }
  80 +
  81 + }
  82 +
  83 + public void quitPlayer(VideoActivity v)
  84 + {
  85 + video.stopPlayback();
  86 + v.finish();
  87 + return;
  88 + }
  89 +
  90 + public void setVideoViewer(VideoView v)
  91 + {
  92 + video = v;
  93 + }
  94 +
  95 + public void setVideoActivity(VideoActivity v)
  96 + {
  97 + vActivity = v;
  98 + }
  99 +
50 100 public void loadVideo()
51 101 {
52 102 // Carrega la qualitat i, a partir d'aixo, el seguent segment
... ... @@ -56,6 +106,7 @@ public class HLS
56 106 {
57 107 endReached = true;
58 108 }
  109 + setBufferSize();
59 110 }
60 111  
61 112 public String next() throws IOException
... ... @@ -71,59 +122,47 @@ public class HLS
71 122 }
72 123 Segment seg = segments.get(currentSegment++);
73 124 String path = localFolder+seg.getURL().substring(seg.getURL().lastIndexOf("/") + 1, seg.getURL().length());
74   - if(!new File(path).exists()) //Para qué bajarlo dos veces?
  125 + Log.d(TAG, seg.getName() + " " + seg.getURL());
  126 + return path;
  127 + }
  128 +
  129 + public void updateQuality(long bps)
  130 + {
  131 + if ((bps <= qualities.get(currentQuality).getQuality()) && (bps != -1))
75 132 {
76   - Log.d(TAG, seg.getName() + " " + seg.getURL());
77   - long startTime = System.currentTimeMillis();
78   - long segmentBytes = TrafficStats.getTotalRxBytes();
79   - descarregarguardar(seg.getURL(), localFolder);
80   - double bps = bm.Measure(segmentBytes, startTime);
81   - Log.d(TAG, "Velocitat actual (KB/s): " + (bps / 8e3));
82   - if ((bps <= qualities.get(currentQuality).getQuality()) && (bps != -1))
  133 + int newQuality;
  134 + for(newQuality = 0; newQuality < qualities.size(); newQuality++)
83 135 {
84   - int newQuality;
85   - for(newQuality = 0; newQuality < qualities.size(); newQuality++)
86   - {
87   - if(bps >= qualities.get(newQuality).getQuality())
88   - {
89   - break;
90   - }
91   - }
92   - if(currentQuality != newQuality)
  136 + if(bps >= qualities.get(newQuality).getQuality())
93 137 {
94   - currentQuality = newQuality;
95   - currentVideo--; //Corregimos el del loadVideo()
96   - loadVideo(); //Cargamos la nueva calidad
  138 + break;
97 139 }
98 140 }
99   - else if((bps > qualities.get(currentQuality).getQuality()) && (bps != -1))
  141 + if(currentQuality != newQuality)
100 142 {
101   - int newQuality;
102   - for(newQuality = qualities.size()-1; newQuality > 0; newQuality--)
103   - {
104   - if(bps <= qualities.get(newQuality).getQuality())
105   - {
106   - newQuality--;
107   - break;
108   - }
109   - }
110   - if(currentQuality != newQuality)
  143 + currentQuality = newQuality;
  144 + currentVideo--; //Corregimos el del loadVideo()
  145 + loadVideo(); //Cargamos la nueva calidad
  146 + }
  147 + }
  148 + else if((bps > qualities.get(currentQuality).getQuality()) && (bps != -1))
  149 + {
  150 + int newQuality;
  151 + for(newQuality = qualities.size()-1; newQuality > 0; newQuality--)
  152 + {
  153 + if(bps <= qualities.get(newQuality).getQuality())
111 154 {
112   - currentQuality = newQuality;
113   - currentVideo--; //Corregimos el del loadVideo()
114   - loadVideo(); //Cargamos la nueva calidad
  155 + newQuality--;
  156 + break;
115 157 }
116 158 }
  159 + if(currentQuality != newQuality)
  160 + {
  161 + currentQuality = newQuality;
  162 + currentVideo--; //Corregimos el del loadVideo()
  163 + loadVideo(); //Cargamos la nueva calidad
  164 + }
117 165 }
118   - return path;
119   - }
120   -
121   - public void descarregarguardar(String url, String path)
122   - {
123   - Request req = new Request(Uri.parse(url));
124   - req.setVisibleInDownloadsUi(false);
125   - req.setDestinationUri(Uri.parse("file://"+path + url.substring(url.lastIndexOf("/")+1, url.length())));
126   - dm.enqueue(req);
127 166 }
128 167  
129 168 public String previous() throws IOException
... ... @@ -136,9 +175,127 @@ public class HLS
136 175 seg = segments.get(currentSegment++);
137 176 return localFolder + seg.getURL().substring(seg.getURL().lastIndexOf("/") + 1, seg.getURL().length());
138 177 }
139   -
140   - public void startDownloadManager(Context ctx)
  178 +
  179 + public boolean hasEnded()
  180 + {
  181 + return ended;
  182 + }
  183 +
  184 + public void buffer()
  185 + {
  186 + video.stopPlayback();
  187 + started = false;
  188 + }
  189 +
  190 + public void downloadSegment(String url)
141 191 {
142   - dm = (DownloadManager) ctx.getSystemService("download");
  192 + DescarregaSegment ds = new DescarregaSegment(vActivity);
  193 + try
  194 + {
  195 + ds.execute(new URL(url));
  196 + }
  197 + catch (MalformedURLException e)
  198 + {
  199 + e.printStackTrace();
  200 + }
  201 + }
  202 +
  203 + public class DescarregaSegment extends AsyncTask<URL, Integer, Long>
  204 + {
  205 + final static String TAG = "DescarregaSegment";
  206 + private Context ctx;
  207 + private long bps;
  208 + AlertDialog alertDialog;
  209 +
  210 + public DescarregaSegment(Context c)
  211 + {
  212 + ctx = c;
  213 + bps = 0;
  214 + AlertDialog.Builder builder = new AlertDialog.Builder(vActivity);
  215 + LayoutInflater inflater = vActivity.getLayoutInflater();
  216 + builder.setView(inflater.inflate(R.layout.buffering_dialog,null));
  217 + alertDialog = builder.create();
  218 + }
  219 +
  220 +
  221 + @Override
  222 + protected Long doInBackground(URL... urls)
  223 + {
  224 + if(!started)
  225 + {
  226 + alertDialog.show();
  227 + }
  228 + Long downloaded = Long.valueOf(0);
  229 + long startTime = System.currentTimeMillis();
  230 + long segmentBytes = TrafficStats.getTotalRxBytes();
  231 + Log.d(TAG, "Velocitat actual (KB/s): " + (bps / 8e3));
  232 + // Iniciem la connexi� i creem els Streams
  233 + try
  234 + {
  235 + FileOutputStream out = new FileOutputStream(localFolder + "video.ts");
  236 + BufferedInputStream in = new BufferedInputStream(urls[0].openStream());
  237 + Log.d(TAG, "\nDescarregant: \n");
  238 + Log.d(TAG, ">> URL: " + urls[0]);
  239 + byte data[] = new byte[102400];
  240 + int count;
  241 + while ((count = in.read(data)) != -1)
  242 + {
  243 + downloaded += count;
  244 + out.write(data, 0, count);
  245 + }
  246 + out.flush();
  247 + out.close();
  248 + in.close();
  249 + bps = (long) bm.Measure(segmentBytes, startTime);
  250 + Log.d(TAG, "Descarrega finalitzada");
  251 + }
  252 + catch(IOException e)
  253 + {
  254 + this.cancel(true);
  255 + Toast.makeText(ctx, e.getMessage(), Toast.LENGTH_LONG).show();
  256 + return Long.valueOf(-1);
  257 + }
  258 + return downloaded;
  259 + }
  260 + protected void onPostExecute(Long result)
  261 + {
  262 + totalDownloaded += result;
  263 + if(ended = true)
  264 + {
  265 + quitPlayer((VideoActivity) ctx);
  266 + }
  267 + if(TRIGGER_PLAY == -1)
  268 + {
  269 + long Bps = (long) (result/segments.get(currentSegment).getDuration());
  270 + TRIGGER_PLAY = 15*Bps/1000;
  271 + }
  272 + if(!started && totalDownloaded >= TRIGGER_PLAY)
  273 + {
  274 + alertDialog.dismiss();
  275 + started = true;
  276 + video.start();
  277 + video.requestFocus();
  278 + }
  279 + String newSegment = null;
  280 + try
  281 + {
  282 + updateQuality((long) bps);
  283 + newSegment = next();
  284 + }
  285 + catch(IOException e)
  286 + {
  287 + Toast.makeText(ctx, "No s'ha trobat el segment", Toast.LENGTH_LONG).show();
  288 + quitPlayer((VideoActivity) ctx);
  289 + }
  290 + if(newSegment.equals(null))
  291 + {
  292 + ended = true;
  293 + }
  294 + else
  295 + {
  296 + downloadSegment(newSegment);
  297 + }
  298 + return;
  299 + }
143 300 }
144 301 }
145 302 \ No newline at end of file
... ...
src/com/upc/pbe/upcnews/MainActivity.java
... ... @@ -21,7 +21,8 @@ import android.widget.TextView;
21 21 import android.widget.Toast;
22 22  
23 23 //Finestra incial i activity principal del programa
24   -public class MainActivity extends Activity implements OnClickListener {
  24 +public class MainActivity extends Activity implements OnClickListener
  25 +{
25 26  
26 27 private final static String TAG = "Main";
27 28 private static String html;
... ... @@ -78,19 +79,18 @@ public class MainActivity extends Activity implements OnClickListener {
78 79 }
79 80 catch (InterruptedException e)
80 81 {
81   - // TODO Auto-generated catch block
82 82 e.printStackTrace();
83 83 }
84 84 catch (ExecutionException e)
85 85 {
86   - // TODO Auto-generated catch block
87 86 e.printStackTrace();
88 87 }
89 88 catch (MalformedURLException e)
90 89 {
91 90 Toast.makeText(this, "URL Malformada", Toast.LENGTH_LONG).show();
92 91 }
93   - if(!html.equals("")) {
  92 + if(!html.equals(""))
  93 + {
94 94 ((UpcApp) getApplication()).setDesc(html);
95 95 startActivity(new Intent(this, Directoris.class));
96 96 }
... ...
src/com/upc/pbe/upcnews/ParentList.java
... ... @@ -5,7 +5,6 @@ import java.util.ArrayList;
5 5 public class ParentList
6 6 {
7 7 private String ID;
8   - private int currentQuality;
9 8 private String Type, Name;
10 9 private boolean Default; //Estos 3 ultimos son para los ext-x-media, los ext-x-stream lo IGNORAN
11 10 private ArrayList<Video> lists; //per cada qualitat
... ... @@ -14,7 +13,6 @@ public class ParentList
14 13 public ParentList(String ID)
15 14 {
16 15 this.ID = ID;
17   - currentQuality = 0;
18 16 Type = "";
19 17 Name = "";
20 18 Default = false;
... ... @@ -30,15 +28,7 @@ public class ParentList
30 28 {
31 29 ID = id;
32 30 }
33   -
34   - public int getCurrentQuality()
35   - {
36   - return currentQuality;
37   - }
38   - public void setCurrentQuality(int q)
39   - {
40   - currentQuality = q;
41   - }
  31 +
42 32  
43 33 public boolean getDefault()
44 34 {
... ...
src/com/upc/pbe/upcnews/VideoActivity.java
... ... @@ -19,6 +19,7 @@ public class VideoActivity extends Activity {
19 19 private final static String TAG = "VideoActivity";
20 20 private VideoView video;
21 21 private HLS h = null;
  22 + private String filePath;
22 23  
23 24  
24 25 @Override
... ... @@ -34,20 +35,25 @@ public class VideoActivity extends Activity {
34 35 }
35 36  
36 37 setContentView(R.layout.activity_video);
  38 + filePath = ((UpcApp)getApplication()).getLocalPath() + "video.ts";
37 39 video = (VideoView) findViewById(R.id.VideoView1);
38 40 //Creem un listener associat al fi de l'activitat (el fi de cada ts)
39 41 io.vov.vitamio.widget.MediaController mc = new MediaController(this);
40 42 video.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
41 43 public void onCompletion(MediaPlayer mp) {
42 44 //Al acabar cada ts, reproduit el seguent
43   - playNext();
  45 + if(h.hasEnded())
  46 + {
  47 + finish();
  48 + return;
  49 + }
  50 + h.buffer();
44 51 }
45 52 });
46 53 mc.setOnFFLeftListener(new View.OnClickListener() {
47 54 public void onClick(View v) {
48 55 Log.d(TAG, "FFLEFT");
49   - video.stopPlayback();
50   - playPrevious();
  56 + video.seekTo(-100);
51 57 }
52 58 });
53 59 mc.setOnFFRightListener(new View.OnClickListener() {
... ... @@ -60,39 +66,29 @@ public class VideoActivity extends Activity {
60 66 video.setVideoQuality(MediaPlayer.VIDEOQUALITY_HIGH);
61 67 //Creem un gestor HLS, carreguem el video i iniciem la reproduccio
62 68 h = ((UpcApp)getApplication()).getHLS();
63   - h.startDownloadManager(this);
  69 + h.setVideoViewer(video);
  70 + h.setVideoActivity(this);
64 71 h.loadVideo();
65 72 video.stopPlayback();
66 73 video.setMediaController(mc);
67   - playNext();
68   - }
69   -
70   - public void play(String url) {
71   - if(url == null) {
72   - super.finish();
73   - return;
74   - }
75   - Log.d(TAG,"A reproduir: " + url);
76   - video.setVideoPath("file://" + url);
77   - video.start();
78   - video.requestFocus();
  74 + video.setVideoPath("file://" + filePath);
  75 + h.downloadSegment(playNext());
79 76 }
80 77  
81   - public void playNext() {
  78 + public String playNext() {
82 79 try {
83   - String next = h.next();
84   - play(next);
  80 + return h.next();
85 81 }
86 82 catch(IOException e) {
87 83 Toast.makeText(this, "No s'ha trobat el segment", Toast.LENGTH_LONG).show();
88 84 super.finish();
89   - return;
  85 + return "";
90 86 }
91 87 }
92 88 public void playPrevious() {
93 89 try {
94 90 String prev = h.previous();
95   - play(prev);
  91 + //play(prev);
96 92 }
97 93 catch(IOException e) {
98 94 Toast.makeText(this, "No s'ha trobat el segment", Toast.LENGTH_LONG).show();
... ... @@ -107,4 +103,5 @@ public class VideoActivity extends Activity {
107 103 video.setVideoLayout(VideoView.VIDEO_LAYOUT_SCALE, 0);
108 104 super.onConfigurationChanged(newConfig);
109 105 }
  106 +
110 107 }
111 108 \ No newline at end of file
... ...