y4mscaler(1)

okay so we're doing y4mscaler(1) from the y4mtools manual and bestie it is a whole entire unit of a page, so buckle up πŸ’–


🌸 NAME 🌸

y4mscaler β€” scale/crop/translate a YUV4MPEG2 stream


✨ SYNOPSIS ✨

y4mscaler [options] < Y4Mstream > Y4Mstream

πŸ¦‹ DESCRIPTION πŸ¦‹

y4mscaler is a general-purpose video scaler and it operates on YUV4MPEG2 streams β€” the exact kind that the MJPEGtools make and eat, like lav2yuv and mpeg2enc(1) πŸŽ€

She is built to live in a pipeline, okay? So input comes from stdin, and output goes to stdout. That's the whole vibe. No files, no drama, just pipes πŸ’…

So what does she actually do? The essential function of y4mscaler is to take a specified "active" region of the input stream (the source) and scale it into a specified active region of the output stream (the target). Pixels outside of the source's active region? Ignored, not even a little bit sorry. Pixels outside the target's active region? Filled with a background color. And as a lil bonus, the source may also have a matte applied to it β€” pixels outside the source matte get set to a separately specified background color. Yes, two different background colors, she contains multitudes 🫢

She handles chroma subsampling correctly, which means she can also do chroma subsampling conversions πŸ”₯. The YUV4MPEG2 stream format supports:

  • three varieties of 4:2:0 subsampling
  • plus 4:1:1
  • plus 4:2:2
  • plus 4:4:4
  • plus a 4:4:4 mode with an alpha channel
  • plus a monochrome luma-only mode
✨ (go read "NOTES ON CHROMA MODES AND SUBSAMPLING" for the tea on all of that)

She can also do simple interlacing conversions: flipping from top-field-first to bottom-field-first and vice-versa (and ngl, that one is lossy β€” she does it by discarding the first field, rip to that field 😭), and building a progressive stream out of an interlaced one by discarding every other field, which effectively halves the vertical resolution. Iconic but at a cost, bestie.

The source and target are defined by many, many parameters. But don't panic β€” y4mscaler has many, many heuristics built in to automagically set them appropriately 🌈. Most source parameters get taken straight from the input stream header, and whatever source and target parameters you haven't specified get guessed in a sane manner. She's got you πŸ’–

Oh and she ships with preset parameters for a bunch of common target streams: DVD, VideoCD (VCD), SuperVCD (SVCD), the associated still image formats, and DV. Slay.


πŸ’« EXAMPLES πŸ’«

Wanna make a stream that's appropriate for an SVCD? Say less:

y4mscaler -O preset=svcd

Wanna make a VideoCD (a non-interlaced format) out of a DV source (an interlaced format), while shifting the input frame 4 pixels to the left? Okay:

y4mscaler -I ilace=bottom-only -I active=-4+0cc -O preset=vcd

Got a widescreen NTSC DV source and you want it letterboxed with blue bars on the top and bottom? Cute:

y4mscaler -O sar=ntsc -O bg=RGB:0,0,255

Same widescreen NTSC DV source but you want it "fullscreen" β€” like, the sides get clipped, exactly how it looks on TV:

y4mscaler -O sar=ntsc -O infer=clip

Centered, letterboxed NTSC source β†’ widescreen (16:9) format stream for DVD, with the black bars removed:

y4mscaler -O preset=dvd -O sar=ntsc_wide -O infer=clip

And the main character of the examples: take the center 100x100 pixel chunk of an NTSC DV stream, wrap it in a 20-pixel blue border, and blow it up to a full-screen SuperVCD stream πŸŽ€

y4mscaler -I active=140x140+0+0cc -I matte=100x100+0+0cc -I bg=RGB:0,0,255 -O preset=svcd

πŸ‘‘ OPTIONS πŸ‘‘

The first three options β€” -v, -V, and -h β€” are the simple straightforward ones. They take either no arguments or one numeric argument. No thoughts, head empty, love that for them πŸ’…

  • -v [0,1,2] β€” set the verbosity level.
    • 0 = warnings and errors only.
    • 1 = add informative messages, too (default).
    • 2 = add chatty debugging message, too.
  • -V β€” show version information and exit. Bye πŸ‘‹
  • -h β€” show a help message (synopsis of options).

Now the big three: -I, -O, and -S. Each one takes one argument of the form parameter=value, and those specify parameters for the input, output, and scaling, respectively. You can use these options repeatedly to specify multiple parameters β€” stack 'em up, she doesn't mind 🫢

