LinkPi encoder family

There are two things which you can do. The first is make sure that you have the correct audio mode and volume set on your Shield. Settings/Device Preferences/Display and Sound/HDMI Fixed Volume

The second is to adjust the audio gain on your LinkPi. Open the LinkPi GUI, browse to the "Encode" page, Audio tab, Adjust the "gain" drop-down, and then hit "Save"

So I was having some issues letting my Osprey boxes sleep.
Specifically, I was having freezes when waking on my Elgato Cam Link 4K capture cards. It would also take a very long time for those to come back online when they did sleep. I would get a no signal message for a good 15 seconds or so.

I ended up taking a shot in the dark and buying these. My local Walmart had them and they came in an hour or so.

https://www.walmart.com/ip/Monster-LED-4K-Black-Audio-Video-USB-3-0-HDMI-Capture-Card-Record-High-Quality-Videos-Live-Stream/5550338999

I ended up finding that they output over USB 2.0 50 FPS at 1080p natively.

I was actually able to use Claude and some trickery to patch the firmware to get them to advertise and output 60 FPS at 1080p natively over USB 2.0. It was a little bit complicated and I wouldn't recommend a novice doing it, but it is possible to do and I am getting very good picture quality so far over USB 2.0 and basically instant wakes.

No more lockups or freezes. These things are actually pretty solid. They use a MacroSilicon MS2131 chipset.

I can share how I patched the firmware, but it's a really long post, and I'm just going to put in what Claude generated, as it's much clearer than what I would write, and I would rather let the AI explain it, because it actually did indeed work on three capture cards.

1 Like

Claude's Explanation:

MS2131 60Hz Firmware Patch Guide

Overview

The MacroSilicon MS2131 USB HDMI capture card (Monster MAD1-2024-BLK) ships with firmware that limits 1080p MJPEG capture to 50fps over USB 2.0. The chip supports 60fps — both 50fps and 60fps frame intervals exist in the USB 3.0 descriptors — but the USB 2.0 descriptors only advertise 50fps.

This guide documents the process of patching the firmware to enable 60fps over USB 2.0, specifically for use with LinkPi ENC1-V3 encoders which only have USB 2.0 ports.

Prerequisites

  • Windows PC with Python 3.x installed
  • ms213x_flash.exe from steve-m/ms213x_flash
  • Monster MAD1-2024-BLK capture card (MS2131 chipset, VID 345f, PID 2131)
  • USB cable to connect the card to the PC

Tools

Tool Purpose Source
ms213x_flash.exe Backup and flash firmware GitHub Releases
patch_final.py Patch 50fps→60fps and fix checksum Custom (below)

Step 1: Backup Original Firmware

Connect the Monster card to the PC via USB. Run:

ms213x_flash.exe

This auto-detects the MS2131 and saves a backup file like:

MS2131_2023-06-10_backup_25f7_62d6.bin

Keep this backup safe. You can always restore it to revert the patch.

Step 2: Patch the Firmware

Save the following script as patch_final.py:

import shutil
import sys

# --- Configuration ---
# Path to your original firmware backup
src = r'C:\Users\David\Desktop\MS2131_2023-06-10_backup_25f7_62d6.bin'
# Path for the patched output
dst = r'C:\Users\David\Desktop\MS2131_60hz_final.bin'

# --- Copy original to new file ---
shutil.copy2(src, dst)
data = bytearray(open(dst, 'rb').read())

# --- Read firmware structure ---
# Header length is 0x30 (48 bytes)
HEADER_LEN = 0x30

# Code length is stored at offset 0x02-0x03 (big-endian)
code_len = (data[0x02] << 8) | data[0x03]
print(f'Code length: {code_len} (0x{code_len:04x})')
print(f'Header: {HEADER_LEN} (0x{HEADER_LEN:02x})')
print(f'Checksum offset: {HEADER_LEN + code_len} (0x{HEADER_LEN + code_len:04x})')

# --- Verify original checksums ---
orig_header_csum = (data[HEADER_LEN + code_len + 0] << 8) | data[HEADER_LEN + code_len + 1]
orig_code_csum = (data[HEADER_LEN + code_len + 2] << 8) | data[HEADER_LEN + code_len + 3]
print(f'Stored header checksum: {orig_header_csum:04x}')
print(f'Stored code checksum:   {orig_code_csum:04x}')

# Verify we can reproduce the original code checksum
calc = 0
for i in range(HEADER_LEN, HEADER_LEN + code_len):
    calc += data[i]
calc = calc & 0xFFFF
print(f'Calculated code checksum (before patch): {calc:04x}')

if calc != orig_code_csum:
    print('ERROR: Cannot reproduce original checksum. Aborting.')
    sys.exit(1)
print('Original checksum verified OK')

# --- Patch 50fps -> 60fps ---
# UVC frame intervals are stored in 100-nanosecond units (little-endian):
#   50fps = 200000 = 0x00030D40 -> bytes: 40 0D 03 00
#   60fps = 166666 = 0x00028B0A -> bytes: 0A 8B 02 00
old = b'\x40\x0D\x03\x00'
new = b'\x0A\x8B\x02\x00'

count = 0
i = 0
while i < len(data) - 3:
    if data[i:i+4] == old:
        data[i:i+4] = new
        count += 1
    i += 1
print(f'\nPatched {count} occurrences of 50fps -> 60fps')

# --- Recalculate code checksum ---
# The code checksum is a simple 16-bit sum of all bytes in the code section
# (from HEADER_LEN to HEADER_LEN + code_len)
new_csum = 0
for i in range(HEADER_LEN, HEADER_LEN + code_len):
    new_csum += data[i]
new_csum = new_csum & 0xFFFF
print(f'New code checksum: {new_csum:04x}')

# --- Write new checksum ---
# Checksum is stored big-endian at offset HEADER_LEN + code_len + 2
data[HEADER_LEN + code_len + 2] = (new_csum >> 8) & 0xFF
data[HEADER_LEN + code_len + 3] = new_csum & 0xFF

# --- Verify ---
verify = (data[HEADER_LEN + code_len + 2] << 8) | data[HEADER_LEN + code_len + 3]
print(f'Written code checksum:  {verify:04x}')

# --- Save ---
open(dst, 'wb').write(data)
print(f'\nSaved to {dst}')
print(f'Original backup untouched: {src}')

Run it:

python patch_final.py

Expected output:

Code length: 64416 (0xfba0)
Header: 48 (0x30)
Checksum offset: 64464 (0xfbd0)
Stored header checksum: 25f7
Stored code checksum:   62d6
Calculated code checksum (before patch): 62d6
Original checksum verified OK

Patched 37 occurrences of 50fps -> 60fps
New code checksum: 6d19
Written code checksum:  6d19

Saved to C:\Users\David\Desktop\MS2131_60hz_final.bin
Original backup untouched: C:\Users\David\Desktop\MS2131_2023-06-10_backup_25f7_62d6.bin

Step 3: Flash the Patched Firmware

ms213x_flash.exe -w MS2131_60hz_final.bin

The tool will:

  1. Back up the current firmware automatically
  2. Erase flash
  3. Write the patched firmware
  4. Verify the flash contents

Wait for "Successfully written and verified flash" before unplugging.

Step 4: Verify on LinkPi

  1. Unplug the Monster card from the PC
  2. Plug it into the LinkPi USB port
  3. Open the LinkPi web UI
  4. The USB channel should now show 60Hz as the framerate option

If the LinkPi config still says 50, update it:

ssh root@<linkpi-ip>
sed -i 's/"framerate": 50/"framerate": 60/' /link/config/config.json
reboot

Restoring Original Firmware

If anything goes wrong, reflash the original backup:

ms213x_flash.exe -w MS2131_2023-06-10_backup_25f7_62d6.bin

How the Patch Works

