View Full Version : JpegSource advanced JPEG decoder for Avisynth 2.6
SEt
5th January 2014, 01:24
As someone asked for JPEG decoder that does no colorspace conversions and provide YUV data directly, and I've written exactly such thing for some other project – here it is, JpegSource for Avisynth.
Current (2014.4.19) version: https://www.dropbox.com/s/rjnt0y3ead2c6ef/JpegSource_20140419.7z
Previous (2014.1.5) version: https://www.dropbox.com/s/qvm4kn27b4f7bb9/JpegSource.7z
Due to various chroma subsamplings of JPEG it's Avisynth 2.6 only plugin. And even current Avisynth 2.6 doesn't support all colorspaces that you can encounter in JPEG, like YUV440 and CMYK/YCCK, so to process them you'd have to use single-channel mode. To comply with other Avisynth restrictions multi-channel mode may also "un-crop" images a bit (to provide even width to YV16 etc.), while single-channel mode always returns exact dimensions.
Syntax: JpegSource(string file, int rec, int channel, int length, float fps_num, int fps_den)
file – source file name
rec – number of reconstruction passes. Default: 1.
channel – load only one image channel with specified index (zero based). Default: -1 (load all channels).
length – clip length in frames. Default: 1000.
fps_num and fps_den – fps numerator and denominator. Default: 24 and 1.
MTMode to use: 1. (3 and 5 are ok too; don't use 2 or 4.)
Beside simply decoding JPEG files it can try to "reconstruct" the data. Shouldn't hurt any image. On high-quality JPEGs change is insignificant, on strongly compressed can produce quite impressive results, but won't help on recompressed files where artifacts were produced by previous compressions. Reconstruction requires SSSE3 capable CPU. For example try on this (http://upload.wikimedia.org/wikipedia/commons/8/8c/JPEG_example_JPG_RIP_025.jpg) file.
Can also decode PJG-compressed JPEG files and JPEG files with arithmetic compression.
Remember that JPEGs use PC levels, Rec.601 colorspace and MPEG1 chroma position most of the time. Sadly, there is no way now for source filter to provide such information and you'd have to set correct parameters manually when converting to other colorspaces. (Actually, there is something about chroma position, but it doesn't work.)
License: free for non-commercial use, closed source. (Ad-infested software is not "non-commercial".)
Usage Notes
RGB JPEGs are decoded as YV24 etc. To get proper RGB combine them by
MergeRGB(last, UToY8(), VToY8(), "RGB24").
To correctly upsample MPEG1 chroma (most JPEGs) use
YToUV(UToY8().Spline36Resize(last.width, last.height), VToY8().Spline36Resize(last.width, last.height), last)
Reel.Deel
5th January 2014, 13:10
Thank you SEt. It's nice to finally be able to decode 4:4:4 jpegs natively in AviSynth (I was using jpeg2yuv and RawSource before but it was a hassle).
I quickly tried with the sample picture you linked, and I have to say the reconstruction pass does a very nice job of deblocking.
One last thing, I ran JpegSource.dll through Dependency Walker and I saw something odd, it lists "AVISYNTH.DLL" as a dependency. Is that normal? I've not seen that before.
Groucho2004
5th January 2014, 13:24
One last thing, I ran JpegSource.dll through Dependency Walker and I saw something odd, it lists "AVISYNTH.DLL" as a dependency. Is that normal? I've not seen that before.
That happens when you statically link with avisynth.lib.
SEt
5th January 2014, 14:14
It's not just deblocking it tries to remove all JPEG artifacts. For example text strongly compressed in JPEG should be way less painful to read after 3 passes of reconstruction. The interesting aspect of this "reconstruction" is that if you compress reconstructed image with exactly the same settings you should get exactly the same JPEG file. So it's indeed kind of reconstruction or more accurate decoding unlike usual dumb blur-them-all postprocessings.
The funny thing is with such postprocessing JPEG can rival or even surpass JPEG2000 on low bitrates, what is even more true with more efficient final entropy coding like PJG.
You don't need to worry about missing runtimes with my builds. Yes, avisynth.dll as dependency is normal for 2.6 interfaces. (I know it's ugly, but that's how 2.6 interfaces work.)
ultim
5th January 2014, 14:44
Yes, avisynth.dll as dependency is normal for 2.6 interfaces. (I know it's ugly, but that's how 2.6 interfaces work.)
There is zero need for plugins to link with the avisynth.dll binary in any way, not dynamically nor statically. It is not normal for a plugin, not even in 2.6, to work like that. If for some strange reason you do want to link with it on purpose, it's fine by me, but I felt the need to post this before other plugin authors start linking with avisynth.dll by mistake.
Wilbert
5th January 2014, 15:51
If for some strange reason you do want to link with it on purpose
It would be nice if it would be open source. Is there a reason that you don't want to open it?
Btw, what's YUV440? I read somewhere that it is rotated YUV422, but i have no idea what that means. Does it mean that chroma is shared between two vertical pixels (instead of horizontal)?
innocenat
5th January 2014, 16:05
Btw, what's YUV440? I read somewhere that it is rotated YUV422, but i have no idea what that means. Does it mean that chroma is shared between two vertical pixels (instead of horizontal)?
Yes, chroma is shared between two vertical pixels.
SEt
5th January 2014, 16:29
ultim, global variable AVS_linkage is effectively linking. Be it static like here or dynamic as assignment in AvisynthPluginInit3 doesn't change the fact. If you think that assignment is the preferred way, ok, next version will link by that.
Wilbert, closed source because I don't want commercial usage of reconstruction code.
Yes, in YUV440 chroma is shared between two vertical pixels but not horizontal. It often appears as result of lossless rotation by 90 degrees of YUV422 data. Avisynth has enough flags to express such subsampling, but refuses to create frames of this type.
Btw, does anyone know how rotated YUV411 is called? I can't think of a way to express such subsampling in standard notation.
foxyshadis
7th January 2014, 03:43
Can you add a native VapourSynth interface? (Or have you?) The colorspace options there are more versatile.
You could also possibly take advantage of decoding into high bit depth - I've always wondered if using a floating-point iDCT directly into a high bit depth prior to transforming to RGB would solve some banding problems, even if it obviously wasn't created with more than 8 bits.
wOxxOm
7th January 2014, 06:36
Btw, does anyone know how rotated YUV411 is called? I can't think of a way to express such subsampling in standard notation.
The standard notation describes two rows, so the only way is to use a non-standard 4-row 4-column description 4:4:0:0:0, also as an example: the non-rotated 420 would be 42020 (to convert any standard notation simply repeat the chroma numbers twice).
SEt
7th January 2014, 15:09
Can you add a native VapourSynth interface? (Or have you?) The colorspace options there are more versatile.
I have no interest in VapourSynth.
You could also possibly take advantage of decoding into high bit depth - I've always wondered if using a floating-point iDCT directly into a high bit depth prior to transforming to RGB would solve some banding problems, even if it obviously wasn't created with more than 8 bits.
Maybe. With standard decoding blocking is far more serious issue, but with reconstruction it might make sense to try to combat banding too. Can you post examples of JPEGs with banding problem?
ajp_anton
8th January 2014, 01:59
So with an unsupported colorspace, will it fail to open it, or silently convert it to a compatible format?
ultim
8th January 2014, 08:45
ultim, global variable AVS_linkage is effectively linking. Be it static like here or dynamic as assignment in AvisynthPluginInit3 doesn't change the fact. If you think that assignment is the preferred way, ok, next version will link by that.
From the Avisynth's core view, I don't care. But it is your interest that you don't link with avisynth.dll directly, because if you do, Windows will only load your plugin if it can find avisynth.dll in the standard system paths. It will be in the system path for most installations, but not all.
SEt
8th January 2014, 10:57
So with an unsupported colorspace, will it fail to open it, or silently convert it to a compatible format?
No silent conversions here – it will fail. This plugin always provides raw data.
But it is your interest that you don't link with avisynth.dll directly, because if you do, Windows will only load your plugin if it can find avisynth.dll in the standard system paths. It will be in the system path for most installations, but not all.
Not a problem if it's all you have against symbol importing. As it's plugin to Avisynth and will be loaded by Avisynth that means that avisynth.dll will already be loaded in memory. In that case import will be resolved by avisynth.dll in memory regardless of where the file is placed.
ultim
8th January 2014, 18:46
Not a problem if it's all you have against symbol importing. As it's plugin to Avisynth and will be loaded by Avisynth that means that avisynth.dll will already be loaded in memory. In that case import will be resolved by avisynth.dll in memory regardless of where the file is placed.
To my knowledge, Windows uses the basename, and optionally the full path if supplied, when searching for already loaded libraries in memory. That means it wouldn't work if avisynth.dll is named differently, or if the symbols are supplied by a different library, like VapourSynth (as VS is able to load AVS plugins). I know you don't care about VS, but it is a real-life example of the problem I am trying to demonstrate.
Anyway, if not supporting those scenarios is fine by you, fine by me. I only brought up the issue because others might care about those few cases that you don't care about, and because of those few cases it is generally better not to link with avisynth.dll directly. With my original post I'm not trying to get you to change your code, it was just to let other developers know that there is an even better approach than linking to the core.
SEt
8th January 2014, 19:28
Indeed, this time you are correct, though the case of renamed avisynth.dll is kind of artificial. It was explicitly stated that it's Avisynth 2.6 plugin.
Reel.Deel
9th January 2014, 05:08
Can you post examples of JPEGs with banding problem?
I took a picture of the sun and sky a while back and it made a good example of JPEG banding. Source is a raw photo taken with my Canon 7D and processed with Adobe Lightroom 5.
- Banding.7z (https://www.dropbox.com/s/2w8ufrtco6bin5f/Banding.7z) - 4:2:0 JPEGs ranging from quality 0 - 100 (>54 are 4:4:4)
- Original.7z (https://www.dropbox.com/s/3nuwvzzrzi0crls/Original.7z) - 16-bit TIFF
Let me know if you want something with more detail.
Nevilne
12th April 2014, 17:57
Thanks for the filter, the reconstruction is very nice. What would be the safe number for good quality pictures? I've tested some with 3 and it didn't seem to do any harm.
Some bugs to report:
RGB jpegs open as YV24:
http://i1.someimage.com/kFS0P4R.jpg
YUV 4:1:1 chroma gets displaced (sane shamanism with avisynth chromaplacements is not enough, needs an offset)
http://i1.someimage.com/KXOlJZB.jpg
(compare red leaves of jpegsource with imagesource)
When you open the image with jpegsource, it blocks the source file. Other image source filters like ImageSource, FFImageSource don't block the file and even allow seeking after file deletion with end=999 repetition.
SEt
13th April 2014, 11:23
For good quality pictures doesn't really matter – filter limits itself to variation introduced by compression data loss, so change will be small anyway. I usually use 1 for realtime postprocessing in my image viewer to save time.
For highly compressed photos I prefer 1 level, as 2+ produce too soft image.
For highly compressed text 3-4 are nice for salvaging as much as possible.
RGB JPEGs are quite rare, most Avisynth filters now strongly prefer planar formats and there is no planar RGB in Avisynth yet. So that behavior is somewhat "by design". You can easily get correct RGB from that by
MergeRGB(last, UToY8(), VToY8(), "RGB24")
For correctly handling MPEG1 YUV chroma in conversions you can explicitly upsample chroma before it. For example to get correctly aligned YV24 you can use:
YToUV(UToY8().Spline36Resize(last.width, last.height), VToY8().Spline36Resize(last.width, last.height), last)
Also do note that current resizing functions always process chroma as MPEG1, while conversions process it as MPEG2 by default.
Indeed, it's possible to close file earlier – will do it in next version.
My new version of decoder can also support JPEGs with arithmetic compression – not sure if there is any interest here for working with such images.
wOxxOm
14th April 2014, 19:23
SEt, if it's possible at all, can you adapt your pp algorithm to make an MPEG-2 post-processor?
SEt
14th April 2014, 21:54
It's not independent pp – it's more like some alternative stages in the process of decoding. So, first of all cutting into some MPEG-2 decoder is required. Next some (expensive!) algorithm implementation adaptation is required as MPEG frames unlike JPEG ones can have different compression levels for different blocks.
filler56789
16th April 2014, 02:43
Hi there, does this plugin require a specific build of Avisynth 2.6, or not? :confused:
Currently running:
Avisynth 2.60, build:May 25 2011 [19:58:41]
Error message:
The procedure entry point ?AVS_linkage-blah-blah-blah could not be located in the dynamic link library avisynth.dll.
Reel.Deel
16th April 2014, 02:54
Hi there, does this plugin require a specific build of Avisynth 2.6, or not? :confused:
Currently running:
Avisynth 2.60, build:May 25 2011 [19:58:41]
If I'm not wrong the minimum requirement is AviSynth 2.6.0 Alpha4 but Alpha5 (http://forum.doom9.org/showthread.php?t=168764) is definitely recommended.
StainlessS
16th April 2014, 04:16
The procedure entry point ?AVS_linkage-blah-blah-blah could not be located in the dynamic link library avisynth.dll.
I think that refers to changes made in v2.6alpha5, so alpha 5 is required.
Alpha4 will not be supported by anybody, 1st question asked would be, 'does it work under alpha5', alpha4 is now obsolete.
filler56789
16th April 2014, 05:10
Okay, just tried Avisynth alpha5, and this time,
VirtualDub opens the AVS file --- BUT.....
a) frame #0 is green;
b) if I try to go to frame #1, or just check the properties in the File Menu,
crashinfo.txt (part 1)
VirtualDub crash report -- build 32842 (release)
--------------------------------------
Disassembly:
7c812a60: 68daffff8b push 8bffffda
7c812a65: 4d dec ebp
7c812a66: 1089013bc60f adc [ecx+fc63b01], cl
7c812a6c: 84c5 test ch, al
7c812a6e: 1d03008975 sbb eax, 75890003
7c812a73: e483 in al, 83h
7c812a75: 4d dec ebp
7c812a76: fc cld
7c812a77: ffe8 jmp eax
7c812a79: 1c00 sbb al, 00h
7c812a7b: 0000 add [eax], al
7c812a7d: 8b45e4 mov eax, [ebp-1ch]
7c812a80: e88cfafeff call 7c802511
7c812a85: c20c00 ret 000c
7c812a88: ff db 0ffh
7c812a89: ff db 0ffh
7c812a8a: ff db 0ffh
7c812a8b: ff00 inc dword ptr [eax]
7c812a8d: 0000 add [eax], al
7c812a8f: 00992a817c90 add [ecx-6f837ed6], bl
7c812a95: 90 nop
7c812a96: 90 nop
7c812a97: 90 nop
7c812a98: 90 nop
7c812a99: 8d45cc lea eax, [ebp-34h]
7c812a9c: 50 push eax
7c812a9d: ff154412807c call dword ptr [7c801244]
7c812aa3: c3 ret
7c812aa4: 90 nop
7c812aa5: 90 nop
7c812aa6: 90 nop
7c812aa7: 90 nop
7c812aa8: 90 nop
7c812aa9: 8bff mov edi, edi
7c812aab: 55 push ebp
7c812aac: 8bec mov ebp, esp
7c812aae: 83ec50 sub esp, 50h
7c812ab1: 8b4508 mov eax, [ebp+08h]
7c812ab4: 8365b800 and dword ptr [ebp-48h], 00h
7c812ab8: 8945b0 mov [ebp-50h], eax
7c812abb: 8b450c mov eax, [ebp+0ch]
7c812abe: 56 push esi
7c812abf: 8b7514 mov esi, [ebp+14h]
7c812ac2: 83e001 and eax, 01h
7c812ac5: 85f6 test esi, esi
7c812ac7: 8945b4 mov [ebp-4ch], eax
7c812aca: c745bca92a817c mov dword ptr [ebp-44h], 7c812aa9
7c812ad1: 0f8499000000 jz 7c812b70
7c812ad7: 8b4d10 mov ecx, [ebp+10h]
7c812ada: 83f90f cmp ecx, 0fh
7c812add: 0f87451e0300 ja 7c844928
7c812ae3: 85c9 test ecx, ecx
7c812ae5: 894dc0 mov [ebp-40h], ecx
7c812ae8: 7407 jz 7c812af1
7c812aea: 57 push edi
7c812aeb: 8d7dc4 lea edi, [ebp-3ch]
7c812aee: f3a5 rep movsd
7c812af0: 5f pop edi
7c812af1: 8d45b0 lea eax, [ebp-50h]
7c812af4: 50 push eax
7c812af5: ff151015807c call dword ptr [7c801510]
7c812afb: 5e pop esi <-- FAULT
7c812afc: c9 leave
7c812afd: c21000 ret 0010
7c812b00: 85ff test edi, edi
7c812b02: 0f8e3693ffff jle 7c80be3e
7c812b08: 8b55fc mov edx, [ebp-04h]
7c812b0b: 89550c mov [ebp+0ch], edx
7c812b0e: 0fb716 movzx edx, word ptr [esi]
7c812b11: 8b7df8 mov edi, [ebp-08h]
7c812b14: 8a143a mov dl, [edx+edi]
7c812b17: 8811 mov [ecx], dl
7c812b19: 8b780c mov edi, [eax+0ch]
7c812b1c: 0fb6d2 movzx edx, dl
7c812b1f: 668b1457 mov dx, [edi+edx*2]
7c812b23: 663b16 cmp edx, [esi]
7c812b26: 0f85da8b0300 jnz 7c84b706
7c812b2c: 8b5008 mov edx, [eax+08h]
7c812b2f: 668b5a04 mov bx, [edx+04h]
7c812b33: 3819 cmp [ecx], bl
7c812b35: 0f84d88b0300 jz 7c84b713
7c812b3b: 46 inc esi
7c812b3c: 46 inc esi
7c812b3d: 41 inc ecx
7c812b3e: ff4d0c dec dword ptr [ebp+0ch]
7c812b41: 75cb jnz 7c812b0e
7c812b43: e9f692ffff jmp 7c80be3e
7c812b48: 8b4d10 mov ecx, [ebp+10h]
7c812b4b: e82478ffff call 7c80a374
7c812b50: 8b550c mov edx, [ebp+0ch]
7c812b53: 8bd8 mov ebx, eax
7c812b55: 43 inc ebx
7c812b56: e911a3ffff jmp 7c80ce6c
7c812b5b: 8bd9 mov ebx, ecx
7c812b5d: 895d08 mov [ebp+08h], ebx
filler56789
16th April 2014, 05:11
crashinfo.txt (part 2)
Built on Aegis on Fri Dec 24 13:18:44 2010 using compiler version 1400
Windows 5.1 (Windows XP x86 build 2600) [Service Pack 3]
EAX = 01c7fe34
EBX = 00000000
ECX = 00000000
EDX = 00c8cc98
EBP = 01c7fe84
ESI = 01c7febc
EDI = 00000000
ESP = 01c7fe30
EIP = 7c812afb
EFLAGS = 00000206
FPUCW = ffff027f
FPUTW = ffffffff
Crash reason: Unhandled Microsoft C++ Exception
Crash context:
An exception occurred in module 'kernel32'.
Pointer dumps:
EAX 01c7fe30: 00ba6814 e06d7363 00000001 00000000 7c812afb 00000003 19930520 01c7feec
EDX 00c8cc98: 00000066 00000000 00000000 00000000 00000000 00000000 00000000 00000000
ESI 01c7feb8: 0062981c 00000000 004c707f 01c7feec 0062981c 00c8b4f8 00c8bf68 004dbcb1
ESP 01c7fe30: 00ba6814 e06d7363 00000001 00000000 7c812afb 00000003 19930520 01c7feec
01c7fe50: 0062981c 00c8cc99 000003a6 00c8cc40 00000042 01c7ffa0 7c90e920 7c9101e0
01c7fe70: ffffffff 00000000 005b62e6 00c8cc40 00000400 01c7febc 005b392b e06d7363
01c7fe90: 00000001 00000003 01c7feb0 e06d7363 00000001 00000000 00000000 00000003
EBP 01c7fe80: 00000400 01c7febc 005b392b e06d7363 00000001 00000003 01c7feb0 e06d7363
01c7fea0: 00000001 00000000 00000000 00000003 19930520 01c7feec 0062981c 00000000
01c7fec0: 004c707f 01c7feec 0062981c 00c8b4f8 00c8bf68 004dbcb1 00000000 00000000
01c7fee0: 00000001 00000000 00000000 00c8cc40 011750dc 00c8bf68 00000000 00000000
Thread call stack:
7c812afb: kernel32!RaiseException [7c800000+12aa9+52]
7c812afb: kernel32!RaiseException [7c800000+12aa9+52]
005b62e6: _vsnprintf()
005b392b: _CxxThrowException@8()
004c707f: AVIReadTunnelStream::Read()
004dbcb1: VideoSourceAVI::_read()
004c81b5: DubSource::read()
004ccb6d: InputFileAVI::_InfoDlgThread()
005b91e3: _cftof_l()
005b91e3: _cftof_l()
005b6e3a: _callthreadstart()
005b91e3: _cftof_l()
005b6ed3: _threadstart@4()
7c80b729: kernel32!GetModuleFileNameA [7c800000+b56f+1ba]
005b91e3: _cftof_l()
-- End of report
SEt
16th April 2014, 08:39
It's guaranteed to work with mine Avisynth 2.6 MT (http://forum.doom9.org/showthread.php?t=148782), but latest official build should also work with no problems.
Is your CPU SSSE3 capable? Reconstruction code requires SSSE3 and will crash if you don't have it (in current version, next will check for support). Try with rec=0 if that's the case.
PS: Looking at GetCPUFlags() flags is seems no modern CPU is CPUF_X86_64 capable, as it's defined as CPUF_SSE2+CPUF_3DNOW_EXT :rolleyes: That flag is absolutely useless and should be removed.
filler56789
16th April 2014, 11:53
Try with rec=0 if that's the case.
Now it works \o/
Thanks for the info.
Reconstruction code requires SSSE3 and will crash if you don't have it.
Please include a very-detailed README.txt in the next release. ;)
Groucho2004
16th April 2014, 12:07
I think that refers to changes made in v2.6alpha5, so alpha 5 is required.
AVS_Linkage was introduced in Alpha4.
StainlessS
16th April 2014, 12:38
Slap!, Slap!
Thank you master :(
Reel.Deel
16th April 2014, 13:32
Also do note that current resizing functions always process chroma as MPEG1, while conversions process it as MPEG2 by default.
Interesting, I did not know this!
So for example, if I load a YV12 picture with MPEG2 chroma placement and resize with Spline36Resize(width/2, height/2) it's wrong?
But a picture with MPEG1 chroma placement would be correct?
My new version of decoder can also support JPEGs with arithmetic compression not sure if there is any interest here for working with such images.
I've only experienced a few of those, unfortunately ImageSource and FFImageSource are not able to open them. This would be a bonus for JpegSource. :)
Gavino
16th April 2014, 14:05
So for example, if I load a YV12 picture with MPEG2 chroma placement and resize with Spline36Resize(width/2, height/2) it's wrong?
But a picture with MPEG1 chroma placement would be correct?
Yes, there is a slight (usually imperceptible, but not always) horizontal chroma shift in the MPEG2 case.
See here (http://forum.doom9.org/showthread.php?p=1505936#post1505936) and subsequent posts.
SEt
18th April 2014, 01:54
New version:
Support JPEGs with arithmetic compression.
No longer locks files after first frame was decoded.
Added MT and cache hints for Avisynth+.
Changed compiler to VS2013.
Reel.Deel, I've experimented with your banding examples and dithered DCT output (not quite higher bit depth, but close enough) no noticeable improvements.
SEt
19th April 2014, 10:05
Update:
Added single-channel mode, so you can load pretty much every JPEG you can encounter even when Avisynth doesn't have appropriate colorspace.
filler56789
22nd April 2014, 02:40
^ :thanks: for the update.
No README.txt yet, but there is a page for it in the Wiki, and that's a start, me presumes :)
http://avisynth.nl/index.php/JpegSource
Reel.Deel
22nd April 2014, 08:06
@SEt
Regarding the Wiki, if there's anything you would like to change please let me know.
When I get some time I would like to add information about JPEG subsampling (and chroma placement) and note that most JPEGs use PC levels (0-255) and the Rec.601 matrix when converting to RGB.
I know you said that JpegSource had something about chroma placement but it did not work, are there other ways to correctly identify JPEG chroma placement?
A while back I posted this in another thread:
I've found JPEGsnoop (http://www.impulseadventure.com/photo/jpeg-snoop.html) to be a handy tool for correctly identifying JPEG chroma placement. Most original JPEGs have metadata with the YCbCrPositioning (http://freeimage.sourceforge.net/fnet/html/4A015DE9.htm) property; it can either be "centered" or "co-sited".
After testing lots of pictures I came to the conclusion that all of my 4:2:0 JPEGs taken with various camera phones are "centered" and 4:2:2 JPEGs taken 2 different cameras are "co-sited".
This Chrominance Subsampling in Digital Images (http://dougkerr.net/Pumpkin/articles/Subsampling.pdf) PDF (page 3-6) has good information on the chroma placement between "centered" and "co-sited"...
Unfortunately that information is only reliable on original JPEGs, recompressed JPEGs sometimes lack the metadata and if it has it is not guaranteed to be correct.
-------
Reel.Deel, I've experimented with your banding examples and dithered DCT output (not quite higher bit depth, but close enough) no noticeable improvements.
Well that sucks. Althought there will be no visible improvements, it would still be nice if JpegSource could output 16-bits.
Only then I could have a true 16-bit workflow (JPEG --> 16-bit denoise --> 16-bit color correction --> 16-bit debanding (if necessary) --> 16-bit YUV to RGB conversion and finally save as a 16-bit PNG for archival.)
I know 16-bits is not magically going to make any image look better but at least there would be minimal rounding errors, then again it's just wishful thinking :).
foxyshadis
22nd April 2014, 08:51
Thanks for at least giving it a shot, SEt. I'd wondered for years if decoding to float or larger integer and dithering from there would help, but never taken the time to rip apart a decoder to find out. Thanks for at least taking the time to confirm that it's not helpful!
I'll have to stick with old-fashioned debanding solutions like gradfun then.
SEt
22nd April 2014, 11:43
@Reel.Deel
I think it should be mentioned that reconstruction is optional and can be turned off if you want regular JPEG decoding. Also without reconstruction just SSE2 is sufficient.
There can be a tag in JPEG that indicates that co-sited chroma (MPEG2) is used unlike default one (MPEG1) and JpegSource does know that information, but there is no good way to pass that to Avisynth: there are flags like CS_MPEG1_CHROMA_PLACEMENT, but not only nothing uses them, they are treated as completely new colorspaces so everything breaks with them. With recompressed JPEGs nothing could be done.
I'm thinking of adding 16-bit decoding – when I have time, I guess...
@foxyshadis
Well, I've might did something wrong, but there was subtle change and it was absolutely non-convincing, unlike apparent debanding of gradfun.
xyz1
23rd April 2014, 11:58
SEt,
Thank you man for this thread. Thank you very much.
(I've been waiting 5 days to be able to say this :D)
SEt
23rd April 2014, 22:19
Haha, I remember your pain – registered here to post plugin and had to wait 5 days to do so. Was "wtf are the rules here?"
filler56789
25th April 2014, 22:47
Hummm, would it be "worth the effort" :confused: to (somehow) force a conversion to YUY2 or YV**, for dealing with «uncommon» types of chroma subsampling?
Example: http://forum.videohelp.com/attachments/24790-1398452405/zYCC_(2x2-2x1-2x1).jpg
OT: ImageSource() works fine with RGB JPEGs (even the weirdest ones :) )
SEt
26th April 2014, 00:01
I see nothing special in that JPEGs: usual YV12.
As for conversions – see second example in first post. For unsupported chroma just replace UToY8/VToY8 by calls to JpegSource for planes 1 and 2.
JpegSource also works fine with RGB JPEGs – no problems so far.
Reel.Deel
26th April 2014, 00:53
I see nothing special in that JPEGs: usual YV12.
Actually, filler56789 linked to a 4:4:0 encoded JPEG.
-----------
@filler56789
To convert 4:4:0 JPEGs to 4:4:4 (YV24) do something like this:source = "image.jpg"
Y = JpegSource(source, channel=0)
U = JpegSource(source, channel=1).Spline36Resize(Y.width, Y.height)
V = JpegSource(source, channel=2).Spline36Resize(Y.width, Y.height)
YToUV(U,V,Y)
#ConvertToRGB24(matrix="PC.601") #Only needed if you want RGB output
Since Avisynth does not support 4:4:0 converting to YV24 is the better choice, with YV12 and YV16 you'll loose half the horizontal resolution in the chroma planes.
SEt
26th April 2014, 02:23
Oh, indeed it's actually 440. My other tool looked only at maximum sampling (2x2) and incorrectly guessed that it's 420. JpegSource detects this correctly, but I guess it also can get some more intellect in next version in case someone decides to use such redundant sampling with evil numbers like 3.
filler56789
26th April 2014, 02:40
@Reel.Deel — your recipe works :cool: ~ many thanks 4 that.
Spline36Resize()
In this particular case at least, shouldn't PointResize() be sufficient and adequate? :confused:
SEt
26th April 2014, 02:46
Spline36Resize()
In this particular case at least, shouldn't PointResize() be sufficient and adequate? :confused:
It all depends on how much you treasure chroma. In case you don't care (like many JPEG decoders) yes, PointResize is enough.
filler56789
26th April 2014, 03:53
It all depends on how much you treasure chroma. In case you don't care (like many JPEG decoders) – yes, PointResize is enough.
Thanks for the lesson, sir, I really need to drink more coffee :o
Regarding the Wiki...... I think it should include more "real-life examples" :) ---
--- based on the last script posted by Reel.Deel, here is what works for a "pathological" :devil: RGB file created w/ cjpeg.exe:
source = "zRGBsamplefile.jpg"
G = JpegSource(source, rec=0, channel=1)
R = JpegSource(source, rec=0, channel=0).Spline36Resize(G.width, G.height)
B = JpegSource(source, rec=0, channel=2).Spline36Resize(G.width, G.height)
MergeRGB(R, G, B, "RGB24")
As you can see, it's rather convoluted when compared to:
ImageSource("zRGBsamplefile.jpg", fps=25, end=249)
:helpful:
Reel.Deel
26th April 2014, 04:51
Regarding the Wiki...... I think it should include more "real-life examples" :)
When I get some time I'll gladly add some more examples. One good thing about the Wiki is that anyone can add useful information.
--- based on the last script posted by Reel.Deel, here is what works for a "pathological" :devil: RGB file created w/ cjpeg.exe:
source = "zRGBsamplefile.jpg"
G = JpegSource(source, rec=0, channel=1)
R = JpegSource(source, rec=0, channel=0).Spline36Resize(G.width, G.height)
B = JpegSource(source, rec=0, channel=2).Spline36Resize(G.width, G.height)
MergeRGB(R, G, B, "RGB24")
That example is wrong. The following examples are correct (and identical).
Simple:
JpegSource("RGBimage.jpg")
MergeRGB(last, UToY8(), VToY8(), "RGB24")
Convoluted:
JpegSource("RGBimage.jpg")
R = last
G = UToY8()
B = VToY8()
MergeRGB(R,G,B, pixel_type="RGB24")
As you can see, it's rather convoluted when compared to:
ImageSource("zRGBsamplefile.jpg", fps=25, end=249)
You know you can always make a function and then autoload it.
Something like this:
function JpegSourceRGB(string file, int "rec", int "length", float "fps_num", int "fps_den")
{
JpegSource(file=file, rec=rec, length=length, fps_num=fps_num, fps_den)
MergeRGB(last, UToY8(), VToY8(), "RGB24")
}
Then use it like this and be done with it:
JpegSourceRGB("RGBimage.jpg")
filler56789
26th April 2014, 05:46
That example is wrong.
It does work for the file I have, so how on Earth can it "be wrong"?
The following examples are correct (and identical).
Simple:
JpegSource("RGBimage.jpg")
MergeRGB(last, UToY8(), VToY8(), "RGB24")
OK, if I try to open the script above in VirtualDub,
I receive the following error message:
Avisynth open failure:
JpegSource: unsupported multi-channel configuration - use one channel mode
Conclusion: don't assume all RGB Jpeg files are "4:4:4".
More sample files:
http://forum.videohelp.com/attachments/24801-1398489774/Nene421-ycc.jpg
http://forum.videohelp.com/attachments/24800-1398489774/Nene421-rgb.jpg
http://forum.videohelp.com/attachments/24802-1398497209/Nene3xRGB.jpg
http://forum.videohelp.com/attachments/24803-1398497209/Nene3xYCC.jpg
SEt
26th April 2014, 16:25
^ these are good examples of "evil" JPEGs.
While I might support passing 444 RGB JPEGs to Avisynth as RGB24, here you'd have to do the conversions yourself. The idea of this source filter is to provide the actual data encoded in image without any colorspace conversions or resizes (that are usually really poor quality in decoders), and Avisynth colorspace support is quite limited.
Reel.Deel's idea is correct: you can write script function that does required resizes automatically. Just get max width and height and resize all components to them. (Well, in reality it's a bit more complicated as you would also need to account for components cut in the middle of sampling block.) Is it RGB, YUV or some other colorspace file you's have to know yourself, as there is no way now for plugin to pass such metainformation to script.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.