The parameter names and values are not case-sensitive. And when you see a definition like "parameter=[AAA|BBB|CCC]", that means only one of the listed keywords AAA, BBB, or CCC may be chosen. Succeeding options will override earlier ones. Last one wins, periodt.

πŸ’œ -I β€” input_parameter

Specify parameters for the source/input stream. All -I arguments are evaluated in order, and later arguments on the command-line will override earlier ones. And important: all -I arguments are evaluated before any -O arguments.

  • active=WxH+X+Yaa β€” specify the active region of the source frame, which is scaled to fit the active region of the target frame. Default is the full frame. (The "WxH" may be omitted, and the region size defaults to the size of the source frame.) W and H are width and height. X and Y are the offset of the anchor point. "aa" is the anchor mode (default: TL) β€” go see "NOTES ON REGION GEOMETRY" for the details, iykyk.
    • Example: active=200x180+30+24cc
  • matte=WxH+X+Y β€” specify a matte region for the source frame. All pixels outside of this region get set to the source background color. The default matte is the full frame. (The "WxH" may be omitted, and the region size defaults to the size of the source frame.) W and H are width and height. X and Y are the offset of the anchor point. "aa" is the anchor mode (default: TL) β€” see "NOTES ON REGION GEOMETRY" for details.
    • Example: matte=200x180+30+24cc
  • bg=RGB:r,g,b
  • bg=YCBCR:y,cb,cr
  • bg=RGBA:r,g,b,a
  • bg=YCBCRA:y,cb,cr,a β€” set the source background color. Pixels outside of the source's matte region get set to this color ✨. You can specify the color as either an R'G'B' or a Y'CbCr triplet. For example, the default color is black, specified as "bg=YCBCR:16,128,128" or "bg=RGB:0,0,0". The 'A' versions will set the alpha (transparency) value of the color. The alpha range is [0,255] for RGBA and [16,235] for YCBCRA. The default is fully-opaque (255 for RGBA, 235 for YCBCRA).
  • norm=[NTSC|PAL|SECAM] β€” specify the "norm" of the source stream. This is normally inferred from the stream header, so you rarely need it.
  • ilace=[NONE|TOP_FIRST|BOTTOM_FIRST|TOP_ONLY|BOTTOM_ONLY] β€” specify the interlacing used by the source stream. NONE, TOP_FIRST, and BOTTOM_FIRST correspond to non-interlaced, top-field-first, and bottom-field-first. These values are normally inferred from the stream header; specifying them will override the stream header. TOP_ONLY and BOTTOM_ONLY specify that only the top or bottom field of each frame should be used, and the other field is discarded 😭. These options can only be used with an interlaced input, and they cause the interlaced stream to be treated as a progressive stream with half the height. (This is especially useful for making a VCD out of a full-size interlaced input stream, fr fr.)
🚨 But listen: these two special options can only be used when the source is a pure progressive stream β€” as opposed to a YUV4MPEG2 "mixed-mode" stream. Don't try it, she'll be sad.
  • chromass=[420JPEG|420MPEG2|420PALDV|444|422|411|mono|444alpha] β€” specify the chroma subsampling mode used in the source stream. This parameter is inferred from the stream header, so this keyword should almost never be used in a source specification. The only useful reason to specify this keyword is to override one variety of 4:2:0 with another.
⚠️ Any other use will cause processing to fail. Not a vibe. Don't.
  • sar=N:D
  • sar=[NTSC|PAL|NTSC_WIDE|PAL_WIDE] β€” specify the sample-aspect-ratio of the source stream. The value can either be a numeric ratio (such as "10:11") or one of the keywords, which correspond to the CCIR-601 values for 4:3 or 16:9 displays, respectively. This parameter is usually inferred from the stream header.

πŸ’œ -O β€” output_parameter

