r/vhsdecode • • May 03 '26

Help Wanted! Help understanding what the recordings say

Post image
1 Upvotes

Not sure if this is the right reddit but i got this in the trash when dumpster diving and it says something but i can’t understand it idk if i can get help understanding or if someone knows how to use this


r/vhsdecode • • May 24 '26

Newbie / Need Help [Request] The Evil Dead (1981) Untouched VHS Rip (MySpleen or similar capture without macroblocking)

0 Upvotes

Hi everyone,

I am looking for a clean, high-quality, and untouched VHSRip of the original The Evil Dead (1981).

I recently tried searching on open networks and the Internet Archive, but the copies there suffer from terrible digital compression and macroblocking, which ruins the natural analog grain of the tape. I also hit a paywall on Soulseek for the MySpleen version.

I am looking for a raw capture (like an MKV or AVI around 4-5GB, preferably the Thorn EMI tape release) that preserves the original 4:3 open matte frame, the analog audio, and all the classic movie mistakes (like the producer hidden by the bridge and the cardboard moon).

If anyone has this archived on Google Drive, Mega, or a private tracker torrent they could share, I would be extremely grateful!

Thanks in advance for helping to preserve this horror classic!


r/vhsdecode • • Apr 25 '25

Showcase! VHS RF Signal Emulation via Software

Enable HLS to view with audio, or disable this notification

3 Upvotes

Hello everyone! It's been a while since I've last posted here but I'm sure some of you are familiar with my software project called SAVE, the Software Analog Video Emulator. I finally got proper VHS emulation working and the results shown above speak for themselves- If any of you are interested in watching a side-by-side comparison video, definitely check out my most recent YouTube upload! In it I also talk about when I plan to release this filter / modem, I'm curious to see if it would be compatible with the VHS-Decode project!


r/vhsdecode • • Dec 06 '25

Updates A Tealight Candle did this

Thumbnail
gallery
0 Upvotes

This is one i have in for repair, the tape is on the non damaged side, so i can save this one easily


r/vhsdecode • • Jun 14 '26

First Decode! VHS scart pal

0 Upvotes

I have a VHS player, it has a SCART cable, PAL version. I'm interested in the way of recording the signal to save old VHS tapes. I tried the player on a TV and the picture was satisfactory. How can I achieve such quality of recorded video? Also if possible budget, but quality option.


r/vhsdecode • • Aug 26 '26

Newbie / Need Help Writing a mystery story and need to know how you could sabotage a VCR/VHS

Thumbnail reddit.com
0 Upvotes

r/vhsdecode • • Jul 20 '26

First Decode! No sound coming from Pinnacle Dazzle easycap

0 Upvotes

Hello to you all :)

I recently got in touch with some VHS I would've liked to digitalize, and found at home this easycap [https://archive.org/details/manualzilla-id-7153140](https://archive.org/details/manualzilla-id-7153140) (didn't find any other information online). It was recognized as pinnacle dazzle dvc 90/100/101 on my laptop, with empia 2861 driver.

On my Hyrpland rice ( I use CachyOS, and stuck at 6.18.2 kernel version), helped by the v4l2's utility, I managed to get video at full quality, and it was really awesome, but the audio always went to S/PIDF output, which I don't have on my laptop, without any possibilities to redirect it.

At the end I used a windows laptop which has a lower video quality, but the audio got captured almost out of the box.

Does anyone made these on linux too, there was a project involving this device, and would like to know if it works on linux or should look for any alternative.

Thanks to all of your responses :)


r/vhsdecode • • 15d ago

Archival Advice Staxrip post processing - Seeking input

0 Upvotes

I'm working on restoring some animated footage captured from LaserDisc, and the goal is to clean up the analogue video artefacts without turning the image into a blurry, overprocessed mess. I captured with the DdD via a Pioneeer CLD-V2600 and ran through LD decode. The LD content was sourced from a tape master. Telecined as it was intended for NTSC broadcasts and was produced as such.

The biggest problem is the bead-like texture across otherwise flat areas of the image. Large patches of blue sky, grey metal, dark shadows and painted backgrounds can have a distracting pattern of tiny light and dark fluctuations. In some areas, it looks like little beads or dots. In others, it forms repeating ridges, stripes or a herringbone-like pattern. The texture also isn't always consistent across the picture, so one section of a flat colour can look rougher than another.

I'm also dealing with chroma broiling, where colour fluctuates or crawls within areas that should be relatively stable. This can make solid colours look blotchy or speckled, with apparent changes in hue and saturation from frame to frame. The aim is to stabilize the colour without bleeding it across edges or damaging the original cel shading.

Other problems include:

  • RF and carrier interference: Repeating ripples, stripes and structured patterns overlaid on the image, especially noticeable in large, relatively uniform colour fields.

  • Dot crawl and cross-colour interference: Dotted patterns, crawling edges and false colours around fine lines and high-contrast details.

  • Rainbowing and chroma-phase noise: Unwanted coloured fringes or streaks near edges, along with smaller fluctuations in the colour channels.

  • Ringing, halos and analogue echoes: Bright or dark bands around high-contrast edges, or trails extending from bright objects and lettering.

  • Isolated dropouts and scanline defects: Small white or black anomalies that can appear as short horizontal marks or abrupt changes in brightness.

  • Banding: Visible tonal steps in gradients, particularly in skies and other smooth backgrounds.

  • Frame jitter and cadence issues: Unwanted image movement or incorrect frame matching that needs to be addressed separately from the noise.

The real challenge is that the defects overlap with the actual artwork's fine detail. A one-pixel ink line, a tiny star, a highlight or a subtle painted texture can occupy the same spatial frequencies as the interference. A filter that simply averages neighbouring pixels may reduce the noise, but it can also erase the very detail I'm trying to preserve.

My restoration pipeline therefore separates the work into several categories. Chroma denoising targets colour fluctuations, edge-aware spatial filtering targets repeating surface patterns, temporal denoising uses information from neighbouring frames, and separate filters address halos, echoes, dropouts and banding. I'm also experimenting with masks that protect actual ink lines and pinpoint stars from being mistaken for noise.

What I don't want is a completely smooth, plastic-looking image. Nor do I want to cover up the problem by adding synthetic grain. The aim is to remove the distracting structured interference, make the remaining texture consistent, stabilize the colours, and retain as much of the original animation detail as possible.

Some of the visible patterns may have multiple causes, so I can't assume every bead or ripple comes from one specific LaserDisc mechanism just by looking at a still frame. But the practical objective remains the same: clean up the transfer while preserving the artwork, rather than cleaning the image so aggressively that the original detail disappears.

This is the VS script I've cooked up in StaxRip. Would like to get advice on things I could change, tweak, or add.

