Skip to content

Commit 716df2f

Browse files
committed
Work with frame copy instead of just modifying it
1 parent 77e960c commit 716df2f

File tree

5 files changed

+140
-73
lines changed

5 files changed

+140
-73
lines changed

docs/CHANGELOG.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
## Change log
22

3-
### 0.36.0-dev.4 (20251205)
3+
### 0.36.0-dev.5 (20251209)
4+
* Fix hinting
5+
* Fix ass_set_storage_size not be called
46
* Switch submodule build system to meson
57
* Update avisynth(plus) headers to v12
68
* Update libass to 0.17.4
79
* Unicode-safe file reading
810
* Add frame size parameters
911
* Add set_default_storage_size boolean
1012
* Use frame properties if they available for "YCbCr Matrix: None"
13+
* Work with frame copy instead of just modifying it
1114

1215
### 0.35 (20210304)
1316
* Windows MSVC: Update to libass v0.15
@@ -21,7 +24,7 @@
2124
* Fix: possible crash on initializing phase (buffer overread, linux crashed, Windows was just lucky)
2225

2326
### 0.34 (20210301)
24-
* Fix the fix: revert matrix change made in 0.33
27+
* Fix the fix: revert matrix change made in 0.33
2528
* Fix: Check matrix from .ASS file "YCbCr Matrix:" section besides "Video Colorspace:"
2629
Recognized values are "tv.601" and "tv.709"
2730

src/assrender.c

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,6 @@ static const char* detect_bom(const char* buf, const size_t bufsize) {
5757
return "UTF-8";
5858
}
5959

