gstreamer/gstreamer-sharp/Caps.custom
Maarten Bosmans 9713ead713 Don't modify hash tables while iterating over them
This caused crashes for caps with more than a single struct
when unreffing them in one way or another.

Fixes bug #627677.
2010-08-23 10:54:41 +02:00

250 lines
5.5 KiB
Text

public static Gst.Caps NewEmpty () {
return new Gst.Caps ();
}
public Caps (Structure s) : this () {
Append (s);
}
public Caps (Structure[] s) : this () {
foreach (Structure o in s)
Append (o);
}
public Caps (string mediaType, params object[] fields) : this () {
Append (new Structure (mediaType, fields));
}
[DllImport ("gstreamersharpglue-0.10.dll") ]
extern static uint gstsharp_gst_caps_get_refcount_offset ();
static uint refcount_offset = gstsharp_gst_caps_get_refcount_offset ();
private int Refcount {
get {
unsafe {
int* raw_ptr = (int*) ( ( (byte*) Handle) + refcount_offset);
return (*raw_ptr);
}
}
}
public bool IsWritable {
get {
return (Refcount == 1);
}
}
/* FIXME: This is not optimal! */
public void MakeWritable() {
if (IsWritable)
return;
RemoveStructureReferences ();
IntPtr copy = gst_caps_copy (Raw);
Raw = copy;
/* ^--- Takes a second ref, not good */
Unref (Raw);
/* ^--- Sets Owned = false, wrong! */
Owned = true;
}
private Hashtable structures = new Hashtable ();
private void RemoveStructureReference (Structure s) {
structures.Remove (s.Handle);
s.CreateNativeCopy ();
}
private void RemoveStructureReferences () {
foreach (Structure s in structures.Values) {
s.CreateNativeCopy ();
}
structures.Clear ();
}
[DllImport ("libgstreamer-0.10.dll") ]
private static extern IntPtr gst_caps_get_structure (IntPtr handle, uint index);
public Structure this [uint index] {
get {
if (index >= Size)
throw new ArgumentOutOfRangeException ();
IntPtr raw_ptr = gst_caps_get_structure (Handle, (uint) index);
if (structures.Contains (raw_ptr)) {
Structure ret = (Gst.Structure) structures[raw_ptr];
return ret;
} else {
Structure ret = new Gst.Structure (raw_ptr);
ret.FreeNative = false;
structures.Add (raw_ptr, ret);
return ret;
}
}
}
private class StructureEnumerator : IEnumerator {
Gst.Caps caps;
long index;
public StructureEnumerator (Gst.Caps caps) {
this.caps = caps;
index = -1;
}
public object Current {
get {
if (index >= caps.Size)
throw new ArgumentOutOfRangeException ();
if (index == -1)
throw new ArgumentException ();
return caps[ (uint) index];
}
}
public bool MoveNext () {
index += 1;
return (index < caps.Size);
}
public void Reset () {
index = -1;
}
}
public IEnumerator GetEnumerator() {
return new StructureEnumerator (this);
}
[DllImport ("libgstreamer-0.10.dll") ]
static extern void gst_caps_append_structure (IntPtr caps, IntPtr structure);
[DllImport ("libgstreamer-0.10.dll") ]
static extern IntPtr gst_structure_copy (IntPtr raw);
public void Append (Structure s) {
if (!IsWritable)
throw new ApplicationException ();
gst_caps_append_structure (Handle, gst_structure_copy (s.Handle));
}
[DllImport ("libgstreamer-0.10.dll") ]
static extern void gst_caps_append (IntPtr caps, IntPtr caps2);
public void Append (Caps caps) {
if (!IsWritable)
throw new ApplicationException ();
gst_caps_append (Handle, gst_caps_copy (caps.Handle));
}
[DllImport ("libgstreamer-0.10.dll") ]
static extern void gst_caps_merge_structure (IntPtr caps, IntPtr structure);
public void Merge (Structure s) {
if (!IsWritable)
throw new ApplicationException ();
gst_caps_merge_structure (Handle, gst_structure_copy (s.Handle));
}
[DllImport ("libgstreamer-0.10.dll") ]
static extern void gst_caps_merge (IntPtr caps, IntPtr caps2);
public void Merge (Caps caps) {
if (!IsWritable)
throw new ApplicationException ();
/* Removes all structures! */
if (caps.IsAny) {
RemoveStructureReferences ();
}
gst_caps_merge (Handle, gst_caps_copy (caps.Handle));
}
[DllImport ("libgstreamer-0.10.dll") ]
static extern void gst_caps_remove_structure (IntPtr caps, uint index);
public void RemoveStructure (uint index) {
if (!IsWritable)
throw new ApplicationException ();
if (index >= Size)
throw new ArgumentOutOfRangeException ();
if (structures.Contains (this[index].Handle)) {
RemoveStructureReference (this[index]);
}
gst_caps_remove_structure (Handle, index);
}
[DllImport ("libgstreamer-0.10.dll") ]
static extern bool gst_caps_do_simplify (IntPtr caps);
public bool DoSimplify () {
if (!IsWritable)
throw new ApplicationException ();
/* FIXME: This is not optimal but we don't know before
* which structures will be removed */
RemoveStructureReferences ();
return gst_caps_do_simplify (Handle);
}
[DllImport ("libgstreamer-0.10.dll") ]
static extern void gst_caps_truncate (IntPtr caps);
public void Truncate () {
if (!IsWritable)
throw new ApplicationException ();
for (uint i = 1; i < Size; i++)
RemoveStructureReference (this[i]);
gst_caps_truncate (Handle);
}
[DllImport ("libgstreamer-0.10.dll") ]
static extern void gst_caps_unref (IntPtr raw);
protected override void Unref (IntPtr raw) {
RemoveStructureReferences ();
if (Owned) {
gst_caps_unref (raw);
Owned = false;
}
}
class FinalizerInfo {
IntPtr handle;
public FinalizerInfo (IntPtr handle) {
this.handle = handle;
}
public bool Handler () {
gst_caps_unref (handle);
return false;
}
}
~Caps () {
if (!Owned)
return;
RemoveStructureReferences ();
FinalizerInfo info = new FinalizerInfo (Handle);
Gst.GLib.Timeout.Add (50, new Gst.GLib.TimeoutHandler (info.Handler));
}
protected override Gst.GLib.Opaque Copy (IntPtr raw) {
return Gst.GLib.Opaque.GetOpaque (gst_caps_ref (raw), typeof (Caps), true);
}