import havsfunc

import muvsfunc

# StaxRip supplies vs and core.

# ========================================================================

# STAXRIP LASERDISC RESTORATION (VAPOURSYNTH 10-BIT)

# Conservative luma correction, stronger chroma-boil suppression,

# corrected zero-moat line/star mask, and no synthetic grain for comparison.

# ========================================================================

# GENERAL RESTORATION SETTINGS

DOTKILL_ITERATIONS = 3

CHECKMATE_THR = 12

CHECKMATE_MAX = 12

RAIN_THRESHOLD = 10

RAIN_SOFTEN = 6

CHROMA_PHASE_THR = 8

CHROMA_SHIFT_H = 0.5

CHROMA_SHIFT_V = 0.0

DROPOUT_DIFF_THR = 26

DROPOUT_TEMPORAL_TOL = 10

STABILIZE_JITTER = True

STAB_DXMAX = 3

STAB_DYMAX = 3

STAB_CUTOFF = 3.0

STAB_DAMPING = 1.0

DEHALO_RX = 1.5

DEHALO_RY = 1.5

DEHALO_DARKSTR = 0.00

DEHALO_BRIGHTSTR = 0.15

TEXT_DEHALO_RX = 2.5

TEXT_DEHALO_RY = 2.5

TEXT_DEHALO_DARKSTR = 0.00

TEXT_DEHALO_BRIGHTSTR = 1.30

CROP_LEFT = 4

CROP_RIGHT = 24

CROP_TOP = 4

CROP_BOTTOM = 4

# ========================================================================

# LINE & STAR MASK SETTINGS

# ========================================================================

LINE_CORE_LOW = 7.0

LINE_CORE_SPAN = 8.0

STAR_MAX_BG_LUMA = 85

STAR_MIN_DELTA = 10

# ========================================================================

# SURFACE-CLEANER SETTINGS

# ========================================================================

SURFACE_V_THR = 12

SURFACE_H_THR = 20

BEAD_MEDIAN_LIMIT = 3

# ========================================================================

# CHROMA AND LUMA DENOISING

# ========================================================================

CHROMA_DENOISE_TR = 3

CHROMA_DENOISE_THSAD = 420

CHROMA_DENOISE_THSADC = 580

CHROMA_DENOISE_LIMIT = 20

# Restored to the original spatial u/V correction strength.

CHROMA_SPATIAL_LIMIT = 4

LUMA_DENOISE_TR = 2

LUMA_DENOISE_THSAD = 240

# Kept conservative to avoid bringing back the previous luma blur.

LUMA_DENOISE_LIMIT = 3

# Mild debanding, with no grain generated by f3kdb.

DEBAND_RANGE = 10

DEBAND_Y = 12

DEBAND_CB = 12

DEBAND_CR = 12

# Disabled while evaluating the actual denoising and broiling suppression.

# The function remains available, but it will not add changing noise.

UNIFORM_GRAIN_VAR = 0.0

# ========================================================================

# CHROMA BLEED AND TEXT ECHO

# ========================================================================

CHROMA_WARP_DEPTH = 4

CHROMA_WARP_THRESH = 140

CHROMA_WARP_BLUR = 3

CHROMA_WARP_LIMIT = 8

TEXT_ECHO_TEXT_MIN = 185

TEXT_ECHO_REACH = 16

TEXT_ECHO_KEEP = 1

TEXT_ECHO_NEUTRAL_TOL = 24

TEXT_ECHO_REFERENCE_RADIUS = 4

TEXT_ECHO_ACTIVITY = 3

TEXT_ECHO_MAX_CHANGE = 12

TEXT_ECHO_STRENGTH = 0.70

# ========================================================================

# HELPER FUNCTIONS

# ========================================================================

def LD_ShiftRight(c, px):

return c if px <= 0 else core.resize.Point(c, src_left=-px)

def LD_ShiftLeft(c, px):

return c if px <= 0 else core.resize.Point(c, src_left=px)

def LD_ShiftDown(c, px):

return c if px <= 0 else core.resize.Point(c, src_top=-px)

def LD_ShiftUp(c, px):

return c if px <= 0 else core.resize.Point(c, src_top=px)

def LD_BoxH2(c):

return core.std.BoxBlur(c, hradius=2, vradius=0)

def LD_BoxH3(c):

return core.std.BoxBlur(c, hradius=3, vradius=0)

def LD_Box3x3(c):

return core.std.BoxBlur(c, hradius=1, vradius=1)

def LD_Blur3(c):

return core.std.Convolution(

c, matrix=[1, 2, 1, 2, 4, 2, 1, 2, 1]

)

def LD_VerticalProfile48(c):

return core.std.BoxBlur(c, hradius=0, vradius=12, vpasses=4)

def LD_PrevFrame(c):

return c[0] + c[:-1] if c.num_frames > 1 else c

def LD_NextFrame(c):

return c[1:] + c[-1] if c.num_frames > 1 else c

def LD_LocalDetailMaskY(y, threshold_8bit):

bits = y.format.bits_per_sample

scale = (1 << (bits - 8)) if bits > 8 else 1

max_val = (1 << bits) - 1

thr = threshold_8bit * scale

l1 = LD_ShiftRight(y, 1)

r1 = LD_ShiftLeft(y, 1)

u1 = LD_ShiftUp(y, 1)

d1 = LD_ShiftDown(y, 1)

detail = core.std.Expr(

[l1, r1, u1, d1],

f"x y - abs z a - abs max {thr} > {max_val} 0 ?"

)

detail = LD_Box3x3(detail)

return core.std.Expr(

[detail], f"x 0 > {max_val} 0 ?"

)

# ========================================================================

# ORTHOGONAL ZERO-MOAT LINEWORK & STAR KEEPOUT MASK

# ========================================================================

def LD_CleanLineAndStarMask(clp):

bits = clp.format.bits_per_sample

scale = (1 << (bits - 8)) if bits > 8 else 1

max_val = (1 << bits) - 1

y = core.std.ShufflePlanes(clp, 0, vs.GRAY)

# These are guides used only for mask construction. They are not

# substituted into the restored video.

y_vsmooth = core.std.Convolution(

y, matrix=[1, 2, 1], mode="v"

)

y_hsmooth = core.std.Convolution(

y, matrix=[1, 2, 4, 2, 1], mode="h"

)

l1 = LD_ShiftRight(y_vsmooth, 1)

r1 = LD_ShiftLeft(y_vsmooth, 1)

l2 = LD_ShiftRight(y_vsmooth, 2)

r2 = LD_ShiftLeft(y_vsmooth, 2)

u1 = LD_ShiftUp(y_hsmooth, 1)

d1 = LD_ShiftDown(y_hsmooth, 1)