Specify parameters for the destination/output stream. All -O arguments are evaluated in order, and later arguments on the command-line will override earlier ones. And all -O arguments are evaluated after any -I arguments.

  • size=WxH
  • size=SRC β€” set the output/target frame size, as width W and height H in pixels. Use the keyword SRC to specify that the target frame size should match the source frame size. Matchy matchy, we love a coordinated moment πŸ’–
  • active=WxH+X+Yaa β€” specify the active region of the target frame, and the active region of the source frame gets scaled into it. Default is the full target frame. (The "WxH" may be omitted, and the region size defaults to the size of the target frame.) W and H are width and height. X and Y are the offset of the anchor point. "aa" is the anchor mode (default: TL) β€” "NOTES ON REGION GEOMETRY" has the lore.
    • Example: active=200x180+30+24cc
  • bg=RGB:r,g,b
  • bg=YCBCR:y,cb,cr
  • bg=RGBA:r,g,b,a
  • bg=YCBCRA:y,cb,cr,a β€” set the target background color. Pixels outside of the target's active region get set to this color ✨. You can specify the color as either an R'G'B' or a Y'CbCr triplet. For example, the default color is black, specified as "bg=YCBCR:16,128,128" or "bg=RGB:0,0,0". The 'A' versions will set the alpha (transparency) value of the color. The alpha range is [0,255] for RGBA and [16,235] for YCBCRA. The default is fully-opaque (255 for RGBA, 235 for YCBCRA).
  • ilace=[NONE|TOP_FIRST|BOTTOM_FIRST] β€” specify the interlacing used by the target stream. NONE, TOP_FIRST, and BOTTOM_FIRST correspond to non-interlaced, top-field-first, and bottom-field-first. The default is to match the source stream. If the source and target are both interlaced but with different modes (like, one is bottom-first and the other is top-first), then y4mscaler will convert one mode to the other by dropping the first source field. Sorry to that field 🫑
  • chromass=[420JPEG|420MPEG2|420PALDV|444|422|411|mono|444alpha] β€” specify the chroma subsampling mode to be used in the target stream. The default is to match the source mode. See "NOTES ON CHROMA MODES AND SUBSAMPLING" for more info, bestie.
  • sar=N:D
  • sar=[SRC|NTSC|PAL|NTSC_WIDE|PAL_WIDE] β€” specify the sample-aspect-ratio of the source stream. The value can either be a numeric ratio (such as "10:11") or one of the keywords, which correspond to the CCIR-601 values for 4:3 or 16:9 displays, respectively. The keyword SRC specifies that the target SAR should match the source.

okay that's part 1 and there is so much more coming so don't go anywhere πŸ’…

  • scale=N/D, Xscale=N/D, Yscale=N/D β€” set the scaling ratios as a fraction, like scale=1/2. scale= sets X and Y at the same time; Xscale= and Yscale= let you do them independently. πŸ’…
  • infer=[PAD|CLIP|PRESERVE_X|PRESERVE_Y] β€” picks the mode used to infer scaling ratios from active regions and SARs. These keywords are mutually exclusive, bestie. Default is PAD.
  • infer=[SIMPLIFY|EXACT] β€” decides whether that heuristic up there uses exact ratios, or whether it's allowed to nudge active regions around a lil bit to simplify the scaling ratios. Mutually exclusive keywords again. Default is SIMPLIFY.
  • align=[TL|TC|TR|CL|CC|CR|BL|BC|BR] β€” sets the alignment point between the source and target active regions. The keywords mean "top-left", "top-center", "top-right", etc. The corner/point you name on the source region gets mapped to that exact same spot in the target region, and any cropping or padding applied to the active regions preserves that mapping. Default is CC ("center-center"), aka the source and target regions are mutually centered. Keywords are mutually exclusive. Default is CC. Go read "NOTES ON SOURCE AND TARGET ALIGNMENT" for the deets. ✨
  • preset=[VCD|CVD|SVCD|DVD|DVD_WIDE|DV|DV_WIDE| SVCD_STILL_HI|SVCD_STILL_LO|VCD_STILL_HI|VCD_STILL_LO| ATSC_720P|ATSC_1080I|ATSC_1080P] β€” drop in preset target parameters for a bunch of common output formats. You can override individual parameters by following it up with more -O settings. These keywords are mutually exclusive. For the full rundown of what each preset keyword implies, see "NOTES ON TARGET PRESETS". πŸ‘‘
    • VCD β€” 352-wide VideoCD, progressive
    • CVD β€” 352-wide (full-height) ChinaVideoDisc
    • SVCD β€” 480-wide SuperVCD
    • DVD β€” 720-wide DVD
    • DVD_WIDE β€” 720-wide DVD, anamorphic pixels
    • DV β€” 720-wide DV (bottom-field-first, 4:1:1)
    • DV_WIDE β€” 720-wide DV, anamorphic pixels
    • SVCD_STILL_HI β€” high-resolution SVCD still image
    • SVCD_STILL_LO β€” low-resolution SVCD still image
    • VCD_STILL_HI β€” high-resolution VCD still image
    • VCD_STILL_LO β€” low-resolution SVCD still image
    • ATSC_720P β€” ATSC 720p (progressive HDTV)
    • ATSC_1080I β€” ATSC 1080i (interlaced HDTV)
    • ATSC_1080P β€” ATSC 1080p (HDTV)

