2017-07-24 71 views
0

我有我自己的MediaDataSource
MediaExtractor不理解音頻/ AACP流



    class MyDataSource extends MediaDataSource { 
     private static final String TAG = "MyDataSource"; 
     private HttpURLConnection connection; 
     private BufferedInputStream inputStream; 

     MyDataSource(@NonNull URL streamURL) throws Throwable { 
      this.connection = (HttpURLConnection) streamURL.openConnection(); 
      this.connection.setRequestMethod("GET"); 
      this.connection.addRequestProperty("Icy-Metadata", "0"); 
      this.connection.connect(); 
      int responseCode = this.connection.getResponseCode(); 
      if (responseCode != 200) 
       throw new IOException("http response code " + responseCode); 
      for (Map.Entry<String, List<String>> header: this.connection.getHeaderFields().entrySet()) { 
       for (String headerValue : header.getValue()) 
        Log.v(TAG, "responseHeader(" + header.getKey() + ") = \"" + headerValue + "\""); 
      } 
      this.inputStream = new BufferedInputStream(connection.getInputStream()); 
     } 

     @Override 
     public long getSize() { 
      return -1; 
     } 

     @Override 
     public int readAt(long position, @NonNull byte[] buffer, int offset, int size) throws IOException { 
      int bytesRead; 
      int bytesReadTotal = 0; 
      do { 
       bytesRead = this.inputStream.read(buffer, offset + bytesReadTotal, size - bytesReadTotal); 
       bytesReadTotal += bytesRead; 
      } while(bytesRead != 0 && bytesReadTotal < size); 
      return bytesReadTotal; 
     } 

     @Override 
     public void close() { 
      try { 
       if (inputStream != null) { 
        inputStream.close(); 
        inputStream = null; 
       } 
       if (connection != null) { 
        connection.disconnect(); 
        connection = null; 
       } 
      } catch(IOException e) { 
       Log.e(TAG, "close", e); 
      } 
     } 
    } 

,當我嘗試播放MP3流(例如A.0.0.00Radio):



    MyDataSource dataSource = new MyDataSource(new URL("http://streaming.shoutcast.com/80sPlanet")); 
    MediaExtractor mediaExtractor = new MediaExtractor(); 
    mediaExtractor.setDataSource(); 
    MediaFormat mediaFormat = mediaExtractor.getTrackFormat(0); 
    String mime = mediaFormat.getString(MediaFormat.KEY_MIME); 
    Log.v("Player", "mime: " + mime); 
    mediaExtractor.selectTrack(0); 
    MediaCodec mediaCodec = MediaCodec.createDecoderByType(mime); 
    mediaCodec.configure(this.mediaFormat, null, null, 0); 
    int sampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE); 
    AudioTrack audioTrack = new AudioTrack(
     AudioManager.STREAM_MUSIC, 
     sampleRate, 
     AudioFormat.CHANNEL_OUT_STEREO, 
     AudioFormat.ENCODING_PCM_16BIT, 
     AudioTrack.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT), 
     AudioTrack.MODE_STREAM); 
    mediaCodec.setCallback(new MyCodecCallback()); 
    mediaCodec.start(); 
    audioTrack.play(); 