UVC Frame Intervals

USB Video Class (UVC) devices advertise supported framerates as "frame intervals" in 100-nanosecond units:

Framerate Interval (decimal) Interval (hex, little-endian)
60 fps 166,666 0A 8B 02 00
50 fps 200,000 40 0D 03 00
30 fps 333,333 15 16 05 00
25 fps 400,000 80 1A 06 00
20 fps 500,000 20 A1 07 00
10 fps 1,000,000 40 42 0F 00

The patch replaces all occurrences of the 50fps interval (40 0D 03 00) with the 60fps interval (0A 8B 02 00) in the firmware binary.

Firmware Checksum

The MS2131 firmware has two checksums stored at the end of the code section:

  • Header checksum (2 bytes): Sum of header bytes (not modified by this patch)
  • Code checksum (2 bytes): 16-bit sum of all bytes in the code section

The checksum calculation (from ms213x_flash.c):

uint16_t calculate_code_checksum(uint8_t *data, int len) {
    uint32_t csum = 0;
    for (int i = 0; i < len; i++)
        csum += data[i];
    return csum & 0xffff;
}

After patching the frame intervals, the code checksum must be recalculated and written back, otherwise ms213x_flash will refuse to flash with "Code checksum mismatch."

Firmware Layout

Offset 0x0000 - 0x002F: Header (48 bytes)
  0x00-0x01: Magic bytes (0x3C 0xC3)
  0x02-0x03: Code length (big-endian)

Offset 0x0030 - 0xFBCF: Code section (64,416 bytes)
  Contains UVC descriptors, MJPEG encoder config, USB stack, etc.

Offset 0xFBD0 - 0xFBD3: Checksums (4 bytes)
  0xFBD0-0xFBD1: Header checksum (big-endian)
  0xFBD2-0xFBD3: Code checksum (big-endian)

Offset 0xF830 - 0xF92F: EDID (256 bytes, in user data area)

Bandwidth Considerations

1080p60 MJPEG over USB 2.0:

  • Typical bitrate: ~96 Mbps (200KB/frame × 60fps)
  • Worst case: ~144 Mbps (300KB/frame × 60fps)
  • USB 2.0 isochronous throughput: ~280-350 Mbps practical

The 60fps MJPEG stream uses roughly 30-40% of available USB 2.0 bandwidth, well within limits.

Files

File Description
MS2131_2023-06-10_backup_25f7_62d6.bin Original unmodified firmware backup
MS2131_60hz_final.bin Patched firmware with 60fps USB 2.0 support
patch_final.py Patch script
ms213x_flash.exe Flash tool (from GitHub)

Hardware

  • Capture Card: Monster MAD1-2024-BLK
  • Chipset: MacroSilicon MS2131 (VID 345f, PID 2131)
  • Firmware Date: 2023-06-10
  • Encoder: LinkPi ENC1-V3 (SS524V100, USB 2.0 only)

References

I also want to clarify that I used a slightly different version of the script in production because I had to figure out an issue with the checksum, so I had to patch it a couple of times before it finally worked. This is Claude's amalgamation of everything we did. So obviously proceed at your own risk, although I will be happy to provide a firmware file to anyone who wants to try this on one of these monster capture cards from Walmart.

Edit: I confirmed that this script produces an identical file to what I flashed on my cards. I took the original that used an earlier iteration of it and recreated the .bin file and the checksums were the same. Regardless I have the firmware file saved and will send it to whoever would like a copy.

Edit1: I thought I should update this and just say I was experiencing weird picture quality issues after flashing this. So I went back to stock and returned the cards and just ended up buying another encoder.

Although for USB 2.0 50 Hz, they're solid.

So, these will work fine at the above output without patching the firmware? I have tried a couple different USB 3.0 devices which would not work with my LinkPi ENC5-V2. I am running a very cheap usb 2.0 device which will only output 1080p at 30 fps.

I may try fooling around with one of these. My local Walmart has them in stock...

