Java Code Examples for android.media.MediaCodec#dequeueOutputBuffer()
The following examples show how to use
android.media.MediaCodec#dequeueOutputBuffer() .
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: EncoderDebugger.java From libstreaming with Apache License 2.0 | 5 votes |
private void flushMediaCodec(MediaCodec mc) { int index = 0; BufferInfo info = new BufferInfo(); while (index != MediaCodec.INFO_TRY_AGAIN_LATER) { index = mc.dequeueOutputBuffer(info, 1000000/FRAMERATE); if (index>=0) { mc.releaseOutputBuffer(index, false); } } }
Example 2
Source File: EncoderDebugger.java From spydroid-ipcamera with GNU General Public License v3.0 | 5 votes |
private void flushMediaCodec(MediaCodec mc) { int index = 0; BufferInfo info = new BufferInfo(); while (index != MediaCodec.INFO_TRY_AGAIN_LATER) { index = mc.dequeueOutputBuffer(info, 1000000/FRAMERATE); if (index>=0) { mc.releaseOutputBuffer(index, false); } } }
Example 3
Source File: AudioCodec.java From bcm-android with GNU General Public License v3.0 | 5 votes |
private void handleCodecOutput(MediaCodec mediaCodec, ByteBuffer[] codecOutputBuffers, MediaCodec.BufferInfo bufferInfo, OutputStream outputStream) throws IOException { int codecOutputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0); while (codecOutputBufferIndex != MediaCodec.INFO_TRY_AGAIN_LATER) { if (codecOutputBufferIndex >= 0) { ByteBuffer encoderOutputBuffer = codecOutputBuffers[codecOutputBufferIndex]; encoderOutputBuffer.position(bufferInfo.offset); encoderOutputBuffer.limit(bufferInfo.offset + bufferInfo.size); if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != MediaCodec.BUFFER_FLAG_CODEC_CONFIG) { byte[] header = createAdtsHeader(bufferInfo.size - bufferInfo.offset); outputStream.write(header); byte[] data = new byte[encoderOutputBuffer.remaining()]; encoderOutputBuffer.get(data); outputStream.write(data); } encoderOutputBuffer.clear(); mediaCodec.releaseOutputBuffer(codecOutputBufferIndex, false); } else if (codecOutputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { codecOutputBuffers = mediaCodec.getOutputBuffers(); } codecOutputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0); } }
Example 4
Source File: AudioCodec.java From deltachat-android with GNU General Public License v3.0 | 5 votes |
private void handleCodecOutput(MediaCodec mediaCodec, ByteBuffer[] codecOutputBuffers, MediaCodec.BufferInfo bufferInfo, OutputStream outputStream) throws IOException { int codecOutputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0); while (codecOutputBufferIndex != MediaCodec.INFO_TRY_AGAIN_LATER) { if (codecOutputBufferIndex >= 0) { ByteBuffer encoderOutputBuffer = codecOutputBuffers[codecOutputBufferIndex]; encoderOutputBuffer.position(bufferInfo.offset); encoderOutputBuffer.limit(bufferInfo.offset + bufferInfo.size); if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != MediaCodec.BUFFER_FLAG_CODEC_CONFIG) { byte[] header = createAdtsHeader(bufferInfo.size - bufferInfo.offset); outputStream.write(header); byte[] data = new byte[encoderOutputBuffer.remaining()]; encoderOutputBuffer.get(data); outputStream.write(data); } encoderOutputBuffer.clear(); mediaCodec.releaseOutputBuffer(codecOutputBufferIndex, false); } else if (codecOutputBufferIndex== MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { codecOutputBuffers = mediaCodec.getOutputBuffers(); } codecOutputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0); } }
Example 5
Source File: AudioCodec.java From mollyim-android with GNU General Public License v3.0 | 5 votes |
private void handleCodecOutput(MediaCodec mediaCodec, ByteBuffer[] codecOutputBuffers, MediaCodec.BufferInfo bufferInfo, OutputStream outputStream) throws IOException { int codecOutputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0); while (codecOutputBufferIndex != MediaCodec.INFO_TRY_AGAIN_LATER) { if (codecOutputBufferIndex >= 0) { ByteBuffer encoderOutputBuffer = codecOutputBuffers[codecOutputBufferIndex]; encoderOutputBuffer.position(bufferInfo.offset); encoderOutputBuffer.limit(bufferInfo.offset + bufferInfo.size); if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != MediaCodec.BUFFER_FLAG_CODEC_CONFIG) { byte[] header = createAdtsHeader(bufferInfo.size - bufferInfo.offset); outputStream.write(header); byte[] data = new byte[encoderOutputBuffer.remaining()]; encoderOutputBuffer.get(data); outputStream.write(data); } encoderOutputBuffer.clear(); mediaCodec.releaseOutputBuffer(codecOutputBufferIndex, false); } else if (codecOutputBufferIndex== MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { codecOutputBuffers = mediaCodec.getOutputBuffers(); } codecOutputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0); } }
Example 6
Source File: DecodeEditEncodeTest.java From Android-MediaCodec-Examples with Apache License 2.0 | 4 votes |
/** * Checks the video data. * * @return the number of bad frames */ private int checkVideoData(VideoChunks inputData, MediaCodec decoder, OutputSurface surface) { final int TIMEOUT_USEC = 1000; ByteBuffer[] decoderInputBuffers = decoder.getInputBuffers(); ByteBuffer[] decoderOutputBuffers = decoder.getOutputBuffers(); MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); int inputChunk = 0; int checkIndex = 0; int badFrames = 0; boolean outputDone = false; boolean inputDone = false; while (!outputDone) { if (VERBOSE) Log.d(TAG, "check loop"); // Feed more data to the decoder. if (!inputDone) { int inputBufIndex = decoder.dequeueInputBuffer(TIMEOUT_USEC); if (inputBufIndex >= 0) { if (inputChunk == inputData.getNumChunks()) { // End of stream -- send empty frame with EOS flag set. decoder.queueInputBuffer(inputBufIndex, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM); inputDone = true; if (VERBOSE) Log.d(TAG, "sent input EOS"); } else { // Copy a chunk of input to the decoder. The first chunk should have // the BUFFER_FLAG_CODEC_CONFIG flag set. ByteBuffer inputBuf = decoderInputBuffers[inputBufIndex]; inputBuf.clear(); inputData.getChunkData(inputChunk, inputBuf); int flags = inputData.getChunkFlags(inputChunk); long time = inputData.getChunkTime(inputChunk); decoder.queueInputBuffer(inputBufIndex, 0, inputBuf.position(), time, flags); if (VERBOSE) { Log.d(TAG, "submitted frame " + inputChunk + " to dec, size=" + inputBuf.position() + " flags=" + flags); } inputChunk++; } } else { if (VERBOSE) Log.d(TAG, "input buffer not available"); } } if (!outputDone) { int decoderStatus = decoder.dequeueOutputBuffer(info, TIMEOUT_USEC); if (decoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) { // no output available yet if (VERBOSE) Log.d(TAG, "no output from decoder available"); } else if (decoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { decoderOutputBuffers = decoder.getOutputBuffers(); if (VERBOSE) Log.d(TAG, "decoder output buffers changed"); } else if (decoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { MediaFormat newFormat = decoder.getOutputFormat(); if (VERBOSE) Log.d(TAG, "decoder output format changed: " + newFormat); } else if (decoderStatus < 0) { fail("unexpected result from decoder.dequeueOutputBuffer: " + decoderStatus); } else { // decoderStatus >= 0 ByteBuffer decodedData = decoderOutputBuffers[decoderStatus]; if (VERBOSE) Log.d(TAG, "surface decoder given buffer " + decoderStatus + " (size=" + info.size + ")"); if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { if (VERBOSE) Log.d(TAG, "output EOS"); outputDone = true; } boolean doRender = (info.size != 0); // As soon as we call releaseOutputBuffer, the buffer will be forwarded // to SurfaceTexture to convert to a texture. The API doesn't guarantee // that the texture will be available before the call returns, so we // need to wait for the onFrameAvailable callback to fire. decoder.releaseOutputBuffer(decoderStatus, doRender); if (doRender) { if (VERBOSE) Log.d(TAG, "awaiting frame " + checkIndex); assertEquals("Wrong time stamp", computePresentationTime(checkIndex), info.presentationTimeUs); surface.awaitNewImage(); surface.drawImage(); if (!checkSurfaceFrame(checkIndex++)) { badFrames++; } } } } } return badFrames; }
Example 7
Source File: ScreenRecoder.java From ScreenRecoder with MIT License | 4 votes |
private void stream(MediaCodec codec) { BufferInfo info = new BufferInfo(); ByteBuffer[] buffers = null; while (!mQuitting) { int index = codec.dequeueOutputBuffer(info, TIMEOUT_USEC); if (index >= 0) { if (buffers == null) { buffers = codec.getOutputBuffers(); } ByteBuffer buffer = buffers[index]; buffer.limit(info.offset + info.size); buffer.position(info.offset); muxer.writeSampleData(videoTrackIndex, buffer, info); codec.releaseOutputBuffer(index, false); } else if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { if (mMuxerStarted) { throw new RuntimeException("format changed twice"); } MediaFormat newFormat = codec.getOutputFormat(); // now that we have the Magic Goodies, start the muxer videoTrackIndex = muxer.addTrack(newFormat); muxer.start(); mMuxerStarted = true; buffers = null; } else if (index == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { buffers = null; } else if (index == MediaCodec.INFO_TRY_AGAIN_LATER) { Log.e("sam", "Codec dequeue buffer timed out."); } } muxer.stop(); muxer.release(); }
Example 8
Source File: EncodedAudioRecorder.java From speechutils with Apache License 2.0 | 4 votes |
/** * Reads bytes from the given recorder and encodes them with the given encoder. * Uses the (deprecated) Synchronous Processing using Buffer Arrays. * <p/> * Encoders (or codecs that generate compressed data) will create and return the codec specific * data before any valid output buffer in output buffers marked with the codec-config flag. * Buffers containing codec-specific-data have no meaningful timestamps. */ @TargetApi(Build.VERSION_CODES.JELLY_BEAN) private int recorderEncoderLoop(MediaCodec codec, SpeechRecord speechRecord) { int status = -1; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { codec.start(); // Getting some buffers (e.g. 4 of each) to communicate with the codec ByteBuffer[] codecInputBuffers = codec.getInputBuffers(); ByteBuffer[] codecOutputBuffers = codec.getOutputBuffers(); Log.i("input buffers " + codecInputBuffers.length + "; output buffers: " + codecOutputBuffers.length); boolean doneSubmittingInput = false; int numDequeueOutputBufferTimeout = 0; int index; while (true) { if (!doneSubmittingInput) { index = codec.dequeueInputBuffer(DEQUEUE_INPUT_BUFFER_TIMEOUT); if (index >= 0) { int size = queueInputBuffer(codec, codecInputBuffers, index, speechRecord); if (size == -1) { codec.queueInputBuffer(index, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); Log.i("enc: in: EOS"); doneSubmittingInput = true; } else { Log.i("enc: in: " + size); mNumBytesSubmitted += size; } } else { Log.i("enc: in: timeout, will try again"); } } MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); index = codec.dequeueOutputBuffer(info, DEQUEUE_OUTPUT_BUFFER_TIMEOUT); Log.i("enc: out: flags/index: " + info.flags + "/" + index); if (index == MediaCodec.INFO_TRY_AGAIN_LATER) { numDequeueOutputBufferTimeout++; Log.i("enc: out: INFO_TRY_AGAIN_LATER: " + numDequeueOutputBufferTimeout); if (numDequeueOutputBufferTimeout > MAX_NUM_RETRIES_DEQUEUE_OUTPUT_BUFFER) { break; } } else if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { MediaFormat format = codec.getOutputFormat(); Log.i("enc: out: INFO_OUTPUT_FORMAT_CHANGED: " + format.toString()); } else if (index == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { codecOutputBuffers = codec.getOutputBuffers(); Log.i("enc: out: INFO_OUTPUT_BUFFERS_CHANGED"); } else { dequeueOutputBuffer(codec, codecOutputBuffers, index, info); mNumBytesDequeued += info.size; numDequeueOutputBufferTimeout = 0; if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { Log.i("enc: out: EOS"); status = 0; break; } } } codec.stop(); codec.release(); Log.i("stopped and released codec"); } return status; }
Example 9
Source File: EncodedAudioRecorder.java From AlexaAndroid with GNU General Public License v2.0 | 4 votes |
/** * Reads bytes from the given recorder and encodes them with the given encoder. * Uses the (deprecated) Synchronous Processing using Buffer Arrays. * <p/> * Encoders (or codecs that generate compressed data) will create and return the codec specific * data before any valid output buffer in output buffers marked with the codec-config flag. * Buffers containing codec-specific-data have no meaningful timestamps. */ @TargetApi(Build.VERSION_CODES.JELLY_BEAN) private void recorderEncoderLoop(MediaCodec codec, SpeechRecord speechRecord) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { codec.start(); // Getting some buffers (e.g. 4 of each) to communicate with the codec ByteBuffer[] codecInputBuffers = codec.getInputBuffers(); ByteBuffer[] codecOutputBuffers = codec.getOutputBuffers(); Log.i("input buffers " + codecInputBuffers.length + "; output buffers: " + codecOutputBuffers.length); boolean doneSubmittingInput = false; int numRetriesDequeueOutputBuffer = 0; int index; while (true) { if (!doneSubmittingInput) { index = codec.dequeueInputBuffer(DEQUEUE_TIMEOUT); if (index >= 0) { int size = queueInputBuffer(codec, codecInputBuffers, index, speechRecord); if (size == -1) { codec.queueInputBuffer(index, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); Log.i("enc: in: EOS"); doneSubmittingInput = true; } else { Log.i("enc: in: " + size); mNumBytesSubmitted += size; } } else { Log.i("enc: in: timeout, will try again"); } } MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); index = codec.dequeueOutputBuffer(info, DEQUEUE_TIMEOUT); Log.i("enc: out: flags/index: " + info.flags + "/" + index); if (index == MediaCodec.INFO_TRY_AGAIN_LATER) { Log.i("enc: out: INFO_TRY_AGAIN_LATER: " + numRetriesDequeueOutputBuffer); if (++numRetriesDequeueOutputBuffer > MAX_NUM_RETRIES_DEQUEUE_OUTPUT_BUFFER) { break; } } else if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { MediaFormat format = codec.getOutputFormat(); Log.i("enc: out: INFO_OUTPUT_FORMAT_CHANGED: " + format.toString()); } else if (index == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { codecOutputBuffers = codec.getOutputBuffers(); Log.i("enc: out: INFO_OUTPUT_BUFFERS_CHANGED"); } else { dequeueOutputBuffer(codec, codecOutputBuffers, index, info); mNumBytesDequeued += info.size; if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { Log.i("enc: out: EOS"); break; } } } codec.stop(); codec.release(); } }
Example 10
Source File: EncodedAudioRecorder.java From AlexaAndroid with GNU General Public License v2.0 | 4 votes |
/** * Reads bytes from the given recorder and encodes them with the given encoder. * Uses the (deprecated) Synchronous Processing using Buffer Arrays. * <p/> * Encoders (or codecs that generate compressed data) will create and return the codec specific * data before any valid output buffer in output buffers marked with the codec-config flag. * Buffers containing codec-specific-data have no meaningful timestamps. */ @TargetApi(Build.VERSION_CODES.JELLY_BEAN) private void recorderEncoderLoop(MediaCodec codec, SpeechRecord speechRecord) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { codec.start(); // Getting some buffers (e.g. 4 of each) to communicate with the codec ByteBuffer[] codecInputBuffers = codec.getInputBuffers(); ByteBuffer[] codecOutputBuffers = codec.getOutputBuffers(); Log.i("input buffers " + codecInputBuffers.length + "; output buffers: " + codecOutputBuffers.length); boolean doneSubmittingInput = false; int numRetriesDequeueOutputBuffer = 0; int index; while (true) { if (!doneSubmittingInput) { index = codec.dequeueInputBuffer(DEQUEUE_TIMEOUT); if (index >= 0) { int size = queueInputBuffer(codec, codecInputBuffers, index, speechRecord); if (size == -1) { codec.queueInputBuffer(index, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); Log.i("enc: in: EOS"); doneSubmittingInput = true; } else { Log.i("enc: in: " + size); mNumBytesSubmitted += size; } } else { Log.i("enc: in: timeout, will try again"); } } MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); index = codec.dequeueOutputBuffer(info, DEQUEUE_TIMEOUT); Log.i("enc: out: flags/index: " + info.flags + "/" + index); if (index == MediaCodec.INFO_TRY_AGAIN_LATER) { Log.i("enc: out: INFO_TRY_AGAIN_LATER: " + numRetriesDequeueOutputBuffer); if (++numRetriesDequeueOutputBuffer > MAX_NUM_RETRIES_DEQUEUE_OUTPUT_BUFFER) { break; } } else if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { MediaFormat format = codec.getOutputFormat(); Log.i("enc: out: INFO_OUTPUT_FORMAT_CHANGED: " + format.toString()); } else if (index == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { codecOutputBuffers = codec.getOutputBuffers(); Log.i("enc: out: INFO_OUTPUT_BUFFERS_CHANGED"); } else { dequeueOutputBuffer(codec, codecOutputBuffers, index, info); mNumBytesDequeued += info.size; if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { Log.i("enc: out: EOS"); break; } } } codec.stop(); codec.release(); } }
Example 11
Source File: ExtractMpegFramesTest_egl14.java From Android-MediaCodec-Examples with Apache License 2.0 | 4 votes |
/** * Work loop. */ static void doExtract(MediaExtractor extractor, int trackIndex, MediaCodec decoder, CodecOutputSurface outputSurface) throws IOException { final int TIMEOUT_USEC = 10000; ByteBuffer[] decoderInputBuffers = decoder.getInputBuffers(); MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); int inputChunk = 0; int decodeCount = 0; long frameSaveTime = 0; boolean outputDone = false; boolean inputDone = false; while (!outputDone) { if (VERBOSE) Log.d(TAG, "loop"); // Feed more data to the decoder. if (!inputDone) { int inputBufIndex = decoder.dequeueInputBuffer(TIMEOUT_USEC); if (inputBufIndex >= 0) { ByteBuffer inputBuf = decoderInputBuffers[inputBufIndex]; // Read the sample data into the ByteBuffer. This neither respects nor // updates inputBuf's position, limit, etc. int chunkSize = extractor.readSampleData(inputBuf, 0); if (chunkSize < 0) { // End of stream -- send empty frame with EOS flag set. decoder.queueInputBuffer(inputBufIndex, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM); inputDone = true; if (VERBOSE) Log.d(TAG, "sent input EOS"); } else { if (extractor.getSampleTrackIndex() != trackIndex) { Log.w(TAG, "WEIRD: got sample from track " + extractor.getSampleTrackIndex() + ", expected " + trackIndex); } long presentationTimeUs = extractor.getSampleTime(); decoder.queueInputBuffer(inputBufIndex, 0, chunkSize, presentationTimeUs, 0 /*flags*/); if (VERBOSE) { Log.d(TAG, "submitted frame " + inputChunk + " to dec, size=" + chunkSize); } inputChunk++; extractor.advance(); } } else { if (VERBOSE) Log.d(TAG, "input buffer not available"); } } if (!outputDone) { int decoderStatus = decoder.dequeueOutputBuffer(info, TIMEOUT_USEC); if (decoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) { // no output available yet if (VERBOSE) Log.d(TAG, "no output from decoder available"); } else if (decoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { // not important for us, since we're using Surface if (VERBOSE) Log.d(TAG, "decoder output buffers changed"); } else if (decoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { MediaFormat newFormat = decoder.getOutputFormat(); if (VERBOSE) Log.d(TAG, "decoder output format changed: " + newFormat); } else if (decoderStatus < 0) { fail("unexpected result from decoder.dequeueOutputBuffer: " + decoderStatus); } else { // decoderStatus >= 0 if (VERBOSE) Log.d(TAG, "surface decoder given buffer " + decoderStatus + " (size=" + info.size + ")"); if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { if (VERBOSE) Log.d(TAG, "output EOS"); outputDone = true; } boolean doRender = (info.size != 0); // As soon as we call releaseOutputBuffer, the buffer will be forwarded // to SurfaceTexture to convert to a texture. The API doesn't guarantee // that the texture will be available before the call returns, so we // need to wait for the onFrameAvailable callback to fire. decoder.releaseOutputBuffer(decoderStatus, doRender); if (doRender) { if (VERBOSE) Log.d(TAG, "awaiting decode of frame " + decodeCount); outputSurface.awaitNewImage(); outputSurface.drawImage(true); if (decodeCount < MAX_FRAMES) { File outputFile = new File(FILES_DIR, String.format("frame-%02d.png", decodeCount)); long startWhen = System.nanoTime(); outputSurface.saveFrame(outputFile.toString()); frameSaveTime += System.nanoTime() - startWhen; } decodeCount++; } } } } int numSaved = (MAX_FRAMES < decodeCount) ? MAX_FRAMES : decodeCount; Log.d(TAG, "Saving " + numSaved + " frames took " + (frameSaveTime / numSaved / 1000) + " us per frame"); }
Example 12
Source File: ExtractMpegFramesTest.java From Android-MediaCodec-Examples with Apache License 2.0 | 4 votes |
/** * Work loop. */ static void doExtract(MediaExtractor extractor, int trackIndex, MediaCodec decoder, CodecOutputSurface outputSurface) throws IOException { final int TIMEOUT_USEC = 10000; ByteBuffer[] decoderInputBuffers = decoder.getInputBuffers(); MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); int inputChunk = 0; int decodeCount = 0; long frameSaveTime = 0; boolean outputDone = false; boolean inputDone = false; while (!outputDone) { if (VERBOSE) Log.d(TAG, "loop"); // Feed more data to the decoder. if (!inputDone) { int inputBufIndex = decoder.dequeueInputBuffer(TIMEOUT_USEC); if (inputBufIndex >= 0) { ByteBuffer inputBuf = decoderInputBuffers[inputBufIndex]; // Read the sample data into the ByteBuffer. This neither respects nor // updates inputBuf's position, limit, etc. int chunkSize = extractor.readSampleData(inputBuf, 0); if (chunkSize < 0) { // End of stream -- send empty frame with EOS flag set. decoder.queueInputBuffer(inputBufIndex, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM); inputDone = true; if (VERBOSE) Log.d(TAG, "sent input EOS"); } else { if (extractor.getSampleTrackIndex() != trackIndex) { Log.w(TAG, "WEIRD: got sample from track " + extractor.getSampleTrackIndex() + ", expected " + trackIndex); } long presentationTimeUs = extractor.getSampleTime(); decoder.queueInputBuffer(inputBufIndex, 0, chunkSize, presentationTimeUs, 0 /*flags*/); if (VERBOSE) { Log.d(TAG, "submitted frame " + inputChunk + " to dec, size=" + chunkSize); } inputChunk++; extractor.advance(); } } else { if (VERBOSE) Log.d(TAG, "input buffer not available"); } } if (!outputDone) { int decoderStatus = decoder.dequeueOutputBuffer(info, TIMEOUT_USEC); if (decoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) { // no output available yet if (VERBOSE) Log.d(TAG, "no output from decoder available"); } else if (decoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { // not important for us, since we're using Surface if (VERBOSE) Log.d(TAG, "decoder output buffers changed"); } else if (decoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { MediaFormat newFormat = decoder.getOutputFormat(); if (VERBOSE) Log.d(TAG, "decoder output format changed: " + newFormat); } else if (decoderStatus < 0) { fail("unexpected result from decoder.dequeueOutputBuffer: " + decoderStatus); } else { // decoderStatus >= 0 if (VERBOSE) Log.d(TAG, "surface decoder given buffer " + decoderStatus + " (size=" + info.size + ")"); if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { if (VERBOSE) Log.d(TAG, "output EOS"); outputDone = true; } boolean doRender = (info.size != 0); // As soon as we call releaseOutputBuffer, the buffer will be forwarded // to SurfaceTexture to convert to a texture. The API doesn't guarantee // that the texture will be available before the call returns, so we // need to wait for the onFrameAvailable callback to fire. decoder.releaseOutputBuffer(decoderStatus, doRender); if (doRender) { if (VERBOSE) Log.d(TAG, "awaiting decode of frame " + decodeCount); outputSurface.awaitNewImage(); outputSurface.drawImage(true); if (decodeCount < MAX_FRAMES) { File outputFile = new File(FILES_DIR, String.format("frame-%02d.png", decodeCount)); long startWhen = System.nanoTime(); outputSurface.saveFrame(outputFile.toString()); frameSaveTime += System.nanoTime() - startWhen; } decodeCount++; } } } } int numSaved = (MAX_FRAMES < decodeCount) ? MAX_FRAMES : decodeCount; Log.d(TAG, "Saving " + numSaved + " frames took " + (frameSaveTime / numSaved / 1000) + " us per frame"); }
Example 13
Source File: DecodeEditEncodeTest.java From Android-MediaCodec-Examples with Apache License 2.0 | 4 votes |
/** * Generates video frames, feeds them into the encoder, and writes the output to the * VideoChunks instance. */ private void generateVideoData(MediaCodec encoder, InputSurface inputSurface, VideoChunks output) { final int TIMEOUT_USEC = 10000; ByteBuffer[] encoderOutputBuffers = encoder.getOutputBuffers(); MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); int generateIndex = 0; int outputCount = 0; // Loop until the output side is done. boolean inputDone = false; boolean outputDone = false; while (!outputDone) { if (VERBOSE) Log.d(TAG, "gen loop"); // If we're not done submitting frames, generate a new one and submit it. The // eglSwapBuffers call will block if the input is full. if (!inputDone) { if (generateIndex == NUM_FRAMES) { // Send an empty frame with the end-of-stream flag set. if (VERBOSE) Log.d(TAG, "signaling input EOS"); if (WORK_AROUND_BUGS) { // Might drop a frame, but at least we won't crash mediaserver. try { Thread.sleep(500); } catch (InterruptedException ie) {} outputDone = true; } else { encoder.signalEndOfInputStream(); } inputDone = true; } else { generateSurfaceFrame(generateIndex); inputSurface.setPresentationTime(computePresentationTime(generateIndex) * 1000); if (VERBOSE) Log.d(TAG, "inputSurface swapBuffers"); inputSurface.swapBuffers(); } generateIndex++; } // Check for output from the encoder. If there's no output yet, we either need to // provide more input, or we need to wait for the encoder to work its magic. We // can't actually tell which is the case, so if we can't get an output buffer right // away we loop around and see if it wants more input. // // If we do find output, drain it all before supplying more input. while (true) { int encoderStatus = encoder.dequeueOutputBuffer(info, TIMEOUT_USEC); if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) { // no output available yet if (VERBOSE) Log.d(TAG, "no output from encoder available"); break; // out of while } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { // not expected for an encoder encoderOutputBuffers = encoder.getOutputBuffers(); if (VERBOSE) Log.d(TAG, "encoder output buffers changed"); } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { // not expected for an encoder MediaFormat newFormat = encoder.getOutputFormat(); if (VERBOSE) Log.d(TAG, "encoder output format changed: " + newFormat); } else if (encoderStatus < 0) { fail("unexpected result from encoder.dequeueOutputBuffer: " + encoderStatus); } else { // encoderStatus >= 0 ByteBuffer encodedData = encoderOutputBuffers[encoderStatus]; if (encodedData == null) { fail("encoderOutputBuffer " + encoderStatus + " was null"); } // Codec config flag must be set iff this is the first chunk of output. This // may not hold for all codecs, but it appears to be the case for video/avc. assertTrue((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0 || outputCount != 0); if (info.size != 0) { // Adjust the ByteBuffer values to match BufferInfo. encodedData.position(info.offset); encodedData.limit(info.offset + info.size); output.addChunk(encodedData, info.flags, info.presentationTimeUs); outputCount++; } encoder.releaseOutputBuffer(encoderStatus, false); if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { outputDone = true; break; // out of while } } } } // One chunk per frame, plus one for the config data. assertEquals("Frame count", NUM_FRAMES + 1, outputCount); }
Example 14
Source File: AudioDecoder.java From ssj with GNU General Public License v3.0 | 4 votes |
/** * Decodes audio file into a raw file. This method accepts audio file formats with valid * headers (like .mp3, .mp4, and .wav). * @param filepath Path of the file to decode. * @return Decoded raw audio file. * @throws IOException when file cannot be read. */ private File decode(String filepath) throws IOException { // Set selected audio file as a source. MediaExtractor extractor = new MediaExtractor(); extractor.setDataSource(filepath); // Get audio format. MediaFormat format = extractor.getTrackFormat(0); String mime = format.getString(MediaFormat.KEY_MIME); // Cache necessary audio attributes. sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE); channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT); // Create and configure decoder based on audio format. MediaCodec decoder = MediaCodec.createDecoderByType(mime); decoder.configure(format, null, null, 0); decoder.start(); // Create input/output buffers. ByteBuffer[] inputBuffers = decoder.getInputBuffers(); ByteBuffer[] outputBuffers = decoder.getOutputBuffers(); MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); extractor.selectTrack(0); File dst = new File(FileCons.SSJ_EXTERNAL_STORAGE + File.separator + "output.raw"); FileOutputStream f = new FileOutputStream(dst); boolean endOfStreamReached = false; while (true) { if (!endOfStreamReached) { int inputBufferIndex = decoder.dequeueInputBuffer(10 * 1000); if (inputBufferIndex >= 0) { ByteBuffer inputBuffer = inputBuffers[inputBufferIndex]; int sampleSize = extractor.readSampleData(inputBuffer, 0); if (sampleSize < 0) { // Pass empty buffer and the end of stream flag to the codec. decoder.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); endOfStreamReached = true; } else { // Pass data-filled buffer to the decoder. decoder.queueInputBuffer(inputBufferIndex, 0, sampleSize, extractor.getSampleTime(), 0); extractor.advance(); } } } int outputBufferIndex = decoder.dequeueOutputBuffer(bufferInfo, 10 * 1000); if (outputBufferIndex >= 0) { ByteBuffer outputBuffer = outputBuffers[outputBufferIndex]; byte[] data = new byte[bufferInfo.size]; outputBuffer.get(data); outputBuffer.clear(); if (data.length > 0) { f.write(data, 0, data.length); } decoder.releaseOutputBuffer(outputBufferIndex, false); if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { endOfStreamReached = true; } } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { outputBuffers = decoder.getOutputBuffers(); } if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { return dst; } } }
Example 15
Source File: HeifReader.java From heifreader with MIT License | 4 votes |
private static void renderHevcImage(ByteBuffer bitstream, ImageInfo info, Surface surface) { long beginTime = SystemClock.elapsedRealtimeNanos(); // configure HEVC decoder MediaCodec decoder = configureDecoder(info, bitstream.limit(), surface); MediaFormat outputFormat = decoder.getOutputFormat(); Log.d(TAG, "HEVC output-format=" + outputFormat); decoder.start(); try { // set bitstream to decoder int inputBufferId = decoder.dequeueInputBuffer(-1); if (inputBufferId < 0) { throw new IllegalStateException("dequeueInputBuffer return " + inputBufferId); } ByteBuffer inBuffer = decoder.getInputBuffer(inputBufferId); inBuffer.put(bitstream); decoder.queueInputBuffer(inputBufferId, 0, bitstream.limit(), 0, 0); // notify end of stream inputBufferId = decoder.dequeueInputBuffer(-1); if (inputBufferId < 0) { throw new IllegalStateException("dequeueInputBuffer return " + inputBufferId); } decoder.queueInputBuffer(inputBufferId, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); // get decoded image MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); while (true) { int outputBufferId = decoder.dequeueOutputBuffer(bufferInfo, -1); if (outputBufferId >= 0) { decoder.releaseOutputBuffer(outputBufferId, true); break; } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { outputFormat = decoder.getOutputFormat(); Log.d(TAG, "HEVC output-format=" + outputFormat); } else { Log.d(TAG, "HEVC dequeueOutputBuffer return " + outputBufferId); } } decoder.flush(); } finally { decoder.stop(); decoder.release(); } long endTime = SystemClock.elapsedRealtimeNanos(); Log.i(TAG, "HEVC decoding elapsed=" + (endTime - beginTime) / 1000000.f + "[msec]"); }
Example 16
Source File: AudioUtil.java From VideoProcessor with Apache License 2.0 | 4 votes |
/** * 需要改变音频速率的情况下,需要先解码->改变速率->编码 */ public static void decodeToPCM(VideoProcessor.MediaSource audioSource, String outPath, Integer startTimeUs, Integer endTimeUs) throws IOException { MediaExtractor extractor = new MediaExtractor(); audioSource.setDataSource(extractor); int audioTrack = VideoUtil.selectTrack(extractor, true); extractor.selectTrack(audioTrack); if (startTimeUs == null) { startTimeUs = 0; } extractor.seekTo(startTimeUs, MediaExtractor.SEEK_TO_CLOSEST_SYNC); MediaFormat oriAudioFormat = extractor.getTrackFormat(audioTrack); int maxBufferSize; if (oriAudioFormat.containsKey(MediaFormat.KEY_MAX_INPUT_SIZE)) { maxBufferSize = oriAudioFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE); } else { maxBufferSize = 100 * 1000; } ByteBuffer buffer = ByteBuffer.allocateDirect(maxBufferSize); MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); //调整音频速率需要重解码音频帧 MediaCodec decoder = MediaCodec.createDecoderByType(oriAudioFormat.getString(MediaFormat.KEY_MIME)); decoder.configure(oriAudioFormat, null, null, 0); decoder.start(); boolean decodeDone = false; boolean decodeInputDone = false; final int TIMEOUT_US = 2500; File pcmFile = new File(outPath); FileChannel writeChannel = new FileOutputStream(pcmFile).getChannel(); try { while (!decodeDone) { if (!decodeInputDone) { boolean eof = false; int decodeInputIndex = decoder.dequeueInputBuffer(TIMEOUT_US); if (decodeInputIndex >= 0) { long sampleTimeUs = extractor.getSampleTime(); if (sampleTimeUs == -1) { eof = true; } else if (sampleTimeUs < startTimeUs) { extractor.advance(); continue; } else if (endTimeUs != null && sampleTimeUs > endTimeUs) { eof = true; } if (eof) { decodeInputDone = true; decoder.queueInputBuffer(decodeInputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); } else { info.size = extractor.readSampleData(buffer, 0); info.presentationTimeUs = sampleTimeUs; info.flags = extractor.getSampleFlags(); ByteBuffer inputBuffer = decoder.getInputBuffer(decodeInputIndex); inputBuffer.put(buffer); CL.it(TAG, "audio decode queueInputBuffer " + info.presentationTimeUs / 1000); decoder.queueInputBuffer(decodeInputIndex, 0, info.size, info.presentationTimeUs, info.flags); extractor.advance(); } } } while (!decodeDone) { int outputBufferIndex = decoder.dequeueOutputBuffer(info, TIMEOUT_US); if (outputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) { break; } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { MediaFormat newFormat = decoder.getOutputFormat(); CL.it(TAG, "audio decode newFormat = " + newFormat); } else if (outputBufferIndex < 0) { //ignore CL.et(TAG, "unexpected result from audio decoder.dequeueOutputBuffer: " + outputBufferIndex); } else { if (info.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) { decodeDone = true; } else { ByteBuffer decodeOutputBuffer = decoder.getOutputBuffer(outputBufferIndex); CL.it(TAG, "audio decode saveFrame " + info.presentationTimeUs / 1000); writeChannel.write(decodeOutputBuffer); } decoder.releaseOutputBuffer(outputBufferIndex, false); } } } } finally { writeChannel.close(); extractor.release(); decoder.stop(); decoder.release(); } }
Example 17
Source File: AudioRecordThread.java From PhotoMovie with Apache License 2.0 | 4 votes |
/** * 需要改变音频速率的情况下,需要先解码->改变速率->编码 */ private void decodeToPCM(MediaCodec decoder, MediaExtractor extractor, MediaFormat oriAudioFormat, String outPath, Long endTimeUs) throws IOException { int maxBufferSize = getAudioMaxBufferSize(oriAudioFormat); ByteBuffer buffer = ByteBuffer.allocateDirect(maxBufferSize); MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); //调整音频速率需要重解码音频帧 decoder.configure(oriAudioFormat, null, null, 0); decoder.start(); boolean decodeDone = false; boolean decodeInputDone = false; final int TIMEOUT_US = 2500; File pcmFile = new File(outPath); FileChannel writeChannel = new FileOutputStream(pcmFile).getChannel(); ByteBuffer[] inputBuffers = null; ByteBuffer[] outputBuffers = null; try { while (!decodeDone) { if (!decodeInputDone) { boolean eof = false; int decodeInputIndex = decoder.dequeueInputBuffer(TIMEOUT_US); if (Build.VERSION.SDK_INT < 21 && decodeInputIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { outputBuffers = decoder.getOutputBuffers(); inputBuffers = decoder.getInputBuffers(); } else if (decodeInputIndex >= 0) { long sampleTimeUs = extractor.getSampleTime(); if (sampleTimeUs == -1) { eof = true; } else if (endTimeUs != null && sampleTimeUs > endTimeUs) { eof = true; } if (eof) { decodeInputDone = true; decoder.queueInputBuffer(decodeInputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); } else { info.size = extractor.readSampleData(buffer, 0); info.presentationTimeUs = sampleTimeUs; info.flags = extractor.getSampleFlags(); ByteBuffer inputBuffer = null; if (android.os.Build.VERSION.SDK_INT >= 21) { inputBuffer = decoder.getInputBuffer(decodeInputIndex); } else { inputBuffer = inputBuffers[decodeInputIndex]; } inputBuffer.put(buffer); MLog.i(TAG, "audio decode queueInputBuffer " + info.presentationTimeUs / 1000); decoder.queueInputBuffer(decodeInputIndex, 0, info.size, info.presentationTimeUs, info.flags); extractor.advance(); } } } while (!decodeDone) { int outputBufferIndex = decoder.dequeueOutputBuffer(info, TIMEOUT_US); if (outputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) { break; } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { MediaFormat newFormat = decoder.getOutputFormat(); MLog.i(TAG, "audio decode newFormat = " + newFormat); } else if (outputBufferIndex < 0) { //ignore MLog.e(TAG, "unexpected result from audio decoder.dequeueOutputBuffer: " + outputBufferIndex); } else { if (info.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) { decodeDone = true; } else { ByteBuffer decodeOutputBuffer = null; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { decodeOutputBuffer = decoder.getOutputBuffer(outputBufferIndex); } else { decodeOutputBuffer = outputBuffers[outputBufferIndex]; } MLog.i(TAG, "audio decode saveFrame " + info.presentationTimeUs / 1000); writeChannel.write(decodeOutputBuffer); } decoder.releaseOutputBuffer(outputBufferIndex, false); } } } } finally { writeChannel.close(); extractor.release(); decoder.stop(); decoder.release(); } }
Example 18
Source File: MediaPlayerGrabber.java From VIA-AI with MIT License | 4 votes |
private void frameDisplay(MediaCodec decoder) { MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); int srcColorFormat = 0; int srcStride = 0; int outputBufferId = decoder.dequeueOutputBuffer(info, DEFAULT_TIMEOUT_US); if (outputBufferId >= 0) { if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { sawOutputEOS = false; } boolean doRender = (info.size != 0); if (doRender) { outputFrameCount++; ByteBuffer b = null; Image image = null; if (Helper.isUpperThanAPI21()) { image = decoder.getOutputImage(outputBufferId); if(image!=null) { // Log.d(TAG, "image:" + image.getWidth() + "," + image.getHeight() + "," + image.getFormat()); } else { b = decoder.getOutputBuffer(outputBufferId); MediaFormat format = decoder.getOutputFormat(outputBufferId); srcColorFormat = format.getInteger(KEY_COLOR_FORMAT); srcStride = format.getInteger(KEY_STRIDE); } } else { b = outputByteBuffers[outputBufferId]; } if(time==-1) time = System.currentTimeMillis(); else { long diff = (System.currentTimeMillis()-time); if(diff<33) { //waitMs((33*1000-diff)/1000); waitMs((33-diff)); } time = System.currentTimeMillis(); } if(callback!=null) { if(image!=null) callback.onImageReady(image); else if (b!=null) callback.onFrameReady(b,info.offset, width, height, srcColorFormat , srcStride); } decoder.releaseOutputBuffer(outputBufferId, false); } } }
Example 19
Source File: VideoThumbnailsExtractor.java From mollyim-android with GNU General Public License v3.0 | 4 votes |
private static void doExtract(final @NonNull MediaExtractor extractor, final @NonNull MediaCodec decoder, final @NonNull OutputSurface outputSurface, final int outputWidth, int outputHeight, long duration, int thumbnailCount, final @NonNull Callback callback) throws TranscodingException { final int TIMEOUT_USEC = 10000; final ByteBuffer[] decoderInputBuffers = decoder.getInputBuffers(); final MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); int samplesExtracted = 0; int thumbnailsCreated = 0; Log.i(TAG, "doExtract started"); final ByteBuffer pixelBuf = ByteBuffer.allocateDirect(outputWidth * outputHeight * 4); pixelBuf.order(ByteOrder.LITTLE_ENDIAN); boolean outputDone = false; boolean inputDone = false; while (!outputDone) { if (!inputDone) { int inputBufIndex = decoder.dequeueInputBuffer(TIMEOUT_USEC); if (inputBufIndex >= 0) { final ByteBuffer inputBuf = decoderInputBuffers[inputBufIndex]; final int sampleSize = extractor.readSampleData(inputBuf, 0); if (sampleSize < 0 || samplesExtracted >= thumbnailCount) { decoder.queueInputBuffer(inputBufIndex, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM); inputDone = true; Log.i(TAG, "input done"); } else { final long presentationTimeUs = extractor.getSampleTime(); decoder.queueInputBuffer(inputBufIndex, 0, sampleSize, presentationTimeUs, 0 /*flags*/); samplesExtracted++; extractor.seekTo(duration * samplesExtracted / thumbnailCount, MediaExtractor.SEEK_TO_CLOSEST_SYNC); Log.i(TAG, "seek to " + duration * samplesExtracted / thumbnailCount + ", actual " + extractor.getSampleTime()); } } } int outputBufIndex = decoder.dequeueOutputBuffer(info, TIMEOUT_USEC); if (outputBufIndex >= 0) { if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { outputDone = true; } final boolean shouldRender = (info.size != 0) /*&& (info.presentationTimeUs >= duration * decodeCount / thumbnailCount)*/; decoder.releaseOutputBuffer(outputBufIndex, shouldRender); if (shouldRender) { outputSurface.awaitNewImage(); outputSurface.drawImage(); if (thumbnailsCreated < thumbnailCount) { pixelBuf.rewind(); GLES20.glReadPixels(0, 0, outputWidth, outputHeight, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, pixelBuf); final Bitmap bitmap = Bitmap.createBitmap(outputWidth, outputHeight, Bitmap.Config.ARGB_8888); pixelBuf.rewind(); bitmap.copyPixelsFromBuffer(pixelBuf); if (!callback.publishProgress(thumbnailsCreated, bitmap)) { break; } Log.i(TAG, "publishProgress for frame " + thumbnailsCreated + " at " + info.presentationTimeUs + " (target " + duration * thumbnailsCreated / thumbnailCount + ")"); } thumbnailsCreated++; } } } Log.i(TAG, "doExtract finished"); }