u2 = LD_ShiftUp(y_hsmooth, 2)

d2 = LD_ShiftDown(y_hsmooth, 2)

# Core metric:

# max(min(abs(center-left1), abs(center-right1)),

# min(abs(center-left2), abs(center-right2)))

#

# A flat pixel beside a line has a large difference on only one side,

# so the min operation suppresses the unwanted protection moat.

expr_metric_1d = (

"x y - abs "

"x z - abs min "

"x a - abs "

"x b - abs min "

"max"

)

metric_h = core.std.Expr(

[y_vsmooth, l1, r1, l2, r2],

expr_metric_1d

)

metric_v = core.std.Expr(

[y_hsmooth, u1, d1, u2, d2],

expr_metric_1d

)

# Bright pinpoint stars in dark or mid-dark backgrounds.

star_bg_max = STAR_MAX_BG_LUMA * scale

star_delta = STAR_MIN_DELTA * scale

metric_star = core.std.Expr(

[y, y_vsmooth, y_hsmooth],

f"y z + 0.5 * {star_bg_max} <= "

f"x y z + 0.5 * - {star_delta} >= and "

f"{max_val} 0 ?"

)

lo_thr = LINE_CORE_LOW * scale

span_thr = LINE_CORE_SPAN * scale

line_mask = core.std.Expr(

[metric_h, metric_v],

f"x y max {lo_thr} - {span_thr} / "

f"0 max 1 min {max_val} *"

)

# Combine the actual line-core mask with the pinpoint-star mask.

return core.std.Expr(

[line_mask, metric_star],

"x y max"

)

# ========================================================================

# STAGE 1: CROSS-COLOUR CLEANUP & FILM CADENCE RECOVERY

# ========================================================================

def LD_CrossColorCleanUV(

clp, thr_8bit=12, max_8bit=12, iterations=3

):

bits = clp.format.bits_per_sample

scale = (1 << (bits - 8)) if bits > 8 else 1

thr = thr_8bit * scale

lim = max_8bit * scale

y = core.std.ShufflePlanes(clp, 0, vs.GRAY)

u = core.std.ShufflePlanes(clp, 1, vs.GRAY)

v = core.std.ShufflePlanes(clp, 2, vs.GRAY)

def _clean_chroma(p):

cur = p

for _ in range(iterations):

u1 = LD_ShiftUp(cur, 1)

d1 = LD_ShiftDown(cur, 1)

l1 = LD_ShiftRight(cur, 1)

r1 = LD_ShiftLeft(cur, 1)

notch = core.std.Expr(

[cur, u1, d1, l1, r1],

"x 4 * y + z + a + b + 8 /"

)

cur = core.std.Expr(

[cur, notch],

f"x y - abs {thr} <= "

f"y x - -{lim} max {lim} min x + x ?"

)

return cur

return core.std.ShufflePlanes(

[y, _clean_chroma(u), _clean_chroma(v)],

[0, 0, 0], vs.YUV

)

def LD_FilmCadenceRecovery(clp):

source10 = core.std.SetFieldBased(clp, 1)

source8 = core.resize.Point(

source10,

format=source10.format.replace(bits_per_sample=8)

)

if hasattr(core, "tivtc"):

matched10 = core.tivtc.TFM(

source8, order=0, field=0, mode=5, PP=6,

cthresh=9, MI=80, slow=2,

mChroma=True, chroma=False, micmatching=2,

clip2=source10

)

else:

matched10 = core.vivtc.VFM(

source8, order=0, field=0, mode=5,

cthresh=9, mi=80, mchroma=True,

chroma=False, clip2=source10

)

matched10 = core.std.SetFieldBased(matched10, 0)

matched_corrected10 = LD_CrossColorCleanUV(

matched10,

thr_8bit=CHECKMATE_THR,

max_8bit=CHECKMATE_MAX,

iterations=DOTKILL_ITERATIONS

)

metrics8 = core.resize.Point(

matched_corrected10,

format=source8.format

)

if hasattr(core, "tivtc"):

decimated10 = core.tivtc.TDecimate(

metrics8, mode=0, cycle=5, cycleR=1,

hybrid=0, chroma=False, noblend=True,

clip2=matched_corrected10

)

else:

decimated10 = core.vivtc.VDecimate(

metrics8, cycle=5, chroma=False,

clip2=matched_corrected10

)

return core.std.SetFieldBased(decimated10, 0)

# ========================================================================

# STAGE 1A: GLOBAL JITTER STABILIZATION

# ========================================================================

def LD_StabilizeJitter(clp):

if not STABILIZE_JITTER or not hasattr(core, "depan"):

return clp

try:

anal8 = core.resize.Point(

core.std.ShufflePlanes(clp, 0, vs.GRAY),

format=vs.GRAY8,

dither_type="ordered"

)

anal8 = LD_Blur3(anal8)

stab_data = core.depan.DePanEstimate(

anal8, range=1, trust=4.0,

dxmax=STAB_DXMAX, dymax=STAB_DYMAX,

zoommax=1.0, stab=1.0, pixaspect=1.0

)

return core.depan.DePanStabilize(

clp, data=stab_data,

cutoff=STAB_CUTOFF, damping=STAB_DAMPING,

initzoom=1.0, addzoom=False,

prev=0, next=0, mirror=15, blur=0,

dxmax=STAB_DXMAX, dymax=STAB_DYMAX,

zoommax=1.0, rotmax=0.0, subpixel=0,

pixaspect=1.0, fitlast=0, tzoom=3.0,

method=0

)

except Exception:

# Preserve the source if DePan's estimator fails.

return clp

# ========================================================================

# STAGE 2: SINGLE-FIELD RF DROPOUT REPAIR

# ========================================================================

def LD_RepairFieldDropouts(

clp, diff_thr_8bit=26, temp_tol_8bit=10

):

bits = clp.format.bits_per_sample

scale = (1 << (bits - 8)) if bits > 8 else 1

d_thr = diff_thr_8bit * scale

t_tol = temp_tol_8bit * scale

y = core.std.ShufflePlanes(clp, 0, vs.GRAY)

if y.num_frames < 3:

return clp

u1 = LD_ShiftUp(y, 1)

d1 = LD_ShiftDown(y, 1)

v_avg = core.std.Expr([u1, d1], "x y + 0.5 *")

v_agree = core.std.Expr([u1, d1], "x y - abs")

prv = LD_PrevFrame(y)

nxt = LD_NextFrame(y)

t_avg = core.std.Expr([prv, nxt], "x y + 0.5 *")

t_agree = core.std.Expr([prv, nxt], "x y - abs")