我看到以下Logcat trace

 

    07-24 18:11:49.958 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(null) = "HTTP/1.1 200 OK" 
    07-24 18:11:49.958 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Access-Control-Allow-Headers) = "Origin, Accept, X-Requested-With, Content-Type" 
    07-24 18:11:49.958 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Access-Control-Allow-Methods) = "GET, OPTIONS, HEAD" 
    07-24 18:11:49.958 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Access-Control-Allow-Origin) = "*" 
    07-24 18:11:49.958 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Cache-Control) = "no-cache, no-store" 
    07-24 18:11:49.958 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Connection) = "close" 
    07-24 18:11:49.958 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Content-Type) = "audio/mpeg" 
    07-24 18:11:49.958 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Date) = "Mon, 24 Jul 2017 18:11:59 GMT" 
    07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Expires) = "Mon, 26 Jul 1997 05:00:00 GMT" 
    07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-br) = "128" 
    07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-genre) = "Decades,80s" 
    07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-name) = "A.0.0.00Radio:All 80s All The Time" 
    07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-notice1) = "<BR>This stream requires <a href="http://www.winamp.com">Winamp</a><BR>" 
    07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-notice2) = "SHOUTcast DNAS/posix(linux x64) v2.5.1.725<BR>" 
    07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-pub) = "1" 
    07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-sr) = "44100" 
    07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-url) = "http://a.0.00radio.com/80s/" 
    07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Pragma) = "no-cache" 
    07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Server) = "Icecast 2.3.3-kh8" 
    07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Received-Millis) = "1500919909958" 
    07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Response-Source) = "NETWORK 200" 
    07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Selected-Protocol) = "http/1.1" 
    07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Sent-Millis) = "1500919909816" 
    07-24 18:11:49.961 7408-7671/com.sample.sandbox E/WVMExtractor: Failed to open libwvm.so: dlopen failed: library "libwvm.so" not found 
    07-24 18:11:49.962 7408-7671/com.sample.sandbox V/Player: mime: audio/mpeg 
    07-24 18:11:49.964 7408-7681/com.sample.sandbox I/OMXClient: Using client-side OMX mux. 
    07-24 18:11:50.170 7408-7681/com.sample.sandbox I/MediaCodec: MediaCodec will operate in async mode 
    [...] 

似乎一切正常(流實際上是通過設備播放)。
但是,如果我嘗試打開AAC流(例如COOLfahrenheit 93):



    MyDataSource dataSource = new MyDataSource(new URL("http://111.223.51.8:8005")); 
    [...] 

MediaExtractor發瘋:

 
    07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(null) = "HTTP/1.0 200 OK" 
    07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(content-type) = "audio/aacp" 
    07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(icy-br) = "128" 
    07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(icy-genre) = "Easy Listening, Pop" 
    07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(icy-name) = "COOLfahrenheit 93 - (4)" 
    07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(icy-notice1) = "<BR>This stream requires <a href="http://www.winamp.com">Winamp</a><BR>" 
    07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(icy-notice2) = "SHOUTcast DNAS/posix(linux x64) v2.4.7.256<BR>" 
    07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(icy-pub) = "1" 
    07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(icy-url) = " http://www.coolism.net " 
    07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Received-Millis) = "1500921523862" 
    07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Response-Source) = "NETWORK 200" 
    07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Selected-Protocol) = "http/1.0" 
    07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Sent-Millis) = "1500921523387" 
    07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(X-Clacks-Overhead) = "GNU Terry Pratchett" 
    07-24 18:38:45.424 32284-32690/com.sample.sandbox E/WVMExtractor: Failed to open libwvm.so: dlopen failed: library "libwvm.so" not found 
    07-24 18:38:45.425 32284-32690/com.sample.sandbox E/PlayerThread: error 
                       java.io.IOException: Failed to instantiate extractor. 
                        at android.media.MediaExtractor.setDataSource(Native Method) 
                        at com.sample.sandbox.Player.open(Player.java:204) 
                        at com.sample.sandbox.Player.<init>(Player.java:231) 
                        at com.sample.sandbox.PlayerThread.run(PlayerThread.java:28) 

有誰知道問題是什麼?問題肯定不在流本身 - 它完全有效。

回答

0

我的主要錯誤是忽略MediaDataSource::readAt()方法的position參數。
事實證明,MediaExtractor通過文件執行很多跳過(向前和向後! - 這是非常惱人的,當你流HLS)。
我已經注意到這些跳過的數量(及其範圍)取決於內容類型以及特定的編解碼器。我在這個問題上的主要觀點是「MediaExtractor不明白aacp」,因爲AAC編解碼器強烈要求跳過,但是MP3編解碼器不支持。