Reputation: 9629
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
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