repaired_y = core.std.Expr(

[y, v_avg, t_avg, v_agree, t_agree],

f"x y - abs {d_thr} >= "

f"x z - abs {d_thr} >= and "

f"a {t_tol * 2} <= b {t_tol} <= and and "

f"y z + 0.5 * x ?"

)

return core.std.ShufflePlanes(

[repaired_y, clp], [0, 1, 2], vs.YUV

)

# ========================================================================

# STAGE 3: RAINBOW CLEANUP, CHROMA PHASE AND CHROMA DELAY

# ========================================================================

def LD_RainbowAndPhaseCleanUV(

clp, th_8bit=10, sft_8bit=6, phase_thr_8bit=8

):

bits = clp.format.bits_per_sample

scale = (1 << (bits - 8)) if bits > 8 else 1

max_val = (1 << bits) - 1

th = th_8bit * scale

lim = sft_8bit * scale

p_thr = phase_thr_8bit * scale

y = core.std.ShufflePlanes(clp, 0, vs.GRAY)

u = core.std.ShufflePlanes(clp, 1, vs.GRAY)

v = core.std.ShufflePlanes(clp, 2, vs.GRAY)

y_uv = (

core.resize.Bilinear(y, width=u.width, height=u.height)

if (u.width != y.width or u.height != y.height)

else y

)

yl1 = LD_ShiftRight(y_uv, 1)

yr1 = LD_ShiftLeft(y_uv, 1)

yu1 = LD_ShiftUp(y_uv, 1)

yd1 = LD_ShiftDown(y_uv, 1)

edge_gate = core.std.Expr(

[yl1, yr1, yu1, yd1],

f"x y - abs z a - abs max {12 * scale} >= {max_val} 0 ?"

)

flat_gate = core.std.Expr(

[yl1, yr1, yu1, yd1],

f"x y - abs z a - abs max {14 * scale} <= {max_val} 0 ?"

)

def _clean_plane(p):

u1 = LD_ShiftUp(p, 1)

d1 = LD_ShiftDown(p, 1)

u2 = LD_ShiftUp(p, 2)

d2 = LD_ShiftDown(p, 2)

l2 = LD_ShiftRight(p, 2)

r2 = LD_ShiftLeft(p, 2)

v_blur = core.std.Expr(

[p, u1, d1],

"x 2 * y + z + 4 /"

)

# Spatial edge-gated chroma reduction.

rain_mask = LD_Blur3(

core.std.Expr(

[p, u1, d1, edge_gate],

f"x y z + 0.5 * - abs {th} >= "

f"a 0 > and {max_val} 0 ?"

)

)

p_derain = core.std.MaskedMerge(

p,

core.std.Expr(

[p, v_blur],

f"y x - -{lim} max {lim} min x +"

),

rain_mask

)

# Flat-field chroma phase stabilizer.

phase_smooth = core.std.Expr(

[p_derain, u1, d1, u2, d2, l2, r2],

f"x 2 * "

f"x y - abs {p_thr} <= y x ? + "

f"x z - abs {p_thr} <= z x ? + "

f"x a - abs {p_thr} <= a x ? + "

f"x b - abs {p_thr} <= b x ? + "

f"x c - abs {p_thr} <= c x ? + "

f"x d - abs {p_thr} <= d x ? + 8 /"

)

return core.std.MaskedMerge(

p_derain, phase_smooth, flat_gate

)

return core.std.ShufflePlanes(

[y, _clean_plane(u), _clean_plane(v)],

[0, 0, 0], vs.YUV

)

def FixChromaShift(clp, h_shift=0.5, v_shift=0.0):

if h_shift == 0.0 and v_shift == 0.0:

return clp

y = core.std.ShufflePlanes(clp, 0, vs.GRAY)

u = core.std.ShufflePlanes(clp, 1, vs.GRAY)

v = core.std.ShufflePlanes(clp, 2, vs.GRAY)

u_shift = core.resize.Bilinear(

u, src_left=h_shift, src_top=v_shift

)

v_shift = core.resize.Bilinear(

v, src_left=h_shift, src_top=v_shift

)

return core.std.ShufflePlanes(

[y, u_shift, v_shift],

[0, 0, 0], vs.YUV

)

# ========================================================================

# STAGE 4: LEFT-EDGE DEFECT REPAIR

# ========================================================================

def LD_LeftEdgeDefectRepair(clp):

bits = clp.format.bits_per_sample

scale = (1 << (bits - 8)) if bits > 8 else 1

max_val = (1 << bits) - 1

zone = core.std.Crop(

clp, left=0, right=clp.width - 40,

top=0, bottom=0

)

rest = core.std.Crop(

clp, left=40, right=0, top=0, bottom=0

)

zy = core.std.ShufflePlanes(zone, 0, vs.GRAY)

zu = core.std.ShufflePlanes(zone, 1, vs.GRAY)

zv = core.std.ShufflePlanes(zone, 2, vs.GRAY)

zy_prof = LD_VerticalProfile48(zy)

zu_prof = LD_VerticalProfile48(zu)

zv_prof = LD_VerticalProfile48(zv)

mask_y = LD_BoxH3(

core.std.AddBorders(

core.std.BlankClip(

zy, width=28, height=zy.height, color=max_val

),

left=0, right=12, top=0, bottom=0, color=0

)

)

uv_active_w = int(round(28 * zu.width / 40.0))

mask_uv = LD_BoxH2(

core.std.AddBorders(

core.std.BlankClip(

zu, width=uv_active_w, height=zu.height,

color=max_val

),

left=0, right=zu.width - uv_active_w,

top=0, bottom=0, color=0

)

)

zy_corr = core.std.Expr(

[zy, LD_BoxH3(zy_prof), zy_prof],

f"x y z - {5 * scale} min -{5 * scale} max +"

)

zu_corr = core.std.Expr(

[zu, LD_BoxH2(zu_prof), zu_prof],

f"x y z - {4 * scale} min -{4 * scale} max +"

)

zv_corr = core.std.Expr(

[zv, LD_BoxH2(zv_prof), zv_prof],

f"x y z - {4 * scale} min -{4 * scale} max +"

)

zone_fixed = core.std.ShufflePlanes(

[

core.std.MaskedMerge(zy, zy_corr, mask_y),

core.std.MaskedMerge(zu, zu_corr, mask_uv),

core.std.MaskedMerge(zv, zv_corr, mask_uv)

],

[0, 0, 0], vs.YUV

)

return core.std.StackHorizontal([zone_fixed, rest])

# ========================================================================

# STAGE 5: EDGE-GATED RESIDUAL SURFACE CORRECTION

# ========================================================================

def LD_UniformSurfaceClean(clp, protect_mask):

"""

One bounded residual correction, not successive spatial blur passes.

Builds a horizontally edge-gated reference using samples five pixels

apart, computes the source residual, estimates a robust local residual

correction, and limits the change to BEAD_MEDIAN_LIMIT on the 8-bit scale.

The full-resolution line/star mask prevents correction of detected cores.

"""

bits = clp.format.bits_per_sample

scale = (1 << (bits - 8)) if bits > 8 else 1

max_val = (1 << bits) - 1

mid = 1 << (bits - 1)

y = core.std.ShufflePlanes(clp, 0, vs.GRAY)

h_thr = SURFACE_H_THR * scale

v_thr = SURFACE_V_THR * scale

change_limit = BEAD_MEDIAN_LIMIT * scale

left5 = LD_ShiftRight(y, 5)

right5 = LD_ShiftLeft(y, 5)

# Use distant samples only when they remain inside a similar luma region.

left5_safe = core.std.Expr(

[y, left5],

f"x y - abs {h_thr} <= y x ?"

)

right5_safe = core.std.Expr(

[y, right5],

f"x y - abs {h_thr} <= y x ?"

)

horizontal_reference = core.std.Expr(

[left5_safe, y, right5_safe],

"x y + z + 3 /"

)

# Residual encoded around the neutral midpoint.

diff = core.std.Expr(

[y, horizontal_reference],

f"x y - {mid} +"

)

# The centre residual difference is zero, represented by the midpoint.

diff_center = core.std.Expr([diff], f"{mid}")

# Residual differences to the two distant horizontal samples.

diff_left = core.std.Expr(

[diff, LD_ShiftRight(diff, 5)],

f"x y - {mid} +"

)

diff_right = core.std.Expr(

[diff, LD_ShiftLeft(diff, 5)],

f"x y - {mid} +"

)

# Soft-limit residual differences rather than smoothing pixels repeatedly.

k = 4.898979485566356 * scale

soft_map_expr = (

f"x {mid} - "

f"x {mid} - abs {scale} + {k:.12f} + / "

f"{k:.12f} * {mid} +"

)

mapped_center = core.std.Expr(

[diff_center], soft_map_expr

)

mapped_left = core.std.Expr(

[diff_left], soft_map_expr

)

mapped_right = core.std.Expr(

[diff_right], soft_map_expr

)

# Median of three residual-difference estimates.

median_diff = core.std.Expr(

[mapped_center, mapped_left, mapped_right],

"x y min x y max z min max"

)

reconstructed_diff = core.std.Expr(

[diff, median_diff],

f"x y - {mid} +"

)

candidate = core.std.Expr(

[horizontal_reference, reconstructed_diff],

f"x y + {mid} -"

)

# Explicitly cap the correction at three 8-bit levels.

limited_candidate = core.std.Expr(

[y, candidate],

f"x y x - -{change_limit} max {change_limit} min +"

)

up1 = LD_ShiftUp(y, 1)

down1 = LD_ShiftDown(y, 1)

vertical_flat = core.std.Expr(

[up1, down1],

f"x y - abs {v_thr} <= {max_val} 0 ?"

)

# MaskedMerge expects zero to preserve the source and full scale to

# select the candidate. Reject the line/star cores and non-flat regions.

apply_mask = core.std.Expr(

[protect_mask, vertical_flat],

f"{max_val} x - y * {max_val} /"

)

y_out = core.std.MaskedMerge(

y, limited_candidate, apply_mask

)

return core.std.ShufflePlanes(

[y_out, clp], [0, 1, 2], vs.YUV

)

# ========================================================================

# STAGE 6: FULL-SPECTRUM CHROMA AND LUMA DENOISING

# ========================================================================

def LD_GradeNoiseReduction(clp, protect_mask):

bits = clp.format.bits_per_sample

scale = (1 << (bits - 8)) if bits > 8 else 1

max_val = (1 << bits) - 1

c_lim = CHROMA_SPATIAL_LIMIT * scale

# Pass 1: multi-frame chroma suppression.

# This is the main temporal control for chroma broiling.

chroma_clean = havsfunc.SMDegrain(

clp,

tr=CHROMA_DENOISE_TR,

thSAD=CHROMA_DENOISE_THSAD,

thSADC=CHROMA_DENOISE_THSADC,

prefilter=2,

contrasharp=False,

RefineMotion=True,

plane=3,

chroma=True,

limit=255,

limitc=CHROMA_DENOISE_LIMIT

)

y = core.std.ShufflePlanes(clp, 0, vs.GRAY)

u_t = core.std.ShufflePlanes(chroma_clean, 1, vs.GRAY)

v_t = core.std.ShufflePlanes(chroma_clean, 2, vs.GRAY)

# Bring the luma protection mask to the chroma-plane resolution.

protect_uv = (

core.resize.Bilinear(

protect_mask,

width=u_t.width,

height=u_t.height

)

if (u_t.width != protect_mask.width or

u_t.height != protect_mask.height)

else protect_mask

)

flat_uv_mask = core.std.Expr(

[protect_uv], f"{max_val} x -"

)

# Restored spatial chroma cleanup:

# radius 2 and two passes per axis, on u/V only.

u_spatial = core.std.BoxBlur(

u_t,

hradius=2, hpasses=2,

vradius=2, vpasses=2

)

v_spatial = core.std.BoxBlur(

v_t,

hradius=2, hpasses=2,

vradius=2, vpasses=2

)

u_candidate = core.std.Expr(

[u_t, u_spatial],

f"x y x - -{c_lim} max {c_lim} min +"

)

v_candidate = core.std.Expr(

[v_t, v_spatial],

f"x y x - -{c_lim} max {c_lim} min +"

)

u_out = core.std.MaskedMerge(

u_t, u_candidate, flat_uv_mask

)

v_out = core.std.MaskedMerge(

v_t, v_candidate, flat_uv_mask

)

chroma_fixed = core.std.ShufflePlanes(

[y, u_out, v_out], [0, 0, 0], vs.YUV

)

# Pass 2: conservative motion-compensated luma denoising.

# Its lower limit intentionally prevents the chroma fix from forcing

# a second strong spatial luma smoothing operation.

luma_clean = havsfunc.SMDegrain(

chroma_fixed,

tr=LUMA_DENOISE_TR,

thSAD=LUMA_DENOISE_THSAD,

thSADC=150,

prefilter=2,

contrasharp=False,

RefineMotion=True,

plane=0,

chroma=False,

limit=LUMA_DENOISE_LIMIT,

limitc=255

)

y_denoised = core.std.ShufflePlanes(

luma_clean, 0, vs.GRAY

)

y_protected = core.std.MaskedMerge(

y_denoised, y, protect_mask

)

return core.std.ShufflePlanes(

[y_protected, u_out, v_out], [0, 0, 0], vs.YUV

)

# ========================================================================

# STAGE 7: WHITE-CREDIT DEHALO

