Search code examples
c++winapiwic

Encoding animated gif with WIC Imaging Component -> Infinite loop


I have a std::vector<> of IWICBitmapSource and trying to create an animated gif:

void SaveGif()
{
    CComPtr<IWICBitmapEncoder> wicBitmapEncoder;
    auto hr =
        fact->CreateEncoder(
            GUID_ContainerFormatGif,
            nullptr,    // No preferred codec vendor.
            &wicBitmapEncoder
        );
    VectorStream stream;
    hr =
        wicBitmapEncoder->Initialize(
            &stream,
            WICBitmapEncoderNoCache
        );
    for (auto& gox : Gifs)
    {
        CComPtr<IWICBitmapFrameEncode> wicFrameEncode;
        hr =
            wicBitmapEncoder->CreateNewFrame(
                &wicFrameEncode,
                0
            );
        hr =
            wicFrameEncode->Initialize(bag2);
        auto g2 = GUID_WICPixelFormat24bppRGB;
        wicFrameEncode->SetPixelFormat(&g2);

        WICRect wr = {};
        UINT wi, he;
        gox.second->GetSize(&wi,&he);
        wr.Width = wi;
        wr.Height = he;
        hr = wicFrameEncode->WriteSource(gox.second, &wr);
        hr = wicFrameEncode->Commit();
    }
 // save stream to gif file
}

All functions succeed, the final file is animating, but not looping. It stops at the last frame.

How can I tell it to loop indefinitely?


Solution

  • Using the links in Simon Mourier's comment, I came up with this snippet and it seems to be working (for my single testcase):

    CComPtr<IWICMetadataQueryWriter> meta; // Get a metadata writer
    wicBitmapEncoder->GetMetadataQueryWriter(&meta);
    PROPVARIANT app = { 0 };
    PROPVARIANT data = { 0 };
    const char *appext = "NETSCAPE2.0"; // application that defined the extension
    struct LoopCount // the data that is needed for the extension (see Simon's links)
    {
        unsigned char block_size = 3;
        unsigned char block_id = 1;
        unsigned short loopcount = 0;
    } bData;
    
    // Setup the PROPVARIANTS
    PropVariantInit(&app);
    PropVariantInit(&data);
    data.vt = VT_UI1|VT_VECTOR;
    app.vt = VT_UI1|VT_VECTOR;
    app.cac.cElems = strlen(appext);
    app.cac.pElems = (char *)appext;
    
    data.cac.cElems = sizeof(LoopCount);
    data.cac.pElems = (char *)&bData;
    
    meta->SetMetadataByName(L"/appext/application", &app); // Write the metadata
    meta->SetMetadataByName(L"/appext/data", &data);