瀏覽代碼

Factor out ffmpeg process starter into a separate translation unit

rexim 2 年之前
父節點
當前提交
bca6a0a007
共有 6 個文件被更改,包括 113 次插入59 次删除
  1. 1 1
      .gitignore
  2. 0 5
      build.sh
  3. 6 0
      build_raw.sh
  4. 11 0
      ffmpeg.h
  5. 35 53
      ffmpeg_linux.c
  6. 60 0
      main_raw.c

+ 1 - 1
.gitignore

@@ -1,2 +1,2 @@
 *.mp4
 *.mp4
-main
+build/

+ 0 - 5
build.sh

@@ -1,5 +0,0 @@
-#!/bin/sh
-
-set -xe
-
-clang -Wall -Wextra -o main main.c

+ 6 - 0
build_raw.sh

@@ -0,0 +1,6 @@
+#!/bin/sh
+
+set -xe
+
+mkdir -p ./build/
+clang -Wall -Wextra -o ./build/main_raw ./main_raw.c ffmpeg_linux.c

+ 11 - 0
ffmpeg.h

@@ -0,0 +1,11 @@
+#ifndef FFMPEG_H_
+#define FFMPEG_H_
+
+#include <stddef.h>
+
+int ffmpeg_start_rendering(size_t width, size_t height, size_t fps);
+void ffmpeg_send_frame(int pipe, void *data, size_t width, size_t height);
+void ffmpeg_send_frame_flipped(int pipe, void *data, size_t width, size_t height);
+void ffmpeg_end_rendering(int pipe);
+
+#endif // FFMPEG_H_

+ 35 - 53
main.c → ffmpeg_linux.c

@@ -8,100 +8,82 @@
 #include <sys/wait.h>
 #include <sys/wait.h>
 #include <unistd.h>
 #include <unistd.h>
 
 
-#define OLIVEC_IMPLEMENTATION
-#include "olive.c"
-
 #define READ_END 0
 #define READ_END 0
 #define WRITE_END 1
 #define WRITE_END 1
 
 