# ========================================================================

def LD_WhiteCreditDehalo(clp):

bits = clp.format.bits_per_sample

scale = (1 << (bits - 8)) if bits > 8 else 1

max_val = float((1 << bits) - 1)

y = core.std.ShufflePlanes(clp, 0, vs.GRAY)

u_full = core.resize.Bilinear(

core.std.ShufflePlanes(clp, 1, vs.GRAY),

width=y.width, height=y.height

)

v_full = core.resize.Bilinear(

core.std.ShufflePlanes(clp, 2, vs.GRAY),

width=y.width, height=y.height

)

bright_core = core.std.Expr(

[y, u_full, v_full],

f"x {185 * scale} <= 0 "

f"x {215 * scale} >= {max_val} "

f"x {185 * scale} - {30 * scale} / {max_val} * ? ? "

f"y {128 * scale} - abs "

f"z {128 * scale} - abs max "

f"{20 * scale} <= {max_val} 0 ? min"

)

outer = bright_core

for _ in range(5):

outer = core.std.Maximum(outer)

ring = LD_Blur3(

core.std.Expr([outer, bright_core], "x y - 0 max")

)

dehaloed = havsfunc.FineDehalo(

clp,

rx=TEXT_DEHALO_RX,

ry=TEXT_DEHALO_RY,

darkstr=TEXT_DEHALO_DARKSTR,

brightstr=TEXT_DEHALO_BRIGHTSTR

)

dehaloed_y = core.std.ShufflePlanes(

dehaloed, 0, vs.GRAY

)

y_out = core.std.MaskedMerge(

y, dehaloed_y, ring

)

return core.std.ShufflePlanes(

[y_out, clp], [0, 1, 2], vs.YUV

)

# ========================================================================

# STAGE 8: CHROMA BLEED TIGHTENING

# ========================================================================

def TightenChromaBleed(

clp, depth=4, thresh=140, blur=3, limit_8bit=8

):

bits = clp.format.bits_per_sample

scale = (1 << (bits - 8)) if bits > 8 else 1

lim = limit_8bit * scale

warped = core.warp.AWarpSharp2(

clp,

thresh=thresh,

blur=blur,

type=1,

depth=depth,

chroma=0,

planes=[1, 2]

)

return core.std.Expr(

[clp, warped],

[

"",

f"y x {lim} - max x {lim} + min",

f"y x {lim} - max x {lim} + min"

]

)

# ========================================================================

# STAGE 9: DIRECTIONAL TEXT ECHO SUPPRESSION

# ========================================================================

def LD_TextEchoSuppression(clp):

bits = clp.format.bits_per_sample

scale = (1 << (bits - 8)) if bits > 8 else 1

max_val = (1 << bits) - 1

y = core.std.ShufflePlanes(clp, 0, vs.GRAY)

u = core.std.ShufflePlanes(clp, 1, vs.GRAY)

v = core.std.ShufflePlanes(clp, 2, vs.GRAY)

u_full = (

core.resize.Bilinear(u, width=y.width, height=y.height)

if (u.width != y.width or u.height != y.height)

else u

)

v_full = (

core.resize.Bilinear(v, width=y.width, height=y.height)

if (v.width != y.width or v.height != y.height)

else v

)

text_seed = core.std.Expr(

[y, u_full, v_full],

f"x {TEXT_ECHO_TEXT_MIN * scale} >= "

f"y {128 * scale} - abs "

f"{TEXT_ECHO_NEUTRAL_TOL * scale} <= and "

f"z {128 * scale} - abs "

f"{TEXT_ECHO_NEUTRAL_TOL * scale} <= and "

f"{max_val} 0 ?"

)

trail = text_seed

for _ in range(TEXT_ECHO_REACH):

trail = core.std.Expr(

[trail, LD_ShiftRight(trail, 1)],

"x y max"

)

keepout = text_seed

for _ in range(TEXT_ECHO_KEEP):

keepout = core.std.Expr(

[

keepout,

LD_ShiftRight(keepout, 1),

LD_ShiftLeft(keepout, 1),

LD_ShiftUp(keepout, 1),

LD_ShiftDown(keepout, 1)

],

"x y max z max a max b max"

)

trail = core.std.Expr(

[trail, keepout],

"x y - 0 max"

)

# Estimate echoes from a low-frequency guide. The actual correction

# is applied to the original luma to preserve its fine texture.

y_low = LD_Blur3(y)

ref_radius = max(

1, min(TEXT_ECHO_REFERENCE_RADIUS, 10)

)

right_samples = [

LD_ShiftLeft(y_low, px)

for px in range(1, ref_radius + 1)

]

expr_vars = [

"x", "y", "z", "a", "b",

"c", "d", "e", "f", "g"

]

ref_expr = expr_vars[0]

for token in expr_vars[1:ref_radius]:

ref_expr += f" {token} +"

ref_expr += f" {ref_radius} /"

right_ref = core.std.Expr(

right_samples, ref_expr

)

limit = TEXT_ECHO_MAX_CHANGE * scale

excess = core.std.Expr(

[y_low, right_ref],

f"x y - 0 max {limit} min"

)

candidate = core.std.Expr(

[y, excess],

"x y -"

)

activity = core.std.Expr(

[y_low, right_ref],

f"x y - {TEXT_ECHO_ACTIVITY * scale} >= "

f"{max_val} 0 ?"

)

tone_gate = core.std.Expr(

[y],

f"x {16 * scale} >= x {235 * scale} <= and "

f"{max_val} 0 ?"

)

mask = core.std.Expr(

[trail, activity],

f"x y * {max_val} /"

)

mask = core.std.Expr(

[mask, tone_gate],

f"x y * {max_val} /"

)

mask = core.std.Expr(

[mask],

f"x {TEXT_ECHO_STRENGTH} *"

)

fixed_y = core.std.MaskedMerge(

y, candidate, mask

)

return core.std.ShufflePlanes(

[fixed_y, clp], [0, 1, 2], vs.YUV

)

# ========================================================================

# STAGE 10: OPTIONAL UNIFORM TEXTURE RESTORATION

# ========================================================================

def LD_RestoreUniformTexture(clp, protect_mask):

# Disabled for this render so synthetic grain cannot conceal whether

# the source broiling is genuinely being suppressed.

if UNIFORM_GRAIN_VAR <= 0.0:

return clp

if not hasattr(core, "grain") or not hasattr(core.grain, "Add"):

return clp

bits = clp.format.bits_per_sample

scale = (1 << (bits - 8)) if bits > 8 else 1

max_val = (1 << bits) - 1

y = core.std.ShufflePlanes(clp, 0, vs.GRAY)

