【问题标题】:Decoding h264 ByteStream on Android在 Android 上解码 h264 ByteStream
【发布时间】:2014-04-15 10:27:03
【问题描述】:

我想在 Android 中解码和显示原始 h264 视频字节流,因此我目前正在使用 MediaCodec/Format 类。我通过 Udp 从服务器获取帧数据。 但是,不幸的是,目前没有显示任何内容。

这是我目前所拥有的。

初始化 MediaCodec 类:

codec = MediaCodec.createDecoderByType("video/avc");

MediaFormat format = new MediaFormat();
format.setString(MediaFormat.KEY_MIME, "video/avc");
format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 100000);
format.setInteger(MediaFormat.KEY_WIDTH, 800);
format.setInteger(MediaFormat.KEY_HEIGHT, 600);
format.setInteger("max-width", 800);
format.setInteger("max-height", 600);
format.setInteger("push-blank-buffers-on-shutdown", 1);

codec.configure(format, surface, null, 0);

解码器的使用:

int inIndex = codec.dequeueInputBuffer(10000);
if(inIndex >= 0)
{
                ByteBuffer inputBuffer = codecInputBuffers[inIndex];
                inputBuffer.clear();
                inputBuffer.put(frameData);
                codec.queueInputBuffer(inIndex, 0, frameSize, 33, 0);
}

int outIndex = codec.dequeueOutputBuffer(null, 10000);

switch(outIndex)
{
  case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
    codecOutputBuffers = codec.getOutputBuffers();
    System.out.println("OB Changed");
    break;
  case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
        System.out.println("OF Changed");
        break;
  case MediaCodec.INFO_TRY_AGAIN_LATER:
    System.out.println("l8r");
    break;
  default:
    ByteBuffer buffer = codecOutputBuffers[outIndex];
    codec.releaseOutputBuffer(outIndex, true);
}

我正在测试此代码的设备是 Google Nexus 5。当我运行它时,outIndex 始终等于 MediaCodec.INFO_TRY_AGAIN_LATER

我之前写过一个笔记本的客户端,效果很好,所以我猜来自服务器的h264流应该没问题。

感谢您的帮助

编辑: 如果有人遇到同样的问题,fadden 的提议修正案(1)解决了这个问题。我更正了上面的代码。它现在工作。我展示的示例的另一个错误是,您不能将 null 传递给 .dequeueOutputBuffers(...);。你必须做类似的事情

        BufferInfo buffInfo = new MediaCodec.BufferInfo();
        int outIndex = codec.dequeueOutputBuffer(buffInfo, 10000);

即使您对此不感兴趣。 ;)

【问题讨论】:

  • 你能把更正后的代码分享给我们吗?

标签: java android video decode android-mediacodec


【解决方案1】:

我发现了一些问题...

(1) 您正在尝试替换输入缓冲区数组中的缓冲区。 MediaCodec 不是这样工作的——框架提供缓冲区,您将数据复制到其中。这个想法是,通过允许框架进行分配,它可以潜在地避免以后复制数据。

您需要从decoder.getInputBuffers() 获取输入缓冲区数组,并使用它们。确保每次clear()ByteBuffer重置位置和限制。

(2) 您正在写入一个数据包并期待一帧输出数据。实际上,您可能需要在生成第一帧之前提供多个数据缓冲区。有关示例,请参阅this post。在某些配置文件中,允许编码器重新排序帧,因此即使在解码器开始运行之后,您也不能只输入一个帧并等待解码数据从另一侧弹出。

(3) AVC 解码器needs the SPS/PPS data,您可以通过设置了BUFFER_FLAG_CODEC_CONFIG 标志的缓冲区来提供它,或者通过将带有“csd-0”/“csd-1”键的数据添加到@987654332 @使用MediaFormat#setByteBuffer()。可以在EncodeDecodeTest 中找到这两种方法的示例。

bigflake上有很多AVC解码的例子,但是数据源是MediaCodec编码器,所以一般都是免费得到第3点的。

This posting 可能对你有用。

对于显示帧,您可以在 Grafika 中看到不同的方法(通常适用于 .mp4 文件,因此那里的编码/解码实现不那么相关)。

【讨论】:

    猜你喜欢
    • 2014-01-26
    • 1970-01-01
    • 1970-01-01
    • 2012-10-29
    • 2014-02-06
    • 2013-04-25
    • 1970-01-01
    • 2015-05-14
    • 2012-02-24
    相关资源
    最近更新 更多