简体   繁体   English

使用 MediaCodec 和 MediaExtractor 播放视频和音频

[英]Play Video and audio using MediaCodec and MediaExtractor

I am trying to play a video using MediaCodec.我正在尝试使用 MediaCodec 播放视频。 The video is playing but the audio is mute.I want to unmute the audio.After research I found that we need to decode the audio and video separately.I want to use only one Mediacodec and MediaExtractor object to play video and audio.How is this achievable?视频正在播放但是音频静音。我想取消静音。经过研究我发现我们需要将音频和视频分开解码。我只想使用一个Mediacodec和MediaExtractor对象来播放视频和音频。如何这可以实现吗? I used the following code for playing video.我使用以下代码播放视频。

        extractor = new MediaExtractor();
        extractor.setDataSource(SAMPLE);

        for (int i = 0; i < extractor.getTrackCount(); i++) {
            MediaFormat format = extractor.getTrackFormat(i);
            String mime = format.getString(MediaFormat.KEY_MIME);
            if (mime.startsWith("video/")) {
                extractor.selectTrack(i);
                decoder = MediaCodec.createDecoderByType(mime);
                decoder.configure(format, surface, null, 0);
                break;
            }
        }

        if (decoder == null) {
            Log.e("DecodeActivity", "Can't find video info!");
            return;
        }

        decoder.start();

        ByteBuffer[] inputBuffers = decoder.getInputBuffers();
        ByteBuffer[] outputBuffers = decoder.getOutputBuffers();
        BufferInfo info = new BufferInfo();
        boolean isEOS = false;
        long startMs = System.currentTimeMillis();

        while (!Thread.interrupted()) {
            if (!isEOS) {
                int inIndex = decoder.dequeueInputBuffer(10000);
                if (inIndex >= 0) {
                    ByteBuffer buffer = inputBuffers[inIndex];
                    int sampleSize = extractor.readSampleData(buffer, 0);
                    if (sampleSize < 0) {
                        // We shouldn't stop the playback at this point, just pass the EOS
                        // flag to decoder, we will get it again from the
                        // dequeueOutputBuffer
                        Log.d("DecodeActivity", "InputBuffer BUFFER_FLAG_END_OF_STREAM");
                        decoder.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                        isEOS = true;
                    } else {
                        decoder.queueInputBuffer(inIndex, 0, sampleSize, extractor.getSampleTime(), 0);
                        extractor.advance();
                    }
                }
            }

            int outIndex = decoder.dequeueOutputBuffer(info, 10000);
            switch (outIndex) {
            case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
                Log.d("DecodeActivity", "INFO_OUTPUT_BUFFERS_CHANGED");
                outputBuffers = decoder.getOutputBuffers();
                break;
            case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
                Log.d("DecodeActivity", "New format " + decoder.getOutputFormat());
                break;
            case MediaCodec.INFO_TRY_AGAIN_LATER:
                Log.d("DecodeActivity", "dequeueOutputBuffer timed out!");
                break;
            default:
                ByteBuffer buffer = outputBuffers[outIndex];
                Log.v("DecodeActivity", "We can't use this buffer but render it due to the API limit, " + buffer);

                // We use a very simple clock to keep the video FPS, or the video
                // playback will be too fast
                while (info.presentationTimeUs / 1000 > System.currentTimeMillis() - startMs) {
                    try {
                        sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        break;
                    }
                }
                decoder.releaseOutputBuffer(outIndex, true);
                break;
            }

            // All decoded frames have been rendered, we can stop playing now
            if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                Log.d("DecodeActivity", "OutputBuffer BUFFER_FLAG_END_OF_STREAM");
                break;
            }
        }

        decoder.stop();
        decoder.release();
        extractor.release();
    }

You can use one extractor but two MediaCodec instances for audio and video playback.您可以使用一个提取器,但使用两个MediaCodec实例进行音频和视频播放。 Only one MediaCodec instance can't do that.只有一个MediaCodec实例无法做到这一点。 For demuxer one extractor is ok, it demuxes file into an audio stream and a video stream.对于解复用器,一个提取器就可以了,它将文件解复用为音频流和视频流。 But audio and video streams should use different decoders, like audio AAC, video AVC etc... And MediaCodec can't change decode type dynamically, so you should create different MediaCodec instances for each stream.但是音频和视频流应该使用不同的解码器,如音频 AAC、视频 AVC 等......并且MediaCodec不能动态更改解码类型,因此您应该为每个流创建不同的MediaCodec实例。 A player should consider AV synchronization... You can refer: https://github.com/saki4510t/AudioVideoPlayerSample播放器应该考虑AV同步...可以参考: https : //github.com/saki4510t/AudioVideoPlayerSample

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM