diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-02-20 16:03:05 -0700 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-02-20 16:03:05 -0700 |
commit | f5ad1399aec565f9562cee9df21f24124a85c9e0 (patch) | |
tree | a0c06bb92537eb61c7ff222afa0ed78c25b705d1 | |
parent | 690f6f81582dc5304f0e49dab55c68eceba460b0 (diff) |
wip
-rw-r--r-- | libmkv/.gitignore | 13 | ||||
-rw-r--r-- | libmkv/Makefile | 1 | ||||
-rwxr-xr-x | libmkv/changing-resolution-gif.sh | 19 | ||||
l--------- | libmkv/common.c | 1 | ||||
-rw-r--r-- | libmkv/common.h | 113 | ||||
-rw-r--r-- | libmkv/nut-generate.c | 92 |
6 files changed, 168 insertions, 71 deletions
diff --git a/libmkv/.gitignore b/libmkv/.gitignore index e64455c..b5a1b08 100644 --- a/libmkv/.gitignore +++ b/libmkv/.gitignore @@ -1,10 +1,9 @@ /nut-crc32 - /nut-generate -/nut-generate.nut - -/changing-resolution-cam.webm -/changing-resolution-cam.nut -/changing-resolution-gen.* -!/changing-resolution-gen.sh +*.webm +*.nut +*.gif +*.ogv +*.mkv +*.concat.txt diff --git a/libmkv/Makefile b/libmkv/Makefile index a772f09..a0d678d 100644 --- a/libmkv/Makefile +++ b/libmkv/Makefile @@ -13,6 +13,7 @@ all: nut-crc32 ################################################################################ all: nut-generate.nut +nut-generate: common.h nut-generate.nut: %.nut: % ./$< >$@ diff --git a/libmkv/changing-resolution-gif.sh b/libmkv/changing-resolution-gif.sh new file mode 100755 index 0000000..dff17a9 --- /dev/null +++ b/libmkv/changing-resolution-gif.sh @@ -0,0 +1,19 @@ +name=${0##*/} +name=${name%.sh} + +rm -f -- "${name}.part1.gif" "${name}.part2.gif" "${name}.concat.txt" "${name}.gif" + +# Create a 320x240 clip +ffmpeg -f lavfi -t 2 -i testsrc=r=30:s=320x240 "${name}.part1.gif" + +# Create a 640x480 clip +ffmpeg -f lavfi -t 2 -i testsrc=r=30:s=640x480 "${name}.part2.gif" + +# Create a text file with the list of files +{ + echo "file '${name}.part1.gif'" + echo "file '${name}.part2.gif'" +} > "${name}.concat.txt" + +# Concatenate the clips +ffmpeg -f concat -safe 0 -i "${name}.concat.txt" -c:v copy "${name}.nut" diff --git a/libmkv/common.c b/libmkv/common.c new file mode 120000 index 0000000..51e1965 --- /dev/null +++ b/libmkv/common.c @@ -0,0 +1 @@ +common.h
\ No newline at end of file diff --git a/libmkv/common.h b/libmkv/common.h new file mode 100644 index 0000000..996eca6 --- /dev/null +++ b/libmkv/common.h @@ -0,0 +1,113 @@ +#include <assert.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> /* for perror() */ +#include <string.h> /* for memcpy() */ +#include <stdlib.h> /* for realloc(), free() */ +#include <unistd.h> /* for write() */ + +#define LM_ARRAY_LEN(ary) (sizeof(ary)/sizeof((ary)[0])) +#define LM_CEILDIV(n, d) ( ((n)+(d)-1) / (d) ) +#define LM_NEXT_POWER_OF_2(x) ( (x) ? 1ULL<<((sizeof(unsigned long long)*8)-__builtin_clzll(x)) : 1) +#define LM_CAT2(a, b) a ## b +#define LM_CAT2_(a, b) LM_CAT2(a, b) +#define assert_notreached(msg) assert(false) + +struct buf { + uint8_t *dat; + size_t len; + size_t cap; +}; + +static void append(struct buf *buf, void *dat, size_t len) { + assert(buf); + assert(len == 0 || dat); + + if (buf->len + len > buf->cap) { + buf->cap = LM_NEXT_POWER_OF_2(buf->len + len); + buf->dat = realloc(buf->dat, buf->cap); + assert(buf->dat); + } + memcpy(&buf->dat[buf->len], dat, len); + buf->len += len; +} + +static void append_u32be(struct buf *buf, uint32_t val) { + assert(buf); + + uint8_t dat[4] = { + (val>>(8*3))&0xFF, + (val>>(8*2))&0xFF, + (val>>(8*1))&0xFF, + (val>>(8*0))&0xFF, + }; + append(buf, dat, sizeof(dat)); +} + +static bool xwrite(int fd, uint8_t *dat, size_t len) { + assert(len == 0 || dat); + + for (size_t done = 0; done < len;) { + ssize_t n = write(fd, &dat[done], len-done); + if (n < 0) { + perror("write"); + return true; + } + done += n; + } + return false; +} + +static char font[10][8*4] = { + " ## " + " # # " + " # # " + " ## ", + + " # " + " ## " + " # " + " ### ", + + " ## " + " # # " + " # " + " #### ", + + " ## " + " # " + " # " + " ## ", + + " ## " + " # # " + " #### " + " # ", + + " #### " + " ### " + " # " + " ### ", + + " # " + " ### " + " # # " + " ## ", + + " #### " + " # " + " # " + " # ", + + " ## " + " # # " + " #### " + " ## ", + + " ## " + " # # " + " ### " + " # ", +}; +static_assert(LM_ARRAY_LEN(font) == 10); +static_assert(sizeof(font[0]) == 32); diff --git a/libmkv/nut-generate.c b/libmkv/nut-generate.c index c52d8c1..02f9a3d 100644 --- a/libmkv/nut-generate.c +++ b/libmkv/nut-generate.c @@ -21,60 +21,11 @@ #include <stdlib.h> /* for realloc(), free() */ #include <string.h> /* for memcpy(), memset() */ #include <unistd.h> /* for write() */ +#include <fcntl.h> /* for open() */ /* Generic ********************************************************************/ -#define LM_ARRAY_LEN(ary) (sizeof(ary)/sizeof((ary)[0])) -#define LM_CEILDIV(n, d) ( ((n)+(d)-1) / (d) ) -#define LM_NEXT_POWER_OF_2(x) ( (x) ? 1ULL<<((sizeof(unsigned long long)*8)-__builtin_clzll(x)) : 1) -#define LM_CAT2(a, b) a ## b -#define LM_CAT2_(a, b) LM_CAT2(a, b) -#define assert_notreached(msg) assert(false) - -struct buf { - uint8_t *dat; - size_t len; - size_t cap; -}; - -void append(struct buf *buf, void *dat, size_t len) { - assert(buf); - assert(len == 0 || dat); - - if (buf->len + len > buf->cap) { - buf->cap = LM_NEXT_POWER_OF_2(buf->len + len); - buf->dat = realloc(buf->dat, buf->cap); - assert(buf->dat); - } - memcpy(&buf->dat[buf->len], dat, len); - buf->len += len; -} - -void append_u32be(struct buf *buf, uint32_t val) { - assert(buf); - - uint8_t dat[4] = { - (val>>(8*3))&0xFF, - (val>>(8*2))&0xFF, - (val>>(8*1))&0xFF, - (val>>(8*0))&0xFF, - }; - append(buf, dat, sizeof(dat)); -} - -bool xwrite(int fd, uint8_t *dat, size_t len) { - assert(len == 0 || dat); - - for (size_t done = 0; done < len;) { - ssize_t n = write(fd, &dat[done], len-done); - if (n < 0) { - perror("write"); - return true; - } - done += n; - } - return false; -} +#include "common.h" /* NUT ************************************************************************/ @@ -259,9 +210,11 @@ size_t app_res_fb_size(enum app_res res) { struct app_state { enum app_res res; + uint64_t len; + uint64_t last_syncpoint; }; -void app_append_intro(struct buf *out, uint64_t time_ns, enum app_res res) { +void app_append_intro(struct buf *out, enum app_res res) { struct buf pkt = {0}; unsigned int frame_code = 0; #define INC_FRAME_CODE() do { frame_code++; if (frame_code == 'N') frame_code++; } while(0) @@ -273,8 +226,7 @@ void app_append_intro(struct buf *out, uint64_t time_ns, enum app_res res) { pkt.len = 0; /* head *******************************************/ - nut_append_vu(&pkt, 4); /*! version */ - nut_append_vu(&pkt, 0); /*! minor_version */ + nut_append_vu(&pkt, 3); /*! version */ nut_append_vu(&pkt, 1); /*! stream_count */ nut_append_vu(&pkt, /*! max_distance */ APP_FRAME_MAX_HEADER + @@ -322,7 +274,6 @@ void app_append_intro(struct buf *out, uint64_t time_ns, enum app_res res) { /* tail *******************************************/ nut_append_vu(&pkt, 0); /*! header_count_minus_1 */ - nut_append_vu(&pkt, NUT_MAINFLAG_PIPE_MODE); /*! main_flags */ nut_append_packet(out, nut_startcode_main, pkt.dat, pkt.len); @@ -346,14 +297,6 @@ void app_append_intro(struct buf *out, uint64_t time_ns, enum app_res res) { nut_append_packet(out, nut_startcode_stream, pkt.dat, pkt.len); - /* syncpoint **********************************************************/ - pkt.len = 0; - - nut_append_vu(&pkt, time_ns); /*! global_key_pts */ - nut_append_vu(&pkt, 0); /*! back_ptr_div16 */ - - nut_append_packet(out, nut_startcode_syncpoint, pkt.dat, pkt.len); - /* flush **************************************************************/ #undef BOGUS @@ -368,10 +311,21 @@ bool app_write_frame(int fd, struct app_state *state, uint64_t time_ns, enum app struct buf pkt = {0}; if (res != state->res) { - app_append_intro(&out, time_ns, res); + app_append_intro(&out, res); state->res = res; } + /* syncpoint packet ***************************************************/ + pkt.len = 0; + uint64_t syncpoint_beg = state->len + out.len; + + nut_append_vu(&pkt, time_ns); /*! global_key_pts */ + nut_append_vu(&pkt, state->last_syncpoint /*! back_ptr_div16 */ + ? (syncpoint_beg - state->last_syncpoint)/16 + : 0); + + nut_append_packet(&out, nut_startcode_syncpoint, pkt.dat, pkt.len); + /* frame header ( 1+10+1+4 = 16 bytes) */ uint64_t frame_beg = out.len; nut_append_u8(&out, 1); /*! frame_code (1 byte) */ @@ -393,6 +347,8 @@ bool app_write_frame(int fd, struct app_state *state, uint64_t time_ns, enum app /* return */ state->res = res; + state->len += out.len + app_res_fb_size(res); + state->last_syncpoint = syncpoint_beg; return false; } @@ -466,6 +422,14 @@ int main() { for (int y = 0; y < 4*SCALE; y++) for (int x = 0; x < 8*SCALE; x++) framebuffer[(y*app_res_w(res))+x] = font[i][((y/SCALE)*8)+(x/SCALE)] == ' ' ? 0b11000000 : 0b00000011; + if (i%2 == 0) { + char name[] = {'o', 'u', 't', '-', '0'+(i/2), '.', 'n', 'u', 't', '\0'}; + int fd = open(name, O_WRONLY|O_TRUNC|O_CREAT, 0666); + dup2(fd, 1); + close(fd); + state.len = 0; + state.last_syncpoint = 0; + } if (app_write_frame(1, &state, ((uint64_t)i)*1000000000ULL, res, framebuffer)) return 1; } |