From ae028766593cc951cc6e370395ba24371a8557e3 Mon Sep 17 00:00:00 2001 From: Kubat <mael.martin31@gmail.com> Date: Mon, 18 May 2020 18:38:31 +0200 Subject: [PATCH] First try to get duration from a kara (WIP) --- inc/lektor/mkv.h | 4 ++ meson.build | 6 +++ src/main/debug.c | 17 ++++++++ src/mkv/mkv.c | 105 +++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 src/main/debug.c diff --git a/inc/lektor/mkv.h b/inc/lektor/mkv.h index 5474ee6c..692b9f7d 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 35025c61..7426181a 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 00000000..88680a3f --- /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 e7c10bb3..5d083f4a 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) -- GitLab