将Unity Texture2D转换为YUV420P的FFMPEG

Converting Unity texture2d to YUV420P for ffmpeg

本文关键字:YUV420P FFMPEG 转换 Unity Texture2D      更新时间:2023-10-16

我正在尝试使用FFMPEG在Unity Player内部创建视频记录器。

我有下一个代码段:

Unity,C#:

Texture2D frameTexture = new Texture2D(frameWidth, frameHeight, TextureFormat.RGB24, false);
//...
frameTexture.ReadPixels(new Rect(0, 0, frameWidth, frameHeight), 0, 0, false);
frameTexture.Apply();
//.....
byte[] pixels = frameTexture.GetRawTextureData();
AddFrame(pixels, pixels.Length, libApi);

//DLL Function Declaration
[DllImport("VideoCapture", CallingConvention = CallingConvention.Cdecl)]
static extern void AddFrame(byte[] data, int size, System.IntPtr api);

C 代码:

__declspec(dllexport) void AddFrame(uint8_t *data, int size, VideoCapture *vc) {
    vc->AddFrame(data, size);
}
void VideoCapture::AddFrame(uint8_t *data, int size) {
    Log("nAdding framen");
    int err;
    if (!videoFrame) {
        Log("Allocating Video Framen");
        videoFrame = av_frame_alloc();
        videoFrame->format = AV_PIX_FMT_YUV420P;
        videoFrame->width = cctx->width;
        videoFrame->height = cctx->height;
        if ((err = av_frame_get_buffer(videoFrame, 32)) < 0) {
            Debug("Failed to allocate picture", err);
            return;
        }
    }
    if (!swsCtx) {
        Log("Creating SWS contextn");
        swsCtx = sws_getContext(cctx->width, cctx->height, AV_PIX_FMT_RGB24, cctx->width, cctx->height, AV_PIX_FMT_YUV420P, 0, 0, 0, 0);
    }
    uint8_t * inData[1] = { data };
    int inLinesize[1] = { 3 * cctx->width };
    Log("Scaling datan");
    // From RGB to YUV
    if ((err = sws_scale(swsCtx, inData, inLinesize, 0, cctx->height, videoFrame->data, videoFrame->linesize)) < 0) {
        Debug("Failed to scale img", err);
        return;
    }
    ...........

Unity播放器在执行" SWS_SCALE"时会崩溃。

来自Unity的日志:

  ERROR: SymGetSymFromAddr64, GetLastError: 'Attempt to access invalid address.' (Address: 00007FF8437B49A6)
0x00007FF8437B49A6 (swscale-4) 
  ERROR: SymGetSymFromAddr64, GetLastError: 'Attempt to access invalid address.' (Address: 00007FF8437B2982)
0x00007FF8437B2982 (swscale-4) 
0x00007FF8437E78A6 (swscale-4) sws_get_class
0x00007FF8437E8E47 (swscale-4) sws_scale

我认为它是因为" sws_get_class",但是如果我直接调用此功能,它可以工作。如果我将空数据传递到" sws_scale"中,它也可以工作,只是抱怨它是无效的。因此,原因是数据本身,但我没有什么问题。

我还尝试将纹理编码为JPG和PNG,将数组固定在内存中,但结果没有改变。

预先感谢

upd :::

将dll函数更改为

unsafe void AddFrame(byte[] data)
{
    fixed (byte* p = data)
    {
        AddFrame((IntPtr)p, data.Length, customLib);
    }
}
//Function declaration
static extern void AddFrame(IntPtr data, int size, System.IntPtr api);

但是错误仍然存在。

sws_scale失败的原因是sws_getContextsws_scale的源高度和宽度不正确。您应该将尺寸传递到统一的方法或硬核值中。

sws_scale还返回输出切片的高度,而不是错误。