← Firmware research

Hbin, Vbin, Hbin2 and RWZM

The fp has two unrelated ways to make a frame smaller before it reaches the card, and six names for where to tap the result. Most of those names are never used. This is what each one is, which the camera actually switches on, and the decision that picks between them.

Method
Read out of the firmware image, with the branch that decides everything verified instruction by instruction rather than from a decompiler.
Checked against
An independent instruction-level trace of the same firmware run in an emulator (three cases, from the FP3K handoff), and the camera's own table of all 306 recording profiles. Both agree with what is below.
Not from a camera
Nothing here was measured on hardware. It is what the firmware would do, which is a weaker claim than what a camera did — see what is still open.

The short version

Three things, if you read nothing else:

  1. Two of the six taps are real

    Crmf and Hbin2 are the only ones the firmware ever switches on. Gain, Vbin and Spc are never written at all, and Hbin — the one everybody assumed was the normal case — is only ever written to a tap that is left switched off.

  2. Hbin2 is a second stage, not a second algorithm

    The hardware has two horizontal shrink stages and only one vertical. That is exactly why the list reads Vbin, Hbin, Hbin2. They are positions on a chain, not different maths.

  3. The two methods are not mutually exclusive

    When the resampler is on, the binning is not switched off — it is moved to the second stage. And in the one case that matters for recording, it is not even moved: both run at once.

What the chain looks like

Raw pixels from the sensor do not go straight to a file. They run down a correction chain — gain, defect correction, various raw-domain fixes — and the firmware can pull a copy out of that chain at several points and write it to memory. Those pull-out points are called windows, and there are three of them.

The correction chain, its six tap positions, and the three output windows from the sensor → correction chain Gain Crmf Vbin Hbin Hbin2 Spc 0 1 2 3 4 5 window a0 3-bit selector window a7 3-bit selector RWZM window a1 on / off only memory buffer
a0 and a7 each have a three-bit knob choosing which of six points on the chain to copy from. a1 has no knob: it is hard-wired behind the resampler and only has an on/off switch. The red lines show a typical setting, not a fixed one.

Why three? Because recording and the live-view screen usually want different sizes. One window can feed the file while another feeds the display.

The six names come from a debug line the firmware prints when it sets this up (crct1_win_a0 : CrctHbinToBufA and so on). That line is where all four names in this page's title come from, and reading it as a list of alternatives is what sent the earlier notes wrong — three of the six are positions nothing ever selects.

Two different ways to shrink

Binning and resampling are not two settings of one thing. They are separate hardware doing separate jobs.

hbin / vbinRWZM
what it does weighted average of 3 or 5 neighbouring same-colour pixels general resampler, any ratio
ratios available horizontal ÷3 or ÷5, vertical ÷3 only anything from 1.0× up, in 1/1024 steps
where a stage on the correction chain a separate path beside the chain
how it is set an enum: 0, 1, 2 a number: 1024 means 1.0×

The binning enum is tiny and the conversion is worth seeing, because it explains a gap people keep tripping over:

enumhorizontal tapsvertical taps
01 — off1 — off
13 — ÷33 — ÷3
25 — ÷5illegal
There is no ÷2 here, and vertical has no ÷5. Writing an out-of-range value is not a cosmetic bug: the conversion function asserts and drops into an infinite loop, which on a camera means it locks up where it stands. Since vertical stops at ÷3, the only binning combination that keeps a 3:2 frame 3:2 is ÷3 with ÷3.

The resampler's number is a divisor scaled by 1024, so it reads directly as a shrink factor:

The RWZM ratio scale, showing the floor at 1024 <1024 clamped 1024 1.0× 1280 1.25× 1500 1.46× 1600 1.5625× 2048 2× 3072 3× no upper check in the firmware →
The value is a divisor ×1024, so bigger means smaller output. The clamp only has a floor: if (1024 >= ratio) ratio = 1024. There is no upper check anywhere in the path — 3072 is simply the largest the stock tables use.

The hardware has two horizontal stages

Here is the part that answers "what is Hbin2". Laying the registers out by what they drive:

