From 11295a28f6e58ac0b3eda9138cfa7966e1bd19d2 Mon Sep 17 00:00:00 2001 From: Sergey Stepanov Date: Sat, 10 Feb 2024 16:22:45 +0300 Subject: [PATCH] Fix h264 lib for Go 1.22 Unwrapped X264_ C structs prevent crash on Go version 1.22. --- pkg/encoder/h264/libx264.go | 533 ------------------------------------ pkg/encoder/h264/x264.go | 135 +++++---- 2 files changed, 83 insertions(+), 585 deletions(-) delete mode 100644 pkg/encoder/h264/libx264.go diff --git a/pkg/encoder/h264/libx264.go b/pkg/encoder/h264/libx264.go deleted file mode 100644 index 6be21eb6a..000000000 --- a/pkg/encoder/h264/libx264.go +++ /dev/null @@ -1,533 +0,0 @@ -// Package h264 implements cgo bindings for [x264](https://www.videolan.org/developers/x264.html) library. -package h264 - -/* -#cgo !st pkg-config: x264 -#cgo st LDFLAGS: -l:libx264.a - -#include "stdint.h" -#include "x264.h" -#include - -static int x264_encode( x264_t *h, uintptr_t pp_nal, int *pi_nal, x264_picture_t *pic_in, x264_picture_t *pic_out ) { - return x264_encoder_encode(h, (x264_nal_t **)pp_nal, pi_nal, pic_in, pic_out); -} - -*/ -import "C" -import "unsafe" - -const Build = C.X264_BUILD - -// T is opaque handler for encoder -type T struct{} - -// Nal is The data within the payload is already NAL-encapsulated; the ref_idc and type -// are merely in the struct for easy access by the calling application. -// All data returned in x264_nal_t, including the data in p_payload, is no longer -// valid after the next call to x264_encoder_encode. Thus, it must be used or copied -// before calling x264_encoder_encode or x264_encoder_headers again. -type Nal struct { - IRefIdc int32 /* nal_priority_e */ - IType int32 /* nal_unit_type_e */ - BLongStartcode int32 - IFirstMb int32 /* If this NAL is a slice, the index of the first MB in the slice. */ - ILastMb int32 /* If this NAL is a slice, the index of the last MB in the slice. */ - - /* Size of payload (including any padding) in bytes. */ - IPayload int32 - /* If param->b_annexb is set, Annex-B bytestream with startcode. - * Otherwise, startcode is replaced with a 4-byte size. - * This size is the size used in mp4/similar muxing; it is equal to i_payload-4 */ - /* C.uint8_t */ - PPayload unsafe.Pointer - - /* Size of padding in bytes. */ - IPadding int32 -} - -const RcCrf = 1 - -const ( - CspI420 = 0x0002 // yuv 4:2:0 planar - CspVflip = 0x1000 /* the csp is vertically flipped */ - - // CspMask = 0x00ff /* */ - // CspNone = 0x0000 /* Invalid mode */ - // CspI400 = 0x0001 /* monochrome 4:0:0 */ - - //CspYv12 = 0x0003 /* yvu 4:2:0 planar */ - //CspNv12 = 0x0004 /* yuv 4:2:0, with one y plane and one packed u+v */ - //CspNv21 = 0x0005 /* yuv 4:2:0, with one y plane and one packed v+u */ - //CspI422 = 0x0006 /* yuv 4:2:2 planar */ - //CspYv16 = 0x0007 /* yvu 4:2:2 planar */ - //CspNv16 = 0x0008 /* yuv 4:2:2, with one y plane and one packed u+v */ - //CspYuyv = 0x0009 /* yuyv 4:2:2 packed */ - //CspUyvy = 0x000a /* uyvy 4:2:2 packed */ - //CspV210 = 0x000b /* 10-bit yuv 4:2:2 packed in 32 */ - //CspI444 = 0x000c /* yuv 4:4:4 planar */ - //CspYv24 = 0x000d /* yvu 4:4:4 planar */ - //CspBgr = 0x000e /* packed bgr 24bits */ - //CspBgra = 0x000f /* packed bgr 32bits */ - //CspRgb = 0x0010 /* packed rgb 24bits */ - //CspMax = 0x0011 /* end of list */ - //CspHighDepth = 0x2000 /* the csp has a depth of 16 bits per pixel component */ -) - -type Zone struct { - IStart, IEnd int32 /* range of frame numbers */ - BForceQp int32 /* whether to use qp vs bitrate factor */ - IQp int32 - FBitrateFactor float32 - Param *Param -} - -type Param struct { - /* CPU flags */ - Cpu uint32 - IThreads int32 /* encode multiple frames in parallel */ - ILookaheadThreads int32 /* multiple threads for lookahead analysis */ - BSlicedThreads int32 /* Whether to use slice-based threading. */ - BDeterministic int32 /* whether to allow non-deterministic optimizations when threaded */ - BCpuIndependent int32 /* force canonical behavior rather than cpu-dependent optimal algorithms */ - ISyncLookahead int32 /* threaded lookahead buffer */ - - /* Video Properties */ - IWidth int32 - IHeight int32 - ICsp int32 /* CSP of encoded bitstream */ - IBitdepth int32 - ILevelIdc int32 - IFrameTotal int32 /* number of frames to encode if known, else 0 */ - - /* NAL HRD - * Uses Buffering and Picture Timing SEIs to signal HRD - * The HRD in H.264 was not designed with VFR in mind. - * It is therefore not recommended to use NAL HRD with VFR. - * Furthermore, reconfiguring the VBV (via x264_encoder_reconfig) - * will currently generate invalid HRD. */ - INalHrd int32 - - Vui struct { - /* they will be reduced to be 0 < x <= 65535 and prime */ - ISarHeight int32 - ISarWidth int32 - - IOverscan int32 /* 0=undef, 1=no overscan, 2=overscan */ - - /* see h264 annex E for the values of the following */ - IVidformat int32 - BFullrange int32 - IColorprim int32 - ITransfer int32 - IColmatrix int32 - IChromaLoc int32 /* both top & bottom */ - } - - /* Bitstream parameters */ - IFrameReference int32 /* Maximum number of reference frames */ - IDpbSize int32 /* Force a DPB size larger than that implied by B-frames and reference frames. - * Useful in combination with interactive error resilience. */ - IKeyintMax int32 /* Force an IDR keyframe at this interval */ - IKeyintMin int32 /* Scenecuts closer together than this are coded as I, not IDR. */ - IScenecutThreshold int32 /* how aggressively to insert extra I frames */ - BIntraRefresh int32 /* Whether or not to use periodic intra refresh instead of IDR frames. */ - - IBframe int32 /* how many b-frame between 2 references pictures */ - IBframeAdaptive int32 - IBframeBias int32 - IBframePyramid int32 /* Keep some B-frames as references: 0=off, 1=strict hierarchical, 2=normal */ - BOpenGop int32 - BBlurayCompat int32 - IAvcintraClass int32 - IAvcintraFlavor int32 - - BDeblockingFilter int32 - IDeblockingFilterAlphac0 int32 /* [-6, 6] -6 light filter, 6 strong */ - IDeblockingFilterBeta int32 /* [-6, 6] idem */ - - BCabac int32 - ICabacInitIdc int32 - - BInterlaced int32 - BConstrainedIntra int32 - - ICqmPreset int32 - PszCqmFile *int8 /* filename (in UTF-8) of CQM file, JM format */ - Cqm4iy [16]byte /* used only if i_cqm_preset == X264_CQM_CUSTOM */ - Cqm4py [16]byte - Cqm4ic [16]byte - Cqm4pc [16]byte - Cqm8iy [64]byte - Cqm8py [64]byte - Cqm8ic [64]byte - Cqm8pc [64]byte - - /* Log */ - PfLog *[0]byte - PLogPrivate unsafe.Pointer - ILogLevel int32 - BFullRecon int32 /* fully reconstruct frames, even when not necessary for encoding. Implied by psz_dump_yuv */ - PszDumpYuv *int8 /* filename (in UTF-8) for reconstructed frames */ - - /* Encoder analyser parameters */ - Analyse struct { - Intra uint32 /* intra partitions */ - Inter uint32 /* inter partitions */ - - BTransform8x8 int32 - IWeightedPred int32 /* weighting for P-frames */ - BWeightedBipred int32 /* implicit weighting for B-frames */ - IDirectMvPred int32 /* spatial vs temporal mv prediction */ - IChromaQpOffset int32 - - IMeMethod int32 /* motion estimation algorithm to use (X264_ME_*) */ - IMeRange int32 /* integer pixel motion estimation search range (from predicted mv) */ - IMvRange int32 /* maximum length of a mv (in pixels). -1 = auto, based on level */ - IMvRangeThread int32 /* minimum space between threads. -1 = auto, based on number of threads. */ - ISubpelRefine int32 /* subpixel motion estimation quality */ - BChromaMe int32 /* chroma ME for subpel and mode decision in P-frames */ - BMixedReferences int32 /* allow each mb partition to have its own reference number */ - ITrellis int32 /* trellis RD quantization */ - BFastPskip int32 /* early SKIP detection on P-frames */ - BDctDecimate int32 /* transform coefficient thresholding on P-frames */ - INoiseReduction int32 /* adaptive pseudo-deadzone */ - FPsyRd float32 /* Psy RD strength */ - FPsyTrellis float32 /* Psy trellis strength */ - BPsy int32 /* Toggle all psy optimizations */ - - BMbInfo int32 /* Use input mb_info data in x264_picture_t */ - BMbInfoUpdate int32 /* Update the values in mb_info according to the results of encoding. */ - - /* the deadzone size that will be used in luma quantization */ - ILumaDeadzone [2]int32 - - BPsnr int32 /* compute and print PSNR stats */ - BSsim int32 /* compute and print SSIM stats */ - } - - /* Rate control parameters */ - Rc struct { - IRcMethod int32 /* X264_RC_* */ - - IQpConstant int32 /* 0=lossless */ - IQpMin int32 /* min allowed QP value */ - IQpMax int32 /* max allowed QP value */ - IQpStep int32 /* max QP step between frames */ - - IBitrate int32 - FRfConstant float32 /* 1pass VBR, nominal QP */ - FRfConstantMax float32 /* In CRF mode, maximum CRF as caused by VBV */ - FRateTolerance float32 - IVbvMaxBitrate int32 - IVbvBufferSize int32 - FVbvBufferInit float32 /* <=1: fraction of buffer_size. >1: kbit */ - FIpFactor float32 - FPbFactor float32 - - /* VBV filler: force CBR VBV and use filler bytes to ensure hard-CBR. - * Implied by NAL-HRD CBR. */ - BFiller int32 - - IAqMode int32 /* psy adaptive QP. (X264_AQ_*) */ - FAqStrength float32 - BMbTree int32 /* Macroblock-tree ratecontrol. */ - ILookahead int32 - - /* 2pass */ - BStatWrite int32 /* Enable stat writing in psz_stat_out */ - PszStatOut *int8 /* output filename (in UTF-8) of the 2pass stats file */ - BStatRead int32 /* Read stat from psz_stat_in and use it */ - PszStatIn *int8 /* input filename (in UTF-8) of the 2pass stats file */ - - /* 2pass params (same as ffmpeg ones) */ - FQcompress float32 /* 0.0 => cbr, 1.0 => constant qp */ - FQblur float32 /* temporally blur quants */ - FComplexityBlur float32 /* temporally blur complexity */ - Zones *Zone /* ratecontrol overrides */ - IZones int32 /* number of zone_t's */ - PszZones *int8 /* alternate method of specifying zones */ - } - - /* Cropping Rectangle parameters: added to those implicitly defined by - non-mod16 video resolutions. */ - CropRect struct { - ILeft int32 - ITop int32 - IRight int32 - IBottom int32 - } - - /* frame packing arrangement flag */ - IFramePacking int32 - - /* alternative transfer SEI */ - IAlternativeTransfer int32 - - /* Muxing parameters */ - BAud int32 /* generate access unit delimiters */ - BRepeatHeaders int32 /* put SPS/PPS before each keyframe */ - BAnnexb int32 /* if set, place start codes (4 bytes) before NAL units, - * otherwise place size (4 bytes) before NAL units. */ - ISpsId int32 /* SPS and PPS id number */ - BVfrInput int32 /* VFR input. If 1, use timebase and timestamps for ratecontrol purposes. - * If 0, use fps only. */ - BPulldown int32 /* use explicity set timebase for CFR */ - IFpsNum uint32 - IFpsDen uint32 - ITimebaseNum uint32 /* Timebase numerator */ - ITimebaseDen uint32 /* Timebase denominator */ - - BTff int32 - - /* Pulldown: - * The correct pic_struct must be passed with each input frame. - * The input timebase should be the timebase corresponding to the output framerate. This should be constant. - * e.g. for 3:2 pulldown timebase should be 1001/30000 - * The PTS passed with each frame must be the PTS of the frame after pulldown is applied. - * Frame doubling and tripling require b_vfr_input set to zero (see H.264 Table D-1) - * - * Pulldown changes are not clearly defined in H.264. Therefore, it is the calling app's responsibility to manage this. - */ - - BPicStruct int32 - - /* Fake Interlaced. - * - * Used only when b_interlaced=0. Setting this flag makes it possible to flag the stream as PAFF interlaced yet - * encode all frames progressively. It is useful for encoding 25p and 30p Blu-Ray streams. - */ - BFakeInterlaced int32 - - /* Don't optimize header parameters based on video content, e.g. ensure that splitting an input video, compressing - * each part, and stitching them back together will result in identical SPS/PPS. This is necessary for stitching - * with container formats that don't allow multiple SPS/PPS. */ - BStitchable int32 - - BOpencl int32 /* use OpenCL when available */ - IOpenclDevice int32 /* specify count of GPU devices to skip, for CLI users */ - OpenclDeviceId unsafe.Pointer /* pass explicit cl_device_id as void*, for API users */ - PszClbinFile *int8 /* filename (in UTF-8) of the compiled OpenCL kernel cache file */ - - /* Slicing parameters */ - iSliceMaxSize int32 /* Max size per slice in bytes; includes estimated NAL overhead. */ - iSliceMaxMbs int32 /* Max number of MBs per slice; overrides iSliceCount. */ - iSliceMinMbs int32 /* Min number of MBs per slice */ - iSliceCount int32 /* Number of slices per frame: forces rectangular slices. */ - iSliceCountMax int32 /* Absolute cap on slices per frame; stops applying slice-max-size - * and slice-max-mbs if this is reached. */ - - ParamFree *func(arg unsafe.Pointer) - NaluProcess *func(H []T, Nal []Nal, Opaque unsafe.Pointer) - - Opaque unsafe.Pointer -} - -/**************************************************************************** - * H.264 level restriction information - ****************************************************************************/ - -type Level struct { - LevelIdc byte - Mbps int32 /* max macroblock processing rate (macroblocks/sec) */ - FrameSize int32 /* max frame size (macroblocks) */ - Dpb int32 /* max decoded picture buffer (mbs) */ - Bitrate int32 /* max bitrate (kbit/sec) */ - Cpb int32 /* max vbv buffer (kbit) */ - MvRange uint16 /* max vertical mv component range (pixels) */ - MvsPer2mb byte /* max mvs per 2 consecutive mbs. */ - SliceRate byte /* ?? */ - Mincr byte /* min compression ratio */ - Bipred8x8 byte /* limit bipred to >=8x8 */ - Direct8x8 byte /* limit b_direct to >=8x8 */ - FrameOnly byte /* forbid interlacing */ -} - -type PicStruct int32 - -type Hrd struct { - CpbInitialArrivalTime float64 - CpbFinalArrivalTime float64 - CpbRemovalTime float64 - - DpbOutputTime float64 -} - -type SeiPayload struct { - PayloadSize int32 - PayloadType int32 - Payload *byte -} - -type Sei struct { - NumPayloads int32 - Payloads *SeiPayload - /* In: optional callback to free each payload AND x264_sei_payload_t when used. */ - SeiFree *func(arg0 unsafe.Pointer) -} - -type Image struct { - ICsp int32 /* Colorspace */ - IPlane int32 /* Number of image planes */ - IStride [4]int32 /* Strides for each plane */ - Plane [4]uintptr /* Pointers to each plane */ -} - -type ImageProperties struct { - /* In: an array of quantizer offsets to be applied to this image during encoding. - * These are added on top of the decisions made by x264. - * Offsets can be fractional; they are added before QPs are rounded to integer. - * Adaptive quantization must be enabled to use this feature. Behavior if quant - * offsets differ between encoding passes is undefined. */ - QuantOffsets *float32 - /* In: optional callback to free quant_offsets when used. - * Useful if one wants to use a different quant_offset array for each frame. */ - QuantOffsetsFree *func(arg0 unsafe.Pointer) - - /* In: optional array of flags for each macroblock. - * Allows specifying additional information for the encoder such as which macroblocks - * remain unchanged. Usable flags are listed below. - * x264_param_t.analyse.b_mb_info must be set to use this, since x264 needs to track - * extra data internally to make full use of this information. - * - * Out: if b_mb_info_update is set, x264 will update this array as a result of encoding. - * - * For "MBINFO_CONSTANT", it will remove this flag on any macroblock whose decoded - * pixels have changed. This can be useful for e.g. noting which areas of the - * frame need to actually be blitted. Note: this intentionally ignores the effects - * of deblocking for the current frame, which should be fine unless one needs exact - * pixel-perfect accuracy. - * - * Results for MBINFO_CONSTANT are currently only set for P-frames, and are not - * guaranteed to enumerate all blocks which haven't changed. (There may be false - * negatives, but no false positives.) - */ - MbInfo *byte - /* In: optional callback to free mb_info when used. */ - MbInfoFree *func(arg0 unsafe.Pointer) - - /* Out: SSIM of the the frame luma (if x264_param_t.b_ssim is set) */ - FSsim float64 - /* Out: Average PSNR of the frame (if x264_param_t.b_psnr is set) */ - FPsnrAvg float64 - /* Out: PSNR of Y, U, and V (if x264_param_t.b_psnr is set) */ - FPsnr [3]float64 - - /* Out: Average effective CRF of the encoded frame */ - FCrfAvg float64 -} - -type Picture struct { - /* In: force picture type (if not auto) - * If x264 encoding parameters are violated in the forcing of picture types, - * x264 will correct the input picture type and log a warning. - * Out: type of the picture encoded */ - IType int32 - /* In: force quantizer for != X264_QP_AUTO */ - IQpplus1 int32 - /* In: pic_struct, for pulldown/doubling/etc...used only if b_pic_struct=1. - * use pic_struct_e for pic_struct inputs - * Out: pic_struct element associated with frame */ - IPicStruct int32 - /* Out: whether this frame is a keyframe. Important when using modes that result in - * SEI recovery points being used instead of IDR frames. */ - BKeyframe int32 - /* In: user pts, Out: pts of encoded picture (user)*/ - IPts int64 - /* Out: frame dts. When the pts of the first frame is close to zero, - * initial frames may have a negative dts which must be dealt with by any muxer */ - IDts int64 - /* In: custom encoding parameters to be set from this frame forwards - (in coded order, not display order). If NULL, continue using - parameters from the previous frame. Some parameters, such as - aspect ratio, can only be changed per-GOP due to the limitations - of H.264 itself; in this case, the caller must force an IDR frame - if it needs the changed parameter to apply immediately. */ - Param *Param - /* In: raw image data */ - /* Out: reconstructed image data. x264 may skip part of the reconstruction process, - e.g. deblocking, in frames where it isn't necessary. To force complete - reconstruction, at a small speed cost, set b_full_recon. */ - Img Image - /* In: optional information to modify encoder decisions for this frame - * Out: information about the encoded frame */ - Prop ImageProperties - /* Out: HRD timing information. Output only when i_nal_hrd is set. */ - Hrdiming Hrd - /* In: arbitrary user SEI (e.g subtitles, AFDs) */ - ExtraSei Sei - /* private user data. copied from input to output frames. */ - Opaque unsafe.Pointer -} - -func (t *T) cptr() *C.x264_t { return (*C.x264_t)(unsafe.Pointer(t)) } - -func (n *Nal) cptr() *C.x264_nal_t { return (*C.x264_nal_t)(unsafe.Pointer(n)) } - -func (p *Param) cptr() *C.x264_param_t { return (*C.x264_param_t)(unsafe.Pointer(p)) } - -func (p *Picture) cptr() *C.x264_picture_t { return (*C.x264_picture_t)(unsafe.Pointer(p)) } - -// ParamDefault - fill Param with default values and do CPU detection. -func ParamDefault(param *Param) { C.x264_param_default(param.cptr()) } - -// ParamDefaultPreset - the same as ParamDefault, but also use the passed preset and tune to modify the default settings -// (either can be nil, which implies no preset or no tune, respectively). -// -// Currently available presets are, ordered from fastest to slowest: -// "ultrafast", "superfast", "veryfast", "faster", "fast", "medium", "slow", "slower", "veryslow", "placebo". -// -// Currently available tunings are: -// "film", "animation", "grain", "stillimage", "psnr", "ssim", "fastdecode", "zerolatency". -// -// Returns 0 on success, negative on failure (e.g. invalid preset/tune name). -func ParamDefaultPreset(param *Param, preset string, tune string) int32 { - cpreset := C.CString(preset) - defer C.free(unsafe.Pointer(cpreset)) - ctune := C.CString(tune) - defer C.free(unsafe.Pointer(ctune)) - return (int32)(C.x264_param_default_preset(param.cptr(), cpreset, ctune)) -} - -// ParamApplyProfile - applies the restrictions of the given profile. -// -// Currently available profiles are, from most to least restrictive: -// "baseline", "main", "high", "high10", "high422", "high444". -// (can be nil, in which case the function will do nothing). -// -// Returns 0 on success, negative on failure (e.g. invalid profile name). -func ParamApplyProfile(param *Param, profile string) int32 { - cprofile := C.CString(profile) - defer C.free(unsafe.Pointer(cprofile)) - return (int32)(C.x264_param_apply_profile(param.cptr(), cprofile)) -} - -// EncoderOpen - create a new encoder handler, all parameters from Param are copied. -func EncoderOpen(param *Param) *T { - ret := C.x264_encoder_open(param.cptr()) - return *(**T)(unsafe.Pointer(&ret)) -} - -// EncoderEncode - encode one picture. -// Returns the number of bytes in the returned NALs, negative on error and zero if no NAL units returned. -func EncoderEncode(enc *T, ppNal **Nal, piNal *int32, picIn *Picture, picOut *Picture) int32 { - cenc := enc.cptr() - - cppNal := C.uintptr_t(uintptr(unsafe.Pointer(ppNal))) - cpiNal := (*C.int)(unsafe.Pointer(piNal)) - - cpicIn := picIn.cptr() - cpicOut := picOut.cptr() - - return (int32)(C.x264_encode(cenc, cppNal, cpiNal, cpicIn, cpicOut)) -} - -// EncoderClose closes an encoder handler. -func EncoderClose(enc *T) { C.x264_encoder_close(enc.cptr()) } - -// EncoderIntraRefresh - If an intra refresh is not in progress, begin one with the next P-frame. -// If an intra refresh is in progress, begin one as soon as the current one finishes. -// Requires that BIntraRefresh be set. -// -// Should not be called during an x264_encoder_encode. -//func EncoderIntraRefresh(enc *T) { C.x264_encoder_intra_refresh(enc.cptr()) } diff --git a/pkg/encoder/h264/x264.go b/pkg/encoder/h264/x264.go index c55f1502e..74b805c45 100644 --- a/pkg/encoder/h264/x264.go +++ b/pkg/encoder/h264/x264.go @@ -1,18 +1,32 @@ package h264 +/* +// See: [x264](https://www.videolan.org/developers/x264.html) +#cgo !st pkg-config: x264 +#cgo st LDFLAGS: -l:libx264.a + +#include "stdint.h" +#include "x264.h" +#include +*/ +import "C" + import ( "fmt" + "runtime" "unsafe" ) type H264 struct { - ref *T + ref *C.x264_t + + nal *C.x264_nal_t // array of NALs + cNal *C.int // number of NALs + y int // Y size + uv int // U or V size + in, out *C.x264_picture_t - pnals *Nal // array of NALs - nnals int32 // number of NALs - y int32 // Y size - uv int32 // U or V size - in, out *Picture + p runtime.Pinner } type Options struct { @@ -31,10 +45,10 @@ type Options struct { } func NewEncoder(w, h int, th int, opts *Options) (encoder *H264, err error) { - libVersion := LibVersion() + ver := Version() - if libVersion < 150 { - return nil, fmt.Errorf("x264: the library version should be newer than v150, you have got version %v", libVersion) + if ver < 150 { + return nil, fmt.Errorf("x264: the library version should be newer than v150, you have got version %v", ver) } if opts == nil { @@ -46,90 +60,107 @@ func NewEncoder(w, h int, th int, opts *Options) (encoder *H264, err error) { } } - param := Param{} + param := C.x264_param_t{} + if opts.Preset != "" && opts.Tune != "" { - if ParamDefaultPreset(¶m, opts.Preset, opts.Tune) < 0 { + preset := C.CString(opts.Preset) + tune := C.CString(opts.Tune) + defer C.free(unsafe.Pointer(preset)) + defer C.free(unsafe.Pointer(tune)) + if C.x264_param_default_preset(¶m, preset, tune) < 0 { return nil, fmt.Errorf("x264: invalid preset/tune name") } } else { - ParamDefault(¶m) + C.x264_param_default(¶m) } if opts.Profile != "" { - if ParamApplyProfile(¶m, opts.Profile) < 0 { + profile := C.CString(opts.Profile) + defer C.free(unsafe.Pointer(profile)) + if C.x264_param_apply_profile(¶m, profile) < 0 { return nil, fmt.Errorf("x264: invalid profile name") } } - ww, hh := int32(w), int32(h) - - param.IBitdepth = 8 - if libVersion > 155 { - param.ICsp = CspI420 + param.i_bitdepth = 8 + if ver > 155 { + param.i_csp = C.X264_CSP_I420 } else { - param.ICsp = 1 + param.i_csp = 1 } - param.IWidth = ww - param.IHeight = hh - param.ILogLevel = opts.LogLevel - param.ISyncLookahead = 0 - param.IThreads = int32(th) + param.i_width = C.int(w) + param.i_height = C.int(h) + param.i_log_level = C.int(opts.LogLevel) + param.i_sync_lookahead = 0 + param.i_threads = C.int(th) if th != 1 { - param.BSlicedThreads = 1 + param.b_sliced_threads = 1 } - param.Rc.IRcMethod = RcCrf - param.Rc.FRfConstant = float32(opts.Crf) + param.rc.i_rc_method = C.X264_RC_CRF + param.rc.f_rf_constant = C.float(opts.Crf) encoder = &H264{ - y: ww * hh, - uv: ww * hh / 4, - pnals: new(Nal), - out: new(Picture), - in: &Picture{ - Img: Image{ICsp: param.ICsp, IPlane: 3, IStride: [4]int32{0: ww, 1: ww >> 1, 2: ww >> 1}}, + y: w * h, + uv: w * h / 4, + cNal: new(C.int), + nal: new(C.x264_nal_t), + out: new(C.x264_picture_t), + in: &C.x264_picture_t{ + img: C.x264_image_t{ + i_csp: param.i_csp, + i_plane: 3, + i_stride: [4]C.int{0: C.int(w), 1: C.int(w >> 1), 2: C.int(w >> 1)}, + }, }, + ref: C.x264_encoder_open(¶m), } - if encoder.ref = EncoderOpen(¶m); encoder.ref == nil { + if encoder.ref == nil { err = fmt.Errorf("x264: cannot open the encoder") } return } -func LibVersion() int { return int(Build) } - func (e *H264) LoadBuf(yuv []byte) { - e.in.Img.Plane[0] = uintptr(unsafe.Pointer(&yuv[0])) - e.in.Img.Plane[1] = uintptr(unsafe.Pointer(&yuv[e.y])) - e.in.Img.Plane[2] = uintptr(unsafe.Pointer(&yuv[e.y+e.uv])) + e.in.img.plane[0] = (*C.uchar)(unsafe.Pointer(&yuv[0])) + e.in.img.plane[1] = (*C.uchar)(unsafe.Pointer(&yuv[e.y])) + e.in.img.plane[2] = (*C.uchar)(unsafe.Pointer(&yuv[e.y+e.uv])) } -func (e *H264) Encode() (b []byte) { - e.in.IPts += 1 - bytes := EncoderEncode(e.ref, &e.pnals, &e.nnals, e.in, e.out) - if bytes > 0 { - // we merge multiple NALs stored in **pnals into a single byte stream - // ret contains the total size of NALs in bytes, i.e. each e.pnals[...].PPayload * IPayload - b = unsafe.Slice((*byte)(e.pnals.PPayload), bytes) - } - return +func (e *H264) Encode() []byte { + e.in.i_pts += 1 + + e.p.Pin(e.in.img.plane[0]) + e.p.Pin(e.in.img.plane[1]) + e.p.Pin(e.in.img.plane[2]) + + e.p.Pin(e.nal) + bytes := C.x264_encoder_encode(e.ref, &e.nal, e.cNal, e.in, e.out) + e.p.Unpin() + + // we merge multiple NALs stored in **nal into a single byte stream + // ret contains the total size of NALs in bytes, i.e. each e.nal[...].p_payload * i_payload + return unsafe.Slice((*byte)(e.nal.p_payload), bytes) } func (e *H264) IntraRefresh() { // !to implement } -func (e *H264) Info() string { return fmt.Sprintf("x264: v%v", LibVersion()) } +func (e *H264) Info() string { return fmt.Sprintf("x264: v%v", Version()) } func (e *H264) SetFlip(b bool) { if b { - e.in.Img.ICsp |= CspVflip + e.in.img.i_csp |= C.X264_CSP_VFLIP } else { - e.in.Img.ICsp &= ^CspVflip + e.in.img.i_csp &= ^C.X264_CSP_VFLIP } } func (e *H264) Shutdown() error { - EncoderClose(e.ref) + C.x264_encoder_close(e.ref) + e.p.Unpin() return nil } + +func Version() int { return int(C.X264_BUILD) }