Skip to content

Commit

Permalink
Update Clang wrapper generator and wrapper code (#333)
Browse files Browse the repository at this point in the history
  • Loading branch information
melonedo authored Nov 12, 2021
1 parent 717b540 commit 0a710e8
Show file tree
Hide file tree
Showing 115 changed files with 22,125 additions and 10,708 deletions.
1 change: 1 addition & 0 deletions gen/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
vdpau
8 changes: 8 additions & 0 deletions gen/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[deps]
Clang = "40e3b903-d033-50b4-a0cc-940c62c95e31"
FFMPEG = "c87230d0-a227-11e9-1b43-d7ebe4e7570a"
Match = "7eb4fadd-790c-5f42-8a69-bfa0b872bfbf"
Vulkan_Headers_jll = "8d446b21-f3ad-5576-a034-752265b9b6f9"

[compat]
Clang = "0.14.0"
17 changes: 17 additions & 0 deletions gen/epilogue.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
struct_types = Type[]
# Export everything
for name in names(@__MODULE__, all=true)
name in [Symbol("#eval"), Symbol("#include"), :include, :eval] && continue
@eval begin
export $name
$name isa Type && isstructtype($name) && push!(struct_types, $name)
end
end


function Base.getproperty(x::Ptr{<:Union{struct_types...}}, f::Symbol)
T = eltype(x)
fieldpos = Base.fieldindex(T, f)
field_pointer = convert(Ptr{fieldtype(T, fieldpos)}, x + fieldoffset(T, fieldpos))
return field_pointer
end
56 changes: 56 additions & 0 deletions gen/generate.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using Clang.Generators
using FFMPEG
using FFMPEG.FFMPEG_jll
using Vulkan_Headers_jll
using LibGit2
include("rewriter.jl")

cd(@__DIR__)

# Ideally I could have loaded all headers, but it turns out to be too hard

include_dir = joinpath(FFMPEG.FFMPEG_jll.artifact_dir, "include") |> normpath

vulkan_dir = joinpath(Vulkan_Headers_jll.artifact_dir, "include") |> normpath

if !isdir("vdpau")
LibGit2.clone("https://gitlab.freedesktop.org/vdpau/libvdpau", joinpath(@__DIR__, "vdpau"))
end

vdpau_dir = joinpath(@__DIR__, "vdpau", "include")

options = load_options(joinpath(@__DIR__, "generate.toml"))

args = get_default_args()
push!(args, "-I$include_dir", "-isystem$vulkan_dir", "-isystem$vdpau_dir")

const module_names = [
"libavcodec"
"libavdevice"
"libavfilter"
"libavformat"
"libavutil"
"libswscale"
]

library_names = Dict{String, String}()
headers = String[]
for lib in module_names
header_dir = joinpath(include_dir, lib)
append!(headers, joinpath(header_dir, header) for header in readdir(header_dir) if endswith(header, ".h"))
library_names[lib*".+"] = lib
end

options["general"]["library_names"] = library_names

ctx = create_context(headers, args, options)

@add_def time_t

build!(ctx, BUILDSTAGE_NO_PRINTING)
for node in ctx.dag.nodes
for i in eachindex(node.exprs)
node.exprs[i] = rewrite(node.exprs[i])
end
end
build!(ctx, BUILDSTAGE_PRINTING_ONLY)
35 changes: 35 additions & 0 deletions gen/generate.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[general]
library_name = "libffmpeg"
output_file_path = "../lib/libffmpeg.jl"
module_name = "libffmpeg"
jll_pkg_name = "FFMPEG"
prologue_file_path = "prologue.jl"
epilogue_file_path = "epilogue.jl"
use_julia_native_enum_type = false
print_using_CEnum = false
print_enum_as_integer = true
use_deterministic_symbol = true
is_local_header_only = true
smart_de_anonymize = true
printer_blacklist = [
"AV_NOPTS_VALUE",
"av_builtin_constant_p",
"LIBSWSCALE_IDENT",
"LIBAVDEVICE_IDENT",
"LIBAVFILTER_IDENT",
"LIBAVFORMAT_IDENT",
"LIBAVCODEC_IDENT",
"LIBAVUTIL_IDENT",
"AVPROBE_SCORE_MAX",
"Picture",
"AV_BPRINT_SIZE_UNLIMITED",
"FF_CEIL_RSHIFT"
]
extract_c_comment_style = "doxygen"
[codegen]
use_julia_bool = true
always_NUL_terminated_string = true
is_function_strictly_typed = true
opaque_func_arg_as_PtrCvoid = false
opaque_as_mutable_struct = true
use_ccall_macro = false
12 changes: 12 additions & 0 deletions gen/prologue.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const intptr_t = UInt
const time_t = Int

const AV_NOPTS_VALUE = 0x8000000000000000 % Int64
AV_VERSION_INT(a, b, c) = (a << 16 | b << 8) | c
AV_VERSION(a,b,c) = nothing
const AVPROBE_SCORE_MAX = 100
MKTAG(a,b,c,d) = (UInt32(a) | (UInt32(b) << 8) | (UInt32(c) << 16) | UInt32(d) << 24)
FFERRTAG(a,b,c,d) = -MKTAG(a,b,c,d)
macro AV_PIX_FMT_NE(be, le)
Symbol("AV_PIX_FMT_"*string(le))
end
90 changes: 90 additions & 0 deletions gen/rewriter.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using Match
import Base.Meta.isexpr

# argument such as int[2] were translated to NTuple{UInt8, 16}
# but it seems they are never referenced so its fine
const as_ntuple = [
:avcodec_align_dimensions2
:av_display_rotation_get
:av_display_rotation_set
:av_display_matrix_flip
:av_image_fill_max_pixsteps
:av_image_fill_linesizes
:av_image_fill_pointers
:av_image_alloc
:av_image_copy
:av_image_copy_uc_from
:av_image_fill_black
:av_read_image_line2
:av_read_image_line
:av_write_image_line2
:av_write_image_line
:av_tree_find
:av_xtea_init
:av_xtea_le_init
:avcodec_align_dimensions2
]


function rewrite(e::Expr)
@match e begin
Expr(:function, [fncall, body]) => rewrite_fn(e, fncall, body)
Expr(:const, [arg]) => rewrite_const(e)
_ => e
end
end

function rewrite_const(e)
body = e.args[]
lhs, rhs = body.args
name = string(lhs)
if match(r"^AV_PIX_FMT_[\w\d]+$", name) |> !isnothing
func, be, le = rhs.args
func == :AV_PIX_FMT_NE || return e
rhs = Expr(:macrocall, Symbol("@AV_PIX_FMT_NE"), nothing, be, le)
body.args[2] = rhs
end
e
end

# Rewrite function signatures to be more friendly
function rewrite_fn(e, fncall, body, use_strpack=false)
fncall.args[1] isa Symbol || return e

parms = Any[]
content = Any[]

push!(parms, fncall.args[1]) # function name

# Add explicit conversions for Ptr, UInt32/Int32, and va_list
for call_arg in fncall.args[2:end]
@match call_arg begin
# Don't type Ptr{x} types
Expr(:(::), [sym, Expr(:curly, [:Ptr, _])]) => push!(parms, sym)

# Type all integers as Integer
Expr(:(::), [sym, (:UInt32 || :Cuint || :Int32 || :Cint)]) => (sym; push!(parms, :($sym::Integer)))

# va_list
Expr(:(::), [sym, :va_list]) => push!(parms, sym)

# Everything else is unchanged
_ => push!(parms, call_arg)
end
end

if !isexpr(body, :block)
# body just consists of the ccall
push!(content, body)
else
append!(content, body.args)
end

fncall = Expr(:call, parms...)
body = Expr(:block, content...)

new = Expr(e.head, fncall, body)

return new
end

Loading

0 comments on commit 0a710e8

Please sign in to comment.