diff --git a/inc/lektor/mkv.h b/inc/lektor/mkv.h index 5474ee6c1d117ac644d4fe800275baafd409fbcb..692b9f7d312bbbfecf82f7e122ae58c5d0f4b412 100644 --- a/inc/lektor/mkv.h +++ b/inc/lektor/mkv.h @@ -47,6 +47,10 @@ struct kara { Returns 0 on success and -1 on error. */ int kara_metadata_read(struct kara_metadata *dst, const char *filename); +/* Reads the duration of the .mkv file `filename`. Returns 0 on success + and -1 on error. */ +int kara_read_length(size_t *len, const char *filename); + /* Write metadata to a mkv file. Returns 0 on success and -1 on error */ int kara_metadata_write(struct kara_metadata *mdt, const char *filename, const char *mkvpropedit); diff --git a/meson.build b/meson.build index 35025c615e71dce5be66caf643af2d3a8320b8a1..7426181a76d25e858895eb95cd645993b77a44fe 100644 --- a/meson.build +++ b/meson.build @@ -166,6 +166,12 @@ lkt = executable( 'lkt' , include_directories: includes , install: true ) +debug = executable( 'lkt-debug' + , files('src/main/debug.c') + , include_directories: includes + , dependencies: [ bin_deps ] + ) + # Man pages man_sh = find_program('scripts/man.sh') man_header = run_command('realpath', 'doc/header').stdout().strip() diff --git a/src/main/debug.c b/src/main/debug.c new file mode 100644 index 0000000000000000000000000000000000000000..88680a3fa26a468655c4af29f857181fbf1669e6 --- /dev/null +++ b/src/main/debug.c @@ -0,0 +1,17 @@ +#include <lektor/mkv.h> +#include <stdio.h> + +int +main(int argc, char **argv) +{ + size_t len = 0; + + if (argc != 2) + return 1; + + if (kara_read_length(&len, argv[1]) < 0) + return 2; + + printf("Kara length: %ld\n", len); + return 0; +} diff --git a/src/mkv/mkv.c b/src/mkv/mkv.c index e7c10bb36c79420537f48754cb7246f8c913017e..5d083f4a2cdbeb6dccdea3a6081b1b3bde4b50d6 100644 --- a/src/mkv/mkv.c +++ b/src/mkv/mkv.c @@ -7,6 +7,7 @@ #include <string.h> #include <strings.h> #include <unistd.h> +#include <errno.h> #include <common/bufferfd.h> #include <lektor/mkv.h> @@ -401,7 +402,7 @@ mkv_read_tag(struct bufferfd *bf, struct mkv_tag *res) } static ssize_t -mkv_seek_tags(struct bufferfd *bf, size_t header_len) +mkv_seek(struct bufferfd *bf, size_t header_len, size_t what) { uint64_t seekhead_len; @@ -430,7 +431,7 @@ mkv_seek_tags(struct bufferfd *bf, size_t header_len) seekhead_len -= n; - if (eid == EBML_MKV_SEEK && s.id == EBML_MKV_TAGS) + if (eid == EBML_MKV_SEEK && s.id == what) return bufferfd_seek(bf, s.pos + header_len); } @@ -497,17 +498,113 @@ kara_read_tags(struct bufferfd *bf, struct kara_metadata *dst) return 0; } +static int +kara_read_segment(struct bufferfd *bf, size_t *len) +{ + /* TODO: Read correct elements, Duration and TimestampScale, + the result will be `*len = Duration * TimestampScale`. */ + uint64_t data_len; + + if (mkv_read_element_length(bf, &data_len) < 0) + return -1; + + while (data_len > 0) { + ssize_t n; + uint32_t eid; + uint64_t elen; + + if ((n = mkv_read_element_id(bf, &eid)) < 0 || eid != EBML_MKV_SEGMENT) + return -1; + + data_len -= n; + + if ((n = mkv_read_element_length(bf, &elen)) < 0) + return -1; + + data_len -= n; + + /* Find what we need */ + + if (eid == EBML_MKV_SEG_DURATION || + eid == EBML_MKV_SEG_TS_SCALE) { + switch (*len) { + case 0: + *len = 1; + /* Fallthrough */ + default: + printf("Len: %ld\n", n); + *len *= 1; + } + } + } + + return 0; +} + +int +kara_read_length(size_t *len, const char *filename) +{ + errno = 0; + int status_code = -1; + struct bufferfd file = { + .len = 0, + .pos = 0, + .fd = open(filename, O_RDONLY), + }; + + if (file.fd < 0) { + LOG_ERROR("MKV", "Faield to open file '%s': %s", + filename, strerror(errno)); + return -1; + } + + uint32_t eid; + uint64_t elength; + ssize_t header_len = mkv_skip_header(&file); + + if (header_len < 0) + goto error; + + *len = 0; + + for (;;) { + if (mkv_read_element_id(&file, &eid) < 0) + goto error; + + if (eid == EBML_MKV_SEEKHEAD) { + if (mkv_seek(&file, (size_t) header_len, (size_t) EBML_MKV_SEGMENT) < 0) + goto error; + } else if (eid == EBML_MKV_SEGMENT) { + if (kara_read_segment(&file, len) < 0) + goto error; + break; + } else { + if (mkv_read_element_length(&file, &elength) < 0) + goto error; + if (bufferfd_skip(&file, elength) < 0) + goto error; + } + } + + status_code = 0; +error: + close(file.fd); + return status_code; +} + int kara_metadata_read(struct kara_metadata *dst, const char *filename) { int status_code = -1; struct bufferfd file; + errno = 0; file.len = 0; file.pos = 0; file.fd = open(filename, O_RDONLY); if (file.fd < 0) { - perror("Failed to open file"); + LOG_ERROR("MKV", "Failed to open file '%s': %s", + filename, strerror(errno)); return -1; } @@ -525,7 +622,7 @@ kara_metadata_read(struct kara_metadata *dst, const char *filename) goto error; if (eid == EBML_MKV_SEEKHEAD) { - if (mkv_seek_tags(&file, (size_t) header_len) < 0) + if (mkv_seek(&file, (size_t) header_len, (size_t) EBML_MKV_TAGS) < 0) goto error; } else if (eid == EBML_MKV_TAGS) { if (kara_read_tags(&file, dst) < 0)