summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libmkv/nut-3.c172
1 files changed, 100 insertions, 72 deletions
diff --git a/libmkv/nut-3.c b/libmkv/nut-3.c
index cc40929..f946c0d 100644
--- a/libmkv/nut-3.c
+++ b/libmkv/nut-3.c
@@ -27,6 +27,8 @@
#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)
struct buf {
uint8_t *dat;
@@ -34,7 +36,7 @@ struct buf {
size_t cap;
};
-void append(struct buf *buf, uint8_t *dat, size_t len) {
+void append(struct buf *buf, void *dat, size_t len) {
assert(buf);
assert(len == 0 || dat);
@@ -165,7 +167,7 @@ void nut_append_vs(struct buf *buf, int64_t val) {
nut_append_vu(buf, temp);
}
-void nut_append_vb(struct buf *buf, uint8_t *dat, size_t len) {
+void nut_append_vb(struct buf *buf, void *dat, size_t len) {
assert(buf);
assert(len == 0 || dat);
@@ -199,7 +201,7 @@ uint32_t nut_crc32(uint8_t *dat, int len){
return crc;
}
-void nut_append_packet(struct buf *buf, uint8_t *startcode, uint8_t *data, size_t len) {
+void nut_append_packet(struct buf *buf, uint8_t *startcode, void *data, size_t len) {
assert(buf);
assert(startcode);
assert(len == 0 || data);
@@ -228,6 +230,28 @@ struct app_state {
uint64_t last_syncpoint;
};
+#define APP_COMMON_FLAGS NUT_FRAMEFLAG_KEY|NUT_FRAMEFLAG_SIZE_MSB|NUT_FRAMEFLAG_CHECKSUM|NUT_FRAMEFLAG_SM_DATA
+
+#define APP_SIZE_MSB_MUL 0x2000 /* must be less than 0x4000 */
+
+#define _APP_ELIDE_640_480 19
+#define _APP_ELIDE_720_480 19
+#define _APP_ELIDE_720_576 19
+#define _APP_W_640_480 640
+#define _APP_W_720_480 720
+#define _APP_W_720_576 720
+#define _APP_H_640_480 480
+#define _APP_H_720_480 480
+#define _APP_H_720_576 576
+
+#define APP_ELIDE(res) LM_CAT2_(_APP_ELIDE_, res)
+#define APP_W(res) LM_CAT2_(_APP_W_, res)
+#define APP_H(res) LM_CAT2_(_APP_H_, res)
+#define APP_FB(res) (APP_W(res)*APP_H(res)/2)
+#define APP_SIZE(res) (APP_ELIDE(res)+APP_FB(res))
+/* HERE */
+#define APP_FRAME_MAX_OVERHEAD 31
+
bool app_write_intro(int fd, struct app_state *state, uint64_t time_ns) {
assert(state);
@@ -239,11 +263,12 @@ bool app_write_intro(int fd, struct app_state *state, uint64_t time_ns) {
/* main_header ********************************************************/
#define BOGUS 0
+ pkt.len = 0;
nut_append_vu(&pkt, 3); /*! version */
nut_append_vu(&pkt, 1); /*! stream_count */
- nut_append_vu(&pkt, (720*(576/2)) + 256/*TODO*/); /*! max_distance */
-
+ nut_append_vu(&pkt, APP_FB(720_576) + /*! max_distance */
+ APP_FRAME_MAX_OVERHEAD);
/* time bases *************************************/
nut_append_vu(&pkt, 1); /*! time_base_count */
@@ -253,57 +278,57 @@ bool app_write_intro(int fd, struct app_state *state, uint64_t time_ns) {
/* frame codes ************************************/
/* "A muxer SHOULD mark [frame codes] 0x00 and 0xFF as invalid" */
-#define SIZE_MSB_MUL 0x2000 /* must be less than 0x4000 */
-#define COMMON_FLAGS NUT_FRAMEFLAG_KEY|NUT_FRAMEFLAG_SIZE_MSB|NUT_FRAMEFLAG_CHECKSUM|NUT_FRAMEFLAG_SM_DATA
/* frame_code=0 (invalid) */
- nut_append_vu(&pkt, NUT_FRAMEFLAG_INVALID); /*! flags */
- nut_append_vu(&pkt, 2); /*! field_count */
- nut_append_vu(&pkt, BOGUS); /*! 0: fields.pts */
- nut_append_vu(&pkt, 1); /*! 1: fields.size_msb_nul */
+ nut_append_vu(&pkt, NUT_FRAMEFLAG_INVALID); /*! flags */
+ nut_append_vu(&pkt, 2); /*! field_count */
+ nut_append_vu(&pkt, BOGUS); /*! 0: fields.pts */
+ nut_append_vu(&pkt, 1); /*! 1: fields.size_msb_nul */
/* frame_code=1 (640x480) */
- nut_append_vu(&pkt, COMMON_FLAGS); /*! flags */
- nut_append_vu(&pkt, 8); /*! field_count */
- nut_append_vu(&pkt, BOGUS); /*! 0: fields.pts */
- nut_append_vu(&pkt, SIZE_MSB_MUL); /*! 1: fields.size_msb_nul */
- nut_append_vu(&pkt, 0); /*! 2: fields.stream */
- nut_append_vu(&pkt, (640*(480/2))%SIZE_MSB_MUL); /*! 3: fields.size_lsb */
- nut_append_vu(&pkt, 0); /*! 4: fields.reserved */
- nut_append_vu(&pkt, 1); /*! 5: fields.count */
- nut_append_vs(&pkt, NUT_UNKNOWN_MATCH_TIME); /*! 6: fields.match */
- nut_append_vu(&pkt, 1); /*! 7: fields.elision_header */
+ nut_append_vu(&pkt, APP_COMMON_FLAGS); /*! flags */
+ nut_append_vu(&pkt, 8); /*! field_count */
+ nut_append_vu(&pkt, BOGUS); /*! 0: fields.pts */
+ nut_append_vu(&pkt, APP_SIZE_MSB_MUL); /*! 1: fields.size_msb_nul */
+ nut_append_vu(&pkt, 0); /*! 2: fields.stream */
+ nut_append_vu(&pkt, APP_SIZE(640_480) % /*! 3: fields.size_lsb */
+ APP_SIZE_MSB_MUL);
+ nut_append_vu(&pkt, 0); /*! 4: fields.reserved */
+ nut_append_vu(&pkt, 1); /*! 5: fields.count */
+ nut_append_vs(&pkt, NUT_UNKNOWN_MATCH_TIME); /*! 6: fields.match */
+ nut_append_vu(&pkt, 1); /*! 7: fields.elision_header */
/* frame_code=2 (720x480) */
- nut_append_vu(&pkt, COMMON_FLAGS); /*! flags */
- nut_append_vu(&pkt, 8); /*! field_count */
- nut_append_vu(&pkt, BOGUS); /*! 0: fields.pts */
- nut_append_vu(&pkt, SIZE_MSB_MUL); /*! 1: fields.size_msb_mul */
- nut_append_vu(&pkt, 0); /*! 2: fields.stream */
- nut_append_vu(&pkt, (720*(480/2))%SIZE_MSB_MUL); /*! 3: fields.size_lsb */
- nut_append_vu(&pkt, 0); /*! 4: fields.reserved */
- nut_append_vu(&pkt, 1); /*! 5: fields.count */
- nut_append_vs(&pkt, NUT_UNKNOWN_MATCH_TIME); /*! 6: fields.match */
- nut_append_vu(&pkt, 2); /*! 7: fields.elision_header */
+ nut_append_vu(&pkt, APP_COMMON_FLAGS); /*! flags */
+ nut_append_vu(&pkt, 8); /*! field_count */
+ nut_append_vu(&pkt, BOGUS); /*! 0: fields.pts */
+ nut_append_vu(&pkt, APP_SIZE_MSB_MUL); /*! 1: fields.size_msb_mul */
+ nut_append_vu(&pkt, 0); /*! 2: fields.stream */
+ nut_append_vu(&pkt, APP_SIZE(720_480) % /*! 3: fields.size_lsb */
+ APP_SIZE_MSB_MUL);
+ nut_append_vu(&pkt, 0); /*! 4: fields.reserved */
+ nut_append_vu(&pkt, 1); /*! 5: fields.count */
+ nut_append_vs(&pkt, NUT_UNKNOWN_MATCH_TIME); /*! 6: fields.match */
+ nut_append_vu(&pkt, 2); /*! 7: fields.elision_header */
/* frame_code=3 (720x576) */
- nut_append_vu(&pkt, COMMON_FLAGS); /*! flags */
- nut_append_vu(&pkt, 8); /*! field_count */
- nut_append_vu(&pkt, BOGUS); /*! 0: fields.pts */
- nut_append_vu(&pkt, 0x2000); /*! 1: fields.size_msb_nul */
- nut_append_vu(&pkt, 0); /*! 2: fields.stream */
- nut_append_vu(&pkt, (720*(576/2))%SIZE_MSB_MUL); /*! 3: fields.size_lsb */
- nut_append_vu(&pkt, 0); /*! 4: fields.reserved */
- nut_append_vu(&pkt, 1); /*! 5: fields.count */
- nut_append_vs(&pkt, NUT_UNKNOWN_MATCH_TIME); /*! 6: fields.match */
- nut_append_vu(&pkt, 2); /*! 7: fields.elision_header */
+ nut_append_vu(&pkt, APP_COMMON_FLAGS); /*! flags */
+ nut_append_vu(&pkt, 8); /*! field_count */
+ nut_append_vu(&pkt, BOGUS); /*! 0: fields.pts */
+ nut_append_vu(&pkt, APP_SIZE_MSB_MUL); /*! 1: fields.size_msb_nul */
+ nut_append_vu(&pkt, 0); /*! 2: fields.stream */
+ nut_append_vu(&pkt, APP_SIZE(720_576) % /*! 3: fields.size_lsb */
+ APP_SIZE_MSB_MUL);
+ nut_append_vu(&pkt, 0); /*! 4: fields.reserved */
+ nut_append_vu(&pkt, 1); /*! 5: fields.count */
+ nut_append_vs(&pkt, NUT_UNKNOWN_MATCH_TIME); /*! 6: fields.match */
+ nut_append_vu(&pkt, 2); /*! 7: fields.elision_header */
/* frame_code=4-255 (invalid) */
- nut_append_vu(&pkt, NUT_FRAMEFLAG_INVALID); /*! flags */
- nut_append_vu(&pkt, 2); /*! field_count */
- nut_append_vu(&pkt, BOGUS); /*! 0: fields.pts */
- nut_append_vu(&pkt, 256-4-1); /*! 1: fields.size_msb_nul */
-#undef COMMON_FLAGS
+ nut_append_vu(&pkt, NUT_FRAMEFLAG_INVALID); /*! flags */
+ nut_append_vu(&pkt, 2); /*! field_count */
+ nut_append_vu(&pkt, BOGUS); /*! 0: fields.pts */
+ nut_append_vu(&pkt, 256-4-1); /*! 1: fields.size_msb_nul */
/* elision headers ********************************/
nut_append_vu(&pkt, 3); /*! header_count_minus_1 */
@@ -312,39 +337,42 @@ bool app_write_intro(int fd, struct app_state *state, uint64_t time_ns) {
hdr.len = 0;
nut_append_vu(&hdr, 2); /*! side_data_count */
nut_append_vb_str(&hdr, "Width"); /*! side_data[0].name */
- nut_append_vu(&hdr, 640); /*! side_data[0].value */
+ nut_append_vu(&hdr, APP_W(640_480)); /*! side_data[0].value */
nut_append_vb_str(&hdr, "Height"); /*! side_data[1].name */
- nut_append_vu(&hdr, 480/2); /*! side_data[1].value */
+ nut_append_vu(&hdr, APP_H(640_480)/2); /*! side_data[1].value */
nut_append_vu(&hdr, 0); /*! meta_data_count */
+ assert(hdr.len == APP_ELIDE(640_480));
nut_append_vb(&pkt, hdr.dat, hdr.len);
/* elision_header[2] (720x480) */
hdr.len = 0;
nut_append_vu(&hdr, 2); /*! side_data_count */
nut_append_vb_str(&hdr, "Width"); /*! side_data[0].name */
- nut_append_vu(&hdr, 720); /*! side_data[0].value */
+ nut_append_vu(&hdr, APP_W(720_480)); /*! side_data[0].value */
nut_append_vb_str(&hdr, "Height"); /*! side_data[1].name */
- nut_append_vu(&hdr, 480/2); /*! side_data[1].value */
+ nut_append_vu(&hdr, APP_H(720_480)/2); /*! side_data[1].value */
nut_append_vu(&hdr, 0); /*! meta_Data_count */
+ assert(hdr.len == APP_ELIDE(720_480));
nut_append_vb(&pkt, hdr.dat, hdr.len);
/* elision_header[3] (720x576) */
hdr.len = 0;
nut_append_vu(&hdr, 2); /*! side_data_count */
nut_append_vb_str(&hdr, "Width"); /*! side_data[0].name */
- nut_append_vu(&hdr, 720); /*! side_data[0].value */
+ nut_append_vu(&hdr, APP_H(720_576)); /*! side_data[0].value */
nut_append_vb_str(&hdr, "Height"); /*! side_data[1].name */
- nut_append_vu(&hdr, 576/2); /*! side_data[1].value */
+ nut_append_vu(&hdr, APP_H(720_576)/2); /*! side_data[1].value */
nut_append_vu(&hdr, 0); /*! meta_data_count */
+ assert(hdr.len == APP_ELIDE(720_576));
nut_append_vb(&pkt, hdr.dat, hdr.len);
nut_append_packet(&out, nut_startcode_main, pkt.dat, pkt.len);
#undef BOGUS
/* stream_header ******************************************************/
-
- pkt.len = 0;
#define BOGUS 1
+ pkt.len = 0;
+
nut_append_vu(&pkt, 0); /*! stream_id */
nut_append_vu(&pkt, NUT_STREAMCLASS_VIDEO); /*! stream_class */
nut_append_vb(&pkt, "BGR\x08", 4); /*! fourcc */
@@ -382,27 +410,27 @@ bool app_write_frame(int fd, struct app_state *state, uint64_t time_ns, enum app
struct buf pkt = {0};
uint64_t beg = state->len;
- size_t framebuffer_size;
+ size_t full_size, fb_size;
switch (res) {
- case APP_RES_640_480: framebuffer_size = 640*(480/2); break;
- case APP_RES_720_480: framebuffer_size = 720*(480/2); break;
- case APP_RES_720_576: framebuffer_size = 720*(576/2); break;
+ case APP_RES_640_480: full_size = APP_SIZE(640_480); fb_size = APP_FB(640_480); break;
+ case APP_RES_720_480: full_size = APP_SIZE(720_480); fb_size = APP_FB(720_480); break;
+ case APP_RES_720_576: full_size = APP_SIZE(720_576); fb_size = APP_FB(720_576); break;
}
- /* packet (syncpoint) */
- nut_append_vu(&pkt, time_ns); /*! global_key_pts */
- nut_append_vu(&pkt, state->last_syncpoint ? (beg - state->last_syncpoint)/16 : 0); /*! back_ptr_div16 */
+ /* packet (syncpoint) ( (8+1)+ (10+2) + 4 = 25 bytes) */
+ nut_append_vu(&pkt, time_ns); /*! global_key_pts (<=10 bytes) */
+ nut_append_vu(&pkt, state->last_syncpoint ? (beg - state->last_syncpoint)/16 : 0); /*! back_ptr_div16 (<=2 bytes) */
nut_append_packet(&out, nut_startcode_syncpoint, pkt.dat, pkt.len);
- /* frame header */
+ /* frame header ( 1+1+4 = 6 bytes) */
uint64_t frame_beg = out.len;
- nut_append_u8(&out, 1+res); /*! frame_code */
- nut_append_vu(&out, framebuffer_size/SIZE_MSB_MUL); /*! data_size_msb */
- nut_append_u32(&out, nut_crc32(&out.dat[frame_beg], out.len - frame_beg)); /*! checksum */
+ nut_append_u8(&out, 1+res); /*! frame_code (4 byte) */
+ nut_append_vu(&out, full_size/APP_SIZE_MSB_MUL); /*! data_size_msb (1 byte) */
+ nut_append_u32(&out, nut_crc32(&out.dat[frame_beg], out.len - frame_beg)); /*! checksum (4 bytes) */
/* side_data and meta_data come from elision headers */
/* flush */
- fprintf(stderr, "frame_overhead=%zu\n", out.len);
+ assert(out.len <= APP_FRAME_MAX_OVERHEAD);
bool err = xwrite(fd, out.dat, out.len);
free(out.dat);
free(pkt.dat);
@@ -411,9 +439,9 @@ bool app_write_frame(int fd, struct app_state *state, uint64_t time_ns, enum app
state->len += out.len;
/* frame data */
- if (xwrite(fd, framebuffer, framebuffer_size))
+ if (xwrite(fd, framebuffer, fb_size))
return true;
- state->len += framebuffer_size;
+ state->len += fb_size;
/* return */
state->pts = time_ns;
@@ -482,7 +510,7 @@ int main() {
if (app_write_intro(1, &state, 0))
return 1;
- uint8_t framebuffer[720*(576/2)];
+ uint8_t framebuffer[APP_FB(720_576)];
#define SCALE 10
for (int i = 0; i < 10; i++) {
@@ -490,9 +518,9 @@ int main() {
for (int y = 0; y < 4*SCALE; y++) {
int width;
switch (i%3) {
- case APP_RES_640_480: width = 640; break;
- case APP_RES_720_480: width = 720; break;
- case APP_RES_720_576: width = 720; break;
+ case APP_RES_640_480: width = APP_W(640_480); break;
+ case APP_RES_720_480: width = APP_W(720_480); break;
+ case APP_RES_720_576: width = APP_W(720_576); break;
}
for (int x = 0; x < 8*SCALE; x++)
framebuffer[(y*width)+x] = font[i][((y/SCALE)*8)+(x/SCALE)] == ' ' ? 0b11000000 : 0b00000011;