πŸŽ€ -S scaling_parameter πŸŽ€

Hand over parameters for the scaling engine. Every -S argument gets evaluated in order, and anything later on the command line overrides what came before. Periodt.

  • mode=MONO β€” request monochrome scaling. The source gets treated as monochrome and its chroma channels are straight-up ignored. The output stream's chroma channels get zeroed, so you get a grayscale result. πŸ–€
  • mode=LINESWITCH β€” request line swapping. Basically, the top and bottom fields inside each frame get swapped. This can help with malformed streams that have a messed-up spatial order. Heads up: this only does anything on interlaced streams.
  • scaler=scaler-name β€” use a specific scaling engine. The available engines are:
    • 'default' β€” Matto's Generic Scaler (the default)
  • option=scaler-option β€” specify an option for whichever scaling engine you chose. Want to see everything available? Use option=help.

For the default engine, the available scaler-options pick the filter kernel:

  • box β€” box filter
  • linear β€” linear interpolation
  • quadratic β€” quadratic interpolation
  • cubic β€” cubic interpolation, Mitchell-Netravali spline
  • cubicCR β€” cubic interpolation, Catmull-Rom spline
  • cubicB β€” cubic interpolation, B-spline
  • cubicK4 β€” Keys 4th-order cubic
  • sinc:N β€” sinc with Lanczos window, N cycles

Want different kernels for the x and y scaling directions? Use two kernel names separated by a comma, e.g. option=box,quadratic.

sinc:N gives the best quality results (least aliasing), but it's also the slowest, no cap. Quality goes up with bigger values of N, and so does processing time. In the graphics world, cubic is generally regarded as the 3rd-order cubic spline with the best trade-off between smoothing and aliasing. box gives the worst quality results (most aliasing) but is the fastest. The default kernel is cubicK4, which has a flatter passband and sharper cutoff than cubic. (It needs the same computational power as sinc:4, but produces fewer ringing artifacts.) πŸ¦‹


🌈 NOTES ON TARGET PRESETS 🌈

Here's the full tea on the settings each target preset= keyword hands you. When two values show up, the primary one is for NTSC streams and the value in {braces} is for PAL streams. If the interlace value is unspecified, it's inherited from the source; otherwise, the indicated target interlacing is required.

  • VCD β€” frame size 352x240{288}, interlace none, SAR 10:11{59:54}, subsampling 4:2:0-JPEG
  • CVD β€” frame size 352x480{576}, interlace ---, SAR 20:11{59:27}, subsampling 4:2:0-MPEG2
  • SVCD β€” frame size 480x480{576}, interlace ---, SAR 15:11{59:36}, subsampling 4:2:0-MPEG2
  • DVD β€” frame size 720x480{576}, interlace ---, SAR 10:11{59:54}, subsampling 4:2:0-MPEG2
  • DVD_WIDE β€” frame size 720x480{576}, interlace ---, SAR 40:33{118:81}, subsampling 4:2:0-MPEG2
  • DV β€” frame size 720x480{576}, interlace bottom-first, SAR 10:11{59:54}, subsampling 4:1:1
  • DV_WIDE β€” frame size 720x480{576}, interlace bottom-first, SAR 40:33{118:81}, subsampling 4:1:1
  • SVCD_STILL_HI β€” frame size 704x480{576}, interlace none, SAR 10:11{59:54}, subsampling 4:2:0-MPEG2
  • SVCD_STILL_LO β€” frame size 480x480{576}, interlace none, SAR 15:11{59:36}, subsampling 4:2:0-MPEG2
  • VCD_STILL_HI β€” frame size 704x480{576}, interlace none, SAR 10:11{59:54}, subsampling 4:2:0-JPEG
  • VCD_STILL_LO β€” frame size 352x240{288}, interlace none, SAR 10:11{59:54}, subsampling 4:2:0-JPEG
  • ATSC_720p β€” frame size 1280x720, interlace none, SAR 1:1, subsampling 4:2:0-MPEG2
  • ATSC_1080i β€” frame size 1920x1080, interlace (required), SAR 1:1, subsampling 4:2:0-MPEG2
  • ATSC_1080p β€” frame size 1920x1080, interlace none, SAR 1:1, subsampling 4:2:0-MPEG2

