From f9e31522001c97fb85ed2f9fc00ffe8fc4fe8350 Mon Sep 17 00:00:00 2001 From: cubicibo <55701024+cubicibo@users.noreply.github.com> Date: Sat, 26 Aug 2023 23:41:50 +0200 Subject: [PATCH 1/2] Try to sample on the frame grid. --- ass2bdnxml.c | 57 +++++++++++++++++++++++++++++++++------------------- common.h | 15 +++++++++++--- render.c | 48 ++++++++++++++++++++++++++++++++----------- 3 files changed, 84 insertions(+), 36 deletions(-) diff --git a/ass2bdnxml.c b/ass2bdnxml.c index 16fe3ba..000d01f 100644 --- a/ass2bdnxml.c +++ b/ass2bdnxml.c @@ -23,19 +23,13 @@ #include "common.h" -typedef struct frate_s { - char *name; - int rate; - double frame_dur; -} frate_t; - frate_t frates[] = { - {"23.976", 24, 1000.0 / (24000.0 / 1001.0)}, - {"24", 24, 1000.0 / (24.0 / 1.0)}, - {"25", 25, 1000.0 / (25.0 / 1.0)}, - {"29.97", 30, 1000.0 / (30000.0 / 1001.0)}, - {"50", 50, 1000.0 / (50.0 / 1.0)}, - {"59.94", 60, 1000.0 / (60000.0 / 1001.0)}, + {"23.976",24, 1000.0 / (24000.0 / 1001.0), 24000, 1001}, + {"24", 24, 1000.0 / (24.0 / 1.0), 24, 1}, + {"25", 25, 1000.0 / (25.0 / 1.0), 25, 1}, + {"29.97", 30, 1000.0 / (30000.0 / 1001.0), 30000, 1001}, + {"50", 50, 1000.0 / (50.0 / 1.0), 50, 1}, + {"59.94", 60, 1000.0 / (60000.0 / 1001.0), 60000, 1001}, {NULL, 0, 0} }; @@ -88,6 +82,24 @@ void mktc(int tc, int fps, char *buf) } } +static void frame_to_tc(uint64_t frames, frate_t *fps, char *buf) +{ + frames--; + uint8_t frame = frames % fps->rate; + uint64_t ts = frames/fps->rate; + uint8_t sec = ts % 60; + ts /= 60; + uint8_t m = ts % 60; + ts /= 60; + if (ts > 99) { + fprintf(stderr, "timestamp overflow (more than 99 hours).\n"); + exit(1); + } else if (snprintf(buf, 12, "%02d:%02d:%02d:%02d", (uint8_t)ts, m, sec, frame) != 11) { + fprintf(stderr, "Timecode lead to invalid format: %s\n", buf); + exit(1); + } +} + void write_xml(eventlist_t *evlist, vfmt_t *vfmt, frate_t *frate, char *track_name, char *language, opts_t *args) { @@ -103,9 +115,10 @@ void write_xml(eventlist_t *evlist, vfmt_t *vfmt, frate_t *frate, exit(1); } - mktc(evlist->events[0]->in / frate->frame_dur, frate->rate, buf_in); - mktc(evlist->events[evlist->nmemb - 1]->out / frate->frame_dur, - frate->rate, buf_out); + //mktc(evlist->events[0]->in / frate->frame_dur, frate->rate, buf_in); + //mktc(evlist->events[evlist->nmemb - 1]->out / frate->frame_dur, frate->rate, buf_out); + frame_to_tc(evlist->events[0]->in, frate, buf_in); + frame_to_tc(evlist->events[evlist->nmemb - 1]->out, frate, buf_out); fprintf(of, "\n" "\n" @@ -116,15 +129,19 @@ void write_xml(eventlist_t *evlist, vfmt_t *vfmt, frate_t *frate, " name, frate->name, buf_out, buf_in); - mktc(0, frate->rate, buf_in); + //mktc(0, frate->rate, buf_in); + frame_to_tc(1, frate, buf_in); + fprintf(of, "ContentInTC=\"%s\" ContentOutTC=\"%s\" NumberofEvents=\"%d\" Type=\"Graphic\"/>\n" " \n" " \n", buf_in, buf_out, evlist->nmemb); for (i = 0; i < evlist->nmemb; i++) { image_t *img = evlist->events[i]; - mktc(img->in / frate->frame_dur, frate->rate, buf_in); - mktc(img->out / frate->frame_dur, frate->rate, buf_out); + frame_to_tc(img->in, frate, buf_in); + frame_to_tc(img->out, frate, buf_out); + //mktc(img->in / frate->frame_dur, frate->rate, buf_in); + //mktc(img->out / frate->frame_dur, frate->rate, buf_out); fprintf(of, " \n", buf_in, buf_out); @@ -313,9 +330,7 @@ int main(int argc, char *argv[]) } } - args.fps = frate->rate; - - evlist = render_subs(subfile, rint(frate->frame_dur), &args); + evlist = render_subs(subfile, frate, &args); write_xml(evlist, vfmt, frate, track_name, language, &args); diff --git a/common.h b/common.h index d6ad909..801c871 100644 --- a/common.h +++ b/common.h @@ -1,3 +1,5 @@ +#include + typedef struct BoundingBox_s { int x1; int x2; @@ -5,10 +7,18 @@ typedef struct BoundingBox_s { int y2; } BoundingBox_t; +typedef struct frate_s { + char *name; + int rate; + double frame_dur; + uint64_t num; + uint64_t denom; +} frate_t; + typedef struct image_s { int width, height, stride, dvd_mode; int subx1, suby1, subx2, suby2; - long long in, out; + uint64_t in, out; BoundingBox_t crops[2]; uint8_t *buffer; } image_t; @@ -20,7 +30,6 @@ typedef struct eventlist_s { typedef struct opts_s { double par; - int fps; int frame_w; int frame_h; int render_w; @@ -33,4 +42,4 @@ typedef struct opts_s { const char *fontdir; } opts_t; -eventlist_t *render_subs(char *subfile, int frame_d, opts_t *args); +eventlist_t *render_subs(char *subfile, frate_t *frate, opts_t *args); diff --git a/render.c b/render.c index 61d7dbb..0758468 100644 --- a/render.c +++ b/render.c @@ -10,6 +10,13 @@ #define MIN(a,b) ((a) > (b) ? (b) : (a)) #define BOX_AREA(box) ((box.x2-box.x1)*(box.y2-box.y1)) +typedef enum SamplingFlag_s { + SAMPLE_TC_IN = 0, + SAMPLE_TC_OUT, + SAMPLE_TC_MID, + INVALID_SAMPLING +} SamplingFlag_t; + ASS_Library *ass_library; ASS_Renderer *ass_renderer; @@ -357,35 +364,52 @@ static int find_split(image_t *frame) return best_score < (uint32_t)(-1); } -static int get_frame(ASS_Renderer *renderer, ASS_Track *track, image_t *frame, - long long time, int frame_d) +static uint64_t frame_to_realtime_ms(uint64_t frame_cnt, frate_t *frate, SamplingFlag_t flag) +{ + if (flag == SAMPLE_TC_OUT) { + return (uint64_t)floor((1000 * frame_cnt * frate->denom)/(double)frate->num); + } else if (flag == SAMPLE_TC_IN) { + return (uint64_t)ceil((1000*(frame_cnt - 1) * frate->denom)/(double)frate->num); + } else if (flag == SAMPLE_TC_MID) { + return (uint64_t)round(((1000*frame_cnt * frate->denom)/frate->num) - (500*frate->denom)/frate->num); + } + fprintf(stderr, "Invalid sampling flag.\n"); + exit(1); +} + +static int get_frame(ASS_Renderer *renderer, ASS_Track *track, + image_t *frame, uint64_t frame_cnt, frate_t *frate) { int changed; - ASS_Image *img = ass_render_frame(renderer, track, time, &changed); + + uint64_t ms = frame_to_realtime_ms(frame_cnt, frate, SAMPLE_TC_MID); + ASS_Image *img = ass_render_frame(renderer, track, ms, &changed); if (changed && img) { - frame->out = time + frame_d; + frame->out = frame_cnt + 1; blend(frame, img); - frame->in = time; + frame->in = frame_cnt; if (frame->subx1 == -1 || frame->suby1 == -1) return 2; return 3; } else if (!changed && img) { - frame->out = time + frame_d; + ++frame->out; return 1; } else { return 0; } } -eventlist_t *render_subs(char *subfile, int frame_d, opts_t *args) +eventlist_t *render_subs(char *subfile, frate_t *frate, opts_t *args) { long long tm = 0; int count = 0, fres = 0; int img_cnt; + uint64_t frame_cnt = 1; + eventlist_t *evlist = calloc(1, sizeof(eventlist_t)); init(args); @@ -403,7 +427,7 @@ eventlist_t *render_subs(char *subfile, int frame_d, opts_t *args) eventlist_set(evlist, frame, count - 1); } - fres = get_frame(ass_renderer, track, frame, tm, frame_d); + fres = get_frame(ass_renderer, track, frame, frame_cnt, frate); switch (fres) { case 3: @@ -429,16 +453,16 @@ eventlist_t *render_subs(char *subfile, int frame_d, opts_t *args) /* fall through */ case 2: case 1: - tm += frame_d; + ++frame_cnt; break; case 0: { - long long offset = ass_step_sub(track, tm, 1); + tm = frame_to_realtime_ms(frame_cnt, frate, SAMPLE_TC_MID); + uint64_t offset = ass_step_sub(track, tm, 1); + ++frame_cnt; if (tm && !offset) goto finish; - - tm += offset; break; } } From 8d1f7c02c3f995a2b394ce84b3d810d61fb3ea60 Mon Sep 17 00:00:00 2001 From: cubicibo <55701024+cubicibo@users.noreply.github.com> Date: Sun, 27 Aug 2023 11:29:57 +0200 Subject: [PATCH 2/2] Add event seek while remaining on the frame grid. --- render.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/render.c b/render.c index 0758468..486fe63 100644 --- a/render.c +++ b/render.c @@ -457,12 +457,17 @@ eventlist_t *render_subs(char *subfile, frate_t *frate, opts_t *args) break; case 0: { - tm = frame_to_realtime_ms(frame_cnt, frate, SAMPLE_TC_MID); - uint64_t offset = ass_step_sub(track, tm, 1); - ++frame_cnt; + tm = (uint64_t)ass_step_sub(track, frame_to_realtime_ms(frame_cnt, frate, SAMPLE_TC_MID), 1); + uint64_t offset = (tm*frate->rate)/1000; - if (tm && !offset) + if (!tm && frame_cnt > 1) goto finish; + + if (offset == 0) { + offset = 1; //avoid deadlocks + } + + frame_cnt += offset; break; } }