[nut]: r500 - in src/trunk/nututils: . Makefile nutparse.c

Author: ods15 Date: Thu May 31 17:20:58 2007 New Revision: 500 Log: Add nutparse util, could also be used as starting point for nutlint Patch by Clemens Ladisch <cladisch ZING fastmail ZORT net> Added: src/trunk/nututils/nutparse.c Modified: src/trunk/nututils/ (props changed) src/trunk/nututils/Makefile Modified: src/trunk/nututils/Makefile ============================================================================== --- src/trunk/nututils/Makefile (original) +++ src/trunk/nututils/Makefile Thu May 31 17:20:58 2007 @@ -2,7 +2,7 @@ include ../config.mak CFLAGS += -I../libnut -lm -all: avireader nutmerge nutindex # oggreader +all: avireader nutmerge nutindex nutparse # oggreader avireader: demux_avi.c ${CC} ${CFLAGS} -DAVI_PROG $^ -o $@ @@ -12,6 +12,8 @@ nutmerge: demux_ogg.c demux_avi.c framer ${CC} ${CFLAGS} $^ -o $@ nutindex: nutindex.c ${CC} ${CFLAGS} $^ -o $@ +nutparse: nutparse.c + ${CC} ${CFLAGS} $^ -o $@ clean: - rm -f *\~ nutmerge nutindex avireader oggreader *.o + rm -f *\~ nutmerge nutindex nutparse avireader oggreader *.o Added: src/trunk/nututils/nutparse.c ============================================================================== --- (empty file) +++ src/trunk/nututils/nutparse.c Thu May 31 17:20:58 2007 @@ -0,0 +1,842 @@ +/* + * nutparse.c - dumps a .nut file as text + * Copyright (c) 2007 Clemens Ladisch <clemens@ladisch.de> + * + * This file is available under the MIT/X license, see COPYING. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <stdint.h> +#include <inttypes.h> +#include <string.h> +#include <errno.h> +#include <getopt.h> + +#define MAIN_STARTCODE UINT64_C(0x4e4d7a561f5f04ad) +#define STREAM_STARTCODE UINT64_C(0x4e5311405bf2f9db) +#define SYNCPOINT_STARTCODE UINT64_C(0x4e4be4adeeca4569) +#define INDEX_STARTCODE UINT64_C(0x4e58dd672f23e64e) +#define INFO_STARTCODE UINT64_C(0x4e49ab68b596ba78) + +#define FLAG_KEY 0x0001 +#define FLAG_EOR 0x0002 +#define FLAG_CODED_PTS 0x0008 +#define FLAG_STREAM_ID 0x0010 +#define FLAG_SIZE_MSB 0x0020 +#define FLAG_CHECKSUM 0x0040 +#define FLAG_RESERVED 0x0080 +#define FLAG_CODED 0x1000 +#define FLAG_INVALID 0x2000 + +#define ABS(x) ((x) > 0 ? (x) : -(x)) + +static FILE *input; +static uint64_t file_position; +static uint32_t crc; +static int stream_count = -1; +static uint64_t max_distance; +static int time_base_count = -1; +static struct { + uint64_t num; + uint64_t denom; +} *time_bases; +static struct { + uint64_t flags; + uint64_t stream_id; + uint64_t data_size_mul; + uint64_t data_size_lsb; + int64_t pts_delta; + uint64_t reserved_count; +} frame_types[256]; +static struct { + int time_base_id; + int msb_pts_shift; + uint64_t max_pts_distance; + uint64_t last_pts; +} *streams; + +static void error(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + putc('\n', stderr); + exit(EXIT_FAILURE); +} + +static void usage(void) +{ + puts("Usage: nutparse input.nut"); +} + +static void version(void) +{ + puts("nutparse version 0.1"); +} + +static uint64_t gcd(uint64_t a, uint64_t b) +{ + while (b) { + uint64_t t = b; + b = a % b; + a = t; + } + return a; +} + +static inline void reset_checksum(void) +{ + crc = 0; +} + +static void update_checksum(uint8_t byte) +{ + static const uint32_t crc_table[16] = { + 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, + 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, + 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, + 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, + }; + + crc ^= byte << 24; + crc = (crc << 4) ^ crc_table[crc >> 28]; + crc = (crc << 4) ^ crc_table[crc >> 28]; +} + +static uint8_t read_byte(void) +{ + int c = getc(input); + if (c == EOF) + error("unexpected EOF"); + ++file_position; + update_checksum(c); + return c; +} + +static uint64_t read_fixed(int bytes) +{ + uint64_t value = 0; + int i; + + for (i = bytes; i > 0; --i) + value = (value << 8) | read_byte(); + return value; +} + +static uint64_t read_var(void) +{ + uint64_t value = 0; + uint8_t byte; + + do { + if (value & UINT64_C(0xe000000000000000)) + error("value too big (more than 64 bits)"); + byte = read_byte(); + value = (value << 7) | (byte & 0x7f); + } while (byte & 0x80); + return value; +} + +static uint64_t read_var_restricted(void) +{ + uint64_t value = 0; + uint8_t byte; + int padding = 0; + + for (;;) { + byte = read_byte(); + if (byte != 0x80) + break; + ++padding; + if (padding > 8) + error("more than 8 consecutive padding bytes"); + } + for (;;) { + if (value & UINT64_C(0xe000000000000000)) + error("value too big (more than 64 bits)"); + value = (value << 7) | (byte & 0x7f); + if ((byte & 0x80) == 0) + break; + byte = read_byte(); + } + return value; +} + +static int64_t convert_to_signed(uint64_t temp) +{ + ++temp; + if (temp == 0) + error("signed value too big (more than 63 bits)"); + if (temp & 1) + return -(temp >> 1); + else + return temp >> 1; +} + +static int64_t read_svar(void) +{ + return convert_to_signed(read_var()); +} + +static int64_t read_svar_restricted(void) +{ + return convert_to_signed(read_var_restricted()); +} + +static uint64_t convert_ts(uint64_t t, int tb_from, int tb_to) +{ + uint64_t ln = time_bases[tb_from].num * time_bases[tb_to].denom; + uint64_t d1 = time_bases[tb_from].denom; + return (ln / d1 * t + ln % d1 * t / d1) / time_bases[tb_to].num; +} + +static double time_in_s(uint64_t t, int time_base_id) +{ + return (double)t * time_bases[time_base_id].num / time_bases[time_base_id].denom; +} + +static void parse_file_id(void) +{ + char id[25]; + + if (fread(id, 1, 25, input) != 25) + error("unexpected EOF"); + if (memcmp(id, "nut/multimedia container", 25) != 0) + error("invalid file ID string"); + puts(id); + file_position = 25; +} + +static void parse_main_header(void) +{ + uint64_t value; + uint64_t tmp_flag; + uint64_t tmp_fields; + int64_t tmp_pts; + uint64_t tmp_mul; + uint64_t tmp_stream; + uint64_t tmp_size; + uint64_t tmp_res; + uint64_t count; + int i, j; + uint64_t j64; + + value = read_var(); + printf(" version: %"PRIu64"\n", value); + if (value != 2 && value != 3) /* TODO: remove 2 */ + error("invalid version"); + value = read_var(); + printf(" stream_count: %"PRIu64"\n", value); + if (value > 0x1000) + error("implementation limit exceeded"); + stream_count = value; + streams = calloc(stream_count, sizeof *streams); + if (!streams) + error("out of memory"); + value = read_var(); + printf(" max_distance: %"PRIu64"\n", value); + max_distance = value; + value = read_var(); + printf(" time_base_count: %"PRIu64"\n", value); + if (!value) + error("time_base_count must not be zero"); + if (value > 0x1000) + error("implementation limit exceeded"); + time_base_count = value; + time_bases = calloc(time_base_count, sizeof *time_bases); + if (!time_bases) + error("out of memory"); + for (i = 0; i < time_base_count; ++i) { + time_bases[i].num = read_var(); + time_bases[i].denom = read_var(); + printf(" time_base[%d]: %"PRIu64"/%"PRIu64"\n", + i, time_bases[i].num, time_bases[i].denom); + if (!time_bases[i].num || !time_bases[i].denom) + error("time base values must not be zero"); + if (gcd(time_bases[i].num, time_bases[i].denom) != 1) + error("time base values must be relatively prime"); + if (time_bases[i].denom >= (1 << 31)) + error("time base denominator is not less than 2^31"); + for (j = 0; j < i; ++j) + if (time_bases[i].num == time_bases[j].num && + time_bases[i].denom == time_bases[j].denom) + error("time base is identical to time base %d", j); + } + tmp_pts = 0; + tmp_mul = 1; + tmp_stream = 0; + for (i = 0; i < 256; ) { + tmp_flag = read_var(); + printf(" tmp_flag: %"PRIu64"\n", tmp_flag); + tmp_fields = read_var(); + printf(" tmp_fields: %"PRIu64"\n", tmp_fields); + if (tmp_fields > 0) { + tmp_pts = read_svar(); + printf(" tmp_pts: %"PRId64"\n", tmp_pts); + if (tmp_pts <= -16384 || tmp_pts >= 16384) + error("absolute pts difference must be less than 16384"); + } + if (tmp_fields > 1) { + tmp_mul = read_var(); + printf(" tmp_mul: %"PRIu64"\n", tmp_mul); + if (tmp_mul >= 16384) + error("data size multiplicator must be less than 16384"); + } + if (tmp_fields > 2) { + tmp_stream = read_var(); + printf(" tmp_stream: %"PRIu64"\n", tmp_stream); + if (tmp_stream >= stream_count) + error("invalid stream id"); + if (tmp_stream >= 250) + error("stream id must be less than 250"); + } + if (tmp_fields > 3) { + tmp_size = read_var(); + printf(" tmp_size: %"PRIu64"\n", tmp_size); + if (tmp_size >= 16384) + error("data size lsb must be less than 16384"); + } else + tmp_size = 0; + if (tmp_fields > 4) { + tmp_res = read_var(); + printf(" tmp_res: %"PRIu64"\n", tmp_res); + if (tmp_res >= 256) + error("reserved count must be less than 256"); + } else + tmp_res = 0; + if (tmp_fields > 5) { + count = read_var(); + printf(" count: %"PRIu64"\n", count); + } else { + if (tmp_size > tmp_mul) + error("count underflow"); + count = tmp_mul - tmp_size; + if (!count) + error("count is zero"); + } + for (j64 = 6; j64 < tmp_fields; ++j64) + printf(" tmp_reserved[%"PRIu64"]: %"PRIu64"\n", j64, read_var()); + for (j = 0; j < count && i < 256; ++j, ++i) { + if (i == 'N') { + frame_types[i].flags = FLAG_INVALID; + --j; + continue; + } + if (j == 0) { + printf(" frame_type[0x%02x]:", i); + if (tmp_flag & FLAG_KEY) + printf(" key"); + if (tmp_flag & FLAG_EOR) + printf(" eor"); + if (tmp_flag & FLAG_CODED_PTS) + printf(" coded_pts"); + if (tmp_flag & FLAG_STREAM_ID) + printf(" stream_id"); + if (tmp_flag & FLAG_SIZE_MSB) + printf(" size_msb"); + if (tmp_flag & FLAG_CHECKSUM) + printf(" checksum"); + if (tmp_flag & FLAG_RESERVED) + printf(" reserved"); + if (tmp_flag & FLAG_CODED) + printf(" flag_coded"); + if (tmp_flag & FLAG_INVALID) + printf(" invalid"); + if (!(tmp_flag & (FLAG_STREAM_ID | FLAG_INVALID)) || (tmp_flag & FLAG_CODED)) + printf(" stream_id: %"PRIu64, tmp_stream); + if (!(tmp_flag & (FLAG_SIZE_MSB | FLAG_INVALID)) || (tmp_flag & FLAG_CODED)) { + printf(" data_size_mul: %"PRIu64, tmp_mul); + printf(" data_size_lsb: %"PRIu64, tmp_size); + } + if (!(tmp_flag & (FLAG_CODED_PTS | FLAG_INVALID)) || (tmp_flag & FLAG_CODED)) + printf(" pts_delta: %"PRId64, tmp_pts); + if ((!(tmp_flag & (FLAG_RESERVED | FLAG_INVALID)) || (tmp_flag & FLAG_CODED)) && + tmp_res != 0) + printf(" reserved_count: %"PRIu64, tmp_res); + putchar('\n'); + } + frame_types[i].flags = tmp_flag; + frame_types[i].stream_id = tmp_stream; + frame_types[i].data_size_mul = tmp_mul; + frame_types[i].data_size_lsb = tmp_size + j; + frame_types[i].pts_delta = tmp_pts; + frame_types[i].reserved_count = tmp_res; + } + } +} + +static void parse_stream_header(void) +{ + uint64_t value, value2; + int id, class, i; + uint8_t fourcc[4]; + + if (stream_count < 0) + error("no main_header before stream_header"); + value = read_var(); + printf(" stream_id: %"PRIu64"\n", value); + if (value >= stream_count) + error("invalid stream id"); + id = value; + value = read_var(); + printf(" stream_class: %"PRIu64, value); + if (value < 4) { + static const char *const class_names[4] = { + "video", "audio", "subtitles", "userdata" + }; + class = value; + printf(" (%s)", class_names[class]); + } else + class = -1; + putchar('\n'); + value = read_var(); + if (value != 2 && value != 4) + error("invalid fourcc length"); + printf(" fourcc: "); + for (i = 0; i < value; ++i) + fourcc[i] = read_byte(); + if (value == 2) + printf("0x%02x%02x\n", fourcc[1], fourcc[0]); + else { + printf("%02x,%02x,%02x,%02x (", fourcc[0], fourcc[1], fourcc[2], fourcc[3]); + for (i = 0; i < 4; ++i) + if (fourcc[i] >= 32 && fourcc[i] < 127) + putchar(fourcc[i]); + else + putchar('.'); + puts(")"); + } + value = read_var(); + printf(" time_base_id: %"PRIu64"\n", value); + if (value >= time_base_count) + error("invalid time base id"); + streams[id].time_base_id = value; + value = read_var(); + printf(" msb_pts_shift: %"PRIu64"\n", value); + if (value >= 16) + error("invalid msb_pts_shift value"); + streams[id].msb_pts_shift = value; + value = read_var(); + printf(" max_pts_distance: %"PRIu64"\n", value); + streams[id].max_pts_distance = value; + printf(" decode_delay: %"PRIu64"\n", read_var()); + value = read_var(); + printf(" stream_flags: %"PRIu64, value); + if (value & 1) + printf(" (fixed_fps)"); + putchar('\n'); + value = read_var(); + printf(" codec_specific_data: %"PRIu64" bytes\n", value); + for (; value > 0; --value) + read_byte(); + if (class == 0) { + value = read_var(); + printf(" width: %"PRIu64"\n", value); + if (!value) + error("width must not be zero"); + value = read_var(); + printf(" height: %"PRIu64"\n", value); + if (!value) + error("height must not be zero"); + value = read_var(); + printf(" sample_width: %"PRIu64"\n", value); + value2 = read_var(); + printf(" sample_height: %"PRIu64"\n", value2); + if ((!value) ^ (!value2)) + error("none or both of sample_width/height must be zero"); + if (value && gcd(value, value2) != 1) + error("sample_width/height must be relatively prime"); + printf(" colorspace_type: %"PRIu64"\n", read_var()); + } else if (class = 1) { + value = read_var(); + printf(" samplerate_num: %"PRIu64"\n", value); + if (!value) + error("sample rate must not be zero"); + value = read_var(); + printf(" samplerate_denom: %"PRIu64"\n", value); + if (!value) + error("invalid sample rate"); + value = read_var(); + printf(" channel_count: %"PRIu64"\n", value); + if (!value) + error("channel count must not be zero"); + } +} + +static void parse_syncpoint(void) +{ + uint64_t value, pts; + int tbid, i; + + if (stream_count < 0) + error("no main_header before syncpoint"); + value = read_var(); + pts = value / time_base_count; + tbid = value % time_base_count; + printf(" global_key_pts: %"PRIu64"@%d (%.3lf s)\n", pts, tbid, time_in_s(pts, tbid)); + for (i = 0; i < stream_count; ++i) + streams[i].last_pts = convert_ts(pts, tbid, streams[i].time_base_id); + value = read_var(); + printf(" back_ptr_div16: %"PRIu64" (%"PRIu64")\n", value, value * 16 + 15); +} + +static void parse_index(void) +{ + uint64_t value, pts; + uint64_t syncpoints; + uint64_t last_pos; + int64_t last_pts; + uint64_t j, x, xx, n, a, b; + int tbid, i, type, flag, has_keyframe; + + if (stream_count < 0) + error("no main_header before index"); + value = read_var(); + pts = value / time_base_count; + tbid = value % time_base_count; + printf(" max_pts: %"PRIu64"@%d (%.3lf s)\n", pts, tbid, time_in_s(pts, tbid)); + syncpoints = read_var(); + printf(" syncpoints %"PRIu64"\n", syncpoints); + last_pos = 0; + for (j = 0; j < syncpoints; ++j) { + value = read_var(); + printf(" syncpoint_pos_div16: %"PRIu64" (0x%"PRIx64")\n", value, (last_pos + value) << 4); + last_pos += value; + } + for (i = 0; i < stream_count; ++i) { + last_pts = -1; + for (j = 0; j < syncpoints; ) { + x = read_var(); + printf(" x: %"PRIu64" ", x); + type = x & 1; + x >>= 1; + n = j; + if (type) { + flag = x & 1; + x >>= 1; + printf("(%"PRIu64"*%d,%d)\n", x, flag, !flag); + n += x + 1; + } else { + putchar('('); + for (xx = x; xx != 1; ++n, xx >>= 1) + printf("%d", (int)xx & 1); + puts(")"); + } + for (; j < n && j < syncpoints; ++j) { + if (type) { + if (x > 0) { + has_keyframe = flag; + --x; + } else + has_keyframe = !flag; + } else { + has_keyframe = (int)x & 1; + x >>= 1; + } + if (!has_keyframe) + continue; + a = read_var(); + if (!a) { + printf(" A: %"PRIu64"\n", a); + a = read_var(); + printf(" A: %"PRIu64" (keyframe_pts[%"PRIu64"][%d]: %"PRIu64")\n", a, j, i, last_pts + a); + b = read_var(); + printf(" B: %"PRIu64" (eor_pts[%"PRIu64"][%d]: %"PRIu64")\n", b, j, i, last_pts + a + b); + } else { + printf(" A: %"PRIu64" (keyframe_pts[%"PRIu64"][%d]: %"PRIu64")\n", a, j, i, last_pts + a); + b = 0; + } + last_pts += a + b; + } + } + } +} + +static void parse_info_packet(void) +{ + uint64_t value, pts, count; + int64_t type; + int tbid; + + if (stream_count < 0) + error("no main_header before info_packet"); + value = read_var(); + printf(" stream_id_plus1: %"PRIu64"\n", value); + if (value > stream_count) + error("invalid stream id"); + printf(" chapter_id: %"PRIu64"\n", read_svar()); + value = read_var(); + pts = value / time_base_count; + tbid = value % time_base_count; + printf(" chapter_start: %"PRIu64"@%d (%.3lf s)\n", pts, tbid, time_in_s(pts, tbid)); + value = read_var(); + printf(" chapter_len: %"PRIu64" (%.3lf s)\n", value, time_in_s(value, tbid)); + count = read_var(); + printf(" count: %"PRIu64"\n", count); + for (; count > 0; --count) { + value = read_var(); + printf(" name: \""); + for (; value > 0; --value) + fputc(read_byte(), stdout); + puts("\""); + type = read_svar(); + if (type == -1) { + puts(" value: -1 (type: UTF-8)"); + value = read_var(); + printf(" value: \""); + for (; value > 0; --value) + fputc(read_byte(), stdout); + puts("\""); + } else if (type == -2) { + puts(" value: -2 (type: user-defined)"); + value = read_var(); + printf(" type: \""); + for (; value > 0; --value) + fputc(read_byte(), stdout); + puts("\""); + value = read_var(); + printf(" value: "); + if (value > 0) + printf("%02x", read_byte()); + for (--value; value > 0; --value) + printf(",%02x", read_byte()); + putchar('\n'); + } else if (type == -3) { + puts(" value: -3 (type: s)"); + printf(" value: %"PRId64"\n", read_svar()); + } else if (type == -4) { + puts(" value: -4 (type: t)"); + value = read_var(); + pts = value / time_base_count; + tbid = value % time_base_count; + printf(" value: %"PRIu64"@%d (%.3lf s)\n", pts, tbid, time_in_s(pts, tbid)); + } else if (value < -4) { + printf(" value: %"PRId64" (type: r)\n", type); + printf(" value: %"PRId64"/%"PRId64"\n", read_svar(), -type - 4); + } else + printf(" value: %"PRId64" (type: v)\n", type); + } +} + +static void parse_packet(void) +{ + uint64_t startcode; + uint64_t forward_ptr; + uint32_t checksum, actual_checksum; + uint64_t end_pos; + + /* TODO: check max_distance */ + startcode = read_fixed(7) | ((uint64_t)'N' << 56); + switch (startcode) { + case MAIN_STARTCODE: + printf("main_header"); + break; + case STREAM_STARTCODE: + printf("stream_header"); + break; + case SYNCPOINT_STARTCODE: + printf("syncpoint"); + break; + case INDEX_STARTCODE: + printf("index"); + break; + case INFO_STARTCODE: + printf("info_packet"); + break; + default: + printf("unknown_packet"); + break; + } + printf(" at 0x%"PRIx64"\n", file_position - 8); + printf(" startcode: 0x%016"PRIx64"\n", startcode); + forward_ptr = read_var_restricted(); + printf(" forward_ptr: %"PRIu64"\n", forward_ptr); + if (forward_ptr > 4096) { + actual_checksum = crc; + checksum = read_fixed(4); + printf(" header_checksum: 0x%08"PRIx32"\n", checksum); + if (checksum != actual_checksum) + error("invalid checksum"); + } + reset_checksum(); + end_pos = file_position + forward_ptr - 4; + switch (startcode) { + case MAIN_STARTCODE: + parse_main_header(); + break; + case STREAM_STARTCODE: + parse_stream_header(); + break; + case SYNCPOINT_STARTCODE: + parse_syncpoint(); + break; + case INDEX_STARTCODE: + end_pos -= 8; /* special handling for index_ptr behind reserved_bytes */ + parse_index(); + break; + case INFO_STARTCODE: + parse_info_packet(); + break; + } + if (file_position > end_pos) + error("packet has more data than indicated by forward_ptr"); + else if (file_position < end_pos) { + printf(" reserved_bytes: %02x", read_byte()); + while (file_position < end_pos) + printf(",%02x", read_byte()); + putchar('\n'); + } + if (startcode == INDEX_STARTCODE) + printf(" index_ptr: 0x%016"PRIx64"\n", read_fixed(8)); + actual_checksum = crc; + checksum = read_fixed(4); + printf(" checksum: 0x%08"PRIx32"\n", checksum); + if (checksum != actual_checksum) + error("invalid checksum"); +} + +static void parse_frame(int frame_type) +{ + uint64_t value; + uint64_t frame_flags; + uint64_t stream_id; + uint64_t coded_pts; + int64_t pts_delta; + uint64_t data_size_msb; + uint64_t reserved_count; + uint64_t data_size; + uint64_t old_last_pts; + uint32_t checksum, actual_checksum; + + printf("frame_0x%02x\n", frame_type); + if (stream_count < 0) + error("no main_header before frame"); + frame_flags = frame_types[frame_type].flags; + stream_id = frame_types[frame_type].stream_id; + pts_delta = frame_types[frame_type].pts_delta; + data_size_msb = 0; + reserved_count = frame_types[frame_type].reserved_count; + if (frame_flags & FLAG_CODED) { + value = read_var_restricted(); + printf(" coded_flags: %"PRIu64"\n", value); + frame_flags ^= value; + } + if (frame_flags & FLAG_INVALID) + error("frame type is invalid"); + if (frame_flags & FLAG_STREAM_ID) { + stream_id = read_var_restricted(); + printf(" stream_id: %"PRIu64"\n", stream_id); + if (stream_id >= stream_count) + error("invalid stream id"); + } + if (frame_flags & FLAG_CODED_PTS) { + coded_pts = read_var_restricted(); + printf(" coded_pts: %"PRIu64"\n", coded_pts); + } + if (frame_flags & FLAG_SIZE_MSB) { + data_size_msb = read_var_restricted(); + printf(" data_size_msb: %"PRIu64"\n", data_size_msb); + } + if (frame_flags & FLAG_RESERVED) { + reserved_count = read_var_restricted(); + printf(" reserved_count: %"PRIu64"\n", reserved_count); + } + for (; reserved_count > 0; --reserved_count) + printf(" reserved: %"PRIu64"\n", read_var_restricted()); + if (frame_flags & FLAG_CHECKSUM) { + actual_checksum = crc; + checksum = read_fixed(4); + printf(" checksum: 0x%08"PRIx32"\n", checksum); + if (checksum != actual_checksum) + error("invalid checksum"); + } + data_size = data_size_msb * frame_types[frame_type].data_size_mul + frame_types[frame_type].data_size_lsb; + printf(" frame:"); + if (frame_flags & FLAG_KEY) + printf(" key"); + if (frame_flags & FLAG_EOR) + printf(" eor"); + if (!(frame_flags & FLAG_STREAM_ID)) + printf(" stream_id: %"PRIu64, stream_id); + old_last_pts = streams[stream_id].last_pts; + if (!(frame_flags & FLAG_CODED_PTS)) + streams[stream_id].last_pts += frame_types[frame_type].pts_delta; + else if (coded_pts >= (1 << streams[stream_id].msb_pts_shift)) + streams[stream_id].last_pts = coded_pts - (1 << streams[stream_id].msb_pts_shift); + else { + unsigned int mask = (1 << streams[stream_id].msb_pts_shift) - 1; + int64_t delta = streams[stream_id].last_pts - mask / 2; + streams[stream_id].last_pts = ((coded_pts - delta) & mask) + delta; + } + printf(" pts: %"PRIi64" (%.3lf s)", streams[stream_id].last_pts, + time_in_s(streams[stream_id].last_pts, streams[stream_id].time_base_id)); + /* TODO: check pts monotoneness and other pts/dts constraints */ + printf(" data_size: %"PRIu64"\n", data_size_msb * frame_types[frame_type].data_size_mul + frame_types[frame_type].data_size_lsb); + if ((frame_flags & (FLAG_KEY | FLAG_EOR)) == FLAG_EOR) + error("eor frames must be key frames"); + if ((frame_flags & FLAG_EOR) && data_size) + error("eor frames must have zero size"); + if (!(frame_flags & FLAG_CHECKSUM)) { + if (data_size > 2 * max_distance) + error("large frame must have a checksum"); + if (ABS((int64_t)streams[stream_id].last_pts - (int64_t)old_last_pts) > streams[stream_id].max_pts_distance) + error("max_pts_distance exceeded without a checksum"); + } + for (; data_size > 0; --data_size) + read_byte(); +} + +int main(int argc, char *argv[]) +{ + static char short_options[] = "hV"; + static struct option long_options[] = { + {"help", 0, NULL, 'h'}, + {"version", 0, NULL, 'V'}, + {} + }; + int c; + + while ((c = getopt_long(argc, argv, short_options, + long_options, NULL)) != -1) { + switch (c) { + case 'h': + usage(); + return 0; + case 'V': + version(); + return 0; + default: + error("Try `nutparse --help' for more information."); + } + } + + if (argc - optind != 1) { + usage(); + return 1; + } + + input = fopen(argv[1], "rb"); + if (!input) + error("Cannot open %s: %s", argv[1], strerror(errno)); + + parse_file_id(); + for (;;) { + reset_checksum(); + c = fgetc(input); + if (c == EOF) + break; + ++file_position; + update_checksum(c); + if (c == 'N') + parse_packet(); + else + parse_frame(c); + } + + fclose(input); + return 0; +}
participants (1)
-
ods15