Skip to content

Commit 2cd6991

Browse files
committed
feat(uuid): add libavutil UUID support
Implements wrapper functions for the libavutil/uuid.h functionality: - Adds AVUUID type and constants - Implements manual wrappers for uuid functions in custom.go - Updates generator to skip uuid functions (handled manually) - Adds comprehensive test cases for UUID operations These additions allow working with UUIDs according to IETF RFC 4122 specification, including parsing, comparison, and string serialization operations.
1 parent 31dc90b commit 2cd6991

9 files changed

Lines changed: 242 additions & 1 deletion

File tree

bindings_test.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,3 +268,87 @@ func TestGeneratorErrorHandling(t *testing.T) {
268268
t.Logf("Error handling test passed: AVERROR_EOF = %d", AVErrorEofConst)
269269
})
270270
}
271+
272+
// TestUUID tests the UUID functionality from libavutil/uuid.h
273+
func TestUUID(t *testing.T) {
274+
t.Run("Parse and Unparse", func(t *testing.T) {
275+
// Parse a UUID string
276+
uuidStr := "550e8400-e29b-41d4-a716-446655440000"
277+
var uuid AVUUID
278+
279+
cStr := ToCStr(uuidStr)
280+
defer cStr.Free()
281+
282+
ret, err := AVUuidParse(cStr, &uuid)
283+
if ret != 0 || err != nil {
284+
t.Fatalf("Failed to parse UUID: %v", err)
285+
}
286+
287+
// Unparse it back to string
288+
outStr := AllocCStr(37)
289+
defer outStr.Free()
290+
AVUuidUnparse(&uuid, outStr)
291+
292+
result := outStr.String()
293+
if result != uuidStr {
294+
t.Fatalf("UUID mismatch: expected %s, got %s", uuidStr, result)
295+
}
296+
297+
t.Logf("UUID parse/unparse test passed: %s", result)
298+
})
299+
300+
t.Run("UUID Operations", func(t *testing.T) {
301+
// Create two identical UUIDs
302+
var uuid1, uuid2 AVUUID
303+
uuidStr := "550e8400-e29b-41d4-a716-446655440000"
304+
cStr := ToCStr(uuidStr)
305+
defer cStr.Free()
306+
307+
AVUuidParse(cStr, &uuid1)
308+
AVUuidCopy(&uuid2, &uuid1)
309+
310+
// Test equality
311+
equal, _ := AVUuidEqual(&uuid1, &uuid2)
312+
if equal == 0 {
313+
t.Fatal("UUIDs should be equal")
314+
}
315+
316+
// Test nil UUID
317+
var nilUuid AVUUID
318+
AVUuidNil(&nilUuid)
319+
320+
equal, _ = AVUuidEqual(&uuid1, &nilUuid)
321+
if equal != 0 {
322+
t.Fatal("UUID should not equal nil UUID")
323+
}
324+
325+
t.Logf("UUID operations test passed")
326+
})
327+
328+
t.Run("URN Parsing", func(t *testing.T) {
329+
// Parse a UUID URN
330+
urnStr := "urn:uuid:550e8400-e29b-41d4-a716-446655440000"
331+
var uuid AVUUID
332+
333+
cStr := ToCStr(urnStr)
334+
defer cStr.Free()
335+
336+
ret, err := AVUuidUrnParse(cStr, &uuid)
337+
if ret != 0 || err != nil {
338+
t.Fatalf("Failed to parse UUID URN: %v", err)
339+
}
340+
341+
// Verify by unparsing
342+
outStr := AllocCStr(37)
343+
defer outStr.Free()
344+
AVUuidUnparse(&uuid, outStr)
345+
346+
result := outStr.String()
347+
expected := "550e8400-e29b-41d4-a716-446655440000"
348+
if result != expected {
349+
t.Fatalf("UUID mismatch: expected %s, got %s", expected, result)
350+
}
351+
352+
t.Logf("UUID URN parse test passed: %s", result)
353+
})
354+
}

callbacks.gen.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ import "unsafe"
9696
// #include <libavutil/tree.h>
9797
// #include <libavutil/twofish.h>
9898
// #include <libavutil/tx.h>
99+
// #include <libavutil/uuid.h>
99100
// #include <libavutil/version.h>
100101
// #include <libavutil/video_enc_params.h>
101102
// #include <libavutil/video_hint.h>

constants.gen.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ package ffmpeg
9494
// #include <libavutil/tree.h>
9595
// #include <libavutil/twofish.h>
9696
// #include <libavutil/tx.h>
97+
// #include <libavutil/uuid.h>
9798
// #include <libavutil/version.h>
9899
// #include <libavutil/video_enc_params.h>
99100
// #include <libavutil/video_hint.h>
@@ -2653,6 +2654,15 @@ const AVTimecodeStrSize = C.AV_TIMECODE_STR_SIZE
26532654
// AVTsMaxStringSize wraps AV_TS_MAX_STRING_SIZE.
26542655
const AVTsMaxStringSize = C.AV_TS_MAX_STRING_SIZE
26552656

2657+
// AVPriUuid wraps AV_PRI_UUID.
2658+
const AVPriUuid = C.AV_PRI_UUID
2659+
2660+
// AVPriUrnUuid wraps AV_PRI_URN_UUID.
2661+
const AVPriUrnUuid = C.AV_PRI_URN_UUID
2662+
2663+
// AVUuidLen wraps AV_UUID_LEN.
2664+
const AVUuidLen = C.AV_UUID_LEN
2665+
26562666
// LIBAVUtilVersionMajor wraps LIBAVUTIL_VERSION_MAJOR.
26572667
const LIBAVUtilVersionMajor = C.LIBAVUTIL_VERSION_MAJOR
26582668

custom.go

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package ffmpeg
66
#include <libavcodec/avcodec.h>
77
#include <libavcodec/bsf.h>
88
#include <libavfilter/avfilter.h>
9+
#include <libavutil/uuid.h>
910
1011
// Forward declarations for iteration functions
1112
extern const AVCodec *av_codec_iterate(void **opaque);
@@ -187,3 +188,107 @@ type AVAdler = uint32
187188
// AVCRC is a typedef alias for uint32_t in FFmpeg.
188189
// This represents a CRC (Cyclic Redundancy Check) value.
189190
type AVCRC = uint32
191+
192+
// AVUUID is a typedef to a 16-byte array in FFmpeg (uint8_t[16]).
193+
// This represents a UUID as an opaque sequence of 16 unsigned bytes.
194+
// Binary representation of a UUID per IETF RFC 4122.
195+
type AVUUID = [16]uint8
196+
197+
// --- Manual UUID function wrappers (arrays need pointer conversion in CGO) ---
198+
199+
// AVUuidParse parses a string representation of a UUID formatted according to IETF RFC 4122
200+
// into an AVUUID. The parsing is case-insensitive. The string must be 37
201+
// characters long, including the terminating NUL character.
202+
//
203+
// Example string representation: "2fceebd0-7017-433d-bafb-d073a7116696"
204+
//
205+
// @param[in] in String representation of a UUID
206+
// @param[out] uu AVUUID
207+
// @return A non-zero value in case of an error.
208+
func AVUuidParse(in *CStr, uu *AVUUID) (int, error) {
209+
var tmpin *C.char
210+
if in != nil {
211+
tmpin = in.ptr
212+
}
213+
ret := C.av_uuid_parse(tmpin, (*C.uint8_t)(unsafe.Pointer(&uu[0])))
214+
return int(ret), WrapErr(int(ret))
215+
}
216+
217+
// AVUuidUrnParse parses a URN representation of a UUID, as specified at IETF RFC 4122,
218+
// into an AVUUID. The parsing is case-insensitive. The string must be 46
219+
// characters long, including the terminating NUL character.
220+
//
221+
// Example string representation: "urn:uuid:2fceebd0-7017-433d-bafb-d073a7116696"
222+
//
223+
// @param[in] in URN UUID
224+
// @param[out] uu AVUUID
225+
// @return A non-zero value in case of an error.
226+
func AVUuidUrnParse(in *CStr, uu *AVUUID) (int, error) {
227+
var tmpin *C.char
228+
if in != nil {
229+
tmpin = in.ptr
230+
}
231+
ret := C.av_uuid_urn_parse(tmpin, (*C.uint8_t)(unsafe.Pointer(&uu[0])))
232+
return int(ret), WrapErr(int(ret))
233+
}
234+
235+
// AVUuidParseRange parses a string representation of a UUID formatted according to IETF RFC 4122
236+
// into an AVUUID. The parsing is case-insensitive.
237+
//
238+
// @param[in] inStart Pointer to the first character of the string representation
239+
// @param[in] inEnd Pointer to the character after the last character of the
240+
// string representation. That memory location is never
241+
// accessed. It is an error if `inEnd - inStart != 36`.
242+
// @param[out] uu AVUUID
243+
// @return A non-zero value in case of an error.
244+
func AVUuidParseRange(inStart *CStr, inEnd *CStr, uu *AVUUID) (int, error) {
245+
var tmpinStart *C.char
246+
if inStart != nil {
247+
tmpinStart = inStart.ptr
248+
}
249+
var tmpinEnd *C.char
250+
if inEnd != nil {
251+
tmpinEnd = inEnd.ptr
252+
}
253+
ret := C.av_uuid_parse_range(tmpinStart, tmpinEnd, (*C.uint8_t)(unsafe.Pointer(&uu[0])))
254+
return int(ret), WrapErr(int(ret))
255+
}
256+
257+
// AVUuidUnparse serializes a AVUUID into a string representation according to IETF RFC 4122.
258+
// The string is lowercase and always 37 characters long, including the terminating NUL character.
259+
//
260+
// @param[in] uu AVUUID
261+
// @param[out] out Pointer to an array of no less than 37 characters.
262+
func AVUuidUnparse(uu *AVUUID, out *CStr) {
263+
var tmpout *C.char
264+
if out != nil {
265+
tmpout = out.ptr
266+
}
267+
C.av_uuid_unparse((*C.uint8_t)(unsafe.Pointer(&uu[0])), tmpout)
268+
}
269+
270+
// AVUuidEqual compares two UUIDs for equality.
271+
//
272+
// @param[in] uu1 AVUUID
273+
// @param[in] uu2 AVUUID
274+
// @return Nonzero if uu1 and uu2 are equal, 0 otherwise.
275+
func AVUuidEqual(uu1 *AVUUID, uu2 *AVUUID) (int, error) {
276+
ret := C.av_uuid_equal((*C.uint8_t)(unsafe.Pointer(&uu1[0])), (*C.uint8_t)(unsafe.Pointer(&uu2[0])))
277+
return int(ret), WrapErr(int(ret))
278+
}
279+
280+
// AVUuidCopy copies the bytes of src into dest.
281+
//
282+
// @param[out] dest AVUUID
283+
// @param[in] src AVUUID
284+
func AVUuidCopy(dest *AVUUID, src *AVUUID) {
285+
C.av_uuid_copy((*C.uint8_t)(unsafe.Pointer(&dest[0])), (*C.uint8_t)(unsafe.Pointer(&src[0])))
286+
}
287+
288+
// AVUuidNil sets a UUID to the nil UUID, i.e. a UUID with have all
289+
// its 128 bits set to zero.
290+
//
291+
// @param[out] uu AVUUID
292+
func AVUuidNil(uu *AVUUID) {
293+
C.av_uuid_nil((*C.uint8_t)(unsafe.Pointer(&uu[0])))
294+
}