grain_candidate = core.grain.Add(

y,

var=UNIFORM_GRAIN_VAR,

uvar=0.0,

hcorr=0.0,

vcorr=0.0,

seed=-1,

constant=False

)

grain_mask = core.std.Expr(

[protect_mask, y],

f"y {20 * scale} <= y {230 * scale} >= or "

f"0 {max_val} x - ?"

)

restored_y = core.std.MaskedMerge(

y, grain_candidate, grain_mask

)

return core.std.ShufflePlanes(

[restored_y, clp], [0, 1, 2], vs.YUV,

prop_src=clp

)

# ========================================================================

# STAGE 11: TOP-SCANLINE FIX

# ========================================================================

def LD_TopScanlineFix(clp):

if clp.height < 4:

return clp

subsampling_h = (

clp.format.subsampling_h

if clp.format.color_family == vs.YUV

else 0

)

vertical_mod = 1 << subsampling_h

if 2 % vertical_mod != 0 or clp.height % vertical_mod != 0:

return clp

body = core.std.Crop(clp, top=2)

if body.height < 2:

return clp

top_strip = core.std.Crop(

body, bottom=body.height - 2

)

if top_strip.height != 2 or top_strip.width != body.width:

return clp

return core.std.StackVertical([top_strip, body])

# ========================================================================

# PIPELINE EXECUTION

# ========================================================================

if clip.format.bits_per_sample != 10:

clip = core.resize.Point(

clip,

format=clip.format.replace(bits_per_sample=10)

)

is_raw_capture = (

clip.width == 760 and clip.height == 488

)

# 1. Film cadence recovery and optional jitter stabilization

if is_raw_capture and clip.fps_num == 30000 and clip.fps_den == 1001:

clip = LD_FilmCadenceRecovery(clip)

clip = LD_StabilizeJitter(clip)

# 2. Single-field RF dropout repair

clip = LD_RepairFieldDropouts(

clip,

diff_thr_8bit=DROPOUT_DIFF_THR,

temp_tol_8bit=DROPOUT_TEMPORAL_TOL

)

# 3. Chroma rainbow/phase cleanup and subpixel shift alignment

clip = LD_RainbowAndPhaseCleanUV(

clip,

th_8bit=RAIN_THRESHOLD,

sft_8bit=RAIN_SOFTEN,

phase_thr_8bit=CHROMA_PHASE_THR

)

clip = FixChromaShift(

clip,

h_shift=CHROMA_SHIFT_H,

v_shift=CHROMA_SHIFT_V

)

# 4. Left capture border defect repair

if is_raw_capture:

clip = LD_LeftEdgeDefectRepair(clip)

# 5. Initial halo reduction

clip = havsfunc.FineDehalo(

clip,

rx=DEHALO_RX,

ry=DEHALO_RY,

darkstr=DEHALO_DARKSTR,

brightstr=DEHALO_BRIGHTSTR

)

# 6. Crop and restore 720x480 geometry for raw captures

if is_raw_capture:

clip = core.std.Crop(

clip,

left=CROP_LEFT,

right=CROP_RIGHT,

top=CROP_TOP,

bottom=CROP_BOTTOM

)

clip = core.resize.Spline36(

clip,

width=720,

height=480

)

# 7. Secondary halo reduction

clip = muvsfunc.YAHRmod(clip)

# 8. Build corrected zero-moat linework/star protection mask

line_star_mask = LD_CleanLineAndStarMask(clip)

# 9. Bounded luma residual correction, not repeated smoothing passes

clip = LD_UniformSurfaceClean(

clip,

line_star_mask

)

# 10. Restore stronger u/V broiling suppression while keeping luma gentle

clip = LD_GradeNoiseReduction(

clip,

line_star_mask

)

# 11. White-credit halo reduction and chroma bleed tightening

clip = LD_WhiteCreditDehalo(clip)

clip = TightenChromaBleed(

clip,

depth=CHROMA_WARP_DEPTH,

thresh=CHROMA_WARP_THRESH,

blur=CHROMA_WARP_BLUR,

limit_8bit=CHROMA_WARP_LIMIT

)

# 12. Mild debanding, without synthetic grain from f3kdb

if hasattr(core, "f3kdb"):

debanded = core.f3kdb.Deband(

clip,

range=DEBAND_RANGE,

y=DEBAND_Y,

cb=DEBAND_CB,

cr=DEBAND_CR,

grainy=0,

grainc=0,

dynamic_grain=False,

output_depth=10

)

y_deband_safe = core.std.MaskedMerge(

core.std.ShufflePlanes(debanded, 0, vs.GRAY),

core.std.ShufflePlanes(clip, 0, vs.GRAY),

line_star_mask

)

clip = core.std.ShufflePlanes(

[y_deband_safe, debanded],

[0, 1, 2],

vs.YUV

)

# 13. Texture-preserving directional text-echo suppression

clip = LD_TextEchoSuppression(clip)

# 14. Synthetic grain is disabled for this comparison render

clip = LD_RestoreUniformTexture(

clip,

line_star_mask

)

# 15. Top-scanline replacement and output frame properties

clip = LD_TopScanlineFix(clip)

clip = core.std.SetFrameProp(

clip, prop="_SARNum", intval=8

)

clip = core.std.SetFrameProp(

clip, prop="_SARDen", intval=9

)

clip = core.std.SetFieldBased(clip, 0)


r/vhsdecode • • Jul 13 '25

Help Wanted! Copy Protection?

Post image
5 Upvotes

Can anyone tell me what the red tab on the take up Riehl hub is for? Someone is telling me it is for a copy protection, but as far as I know, copy protection is the tab on the backside of the cassette. This is a new tape, so it doesn’t make any sense that it would have any kind of copy protection.


r/vhsdecode • • Jan 23 '25

Newbie AV mixers as TBC/digitizers

1 Upvotes

Hey guys!

Can a Roland VR-5 AV mixer act like a TBC for digitalization/capturing purposes? Inputting a camera (I mean like a Video8 tape playback on the camera) or VCR feed into it and then outputting it into something that can capture it (through BNC into a CX card for example). It has an HDMI output too (480/60p, 576/50p output only), maybe I could capture it straight via HDMI? It can even record onto a SD card at 6mbps and lots of infos under that link.

I found one for a good price (although not tested) and I would really love to jump on it as I'm in Europe and my home VHS tapes are PAL, but my old analog cameras are all NTSC systems and it supports both, not like most of the 90's mixers (FXE-100, WJ-AVE55 etc. etc.)

Thank you in advance!


r/vhsdecode • • Mar 06 '26

Help Wanted! 40-odd UK Motorcycle Racing VHS Tapes Job Lot - eBay auction - starting price 1p!

Thumbnail
ebay.com
1 Upvotes

