LoadingByte / cinecred

Create beautiful film credits without the pain.
https://cinecred.com
GNU General Public License v3.0
69 stars 6 forks source link

[Bug] "IllegalStateException: Already Closed" when render interlaced #14

Open mezhgano opened 3 weeks ago

mezhgano commented 3 weeks ago

I'm trying to export interlaced project that always causes exception somewhere around 55.5%

Log:

---- LOG ----
14725 [GlobalThreadPool] INFO Ghostscript - GPL Ghostscript 10.04.0 (2024-09-18)
14730 [GlobalThreadPool] INFO Ghostscript - Copyright (C) 2024 Artifex Software, Inc.  All rights reserved.
14730 [GlobalThreadPool] INFO Ghostscript - This software is supplied under the GNU AGPLv3 and comes with NO WARRANTY:
14730 [GlobalThreadPool] INFO Ghostscript - see the file COPYING for details.
14764 [GlobalThreadPool] INFO Ghostscript - Processing pages 1 through 1.
14765 [GlobalThreadPool] INFO Ghostscript - Page 1
14953 [GlobalThreadPool] WARNING org.apache.pdfbox.pdmodel.graphics.color.PDICCBased - ICC profile is Perceptual, ignoring, treating as Display class
15101 [GlobalThreadPool] INFO Ghostscript - GPL Ghostscript 10.04.0 (2024-09-18)
15102 [GlobalThreadPool] INFO Ghostscript - Copyright (C) 2024 Artifex Software, Inc.  All rights reserved.
15102 [GlobalThreadPool] INFO Ghostscript - This software is supplied under the GNU AGPLv3 and comes with NO WARRANTY:
15102 [GlobalThreadPool] INFO Ghostscript - see the file COPYING for details.
15140 [GlobalThreadPool] INFO Ghostscript - Processing pages 1 through 1.
15141 [GlobalThreadPool] INFO Ghostscript - Page 1
3714649 [VideoFrameMaterializer] SEVERE Cinecred - Uncaught exception. Will terminate the program.
java.lang.IllegalStateException: Already closed
    at java.base/jdk.internal.foreign.MemorySessionImpl.alreadyClosed(Unknown Source)
    at java.base/jdk.internal.misc.ScopedMemoryAccess$ScopedAccessError.newRuntimeException(Unknown Source)
    at java.base/jdk.internal.misc.ScopedMemoryAccess.copyMemory(Unknown Source)
    at java.base/jdk.internal.foreign.AbstractMemorySegmentImpl.copy(Unknown Source)
    at java.base/java.lang.foreign.MemorySegment.copy(Unknown Source)
    at java.base/java.lang.foreign.MemorySegment.copy(Unknown Source)
    at com.loadingbyte.cinecred.imaging.Bitmap.blit(Bitmap.kt:353)
    at com.loadingbyte.cinecred.imaging.DeferredVideo$BitmapBackend.obtainStaticInterlacedFrame(DeferredVideo.kt:461)
    at com.loadingbyte.cinecred.imaging.DeferredVideo$BitmapBackend.obtainDynamicInterlacedFrame(DeferredVideo.kt:496)
    at com.loadingbyte.cinecred.imaging.DeferredVideo$BitmapBackend.materializeFrame(DeferredVideo.kt:319)
    at com.loadingbyte.cinecred.delivery.VideoContainerRenderJob.render$lambda$2(VideoContainerRenderJob.kt:135)
    at java.base/java.lang.Thread.run(Unknown Source)

Export Settings:

Actually i export this to ProRes 422 HQ, but switch to PNG because it faster to check if it crash again or not :)

Screenshot 2024-11-03 23-10-40 CineCred_–_Delivery_–_Cinecred

Last rendered frame (always somewhere around this section):

Render_2 0002135

Projects Archive

CineCred_Exception_Project.zip

I'm tried to figure out what exactly causing this and notice that it only crash if i set Scroll Per Frame [px] to 4 px, but that exactly speed it needed to be... Any ideas?