Without touching anything, you can get 50 FPS.

If you want to get technical, you can get 60 FPS, and I can send you my firmware file that I patched.

It's really just one executable that you run at the command line with a card plugged in and just pass it the name of the firmware file and it just writes it. You just want to make sure you back up the original firmware first. Fortunately, these things are cheap enough that if you break one, it's not life or death. I mean, I just started doing this today with these cards, so time will tell if they hold up, but so far, it looks fine.

50 FPS is 100% supported though, just out of the box with these. They also wake very quickly if you sleep your boxes. Like I'm tuning very fast with my Ospreys and allowing them to sleep, which I never did before.

This sounds like a pretty decent deal. I might even try some of your wizardry once I get my hands on one. This may help me find the balancing point between "cheap ain't good" and "good ain't cheap".

The wizardry is not too bad and so far I haven't seen any adverse effects. Maybe an output frame or two dropped but that's probably to be expected given that I'm doing something that it's not supposed to do.

That also might have been happening with the Elgatos as well.

Just ordered one to play with. :slightly_smiling_face:
Sometimes I just can't help myself. :man_shrugging:

Let me know if you end up patching it and how it performs. It does seem, at least on the Apple TV, to drop an output frame maybe every couple of minutes, but it's not anything visible. And for the tradeoff of not having 60 FPS, I think it's worth it. Plus instant wake with these cards.

Edit:
Did a little bit more research and it almost seems like the 50 FPS cap on these cards is actually a PAL default and not anything to do with a hardware limitation because it's running great. They seem to have enabled 60 FPS for the USB 3.0 path, but for some reason kept it at PAL default for the USB 2.0 path. It also has like a 25 FPS option, which is clearly PAL. Likely just lazy engineering, not actually a hardware limitation, because I don't see any issues other than the occasional dropped frame, which isn't even noticeable.

If anyone picks these up and would like a known good firmware file, please let me know and I'll be happy to again share it. I might even try to get it up on my website alongside this report so it's documented somewhere a little more durable.

The frame drops I'm seeing are incredibly intermittent and just like completely invisible. I don't notice them at all. So I would say for $20.00 and a little bit of work, this is a great value for 60 FPS capture.

Used CurbSide pickup and got home AND the encoder is missing from the box... They used cheap stickers that don't tear letting someone "peel" them back then put them back in place i guess. I knew stealing graphics cards was a thing and I have even warned my family to open expensive electronics up at the cash register to be sure...
But WHO steals a $20 dongle. :man_shrugging:
Made a 2nd trip back and exchanged my mostly empty box (had the cable and paper inside) for one that we opened before leaving Customer Service Desk. :slightly_smiling_face:
Hopefully I will get a chance to play with this in the next couple weeks.

Let me know how it works for you and if you want the firmware file I patched.

I'm still watching it very carefully to make sure that the stream is stable. Occasionally I see white flashes, but I'm not sure if that's the capture card, or if it has something to do with just DirecTV's feed. Or if it's my encoder.

I have a device I got from amazon based on the MS2130 chip that had the same 50fps limitation on the LinkPi USB2.0. I never returned it after I got a camlink and it was just sitting here on my desk, after seeing your post I tried the same thing you did and it worked! Thanks for sharing!

This is the device I have... Amazon.com: Guermok Video Capture Card, 4K USB3.0 HDMI to USB C Capture Card for Streaming, 1080P 60FPS, Compatible with iPad Mac OS Windows, Quest 3, OBS, PS5/4, Switch2/1, Xbox, Camera (Silver) : Electronics

I'm working on tweaking my patch since I'm seeing some weirdness with the MS2131 chip in mine. I'll report back after I get a chance to flash.

This is for the MS2131 and I will guniea pig when I get home but it is more conservative with the registers it patches and also disables sharpening I'm hoping disabling sharpening will help the frame drops and improve picture quality.

