Search code examples
cffmpegsdlsdl-2

Using SDL2 Render Pixels to create video using ffmpeg


I made a small animation using SDL2 and I want to use ffmpeg to convert it to an h264 encoded video. I'm getting the texture RGBA pixels using SDL_RenderReadPixels and sending them to ffmpeg for rendering. The video does render, but is all messed up. The following is my code

Spawning ffmpeg

int child_pipe[2];

if (pipe(child_pipe) < 0) {
    perror("child_pipe");
}

printf("child_pipe[0]: %d, child_pipe[1]: %d\n", child_pipe[0], child_pipe[1]);

args.ffmpeg = &(FFMpeg){.std_in = child_pipe[WRITE_END]};

child_pid = fork();

printf("child: %d\n", child_pid);

if (child_pid == 0) {
    close(child_pipe[WRITE_END]);

    if (dup2(child_pipe[READ_END], STDIN_FILENO) < 0) {
        perror("dup2");
        return -1;
    }

    char *argv[] = {"ffmpeg",  "-loglevel", "verbose", "-y",   "-f",      "rawvideo", "-pixel_format", "rgba",      "-s",
                    "894x702", "-i",        "-",       "-c:v", "libx264", "-pix_fmt", "yuv420p",       "thing.mp4", NULL};

    int x = execvp("ffmpeg", argv);

    if (x != 0) {
        perror("execv");
        return x;
    }

    return -1;
}


Here's how I render into SDL2 renderer. The rendering on SDL2 has no issues. In here I get the render pixels and send them to ffmpeg.

void render_image(SDL_Renderer *renderer, int array[], size_t array_size, Image *image, FFMpeg *ffmpeg) {
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer);

    for (int i = 0; i < array_size; i++) {
        paint_image_strip(renderer, image, i, array[i]);
    }

    if (ANIMATION_DELAY_MS > 0) {
        SDL_Delay(ANIMATION_DELAY_MS);
    }

    if (ffmpeg != NULL) {
        int size = image->width * image->height * sizeof(Uint32);
        Uint32 *pixels = (Uint32 *)malloc(size);

        if (pixels == NULL) {
            printf("Malloc failed. Buy more ram\n");
            return;
        }

        int ret = SDL_RenderReadPixels(renderer, NULL, SDL_PIXELFORMAT_RGBA8888, pixels, image->width * sizeof(Uint32));

        if (ret != 0) {
            fprintf(stderr, "SDL_RenderReadPixels failed: %s\n", SDL_GetError());
            free(pixels);
        }

        int n = write(ffmpeg->std_in, image->img_data, size);

        if (n < 0) {
            perror("write failed");
        }

        free(pixels);
    }

    SDL_RenderPresent(renderer);
}

Here's the issue. Here is what I see in SDL2 window

enter image description here

and this is what ffmpeg renders enter image description here

there are inklings of the original image here. I thought it was an issue with RGBA vs ARGB but on double checking that wasn't the case.

Expecting proper ffmpeg rendering.


Solution

  • It was an extremely stupid issue. On this line

    int n = write(ffmpeg->std_in, image->img_data, size);
    

    I'm writing the image data instead of the data I get from SDL2