LoadingByte commented 3 weeks ago

Thanks for catching this! I managed to trace back the bug to a premature free of an image buffer in the interlaced video renderer.

This will be fixed in the next release, and in the meantime, I can provide you with a dev build if you tell me which OS you're using :)

mezhgano commented 3 weeks ago

Thanks for such a quick response! I'm using CineCred on Windows 10 and totally happy with new way to create credits. As a temporary workaround i had to export this project as progressive, then just import to After Effects and export as interlaced.

LoadingByte commented 2 weeks ago

Sorry for the delay, but here's your dev build at last: https://loadingbyte.com/files/cinecred-1.8.0-SNAPSHOT-windows-x86_64.zip

mezhgano commented 2 weeks ago

That's fine, really not expecting this, much appreciated.

I'm tried dev build today, now it successfully renders, but looks like something is still messed up.

This is how interlaced frame should look like after deinterlace effect applied, pipeline was:

CineCred (Progressive Render) > After Effects (Interlaced Render, Top Field First) > Import to After Effects and applied deinterlace effect > Screenshot

It looks almost identical to progressive render: Screenshot 2024-11-14 18-56-00 Adobe_After_Effects_2024_-_NPROJECTSFL05_Work_ _

And this is screenshot of exact same frame straight from CineCred, pipeline was:

CineCred (Interlace Render, Top Filed First) > Import to After Effects with deinterlace effect > Screenshot

Fields is visible: Screenshot 2024-11-14 18-56-04 Adobe_After_Effects_2024_-_NPROJECTSFL05_Work_ _

I though it might be my mistake with something, because i don't own TVLogic monitor to be sure 100%. Today i had a talk with video engineer from local studio, they have it and he's confirmed that interlaced version from CineCred is messed. By the way i'm only used "Top Field First" because its local standard.

So for now i am always export progressive from CineCred as described in previous comment.

LoadingByte commented 1 week ago

I'm wondering how After Effects converts progressive footage to interlaced. Unless it's applying sth like optical flow to generate fields in-between progressive frames, it will never yield the same result as Cinecred.

A bit of background: To generate an interlaced video at say 25 frames per second (so 50 fields per second), Cinecred first internally renders the credits at 50 progressive frames per second. Assuming you're exporting top field first, it then generates field 1 by grabbing the odd lines of internal frame 1, field 2 from the even lines of frame 2, field 3 from the odd lines of frame 3, and so on. This is exactly what a physical interlaced camera would do: sample fields 1/50th of a second apart. Also, I tested this behavior extensively and am pretty certain the implementation is correct. But of course, it's always possible that I missed some rare bug.

When you combine a pair of fields generated by Cinecred into a single progressive frame by just interlacing the fields (which is done by most video players, most apparent when pausing), you'll see something very similar to your second picture. Actually, it looks like After Effects is really doing exactly that simple combination here. Perhaps its deinterlacer is targeted towards fixing horizontal movement, but the credits of course move vertically, so it doesn't do anything smart.

So all in all, Cinecred renders interlaced credits in a physically correct way, equivalent to pointing a physical interlaced camera at a sheet of paper (with the credits printed on it) and moving the paper at a steady pace. As the result of this process doesn't match what you need, maybe you're actually looking for something different? I never worked in a fully interlaced workflow before, so I'm unsure what it could be. But as you're experienced in this matter, maybe you can already specify it, or we can figure it out :)

mezhgano commented 3 days ago

Ok, thanks for the clarification. I suggest we put the question on hold for now, I'll try to gather more information and check a few things.

By the way i used third-party plugin "FieldsKit" from "RE:Vision Effects" to check how deinterlaced video looks like, it has variety of options to achieve it:

image

mezhgano commented 2 days ago

Also, interesting thing to notice, if i inspect both After Effects and CineCred renders with ffprobe it shows different interlaced statements:

After Effects: yuv422p10le(gbr/bt709/bt709, top coded first (swapped))

CineCred: yuv422p10le(bt709, top first)