enums.gen.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ import "unsafe"
9696
// #include <libavutil/tree.h>
9797
// #include <libavutil/twofish.h>
9898
// #include <libavutil/tx.h>
99+
// #include <libavutil/uuid.h>
99100
// #include <libavutil/version.h>
100101
// #include <libavutil/video_enc_params.h>
101102
// #include <libavutil/video_hint.h>

functions.gen.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ import "unsafe"
9696
// #include <libavutil/tree.h>
9797
// #include <libavutil/twofish.h>
9898
// #include <libavutil/tx.h>
99+
// #include <libavutil/uuid.h>
99100
// #include <libavutil/version.h>
100101
// #include <libavutil/video_enc_params.h>
101102
// #include <libavutil/video_hint.h>
@@ -16081,6 +16082,34 @@ func AVTxUninit(ctx **AVTXContext) {
1608116082
}
1608216083
}
1608316084

16085+
// --- Function av_uuid_parse ---
16086+
16087+
// av_uuid_parse skipped due to array typedef (manually wrapped in custom.go)
16088+
16089+
// --- Function av_uuid_urn_parse ---
16090+
16091+
// av_uuid_urn_parse skipped due to array typedef (manually wrapped in custom.go)
16092+
16093+
// --- Function av_uuid_parse_range ---
16094+
16095+
// av_uuid_parse_range skipped due to array typedef (manually wrapped in custom.go)
16096+
16097+
// --- Function av_uuid_unparse ---
16098+
16099+
// av_uuid_unparse skipped due to array typedef (manually wrapped in custom.go)
16100+
16101+
// --- Function av_uuid_equal ---
16102+
16103+
// av_uuid_equal skipped due to array typedef (manually wrapped in custom.go)
16104+
16105+
// --- Function av_uuid_copy ---
16106+
16107+
// av_uuid_copy skipped due to array typedef (manually wrapped in custom.go)
16108+
16109+
// --- Function av_uuid_nil ---
16110+
16111+
// av_uuid_nil skipped due to array typedef (manually wrapped in custom.go)
16112+
1608416113
// --- Function av_video_enc_params_block ---
1608516114

1608616115
// AVVideoEncParamsBlock wraps av_video_enc_params_block.

internal/generator/generator.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,16 @@ outer:
799799
continue outer
800800
}
801801

802+
// WORKAROUND: UUID functions use AVUUID (array typedef) which requires pointer conversion in CGO
803+
// These are manually wrapped in custom.go with proper pointer handling
804+
if fn.Name == "av_uuid_parse" || fn.Name == "av_uuid_urn_parse" || fn.Name == "av_uuid_parse_range" ||
805+
fn.Name == "av_uuid_unparse" || fn.Name == "av_uuid_equal" || fn.Name == "av_uuid_copy" || fn.Name == "av_uuid_nil" {
806+
o.Commentf("%v skipped due to array typedef (manually wrapped in custom.go)", fn.Name)
807+
o.Line()
808+
809+
continue outer
810+
}
811+
802812
if typeEquals(fn.Result, fileType) || typeEquals(fn.Result, fileType2) {
803813
o.Commentf("%v skipped due to return", fn.Name)
804814
o.Line()

internal/generator/parser.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ var files = []string{
124124
"libavutil/tree.h",
125125
"libavutil/twofish.h",
126126
"libavutil/tx.h",
127-
////"libavutil/uuid.h", //Unknown typedef kind NoDeclFound
127+
"libavutil/uuid.h",
128128
"libavutil/version.h",
129129
"libavutil/video_enc_params.h",
130130
"libavutil/video_hint.h",

structs.gen.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ import "unsafe"
9696
// #include <libavutil/tree.h>
9797
// #include <libavutil/twofish.h>
9898
// #include <libavutil/tx.h>
99+
// #include <libavutil/uuid.h>
99100
// #include <libavutil/version.h>
100101
// #include <libavutil/video_enc_params.h>
101102
// #include <libavutil/video_hint.h>

0 commit comments

Comments
 (0)