πŸ’– NOTES ON REGION GEOMETRY πŸ’–

Active and matte regions get specified with a geometry string shaped like WxH+X+Yaa. The WxH part is the size of the region β€” Width and Height in pixels. (Sometimes the WxH can be left out entirely, and the region size just defaults to the full frame size.) The +X+Y part is the region's position, expressed as an offset relative to the anchor point given by aa. 🫢

The aa code is one of TL, TC, TR, CL, CC, CR, BL, BC, or BR. These stand for "top-left", "top-center", ..., "bottom-center", "bottom-right". Not case-sensitive, so go off with your lowercase. πŸ’…

The +X+Y is the offset of the region's anchor point from the frame's anchor point. Example time: +20+30TL means the top-left corner of the region sits 20 pixels to the right and 30 pixels down from the top-left corner of the frame.

Offsets can be negative too, bestie. Like -4+0CC means the region's center (vertical and horizontal) is offset 4 pixels to the left of the center of the frame.

The default anchoring point for geometry strings is TL, aka the top-left corner.


✨ NOTES ON SOURCE AND TARGET ALIGNMENT ✨

Lowkey the most common situation ever: the source and target active regions don't match exactly. This happens when, using the given or calculated scaling ratios, the source region scales to a different size or shape than the target region. When that goes down, the source and target regions get mutually clipped, so only the part of the source that actually fits gets scaled into the target.

Before any clipping or padding happens, the source and target regions are aligned so the points you named with align=aa line up exactly. That aa code is an anchor point, same as described above.

So for example, align=BC says the bottom-center of the source region should get mapped to the bottom-center of the target region. In other words, the source region is horizontally centered and vertically aligned to the bottom of the target region before clipping:

               ----------------  source
               |abcdefghijklmn|
            ---|opqrstuvwxyz01|---  target      ----------------
            |  |234567890ABCDE|  |              |234567890ABCDE|
            |  |FGHIJKLMNOPQRS|  |              |FGHIJKLMNOPQRS|
            |  |TUVWXYZabcdefg|  |              |TUVWXYZabcdefg|
            ----------------------              ----------------
                   Before                       Mutually Clipped

If instead you'd gone with align=TR, the source would get clipped in a different place, and scaled into a different region of the target frame:

            ----------------------                 ----------------
            |     |abcdefghijklmn|                 |abcdefghijklmn|
            |     |opqrstuvwxyz01|                 |opqrstuvwxyz01|
            |     |234567890ABCDE|                 |234567890ABCDE|
            ------|FGHIJKLMNOPQRS|                 ----------------
         target   |TUVWXYZabcdefg| source
                  ----------------
                   Before                       Mutually Clipped

The default alignment mode is CC, meaning the source and target are mutually centered. πŸŽ€

πŸ’« NOTES ON SCALE FACTOR INFERENCE πŸ’«

ok so bestie, here's the tea β˜• β€” if you don't hand over your X and Y scaling factors explicitly, y4mscaler is gonna infer them for you, based on the source and target active regions plus the sample aspect ratios (SAR's). she's smart like that πŸ’…

But like… if the active regions aren't shape-compatible (given those SAR's, bestie), then the source and target regions get clipped or padded β€” and you get to pick the policy. You set it with the infer= parameter, choosing one of four keywords: PAD, CLIP, PRESERVE_X, or PRESERVE_Y. (And the default? PAD.) ✨

  • PAD β€” Pick scaling factors that pad the source, but make sure all of the source image content ends up in the target. nothing left behind 🫢
  • CLIP</c> β€” Pick scaling factors that clip the source, but fill the target region as much as possible. maximum target saturation βœ‚οΈ
  • PRESERVE_X β€” Pick scaling factors that preserve as much of the horizontal source content as possible. horizontal girlies rise πŸ‘‘
  • PRESERVE_Y β€” Pick scaling factors that preserve as much of the vertical source content as possible. vertical girlies, this one's for you πŸ‘‘