"""
MS2131 Firmware Patcher v2
==========================
1. Mirror USB 3.0 frame interval layout onto USB 2.0 descriptors
   - Adds 60fps as default and primary interval
   - Preserves 50fps as fallback
   - Drops 25fps (PAL artifact)
2. Disable sharpening (register 0xF6B4: 0x7A -> 0x00)

USB 3.0 reference: default=60, [60, 50, 30, 20, 10]
"""

import shutil
import struct
import sys

# --- Configuration ---
src = r'C:\Users\David\Desktop\MS2131_2023-06-10_backup_25f7_62d6.bin'
dst = r'C:\Users\David\Desktop\MS2131_60hz_v2.bin'

HEADER_LEN = 0x30

FPS_60 = b'\x0A\x8B\x02\x00'  # 166666
FPS_50 = b'\x40\x0D\x03\x00'  # 200000
FPS_30 = b'\x15\x16\x05\x00'  # 333333
FPS_25 = b'\x80\x1A\x06\x00'  # 400000
FPS_20 = b'\x20\xA1\x07\x00'  # 500000
FPS_10 = b'\x40\x42\x0F\x00'  # 1000000

NAMES = {FPS_60:'60', FPS_50:'50', FPS_30:'30', FPS_25:'25', FPS_20:'20', FPS_10:'10'}
def iv(b): return NAMES.get(bytes(b), '?')

# --- Load ---
shutil.copy2(src, dst)
data = bytearray(open(dst, 'rb').read())
print(f'Firmware: {len(data)} bytes')

magic = (data[0] << 8) | data[1]
if magic != 0x3CC3:
    print(f'Bad magic 0x{magic:04x}'); sys.exit(1)

code_len = (data[0x02] << 8) | data[0x03]
csum_offset = HEADER_LEN + code_len
stored_code_csum = (data[csum_offset + 2] << 8) | data[csum_offset + 3]
calc_csum = sum(data[HEADER_LEN:HEADER_LEN + code_len]) & 0xFFFF
if calc_csum != stored_code_csum:
    print(f'Checksum mismatch: stored={stored_code_csum:04x} calc={calc_csum:04x}'); sys.exit(1)
print(f'Checksum OK: {calc_csum:04x}\n')

# =========================================================================
# PATCH 1: Mirror USB 3.0 interval layout onto USB 2.0 descriptors
# =========================================================================
print('=' * 60)
print('PATCH 1: Mirror USB 3.0 intervals')
print('=' * 60)

# Target patterns (matched by current default + interval list):
#
# 5-interval descriptors (MJPEG 1920x1080, MJPEG 1600x1200):
#   FROM: default=50, [50, 30, 25, 20, 10]
#   TO:   default=60, [60, 50, 30, 20, 10]  (matches USB 3.0)
#
# 4-interval descriptor (UNCOMP 720x576):
#   FROM: default=50, [50, 25, 20, 10]
#   TO:   default=60, [60, 50, 20, 10]  (best fit for 4 slots)

SUBTYPE_NAMES = {0x05: 'UNCOMP', 0x07: 'MJPEG'}
desc_patched = 0

