chikka.anddev
chikka.anddev

Reputation: 9629

Playback speed is 2x faster using MediaSync and MediaExtractor

I am using MediaSync and MediaExtractor for playing video.

To start playback I have written below code

 MediaSync mediaSync = new MediaSync();
            mediaSync.setSurface(surface);
            Surface inputSurface = mediaSync.createInputSurface();

             mediaExtractor = new MediaExtractor();

            try {
                mediaExtractor.setDataSource(this.clipPath);
            } catch (IOException e1) {
                e1.printStackTrace();
            }


            for (int i = 0; i < mediaExtractor.getTrackCount(); i++) {
                MediaFormat format = mediaExtractor.getTrackFormat(i);
                String mime = format.getString(MediaFormat.KEY_MIME);
                if (mime.startsWith("video/")) {
                    Log.d("Med","Formt data:" +format.toString());
                    Log.d("Med","frame  data:" +format.getInteger(MediaFormat.KEY_FRAME_RATE));
                    ratio=format.getInteger(MediaFormat.KEY_FRAME_RATE);
//                    Log.d("Med","capture  data:" +format.getInteger(MediaFormat.KEY_CAPTURE_RATE));

                            mediaExtractor.selectTrack(i);
//                    ratio=1000f/format.getInteger(MediaFormat.KEY_FRAME_RATE);
                    try {
                        videoDecoder = MediaCodec.createDecoderByType(mime);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    videoDecoder.configure(format, inputSurface, null, 0);
                    Log.d(LOG_TAG, "Found a video track.");
                    break;
                }
            }

            SyncParams syncParams = new SyncParams();
            syncParams.allowDefaults();

            mediaSync.setPlaybackParams(new PlaybackParams().allowDefaults());
            mediaSync.setSyncParams(syncParams);

            videoDecoder.setCallback(decoderCallback, null);
            videoDecoder.start();

I have used below code for decoder callback:

MediaCodec.Callback decoderCallback = new MediaCodec.Callback() {
            @Override
            public void onInputBufferAvailable(MediaCodec codec, int index) {
                if (index >= 0) {
                    ByteBuffer byteBuffer = codec.getInputBuffer(index);
                    int sampleSize = mediaExtractor.readSampleData(byteBuffer, 0);
                    Log.d(LOG_TAG, "SampleSize: " + sampleSize);
                    if (sampleSize < 0) {
                        //we're at end of file so submit EOS to the decoder input
                        Log.d(LOG_TAG, "Video Decoder input EOS reached");
                        codec.queueInputBuffer(index, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                    } else {
                        long sampleTime = mediaExtractor.getSampleTime();
                        Log.d(LOG_TAG  ,"ratio"+ratio+" sampletime"+sampleTime);
                        codec.queueInputBuffer(index, 0, sampleSize, sampleTime, 0);
                        mediaExtractor.advance();
                    }
                }
            }

            @Override
            public void onError(MediaCodec codec, MediaCodec.CodecException e) {

            }



               @Override
                public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) {

                }

                @Override
                public void onOutputBufferAvailable(MediaCodec codec, int index, MediaCodec.BufferInfo info) {
                    Log.d(LOG_TAG, "Rendering with preso time: " + info.presentationTimeUs);
                    codec.releaseOutputBuffer(index, info.presentationTimeUs);

                }
            };

If I modified code in onOutputBufferAvailable,it plays with normal playback speed,

@Override
            public void onOutputBufferAvailable(MediaCodec codec, int index, MediaCodec.BufferInfo info) {
                Log.d(LOG_TAG, "Rendering with preso time: " + info.presentationTimeUs);
                codec.releaseOutputBuffer(index, info.presentationTimeUs+(ratio+1000000L));
                try {

                    Thread.sleep((int)(1000/ratio));
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

It is not correct way of doing it.

If anybody can help me to find correct way to play video at normal speed.

Upvotes: 2

Views: 1391

Answers (1)

craigts
craigts

Reputation: 3077

Not sure if this will solve your problem, but the call you are making to releaseOutputBuffer appears to have the timestamp in microseconds. Looking at the example from the MediaSync docs, shows that this timestamp needs to be in nanoseconds. So you need to multiply info.presentationTimeUs * 1000.

onOutputBufferAvailable(MediaCodec codec, int bufferId, BufferInfo info) {
 // ...
 if (codec == videoDecoder) {
     // surface timestamp must contain media presentation time in nanoseconds.
     codec.releaseOutputBuffer(bufferId, 1000 * info.presentationTime);
 } else {
     ByteBuffer audioByteBuffer = codec.getOutputBuffer(bufferId);
     sync.queueAudio(audioByteBuffer, bufferId, info.presentationTime);
 }
 // ...

}

http://developer.android.com/reference/android/media/MediaSync.html

Upvotes: 1

Related Questions