And it doesn't stop there, because the policy ALSO gets affected by one of two other keywords: SIMPLIFY or EXACT. (Default is SIMPLIFY, fyi.)

  • EXACT β€” Calculate exact scaling factors. precision, periodt πŸ“
  • SIMPLIFY β€” Adjust the active regions and scaling factors (within 10% or so) to simplify the ratios as much as possible. (Like, crop or pad a tiny bit to get a ratio of 2/1 instead of 45/22.) she's doing aesthetic math πŸ’–

🌈 NOTES ON CHROMA MODES AND SUBSAMPLING 🌈

ok so y4mscaler can convert streams from one chroma subsampling mode to another. And ngl? These conversions are always lossy operations, bestie. Even if the overall frame is going through plain 1/1 scaling. no cap, it's just how it is 😭

y4mscaler will infer the source's subsampling mode from tags in the input stream header. The target presets (preset=XXX) will attempt to set the target subsampling mode appropriately. Otherwise, by default the target subsampling mode matches the source. And if you wanna be extra and set it yourself? You can explicitly set the subsampling mode for the source and/or the target using the chromass= parameter. main character energy πŸ’…

y4mscaler is capable of reading and writing streams in the 4:4:4, 4:2:2, 4:1:1, and 4:2:0 (all three varieties) subsampling modes. BUT β€” heads up 🚨 β€” the first three are a relatively new addition to the YUV4MPEG2 standard, and many MJPEGtools will fail to process them correctly, if at all. (Not slay of them, honestly. πŸ’€)

Good news though: smil2yuv and raw2yuv can produce native 4:1:1 streams from NTSC DV video, which can then be converted to 4:2:0 by y4mscaler before further processing by other tools. teamwork makes the dream work 🧚

Now, alpha channel drama:

  • If the source has an alpha-channel (i.e. 444ALPHA mode) and the target does not β€” the alpha channel just gets discarded. bye girl πŸ‘‹
  • If the target has an alpha-channel but the source does not β€” a constant alpha-channel will be created using the alpha-value of the target's background color (as set by -O bg=). The default is fully-opaque. πŸŽ€

Similarly, if the target has chroma channels but the source does not (i.e. a luma-only MONO stream), then the chroma channels in the output will be set according to the background color. consistent, bestie πŸ’œ


πŸ¦‹ NOTES ON ANOMALOUS INTERLACE MIXTURES πŸ¦‹

so the YUV4MPEG2 format allows for "mixed-mode interlacing" streams β€” which may contain a mixture of progressive and interlaced frames. each frame is tagged as temporally interlaced or progressive, and vertically-subsampled frames (4:2:0 formats) are further tagged as spatially interlaced or not.

Unfortunately 😭 that allows for the possibility of anomalous frames β€” ones that happen to be temporally interlaced (fields sampled at different times) but spatially progressive (subsampling performed across the entire frame), or vice-versa. and like, the only reasonable thing to do with such anomalous frames is to vertically-upsample the chroma, essentially making the problem go away as quickly as possible. sweep it under the rug, iconic behavior πŸ™ˆ

y4mscaler will only process such frames if the target output format is non-vertically-subsampled (e.g. 4:4:4, 4:2:2, etc.) and no other vertical processing is required. Otherwise y4mscaler will bail on processing in midstream when it encounters an anomalous frame. πŸ’€

If there is any possibility of encountering such an error, y4mscaler will print a warning when processing begins. so watch that stderr, bestie, she's telling you something πŸ‘€

✨ EXIT STATUS ✨

  • 0 β€” Successful program execution. we ate and left no crumbs 🍽️
  • 1 β€” Usage, syntax, or operational error. 😭

🫢 AUTHOR 🫢

This manual page is copyright 2005 by Matthew Marjanovic. Feel free to direct any questions, remarks, problems, or bug reports concerning this tool to <dmg @ mir.com>.

For more info, see our website at:

<http://www.mir.com/DMG/>

For more information on MJPEGtools, consult:

<http://mjpeg.sourceforge.net/>

πŸ‘‘ SEE ALSO πŸ‘‘

mjpegtools(1), yuv2lav(1), mpeg2enc(1), ppmtoy4m(1), raw2yuv(1), smil2yuv(1), yuvplay(1), yuvscaler(1)


and that's the whole page bestie, you made it to the end πŸŽ‰ this lil gem lives in the y4mtools collection, dated February 14, 2003 (yes, valentine's day, it's giving romance πŸ’–), and it's filed under y4mscaler(1). go forth and scale slayfully βœ¨πŸ’…πŸŒΈ