From f4c5e7ec6d32be8a8a5326b2b8a42ec3991a0bf8 Mon Sep 17 00:00:00 2001 From: Rui Pires Date: Sun, 18 Jun 2023 13:37:51 +0100 Subject: [PATCH] Update --- .gitmodules | 3 +++ CCLArgs | 1 + Makefile | 11 ++++++++++ a.mp4 | Bin 0 -> 10295 bytes buildnrun.sh | 7 ++++++ src/canvas.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/canvas.h | 37 +++++++++++++++++++++++++++++++ src/defs.h | 23 ++++++++++++++++++++ src/err.h | 14 ++++++++++++ src/ffmpeg.c | 51 +++++++++++++++++++++++++++++++++++++++++++ src/ffmpeg.h | 8 +++++++ src/main.c | 46 +++++++++++++++++++++++++++++++++++++++ src/wav.c | 47 ++++++++++++++++++++++++++++++++++++++++ src/wav.h | 31 ++++++++++++++++++++++++++ 14 files changed, 339 insertions(+) create mode 100644 .gitmodules create mode 160000 CCLArgs create mode 100644 Makefile create mode 100644 a.mp4 create mode 100755 buildnrun.sh create mode 100644 src/canvas.c create mode 100644 src/canvas.h create mode 100644 src/defs.h create mode 100644 src/err.h create mode 100644 src/ffmpeg.c create mode 100644 src/ffmpeg.h create mode 100644 src/main.c create mode 100644 src/wav.c create mode 100644 src/wav.h diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..bc2c252 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "CCLArgs"] + path = CCLArgs + url = https://github.com/RuiDGPires/CCLArgs diff --git a/CCLArgs b/CCLArgs new file mode 160000 index 0000000..d08b78c --- /dev/null +++ b/CCLArgs @@ -0,0 +1 @@ +Subproject commit d08b78c0d91e9d4d1b2326251c82e734cc75d85e diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..51e95d8 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +C_FILES := $(wildcard src/*.c) +H_FILES := $(wildcard src/*.h) $(wildcard src/include/*.h) +TARGET := vis +CC := gcc + +$(TARGET): $(C_FILES) $(H_FILES) + gcc $(C_FILES) -o $@ + +.PHONY: clean +clean: + rm $(TARGET) diff --git a/a.mp4 b/a.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..b78bd34f9a314af48bf999553696deb2dd477fd9 GIT binary patch literal 10295 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 jpjOr8 literal 0 HcmV?d00001 diff --git a/buildnrun.sh b/buildnrun.sh new file mode 100755 index 0000000..7641aa7 --- /dev/null +++ b/buildnrun.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +VIDEO_FILE=output.mp4 + +make +./vis ${VIDEO_FILE} +vlc ${VIDEO_FILE} >/dev/null 2>&1 diff --git a/src/canvas.c b/src/canvas.c new file mode 100644 index 0000000..cd20139 --- /dev/null +++ b/src/canvas.c @@ -0,0 +1,60 @@ +#include +#include +#include "canvas.h" +#include "err.h" + +u32 point_dist_sqrd(point_t p1, point_t p2) { + i32 dx = (i32) (p1.x - p2.x), dy = (i32) (p1.y - p2.y); + return dx*dx + dy*dy; +} + +canvas_t *canvas_create(u32 width, u32 height) { + u32 *buffer = (u32*) malloc(sizeof(u32) * width * height); + canvas_t *canvas = canvas_from_buffer(buffer, width, height); + canvas->is_static = FALSE; + return canvas; +} + +canvas_t *canvas_from_buffer(u32 *buffer, u32 width, u32 height) { + canvas_t *canvas = (canvas_t *) malloc(sizeof(canvas_t)); + canvas->width = width; + canvas->height = height; + canvas->buffer = buffer; + canvas->is_static = TRUE; + return canvas; +} + +void canvas_destroy(canvas_t **canvas) { + if ((*canvas)->is_static == FALSE) + free((*canvas)->buffer); + + free(*canvas); + *canvas = NULL; +} + +void canvas_fill(canvas_t *canvas, color_t color) { + for (usize i = 0; i < canvas->width * canvas->height; i++) { + canvas->buffer[i] = color; + } +} + +void canvas_dump(canvas_t *canvas, int fd) { + write(fd, canvas->buffer, sizeof(color_t)*canvas->width*canvas->height); +} + +void canvas_draw_point(canvas_t *canvas, point_t point, color_t color) { + canvas->buffer[point.x + point.y*canvas->width] = color; +} + +void canvas_draw_circle(canvas_t *canvas, point_t center, u32 radius, color_t color) { + ERR_ASSERT(center.x - radius >= 0 && center.x + radius < canvas->width && center.y - radius >= 0 && center.y + radius < canvas->height, "Invalid circle"); + for (u32 x = center.x - radius; x < center.x + radius; x++){ + for (u32 y = center.y - radius; y < center.y + radius; y++){ + point_t p = (point_t) {.x = x, .y = y}; + + if (point_dist_sqrd(p, center) <= radius*radius) { + canvas_draw_point(canvas, p, color); + } + } + } +} diff --git a/src/canvas.h b/src/canvas.h new file mode 100644 index 0000000..1d0f6c0 --- /dev/null +++ b/src/canvas.h @@ -0,0 +1,37 @@ +#ifndef __CANVAS_H__ +#define __CANVAS_H__ + +#include "defs.h" + +typedef u32 color_t; + +#define RGBA(r, g, b, a) ((((r)&0xFF)<<(8*0)) | (((g)&0xFF)<<(8*1)) | (((b)&0xFF)<<(8*2)) | (((a)&0xFF)<<(8*3))) + +#define COLOR_RED RGBA(0xFF, 0x00, 0x00, 0xFF) +#define COLOR_GREEN RGBA(0x00, 0xFF, 0x00, 0xFF) +#define COLOR_BLUE RGBA(0x00, 0x00, 0xFF, 0xFF) +#define COLOR_BLACK RGBA(0x00, 0x00, 0x00, 0xFF) +#define COLOR_WHITE RGBA(0xFF, 0xFF, 0xFF, 0xFF) + +typedef struct { + u32 width, height; + color_t *buffer; + u8 is_static; +} canvas_t; + +typedef struct { + usize x, y; +} point_t; + +u32 point_dist_sqrd(point_t, point_t); + +canvas_t *canvas_create(u32, u32); +canvas_t *canvas_from_buffer(u32 *, u32, u32); +void canvas_destroy(canvas_t **); + +void canvas_fill(canvas_t *, color_t); +void canvas_dump(canvas_t *, int); +void canvas_draw_point(canvas_t *, point_t, color_t); +void canvas_draw_circle(canvas_t *, point_t, u32, color_t); + +#endif diff --git a/src/defs.h b/src/defs.h new file mode 100644 index 0000000..08e4ca4 --- /dev/null +++ b/src/defs.h @@ -0,0 +1,23 @@ +#ifndef __DEFS_H__ +#define __DEFS_H__ + +#include +#include + +#define TRUE 1 +#define FALSE 0 + +#define STR2(v) #v +#define STR(v) STR2(v) + +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; + +typedef int32_t i32; +typedef int16_t i16; +typedef int8_t i8; + +typedef size_t usize; + +#endif diff --git a/src/err.h b/src/err.h new file mode 100644 index 0000000..f5972ef --- /dev/null +++ b/src/err.h @@ -0,0 +1,14 @@ +#ifndef __ERR_H__ +#define __ERR_H__ + +#include +#include +#include +#include + +#define ERR(...) {fprintf(stderr, "ERR: " __VA_ARGS__); fprintf(stderr, "\n"); exit(1);} + +#define ERR_ASSERT(cond, ...) {if (!(cond)) ERR(__VA_ARGS__)} +#define ERR_ASSERT_CLN(cond, cln, ...) {if (!(cond)) {{cln;} ERR(__VA_ARGS__)}} + +#endif diff --git a/src/ffmpeg.c b/src/ffmpeg.c new file mode 100644 index 0000000..eae681a --- /dev/null +++ b/src/ffmpeg.c @@ -0,0 +1,51 @@ +#include +#include +#include "ffmpeg.h" +#include "err.h" + +#define PIPE_READ 0 +#define PIPE_WRITE 1 + +#define MAX_CHARS_DIM 100 +#define MAX_CHARS_FPS 4 + +int open_ffmpeg(const char *filename, u32 width, u32 height, u32 fps) { + int pipefd[2]; + ERR_ASSERT(pipe(pipefd) >= 0, "Unable to open pipe"); + + int child = fork(); + + char dims_s[MAX_CHARS_DIM]; + char fps_s[MAX_CHARS_FPS]; + snprintf(dims_s, MAX_CHARS_DIM, "%ux%u", width, height); + snprintf(fps_s, MAX_CHARS_FPS, "%u", fps); + + ERR_ASSERT(child >= 0, "Unable to fork"); + + if (child == 0) { + ERR_ASSERT(dup2(pipefd[PIPE_READ], STDIN_FILENO) >= 0, "Unable to reopen read pipe as stdin"); + close(pipefd[PIPE_WRITE]); + + ERR_ASSERT(execlp("ffmpeg", + "ffmpeg", + "-loglevel", "verbose", + "-y", + "-f", "rawvideo", + "-pix_fmt", "rgba", + "-s", dims_s, + "-r", fps_s, + "-an", + "-i", "-", + "-c:v", "libx264", + + filename, + // ... + NULL + ) >= 0, "Unable to open FFMPEG: %s", strerror(errno)); + assert(0 && "Unreachable"); + } + + close(pipefd[PIPE_READ]); + return pipefd[PIPE_WRITE]; +} + diff --git a/src/ffmpeg.h b/src/ffmpeg.h new file mode 100644 index 0000000..5c848ca --- /dev/null +++ b/src/ffmpeg.h @@ -0,0 +1,8 @@ +#ifndef __FFMPEG_H__ +#define __FFMPEG_H__ + +#include "defs.h" + +int open_ffmpeg(const char *, u32 width, u32 height, u32 fps); + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..888164d --- /dev/null +++ b/src/main.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include "../CCLArgs/cclargs.h" +#include "ffmpeg.h" +#include "defs.h" +#include "err.h" +#include "wav.h" +#include "canvas.h" + +#define WIDTH 600 +#define HEIGHT 400 +#define FPS 30 +#define DURATION 5 + +#define MAX_FILENAME 100 + +#define USAGE "vis " +#define DEFAULT_NAME "a.mp4" + +int main(ARGS) { + char *output_file = DEFAULT_NAME; + + BEGIN_PARSE_ARGS("") + ARG_STRING(output_file, "-o") + END_PARSE_ARGS + + color_t pixels[WIDTH*HEIGHT]; + canvas_t *canvas = canvas_from_buffer(pixels, WIDTH, HEIGHT); + + int outfd = open_ffmpeg(output_file, WIDTH, HEIGHT, FPS); + + canvas_fill(canvas, COLOR_BLUE); + canvas_draw_circle(canvas, (point_t){.x = WIDTH/2, .y = HEIGHT/2}, HEIGHT/3, COLOR_RED); + + for (usize i = 0; i < FPS * DURATION; i++) { + canvas_dump(canvas, outfd); + } + + close(outfd); + canvas_destroy(&canvas); + wait(NULL); + printf("Operation completed\n"); + return 0; +} diff --git a/src/wav.c b/src/wav.c new file mode 100644 index 0000000..fa00b44 --- /dev/null +++ b/src/wav.c @@ -0,0 +1,47 @@ +#include + +#include "wav.h" +#include "err.h" + +#define BUFFER_SIZE 4096 + +// Function to read audio file and retrieve its contents +wav_t *wav_from_file(const char* filename) { + FILE* file = fopen(filename, "rb"); + ERR_ASSERT(file != NULL, "Failed to open file"); + + wav_t *wav = (wav_t *) malloc(sizeof(wav_t)); + wav_header_t header; + + // Read the WAV file header + size_t headerSize = fread(&header, 1, sizeof(wav_header_t), file); + + ERR_ASSERT_CLN(headerSize == sizeof(wav_header_t), fclose(file), "Invalid WAV File"); + + // Check if the file format is valid + ERR_ASSERT_CLN(header.chunkID[0] == 'R' && header.chunkID[1] == 'I' && header.chunkID[2] == 'F' && header.chunkID[3] == 'F' && header.format[0] == 'W' && header.format[1] == 'A' && header.format[2] == 'V' && header.format[3] == 'E', + fclose(file), "Invalid WAV file format"); + + // Allocate memory to store audio data + u32 dataSize = header.subchunk2Size; + + wav->header = header; + u8* buffer = (uint8_t*)malloc(sizeof(u8) * dataSize); + + ERR_ASSERT_CLN(buffer != NULL, fclose(file), "Failed to allocate memory"); + wav->buffer = buffer; + + // Read the audio data into the buffer + usize bytesRead = fread(buffer, 1, dataSize, file); + fclose(file); + + ERR_ASSERT_CLN(bytesRead == dataSize, free(buffer), "Error occurred while reading the audio data") + + return wav; +} + +void destroy_wav(wav_t **wav) { + free((*wav)->buffer); + free(*wav); + *wav = NULL; +} diff --git a/src/wav.h b/src/wav.h new file mode 100644 index 0000000..40c56e0 --- /dev/null +++ b/src/wav.h @@ -0,0 +1,31 @@ +#ifndef __WAV_H__ +#define __WAV_H__ + +#include "defs.h" + +// WAV file header structure +typedef struct { + char chunkID[4]; + u32 chunkSize; + char format[4]; + char subchunk1ID[4]; + u32 subchunk1Size; + u16 audioFormat; + u16 numChannels; + u32 sampleRate; + u32 byteRate; + u16 blockAlign; + u16 bitsPerSample; + char subchunk2ID[4]; + u32 subchunk2Size; +} wav_header_t; + +typedef struct { + wav_header_t header; + u8 *buffer; +} wav_t; + +wav_t *wav_from_file(const char *); +void wav_destroy(wav_t **); + +#endif