解析M3U音樂連結檔案,解析m3u連結
M3U本質上說不是音頻檔案,它是音頻檔案的列表檔案,是純文字檔案。你下載下來開啟它,播放軟體並不是播放它,而是根據它的記錄找到網路地址進行線上播放。
下面我們來解析m3u檔案中的音樂網路地址:
一、介面如下:介面很簡單,一個輸入框(輸入一個m3u檔案連結),然後解析、開始和終止按鈕。解析完成後,開始按鈕獲得焦點
播放從m3u檔案解析的音樂
二、xml檔案如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/m3uTextPath" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="60dip" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/parse" android:onClick="mainCLick" android:text="解析" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/start" android:onClick="mainCLick" android:text="開始" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/stop" android:onClick="mainCLick" android:text="終止" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/pausePull" android:onClick="mainCLick" android:text="pull解析" /> </LinearLayout> <!-- id為@id/android:list的ListView為客戶化的list布局,如果沒有,則系統會調用預設的布局 --><ListView android:id="@id/android:list" android:layout_width="fill_parent"android:layout_height="wrap_content" android:background="#00FF00"android:drawSelectorOnTop="false" android:layout_marginTop="100dip"/> <!-- 當ListView中沒有資料時,id為@id/android:empty的view就會顯示出來 --><TextView android:id="@id/android:empty" android:layout_width="fill_parent"android:layout_height="wrap_content" android:textColor="#FF0000"android:text="No data" android:gravity="center_vertical|center_horizontal" android:layout_marginTop="110dip"/></RelativeLayout>
三、activity
package com.example.m3upulltest;import java.io.IOException;import java.io.InputStream;import java.util.List;import com.example.parseUtil.M3UParser;import com.example.parseUtil.Person;import com.example.parseUtil.netXmlPause;import android.app.ListActivity;import android.media.MediaPlayer;import android.os.Bundle;import android.util.Log;import android.view.Menu;import android.view.View;import android.widget.ArrayAdapter;import android.widget.Button;import android.widget.EditText;import android.widget.ListAdapter;import android.widget.Toast;public class MainActivity extends ListActivity {/** * Android支援播放網路上的Audio * 訪問網路上的Audio,我們通過Http需要擷取音頻流 * 這可能要涉及到ICY協議。ICY對Http協議進行了擴充 * 然而,網路上的網站,往往並不允許我們直接存取其音頻流 * 我們需要一種中間檔案來指向我們需要的音頻流的地址,以使第三方的軟體可以播放。 * 對於ICY流來說,其就是一個PLS檔案或者一個M3U檔案 * PLS對應的MIME類型為:audio/x-scpls * M3U對應的MIME類型為:audio/x-mpegurl * * 雖然Android提供了對ICy流的支援,但是其並沒有提供現成的方法來解析M3U或PLS檔案 * 所以,為了播放網路上的音頻流,我們需要自己實現這些檔案的解析 * M3U檔案其實就是一個音頻流的索引檔案,他指向要播放的音頻流的路徑。 * @author Administrator * */ //private EditText m3uTextPath;private Button btnParse, btnPlay, btnStop; private EditText editUrl; private MediaPlayer player; private List<String> pathList; private int currPosition = 0; //記錄當前播放的媒體檔案的index protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);editUrl = (EditText)findViewById(R.id.m3uTextPath);btnParse = (Button)this.findViewById(R.id.parse); btnPlay = (Button)this.findViewById(R.id.start); btnStop = (Button)this.findViewById(R.id.stop); editUrl.setText("http://pubint.ic.llnwd.net/stream/pubint_kmfa.m3u"); // InputMethodManager imm = (InputMethodManager)this.getSystemService(INPUT_METHOD_SERVICE); btnPlay.setEnabled(false); btnStop.setEnabled(false); player = new MediaPlayer(); player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { public void onCompletion(MediaPlayer player) { // 這個方法當MediaPlayer的play()執行完後觸發 player.stop(); player.reset(); if(pathList.size() > currPosition+1){ currPosition++; //轉到下一首 prepareToPlay(); } } }); player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { //緩衝完成執行 public void onPrepared(MediaPlayer arg0) { // 這個方法當MediaPlayer的prepare()執行完後觸發 btnStop.setEnabled(true); player.start(); //當一曲播放完後,執行onCompletionListener的onCompletion方法 } }); }/** * 播放音樂 */private void prepareToPlay(){ try { //擷取當前音頻流的路徑後我們需要通過MediaPlayer的setDataSource來設定,然後調用prepareAsync()來完成緩衝載入 String path = pathList.get(currPosition); player.setDataSource(path); //之所以使用prepareAsync是因為該方法是非同步,因為訪問音頻流是網路操作,在緩衝和準備播放時需要花費 //較長的時間,這樣使用者介面就可能出現卡死的現象 //該方法執行完成後,會執行onPreparedListener的onPrepared()方法。 player.prepareAsync();//非同步線程避免卡死 } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalStateException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 按鈕事件 * @throws Exception */public void mainCLick(View v) throws Exception{switch (v.getId()) {case R.id.parse://完成解析 // progress = ProgressDialog.show(this, "提示", "正在解析,請稍後..."); // progress.show(); String url = null; if(editUrl.getText() != null){ url = editUrl.getText().toString(); } if(url != null && !url.trim().equals("")){ pathList = M3UParser.parseStringFromUrl(url); ListAdapter adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, pathList); this.setListAdapter(adapter); btnPlay.setEnabled(true); }else{ Toast.makeText(this, "請輸入正確的M3U檔案訪問地址", Toast.LENGTH_LONG).show(); } break;case R.id.start: //這裡播放是從第一個開始 btnPlay.setEnabled(false); btnParse.setEnabled(false); this.currPosition = 0; if(pathList != null && pathList.size() > 0){ prepareToPlay(); } break; case R.id.stop: player.pause(); btnPlay.setEnabled(true); btnStop.setEnabled(false); break; default:break;}}//菜單public boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}}三、解析代碼:
package com.example.parseUtil;import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.List;import org.apache.http.HttpResponse;import com.example.HTTPServer.HttpConnect;public class M3UParser {/** * 返回List<String>類型 * @param url * @return */public static List<String> parseStringFromUrl(String url) {List<String> resultList = null; HttpResponse res = HttpConnect.getResponseFromUrl(url); try { if(res != null){ resultList = new ArrayList<String>(); InputStream in = res.getEntity().getContent(); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); String line = ""; while((line = reader.readLine()) != null){ if(line.startsWith("#")){ //這裡是Metadata資訊 }else if(line.length() > 0 && line.startsWith("http://")){ //這裡是一個指向的音頻流路徑 resultList.add(line); } } in.close(); } } catch (Exception e) { e.printStackTrace(); } return resultList; }/** * 從指定的Url進行解析,返回一個包含FilePath對象的列表 * FilePath封裝每一個Audio路徑。 * @param url * @return */ public static List<FilePath> parseFromUrl(String url) { List<FilePath> resultList = null; HttpResponse response = HttpConnect.getResponseFromUrl(url); try { if(response != null){ resultList = new ArrayList<M3UParser.FilePath>(); InputStream in = response.getEntity().getContent(); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); String line = ""; while((line = reader.readLine()) != null){ if(line.startsWith("#")){ //這裡是Metadata資訊 }else if(line.length() > 0 && line.startsWith("http://")){ //這裡是一個指向的音頻流路徑 FilePath filePath = new FilePath(line); resultList.add(filePath); } } in.close(); } } catch (Exception e) { e.printStackTrace(); } return resultList; } //解析後的實體物件 static class FilePath{ private String filePath; public FilePath(String filePath){ this.filePath = filePath; } public String getFilePath() { return filePath; } public void setFilePath(String filePath) { this.filePath = filePath; } } }