3

I am trying to work on media extractor for audio streaming of OGG file format on android. I have written some code with help of google documents. but it doesn't work at all. May be i have Written a wrong code or syntax As i am student. it show me failed to instantiate extractor

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;
    }
}

}

Swap-IOS-Android
  • 4,363
  • 6
  • 49
  • 77
  • Crashes for me with the same message on line "SetDataSource". Tried with sdcard and internal storage...tried FilePath and FileDescriptor..doesn't work. Have you figured out what was wrong? – Paul Kapustin Jan 25 '13 at 17:16
  • @badbadboy no not yet i am currently using mp3 stream in my app.. but i am waiting for new version of android release so after that i can have more documents on media extractor and code. – Swap-IOS-Android Jan 28 '13 at 09:34

4 Answers4

2

I ASSUME your question is "why doesn't it work at all?" Usually, this is much too big a question, but in this case it looks to me like you have not understood at all how the MediaExtractor & MediaCodec work.

Not all your fault though. The documentation is cryptic, to put it kindly. However I have succeeded in playing audio files this way.

My scheme assumes that MediaCodec implements an asynchronous queue of buffers. There seem to be about 4 buffers in this queue.

So I use 2 threads: One thread puts data from the MediaExtractor into the queue, and another thread takes decoded audio out from the queue and writes it to an AudioTrack.

I Then need to be very careful to avoid deadlock during a seek, for example. And I end up with a lot more code than yours. I don't know how to avoid that !

I am thinking of trying video. Any helpful references would be appreciated !

Don

1

Code will be something below, which is working perfectly for me for local audio file in JB platform.

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)...
kleopatra
  • 51,061
  • 28
  • 99
  • 211
Suman
  • 9
  • 1
1

Setting the data source to a remote URL will require the android.permission.INTERNET permission to be declared in the AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET" />
Tim Allclair
  • 7,347
  • 2
  • 27
  • 25
0

Try passing it a file descriptor of an opened file, instead of a file path. It worked for me when I had this problem. I have no idea why.

Andy Newman
  • 1,178
  • 2
  • 8
  • 23