i = 0
while i < len(data) - 26:
    if data[i + 1] == 0x24 and data[i + 2] in (0x05, 0x07):
        bLen = data[i]
        if bLen >= 26 and i + bLen <= len(data):
            n = data[i + 25]
            if bLen == 26 + 4 * n and n > 0:
                subtype = SUBTYPE_NAMES.get(data[i + 2], '?')
                fidx = data[i + 3]
                w = struct.unpack_from('<H', data, i + 5)[0]
                h = struct.unpack_from('<H', data, i + 7)[0]
                default_iv = bytes(data[i + 21:i + 25])
                intervals = [bytes(data[i + 26 + j * 4:i + 26 + j * 4 + 4]) for j in range(n)]

                has_50 = (default_iv == FPS_50) or (FPS_50 in intervals)
                has_60 = (default_iv == FPS_60) or (FPS_60 in intervals)

                if has_50 and not has_60:
                    old_str = f'default={iv(default_iv)}, [{", ".join(iv(x) for x in intervals)}]'
                    print(f'  0x{i:04x} {subtype:6s} idx={fidx:2d} {w}x{h} n={n}')
                    print(f'    FROM: {old_str}')

                    if n == 5 and intervals == [FPS_50, FPS_30, FPS_25, FPS_20, FPS_10]:
                        # 5-interval: [50,30,25,20,10] -> [60,50,30,20,10]
                        new_default = FPS_60
                        new_intervals = [FPS_60, FPS_50, FPS_30, FPS_20, FPS_10]
                    elif n == 4 and intervals == [FPS_50, FPS_25, FPS_20, FPS_10]:
                        # 4-interval: [50,25,20,10] -> [60,50,20,10]
                        new_default = FPS_60
                        new_intervals = [FPS_60, FPS_50, FPS_20, FPS_10]
                    else:
                        print(f'    SKIPPED: unexpected interval layout')
                        i += bLen
                        continue

                    # Write default
                    data[i + 21:i + 25] = new_default
                    # Write intervals
                    for j, iv_bytes in enumerate(new_intervals):
                        data[i + 26 + j * 4:i + 26 + j * 4 + 4] = iv_bytes

                    new_str = f'default={iv(new_default)}, [{", ".join(iv(x) for x in new_intervals)}]'
                    print(f'    TO:   {new_str}')
                    desc_patched += 1

                i += bLen
                continue
    i += 1

print(f'\n  Descriptors patched: {desc_patched}\n')

# =========================================================================
# PATCH 2: Disable sharpening
# =========================================================================
print('=' * 60)
print('PATCH 2: Disable sharpening (reg 0xF6B4)')
print('=' * 60)

SHARP_PATTERN = b'\x90\xf6\xb4\x74\x7a\xf0'
SHARP_PATCHED = b'\x90\xf6\xb4\x74\x00\xf0'

sharp_count = 0
for i in range(len(data) - len(SHARP_PATTERN)):
    if data[i:i + len(SHARP_PATTERN)] == SHARP_PATTERN:
        pre_ok = (i >= 7 and data[i - 7:i - 4] == b'\x7f\xb5\x7e')
        post_ok = (i + 6 + 6 < len(data) and data[i + 6:i + 9] == b'\x7d\x11\x7f')
        print(f'  Found at 0x{i:04x}  context: pre={pre_ok} post={post_ok}')
        if pre_ok and post_ok:
            data[i:i + len(SHARP_PATTERN)] = SHARP_PATCHED
            sharp_count += 1
            print(f'    Patched: 0x7A -> 0x00')
        else:
            print(f'    SKIPPED: context mismatch')

print(f'\n  Luma  (0xF6BE) = 0x11 (disabled): already stock')
print(f'  Chroma (0xF6BF) = 0x11 (disabled): already stock\n')

# =========================================================================
# Checksum
# =========================================================================
print('=' * 60)
print('CHECKSUM')
print('=' * 60)
new_csum = sum(data[HEADER_LEN:HEADER_LEN + code_len]) & 0xFFFF
data[csum_offset + 2] = (new_csum >> 8) & 0xFF
data[csum_offset + 3] = new_csum & 0xFF
print(f'  Old: {stored_code_csum:04x}')
print(f'  New: {new_csum:04x}\n')

# =========================================================================
# Save and verify
# =========================================================================
open(dst, 'wb').write(data)

