diff --git a/Makefile.in b/Makefile.in index d4de9e59d..2f58998d7 100644 --- a/Makefile.in +++ b/Makefile.in @@ -137,6 +137,7 @@ OBJS = @OBJS@ \ src/utils/sdp.o \ src/utils/synchronized_queue.o \ src/utils/thread.o \ + src/utils/time.o \ src/utils/vf_split.o \ src/utils/wait_obj.o \ src/utils/worker.o \ diff --git a/src/utils/time.c b/src/utils/time.c new file mode 100644 index 000000000..f4cbb326c --- /dev/null +++ b/src/utils/time.c @@ -0,0 +1,56 @@ +/** + * @file utils/time.h + * @author Martin Pulec + */ +/* + * Copyright (c) 2019 CESNET, z. s. p. o. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of CESNET nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#include "config_unix.h" +#include "config_win32.h" +#endif + +#include "utils/time.h" + +void format_time_ms(uint64_t ts, char *buf) { + int ms = ts % 1000; + ts /= 1000; + int s = ts % 60; + ts /= 60; + int m = ts % 60; + ts /= 60; + int h = ts % 100; // 99 max + + sprintf(buf, "%02d:%02d:%02d.%03d", h, m, s, ms); +} diff --git a/src/utils/time.h b/src/utils/time.h new file mode 100644 index 000000000..f3bda2c40 --- /dev/null +++ b/src/utils/time.h @@ -0,0 +1,63 @@ +/** + * @file utils/time.h + * @author Martin Pulec + * + * Time utility functions + */ +/* + * Copyright (c) 2019 CESNET, z. s. p. o. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, is permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of CESNET nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UTILS_TIME_H_ +#define UTILS_TIME_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + * Formats textual represenation of timestamp (in ms) in format HH:MM:SS.mmm + * (mmm is milliseconds). + * + * @param[in] ts timestamp in ms + * @param[out] buf output buffer (must be at least 13 B long) + */ +void format_time_ms(uint64_t ts, char *buf); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif// UTILS_TIME_H_ + diff --git a/src/video_capture/file.c b/src/video_capture/file.c index 252333103..5eb9e2863 100644 --- a/src/video_capture/file.c +++ b/src/video_capture/file.c @@ -42,6 +42,8 @@ /** * @todo * - selectable pixel format + * - audio-only input + * - regularly (every 30 s or so) write position in file (+ duration at the beginning) */ #ifdef HAVE_CONFIG_H @@ -68,6 +70,7 @@ #include "module.h" #include "utils/color_out.h" #include "utils/misc.h" +#include "utils/time.h" #include "video.h" #include "video_capture.h" #include "video_capture/import.h" // vidcap_import_register_keyboard_ctl @@ -187,8 +190,13 @@ static void vidcap_file_process_messages(struct vidcap_state_lavf_decoder *s) { if (strstr(msg->text, "seek ") != NULL) { const char *count_str = msg->text + strlen("seek "); int sec = atoi(count_str); - AVRational tb = s->fmt_ctx->streams[s->video_stream_idx]->time_base; - CHECK_FF(avformat_seek_file(s->fmt_ctx, s->video_stream_idx, INT64_MIN, s->fmt_ctx->streams[s->video_stream_idx]->start_time + s->last_vid_pts + sec * tb.den / tb.num, INT64_MAX, AVSEEK_FLAG_FRAME), {}); + AVStream *st = s->fmt_ctx->streams[s->video_stream_idx]; + AVRational tb = st->time_base; + CHECK_FF(avformat_seek_file(s->fmt_ctx, s->video_stream_idx, INT64_MIN, st->start_time + s->last_vid_pts + sec * tb.den / tb.num, INT64_MAX, AVSEEK_FLAG_FRAME), {}); + char position[13], duration[13]; + format_time_ms(s->last_vid_pts * tb.num * 1000 / tb.den + sec * 1000, position); + format_time_ms(st->duration * tb.num * 1000 / tb.den, duration); + log_msg(LOG_LEVEL_NOTICE, MOD_NAME "Seeking to %s / %s\n", position, duration); } else if (strcmp(msg->text, "pause") == 0) { s->paused = !s->paused; log_msg(LOG_LEVEL_NOTICE, MOD_NAME "%s\n", s->paused ? "paused" : "unpaused");