summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2025-02-20 16:03:05 -0700
committerLuke T. Shumaker <lukeshu@lukeshu.com>2025-02-20 16:03:05 -0700
commitf5ad1399aec565f9562cee9df21f24124a85c9e0 (patch)
treea0c06bb92537eb61c7ff222afa0ed78c25b705d1
parent690f6f81582dc5304f0e49dab55c68eceba460b0 (diff)
wip
-rw-r--r--libmkv/.gitignore13
-rw-r--r--libmkv/Makefile1
-rwxr-xr-xlibmkv/changing-resolution-gif.sh19
l---------libmkv/common.c1
-rw-r--r--libmkv/common.h113
-rw-r--r--libmkv/nut-generate.c92
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;
}