-#define WIDTH 800
-#define HEIGHT 600
-#define FPS 30
-#define STR2(x) #x
-#define STR(x) STR2(x)
-uint32_t pixels[WIDTH*HEIGHT];
-
-int main(void)
+int ffmpeg_start_rendering(size_t width, size_t height, size_t fps)
 {
 {
     int pipefd[2];
     int pipefd[2];
 
 
     if (pipe(pipefd) < 0) {
     if (pipe(pipefd) < 0) {
         fprintf(stderr, "ERROR: could not create a pipe: %s\n", strerror(errno));
         fprintf(stderr, "ERROR: could not create a pipe: %s\n", strerror(errno));
-        return 1;
+        return -1;
     }
     }
 
 
     pid_t child = fork();
     pid_t child = fork();
     if (child < 0) {
     if (child < 0) {
         fprintf(stderr, "ERROR: could not fork a child: %s\n", strerror(errno));
         fprintf(stderr, "ERROR: could not fork a child: %s\n", strerror(errno));
-        return 1;
+        return -1;
     }
     }
 
 
     if (child == 0) {
     if (child == 0) {
         if (dup2(pipefd[READ_END], STDIN_FILENO) < 0) {
         if (dup2(pipefd[READ_END], STDIN_FILENO) < 0) {
             fprintf(stderr, "ERROR: could not reopen read end of pipe as stdin: %s\n", strerror(errno));
             fprintf(stderr, "ERROR: could not reopen read end of pipe as stdin: %s\n", strerror(errno));
-            return 1;
+            return -1;
         }
         }
         close(pipefd[WRITE_END]);
         close(pipefd[WRITE_END]);
-        
+
+        char resolution[64];
+        snprintf(resolution, sizeof(resolution), "%zux%zu", width, height);
+        char framerate[64];
+        snprintf(framerate, sizeof(framerate), "%zu", fps);
+
         int ret = execlp("ffmpeg",
         int ret = execlp("ffmpeg",
             "ffmpeg",
             "ffmpeg",
             "-loglevel", "verbose",
             "-loglevel", "verbose",
             "-y",
             "-y",
+
             "-f", "rawvideo",
             "-f", "rawvideo",
             "-pix_fmt", "rgba",
             "-pix_fmt", "rgba",
-            "-s", STR(WIDTH) "x" STR(HEIGHT),
-            "-r", STR(FPS),
-            "-an",
+            "-s", resolution,
+            "-r", framerate,
             "-i", "-",
             "-i", "-",
-            "-c:v", "libx264",
 
 
+            "-c:v", "libx264",
+            "-vb", "2500k",
+            "-c:a", "aac",
+            "-ab", "200k",
+            "-pix_fmt", "yuv420p",
             "output.mp4",
             "output.mp4",
-            // ...
+
             NULL
             NULL
         );
         );
         if (ret < 0) {
         if (ret < 0) {
             fprintf(stderr, "ERROR: could not run ffmpeg as a child process: %s\n", strerror(errno));
             fprintf(stderr, "ERROR: could not run ffmpeg as a child process: %s\n", strerror(errno));
-            return 1;
+            return -1;
         }
         }
         assert(0 && "unreachable");
         assert(0 && "unreachable");
     }
     }
 
 
     close(pipefd[READ_END]);
     close(pipefd[READ_END]);
 
 
-    Olivec_Canvas oc = olivec_canvas(pixels, WIDTH, HEIGHT, WIDTH);
-
-    size_t duration = 10;
-    float x = WIDTH/2;
-    float y = HEIGHT/2;
-    float r = HEIGHT/8;
-    float dx = 200;
-    float dy = 200;
-    float dt = 1.0f/FPS;
-    for (size_t i = 0; i < FPS*duration; ++i) {
-        float nx = x + dx*dt;
-        if (0 < nx - r && nx + r < WIDTH) {
-            x = nx;
-        } else {
-            dx = -dx;
-        }
-
-        float ny = y + dy*dt;
-        if (0 < ny - r && ny + r < HEIGHT) {
-            y = ny;
-        } else {
-            dy = -dy;
-        }
-
-        olivec_fill(oc, 0xFF181818);
-        olivec_circle(oc, x, y, r, 0xFF0000FF);
-        write(pipefd[WRITE_END], pixels, sizeof(*pixels)*WIDTH*HEIGHT);
-    }
-
-    close(pipefd[WRITE_END]);
+    return pipefd[WRITE_END];
+}
 
 
+void ffmpeg_end_rendering(int pipe)
+{
+    close(pipe);
     wait(NULL);
     wait(NULL);
+}
 
 
-    printf("Done rendering the video!\n");
+void ffmpeg_send_frame(int pipe, void *data, size_t width, size_t height)
+{
+    write(pipe, data, sizeof(uint32_t)*width*height);
+}
 
 
-    return 0;
+void ffmpeg_send_frame_flipped(int pipe, void *data, size_t width, size_t height)
+{
+    for (size_t y = height; y > 0; --y) {
+        write(pipe, (uint32_t*)data + (y - 1)*width, sizeof(uint32_t)*width);
+    }
 }
 }

+ 60 - 0
main_raw.c

@@ -0,0 +1,60 @@
+#include <assert.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#define OLIVEC_IMPLEMENTATION
+#include "olive.c"
+
+#include "ffmpeg.h"
+
+#define WIDTH 800
+#define HEIGHT 600
+#define FPS 30
+#define DURATION 10
+
+uint32_t pixels[WIDTH*HEIGHT];
+
+int main(void)
+{
+    int ffmpeg = ffmpeg_start_rendering(WIDTH, HEIGHT, FPS);
+
+    Olivec_Canvas oc = olivec_canvas(pixels, WIDTH, HEIGHT, WIDTH);
+
+    float x = WIDTH/2;
+    float y = HEIGHT/2;
+    float r = HEIGHT/8;
+    float dx = 200;
+    float dy = 200;
+    float dt = 1.0f/FPS;
+    for (size_t i = 0; i < FPS*DURATION; ++i) {
+        float nx = x + dx*dt;
+        if (0 < nx - r && nx + r < WIDTH) {
+            x = nx;
+        } else {
+            dx = -dx;
+        }
+
+        float ny = y + dy*dt;
+        if (0 < ny - r && ny + r < HEIGHT) {
+            y = ny;
+        } else {
+            dy = -dy;
+        }
+
+        olivec_fill(oc, 0xFF181818);
+        olivec_circle(oc, x, y, r, 0xFF0000FF);
+        ffmpeg_send_frame(ffmpeg, pixels, WIDTH, HEIGHT);
+    }
+
+    ffmpeg_end_rendering(ffmpeg);
+
+    printf("Done rendering the video!\n");
+
+    return 0;
+}