summaryrefslogtreecommitdiff
path: root/libmkv/nut-generate.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmkv/nut-generate.c')
-rw-r--r--libmkv/nut-generate.c165
1 files changed, 71 insertions, 94 deletions
diff --git a/libmkv/nut-generate.c b/libmkv/nut-generate.c
index 25b7627..c52d8c1 100644
--- a/libmkv/nut-generate.c
+++ b/libmkv/nut-generate.c
@@ -225,9 +225,11 @@ void nut_append_packet(struct buf *buf, uint8_t *startcode, void *data, size_t l
/* High-level (specific to the properties we want) ****************************/
enum app_res {
+ APP_RES_INVALID = -1,
APP_RES_640_480 = 0,
APP_RES_720_480 = 1,
APP_RES_720_576 = 2,
+ APP_RES_NUM = 3,
};
#define APP_RES_MIN APP_RES_640_480
#define APP_RES_MAX APP_RES_720_576
@@ -259,147 +261,124 @@ struct app_state {
enum app_res res;
};
-bool app_write_intro(int fd, uint64_t time_ns) {
- struct buf out = {0};
+void app_append_intro(struct buf *out, uint64_t time_ns, 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)
- append(&out, nut_file_id_string, sizeof(nut_file_id_string));
+ append(out, nut_file_id_string, sizeof(nut_file_id_string));
#define BOGUS(n) n
/* main_header ********************************************************/
pkt.len = 0;
/* head *******************************************/
- nut_append_vu(&pkt, 4); /*! version */
- nut_append_vu(&pkt, 0); /*! minor_version */
- nut_append_vu(&pkt, 1); /*! stream_count */
- nut_append_vu(&pkt, /*! max_distance */
+ nut_append_vu(&pkt, 4); /*! version */
+ nut_append_vu(&pkt, 0); /*! minor_version */
+ nut_append_vu(&pkt, 1); /*! stream_count */
+ nut_append_vu(&pkt, /*! max_distance */
APP_FRAME_MAX_HEADER +
- app_res_fb_size(APP_RES_MAX));
+ app_res_fb_size(res));
/* time bases *************************************/
- nut_append_vu(&pkt, 1); /*! time_base_count */
+ nut_append_vu(&pkt, 1); /*! time_base_count */
/* time_base[0] = 1ns */
- nut_append_vu(&pkt, 1); /*! numerator */
- nut_append_vu(&pkt, 1000000000ULL); /*! denominator */
+ nut_append_vu(&pkt, 1); /*! numerator */
+ nut_append_vu(&pkt, 1000000000ULL); /*! denominator */
/* frame codes ************************************/
/* "A muxer SHOULD mark [frame codes] 0x00 and 0xFF as invalid" */
/* 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)); /*! 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)); /*! 0: fields.pts */
+ nut_append_vu(&pkt, 1); /*! 1: fields.size_msb_nul */
INC_FRAME_CODE();
- for (enum app_res res = APP_RES_MIN; res <= APP_RES_MAX; res++) {
- /* frame_code=(res*2)+1 (at `res`) */
- nut_append_vu(&pkt, APP_COMMON_FLAGS); /*! flags */
- nut_append_vu(&pkt, 6); /*! field_count */
- nut_append_vu(&pkt, BOGUS(0)); /*! 0: fields.pts */
- nut_append_vu(&pkt, APP_FRAME_SIZE_MSB_MUL); /*! 1: fields.size_msb_nul */
- nut_append_vu(&pkt, 0); /*! 2: fields.stream */
- nut_append_vu(&pkt, /*! 3: fields.size_lsb */
- app_res_fb_size(res) % APP_FRAME_SIZE_MSB_MUL);
- nut_append_vu(&pkt, 0); /*! 4: fields.reserved */
- nut_append_vu(&pkt, 1); /*! 5: fields.count */
- INC_FRAME_CODE();
-
- /* frame_code=(res*2)+2 (change to `res`) */
- nut_append_vu(&pkt, APP_COMMON_FLAGS| /*! flags */
- NUT_FRAMEFLAG_SM_DATA);
- nut_append_vu(&pkt, 6); /*! field_count */
- nut_append_vu(&pkt, BOGUS(0)); /*! 0: fields.pts */
- nut_append_vu(&pkt, APP_FRAME_SIZE_MSB_MUL); /*! 1: fields.size_msb_nul */
- nut_append_vu(&pkt, 0); /*! 2: fields.stream */
- nut_append_vu(&pkt, /*! 3: fields.size_lsb */
- (app_res_sm_size(res) + app_res_fb_size(res)) % APP_FRAME_SIZE_MSB_MUL);
- nut_append_vu(&pkt, 0); /*! 4: fields.reserved */
- nut_append_vu(&pkt, 1); /*! 5: fields.count */
- INC_FRAME_CODE();
- }
+ /* frame_code=1 (res) */
+ nut_append_vu(&pkt, /*! flags */
+ NUT_FRAMEFLAG_KEY | /* Because they're full framebuffers, all frames are keyframes. */
+ NUT_FRAMEFLAG_SIZE_MSB | /* 640*480/2 > 16384 (the max val of data_size_lsb). */
+ NUT_FRAMEFLAG_CODED_PTS | /* framerate is unknown, each frame must have a timestamp. */
+ NUT_FRAMEFLAG_CHECKSUM ); /* framerate is unknown, guard against exceeding max_pts_distance. */
+ nut_append_vu(&pkt, 6); /*! field_count */
+ nut_append_vu(&pkt, BOGUS(0)); /*! 0: fields.pts */
+ nut_append_vu(&pkt, APP_FRAME_SIZE_MSB_MUL); /*! 1: fields.size_msb_nul */
+ nut_append_vu(&pkt, 0); /*! 2: fields.stream */
+ nut_append_vu(&pkt, /*! 3: fields.size_lsb */
+ app_res_fb_size(res) % APP_FRAME_SIZE_MSB_MUL);
+ nut_append_vu(&pkt, 0); /*! 4: fields.reserved */
+ nut_append_vu(&pkt, 1); /*! 5: fields.count */
+ INC_FRAME_CODE();
/* frame_code=N-255 (invalid) */
- nut_append_vu(&pkt, NUT_FRAMEFLAG_INVALID); /*! flags */
- nut_append_vu(&pkt, 2); /*! field_count */
- nut_append_vu(&pkt, BOGUS(0)); /*! 0: fields.pts */
- nut_append_vu(&pkt, /*! 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)); /*! 0: fields.pts */
+ nut_append_vu(&pkt, /*! 1: fields.size_msb_nul */
256-frame_code-(frame_code < 'N' ? 1 : 0));
/* tail *******************************************/
- nut_append_vu(&pkt, 0); /*! header_count_minus_1 */
- nut_append_vu(&pkt, NUT_MAINFLAG_PIPE_MODE); /*! main_flags */
+ 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);
+ nut_append_packet(out, nut_startcode_main, pkt.dat, pkt.len);
/* stream_header ******************************************************/
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 */
- nut_append_vu(&pkt, 0); /*! time_base_id */
- nut_append_vu(&pkt, BOGUS(0)); /*! msb_pts_shift (only relevant if FRAMEFLAG_CODED_PTS) */
- nut_append_vu(&pkt, BOGUS(0)); /*! max_pts_distance (all frames have a checksum) */
- nut_append_vu(&pkt, 0); /*! decode_delay */
- nut_append_vu(&pkt, 0); /*! stream_flags */
- nut_append_vb(&pkt, NULL, 0); /*! codec_specific_data */
- state->res = APP_RES_640_480;
- nut_append_vu(&pkt, app_res_w(state->res)); /*! width */
- nut_append_vu(&pkt, app_res_h(state->res)); /*! height */
- nut_append_vu(&pkt, 1); /*! sample_width */
- nut_append_vu(&pkt, 2); /*! sample_height */
- nut_append_vu(&pkt, NUT_COLORSPACE_UNKNOWN); /*! colorspace_type */
-
- nut_append_packet(&out, nut_startcode_stream, pkt.dat, pkt.len);
+ nut_append_vu(&pkt, 0); /*! stream_id */
+ nut_append_vu(&pkt, NUT_STREAMCLASS_VIDEO); /*! stream_class */
+ nut_append_vb(&pkt, "BGR\x08", 4); /*! fourcc */
+ nut_append_vu(&pkt, 0); /*! time_base_id */
+ nut_append_vu(&pkt, 0); /*! msb_pts_shift */
+ nut_append_vu(&pkt, BOGUS(0)); /*! max_pts_distance (all frames have a checksum) */
+ nut_append_vu(&pkt, 0); /*! decode_delay */
+ nut_append_vu(&pkt, 0); /*! stream_flags */
+ nut_append_vb(&pkt, NULL, 0); /*! codec_specific_data */
+ nut_append_vu(&pkt, app_res_w(res)); /*! width */
+ nut_append_vu(&pkt, app_res_h(res)); /*! height */
+ nut_append_vu(&pkt, 1); /*! sample_width */
+ nut_append_vu(&pkt, 2); /*! sample_height */
+ nut_append_vu(&pkt, NUT_COLORSPACE_UNKNOWN); /*! colorspace_type */
+
+ 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_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);
+ nut_append_packet(out, nut_startcode_syncpoint, pkt.dat, pkt.len);
/* flush **************************************************************/
#undef BOGUS
- bool ret = xwrite(fd, out.dat, out.len);
- free(out.dat);
free(pkt.dat);
- return ret;
}
bool app_write_frame(int fd, struct app_state *state, uint64_t time_ns, enum app_res res, void *framebuffer) {
assert(framebuffer);
+ assert(0 <= res && res < APP_RES_NUM);
struct buf out = {0};
struct buf pkt = {0};
+ if (res != state->res) {
+ app_append_intro(&out, time_ns, res);
+ state->res = res;
+ }
+
/* frame header ( 1+10+1+4 = 16 bytes) */
uint64_t frame_beg = out.len;
- nut_append_u8(&out, 1+(2*res)+(res != state->res ? 1 : 0)); /*! frame_code (1 byte) */
+ nut_append_u8(&out, 1); /*! frame_code (1 byte) */
nut_append_vu(&out, time_ns); /*! coded_pts (<=10 bytes) */
- nut_append_vu(&out, /*! data_size_msb (1 byte) */
- (app_res_fb_size(res) + (res != state->res ? app_res_sm_size(res) : 0)) / APP_FRAME_SIZE_MSB_MUL);
+ nut_append_vu(&out, app_res_fb_size(res) / APP_FRAME_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) */
- assert(out.len <= APP_FRAME_MAX_HEADER);
-
- /* side/meta data ( 1+(6+2)+(7+2)+1 = 19 bytes) */
- if (res != state->res) {
- uint64_t data_beg = out.len;
- nut_append_vu(&out, 2); /*! side_data_count (1 byte) */
- nut_append_vb_str(&out, "Width"); /*! side_data[0].name (1+5 bytes) */
- nut_append_vu(&out, app_res_w(res)); /*! side_data[0].value (2 bytes) */
- nut_append_vb_str(&out, "Height"); /*! side_data[1].name (1+6 bytes) */
- nut_append_vu(&out, app_res_h(res)); /*! side_data[1].value (2 bytes) */
- nut_append_vu(&out, 0); /*! meta_data_count (1 byte) */
- assert(out.len - data_beg == app_res_sm_size(res));
- }
+ assert(out.len - frame_beg <= APP_FRAME_MAX_HEADER);
/* flush */
bool err = xwrite(fd, out.dat, out.len);
@@ -474,22 +453,20 @@ static_assert(LM_ARRAY_LEN(font) == 10);
static_assert(sizeof(font[0]) == 32);
int main() {
- if (app_write_intro(1, 0))
- return 1;
-
struct app_state state = {
- .res = 0,
+ .res = APP_RES_INVALID,
};
uint8_t framebuffer[app_res_fb_size(APP_RES_MAX)];
#define SCALE 10
for (int i = 0; i < 10; i++) {
- memset(framebuffer, 0, sizeof(framebuffer));
+ enum app_res res = (i/2)%APP_RES_NUM;
+ memset(framebuffer, 0b00011000, sizeof(framebuffer));
for (int y = 0; y < 4*SCALE; y++)
for (int x = 0; x < 8*SCALE; x++)
- framebuffer[(y*app_res_w(i%(APP_RES_MAX+1)))+x] = font[i][((y/SCALE)*8)+(x/SCALE)] == ' ' ? 0b11000000 : 0b00000011;
- if (app_write_frame(1, &state, ((uint64_t)i)*1000000000ULL, i%(APP_RES_MAX+1), framebuffer))
+ framebuffer[(y*app_res_w(res))+x] = font[i][((y/SCALE)*8)+(x/SCALE)] == ' ' ? 0b11000000 : 0b00000011;
+ if (app_write_frame(1, &state, ((uint64_t)i)*1000000000ULL, res, framebuffer))
return 1;
}
return 0;