mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 20:21:24 +00:00
fix videoscale stride bugs
Original commit message from CVS: fix videoscale stride bugs
This commit is contained in:
parent
20ed00a9a0
commit
bf81a3702a
2 changed files with 94 additions and 55 deletions
16
ChangeLog
16
ChangeLog
|
@ -1,3 +1,19 @@
|
||||||
|
2004-07-26 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||||
|
|
||||||
|
* gst/videoscale/videoscale.c: (gst_videoscale_setup),
|
||||||
|
(gst_videoscale_planar411), (gst_videoscale_planar400),
|
||||||
|
(gst_videoscale_packed422), (gst_videoscale_packed422rev),
|
||||||
|
(gst_videoscale_scale_nearest_str1),
|
||||||
|
(gst_videoscale_scale_nearest_str2),
|
||||||
|
(gst_videoscale_scale_nearest_str4),
|
||||||
|
(gst_videoscale_scale_nearest_16bit),
|
||||||
|
(gst_videoscale_scale_nearest_24bit):
|
||||||
|
fixed stride issues
|
||||||
|
tested with 320x240 -> 321, 322, 324 x240
|
||||||
|
tested with YV12, I420, YUY2, UYVY
|
||||||
|
fixed packed422rev (don't think it could have worked before)
|
||||||
|
by testing with UYVY
|
||||||
|
|
||||||
2004-07-26 Benjamin Otte <otte@gnome.org>
|
2004-07-26 Benjamin Otte <otte@gnome.org>
|
||||||
|
|
||||||
* ext/lame/gstlame.c: (gst_lame_sink_link), (gst_lame_init),
|
* ext/lame/gstlame.c: (gst_lame_sink_link), (gst_lame_init),
|
||||||
|
|
|
@ -67,11 +67,14 @@ static void gst_videoscale_16bit (GstVideoscale * scale, unsigned char *dest,
|
||||||
unsigned char *src);
|
unsigned char *src);
|
||||||
|
|
||||||
static void gst_videoscale_scale_nearest_str1 (GstVideoscale * scale,
|
static void gst_videoscale_scale_nearest_str1 (GstVideoscale * scale,
|
||||||
unsigned char *dest, unsigned char *src, int sw, int sh, int dw, int dh);
|
unsigned char *dest, unsigned char *src, int sw, int sh, int ss, int dw,
|
||||||
|
int dh, int ds);
|
||||||
static void gst_videoscale_scale_nearest_str2 (GstVideoscale * scale,
|
static void gst_videoscale_scale_nearest_str2 (GstVideoscale * scale,
|
||||||
unsigned char *dest, unsigned char *src, int sw, int sh, int dw, int dh);
|
unsigned char *dest, unsigned char *src, int sw, int sh, int ss, int dw,
|
||||||
|
int dh, int ds);
|
||||||
static void gst_videoscale_scale_nearest_str4 (GstVideoscale * scale,
|
static void gst_videoscale_scale_nearest_str4 (GstVideoscale * scale,
|
||||||
unsigned char *dest, unsigned char *src, int sw, int sh, int dw, int dh);
|
unsigned char *dest, unsigned char *src, int sw, int sh, int ss, int dw,
|
||||||
|
int dh, int ds);
|
||||||
static void gst_videoscale_scale_nearest_16bit (GstVideoscale * scale,
|
static void gst_videoscale_scale_nearest_16bit (GstVideoscale * scale,
|
||||||
unsigned char *dest, unsigned char *src, int sw, int sh, int dw, int dh);
|
unsigned char *dest, unsigned char *src, int sw, int sh, int dw, int dh);
|
||||||
static void gst_videoscale_scale_nearest_24bit (GstVideoscale * scale,
|
static void gst_videoscale_scale_nearest_24bit (GstVideoscale * scale,
|
||||||
|
@ -289,25 +292,37 @@ gst_videoscale_planar411 (GstVideoscale * scale, unsigned char *dest,
|
||||||
int sh = scale->from_height;
|
int sh = scale->from_height;
|
||||||
int dw = scale->to_width;
|
int dw = scale->to_width;
|
||||||
int dh = scale->to_height;
|
int dh = scale->to_height;
|
||||||
|
int ss, ds; /* strides */
|
||||||
|
|
||||||
GST_LOG_OBJECT (scale, "scaling planar 4:1:1 %dx%d to %dx%d", sw, sh, dw, dh);
|
GST_LOG_OBJECT (scale, "scaling planar 4:1:1 %dx%d to %dx%d", sw, sh, dw, dh);
|
||||||
|
|
||||||
gst_videoscale_scale_nearest_str1 (scale, dest, src, sw, sh, dw, dh);
|
/* Y */
|
||||||
|
|
||||||
src += sw * sh;
|
ss = ROUND_UP_4 (sw);
|
||||||
dest += dw * dh;
|
ds = ROUND_UP_4 (dw);
|
||||||
|
|
||||||
dh = dh >> 1;
|
gst_videoscale_scale_nearest_str1 (scale, dest, src, sw, sh, ss, dw, dh, ds);
|
||||||
dw = dw >> 1;
|
|
||||||
sh = sh >> 1;
|
|
||||||
sw = sw >> 1;
|
|
||||||
|
|
||||||
gst_videoscale_scale_nearest_str1 (scale, dest, src, sw, sh, dw, dh);
|
src += ss * sh;
|
||||||
|
dest += ds * dh;
|
||||||
|
|
||||||
src += sw * sh;
|
/* Cb and Cr are 2x2, so divide widths and heights in half */
|
||||||
dest += dw * dh;
|
|
||||||
|
|
||||||
gst_videoscale_scale_nearest_str1 (scale, dest, src, sw, sh, dw, dh);
|
/* we want to round up, so we add 1 before shifting */
|
||||||
|
dh = (dh + 1) >> 1;
|
||||||
|
dw = (dw + 1) >> 1;
|
||||||
|
sh = (sh + 1) >> 1;
|
||||||
|
sw = (sw + 1) >> 1;
|
||||||
|
|
||||||
|
ss = ROUND_UP_4 (sw);
|
||||||
|
ds = ROUND_UP_4 (dw);
|
||||||
|
|
||||||
|
gst_videoscale_scale_nearest_str1 (scale, dest, src, sw, sh, ss, dw, dh, ds);
|
||||||
|
|
||||||
|
src += ss * sh;
|
||||||
|
dest += ds * dh;
|
||||||
|
|
||||||
|
gst_videoscale_scale_nearest_str1 (scale, dest, src, sw, sh, ss, dw, dh, ds);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -318,10 +333,13 @@ gst_videoscale_planar400 (GstVideoscale * scale, unsigned char *dest,
|
||||||
int sh = scale->from_height;
|
int sh = scale->from_height;
|
||||||
int dw = scale->to_width;
|
int dw = scale->to_width;
|
||||||
int dh = scale->to_height;
|
int dh = scale->to_height;
|
||||||
|
int ss, ds; /* strides */
|
||||||
|
|
||||||
GST_LOG_OBJECT (scale, "scaling Y-only %dx%d to %dx%d", sw, sh, dw, dh);
|
GST_LOG_OBJECT (scale, "scaling Y-only %dx%d to %dx%d", sw, sh, dw, dh);
|
||||||
|
|
||||||
gst_videoscale_scale_nearest_str1 (scale, dest, src, sw, sh, dw, dh);
|
ss = ROUND_UP_4 (sw);
|
||||||
|
ds = ROUND_UP_4 (dw);
|
||||||
|
gst_videoscale_scale_nearest_str1 (scale, dest, src, sw, sh, ss, dw, dh, ds);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -332,15 +350,20 @@ gst_videoscale_packed422 (GstVideoscale * scale, unsigned char *dest,
|
||||||
int sh = scale->from_height;
|
int sh = scale->from_height;
|
||||||
int dw = scale->to_width;
|
int dw = scale->to_width;
|
||||||
int dh = scale->to_height;
|
int dh = scale->to_height;
|
||||||
|
int ss, ds; /* strides */
|
||||||
|
|
||||||
GST_LOG_OBJECT (scale, "scaling 4:2:2 %dx%d to %dx%d", sw, sh, dw, dh);
|
GST_LOG_OBJECT (scale, "scaling 4:2:2 %dx%d to %dx%d", sw, sh, dw, dh);
|
||||||
|
|
||||||
gst_videoscale_scale_nearest_str2 (scale, dest, src, sw, sh, dw, dh);
|
/* Y */
|
||||||
gst_videoscale_scale_nearest_str4 (scale, dest + 1, src + 1, sw / 2, sh,
|
ss = ROUND_UP_4 (sw * 2);
|
||||||
dw / 2, dh);
|
ds = ROUND_UP_4 (dw * 2);
|
||||||
gst_videoscale_scale_nearest_str4 (scale, dest + 3, src + 3, sw / 2, sh,
|
gst_videoscale_scale_nearest_str2 (scale, dest, src, sw, sh, ss, dw, dh, ds);
|
||||||
dw / 2, dh);
|
|
||||||
|
|
||||||
|
/* Cb and Cr */
|
||||||
|
gst_videoscale_scale_nearest_str4 (scale, dest + 1, src + 1, sw / 2, sh, ss,
|
||||||
|
dw / 2, dh, ds);
|
||||||
|
gst_videoscale_scale_nearest_str4 (scale, dest + 3, src + 3, sw / 2, sh, ss,
|
||||||
|
dw / 2, dh, ds);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -351,15 +374,21 @@ gst_videoscale_packed422rev (GstVideoscale * scale, unsigned char *dest,
|
||||||
int sh = scale->from_height;
|
int sh = scale->from_height;
|
||||||
int dw = scale->to_width;
|
int dw = scale->to_width;
|
||||||
int dh = scale->to_height;
|
int dh = scale->to_height;
|
||||||
|
int ss, ds; /* strides */
|
||||||
|
|
||||||
GST_LOG_OBJECT (scale, "scaling 4:2:2 %dx%d to %dx%d", sw, sh, dw, dh);
|
GST_LOG_OBJECT (scale, "scaling 4:2:2 %dx%d to %dx%d", sw, sh, dw, dh);
|
||||||
|
|
||||||
gst_videoscale_scale_nearest_str2 (scale, dest + 1, src, sw, sh, dw, dh);
|
/* Y */
|
||||||
gst_videoscale_scale_nearest_str4 (scale, dest, src + 1, sw / 2, sh, dw / 2,
|
ss = ROUND_UP_4 (sw * 2);
|
||||||
dh);
|
ds = ROUND_UP_4 (dw * 2);
|
||||||
gst_videoscale_scale_nearest_str4 (scale, dest + 2, src + 3, sw / 2, sh,
|
gst_videoscale_scale_nearest_str2 (scale, dest + 1, src + 1, sw, sh, ss, dw,
|
||||||
dw / 2, dh);
|
dh, ds);
|
||||||
|
|
||||||
|
/* Cb and Cr */
|
||||||
|
gst_videoscale_scale_nearest_str4 (scale, dest, src, sw / 2, sh, ss,
|
||||||
|
dw / 2, dh, ds);
|
||||||
|
gst_videoscale_scale_nearest_str4 (scale, dest + 2, src + 2, sw / 2, sh, ss,
|
||||||
|
dw / 2, dh, ds);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -567,13 +596,13 @@ gst_videoscale_scale_point_sample (GstVideoscale * scale, unsigned char *src,
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_videoscale_scale_nearest_str1 (GstVideoscale * scale,
|
gst_videoscale_scale_nearest_str1 (GstVideoscale * scale,
|
||||||
unsigned char *dest, unsigned char *src, int sw, int sh, int dw, int dh)
|
unsigned char *dest, unsigned char *src, int sw, int sh, int ss,
|
||||||
|
int dw, int dh, int ds)
|
||||||
{
|
{
|
||||||
int ypos, yinc, y;
|
int ypos, yinc, y;
|
||||||
int xpos, xinc, x;
|
int xpos, xinc, x;
|
||||||
guchar *destp;
|
guchar *destp;
|
||||||
guchar *srcp;
|
guchar *srcp;
|
||||||
int sstride, dstride;
|
|
||||||
|
|
||||||
GST_LOG_OBJECT (scale, "scaling nearest from %p to %p with dest width %d",
|
GST_LOG_OBJECT (scale, "scaling nearest from %p to %p with dest width %d",
|
||||||
src, dest, dw);
|
src, dest, dw);
|
||||||
|
@ -581,12 +610,10 @@ gst_videoscale_scale_nearest_str1 (GstVideoscale * scale,
|
||||||
ypos = 0;
|
ypos = 0;
|
||||||
yinc = (sh << 16) / dh;
|
yinc = (sh << 16) / dh;
|
||||||
xinc = (sw << 16) / dw;
|
xinc = (sw << 16) / dw;
|
||||||
sstride = sw;
|
|
||||||
dstride = dw;
|
|
||||||
|
|
||||||
for (y = dh; y; y--) {
|
for (y = dh; y; y--) {
|
||||||
if (ypos >= 0x10000) {
|
if (ypos >= 0x10000) {
|
||||||
src += (ypos >> 16) * sstride;
|
src += (ypos >> 16) * ss;
|
||||||
ypos &= 0xffff;
|
ypos &= 0xffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -603,7 +630,7 @@ gst_videoscale_scale_nearest_str1 (GstVideoscale * scale,
|
||||||
*destp++ = *srcp;
|
*destp++ = *srcp;
|
||||||
xpos += xinc;
|
xpos += xinc;
|
||||||
}
|
}
|
||||||
dest += dstride;
|
dest += ds;
|
||||||
|
|
||||||
ypos += yinc;
|
ypos += yinc;
|
||||||
}
|
}
|
||||||
|
@ -611,13 +638,13 @@ gst_videoscale_scale_nearest_str1 (GstVideoscale * scale,
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_videoscale_scale_nearest_str2 (GstVideoscale * scale,
|
gst_videoscale_scale_nearest_str2 (GstVideoscale * scale,
|
||||||
unsigned char *dest, unsigned char *src, int sw, int sh, int dw, int dh)
|
unsigned char *dest, unsigned char *src, int sw, int sh, int ss,
|
||||||
|
int dw, int dh, int ds)
|
||||||
{
|
{
|
||||||
int ypos, yinc, y;
|
int ypos, yinc, y;
|
||||||
int xpos, xinc, x;
|
int xpos, xinc, x;
|
||||||
guchar *destp;
|
guchar *destp;
|
||||||
guchar *srcp;
|
guchar *srcp;
|
||||||
int sstride, dstride;
|
|
||||||
|
|
||||||
GST_LOG_OBJECT (scale, "scaling nearest from %p to %p with dest width %d",
|
GST_LOG_OBJECT (scale, "scaling nearest from %p to %p with dest width %d",
|
||||||
src, dest, dw);
|
src, dest, dw);
|
||||||
|
@ -625,13 +652,11 @@ gst_videoscale_scale_nearest_str2 (GstVideoscale * scale,
|
||||||
ypos = 0;
|
ypos = 0;
|
||||||
yinc = (sh << 16) / dh;
|
yinc = (sh << 16) / dh;
|
||||||
xinc = (sw << 16) / dw;
|
xinc = (sw << 16) / dw;
|
||||||
sstride = sw * 2;
|
|
||||||
dstride = dw * 2;
|
|
||||||
|
|
||||||
for (y = dh; y; y--) {
|
for (y = dh; y; y--) {
|
||||||
|
|
||||||
if (ypos >= 0x10000) {
|
if (ypos >= 0x10000) {
|
||||||
src += (ypos >> 16) * sstride;
|
src += (ypos >> 16) * ss;
|
||||||
ypos &= 0xffff;
|
ypos &= 0xffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -649,7 +674,7 @@ gst_videoscale_scale_nearest_str2 (GstVideoscale * scale,
|
||||||
destp += 2;
|
destp += 2;
|
||||||
xpos += xinc;
|
xpos += xinc;
|
||||||
}
|
}
|
||||||
dest += dstride;
|
dest += ds;
|
||||||
|
|
||||||
ypos += yinc;
|
ypos += yinc;
|
||||||
}
|
}
|
||||||
|
@ -657,13 +682,13 @@ gst_videoscale_scale_nearest_str2 (GstVideoscale * scale,
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_videoscale_scale_nearest_str4 (GstVideoscale * scale,
|
gst_videoscale_scale_nearest_str4 (GstVideoscale * scale,
|
||||||
unsigned char *dest, unsigned char *src, int sw, int sh, int dw, int dh)
|
unsigned char *dest, unsigned char *src, int sw, int sh, int ss,
|
||||||
|
int dw, int dh, int ds)
|
||||||
{
|
{
|
||||||
int ypos, yinc, y;
|
int ypos, yinc, y;
|
||||||
int xpos, xinc, x;
|
int xpos, xinc, x;
|
||||||
guchar *destp;
|
guchar *destp;
|
||||||
guchar *srcp;
|
guchar *srcp;
|
||||||
int sstride, dstride;
|
|
||||||
|
|
||||||
GST_LOG_OBJECT (scale, "scaling nearest from %p to %p with dest width %d",
|
GST_LOG_OBJECT (scale, "scaling nearest from %p to %p with dest width %d",
|
||||||
src, dest, dw);
|
src, dest, dw);
|
||||||
|
@ -671,13 +696,11 @@ gst_videoscale_scale_nearest_str4 (GstVideoscale * scale,
|
||||||
ypos = 0;
|
ypos = 0;
|
||||||
yinc = (sh << 16) / dh;
|
yinc = (sh << 16) / dh;
|
||||||
xinc = (sw << 16) / dw;
|
xinc = (sw << 16) / dw;
|
||||||
sstride = sw * 4;
|
|
||||||
dstride = dw * 4;
|
|
||||||
|
|
||||||
for (y = dh; y; y--) {
|
for (y = dh; y; y--) {
|
||||||
|
|
||||||
if (ypos >= 0x10000) {
|
if (ypos >= 0x10000) {
|
||||||
src += (ypos >> 16) * sstride;
|
src += (ypos >> 16) * ss;
|
||||||
ypos &= 0xffff;
|
ypos &= 0xffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -695,7 +718,7 @@ gst_videoscale_scale_nearest_str4 (GstVideoscale * scale,
|
||||||
destp += 4;
|
destp += 4;
|
||||||
xpos += xinc;
|
xpos += xinc;
|
||||||
}
|
}
|
||||||
dest += dstride;
|
dest += ds;
|
||||||
|
|
||||||
ypos += yinc;
|
ypos += yinc;
|
||||||
}
|
}
|
||||||
|
@ -709,19 +732,19 @@ gst_videoscale_scale_nearest_16bit (GstVideoscale * scale,
|
||||||
int xpos, xinc, x;
|
int xpos, xinc, x;
|
||||||
guchar *destp;
|
guchar *destp;
|
||||||
guchar *srcp;
|
guchar *srcp;
|
||||||
int sstride, dstride; /* row strides in bytes */
|
int ss, ds; /* row strides in bytes */
|
||||||
|
|
||||||
GST_LOG_OBJECT (scale, "scaling nearest from %p to %p, destination width %d",
|
GST_LOG_OBJECT (scale, "scaling nearest from %p to %p, destination width %d",
|
||||||
src, dest, dw);
|
src, dest, dw);
|
||||||
|
|
||||||
/* FIXME: strides should be gotten from caps; for now we do it Just Like
|
/* FIXME: strides should be gotten from caps; for now we do it Just Like
|
||||||
videotestsrc, which means round off to next multiple of 4 bytes */
|
videotestsrc, which means round off to next multiple of 4 bytes */
|
||||||
sstride = sw * 2;
|
ss = sw * 2;
|
||||||
if (sw % 2 == 1)
|
if (sw % 2 == 1)
|
||||||
sstride += 2;
|
ss += 2;
|
||||||
dstride = dw * 2;
|
ds = dw * 2;
|
||||||
if (dw % 2 == 1)
|
if (dw % 2 == 1)
|
||||||
dstride += 2;
|
ds += 2;
|
||||||
|
|
||||||
ypos = 0;
|
ypos = 0;
|
||||||
yinc = (sh << 16) / dh; /* 16 bit fixed point arithmetic */
|
yinc = (sh << 16) / dh; /* 16 bit fixed point arithmetic */
|
||||||
|
@ -731,7 +754,7 @@ gst_videoscale_scale_nearest_16bit (GstVideoscale * scale,
|
||||||
for (y = dh; y; y--) { /* faster than 0 .. dh */
|
for (y = dh; y; y--) { /* faster than 0 .. dh */
|
||||||
|
|
||||||
if (ypos >= 0x10000) { /* ypos >= 1 ? */
|
if (ypos >= 0x10000) { /* ypos >= 1 ? */
|
||||||
src += (ypos >> 16) * sstride; /* go down round(ypos) src lines */
|
src += (ypos >> 16) * ss; /* go down round(ypos) src lines */
|
||||||
ypos &= 0xffff; /* ypos %= 1 */
|
ypos &= 0xffff; /* ypos %= 1 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -751,7 +774,7 @@ gst_videoscale_scale_nearest_16bit (GstVideoscale * scale,
|
||||||
destp += 2; /* go right one destination pixel */
|
destp += 2; /* go right one destination pixel */
|
||||||
xpos += xinc;
|
xpos += xinc;
|
||||||
}
|
}
|
||||||
dest += dstride; /* go down one destination line */
|
dest += ds; /* go down one destination line */
|
||||||
|
|
||||||
ypos += yinc;
|
ypos += yinc;
|
||||||
}
|
}
|
||||||
|
@ -765,14 +788,14 @@ gst_videoscale_scale_nearest_24bit (GstVideoscale * scale,
|
||||||
int xpos, xinc, x;
|
int xpos, xinc, x;
|
||||||
guchar *destp;
|
guchar *destp;
|
||||||
guchar *srcp;
|
guchar *srcp;
|
||||||
int sstride, dstride; /* row strides in bytes */
|
int ss, ds; /* row strides in bytes */
|
||||||
|
|
||||||
GST_LOG_OBJECT (scale, "scaling nearest %p %p %d", src, dest, dw);
|
GST_LOG_OBJECT (scale, "scaling nearest %p %p %d", src, dest, dw);
|
||||||
|
|
||||||
/* FIXME: strides should be gotten from caps; for now we do it Just Like
|
/* FIXME: strides should be gotten from caps; for now we do it Just Like
|
||||||
videotestsrc, which means round off to next multiple of 4 bytes */
|
videotestsrc, which means round off to next multiple of 4 bytes */
|
||||||
sstride = ROUND_UP_4 (sw * 3);
|
ss = ROUND_UP_4 (sw * 3);
|
||||||
dstride = ROUND_UP_4 (dw * 3);
|
ds = ROUND_UP_4 (dw * 3);
|
||||||
|
|
||||||
ypos = 0;
|
ypos = 0;
|
||||||
yinc = (sh << 16) / dh;
|
yinc = (sh << 16) / dh;
|
||||||
|
@ -781,7 +804,7 @@ gst_videoscale_scale_nearest_24bit (GstVideoscale * scale,
|
||||||
for (y = dh; y; y--) {
|
for (y = dh; y; y--) {
|
||||||
|
|
||||||
if (ypos >= 0x10000) {
|
if (ypos >= 0x10000) {
|
||||||
src += (ypos >> 16) * sstride;
|
src += (ypos >> 16) * ss;
|
||||||
ypos &= 0xffff;
|
ypos &= 0xffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -801,7 +824,7 @@ gst_videoscale_scale_nearest_24bit (GstVideoscale * scale,
|
||||||
destp += 3;
|
destp += 3;
|
||||||
xpos += xinc;
|
xpos += xinc;
|
||||||
}
|
}
|
||||||
dest += dstride;
|
dest += ds;
|
||||||
|
|
||||||
ypos += yinc;
|
ypos += yinc;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue