diff options
-rw-r--r-- | libmkv/nut-3.c | 172 |
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; |