为了账号安全,请及时绑定邮箱和手机立即绑定

MediaCodec和Camera:色彩空间不匹配

MediaCodec和Camera:色彩空间不匹配

ITMISS 2019-11-26 14:40:37
我一直在尝试使用新的低级MediaCodec使H264编码与Android平板电脑上的相机捕获的输入配合使用。由于MediaCodecAPI的文献记录不多,我在此方面遇到了一些困难,但是我终于有了一些工作。我将相机设置如下:        Camera.Parameters parameters = mCamera.getParameters();        parameters.setPreviewFormat(ImageFormat.YV12); // <1>        parameters.setPreviewFpsRange(4000,60000);        parameters.setPreviewSize(640, 480);                    mCamera.setParameters(parameters);最终目标是创建一个RTP流(并与Skype对应),但是到目前为止,我仅将原始H264直接流到我的桌面上。在那里,我使用以下GStreamer管道显示结果:gst-launch udpsrc port=5555 ! video/x-h264,width=640,height=480,framerate=15/1 ! ffdec_h264 ! autovideosink除颜色外,其他所有方法均正常。我需要在计算机中设置2种颜色格式:一种用于摄像机预览(标有的行<1>),另一种用于MediaCodec对象(标有的<2>)确定<1>我使用的线的可接受值parameters.getSupportedPreviewFormats()。由此,我知道相机上唯一受支持的格式是ImageFormat.NV21和ImageFormat.YV2。为<2>,我检索的MediaCodecInfo.CodecCapabilities -object类型视频/ AVC,作为整数值19(与对应MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar和2130708361(其不与任何值对应MediaCodecInfo.CodecCapabilities)。除上述以外的任何其他值都将导致崩溃。组合这些设置会得出不同的结果,我将在下面显示。这是Android上的屏幕截图(即“真实”颜色): 在Android平板电脑上输入 这是Gstreamer显示的结果:<1>= NV21,<2>= COLOR_FormatYUV420Planar NV21-COLOR_FormatYUV420Planar的Gstreamer输出<1>= NV21,<2>= 2130708361 NV21-2130708361的Gstreamer输出<1>= YV2,<2>= COLOR_FormatYUV420Planar YV2-COLOR_FormatYUV420Planar的Gstreamer输出<1>= YV2,<2>= 2130708361 YV2-2130708361的Gstreamer输出可以看出,这些都不令人满意。YV2色彩空间看起来是最有前途的,但看起来像红色(Cr)和蓝色(Cb)是倒置的。我猜NV21看起来是隔行扫描的(但是,我不是该领域的专家)。由于目的是与Skype通信,因此我认为我不应该更改解码器(即Gstreamer命令),对吗?这是否需要在Android中解决?如果可以,如何解决?还是可以通过添加某些RTP有效负载信息来解决?还有其他建议吗?
查看完整描述

3 回答

?
繁花不似锦

TA贡献1851条经验 获得超4个赞

我通过使用一个简单的函数在Android级别上交换字节平面解决了该问题:


public byte[] swapYV12toI420(byte[] yv12bytes, int width, int height) {

    byte[] i420bytes = new byte[yv12bytes.length];

    for (int i = 0; i < width*height; i++)

        i420bytes[i] = yv12bytes[i];

    for (int i = width*height; i < width*height + (width/2*height/2); i++)

        i420bytes[i] = yv12bytes[i + (width/2*height/2)];

    for (int i = width*height + (width/2*height/2); i < width*height + 2*(width/2*height/2); i++)

        i420bytes[i] = yv12bytes[i - (width/2*height/2)];

    return i420bytes;

}


查看完整回答
反对 回复 2019-11-26
?
桃花长相依

TA贡献1860条经验 获得超8个赞

我认为将价值交换到位会更有效。


        int wh4 = input.length/6; //wh4 = width*height/4

        byte tmp;

        for (int i=wh4*4; i<wh4*5; i++)

            {

            tmp = input[i];

            input[i] = input[i+wh4];

            input[i+wh4] = tmp;

            }

甚至更好,您可以代替


            inputBuffer.put(input);

以正确的顺序排列3个平面切片


            inputBuffer.put(input, 0, wh4*4);

            inputBuffer.put(input, wh4*5, wh4);

            inputBuffer.put(input, wh4*4, wh4);

我认为那应该只有很小的开销


查看完整回答
反对 回复 2019-11-26
?
饮歌长啸

TA贡献1951条经验 获得超3个赞

似乎Android正在使用YV12进行传输,但在H264标头中设置的格式为YUV420。除了U和V通道的顺序不同之外,这些格式是相同的,这说明了红色和蓝色的交换。


最好当然是将设置固定在Android端。但是,如果无法为相机和编码器设置兼容设置,则必须在GStreamer端强制使用该格式。


这可以通过capssetter在ffdec_h264



... ! ffdec_h264 ! capssetter caps="video/x-raw-yuv, format=(fourcc)YV12" ! colorspace ! ...


查看完整回答
反对 回复 2019-11-26
  • 3 回答
  • 0 关注
  • 1072 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信