Skip to content

Commit

Permalink
cubicibo/MR/timegrid: Rewrite time handling to sample on frame grid
Browse files Browse the repository at this point in the history
The time unit is now the frame count and FPS rather than the integer ms frame duration.
  • Loading branch information
cubicibo committed Aug 27, 2023
2 parents 3982081 + 8d1f7c0 commit 32f73b4
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 36 deletions.
57 changes: 36 additions & 21 deletions ass2bdnxml.c
Original file line number Diff line number Diff line change
Expand Up @@ -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}
};

Expand Down Expand Up @@ -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)
{
Expand All @@ -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, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<BDN Version=\"0.93\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"BD-03-006-0093b BDN File Format.xsd\">\n"
Expand All @@ -116,15 +129,19 @@ void write_xml(eventlist_t *evlist, vfmt_t *vfmt, frate_t *frate,
" <Events LastEventOutTC=\"%s\" FirstEventInTC=\"%s\" ",
track_name, language, vfmt->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"
" </Description>\n"
" <Events>\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, " <Event Forced=\"False\" InTC=\"%s\" OutTC=\"%s\">\n",
buf_in, buf_out);
Expand Down Expand Up @@ -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);

Expand Down
15 changes: 12 additions & 3 deletions common.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
#include <stdint.h>

typedef struct BoundingBox_s {
int x1;
int x2;
int y1;
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;
Expand All @@ -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;
Expand All @@ -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);
53 changes: 41 additions & 12 deletions render.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand All @@ -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:
Expand All @@ -429,16 +453,21 @@ 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 = (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;

tm += offset;
if (offset == 0) {
offset = 1; //avoid deadlocks
}

frame_cnt += offset;
break;
}
}
Expand Down

0 comments on commit 32f73b4

Please sign in to comment.