60-
#ifdef _WIN32
61-
#define WIN32_LEAN_AND_MEAN
62-
#include <windows.h>
63-
#else
64-
#include <sys/stat.h>
65-
#endif
66-
6760
#ifdef _WIN32
6861
static wchar_t *utf8_to_utf16le(const char *data) {
6962
const int out_size = MultiByteToWideChar(CP_UTF8, 0, data, -1, NULL, 0);
@@ -216,7 +209,6 @@ AVS_Value AVSC_CC assrender_create(AVS_ScriptEnvironment* env, AVS_Value args,
216209
AVS_FilterInfo* fi;
217210
AVS_Clip* c = avs_new_c_filter(env, &fi, avs_array_elt(args, 0), 1);
218211
const AVS_VideoInfo *vi = &fi->vi;
219-
char e[250];
220212

221213
const char* f = avs_as_string(avs_array_elt(args, 1));
222214
const char* vfr = avs_as_string(avs_array_elt(args, 2));
@@ -318,7 +310,7 @@ AVS_Value AVSC_CC assrender_create(AVS_ScriptEnvironment* env, AVS_Value args,
318310
if (!strcasecmp(strrchr(f, '.'), ".srt")) {
319311
FILE* fp = open_utf8_filename(f, "r");
320312
if (!fp) {
321-
sprintf(e, "AssRender: input file '%s' does not exist or is not a regular file", f);
313+
const char* e = avs_sprintf(env, "AssRender: input file '%s' does not exist or is not a regular file", f);
322314
v = avs_new_value_error(e);
323315
avs_release_clip(c);
324316
return v;
@@ -330,15 +322,15 @@ AVS_Value AVSC_CC assrender_create(AVS_ScriptEnvironment* env, AVS_Value args,
330322

331323
fp = open_utf8_filename(f, "rb");
332324
if (!fp) {
333-
sprintf(e, "AssRender: input file '%s' does not exist or is not a regular file", f);
325+
const char* e = avs_sprintf(env, "AssRender: input file '%s' does not exist or is not a regular file", f);
334326
v = avs_new_value_error(e);
335327
avs_release_clip(c);
336328
return v;
337329
}
338330

339331
buf = read_file_bytes(fp, &bufsize);
340332
if (!buf) {
341-
sprintf(e, "AssRender: unable to read '%s'", f);
333+
const char* e = avs_sprintf(env, "AssRender: unable to read '%s'", f);
342334
v = avs_new_value_error(e);
343335
avs_release_clip(c);
344336
return v;
@@ -358,7 +350,7 @@ AVS_Value AVSC_CC assrender_create(AVS_ScriptEnvironment* env, AVS_Value args,
358350
}
359351

360352
if (!ass) {
361-
sprintf(e, "AssRender: unable to parse '%s'", f);
353+
const char* e = avs_sprintf(env, "AssRender: unable to parse '%s'", f);
362354
v = avs_new_value_error(e);
363355
avs_release_clip(c);
364356
return v;
@@ -371,7 +363,7 @@ AVS_Value AVSC_CC assrender_create(AVS_ScriptEnvironment* env, AVS_Value args,
371363
FILE* fh = open_utf8_filename(vfr, "r");
372364

373365
if (!fh) {
374-
sprintf(e, "AssRender: could not read timecodes file '%s'", vfr);
366+
const char* e = avs_sprintf(env, "AssRender: could not read timecodes file '%s'", vfr);
375367
v = avs_new_value_error(e);
376368
avs_release_clip(c);
377369
return v;
@@ -380,7 +372,7 @@ AVS_Value AVSC_CC assrender_create(AVS_ScriptEnvironment* env, AVS_Value args,
380372
data->isvfr = 1;
381373

382374
if (fscanf(fh, "# timecode format v%d", &ver) != 1) {
383-
sprintf(e, "AssRender: invalid timecodes file '%s'", vfr);
375+
const char* e = avs_sprintf(env, "AssRender: invalid timecodes file '%s'", vfr);
384376
v = avs_new_value_error(e);
385377
avs_release_clip(c);
386378
return v;

src/assrender.h

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,42 +9,50 @@
99
#include <string.h>
1010
#include <time.h>
1111
#include <ass/ass.h>
12+
13+
#ifdef _WIN32
14+
# define WIN32_LEAN_AND_MEAN
15+
# include <windows.h>
16+
#else
17+
# include <sys/stat.h>
18+
#endif
19+
1220
#include "avs/config.h"
1321
#ifdef AVS_WINDOWS
14-
#include "avisynth_c.h"
22+
# include "avisynth_c.h"
1523
#else
16-
#include <avisynth/avisynth_c.h>
24+
# include <avisynth/avisynth_c.h>
1725
#endif
1826

1927
#if defined(_MSC_VER)
20-
#define __NO_ISOCEXT
21-
#define __NO_INLINE__
28+
# define __NO_ISOCEXT
29+
# define __NO_INLINE__
2230

23-
#define strcasecmp _stricmp
24-
#define atoll _atoi64
31+
# define strcasecmp _stricmp
32+
# define atoll _atoi64
2533
#endif
2634

2735
typedef struct {
28-
// premultiplied coefficients for integer scaled arithmetics
29-
int y_r, y_g, y_b;
30-
int u_r, u_g, u_b;
31-
int v_r, v_g, v_b;
32-
int offset_y;
33-
bool valid;
36+
// premultiplied coefficients for integer scaled arithmetics
37+
int y_r, y_g, y_b;
38+
int u_r, u_g, u_b;
39+
int v_r, v_g, v_b;
40+
int offset_y;
41+
bool valid;
3442
} ConversionMatrix;
3543

3644
typedef enum {
37-
MATRIX_NONE = 0,
38-
MATRIX_BT601,
39-
MATRIX_PC601,
40-
MATRIX_BT709,
41-
MATRIX_PC709,
42-
MATRIX_PC2020,
43-
MATRIX_BT2020,
44-
MATRIX_TVFCC,
45-
MATRIX_PCFCC,
46-
MATRIX_TV240M,
47-
MATRIX_PC240M
45+
MATRIX_NONE = 0,
46+
MATRIX_BT601,
47+
MATRIX_PC601,
48+
MATRIX_BT709,
49+
MATRIX_PC709,
50+
MATRIX_PC2020,
51+
MATRIX_BT2020,
52+
MATRIX_TVFCC,
53+
MATRIX_PCFCC,
54+
MATRIX_TV240M,
55+
MATRIX_PC240M
4856
} matrix_type;
4957

5058
typedef void (* fPixel)(uint8_t** sub_img, uint8_t** data, uint32_t* pitch, uint32_t width, uint32_t height);

src/include/avs/capi.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@
4343
#endif
4444

4545
#ifdef __cplusplus
46-
# define EXTERN_C extern "C"
46+
# define AVS_EXTERN_C extern "C"
4747
#else
48-
# define EXTERN_C
48+
# define AVS_EXTERN_C
4949
#endif
5050

5151
#ifdef AVS_WINDOWS
@@ -99,20 +99,20 @@
9999
# else
100100
# define AVSC_EXPORT
101101
# endif
102-
# define AVSC_API(ret, name) EXTERN_C AVSC_EXPORT ret AVSC_CC name
102+
# define AVSC_API(ret, name) AVS_EXTERN_C AVSC_EXPORT ret AVSC_CC name
103103
#else
104-
# define AVSC_EXPORT EXTERN_C
105-
# define AVSC_API(ret, name) EXTERN_C ret AVSC_CC name
104+
# define AVSC_EXPORT AVS_EXTERN_C
105+
# define AVSC_API(ret, name) AVS_EXTERN_C ret AVSC_CC name
106106
#endif
107107
#else
108-
# define AVSC_EXPORT EXTERN_C __declspec(dllexport)
108+
# define AVSC_EXPORT AVS_EXTERN_C __declspec(dllexport)
109109
# ifndef AVS_STATIC_LIB
110110
# define AVSC_IMPORT __declspec(dllimport)
111111
# else
112112
# define AVSC_IMPORT
113113
# endif
114114
# ifndef AVSC_NO_DECLSPEC
115-
# define AVSC_API(ret, name) EXTERN_C AVSC_IMPORT ret AVSC_CC name
115+
# define AVSC_API(ret, name) AVS_EXTERN_C AVSC_IMPORT ret AVSC_CC name
116116
# else
117117
# define AVSC_API(ret, name) typedef ret (AVSC_CC *name##_func)
118118
# endif

src/render.c

Lines changed: 91 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -893,58 +893,122 @@ AVS_VideoFrame* AVSC_CC assrender_get_frame(AVS_FilterInfo* p, int n)
893893
udata* ud = (udata*)p->user_data;
894894
ASS_Image* img;
895895
AVS_VideoFrame* src;
896-
896+
AVS_VideoFrame* dst;
897897
int64_t ts;
898898
int changed;
899899

900+
// 1) Get upstream frame
900901
src = avs_get_frame(p->child, n);
901902

902-
avs_make_writable(p->env, &src);
903+
// 2) Allocate a new writable destination frame
904+
dst = avs_new_video_frame_a(p->env, &p->vi, AVS_FRAME_ALIGN);
905+
if (!dst) {
906+
avs_release_video_frame(src);
907+
return 0;
908+
}
909+
910+
// 3) Copy src -> dst (real pixel copy), then free src
911+
912+
if (avs_is_planar(&p->vi)) {
913+
if (avs_is_rgb(&p->vi)) {
914+
// Planar RGB: R, G, B planes
915+
const int planes[3] = { AVS_PLANAR_R, AVS_PLANAR_G, AVS_PLANAR_B };
916+
for (int i = 0; i < 3; ++i) {
917+
const uint8_t* srcp = avs_get_read_ptr_p(src, planes[i]);
918+
int src_pitch = avs_get_pitch_p(src, planes[i]);
919+
uint8_t* dstp = avs_get_write_ptr_p(dst, planes[i]);
920+
int dst_pitch = avs_get_pitch_p(dst, planes[i]);
921+
int row_size = avs_get_row_size_p(src, planes[i]);
922+
int height = avs_get_height_p(src, planes[i]);
923+
avs_bit_blt(p->env, dstp, dst_pitch, srcp, src_pitch, row_size, height);
924+
}
925+
}
926+
else {
927+
// Planar YUV: Y, U, V planes
928+
const int planes[3] = { AVS_PLANAR_Y, AVS_PLANAR_U, AVS_PLANAR_V };
929+
for (int i = 0; i < 3; ++i) {
930+
const uint8_t* srcp = avs_get_read_ptr_p(src, planes[i]);
931+
int src_pitch = avs_get_pitch_p(src, planes[i]);
932+
uint8_t* dstp = avs_get_write_ptr_p(dst, planes[i]);
933+
int dst_pitch = avs_get_pitch_p(dst, planes[i]);
934+
int row_size = avs_get_row_size_p(src, planes[i]);
935+
int height = avs_get_height_p(src, planes[i]);
936+
avs_bit_blt(p->env, dstp, dst_pitch, srcp, src_pitch, row_size, height);
937+
}
938+
}
939+
}
940+
else {
941+
// Packed formats (e.g. RGB32, YUY2, etc.)
942+
const uint8_t* srcp = avs_get_read_ptr_p(src, AVS_DEFAULT_PLANE);
943+
int src_pitch = avs_get_pitch_p(src, AVS_DEFAULT_PLANE);
944+
uint8_t* dstp = avs_get_write_ptr_p(dst, AVS_DEFAULT_PLANE);
945+
int dst_pitch = avs_get_pitch_p(dst, AVS_DEFAULT_PLANE);
946+
int row_size = avs_get_row_size_p(src, AVS_DEFAULT_PLANE);
947+
int height = avs_get_height_p(src, AVS_DEFAULT_PLANE);
948+
avs_bit_blt(p->env, dstp, dst_pitch, srcp, src_pitch, row_size, height);
949+
}
903950

951+
// Original frame no longer needed locally
952+
avs_release_video_frame(src);
953+
954+
// 4) Compute timestamp for libass
904955
if (!ud->isvfr) {
905-
// its a casting party!
956+
// it's a casting party!
906957
ts = (int64_t)n * (int64_t)1000 * (int64_t)p->vi.fps_denominator / (int64_t)p->vi.fps_numerator;
907-
} else {
958+
}
959+
else {
908960
ts = ud->timestamp[n];
909961
}
910962

963+
// 5) Render ASS
911964
img = ass_render_frame(ud->ass_renderer, ud->ass, ts, &changed);
912965

913966
if (img) {
914-
uint32_t height, width, pitch[2];
967+
uint32_t width = p->vi.width;
968+
uint32_t height = p->vi.height;
915969
uint8_t* data[3];
970+
uint32_t pitch[2];
916971

972+
// 6) Build write pointers for the copied frame (dst)
917973
if (avs_is_planar(&p->vi) && !ud->greyscale) {
918-
if (avs_is_rgb(&p->vi)) {
919-
// planar RGB as 444
920-
data[0] = avs_get_write_ptr_p(src, AVS_PLANAR_R);
921-
data[1] = avs_get_write_ptr_p(src, AVS_PLANAR_G);
922-
data[2] = avs_get_write_ptr_p(src, AVS_PLANAR_B);
923-
pitch[0] = avs_get_pitch_p(src, AVS_DEFAULT_PLANE);
924-
}
925-
else {
926-
data[0] = avs_get_write_ptr_p(src, AVS_PLANAR_Y);
927-
data[1] = avs_get_write_ptr_p(src, AVS_PLANAR_U);
928-
data[2] = avs_get_write_ptr_p(src, AVS_PLANAR_V);
929-
pitch[0] = avs_get_pitch_p(src, AVS_PLANAR_Y);
930-
pitch[1] = avs_get_pitch_p(src, AVS_PLANAR_U);
931-
}
974+
if (avs_is_rgb(&p->vi)) {
975+
// planar RGB as 4:4:4
976+
data[0] = avs_get_write_ptr_p(dst, AVS_PLANAR_R);
977+
data[1] = avs_get_write_ptr_p(dst, AVS_PLANAR_G);
978+
data[2] = avs_get_write_ptr_p(dst, AVS_PLANAR_B);
979+
pitch[0] = avs_get_pitch_p(dst, AVS_DEFAULT_PLANE);
980+
}
981+
else {
982+
data[0] = avs_get_write_ptr_p(dst, AVS_PLANAR_Y);
983+
data[1] = avs_get_write_ptr_p(dst, AVS_PLANAR_U);
984+
data[2] = avs_get_write_ptr_p(dst, AVS_PLANAR_V);
985+
pitch[0] = avs_get_pitch_p(dst, AVS_PLANAR_Y);
986+
pitch[1] = avs_get_pitch_p(dst, AVS_PLANAR_U);
987+
}
932988
}
933989
else {
934-
data[0] = avs_get_write_ptr_p(src, AVS_DEFAULT_PLANE);
935-
pitch[0] = avs_get_pitch_p(src, AVS_DEFAULT_PLANE);
990+
data[0] = avs_get_write_ptr_p(dst, AVS_DEFAULT_PLANE);
991+
pitch[0] = avs_get_pitch_p(dst, AVS_DEFAULT_PLANE);
936992
}
937993

938-
height = p->vi.height;
939-
width = p->vi.width;
940-
994+
// 7) Rebuild cached subtitle bitmap if changed
941995
if (changed) {
942-
memset(ud->sub_img[0], 0x00, height * width * ud->pixelsize);
943-
ud->f_make_sub_img(img, ud->sub_img, width, ud->bits_per_pixel, ud->rgb_fullscale, &ud->mx);
996+
memset(ud->sub_img[0], 0, height * width * ud->pixelsize);
997+
ud->f_make_sub_img(
998+
img,
999+
ud->sub_img,
1000+
width,
1001+
ud->bits_per_pixel,
1002+
ud->rgb_fullscale,
1003+
&ud->mx
1004+
);
9441005
}
9451006

1007+
// 8) Blend ASS into the copied frame
9461008
ud->apply(ud->sub_img, data, pitch, width, height);
9471009
}
9481010

949-
return src;
1011+
// 9) Return the modified copy
1012+
return dst;
9501013
}
1014+

0 commit comments

Comments
 (0)