Tencent / libpag

The official rendering library for PAG (Portable Animated Graphics) files that renders After Effects animations natively across multiple platforms.
https://pag.io
Other
4.96k stars 452 forks source link

linux使用MakeOffscreen函数返回空指针,报错为GLDevice::Make() eglCreatePbufferSurface error=12289,---pagSurface is nullptr!!! #2309

Open zhangjiahua1109 opened 3 months ago

zhangjiahua1109 commented 3 months ago

【版本信息】

4.3.3

【平台信息】

Linux

【预期的表现】

Linux中的示例demo跑通就行了。

【实际的情况】

Linux中的示例demo跑不通,报错:GLDevice::Make() eglCreatePbufferSurface error=12289 ---pagSurface is nullptr!!!

【Demo及附件】

include

include

include

include <pag/pag.h>

include <pag/file.h>

int64_t GetTimer() { static auto START_TIME = std::chrono::high_resolution_clock::now(); auto now = std::chrono::high_resolution_clock::now(); auto ns = std::chrono::duration_cast(now - START_TIME); return static_cast(ns.count() * 1e-3); }

std::shared_ptr ReplaceImageOrText() { auto pagFile = pag::PAGFile::Load("../assets/test2.pag"); if (pagFile == nullptr) { printf("pagFile == nullptr"); return nullptr; }

printf("test1");

for (int i = 0; i < pagFile->numImages(); i++) {
    auto pagImage = pag::PAGImage::FromPath("../assets/scene.png");
    pagFile->replaceImage(i, pagImage);
}

printf("test2");

for (int i = 0; i < pagFile->numTexts(); i++) 
{
    std::shared_ptr<pag::TextDocument> textDocumentHandle = pagFile->getTextData(i);
    textDocumentHandle->text = "hah哈 哈哈哈哈👌";

    // Use special font
    auto pagFont = pag::PAGFont::RegisterFont("../resources/font/NotoSansSC-Regular.otf", 0);
    textDocumentHandle->fontFamily = pagFont.fontFamily;
    textDocumentHandle->fontStyle = pagFont.fontStyle;
    pagFile-> replaceText(i, textDocumentHandle);
}

printf("test3");

return pagFile;

}

int64_t TimeToFrame(int64_t time, float frameRate) { return static_cast(floor(time * frameRate / 1000000ll)); }

void BmpWrite(unsigned char image, int imageWidth, int imageHeight, const char filename) { unsigned char header[54] = {0x42, 0x4d, 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

int64_t file_size = static_cast<int64_t>(imageWidth) * static_cast<int64_t>(imageHeight) * 4 + 54;
header[2] = static_cast<unsigned char>(file_size & 0x000000ff);
header[3] = (file_size >> 8) & 0x000000ff;
header[4] = (file_size >> 16) & 0x000000ff;
header[5] = (file_size >> 24) & 0x000000ff;

int64_t width = imageWidth;
header[18] = width & 0x000000ff;
header[19] = (width >> 8) & 0x000000ff;
header[20] = (width >> 16) & 0x000000ff;
header[21] = (width >> 24) & 0x000000ff;

int64_t height = -imageHeight;
header[22] = height & 0x000000ff;
header[23] = (height >> 8) & 0x000000ff;
header[24] = (height >> 16) & 0x000000ff;
header[25] = (height >> 24) & 0x000000ff;

char fname_bmp[128];
snprintf(fname_bmp, 128, "%s.bmp", filename);

FILE* fp;
if (!(fp = fopen(fname_bmp, "wb"))) {
    return;
}

fwrite(header, sizeof(unsigned char), 54, fp);
fwrite(image, sizeof(unsigned char), (size_t)(int64_t)imageWidth * imageHeight * 4, fp);
fclose(fp);

}

int main(int argc, char* argv[]) { auto startTime = GetTimer(); // Register fallback fonts. It should be called only once when the application is being initialized. std::vector fallbackFontPaths = {}; fallbackFontPaths.emplace_back("../resources/font/NotoSerifSC-Regular.otf"); fallbackFontPaths.emplace_back("../resources/font/NotoColorEmoji.ttf"); std::vector ttcIndices(fallbackFontPaths.size()); pag::PAGFont::SetFallbackFontPaths(fallbackFontPaths, ttcIndices);

auto pagFile = ReplaceImageOrText();
if (pagFile == nullptr) {
    printf("---pagFile is nullptr!!!\n");
    return -1;
}

printf("width=%d\n", pagFile->width());
printf("height=%d\n", pagFile->height());

auto pagSurface = pag::PAGSurface::MakeOffscreen(pagFile->width(), pagFile->height());
if (pagSurface == nullptr) {
    printf("---pagSurface is nullptr!!!\n");
    return -1;
}
auto pagPlayer = new pag::PAGPlayer();
pagPlayer->setSurface(pagSurface);
pagPlayer->setComposition(pagFile);

auto totalFrames = TimeToFrame(pagFile->duration(), pagFile->frameRate());
auto currentFrame = 0;

int bytesLength = pagFile->width() * pagFile->height() * 4;

while (currentFrame <= totalFrames) {
    pagPlayer->setProgress(currentFrame * 1.0 / totalFrames);
    auto status = pagPlayer->flush();

    printf("---currentFrame:%d, flushStatus:%d \n", currentFrame, status);

    auto data = new uint8_t[bytesLength];
    pagSurface->readPixels(pag::ColorType::BGRA_8888, pag::AlphaType::Premultiplied, data,
                        pagFile->width() * 4);

    std::string imageName = std::to_string(currentFrame);

    BmpWrite(data, pagFile->width(), pagFile->height(), imageName.c_str());

    delete[] data;

    currentFrame++;
}

delete pagPlayer;

printf("----timeCost--:%ld \n", static_cast<long>(GetTimer() - startTime));

return 0;

}

都是工程自带的demo以及pag文件。

kevingpqi123 commented 3 months ago

出现这种情况下的原因是 linux 平台依赖了两个动态库, list(APPEND libs ${CMAKE_CURRENT_SOURCE_DIR}/vendor/swiftshader/linux/x64/libEGL.so) list(APPEND libs ${CMAKE_CURRENT_SOURCE_DIR}/vendor/swiftshader/linux/x64/libGLESv2.so)

对于 linux 平台而言,关于动态库的查找顺序,可以看下这篇文章:https://www.jianshu.com/p/0de77454f105 可以将这两个动态库拷贝至 /usr/lib/ 目录下

zhangjiahua1109 commented 3 months ago

请问,如果我想在docker中运行的话,如何解决?在docker中也会报空指针的信息,在宿主机上是可以跑的,docker中会报空指针。

kevingpqi123 commented 3 months ago

都是一样的哈,linux 平台需要那两个动态库提供 OpenGL 的软环境,如果 PAGSurface 创建出来为空指针,基本上就是那两个库没有链接上

zhangjiahua1109 commented 3 months ago

我用find命令查过了docker中是存在这两个库的,我怀疑是x11的问题,但是现在没法知道。