Closed IanButterworth closed 5 years ago
What happens if you run it inside of gdb
?
@staticfloat I actually just pushed a commit that gets it beyond the frame encoding to the very final freeing functions, but it hangs then crashes julia without error messages
Would be good to run that inside of gdb
, then when it crashes, get a stack trace to see where it's crashing. If it's within the final freeing functions though, that usually means that there's an out of bounds memory access somewhere; e.g. a structure that you pass to a C routine was actually too small, resulting in the C routing writing past the end of the allocated memory and clobbering something that free()
checks on.
Ok. I'm not familiar with gdb but will give it a go.
By the way, the change to mutable structs is breaking the tests. I haven't looked into how to prevent that yet
Ok. I'm not familiar with gdb but will give it a go.
Use gdb
(or lldb
, doesn't matter which) to run your program, usually through something like gdb --args julia script.jl
, then when gdb
comes up use r
to run the program. It will run as normal, then when it crashes, it will dump you to a gdb
REPL, and you can use bt
to print out a backtrace. Here's some small commands for navigating the callstack within gdb
, which may help you to inspect the state of local variables to figure out why you've crashed.
If it's truly a memory corruption issue, I suggest first double-checking everything that gets sent to C to see if there's an easily-discovered struct that's too small. If nothing jumps out at you, perhaps you will need to run it inside of valgrind
or a similar tool to determine where the illegitimate memory access actually happens.
@ianshmean thanks for taking this on! :heart:
Some thoughts on the current error (without actually looking at the code--I'll try to take a look later):
AVTimecode
not being defined properly. If you only ever need a pointer to it, try defining it as Cvoid
. Otherwise (as mentioned above), you'll probably need to define that struct in Julia.Base.sigatomic_begin()
and Base.sigatomic_end()
around the calls to ffmpeg, but I'm not sure if that was actually necessary.Thanks for the tips! The timebase error actually was fixed by unsafe_store!
-ing the loaded struct pointer back to its source. (I missed that unsafe_load
doesn't point to the original memory)
As of the current branch, it gets through writing the frames, and crashes on the free functions. However, even though it gets through writing the frames and closes the video file, the video file is only ~100 bytes.
I've not yet run it with gdb
. Hope to this evening.
I've been struggling to get gdb up and running, so not tried that yet. If anyone is able to test this, I just pushed more of a direct copy of the example
I don't know why, but the encode loop seems to be running out of order.. I guess there's some odd memory accessing timing going on
[libx264 @ 0x7ff4e90f3000] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2
[libx264 @ 0x7ff4e90f3000] profile High, level 1.3, 4:2:0, 8-bit
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Write packet 0 (size=809)
21
Write packet 2 (size=17)
22
Write packet 1 (size=14)
23
Write packet 4 (size=21)
24
Write packet 3 (size=14)
Write packet 6 (size=21)
Write packet 5 (size=14)
Write packet 8 (size=20)
Write packet 7 (size=14)
Write packet 9 (size=22)
Write packet 10 (size=109)
Write packet 12 (size=18)
Write packet 11 (size=16)
Write packet 14 (size=22)
Write packet 13 (size=16)
Write packet 16 (size=23)
Write packet 15 (size=16)
Write packet 18 (size=23)
Write packet 17 (size=16)
Write packet 19 (size=24)
Write packet 20 (size=112)
Write packet 22 (size=18)
Write packet 21 (size=16)
Write packet 24 (size=22)
Write packet 23 (size=16)
Julia has exited. Press Enter to start a new session.
The file is now 1KB, which is reassuring, but cannot be run, which makes sense if the write order is messed up
Does the C variant also write out of order? Maybe it's some weird optimization that ffmpeg does?
I haven't actually tested the C variant, but I just changed the test video to be based on rand(UInt8)
and the encode loop order now runs in the right order.
Also, the new rand video file does actually play in VLC, it just needs to be a .h264
file as per this post https://stackoverflow.com/a/53331847/1364192
Still crashing on the free functions though
The h.264 stream can be muxed into a mp4 via the ffmpeg executable:
run(`$(VideoIO.ffmpeg) -framerate 24 -i video.h264 -c copy output.mp4`)
which runs in quicktime (typically a pretty picky media player so seems robust..)
It's tempting to just use that at the end given it's a single line, and the low-level muxing example is rather long.. https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/muxing.c
After some tips from @jpsamaroo and handling an assertion bug with PaddedViews
over at https://github.com/JuliaLang/julia/issues/29594 I've now got lldb
running the script and have a backtrace.
Although, the issue isn't immediately clear to me from the backtrace..
...
Write packet 239 (size=945)
Write packet 240 (size=981)
Process 62222 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
frame #0: 0x00000001345e0a9a libavutil.56.dylib`avpriv_slicethread_free + 26
libavutil.56.dylib`avpriv_slicethread_free:
-> 0x1345e0a9a <+26>: movq (%r13), %r15
0x1345e0a9e <+30>: testq %r15, %r15
0x1345e0aa1 <+33>: je 0x1345e0b91 ; <+273>
0x1345e0aa7 <+39>: movl 0x8(%r15), %eax
Target 0: (julia-debug) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
* frame #0: 0x00000001345e0a9a libavutil.56.dylib`avpriv_slicethread_free + 26
frame #1: 0x0000000131552fbe libavcodec.58.dylib`___lldb_unnamed_symbol4842$$libavcodec.58.dylib + 30
frame #2: 0x000000013166c163 libavcodec.58.dylib`avcodec_close + 81
frame #3: 0x000000013150f597 libavcodec.58.dylib`avcodec_free_context + 23
frame #4: 0x00000001191e873d
frame #5: 0x000000010011c1c3 libjulia-debug.dylib`jl_apply_generic(F=0x000000010d4edd58, args=0x00007ffeefbfd438, nargs=1) at gf.c:2213:12
frame #6: 0x00000001001396d0 libjulia-debug.dylib`jl_apply(args=0x00007ffeefbfd430, nargs=2) at julia.h:1624:12
frame #7: 0x000000010053e5e8 libjulia-debug.dylib`jl_capture_interp_frame(data=0x0000000000000002, sp=140732920748512, fp=140732920747056, space_remaining=2) at interpreter-stacktrace.c:394
frame #8: 0x000000010053cb36 libjulia-debug.dylib`jl_gc_wb(parent=0x000000010e204610, ptr=0x000000000016e459) at julia.h:761:9
frame #9: 0x000000010053d67b libjulia-debug.dylib`eval_stmt_value + 43
frame #10: 0x000000010053bf7f libjulia-debug.dylib`eval_primitivetype(ex=0x00007ffeefbfd850, s=0xb76358a9cb690049) at interpreter.c:173
frame #11: 0x000000010053c4b6 libjulia-debug.dylib`jl_capture_interp_frame(data=0x00007ffeefbfda48, sp=140732920748616, fp=4516682544, space_remaining=140732920748336) at interpreter-stacktrace.c:404:13
frame #12: 0x00000001001377bc libjulia-debug.dylib`enter_interpreter_frame + 28
frame #13: 0x000000010053c561 libjulia-debug.dylib`jl_is_interpreter_frame(ip=4531963408) at interpreter-stacktrace.c:384
frame #14: 0x0000000100163dab libjulia-debug.dylib`jl_toplevel_eval_flex(m=0x0000000105b98bf0, e=0x000000010e0b9510, fast=1, expanded=1) at toplevel.c:814:18
frame #15: 0x0000000100125e37 libjulia-debug.dylib`jl_parse_eval_all(fname="/Users/ian/Documents/Leuko/GitHub/VideoIO.jl/examples/encodevideo.jl", content=0x0000000000000000, contentlen=0, inmodule=0x0000000105b98bf0) at ast.c:873:26
frame #16: 0x0000000100165abc libjulia-debug.dylib`jl_load(module=0x0000000105b98bf0, fname="/Users/ian/Documents/Leuko/GitHub/VideoIO.jl/examples/encodevideo.jl") at toplevel.c:878:12
frame #17: 0x0000000100165b32 libjulia-debug.dylib`jl_load_(module=0x0000000105b98bf0, str=0x000000010d503af0) at toplevel.c:885:12
frame #18: 0x0000000105391188 sys-debug.dylib`japi1_include_relative_3501 [inlined] include at boot.jl:328 [opt]
frame #19: 0x0000000105391178 sys-debug.dylib`japi1_include_relative_3501(#self#=<unavailable>, mod=Module @ 0x0000000105b98bf0, _path=0x0000000000000044) at loading.jl:1094 [opt]
frame #20: 0x000000010539d107 sys-debug.dylib`japi1_include_3693(#self#=<unavailable>, mod=Module @ 0x0000000105b98bf0, path=0x0000000000000044) at Base.jl:31 [opt]
frame #21: 0x00000001001136ea libjulia-debug.dylib`jl_fptr_args(f=0x000000010876b890, args=0x00007ffeefbff240, nargs=2, m=0x000000010876b430) at gf.c:1809:12
frame #22: 0x000000010011ba8c libjulia-debug.dylib`_jl_invoke(F=0x000000010876b890, args=0x00007ffeefbff240, nargs=2, mfunc=0x0000000105db5730, world=26229) at gf.c:2043:31
frame #23: 0x000000010011c1c3 libjulia-debug.dylib`jl_apply_generic(F=0x000000010876b890, args=0x00007ffeefbff240, nargs=2) at gf.c:2213:12
frame #24: 0x000000010539c1dc sys-debug.dylib`julia_exec_options_2250(#self#=<unavailable>, opts=<unavailable>) at client.jl:295 [opt]
frame #25: 0x000000010539ca3e sys-debug.dylib`japi1__start_2214(#self#=<unavailable>) at client.jl:464 [opt]
frame #26: 0x00000001001136ea libjulia-debug.dylib`jl_fptr_args(f=0x00000001067dc270, args=0x00007ffeefbff748, nargs=0, m=0x000000010755ba20) at gf.c:1809:12
frame #27: 0x000000010011ba8c libjulia-debug.dylib`_jl_invoke(F=0x00000001067dc270, args=0x00007ffeefbff748, nargs=0, mfunc=0x00000001067dbf40, world=26229) at gf.c:2043:31
frame #28: 0x000000010011c1c3 libjulia-debug.dylib`jl_apply_generic(F=0x00000001067dc270, args=0x00007ffeefbff748, nargs=0) at gf.c:2213:12
frame #29: 0x00000001000017b0 julia-debug`jl_apply(args=0x00007ffeefbff740, nargs=1) at julia.h:1624:12
frame #30: 0x0000000100001343 julia-debug`true_main(argc=1, argv=0x00007ffeefbff990) at repl.c:96:13
frame #31: 0x00000001000011d2 julia-debug`main(argc=1, argv=0x00007ffeefbff990) at repl.c:217:15
frame #32: 0x00007fff6035d3d5 libdyld.dylib`start + 1
frame #33: 0x00007fff6035d3d5 libdyld.dylib`start + 1
(lldb)
EXC_BAD_ACCESS
means you're reaching into a page that you shouldn't be (often signifies a use-after-free, or a pointer's value is corrupt (e.g. gibberish or NULL
or something like that).
As best I can tell, this is crashing because *pctx
is pointing to a non-NULL but invalid memory location. Reading through the source code for this function, it's pretty straightforward, but of course everything would be easier if we had a debug build of the libraries available (so as to have more useful source listings).
By the way, the change to mutable structs is breaking the tests. I haven't looked into how to prevent that yet
Some context:
When I started wrapping ffmpeg, Julia types were not layout compatible with C types, but immutable types were (I don't know why).
The problem with immutable types was that they were, well, immutable. But if they were in memory, then modifying them was possible, in theory.
Now, you really aren't supposed to do this, because since they were immutable, the compiler might do funky things with them (like leave them in registers, and not put them in memory at all).
That said, most of the types being wrapped in FFMpeg were large, so there was little chance that they would not be in memory.
So, everything was made immutable, so it could be loaded into Julia types easily, and if I needed to modify anything, I got a pointer to the original struct in memory and modified it with av_setfield
(defined in utils.jl).
Tada! (Yes, it was a really ugly hack... yuck!)
None of these shenanigans should be necessary now (Julia struct
s should be mostly layout compatible with C structs), but I've never taken the time to go back and fix things (sorry!).
This is most likely why the tests are failing.
So, to go forward, we need to either
av_setfield
to modify the values in memory, orav_setfield
1 is easier in the short run, 2 is the right thing to do.
I can help with 2, but I'm not sure when I'll get to it.
Note that it also should be possible to use Ref
everywhere a Vector
is used to store single pointer references.
(Again, when this was first written, Ref
didn't exist, and I never went back and changed things.)
@kmsquire After your suggestions this now works! thanks!
I do have to say though,
run(`$(VideoIO.ffmpeg) -framerate 24 -i video.h264 -c copy output.mp4`)
for now.As for the struct refactoring you mentioned, I was also looking at the Clang wrap script and wondering whether that should also be updated to the new Clang functionality? Perhaps if we're doing 2) we should also refresh the clang wrapper?
As for the struct refactoring you mentioned, I was also looking at the Clang wrap script and wondering whether that should also be updated to the new Clang functionality? Perhaps if we're doing 2) we should also refresh the clang wrapper?
Yes, that would be good. (In a separate PR, of course.)
- It outputs a .h264 file, which still needs to be mux-ed into a video container. We could just do
run(`$(VideoIO.ffmpeg) -framerate 24 -i video.h264 -c copy output.mp4`)
for now.
I think that would be fine for this pass.
- Looking at the .h264 file in vlc, the output video quality is very poor and glitchy.. and playback time immediately jumps to 75% through, but I'm guessing that's more of a non-muxed stream and ffmpeg encode settings thing, than code implementation thing.
I agree, it's probably due to the settings. It would be nice to find some nicer settings, but if you don't have time to explore, even getting this in as is would be useful.
The encoding is now added as functionality, available both as a high-level encoder for an image stack, and lower-level functions for incorporating into custom loops
imgstack = map(x->rand(UInt8,2048,1536),1:100)
100-element Array{Array{UInt8,2},1}
using VideoIO
props = [:priv_data => ("crf"=>"22","preset"=>"medium")]
encodevideo("video.mp4",imgstack,framerate=30,AVCodecContextProperties=props)
[ Info: Video file saved: /Users/ian/Documents/video.mp4
[ Info: frame= 100 fps=0.0 q=-1.0 Lsize= 129867kB time=00:00:03.23 bitrate=329035.1kbits/s speed=8.17x
[ Info: video:129865kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.001692%
using VideoIO, ProgressMeter
filename = "manual.mp4"
props = [:priv_data => ("crf"=>"22","preset"=>"medium")]
codec_name = "libx264"
framerate = 24
encoder = prepareencoder(imgstack[1],codec_name,framerate,props)
io = Base.open("temp.stream","w")
p = Progress(length(imgstack), 1)
index = 1
for img in imgstack
global index
appendencode!(encoder, io, img, index)
next!(p)
index += 1
end
finishencode!(encoder, io)
close(io)
mux("temp.stream",filename,framerate) #Multiplexes the stream into a video container
[ Info: Video file saved: /Users/ian/Documents/manual.mp4
[ Info: frame= 100 fps=0.0 q=-1.0 Lsize= 134451kB time=00:00:04.04 bitrate=272513.6kbits/s speed=9.88x
[ Info: video:134448kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.001634%
The AVCodecContextProperties
object allows control of the majority of settings required.
A few helpful presets for h264:
AVCodecContextProperties = [:priv_data => ("crf"=>"0","preset"=>"ultrafast")]
AVCodecContextProperties = [:priv_data => ("crf"=>"0","preset"=>"ultraslow")]
AVCodecContextProperties = [:priv_data => ("crf"=>"23","preset"=>"medium")]
AVCodecContextProperties = [:bit_rate => 400000,:gop_size = 10,:max_b_frames=1]
Handle RGB conversion given H264 can't store full RGB frames (and doesn't support AV_PIX_FMT_RGB24
).
Options:
To fix tests and get this merged, I think I'm going to change mutable structs back to immutable, and use av_setfield
within the encoder functions. The alternative seems like a lot more work (updating the clang wrapper, making structs mutable, changing the rest of the code) and I think you're right @kmsquire about the av_setfield
method.. while it's not ideal with modern julia functionality, it's low risk here
Great job getting all of this working! The package name finally won't be a lie anymore! π Thank you!
Seconded. It will be huge to have such improvements (this PR and the rest) to the video support in Julia. Thanks to you and @kmsquire for seeing this through!
Happy to help! π₯π
I've added RGB{N0f8}
support. Same example as above, just pass a RGB{N0f8}
image in.
If lossless RGB is wanted, true RGB lossless requires using libx264rgb
, to avoid the lossy YUV420 conversion. That's achieved with codec_name="libx264rgb"
and "crf" => "0"
in the above example, but that should only really be used for data storage purposes... Not even VLC can handle playing back libx264rgb smoothly. I also added warnings for cases where the crf & codec_name settings seem illogical for RGB lossless or lossy outputs
@kmsquire I tried converting to the av_pointer_to_field
approach but got stuck here. How would you handle writing to the immutable frame struct data arrays?
https://github.com/JuliaIO/VideoIO.jl/blob/41063bfaca92e8c69da4dc84fc7cfe760ae5cc0a/src/encoding.jl#L148-L178
NEARLY there..
Also, ffmpeg is throwing very infrequent non-fatal error messages out, like:
[h264 @ 0x7f8a5fcc7c00] Invalid NAL unit 8, skipping.
It would be good to either fix it, or silence it
I've been trying and failing to build a linux ffmpeg binary that provides the libx264rgb codec. If anyone has any ideas, this is the latest build script https://github.com/ianshmean/FFMPEGBuilder/blob/ad00f98ecc016c209390da7b93107f689106ac14/build_tarballs.jl#L16-L45
I think I've run out of ideas for getting ffmpeg built on linux with -libx264rgb
. This thread suggested some good ideas but didn't fix it.
Any ideas @SimonDanisch @jpsamaroo ?
https://github.com/ianshmean/FFMPEGBuilder/blob/master/build_tarballs.jl
I curious why you need the libx264rgb
codec? If vlc doesn't support it by default, then it's obviously pretty rare, and most cameras only generate data in yuv format. If you're getting data in rgb, it's most likely because it was converted from yuv before it was presented to you.
I have a particular interest in being able to store lossless grayscale and true RGB with h264's high performance compression, given I use scientific cameras that provide full range gray and rgb. Unfortunately from what I can tell from testing, GRAY8 clamps the 0-255 color range to 16-235, and there's no standard h264 RGB full plane mode.
libx264rgb is actually provided in the windows and MacOS builds we use from https://ffmpeg.zeranoe.com/builds/ and it's not clear why that happens from their make config.
I guess I could relax the testing, and just test for YUV420 encoding losslessness, which should pass on all.
All tests are passing!! πThat's previous tests plus encode tests for gray & RGB.
Thanks to @staticfloat for catching my error in the linux ffmpeg build config.. relative paths for cflags when absolute paths were needed! linux now supports libx246rgb
@kmsquire shall I merge? I'm thinking of squash-merging.. a single commit is probably sufficient here
I have a particular interest in being able to store lossless grayscale and true RGB with h264's high performance compression, given I use scientific cameras that provide full range gray and rgb.
We do that with grayscale. What's your experience here, is it truly lossless and what kind of compression ratio do you expect? I frequently wonder about the merits of compression vs. the ease of mmap
when accessing the data.
@timholy I've written up a lossless grayscale set of tests and added it to #174 (where I've fixed gray8 lossless encoding, but gray8 is oddly missing from h264 on the linux build..)
Each setting is tested 3 times (to provide mean and std).
Note that all videos passed the identical check (lossless w.r.t. source imgstack). Also, odd (but understandably odd) results with the random noise example. No variation in file size across repeats, as to be expected.
β Row β preset β identical β fps_mean β fps_std β filesize_perc_mean β filesize_perc_std β
β β Any β Bool β Float64 β Float64 β Float64 β Float64 β
βββββββΌββββββββββββΌββββββββββββΌβββββββββββΌββββββββββΌβββββββββββββββββββββΌββββββββββββββββββββ€
β 1 β ultrafast β true β 304.728 β 9.58154 β 100.0 β 0.0 β
β 2 β superfast β true β 255.114 β 10.716 β 75.3965 β 0.0 β
β 3 β veryfast β true β 199.211 β 52.4159 β 74.9182 β 0.0 β
β 4 β faster β true β 230.773 β 1.19191 β 74.9975 β 0.0 β
β 5 β fast β true β 243.758 β 4.43879 β 71.6298 β 0.0 β
β 6 β medium β true β 214.879 β 7.62118 β 70.9487 β 0.0 β
β 7 β slow β true β 166.16 β 2.05397 β 69.5094 β 0.0 β
β 8 β slower β true β 106.76 β 1.50004 β 67.8143 β 0.0 β
β 9 β veryslow β true β 61.9854 β 3.38506 β 67.0681 β 0.0 β
β Row β preset β identical β fps_mean β fps_std β filesize_perc_mean β filesize_perc_std β
β β Any β Bool β Float64 β Float64 β Float64 β Float64 β
βββββββΌββββββββββββΌββββββββββββΌβββββββββββΌβββββββββββΌβββββββββββββββββββββΌββββββββββββββββββββ€
β 1 β ultrafast β true β 184.186 β 38.182 β 100.0 β 0.0 β
β 2 β superfast β true β 137.663 β 4.6292 β 84.6588 β 0.0 β
β 3 β veryfast β true β 110.791 β 7.99061 β 83.3687 β 0.0 β
β 4 β faster β true β 100.058 β 0.535927 β 80.5937 β 0.0 β
β 5 β fast β true β 70.0545 β 1.19685 β 78.7228 β 0.0 β
β 6 β medium β true β 55.1113 β 4.30227 β 77.7667 β 0.0 β
β 7 β slow β true β 37.3717 β 0.901799 β 76.3431 β 0.0 β
β 8 β slower β true β 19.7098 β 0.165271 β 75.6813 β 0.0 β
β 9 β veryslow β true β 9.98514 β 0.211713 β 75.638 β 0.0 β
β Row β preset β identical β fps_mean β fps_std β filesize_perc_mean β filesize_perc_std β
β β Any β Bool β Float64 β Float64 β Float64 β Float64 β
βββββββΌββββββββββββΌββββββββββββΌβββββββββββΌβββββββββββΌβββββββββββββββββββββΌββββββββββββββββββββ€
β 1 β ultrafast β true β 97.9357 β 6.64778 β 100.0 β 0.0 β
β 2 β superfast β true β 58.8997 β 1.98085 β 92.0584 β 0.0 β
β 3 β veryfast β true β 62.149 β 0.257865 β 92.0584 β 0.0 β
β 4 β faster β true β 61.4085 β 1.86261 β 92.0584 β 0.0 β
β 5 β fast β true β 150.466 β 0.465406 β 64.4206 β 0.0 β
β 6 β medium β true β 144.832 β 3.72393 β 64.4206 β 0.0 β
β 7 β slow β true β 137.637 β 5.64154 β 64.4206 β 0.0 β
β 8 β slower β true β 142.924 β 0.432807 β 64.4206 β 0.0 β
β 9 β veryslow β true β 137.805 β 2.87539 β 64.4206 β 0.0 β
Just to make sure I understand, the file size is typically 2/3 that of the raw frames?
Actually, I was just comparing the ultrafast file size onwards.. what you ask is a more appropriate metric.. comparing to the raw data in the image stack.
Here filesize_perc = filesize("encodedvideo.mp4")/(img_width*img_height*imgstack_length)
It makes a lot of sense for each of the videos, and reassuring that noise is ~100% when it tries hard.
β Row β preset β identical β fps_mean β fps_std β filesize_perc_mean β filesize_perc_std β
β β Any β Bool β Float64 β Float64 β Float64 β Float64 β
βββββββΌββββββββββββΌββββββββββββΌβββββββββββΌββββββββββΌβββββββββββββββββββββΌββββββββββββββββββββ€
β 1 β ultrafast β true β 228.166 β 75.1439 β 4.80392 β 0.0 β
β 2 β superfast β true β 239.73 β 54.2033 β 3.62199 β 0.0 β
β 3 β veryfast β true β 197.506 β 13.1121 β 3.59901 β 0.0 β
β 4 β faster β true β 174.174 β 18.0316 β 3.60282 β 0.0 β
β 5 β fast β true β 235.181 β 7.40358 β 3.44104 β 0.0 β
β 6 β medium β true β 219.654 β 3.27445 β 3.40832 β 0.0 β
β 7 β slow β true β 171.337 β 3.92415 β 3.33917 β 0.0 β
β 8 β slower β true β 105.24 β 6.59151 β 3.25774 β 5.43896e-16 β
β 9 β veryslow β true β 63.1136 β 2.47291 β 3.2219 β 0.0 β
β Row β preset β identical β fps_mean β fps_std β filesize_perc_mean β filesize_perc_std β
β β Any β Bool β Float64 β Float64 β Float64 β Float64 β
βββββββΌββββββββββββΌββββββββββββΌβββββββββββΌβββββββββββΌβββββββββββββββββββββΌββββββββββββββββββββ€
β 1 β ultrafast β true β 176.787 β 36.5227 β 12.2293 β 0.0 β
β 2 β superfast β true β 135.925 β 7.04431 β 10.3532 β 0.0 β
β 3 β veryfast β true β 117.115 β 1.28102 β 10.1954 β 0.0 β
β 4 β faster β true β 94.39 β 3.48494 β 9.85604 β 0.0 β
β 5 β fast β true β 69.657 β 1.61004 β 9.62724 β 0.0 β
β 6 β medium β true β 54.9621 β 0.568074 β 9.51032 β 0.0 β
β 7 β slow β true β 37.8888 β 1.27484 β 9.33622 β 0.0 β
β 8 β slower β true β 20.1112 β 1.04282 β 9.25529 β 0.0 β
β 9 β veryslow β true β 10.0016 β 0.473213 β 9.24999 β 0.0 β
β Row β preset β identical β fps_mean β fps_std β filesize_perc_mean β filesize_perc_std β
β β Any β Bool β Float64 β Float64 β Float64 β Float64 β
βββββββΌββββββββββββΌββββββββββββΌβββββββββββΌββββββββββΌβββββββββββββββββββββΌββββββββββββββββββββ€
β 1 β ultrafast β true β 92.5769 β 8.40224 β 156.444 β 0.0 β
β 2 β superfast β true β 62.3509 β 1.19652 β 144.019 β 0.0 β
β 3 β veryfast β true β 59.9182 β 1.77294 β 144.019 β 0.0 β
β 4 β faster β true β 60.3482 β 2.32679 β 144.02 β 0.0 β
β 5 β fast β true β 149.169 β 1.56068 β 100.784 β 0.0 β
β 6 β medium β true β 146.141 β 3.41282 β 100.784 β 0.0 β
β 7 β slow β true β 147.214 β 1.23929 β 100.784 β 0.0 β
β 8 β slower β true β 138.808 β 2.553 β 100.784 β 0.0 β
β 9 β veryslow β true β 132.505 β 3.28558 β 100.784 β 0.0 β
I've nearly got the encode_video.c example converted into
examples/encodevideo.jl
but get through most of the setting up to line 106 and then: