Skip to content

Conversion of 10/12/14 bit types. Info() new params.#101

Merged
qyot27 merged 709 commits intoAviSynth:MTfrom
pinterf:MT
Jun 15, 2019
Merged

Conversion of 10/12/14 bit types. Info() new params.#101
qyot27 merged 709 commits intoAviSynth:MTfrom
pinterf:MT

Conversation

@pinterf
Copy link
Copy Markdown

@pinterf pinterf commented Aug 23, 2016

When a color space with bit-depth 10/12/14 is involved, conversion assumes the real 10-12-14 range, unless truerange=false is specified.
When truerange==false, the internal range is expanded to 16 bits, only the pixel_format hints to the limited range.
YUV(A) conversions are using bit-shifts. For planar RGB, full range is used (0-1023/4095/16383/65535). Planar RGB is always using 65535 when truerange==false is specified.

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Aug 23, 2016

Info() was modified. Added font (default Courier New), size (default 18), text_color and halo_color parameters, similar to (but less than) e.g. in ShowFrameNumber.
It had hardcoded write area dimensions and assumptions but I have put aside the problem. After #99 I decided to make it work the proper way.

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Aug 24, 2016

New functions: ConvertToRGB48, ConvertToRGB64 (similar to 24/32), ConvertToPlanarRGB
They work within same bit depth: e.g.
YUV420P16 -> ConvertToRGB48 is OK.
RGB48<->RGB64 is OK
RGB32 -> ConvertToRGB64 is not OK.
YUV422PS -> ConvertToPlanarRGB is also OK
todo: PlanarRGB to packed RGB

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Aug 24, 2016

Test cases
lsmashvideosource("test.mp4", format="YUV420P8")
x=last
x = x.Spline16Resize(900,500)

#YUV 8 bit -> Packed RGB OK (still works as in original AVS)
c8_420 = x.ConvertToYUV420().Info()
c8_rgb = x.ConvertToRGB().Info()
c8_rgb24 = x.ConvertToRGB24().Info()
c8_rgb32 = x.ConvertToRGB32().Info()
StackHorizontal(StackVertical(c8_420.ConvertToYUV444(),c8_rgb.ConvertToYUV444()),StackVertical(c8_rgb24.ConvertToYUV444(),c8_rgb32.ConvertToYUV444()))

#YUV 16 bit -> Packed RGB OK
c8_420 = x.ConvertTo16bit().ConvertToYUV420().Info().ConvertTo8bit()
c8_rgb = x.ConvertTo16bit().ConvertToRGB().Info().ConvertTo8bit()
c8_rgb48 = x.ConvertTo16bit().ConvertToRGB48().Info().ConvertTo8bit()
c8_rgb64 = x.ConvertTo16bit().ConvertToRGB64().Info().ConvertTo8bit()
StackHorizontal(StackVertical(c8_420.ConvertToYUV444(),c8_rgb.ConvertToYUV444()),StackVertical(c8_rgb48.ConvertToYUV444(),c8_rgb64.ConvertToYUV444()))

#rgb48->64, 64->48: OK
x.ConvertTo16bit().ConvertToRGB48().ConvertToRGB64().Info().ConvertTo8bit()
x.ConvertTo16bit().ConvertToRGB64().ConvertToRGB48().Info().ConvertTo8bit()

#rgb64 -> Planar RGBAP16
rgbap16 = x.ConvertTo16bit().ConvertToRGB64().ConvertToPlanarRGB().Info()
r16=rgbap16.PlaneToY("R")
g16=rgbap16.PlaneToY("G")
b16=rgbap16.PlaneToY("B")
a16=rgbap16.PlaneToY("A")
argb_from_rgbap16=MergeARGB(a16,r16,g16,b16).ConvertTo8bit()
argb_from_rgbap16

#rgb48 -> Planar RGBP16
rgbp16 = x.ConvertTo16bit().ConvertToRGB48().ConvertToPlanarRGB().Info()
r16=rgbp16.PlaneToY("R")
g16=rgbp16.PlaneToY("G")
b16=rgbp16.PlaneToY("B")
rgb_from_rgbp16=MergeRGB(r16,g16,b16).ConvertTo8bit()
rgb_from_rgbp16

#rgb32 -> Planar RGBAP
rgbap8 = x.ConvertToRGB32().ConvertToPlanarRGB().Info()
r8=rgbap8.PlaneToY("R")
g8=rgbap8.PlaneToY("G")
b8=rgbap8.PlaneToY("B")
a8=rgbap8.PlaneToY("A")
argb_from_rgbap8=MergeARGB(a8,r8,g8,b8).ConvertTo8bit()
argb_from_rgbap8

#rgb24 -> Planar RGBP
rgbp8 = x.ConvertToRGB24().ConvertToPlanarRGB().Info()
r8=rgbp8.PlaneToY("R")
g8=rgbp8.PlaneToY("G")
b8=rgbp8.PlaneToY("B")
rgb_from_rgbp8=MergeRGB(r8,g8,b8).ConvertTo8bit()
rgb_from_rgbp8

#YUV 16 bit -> Planar RGBP
rgbp16 = x.ConvertToYV12().ConvertTo16bit().ConvertToPlanarRGB().Info()
r16=rgbp16.PlaneToY("R")
g16=rgbp16.PlaneToY("G")
b16=rgbp16.PlaneToY("B")
rgb_from_rgbap16=MergeRGB(r16,g16,b16).ConvertTo8bit()
rgb_from_rgbap16

#YUV 8 bit -> Planar RGBP
rgbp8 = x.ConvertToYV12().ConvertToPlanarRGB().Info()
r8=rgbp8.PlaneToY("R")
g8=rgbp8.PlaneToY("G")
b8=rgbp8.PlaneToY("B")
rgb_from_rgbap8=MergeRGB(r8,g8,b8).ConvertTo8bit()
rgb_from_rgbap8

#YUV float bit -> Planar RGBPS
rgbp32 = x.ConvertToYV12().ConvertToFloat().ConvertToPlanarRGB().Info()
r16=rgbp32.PlaneToY("R").ConvertTo16bit()
g16=rgbp32.PlaneToY("G").ConvertTo16bit()
b16=rgbp32.PlaneToY("B").ConvertTo16bit()
rgb_from_rgbap16=MergeRGB(r16,g16,b16).ConvertTo8bit()
rgb_from_rgbap16

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Aug 25, 2016

New function name is ConvertToPlanarRGBA()

ConvertToPlanarRGB/ConvertToPlanarRGBA usage and test cases:

lsmashvideosource("test.mp4", format="YUV420P8")
x=last
x = x.Spline16Resize(900,500)

#PlanarRGBA8 -> RGB24
rgb24 = x.ConvertToPlanarRGBA().Info().ConvertToRGB24()
rgb24

#PlanarRGB8 -> RGB24
rgb24 = x.ConvertToPlanarRGB().Info().ConvertToRGB24()
rgb24

#PlanarRGBA16 -> RGB48
rgb48 = x.ConvertTo16bit().ConvertToPlanarRGBA().Info().ConvertToRGB48()
rgb48.ConvertTo8bit()

#PlanarRGB16 -> RGB48
rgb48 = x.ConvertTo16bit().ConvertToPlanarRGB().Info().ConvertToRGB48()
rgb48.ConvertTo8bit()

#PlanarRGBA8 -> RGB32
rgb32 = x.ConvertToPlanarRGBA().Info().ConvertToRGB32()
rgb32

#PlanarRGB8 -> RGB32
rgb32 = x.ConvertToPlanarRGB().Info().ConvertToRGB32()
rgb32

#PlanarRGB16 -> RGB48
rgb48 = x.ConvertTo16bit().ConvertToPlanarRGB().Info().ConvertToRGB48()
rgb48.ConvertTo8bit()

#PlanarRGBA16 -> RGB48
rgb48 = x.ConvertTo16bit().ConvertToPlanarRGBA().Info().ConvertToRGB48()
rgb48.ConvertTo8bit()

#PlanarRGB16 -> RGB64
rgb64 = x.ConvertToRGB32().ConvertTo16bit().ConvertToPlanarRGB().Info().ConvertToRGB64()
rgb64.ConvertTo8bit()

#PlanarRGBA16 -> RGB64
rgb64 = x.ConvertTo16bit().ConvertToPlanarRGBA().Info().ConvertToRGB64()
rgb64.ConvertTo8bit()

#YV12 -> YUV420P10 (full scale) -> Planar RGBAP10 -> RGBAP16 (full scale) -> RGB64
rgb64 = x.ConvertTo16bit(10, false).ConvertToPlanarRGBA().Info().ConvertTo16bit(truerange=false).ConvertToRGB64()
rgb64.ConvertTo8bit()

@qyot27
Copy link
Copy Markdown
Member

qyot27 commented Aug 25, 2016

Just to confirm something: should the planar RGB formats return the proper colors at this point, or is there more work for that to occur inside AviSynth+, even if you can deconstruct the planes and put them into packed and have a correct image?

I ask, because planar RGB(A) is currently returning greyscale/monochrome images in FFmpeg, and I'm trying to determine if there needs to be something special done on FFmpeg's side to handle it or if the issue is actually just on our side. Like I mentioned, throwing it through PlaneToY/Merge(A)RGB like the testing examples results in the right colors.

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Aug 26, 2016

I think colors are OK. Either converting back to packed RGB with GetPlane or with the ConvertToRGB24/32/48/64 it gives correct results.

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Aug 26, 2016

resize_h_c_planar is still in C (todo). Why float? Unsigned_16 handling has overhead and is properly supported from sse 4.1/avx. Tested against the float version and using the float path was indeed faster, even I did not use int64 for temporary result accumulator (int64 because I have a fear that sum of (uint16_t multiplied by 14-bit-scaled-pixel_coefficients) may overflow from signed int when filter_size is bigger. Although my limited tests did not show any visible corruption for the integer path, I went on with floats because of the minor speed difference and the reuseablity with float pixel type.

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Aug 26, 2016

Conversions from the new RGB types to YUV(A) targets.
RGB48/64
PlanarRGB(A) 8,10-16,float

(todo left: ConvertToY)

Note:
When using ConvertToYUVxxx on PlanarRGBA source, the result is YUVA (alpha is copied)
But packed RGB64 source will result in regular YUVxxxP16, same behaviour as in 8 bit: when converting RGB32 to YV24.

Slow C code of course :(

#8 bit PlanarRGB->YUV420 (YV12)
a = x.ConvertToPlanarRGB().ConvertToYUV420()
#16 bit PlanarRGB->YUV422P16
a = x.ConvertToPlanarRGB().ConvertTo16bit().ConvertToYUV422().Info()
#32 bit PlanarRGB->YUVA444PS
a = x.ConvertToPlanarRGB().ConvertToFloat().Info().ConvertToYUV444().Info().ConvertTo16bit().ConvertToRGB64()
#32 bit PlanarRGBA->YUVA444PS
a = x.ConvertToPlanarRGBA().ConvertToFloat().ConvertToYUV444().Info().ConvertTo16bit().ConvertToRGB64()
#16 bit PlanarRGBA->YUVA420P16
a = x.ConvertToPlanarRGBA().ConvertTo16bit().ConvertToYUV420().Info().ConvertToRGB64()
#RGB48->YUV422P16
a = x.ConvertTo16bit().ConvertToRGB48().ConvertToYUV422().Info()
#RGB64->YUV420P16
a = x.ConvertTo16bit().ConvertToRGB64().ConvertToYUV420().Info()

a.ConvertTo8bit()

@qyot27
Copy link
Copy Markdown
Member

qyot27 commented Aug 26, 2016

I was digging a little deeper, and I think the reason FFmpeg is only showing greyscale images for Planar RGB is that the API functions it uses in the blitter (avs_get_read_ptr_p, avs_get_pitch_p, avs_get_row_size_p, avs_get_height_p) still only use the PLANAR_* constants for YUV, not RGB.

get_pitch_p: references PLANAR_U, V
get_row_size_p: references PLANAR_Y, U, V, Y|U|V_ALIGNED
get_height_p: PLANAR_U, V
get_read_ptr_p: PLANAR_U, V

Using grep PLANAR_Y * in avs_core/core, returns the following results:

alignplanar.cpp: int plane = (env->PlanarChromaAlignment(IScriptEnvironment::PlanarChromaAlignmentTest)) ? PLANAR_U_ALIGNED : PLANAR_Y_ALIGNED;
alignplanar.cpp: if ((dst->GetRowSize(PLANAR_Y_ALIGNED)&(FRAME_ALIGN-1)))
avisynth_c.cpp: case AVS_PLANAR_Y_ALIGNED:
avisynth.cpp: retval=NewPlanarVideoFrame(vi.RowSize(PLANAR_Y), vi.height, vi.RowSize(PLANAR_U), heightUV, align, !vi.IsVPlaneFirst(), vi.IsYUVA());
info.h: const int pitchY = dst->GetPitch(PLANAR_Y);
info.h: BYTE* dstpY = dst->GetWritePtr(PLANAR_Y) + x + y_pitchY;
info.h: const int xSubS = dst->GetRowSize(PLANAR_Y) / UVw;
info.h: const int ySubS = dst->GetHeight(PLANAR_Y) / dst->GetHeight(PLANAR_U);
info.h: const int height = dst->GetHeight(PLANAR_Y);
info.h: const int pitchY = dst->GetPitch(PLANAR_Y);
info.h: BYTE_ dstpY = dst->GetWritePtr(PLANAR_Y) + x + y*pitchY;
info.h: const int xSubS = dst->GetRowSize(PLANAR_Y) / UVw;
interface.cpp: case PLANAR_Y_ALIGNED:
interface.cpp: const int Ybytes = ((RowSize(PLANAR_Y)+3) & ~3) * height;
interface.cpp: if (plane == PLANAR_Y || plane == PLANAR_R || plane == PLANAR_G || plane == PLANAR_B || plane == PLANAR_A) // No subsampling
interface.cpp: if (plane == PLANAR_Y || plane == PLANAR_R || plane == PLANAR_G || plane == PLANAR_B || plane == PLANAR_A) // No subsampling
interface.cpp: case PLANAR_Y_ALIGNED:
interface.cpp: case PLANAR_ALIGNED: case PLANAR_Y_ALIGNED:
interface.cpp: return row_size; // PLANAR_Y, PLANAR_G, PLANAR_B, PLANAR_R
interface.cpp: if (!plane || plane == PLANAR_Y || plane == PLANAR_G) { // planar RGB order GBR
main.cpp: image_size += vi->RowSize(PLANAR_Y) * vi->height;

But grep PLANAR_R * returns just:

interface.cpp: case PLANAR_R: case PLANAR_G: case PLANAR_B:
interface.cpp: case PLANAR_R_ALIGNED: case PLANAR_G_ALIGNED: case PLANAR_B_ALIGNED:
interface.cpp: if (plane == PLANAR_Y || plane == PLANAR_R || plane == PLANAR_G || plane == PLANAR_B || plane == PLANAR_A) // No subsampling
interface.cpp: if (plane == PLANAR_Y || plane == PLANAR_R || plane == PLANAR_G || plane == PLANAR_B || plane == PLANAR_A) // No subsampling
interface.cpp: case PLANAR_R_ALIGNED: case PLANAR_G_ALIGNED: case PLANAR_B_ALIGNED: case PLANAR_A_ALIGNED:
interface.cpp: return row_size; // PLANAR_Y, PLANAR_G, PLANAR_B, PLANAR_R
interface.cpp: case PLANAR_V: case PLANAR_R: return offsetV;

I'm sure not all of the places PLANAR_Y is used signal places that need to be fixed for Planar RGB, but a couple of those places where it's missing do look like they'd be vital to making sure the video stream displays correctly.

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Aug 29, 2016

If you see greyscale on rgb then

  • ffmpeg is seeing all planes the same. E.g. get_read_ptr_p returns always the same plane. I don't think so. Getting read pointer for U and V planes should return the right planes for B and R planes.
  • format mismatch, e.g. ffmpeg thinks that this is grayscale format.
    In avisynth greyscale is sometimes detected by having pitch==0 for the U plane (occurs when videoinfo is not accessible e.g. within the VideoFrame class)
    Comment from avisynth.h VideoInfo:
    // for Planar RGB pitchUV and row_sizeUV = 0, because when no VideoInfo (MakeWriteable)
    // the decision on existance of UV is checked by zero pitch
    When get_pitch is called for U or V planes for Planar RGB it returns 0. Maybe ffmpeg checks them.
    Maybe this is the reason ffmpeg thinks planar rgb to be a greyscale image.
    (Nevertheless, it should use the right planar constants)

On the other hand VideoInfo struct in the c api did not have planar_a offset and pitch handling.
Nor planar_g, b, r. (get_read_ptr, get_pitch etc... logic is duplicated here in the C header, I forgot them to duplicate in C also)
Now I extended it. However AVS_VideoFrame is struct in C vs. avisynth.h's class.
Comment in C header: // DO NOT USE THIS STRUCTURE DIRECTLY
I don't know if expanding this struct with three new fields breaks or not existing C interfaces. (?)
Should be checked!!

@qyot27
Copy link
Copy Markdown
Member

qyot27 commented Aug 30, 2016

With the changes in this pull request, and making Planar RGB match the RGB24/32/48/64 case completely (not just pitch, but the src_p = src_p + (planeheight - 1) * pitch; math as well), FFmpeg now displays a correctly-colored image when ConvertToRGB(A) is used. Tested with both Version() and Colorbars().

BlankClip has some issues with 10~14 depths, it seems.

BlankClip(10,1280,720,color=$FFF000,pixel_type="YV24")

outputs yellow, but

BlankClip(10,1280,720,color=$FFF000,pixel_type="YUVA444P12")

outputs blue.

Also, under Wine, Info() is cropping the text if invoked without arguments, but Info(font="Courier New") doesn't crop the text. The strange thing is that the displayed text isn't in Courier New either time - if anything, it's in Arial or maybe Sans. There's no visible change between the two results except that forcing a font name - and nothing else - makes Info not crop the text. Even if it doesn't honor the font override (I'm simply assuming Courier New isn't installed and that's why it's not used, but it doesn't explain the different behavior when a font is forced vs. left at default).

I haven't yet tested whether the changes to AVS_VideoFrame make a difference. That may take a day or two.

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Aug 30, 2016

When you specify the font (even the default one Courier New) for Info(), it calculates the exact text area, so seeing no cropping is a good news. It renders the whole text as-is for calculation, then sets the rect area by these dimensions and then really renders the text. Because of the double text render (test + real) it is somewhat slower.

For speed reasons, when you do not specify font, we assume a fixed font (Courier New is fixed), and the dimensions are calculated in a faster way: calculate horizontal dimension of (max_line_length pieces of spaces), and also vertical dimensions of n lines of single spaces (Space LF Space LF ....)

It seems that when you don't have Courier New on your system, the dimensions of the space character are much smaller than of a fixed font space. E.g. Arial or other non-fixed-type space. So the calculation returns a smaller rect area and cropping occurs.

Old avisynth routine used hardcoded constants that was unaware of the real size of the text returned by Info(), that was the reason of introducing the calculations above.

I think once you have Courier New on your system the cropping won't occur any more.

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Aug 30, 2016

As for the other issue of 10-12-14 bits:

All internal filters assume such bit-depth formats having pixels in 0-65535 range.
E.g. when you put an Info() on a 10 bit format having true range, it will also seem to be incorrect.

Range truncation occurs only when calling ConvertTo16bit(10) (12) (14).

When you want to have filters work on 10-12-14 bits, use ConvertTo16bit(... truerange=false). The pixel_format will be changed, but the range will stay at 0-65535. It would be a lot of work to treat 10-12-14 bit formats with their real range in all internal filters.

Btw, I agree that once we have these formats, limited true range should be the default for either internal or external filter use. Until the development is reaching this point, read source in 10-12-14 bits, convert it with truerange=false for 16 bits, filter, then if the output requires, convert it back with e.g. ConvertTo16bit(10) (note that truerange=true by default to have a 0-1023 range)

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Aug 30, 2016

Both 16 bit and float resizers are using float arithmetic and coefficients internally.
"Superfast" resizers: approx. tenfold speedup on my i7 compared to the previous C implementation, but obviously it can be polished but I think, not much. As the old 8 bit code, requires ssse3. Plus it can use sse4 specific command if available.

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Sep 1, 2016

ColorYUV uses 8-10-12-14-16 bit lut.
New parameter for the "demo" mode

 #old: draws YV12 with 16-239 U/V image (448x448)
 #new: draws YV12 with 16-240 U/V image (450x450)
 #ColorYUV(showyuv=true) 

 #new options: showyuv_fullrange draws YV12 with 0-255 U/V image (512x512)
ColorYUV(showyuv=true, showyuv_fullrange=true)

 #new options: bits=10,12,14,16 draws YUV420Pxx with 64-961/0-1023 U/V image
 #image size is limited, so color resolution is max 10 bits
 #This sample draws YUV420P12 with 0-1023 U/V image
ColorYUV(showyuv=true, bits=12,showyuv_fullrange=true).Info().ConvertTo8bit()

Luma steps are 16-235-16../0-255-0.. up to 0-65535-0... when bits=16


@pinterf
Copy link
Copy Markdown
Author

pinterf commented Sep 2, 2016

Additional infos for ColorYUV

  • Fixed an uninitialized internal variable regarding pc<->tv conversion,
    resulting in clips sometimes were expanding to pc range when it wasn't asked.
  • for 8+ bit clips parameter ranges are the same as for the 8 bit clips.
    They will be scaled properly for 10-16 bitdepths.
    e.g. off_u=-20 will be converted to -20_4 for 10 bits, -20_256 for 16 bits
  • Samples: Lower left and right should look like the same
 #analyze sample
b = x.ColorYUV(analyze=true).Histogram("levels")
a = x.Histogram("levels")
s8=Stackvertical(a,b)
b = x.ConvertTo16bit(bits=16).ColorYUV(analyze=true).ConvertTo8bit().Histogram("levels")
a = x.Histogram("levels")
s16=Stackvertical(a,b)
stackhorizontal(s8,s16)

 # PC->TV sample, 10 bit (replace for 12,14,16 bits)
b = x.ColorYUV(levels="PC->TV").Histogram("levels")
a = x.Histogram("levels")
s8=Stackvertical(a,b)
b = x.ConvertTo16bit(bits=10).ColorYUV(levels="PC->TV").ConvertTo8bit().Histogram("levels")
a = x.Histogram("levels")
s16=Stackvertical(a,b)
stackhorizontal(s8,s16)

 # TV->PC sample, 10 bit (replace for 12,14,16 bits)
b = x.ColorYUV(levels="TV->PC").Histogram("levels")
a = x.Histogram("levels")
s8=Stackvertical(a,b)
b = x.ConvertTo16bit(bits=10).ColorYUV(levels="TV->PC").ConvertTo8bit().Histogram("levels")
a = x.Histogram("levels")
s16=Stackvertical(a,b)
stackhorizontal(s8,s16)

 # gamma, cont, gan, off_u, off_v, "coring" sample, 10 bit (replace for 12,14,16 bits)
b = x.ColorYUV(gamma_y=128, cont_y=-128, gain_y=0, off_u=-20, off_v=+20, opt="coring").Histogram("levels")
a = x.Histogram("levels")
s8=Stackvertical(a,b)
b = x.ConvertTo16bit(bits=10).ColorYUV(gamma_y=128, cont_y=-128, gain_y=0, off_u=-20, off_v=+20, opt="coring").ConvertTo8bit().Histogram("levels")
a = x.Histogram("levels")
s16=Stackvertical(a,b)
stackhorizontal(s8,s16)

 # autogain sample
b = x.ColorYUV(autogain=true).Histogram("levels")
a = x.Histogram("levels")
s8=Stackvertical(a,b)
b = x.ConvertTo16bit(bits=10).ColorYUV(autogain=true).ConvertTo8bit().Histogram("levels")
a = x.Histogram("levels")
s16=Stackvertical(a,b)
stackhorizontal(s8,s16)

 # autowhite sample
b = x.ColorYUV(autowhite=true).Histogram("levels")
a = x.Histogram("levels")
s8=Stackvertical(a,b)
b = x.ConvertTo16bit(bits=16).ColorYUV(autowhite=true).ConvertTo8bit().Histogram("levels")
a = x.Histogram("levels")
s16=Stackvertical(a,b)
stackhorizontal(s8,s16)

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Sep 2, 2016

Conditinal runtime functions got 16 bit/float support for YUV, 16 bit RGB64 support.
Plus PlanarRGB plane support.

New functions

  • AverageR, AverageG AverageB like AverageLuma
  • RDifference, GDifference, BDifference like LumaDifference(clip1, clip2)
  • RDifferenceFromPrevious, GDifferenceFromPrevious, BDifferenceFromPrevious
  • RDifferenceToNext, GDifferenceToNext, BDifferenceToNext
  • RPlaneMin, GPlaneMin BPlaneMin like YPlaneMin(clip [, float threshold = 0, int offset = 0])
  • RPlaneMax, GPlaneMax BPlaneMax like YPlaneMax(clip [, float threshold = 0, int offset = 0])
  • RPlaneMinMaxDifference, GPlaneMinMaxDifference BPlaneMinMaxDifference like YPlaneMinMaxDifference(clip [, float threshold = 0, int offset = 0])
  • RPlaneMedian, GPlaneMedian, BPlaneMedian like YPlaneMedian(clip [, int offset = 0])

16 bit clips result in values in the same 0.0-65535.0 float range for Average and Difference functions, and in 0-65535 range for the min-max-median functions

For float color spaces the Min, Max, MinMaxDifference and Median functions return values scaled to 16 bits (pixel counts are populated as 16 bit samples internally). Other functions (Average and Difference functions keep the the normal 0-1.0 float range)

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Sep 2, 2016

Test scripts

SetFilterMTMode("DEFAULT_MT_MODE", 2)
SetFilterMTMode("lsmashvideosource", 3)
lsmashvideosource("test.mp4", format="YUV420P8")
x=last
x = x.Spline16Resize(300,160)
x = x.converttoRGB32()
x = x.ConvertTo16bit()

#Sample 1: average RGB for planar
source=x.ConvertToPlanarRGB().ConvertToFloat()
clip1 = source.scriptclip(""" Subtitle ("AverageGBR: " + (string(round(AverageG()*65535.0))) + 
\ "/" + (string(round(AverageB()*65535.0))) + 
\ "/" +  (string(round(AverageR()*65535.0))),align=5,size=12)""")
clip1.ConvertTo8bit().ConvertToYUV444()

#Sample 2: median, min, max, median, minmax
#for float: resulting pixel values are scaled to 16 bit

source=x.ConvertToPlanarRGB().ConvertTo8bit()
clip2a = source.scriptclip(""" Subtitle ("Min/Max/Median/MinMaxDiff: " + (string(round(RPlaneMin(30)))) + 
\ "/" + (string(round(RPlaneMax(30)))) + 
\ "/" + (string(round(RPlaneMedian()))) + 
\ "/" + (string(round(RPlaneMinMaxDifference(30)))) 
\ ,align=5,size=12)""")
clip2a = clip2a.ConvertTo8bit().ConvertToYUV444()

source=x.ConvertToPlanarRGB().ConvertTo16bit()
clip2b = source.scriptclip(""" Subtitle ("Min/Max/Median/MinMaxDiff: " + (string(round(RPlaneMin(30)))) + 
\ "/" + (string(round(RPlaneMax(30)))) + 
\ "/" + (string(round(RPlaneMedian()))) + 
\ "/" + (string(round(RPlaneMinMaxDifference(30)))) 
\ ,align=5,size=12)""")
clip2b = clip2b.ConvertTo8bit().ConvertToYUV444()

source=x.ConvertToPlanarRGB().ConvertToFloat()
clip2c = source.scriptclip(""" Subtitle ("Min/Max/Median/MinMaxDiff: " + (string(round(RPlaneMin(30)))) + 
\ "/" + (string(round(RPlaneMax(30)))) + 
\ "/" + (string(round(RPlaneMedian()))) + 
\ "/" + (string(round(RPlaneMinMaxDifference(30)))) 
\ ,align=5,size=12)""")
clip2c = clip2c.ConvertTo8bit().ConvertToYUV444()

StackVertical(clip2a,clip2b,clip2c)

#Sample 3: check same results through R,G,B to YUV luma and with planar RGB individual channels

#RGB indirect
source=x
GR = source.ShowGreen().converttoYUV420(matrix="PC.601").scriptclip(""" Subtitle ("GREEN average luma: " + (string(round(AverageLuma()))),align=5,size=12)""")
RE = source.ShowRed().converttoYUV420(matrix="PC.601").scriptclip(""" Subtitle ("RED average luma: " + (string(round(AverageLuma()))),align=5,size=12)""")
BL = source.ShowBlue().converttoYUV420(matrix="PC.601").scriptclip(""" Subtitle ("BLUE average luma: " + (string(round(AverageLuma()))),align=5,size=12)""")

clip1 = stackhorizontal(source.converttoYUV420(),RE)
clip2 = stackhorizontal(GR,BL)
clip3 = stackvertical(clip1, Clip2)

clip3a = clip3.ConvertTo8bit()

#RGB through planar
source=x.ConvertToPlanarRGB()
GR = source.scriptclip(""" Subtitle ("GREEN average luma: " + (string(round(AverageG()))),align=5,size=12)""")
RE = source.scriptclip(""" Subtitle ("RED average luma: " + (string(round(AverageR()))),align=5,size=12)""")
BL = source.scriptclip(""" Subtitle ("BLUE average luma: " + (string(round(AverageB()))),align=5,size=12)""")

clip1 = stackhorizontal(source.converttoYUV420(),RE.converttoYUV420())
clip2 = stackhorizontal(GR.converttoYUV420(),BL.converttoYUV420())
clip3 = stackvertical(clip1, Clip2)

clip3b = clip3.ConvertTo8bit()

#RGB through planar float
source=x.ConvertToPlanarRGB().ConvertToFloat()
GR = source.scriptclip(""" Subtitle ("GREEN average luma: " + (string(round(AverageG()*65535.0))),align=5,size=12)""")
RE = source.scriptclip(""" Subtitle ("RED average luma: " + (string(round(AverageR()*65535.0))),align=5,size=12)""")
BL = source.scriptclip(""" Subtitle ("BLUE average luma: " + (string(round(AverageB()*65535.0))),align=5,size=12)""")

clip1 = stackhorizontal(source.converttoYUV420(),RE.converttoYUV420())
clip2 = stackhorizontal(GR.converttoYUV420(),BL.converttoYUV420())
clip3 = stackvertical(clip1, Clip2)

clip3c = clip3.ConvertTo8bit()

StackVertical(clip3a,clip3b,clip3c)

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Sep 4, 2016

Test scripts for Levels

# Gamma, ranges (YUV):
x=x.ConvertToYUV420()
dither=true
coring=true
gamma=2.2
output_low = 55
output_high = 198
clip8 = x.Levels(0, gamma, 255, output_low, output_high , dither=dither, coring=coring)
clip10 = x.ConvertTo16bit(bits=10).Levels(0,gamma,1023,output_low *4,(output_high +1)*4 - 1, dither=dither, coring=coring)
clip16 = x.ConvertTo16bit().Levels(0,gamma,65535,output_low *256,(output_high+1) *256 -1,dither=dither, coring=coring)
stackvertical(clip8.Histogram("levels"), clip10.ConvertTo8bit().Histogram("levels"), Clip16.ConvertTo8bit().Histogram("levels"))


#PlanarRGB 8-10-16 and packed RGB
xx=x.ConvertToPlanarRGB()
dither=true
coring=true
gamma=2.2
output_low = 55
output_high = 198
clip8 = xx.Levels(0, gamma, 255, output_low, output_high , dither=dither, coring=coring)
clip10 = xx.ConvertTo16bit(bits=10).Levels(0,gamma,1023,output_low *4,(output_high +1)*4 - 1, dither=dither, coring=coring)
clip16 = xx.ConvertTo16bit().Levels(0,gamma,65535,output_low *256,(output_high+1) *256 -1,dither=dither, coring=coring)
cliprgb = xx.ConvertTo16bit().ConvertToRGB64().Levels(0,gamma,65535,output_low *256,(output_high+1) *256 -1,dither=dither, coring=coring)
stackvertical(StackHorizontal(clip8.ConvertToYUV444().Histogram("levels"), clip10.ConvertTo8bit().ConvertToYUV444().Histogram("levels")), \ 
StackHorizontal(Clip16.ConvertTo8bit().ConvertToYUV444().Histogram("levels"),ClipRGB.ConvertTo8bit().ConvertToYUV444().Histogram("levels")) \
)

# packed RGB 32/64
xx = x.ConvertToRGB32()
dither=false
coring=false
gamma=1.4
clip8 = xx.Levels(0, gamma, 255, 0, 255, dither=dither, coring=coring)
clip16 = xx.ConvertTo16bit().Levels(0,gamma,65535,0,65535,dither=dither, coring=coring)
stackvertical(clip8.ConvertToYUV444().Histogram("levels"), Clip16.ConvertTo8bit().ConvertToYUV444().Histogram("levels"))

# packed RGB 24/48
xx = x.ConvertToRGB24()
dither=false
coring=false
gamma=1.4
clip8 = xx.Levels(0, gamma, 255, 0, 255, dither=dither, coring=coring)
clip16 = xx.ConvertTo16bit().Levels(0,gamma,65535,0,65535,dither=dither, coring=coring)
stackvertical(clip8.ConvertToYUV444().Histogram("levels"), Clip16.ConvertTo8bit().ConvertToYUV444().Histogram("levels"))

# do nothing (unity transfer function), coring=false:
dither=true
coring=false
gamma=1.0
clip8 = x.Levels(0, gamma, 255, 0, 255, dither=dither, coring=coring)
clip10 = x.ConvertTo16bit(bits=10).Levels(0,gamma,1023,0,1023, dither=dither, coring=coring)
clip16 = x.ConvertTo16bit().Levels(0,gamma,65535,0,65535,dither=dither, coring=coring)
stackvertical(clip8.Histogram("levels"), clip10.ConvertTo8bit().Histogram("levels"), Clip16.ConvertTo8bit().Histogram("levels"))

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Sep 4, 2016

RGBAdjust:
typo in commit text: of course for PlanarRGB(A) 8-16 bits
Test scripts, all 4 images should be identical

#PlanarRGB 8-10-16 and packed RGB
dither=true
r=1.5 # red multiplier
g=1.2
b=0.4
a=1.0 # 1.0: full opacity

rb = 50 # red bias
gb = -12
bb = 10
ab = 0

rg=2.2 # red gamma 
gg=2.2
bg=2.2
ag=2.2

rg=1.0 # red gamma 
gg=1.0
bg=1.0
ag=1.0

analyze=true
dither=false

xx=x.ConvertToPlanarRGB()
clip8 = xx.RgbAdjust(r=r,g=g,b=b,a=a,rb=rb,gb=gb,bb=bb,ab=ab, rg=rg, gg=gg, bg=bg, ag=ag, analyze=analyze, dither=dither)
clip10 = xx.ConvertTo16bit(bits=10).RgbAdjust(r=r,g=g,b=b,a=a,rb=rb*4,gb=gb*4,bb=bb*4,ab=ab*4, rg=rg, gg=gg, bg=bg, ag=ag, analyze=analyze, dither=dither)
clip16 = xx.ConvertTo16bit().                  RgbAdjust(r=r,g=g,b=b,a=a,rb=rb*256,gb=gb*256,bb=bb*256,ab=ab*256, rg=rg, gg=gg, bg=bg, ag=ag, analyze=analyze, dither=dither)
cliprgb = xx.ConvertTo16bit().ConvertToRGB48().RgbAdjust(r=r,g=g,b=b,a=a,rb=rb*256,gb=gb*256,bb=bb*256,ab=ab*256, rg=rg, gg=gg, bg=bg, ag=ag, analyze=analyze, dither=dither)
stackvertical(StackHorizontal(clip8.ConvertToRGB32().ConvertToYUV444().Histogram("levels"), clip10.ConvertTo8bit().ConvertToRGB32().ConvertToYUV444().Histogram("levels")), \ 
StackHorizontal(Clip16.ConvertTo8bit().ConvertToRGB32().ConvertToYUV444().Histogram("levels"),ClipRGB.ConvertTo8bit().ConvertToRGB32().ConvertToYUV444().Histogram("levels")) \
)

xx=x.ConvertToPlanarRGBA()
clip8 = xx.RgbAdjust(r=r,g=g,b=b,a=a,rb=rb,gb=gb,bb=bb,ab=ab, rg=rg, gg=gg, bg=bg, ag=ag, analyze=analyze, dither=dither)
clip10 = xx.ConvertTo16bit(bits=10).RgbAdjust(r=r,g=g,b=b,a=a,rb=rb*4,gb=gb*4,bb=bb*4,ab=ab*4, rg=rg, gg=gg, bg=bg, ag=ag, analyze=analyze, dither=dither)
clip16 = xx.ConvertTo16bit().                  RgbAdjust(r=r,g=g,b=b,a=a,rb=rb*256,gb=gb*256,bb=bb*256,ab=ab*256, rg=rg, gg=gg, bg=bg, ag=ag, analyze=analyze, dither=dither)
cliprgb = xx.ConvertTo16bit().ConvertToRGB64().RgbAdjust(r=r,g=g,b=b,a=a,rb=rb*256,gb=gb*256,bb=bb*256,ab=ab*256, rg=rg, gg=gg, bg=bg, ag=ag, analyze=analyze, dither=dither)
stackvertical(StackHorizontal(clip8.ConvertToRGB32().ConvertToYUV444().Histogram("levels"), clip10.ConvertTo8bit().ConvertToRGB32().ConvertToYUV444().Histogram("levels")), \ 
StackHorizontal(Clip16.ConvertTo8bit().ConvertToRGB32().ConvertToYUV444().Histogram("levels"),ClipRGB.ConvertTo8bit().ConvertToRGB32().ConvertToYUV444().Histogram("levels")) \
)

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Sep 7, 2016

Invert test scripts

lsmashvideosource("test.mp4", format="YUV420P8")
x=last
x = x.Spline16Resize(400,250).ColorYUV(levels="TV->PC")
x=x.ConvertToYUV420()

#invert Y
channels = "Y"
x8=x.Invert(channels).ConvertTo8bit().Histogram("levels")
x10=x.ConvertTo16bit(10).Invert(channels).ConvertTo8bit().Histogram("levels")
x16=x.ConvertTo16bit().Invert(channels).ConvertTo8bit().Histogram("levels")
StackVertical(StackHorizontal(x.Histogram("levels"),x8),StackHorizontal(x10,x16))



#invert YUV 8-10-16,Float
channels = "YUV"
x8=x.Invert(channels).ConvertTo8bit().Histogram("levels")
x10=x.ConvertTo16bit(10).Invert(channels).ConvertTo8bit().Histogram("levels")
x16=x.ConvertTo16bit().Invert(channels).ConvertTo8bit().Histogram("levels")
x32=x.ConvertToFloat().Invert(channels).ConvertTo8bit().Histogram("levels")
StackVertical(StackHorizontal(x.Histogram("levels"),x8),\
StackHorizontal(x10,x16),\
StackHorizontal(x32,BlankClip(x32))\
)

#invert PlanarRGB 8-10-16-Float, RGB24/32,RGB48/64
xx=x.ConvertToPlanarRGB()
channels = "RGB" #combination of RGBA
x8=xx.Invert(channels).ConvertTo8bit().ConvertToRGB32()
x10=xx.ConvertTo16bit(10).Invert(channels).ConvertTo8bit().ConvertToRGB32()
x16=xx.ConvertTo16bit().Invert(channels).ConvertTo8bit().ConvertToRGB32()
x32=xx.ConvertToFloat().Invert(channels).ConvertTo8bit().ConvertToRGB32()
x_rgb32 = x.ConvertToRGB32().Invert(channels).ConvertToRGB32()
x_rgb64 = x.ConvertToRGB32().ConvertTo16bit().Invert(channels).ConvertTo8bit().ConvertToRGB32()
x_rgb24 = x.ConvertToRGB24().Invert(channels).ConvertToRGB32()
x_rgb48 = x.ConvertToRGB24().ConvertTo16bit().Invert(channels).ConvertTo8bit().ConvertToRGB32()
StackVertical(StackHorizontal(xx.ConvertToRGB32(),x8),StackHorizontal(x10,x16),\
StackHorizontal(x_rgb32,x_rgb64),\
StackHorizontal(x_rgb24,x_rgb48),\
StackHorizontal(x32,BlankClip(x32))\
).ConvertToRGB32()

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Sep 7, 2016

Mask test scripts
Alpha plane is filled with 2nd clip's greyscale then Alpha is extracted to Y format.
All converted clips should look the same

lsmashvideosource("test.mp4", format="YUV420P8")
x=last
x = x.Spline16Resize(400,250).ColorYUV(levels="TV->PC")
x_rgb32 = x.ConvertToRGB32()
x_rgb64 = x_rgb32.ConvertTo16bit()
x_planar8  = x_rgb32.ConvertToPlanarRGBA()
x_planar10 = x_planar8.ConvertTo16bit(10)
x_planar16 = x_planar8.ConvertTo16bit()
x_planar32 = x_planar8.ConvertToFloat()

xx_rgb32 = x_rgb32.Mask(x_rgb32)
xx_rgb64 = x_rgb64.Mask(x_rgb64)
xx_planar8 = x_planar8.Mask(x_planar8)
xx_planar10 = x_planar10.Mask(x_planar10)
xx_planar16 = x_planar16.Mask(x_planar16)
xx_planar32 = x_planar32.Mask(x_planar32)

xx_rgb32 = xx_rgb32.ConvertToPlanarRGBA().PlaneToY("A").ConvertTo8bit()
xx_rgb64 = xx_rgb64.ConvertToPlanarRGBA().PlaneToY("A").ConvertTo8bit()
xx_planar8 = xx_planar8.PlaneToY("A").ConvertTo8bit()
xx_planar10 = xx_planar10.PlaneToY("A").ConvertTo8bit()
xx_planar16 = xx_planar16.PlaneToY("A").ConvertTo8bit()
xx_planar32 = xx_planar32.PlaneToY("A").ConvertTo8bit()

StackVertical(StackHorizontal(xx_rgb32,xx_rgb64),\
StackHorizontal(xx_planar8     , xx_planar10 ),\
StackHorizontal(xx_planar16    , xx_planar32 ),\
StackHorizontal(x.ConvertToY() , BlankClip(x).ConvertToY())\
).ConvertToRGB32()

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Sep 8, 2016

GreyScale for new formats. SSE4.1 for RGB64.

#greyscale test YUV no matrix here
xx_yuv8 = x.GreyScale().Info().ConvertTo8bit()
xx_yuv10 = x.ConvertTo16bit(10).GreyScale().Info().ConvertTo8bit()
xx_yuv16 = x.ConvertTo16bit().GreyScale().Info().ConvertTo8bit()
xx_yuv32 = x.ConvertToFloat().GreyScale().Info().ConvertTo8bit()
StackVertical(\
StackHorizontal(xx_yuv8,xx_yuv10),\
StackHorizontal(xx_yuv16,xx_yuv32)\
)


#greyscale test RGB packed 8/16 and planar 8-32
matrix = "rec601" #rec709 rec601 average
xx_rgb32 = x.ConvertToRGB32.GreyScale(matrix=matrix).Info().ConvertTo8bit()
xx_rgb64 = x.ConvertToRGB32.ConvertTo16bit().GreyScale(matrix=matrix).Info().ConvertTo8bit()
xx_rgb24 = x.ConvertToRGB24.GreyScale(matrix=matrix).Info().ConvertTo8bit().ConvertToRGB32()
xx_rgb48 = x.ConvertToRGB24.ConvertTo16bit().GreyScale(matrix=matrix).Info().ConvertTo8bit().ConvertToRGB32()
xx_planar8 = x.ConvertToRGB32.ConvertToPlanarRGB().GreyScale(matrix=matrix).Info().ConvertTo8bit().ConvertToRGB32()
xx_planar10 = x.ConvertToRGB32.ConvertToPlanarRGB().ConvertTo16bit(10).GreyScale(matrix=matrix).Info().ConvertTo8bit().ConvertToRGB32()
xx_planar16 = x.ConvertToRGB32.ConvertToPlanarRGB().ConvertTo16bit().GreyScale(matrix=matrix).Info().ConvertTo8bit().ConvertToRGB32()
xx_planar32 = x.ConvertToRGB32.ConvertToPlanarRGB().ConvertToFloat().GreyScale(matrix=matrix).Info().ConvertTo8bit().ConvertToRGB32()
StackVertical(\
StackHorizontal(xx_rgb32,xx_rgb64),\
StackHorizontal(xx_rgb24,xx_rgb48),\
StackHorizontal(xx_planar8,xx_planar10),\
StackHorizontal(xx_planar16,xx_planar32)\
).ConvertToRGB32()

@qyot27
Copy link
Copy Markdown
Member

qyot27 commented Sep 8, 2016

It would appear that PlanarRGBA->YUV444 is the only path where the alpha plane is actually copied to the output, resulting in YUVA444 as expected. Going to YUV420 or YUV422 drops the alpha plane.

Some things that would/might be useful:

  • ConvertToYUV411 as an alias for ConvertToYV411, it was the only one missing when all the others got more descriptive names, and it'd be nice to be consistent even though that format won't get any high bit depth or alpha treatment.
  • ConvertToRGBA as a generic 'add an alpha plane to packed RGB format' function that can work on both 8-bit and 16-bit formats.
  • ConvertToYUVA for roughly the same purpose - add an alpha plane to an existing YUV source without changing the underlying subsampling format (YUV420->YUVA420, YUV444P16->YUVA444P16, etc.).
  • A possibly even more generic AddAlphaPlane() that simply tacks an alpha plane onto whatever format is input, if it doesn't already have one.

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Sep 8, 2016

Layer() for RGB64.
By avisynth documentation: for full strength Level=257 (default) should be given.
For RGB64 this magic number is Level=65537 (also default when RGB64 is used)

New extension:
ResetMask now accepts parameter (Mask=xxx) which is used for setting the alpha plane for a given value. Default value for Mask is 255 for RGB32, 65535 for RGB64 and full 16 bit, 1.0 for float. For 10-12-14 bit it is set to 1023, 4095 and 16383 respectively.
As it is float, it can be applied to the alpha plane of a float-type YUVA or Planar RGBA clip.

lsmashvideosource("test.mp4", format="YUV420P8")
x=last
x = x.Spline16Resize(800,250).ColorYUV(levels="TV->PC")
x = x.ConvertToRGB32()

transparency0_255 = 128 # ResetMask's new parameter. Also helps testing :)
x2 = ColorBars().ConvertToRGB32().ResetMask(transparency0_255)

x_64 = x.ConvertToRGB32().ConvertTo16bit()
x2_64 = ColorBars().ConvertToRGB32().ConvertTo16bit().ResetMask(transparency0_255 / 255.0 * 65535.0 )

#For pixel-wise transparency information the alpha channel of an RGB32 overlay_clip is used as a mask. 

op = "darken" # subtract lighten darken mul fast
level=257         # 0..257
level64=65537     # 0..65537
threshold=128                   # 0..255   Changes the transition point of op = "darken", "lighten." 
threshold64=threshold*65535/255 # 0..65535 Changes the transition point of op = "darken", "lighten." 
use_chroma = true 
rgb32=Layer(x,x2,op=op,level=level,x=0,y=0,threshold=threshold,use_chroma=use_chroma )
rgb64=Layer(x_64,x2_64,op=op,level=level64,x=0,y=0,threshold=threshold64,use_chroma=use_chroma ).ConvertTo8bit()
StackVertical(rgb32, rgb64)

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Sep 10, 2016

The pixel_format vs. pixel_format name lookup was implemented multiple times.
Now two new functions convert them to each other: GetPixelTypeFromName() and GetPixelTypeName().

Pixel type name from pixel type: that is straightforward 1-1.
But pixel type from pixel type name will accept aliases. So YV12, YUV420 and YUV420P8 (case insensitive) request will return YV12. Other aliases e.g. RGBP8 for RGBP, also accepted, etc...
So we call call a blankclip with YUV444P8 input string instead of YV24.

GetPixelTypeFromName now is also used in Overlay (work in progress)

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Sep 12, 2016

Test script for Overlay "add" function (10-16 bit for any type input).
8 bit case a bit faster than original.

x = x.ConvertToYUV444()

# Prepares some sources.
bg = ColorBars(512,384).ConvertToYUY2
text = BlankClip(bg).Subtitle("Colorbars", size=92, 
\          text_color=$ffffff).ColorYUV(levels="tv->pc")
mask = BlankClip(bg).Subtitle("I am the Mask", size=62, 
\          text_color=$ffffff).ColorYUV(levels="tv->pc")

bg = bg.ConvertToRGB32().ConvertToPlanarRGB() # set input colorspace format here!
text = text.ConvertToYV16() # set overlay colorspace format here!
mask = mask.GreyScale().ConvertToYV16() # set mask colorspace format here!


#add no mask
ov8 = Overlay(bg,text, x=50, y=120, mode="add", opacity=0.5).Info()
ov10 = Overlay(bg.ConvertTo16bit(10),text.ConvertTo16bit(10), x=50, y=120, mode="add", opacity=0.5).Info().ConvertTo8bit()
ov16 = Overlay(bg.ConvertTo16bit(),text.ConvertTo16bit(), x=50, y=120, mode="add", opacity=0.5).Info().ConvertTo8bit()

#add no with mask
ov8m = Overlay(bg,text, x=50, y=120, mode="add", opacity=0.5, mask=mask).Info()
ov10m = Overlay(bg.ConvertTo16bit(10),text.ConvertTo16bit(10), x=50, y=120, mode="add", opacity=0.5, mask=mask.ConvertTo16bit(10)).Info().ConvertTo8bit()
ov16m = Overlay(bg.ConvertTo16bit(),text.ConvertTo16bit(), x=50, y=120, mode="add", opacity=0.5, mask=mask.ConvertTo16bit()).Info().ConvertTo8bit()

return StackHorizontal(\
Stackvertical(ov8,ov10,ov16),\ 
Stackvertical(ov8m,ov10m,ov16m)\
).ConvertToRGB32()

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Sep 14, 2016

Tweak: luma + chroma LUT for 10 bits and luma LUT for 10-16 bits
Parameter realcalc=true to force ignoring LUT usage (calculate each pixel on-the-fly)
Test scripts

lsmashvideosource("test.mp4", format="YUV422P8")
Spline64Resize(320,200).ConvertToYUV444().ConvertTo8bit()
orig = last

cont = 2.1
bright = 11
sat = 1.2
dither_str8 = 1.0
dither_str10 = 1.0
dither_str14 = 1.0
dither_str16 = 1.0


x8=orig.Tweak(sat=sat,realcalc=false,cont=cont,bright=bright,dither=false,coring=true,dither_strength=dither_str8).SubTitle(" 8 bit,   lut, no dither")
x8d=orig.Tweak(sat=sat,realcalc=false,cont=cont,bright=bright,dither=true,coring=true,dither_strength=dither_str8).SubTitle(" 8 bit,   lut,    dither")
x8_b=orig.Tweak(sat=sat,realcalc=true,cont=cont,bright=bright,dither=false,coring=true,dither_strength=dither_str8).SubTitle(" 8 bit, no lut, no dither")
x8d_b=orig.Tweak(sat=sat,realcalc=true,cont=cont,bright=bright,dither=true,coring=true,dither_strength=dither_str8).SubTitle(" 8 bit, no lut,    dither")
x10=orig.ConvertTo16bit(10).Tweak(sat=sat,realcalc=true,cont=cont,bright=bright,dither=false,coring=true,dither_strength=dither_str10).SubTitle("10 bit, no lut, no dither")
x10d=orig.ConvertTo16bit(10).Tweak(sat=sat,realcalc=true,cont=cont,bright=bright,dither=true,coring=true,dither_strength=dither_str10).SubTitle("10 bit, no lut,    dither")
x10_lut=orig.ConvertTo16bit(10).Tweak(sat=sat,realcalc=false,cont=cont,bright=bright,dither=false,coring=true,dither_strength=dither_str10).SubTitle("10 bit,   lut, no dither")
x10d_lut=orig.ConvertTo16bit(10).Tweak(sat=sat,realcalc=false,cont=cont,bright=bright,dither=true,coring=true,dither_strength=dither_str10).SubTitle("10 bit,   lut,    dither")
x14_lut=orig.ConvertTo16bit(14).Tweak(sat=sat,realcalc=false,cont=cont,bright=bright,dither=false,coring=true,dither_strength=dither_str14).SubTitle("14 bit, luma lut, no dither")
x16=orig.ConvertTo16bit().Tweak(sat=sat,realcalc=true,cont=cont,bright=bright,dither=false,coring=true,dither_strength=dither_str16).SubTitle("16 bit, no lut, no dither")
x16d=orig.ConvertTo16bit().Tweak(sat=sat,realcalc=true,cont=cont,bright=bright,dither=true,coring=true,dither_strength=dither_str16).SubTitle("16 bit, no lut,    dither")
x16_lut=orig.ConvertTo16bit().Tweak(sat=sat,realcalc=false,cont=cont,bright=bright,dither=false,coring=true,dither_strength=dither_str16).SubTitle("16 bit,luma lut, no dither")
x16d_lut=orig.ConvertTo16bit().Tweak(sat=sat,realcalc=false,cont=cont,bright=bright,dither=true,coring=true,dither_strength=dither_str16).SubTitle("16 bit,luma lut,    dither")
x32=orig.ConvertToFloat().Tweak(sat=sat,realcalc=true,cont=cont,bright=bright,dither=false,coring=true).SubTitle("32 bit, no lut, no dither")
x32d=orig.ConvertToFloat().Tweak(sat=sat,realcalc=true,cont=cont,bright=bright,dither=true,coring=true).SubTitle("32 bit, no lut,    dither")

StackHorizontal(\
StackVertical(\
x8.ConvertTo8bit().Histogram("levels"),\
x8_b.ConvertTo8bit().Histogram("levels"),\
x10_lut.ConvertTo8bit().Histogram("levels"),\
x16.ConvertTo8bit().Histogram("levels"),\
x32.ConvertTo8bit().Histogram("levels")),\
\
StackVertical(\
x8d.ConvertTo8bit().Histogram("levels"),\
x8d_b.ConvertTo8bit().Histogram("levels"),\
x10d_lut.ConvertTo8bit().Histogram("levels"),\
x16d.ConvertTo8bit().Histogram("levels"),\
x32d.ConvertTo8bit().Histogram("levels")),\
\
StackVertical(\
x10.ConvertTo8bit().Histogram("levels"),\
x10d.ConvertTo8bit().Histogram("levels"),\
x16_lut.ConvertTo8bit().Histogram("levels"),\
x16d_lut.ConvertTo8bit().Histogram("levels"),\
x14_lut.ConvertTo8bit().Histogram("levels"))\
)

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Sep 14, 2016

ColorKeyMask color and tolerance parameters are the same as for 8 bit RGB32, internally they are automatically scaled to the current bit-depth

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Sep 19, 2016

ConvertBits() for all-in-one bit-depth conversion: c[bits]i[truerange]b[dither]i[scale]f
ConvertTo8bit() = ConvertBits(8)
ConvertTo16bit(10) = ConvertBits(10)
ConvertTo16bit() = ConvertBits(16)
ConvertToFloat() = ConvertBits(32)

Video format override between 10-16 bit formats (no content change)
Convert 10 bit format having 16-bit range inside to real 16 bit: clip10.ConvertBits(16, truerange=false)
Convert 16 bit format to 10 bit format, keeping fake 16 bit inside: clip16.ConvertBits(10, truerange=false)

dither is still todo

@qyot27
Copy link
Copy Markdown
Member

qyot27 commented Jun 14, 2019

Given the recent events involved with the repository, I'd say we should go ahead and merge this. If there are no objections, I'll do so tomorrow or Saturday.

@pinterf
Copy link
Copy Markdown
Author

pinterf commented Jun 14, 2019

Agreed, thanks, my days are a bit busy now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants