You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

API 21以下版本MediaCodec解码时TextureView无法正常工作

Fixing MediaCodec No Display on TextureView Below API 21

Hey, this is a super common compatibility issue with MediaCodec pre-API 21—those older Android versions are way pickier about configuration and Surface handling compared to Lollipop and above. Let's walk through the key fixes and checks to get your TextureView showing video:

1. Fix the Invalid csd-0 Data

First off, your current csd-0 setup is a problem! csd-0 holds the H.264 SPS (Sequence Parameter Set) and PPS (Picture Parameter Set) data—this is mandatory for the decoder to understand how to decode the video. Just allocating an empty ByteBuffer like ByteBuffer.allocate(100) works for API 21+ (they have better fallback logic), but pre-21 decoders will just refuse to work without valid codec-specific data.

Here's how to do it right:

  • Extract the actual SPS and PPS bytes from your video stream (these usually come at the start of the stream, or in the container metadata)
  • Package them into a single ByteBuffer following the H.264 standard: start with the SPS (prefixed with 0x00 0x00 0x00 0x01), then the PPS (also prefixed with 0x00 0x00 0x00 0x01)
  • Don't forget to flip() the ByteBuffer so the decoder reads from the start:
// Example: assuming you have spsBytes and ppsBytes as your real SPS/PPS data
ByteBuffer csd0 = ByteBuffer.allocate(spsBytes.length + ppsBytes.length);
csd0.put(spsBytes);
csd0.put(ppsBytes);
csd0.flip(); // Critical! Resets the buffer position to 0
format.setByteBuffer("csd-0", csd0);

2. Fix Surface Initialization for Pre-API 21

Before API 21, you can't just create a Surface from a TextureView's SurfaceTexture directly and pass it to MediaCodec.configure(). You need to wait until the TextureView's Surface is fully available, and use the Surface provided by the TextureView itself.

Do this with a SurfaceTextureListener:

mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        // Initialize your codec ONLY after the TextureView is ready
        setupMediaCodec();
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
        // Handle size changes if needed
    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        // Clean up codec resources here
        if (m_codec != null) {
            m_codec.stop();
            m_codec.release();
        }
        return true;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
        // Optional: handle texture updates
    }
});

private void setupMediaCodec() {
    MediaFormat format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 1920, 1080);
    // Set your corrected csd-0 here...
    format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 100000);
    
    try {
        m_codec = MediaCodec.createDecoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
        // Use the TextureView's built-in Surface directly
        m_codec.configure(format, mTextureView.getSurface(), null, 0);
        m_codec.start();
        // Now start feeding frames to the decoder...
    } catch (IOException e) {
        e.printStackTrace();
    }
}

3. Enforce Strict Buffer Handling for Older Decoders

Pre-API 21 decoders are less forgiving with buffer timing and handling. Make sure you use timeouts when dequeuing buffers, and properly manage input/output buffers:

// Feed input frames to the decoder
private void feedFrameToDecoder(byte[] frameData, long timestampUs) {
    long timeoutUs = 10000; // 10ms timeout to avoid hanging
    int inputBufferId = m_codec.dequeueInputBuffer(timeoutUs);
    
    if (inputBufferId >= 0) {
        ByteBuffer inputBuffer = m_codec.getInputBuffer(inputBufferId);
        inputBuffer.clear();
        inputBuffer.put(frameData);
        // Submit the buffer with a valid timestamp (use monotonic time for real-time streams)
        m_codec.queueInputBuffer(inputBufferId, 0, frameData.length, timestampUs, 0);
    }
}

// Process output frames to render to TextureView
private void processOutputFrames() {
    MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
    long timeoutUs = 10000;
    int outputBufferId = m_codec.dequeueOutputBuffer(bufferInfo, timeoutUs);
    
    while (outputBufferId >= 0) {
        // Release the buffer to render it to the Surface (true = auto-release after rendering)
        m_codec.releaseOutputBuffer(outputBufferId, true);
        outputBufferId = m_codec.dequeueOutputBuffer(bufferInfo, timeoutUs);
    }
}

4. Extra Checks for Pre-API 21

  • Ensure your video frames are valid H.264 NALU units (either prefixed with 0x00 0x00 0x00 0x01 or using length prefixes—older decoders won't handle malformed NALUs)
  • Don't run codec operations on the main thread—use a dedicated background thread to avoid ANRs and timing issues
  • Make sure timestamps are monotonic (increasing) — older decoders can glitch or stop if they get out-of-order timestamps

Start with fixing the csd-0 data first—that's the most likely culprit here. Once that's sorted, verify your Surface initialization flow, and you should see video rendering on pre-API 21 devices.

内容的提问来源于stack exchange,提问作者Bikash Sahani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:21:27