2

我正在使用 MediaSync 和 MediaExtractor 播放视频。

要开始播放,我写了下面的代码

 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();

我已将以下代码用于解码器回调:

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

                }
            };

如果我修改了 onOutputBufferAvailable 中的代码,它会以正常的播放速度播放,

@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();
                }
            }

这不是正确的做法。

如果有人可以帮助我找到以正常速度播放视频的正确方法。

4

1 回答 1

1

不确定这是否能解决您的问题,但您对 releaseOutputBuffer 的调用似乎具有以微秒为单位的时间戳。查看 MediaSync 文档中的示例,表明此时间戳需要以纳秒为单位。所以你需要将 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

于 2015-11-15T22:22:59.580 回答