Main pipeline: one vertical binning stage and two horizontal ones vertical 0x300F0800 horizontal — stage 1 0x300F0840 horizontal — stage 2 0x300F08C0 out coeffs 0x300F0810…0820 9 × u16, /4096 coeffs 0x300F0850…085C 4 × 3 × u8, /64 coeffs 0x300F08C4 1 × 3 × u8, /64 tap “Hbin” tap “Hbin2” selector = 3 selector = 4 never enabled 36 profiles tap “Vbin” selector = 2 never written
One vertical stage, two horizontal ones — which is exactly the shape of the name list: one Vbin, two Hbin. They are positions on a chain, not different algorithms. The sub-pipeline, used for live view, is a cut-down copy with no second horizontal stage at all.

Why a second stage exists at all

Because of an arbitration rule. When the resampler is active, the firmware sometimes has to take the horizontal binning out of stage 1 — but it does not throw the setting away. Four instructions, and they are worth reading literally:

The horizontal binning code being moved from stage 1 to stage 2 before stage 1 code = 1 stage 2 code = 0 after stage 1 code = 0 stage 2 code = 1 c032dda4ldrb ip, [sp, #0x22]; read the horizontal code c032dda8strb ip, [sp, #0x30]; save it into stage 2's slot c032ddacmov ip, #0 c032ddb0strb ip, [sp, #0x22]; clear stage 1
The setting is copied to stage 2 before stage 1 is cleared. Earlier notes in this project read the last two instructions on their own and concluded the binning was disabled. It is not — the work moves, which is what the second stage is for.

The decision

All of the above is settings. What actually picks them is a single function that looks at two things — how much does recording want to shrink and how much does live view want to shrink — and falls into one of six outcomes.

This function was previously believed to be unreachable without a camera, on the grounds that the table holding it was built at runtime. It is not: the table is a constant in ROM and the decision is eight plain branches.

The six outcomes of the path selector recording? yes no rec zoom = lv zoom? yes no both 1.0×? yes no which one is 1.0×? B Crmf 172 profiles C Hbin2 36 profiles D Crmf 81 profiles E RWZM 17 profiles F Hbin2, both pipelines 0 A nothing enabled lv is 1.0× → neither → rec is 1.0× →
Six outcomes, of which branch F is never reached by any stock profile — the code for driving both pipelines at once is present and unused. Counts are over all 306 recording profiles in Ver.5.02.

Try it

Pick what recording and live view each ask for and see which branch the firmware falls into. The three preset buttons are the cases that were independently traced in an emulator, and this page agrees with all three.

E CrctRwzmToBufA
windows a0 / a7 / a1
0 / 0 / 1
a0 selector
1 — Crmf
a7 selector
3 — Hbin
0x300F0870
1
main pipeline gets
recording's zoom, live view's binning
coefficient set
record 1 — [1 14 1] / 16
binning and zoom on one stage?
yes

What is actually switched on

Running the recovered decision over every profile in the firmware gives the whole picture at once. This is the answer to "which of the six names matter":

B
172
D
81
C
36
E
17
F
0
selectornamewritten by the firmware?ever on a window that is enabled?
0CrctGainToBufAneverno
1CrctCrmfToBufAyesyes — 253 profiles
2CrctVbinToBufAneverno
3CrctHbinToBufAyes, in branch Eno — window is off
4CrctHbin2ToBufAyesyes — 36 profiles
5CrctSpcToBufAneverno

Two of six. Hbin is written in exactly one branch, onto a window that branch leaves switched off — so the tap everyone assumed was the normal horizontal case is the one that never carries anything.

There is a second, separate copy of this decision belonging to another imager object in the firmware. It was checked too, and it is narrower still: its selectors are only ever Crmf or Hbin2. What selects between the two imagers has not been traced.

Binning and the resampler run together

Branch E — recording wants to shrink, live view does not — is the one that matters for every UHD clip the camera has ever shot. It does something the earlier notes said was impossible.

The arbitration from the earlier diagram is guarded by a flag. In branch E the firmware sets that flag to 1, which makes the arbitration condition false, so the move never happens. And the main pipeline is handed recording's resampler ratio together with live view's binning taps:

In branch E the main pipeline runs binning and the resampler at once from the recording profile RWZM 1600 — 1.5625× from the live-view profile hbin ÷3, vbin ÷3 main pipeline both stages active at once window a1 → buffer CrctRwzmToBufA 0x300F0870 = 1 — the flag that stops the arbitration firing
The 17 profiles in branch E are exactly the 17 whose live-view binning is set to ÷3 — the two sets match row for row. All of them are UHD-class geometries: 3856×2170, 3840×2160 and 4096×2160.

The two kernels

The weights are not hard-wired in silicon; they come from one of two 56-byte records in ROM, and branch E picks the second. They are strikingly different:

record 0 — [1 2 1] / 4

A real average. Used by the DC Crop path.

25% 50% 25%

record 1 — [1 14 1] / 16

Centre carries 87.5%. Close to a straight pass-through.

6.25% 87.5% 6.25%

That matters for image quality: the mode that matters most for recording is using the kernel that barely averages at all. Independent noise analysis of real clips found the same thing from the other direction — 3K footage shows almost no correlation between neighbouring same-colour pixels, where UHD shows clearly more.

Both records only contain three-tap weights. The ÷5 setting needs five, and those numbers are not in either record. Where they come from is not known — possibly fixed in silicon, possibly somewhere not yet found.

Can the resampler stretch, or enlarge?

Three questions that come up whenever someone wants anamorphic or a different aspect ratio out of this hardware.

Can the two axes differ?

In the code, yes, with no restriction at all. Horizontal and vertical are two separate registers, clamped separately by two structurally identical pieces of code, and the enable test is an or: the resampler switches on if either axis is not 1.0×. If the hardware required a square ratio, that test would be the place to enforce it, and it does not.

But no stock profile does it. Across all 306, the live-view pair and the recording pair each have horizontal equal to vertical, row for row. There is no factory precedent to copy, and no reference footage to compare against.

Can it enlarge?

No. The clamp is one-sided. The value is a divisor, so enlargement needs something below 1024, and anything at or below 1024 is pulled back to 1024. The only way past that is writing the hardware register directly, and whether the silicon does anything sensible below 1.0× is simply unknown — there is no evidence either way in the code.

So can the aspect ratio be changed?

The resampler is the only layer that can, which is worth stating plainly:

layerratios it can produce
sensor readout modea fixed menu of geometries
hbin / vbin÷3 or ÷5 horizontally, ÷3 vertically
RWZManything, and the axes are independent

Three things have to be handled if anyone tries it. The output-size formula runs once per axis, so the size the firmware computes changes with the ratio, and that size has to line up with what the producer actually writes, the canvas, and the preview descriptor. The four ratio fields cannot be split — setting only the recording pair and leaving the preview pair alone has been tried on a camera and produced a corrupted recording followed by a lockup. And there is no factory example, so there is nothing to compare a result against.

If someone does try it, branch C is the least entangled starting point: one pipeline, one set of numbers. Branch E is the worst, because there the binning and the resampler are stacked on the same pipeline and an anamorphic ratio would pass through both.

What the earlier notes got wrong

This page exists because three load-bearing claims in the project's own research notes turned out to be wrong. They are listed here rather than quietly fixed, because each one had already shaped work.

A fourth one was mine, during this work. A first pass at the profile table concluded that a third of the stock profiles used unequal horizontal and vertical ratios. That was wrong: the table's columns are not laid out in the order of the structure they describe, and reading neighbouring columns as neighbouring fields turned "preview versus recording" into "horizontal versus vertical". The correct answer is that no stock profile is anamorphic. The error was caught by checking four known addresses against an independent description of the table.

Still open

Sources

Everything here comes from the Ver.5.02 firmware image. The branch that decides the path, the arbitration, the register writers and the enum conversions were each read as instructions rather than trusted from a decompiler. Three independent confirmations were available and all three agree: an emulator trace of the same firmware from the FP3K technical handoff covering three configurations, that handoff's separate description of the profile table, and the noise analysis of real clips which matches the kernel that branch E selects.

The working notes behind this page are in the repository, and several are in Traditional Chinese: research/imaging-hw/notes/CRCT_PATH_SELECTOR_SOLVED.md is the primary one, with CRCT_REDUCTION_PATHS.md and REDUCTION_INVENTORY.md as the earlier passes it corrects.