2012-10-01 98 views
3

我正在嘗試在Android上爲OGG文件格式的音頻流媒體提取器工作。 我已經寫了一些代碼與谷歌文件的幫助。但它根本不起作用。 可能是我寫了一個錯誤的代碼或語法正如我是學生。 它告訴我沒有實例提取媒體提取器顯示「未能實例化提取器」

public void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.activity_main); 

MediaExtractor extractor = new MediaExtractor(); 
extractor.setDataSource("http://examplelink.com/ogg");// I cant put real link so sorry for that 
int numTracks = extractor.getTrackCount(); 
for (int i = 0; i < numTracks; ++i) { 
    MediaFormat format = extractor.getTrackFormat(i); 
    String mime = format.getString(MediaFormat.KEY_MIME); 
    extractor.selectTrack(i); 

    ByteBuffer inputBuffer = ByteBuffer.allocate(1024); 
    while (extractor.readSampleData(inputBuffer,0) >= 0) { 
      int trackIndex = (int) extractor.getSampleTime(); 
      long presentationTimeUs = extractor.getSampleTime(); 
    } 

    MediaCodec codec = MediaCodec.createDecoderByType(mime); 
    codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */); 
    codec.start(); 
    ByteBuffer[] inputBuffers = codec.getInputBuffers(); 
    ByteBuffer[] outputBuffers = codec.getOutputBuffers(); 
    format = codec.getOutputFormat(); 
    Long timeoutUs=(long) 1; 
    for (;;) { 
     int inputBufferIndex = codec.dequeueInputBuffer(timeoutUs); 
     if (inputBufferIndex >= 0) { 
      // fill inputBuffers[inputBufferIndex] with valid data 
      codec.queueInputBuffer(inputBufferIndex, 0, 128, 0,0); 
     } 
     MediaCodec.BufferInfo info = new BufferInfo(); 
     int outputBufferIndex = codec.dequeueOutputBuffer(info, timeoutUs); 
     if (outputBufferIndex >= 0) { 
      // outputBuffer is ready to be processed or rendered. 
      codec.releaseOutputBuffer(outputBufferIndex, false); 
     } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { 
      outputBuffers = codec.getOutputBuffers(); 
     } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { 
      // Subsequent data will conform to new format. 
      format = codec.getOutputFormat(); 
      AudioTrack mAudioTrack = null; 
      mAudioTrack.setPlaybackRate(format.getInteger(MediaFormat.KEY_SAMPLE_RATE)); 
     } 
     codec.stop(); 
     codec.release(); 
     codec = null; 
    } 
} 

}

+0

崩潰了我上線「的setDataSource」相同的消息被宣佈。 嘗試與SD卡和內部存儲...試圖FilePath和FileDescriptor ..不工作。 你有沒有想過出了什麼問題? – badbadboy

+0

@badbadboy還沒有我目前在我的應用程序中使用mp3流..但我正在等待新版本的android發佈,所以之後,我可以有更多的文件在媒體提取和代碼。 –

回答

2

我想你的問題是「爲什麼沒有在所有的工作?」 通常,這是一個太大的問題,但在這種情況下,它看起來像我根本不明白MediaExtractor MediaCodec如何工作。

雖然不是你的錯。該文件是神祕的,說得好。 但是,我已經成功地以這種方式播放音頻文件。

我的方案假設MediaCodec實現了一個異步緩衝區隊列。這個隊列中似乎有大約4個緩衝區。

所以我使用2個線程:一個線程將來自MediaExtractor的數據放入隊列,另一個線程將解碼後的音頻從隊列中取出並寫入AudioTrack。例如,在搜尋期間,需要非常小心以避免死鎖。我最終得到的代碼比您的代碼多得多。我不知道如何避免這種情況!

我想嘗試視頻。任何有用的參考將不勝感激!

+1

你的回答並不能真正幫助SwapAndroid解決他的問題。可以? –

+0

@SebastianAnnies和@ Don ..你們倆都是對的,我完全不明白..所以你可以與我分享你的工作代碼,所以我可以研究它並改進OGG流的代碼? –

+0

我有同樣的問題。 MediaExtractor在「SetDataSource」上崩潰。你做了什麼來使它工作? – badbadboy

1

代碼將是下面的東西,這是工作完美的我在JB平臺的本地音頻文件。

try{ 
    Extractor lExt = new MediaExtractor(); 
    lExt.setDataSource(file path); //I have tried with local file 
    lExt.setTrack(0); //For local file only one track will be present 
    MediaFormat format = lExt.getTrackFormat(0); //0 is the track ID 
    String mime = format.getString(MediaFormat.KEY_MIME); 
    MediaCodec codec = MediaCodec.createDecoderByType(mime); 
    codec.configure(
     format,//format of input data ::decoder OR desired format of the output data:encoder 
     null,//Specify a surface on which to render the output of this decoder 
     null,//Specify a crypto object to facilitate secure decryption 
     0 //For Decoding, encoding use: CONFIGURE_FLAG_ENCODE 
     ); 
    codec.start(); 
    codec.flush(); 

    //Get Input and Output buffers from codec 
    inputBuffers = codec.getInputBuffers(); 
    outputBuffers = codec.getOutputBuffers(); 

    While(condition) 
    { 
     //Get Audio data from extractor 
     int inputBufIndex = codec.dequeueInputBuffer(50);//Timeout set of 50 microsec 
     if (inputBufIndex >= 0) 
     { 
      ByteBuffer dstBuf = inputBuffers[inputBufIndex]; 
      int sampleSize = extractor.readSampleData(dstBuf, 0); 
      long presentationTimeUs = extractor.getSampleTime(); 

      codec.queueInputBuffer(inputBufIndex, 
          0, //offset 
          sampleSize, 
          presentationTimeUs, 
          0); //Use appropriate flag value 
      extractor.advance(); 
     } 

     //Use codec to decode the data -- handle end of stream properly 
     MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); 
     info.set(0,0,0,0); 
     final int res = codec.dequeueOutputBuffer(info, 20000); 
     if (res >= 0) 
     { 
      int outputBufIndex = res; 
      ByteBuffer buf = outputBuffers[outputBufIndex]; 

      byte[] chunk = new byte[info.size]; 
      buf.get(chunk); // Read the buffer all at once 
      buf.clear(); // ** MUST DO!!! OTHERWISE THE NEXT TIME YOU GET THIS SAME BUFFER BAD THINGS WILL HAPPEN 

      if (chunk.length > 0) 
       //Use this chunk as it contains decoded audio dat    
      codec.releaseOutputBuffer(outputBufIndex, false /* render */); 
     } 
     else if (res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) 
      outputBuffers = codec.getOutputBuffers(); 
    } 
    codec.stop(); 
    codec.release(); 
    lExt.release(); 
} 
catch(Exception ex)... 
0

嘗試將它傳遞給打開文件的文件描述符而不是文件路徑。當我遇到這個問題時它對我有效。我不知道爲什麼。

+0

你能告訴我如何從打開的文件中獲取文件描述符嗎? – sunjinbo

1

數據源設置爲一個遠程URL將需要android.permission.INTERNET對權限在AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET" />