可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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; } }
}
回答1:
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
回答2:
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)...
回答3:
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" />
回答4:
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.