# Verify patched descriptors
print('=' * 60)
print('VERIFICATION')
print('=' * 60)
patched = bytearray(open(dst, 'rb').read())
i = 0
while i < len(patched) - 26:
    if patched[i + 1] == 0x24 and patched[i + 2] in (0x05, 0x07):
        bLen = patched[i]
        if bLen >= 26 and i + bLen <= len(patched):
            n_ = patched[i + 25]
            if bLen == 26 + 4 * n_ and n_ > 0:
                w_ = struct.unpack_from('<H', patched, i + 5)[0]
                h_ = struct.unpack_from('<H', patched, i + 7)[0]
                d_ = bytes(patched[i + 21:i + 25])
                ivs_ = [bytes(patched[i + 26 + j * 4:i + 26 + j * 4 + 4]) for j in range(n_)]
                has_50_ = FPS_50 in ivs_ or d_ == FPS_50
                has_60_ = FPS_60 in ivs_ or d_ == FPS_60
                dup_ = len(set(bytes(x) for x in ivs_)) < len(ivs_)
                if has_60_ and (f'{w_}x{h_}' in ['1920x1080','1600x1200','720x576']):
                    st_ = 'MJPEG' if patched[i+2]==0x07 else 'UNCOMP'
                    tag = ' ** DUPLICATE' if dup_ else ''
                    fallback = ' has 50fps fallback' if has_50_ else ' NO 50fps fallback'
                    print(f'  0x{i:04x} {st_:6s} {w_}x{h_} default={iv(d_)} '
                          f'[{", ".join(iv(x) for x in ivs_)}]{fallback}{tag}')
                i += bLen
                continue
    i += 1

print(f'\nSaved to {dst}')
print(f'Original untouched: {src}')

If anyone happens to try before I get home in an hour let me know how it works!

DANGIT! I picked up my Monster HDMI capture device from Walmart. As with all of the other USB 3.0 devices I have tried, the LinkPi will NOT accept the device AT ALL.

I am convinced that there's something wrong with the USB port on my LinkPi ENC5-V2. It will only accept USB 2.0 devices. I have done several factory resets, and it has successfully upgraded firmware multiple times. But, still NO GO on USB 3.0. What the friggin heck? It's drivin' me nuts! AARRGGHH!:rage:

Has anyone else had this problem? Or, am I just lucky??? :roll_eyes:

I don't want to speak too soon and then have random video corruption, but I may have hit on something where I up the frame rate on these cards to 60 FPS over USB 2.0, but also reduce the MJPEG compression by quite a bit to compensate for the extra strain caused by the extra frames. I also turned off the built-in image sharpening.

So far, I've been watching long enough that I can call it solved, but I would like to watch, for the next day or two to confirm. Once I'm certain I have things dialed in, because I'm definitely on the right track now, I will share the Python script to patch the firmware on these little Walmart cards.

If anyone is curious and wants to test, please let me know and I'll share the script directly. I just don't want to put it out there and have someone flash it and have an issue because I haven't had enough time to test it yet. So far it looks promising though.

Edit: I have my patch down to a frame syncing issue, like vsync being off in a video game. So close :crossed_fingers:

1 Like

Looks like another USB 3.0 card headed for a return. I am glad that you have confirmed that there really isn't a way to get 60 fps out of the Monster card.

As I mentioned before, my LinkPi won't even recognize the Monster branded or any other of the USB 3.0 capture cards I have tried...6 separate devices from 4 different brands.

The only thing which easily connects is my cheapo Vivitar USB 2.0 card from Walmart.

Well, now that I solved the problem with them, I'm happy with the Cam Links.
Honestly, for 50Hz over USB 2.0, these monster cards aren't a bad value.

But for pure 60Hz, the Cam Link is definitely the better option as long as you enable the USB auto-suspend.

I would be happy with this if I could only get it to communicate with my LinkPi...

My cheapo card claims 1080p @ 60hz. Is 60hz the same as 60fps? Is there a way to check the actual output of a card?

It's interchangeable.
It's literally cycles per second, so it corresponds to framerate.

It's really hard to tell the actual output of a card without testing it because they're all generally no-name. My next test is getting a dummy EDID passthrough adapter to see if that will get my cam links to enumerate a little bit faster. If that works, I'll share the findings here because that would be quite useful as those are really cheap.

The idea is it would keep a fake signal passed through to the Cam link so it never truly thinks the Osprey was disconnected even though it was.