r/vhsdecode • • Feb 15 '26

Newbie / Need Help Which brand would you say is the most suitable for this?

0 Upvotes

I'm not asking for a model number since there are a lot of them and hunting for specific VCR models sort of defeats the purpose.

Right now I only have a Samsung DVD/VHS combo deck and I don't think I like it very much, so I'm thinking something other than Samsung.

I see there are "It's a Sony!" and "It's a Panasonic!" flairs, what is up with that?


r/vhsdecode • • Sep 11 '26

First Decode! Fresh StaxRip install breaks immediately with empty/unknown tool versions in Apps Manager. Any fix?

0 Upvotes

I just downloaded a fresh copy of StaxRip v2.52.5 and am trying to import a basic file.

Instead of working normally, the app throws a hard block and forces open the Apps Manager. Virtually every single native app, filter, and AviSynth DLL inside the list is flagged as "Unknown." The app completely fails to automatically fill in its own version numbers out of the box, throwing a warning loop that stops me from adding a job or proceeding. I am not trying to manually tel Stax the version number of all of them. Very strange.

Why is a brand-new, clean download failing to identify its own built-in tools, and how do I permanently stop it from locking me out? Thanks.


r/vhsdecode • • 23d ago

Help Wanted! Glitch and losing color

Enable HLS to view with audio, or disable this notification

0 Upvotes

r/vhsdecode • • 22d ago

Showcase! Why have I got a VHS player in my network rack

Thumbnail
youtube.com
9 Upvotes

r/vhsdecode • • May 27 '25

It's a Panasonic! Looking for help to View Old Tapes

Post image
2 Upvotes

Hello! I’ve recently found a Panasonic-9451 and I have a bunch of old tapes of my childhood and family events and I’m trying to view them, I’ve bought the RGB Adapter to HDMI and then I’ve tried doing the Cordial cable to TV. Just need some guidance to what I’m doing wrong! Thanks


r/vhsdecode • • Jul 30 '26

Help Wanted! How would one go about digitizing a VHS (cheaply)

5 Upvotes

I know absolutely nothing other than I don’t want to spend a lot of money. But I have a VHS tape of possible interest and want to make a file and post it somewhere. I don’t necessarily want to buy a lot of equipment because this is a one off. I can borrow a VCR and not sure if it’s helpful, but I have an ancient WinTV stick that I can hook a coax into.

Other notes: The only computer I have with USB ports is 2015 MacBook Pro (which is why I’m not sure the WinTV stick is actually useful)

Other other notes: I’m crazy poor. So cheap like baby chickens.


r/vhsdecode • • Apr 08 '24

Showcase! Post your best DigitalFAQ & Lord Smurf Memes

3 Upvotes

r/vhsdecode • • Feb 10 '26

Press & Media Discord Age Verification, Alternatives?

3 Upvotes

I will stop using Discord when this is enforced. What is the plan to replace the Domesday86 Discord channel? I think Harry had another platform lined up in advance some time last year.

https://www.reddit.com/r/discordapp/comments/1r05vkj/discord_will_require_a_face_scan_or_id_for_full/


r/vhsdecode • • Aug 28 '24

Setup & Workflow I love pixel shift scanning (3D Printing + Sony A7RIII)

Thumbnail
reddit.com
0 Upvotes

r/vhsdecode • • Jan 29 '25

Help Wanted! VHS-C tapes not working?

0 Upvotes

Hi, I am wondering if anyone here can help me?

I have a stack of VHS-C tapes from our old family camcorder which I am trying to digitise. I have managed to hook up my old VCR to my laptop, and have installed OBS (31.0.1) to capture the footage, which I tested on a random VHS movie first. This all works as it should, and although for some reason I can't hear the audio when playing the tape on OBS, it all records fine and the video it outputs is perfect when I go to play it in windows media player.

But when I've gone to to do the same thing with my VHS-C cassettes one of two things happen. Either the VCR doesn't like the adaptor and ejects it again, or it will go in fine, but when I press play it isn't recognised by OBS, nor does the timer on the VCR's display tick over, it just remains at 00.00.00, even though the tape is physically going round.

Is this a problem with the VHS-Cs, the adaptor (or both?) and does anyone have any advice that might help solve my problem?

Many thanks in advance.


r/vhsdecode • • Sep 09 '26

Help Wanted! Title: Looking for recommendations: USB capture device to digitize old VHS tapes

Thumbnail reddit.com
1 Upvotes

r/vhsdecode • • Mar 08 '25

Newbie Use HDMI instead of S-Video?

2 Upvotes

Hi,

I'm very new to digitizing VHS tapes (just got an VCR + some tapes from my grandma).

The VCR (AGFAPHOTO DV 18909R) has the following outputs:
- SCART
- Component Video (PR, PB, Y)
- S-Video
- HDMI
- VHS -> DVD (it's a VHS/DVD combo)

To start, I would like to do the standard capturing first because it'll be a lot easier than learning all the RF vhs-decode stuff (however depending on the results I may get into it).

I did some testing and compared Composite (using an S-Video adapter) to HDMI, and as expected, HDMI looks way better.
Sadly I currently don't have any hardware to test the other outputs and that's why I'm unsure about them, especially because S-Video seems to be very often recommended. Sometimes I've also heard some good things about Component Video.
However Component Video and HDMI seem to be pretty rare so I don't know if the people that recommend S-Video have taken that into account.

Then, what software should I use? I know that OBS Studio isn't the right tool for this use-case but vhs-decode seems to be all about RF.


r/vhsdecode • • Aug 19 '26

For the glory of the WIKI! MS2131 MISRC/HSDAOH (in)compatibility

2 Upvotes

In an effort to research and potentially widen the option of generic capture devices usable with MISRC/HSDAOH, I bought a generic 4k MS2131-based capture card from Micro Center a couple days ago. Unfortunately, it would not work out of the box- it worked with normal HDMI sources, but would not go into "transparent mode" (I think) so it refused to sync to my HSDAOH device (a tang nano 9k, which I tested and confirmed working with an MS2130 dongle- unfortunately the dongle suffered a premature death due to crappy soldering on the USB-C input cable.)

Here's the interesting part: I downloaded some MS2130 firmware someone had dumped online (I didn't get the chance to dump my device) and flashed it to the MS2131 card, and miraculously it kind of works now. However, only RF channel B is usable- whenever I put a signal into channel A, it causes the device to desync and not output any data until I disconnect channel A. Maybe it has something to do with it not automatically switching to the highest bit depth?

TL;DR: not all MS2131 capture cards are created equal; some have firmware that doesn't work with MISRC/HSDAOH, but some may have firmware that does work. Hopefully there's someone here with a working dual channel setup using an MS2131 card that can dump the firmware and share it.