applemedia: move plugins using private frameworks to applemedia-nonpublic
authorAndoni Morales Alastruey <ylatuya@gmail.com>
Wed, 24 Apr 2013 16:53:11 +0000 (18:53 +0200)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Mon, 20 May 2013 11:31:02 +0000 (13:31 +0200)
45 files changed:
configure.ac
sys/Makefile.am
sys/applemedia-nonpublic/Makefile.am [new file with mode: 0644]
sys/applemedia-nonpublic/bufferfactory.h [new file with mode: 0644]
sys/applemedia-nonpublic/bufferfactory.m [new file with mode: 0644]
sys/applemedia-nonpublic/celapi.c [new file with mode: 0644]
sys/applemedia-nonpublic/celapi.h [new file with mode: 0644]
sys/applemedia-nonpublic/celvideosrc.c [new file with mode: 0644]
sys/applemedia-nonpublic/celvideosrc.h [new file with mode: 0644]
sys/applemedia-nonpublic/cmapi.c [new file with mode: 0644]
sys/applemedia-nonpublic/cmapi.h [new file with mode: 0644]
sys/applemedia-nonpublic/coremediabuffer.c [new file with mode: 0644]
sys/applemedia-nonpublic/coremediabuffer.h [new file with mode: 0644]
sys/applemedia-nonpublic/coremediactx.c [new file with mode: 0644]
sys/applemedia-nonpublic/coremediactx.h [new file with mode: 0644]
sys/applemedia-nonpublic/corevideobuffer.c [new file with mode: 0644]
sys/applemedia-nonpublic/corevideobuffer.h [new file with mode: 0644]
sys/applemedia-nonpublic/cvapi.c [new file with mode: 0644]
sys/applemedia-nonpublic/cvapi.h [new file with mode: 0644]
sys/applemedia-nonpublic/dynapi-internal.h [new file with mode: 0644]
sys/applemedia-nonpublic/dynapi.c [new file with mode: 0644]
sys/applemedia-nonpublic/dynapi.h [new file with mode: 0644]
sys/applemedia-nonpublic/mioapi.c [new file with mode: 0644]
sys/applemedia-nonpublic/mioapi.h [new file with mode: 0644]
sys/applemedia-nonpublic/miovideodevice.c [new file with mode: 0644]
sys/applemedia-nonpublic/miovideodevice.h [new file with mode: 0644]
sys/applemedia-nonpublic/miovideosrc.c [new file with mode: 0644]
sys/applemedia-nonpublic/miovideosrc.h [new file with mode: 0644]
sys/applemedia-nonpublic/mtapi.c [new file with mode: 0644]
sys/applemedia-nonpublic/mtapi.h [new file with mode: 0644]
sys/applemedia-nonpublic/plugin.m [new file with mode: 0644]
sys/applemedia/Makefile.am
sys/applemedia/celapi.c [deleted file]
sys/applemedia/celapi.h [deleted file]
sys/applemedia/celvideosrc.c [deleted file]
sys/applemedia/celvideosrc.h [deleted file]
sys/applemedia/coremediactx.c
sys/applemedia/coremediactx.h
sys/applemedia/mioapi.c [deleted file]
sys/applemedia/mioapi.h [deleted file]
sys/applemedia/miovideodevice.c [deleted file]
sys/applemedia/miovideodevice.h [deleted file]
sys/applemedia/miovideosrc.c [deleted file]
sys/applemedia/miovideosrc.h [deleted file]
sys/applemedia/plugin.m

index eac05f43161a3383df3d54b2221e6590333a1a51..85870a8edaadef314666bdc2fefc1d21b69a59cd 100644 (file)
@@ -2416,6 +2416,7 @@ sys/acmenc/Makefile
 sys/acmmp3dec/Makefile
 sys/androidmedia/Makefile
 sys/applemedia/Makefile
+sys/applemedia-nonpublic/Makefile
 sys/avc/Makefile
 sys/bluez/Makefile
 sys/d3dvideosink/Makefile
index 99c3801e9a41a7e02ba5ace8d6b87952f6c43b8f..d7f482ce945ea1e150d9c52098e55cfab87b3ba5 100644 (file)
@@ -11,7 +11,7 @@ ANDROID_MEDIA_DIR=
 endif
 
 if USE_APPLE_MEDIA
-APPLE_MEDIA_DIR=applemedia
+APPLE_MEDIA_DIR=applemedia applemedia-nonpublic
 else
 APPLE_MEDIA_DIR=
 endif
diff --git a/sys/applemedia-nonpublic/Makefile.am b/sys/applemedia-nonpublic/Makefile.am
new file mode 100644 (file)
index 0000000..27283db
--- /dev/null
@@ -0,0 +1,84 @@
+plugin_LTLIBRARIES = libgstapplemedia_nonpublic.la
+
+libgstapplemedia_nonpublic_la_SOURCES =                        \
+       plugin.m                                \
+       bufferfactory.m                         \
+       corevideobuffer.c                       \
+       coremediabuffer.c                       \
+       cvapi.c                                 \
+       cmapi.c                                 \
+       coremediactx.c                          \
+       dynapi.c
+
+libgstapplemedia_nonpublic_la_CPPFLAGS =                       \
+       -Dgst_dyn_api_get_type=gst_dyn_api_priv_get_type                        \
+       -Dgst_dyn_api_debug=gst_dyn_api_priv_debug                              \
+       -Dgst_dyn_api_new=gst_dyn_api_priv_new                                  \
+       -Dgst_core_media_buffer_new=gst_core_media_buffer_priv_new              \
+       -Dgst_core_media_buffer_get_type=gst_core_media_buffer_priv_get_type    \
+       -Dgst_core_media_buffer_get_pixel_buffer=gst_core_media_buffer_priv_get_pixel_buffer\
+       -Dgst_core_video_buffer_new=gst_core_video_buffer_priv_new              \
+       -Dgst_core_video_buffer_get_type=gst_core_video_buffer_priv_get_type    \
+       -Dgst_core_media_ctx_new=gst_core_media_ctx_priv_new                    \
+       -Dgst_core_media_ctx_get_type=gst_core_media_ctx_priv_get_type
+
+libgstapplemedia_nonpublic_la_CFLAGS =                 \
+       $(GST_CFLAGS)                                                           \
+       $(GST_BASE_CFLAGS)                                                      \
+       $(GST_PLUGINS_BASE_CFLAGS)
+
+
+libgstapplemedia_nonpublic_la_OBJCFLAGS =                      \
+       $(GST_OBJCFLAGS)                        \
+       $(GST_BASE_CFLAGS)                      \
+       $(GST_PLUGINS_BASE_CFLAGS)
+
+if HAVE_IOS
+libgstapplemedia_nonpublic_la_OBJCFLAGS += -fobjc-abi-version=2 -fobjc-legacy-dispatch
+endif
+
+libgstapplemedia_nonpublic_la_LIBADD =                 \
+       $(GST_BASE_LIBS)                        \
+       $(GST_PLUGINS_BASE_LIBS)                \
+       -lgstvideo-$(GST_API_VERSION)
+
+libgstapplemedia_nonpublic_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
+
+libgstapplemedia_nonpublic_la_LDFLAGS =                        \
+       $(GST_PLUGIN_LDFLAGS)                   \
+       $(GST_BASE_LDFLAGS)                     \
+       $(GST_PLUGINS_BASE_LDFLAGS)             \
+       -Wl,-framework -Wl,Foundation           \
+       -Wl,-framework -Wl,CoreFoundation       \
+       -Wl,-framework -Wl,CoreVideo
+
+noinst_HEADERS =                               \
+       miovideosrc.h                           \
+       miovideodevice.h                        \
+       celvideosrc.h                           \
+       bufferfactory.h                         \
+       corevideobuffer.h                       \
+       coremediabuffer.h                       \
+       coremediactx.h                          \
+       mioapi.h                                \
+       mtapi.h                                 \
+       celapi.h                                \
+       cvapi.h                                 \
+       cmapi.h                                 \
+       dynapi.h                                \
+       dynapi-internal.h
+
+if HAVE_IOS
+
+libgstapplemedia_nonpublic_la_SOURCES +=                       \
+       celvideosrc.c                           \
+       mtapi.c                                 \
+       celapi.c
+
+else
+
+libgstapplemedia_nonpublic_la_SOURCES +=                       \
+       mioapi.c
+
+endif
+
diff --git a/sys/applemedia-nonpublic/bufferfactory.h b/sys/applemedia-nonpublic/bufferfactory.h
new file mode 100644 (file)
index 0000000..132b953
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#import <Foundation/Foundation.h>
+
+#include <gst/gst.h>
+
+@interface GstAMBufferFactory : NSObject {
+  gpointer coreMediaCtx;
+}
+
+- (id)initWithError:(GError **)error;
+- (void)finalize;
+
+- (GstBuffer *)createGstBufferForCoreVideoBuffer:(CFTypeRef)cvbuf;
+- (GstBuffer *)createGstBufferForSampleBuffer:(CFTypeRef)sbuf;
+
+@end
diff --git a/sys/applemedia-nonpublic/bufferfactory.m b/sys/applemedia-nonpublic/bufferfactory.m
new file mode 100644 (file)
index 0000000..7b2e845
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#import "bufferfactory.h"
+
+#include "coremediabuffer.h"
+#include "corevideobuffer.h"
+
+@implementation GstAMBufferFactory
+
+- (id)initWithError:(GError **)error
+{
+  GstCoreMediaCtx *ctx;
+
+  ctx =
+      gst_core_media_ctx_new (GST_API_CORE_VIDEO | GST_API_CORE_MEDIA, error);
+  if (ctx == NULL)
+    return nil;
+
+  if ((self = [super init]))
+    coreMediaCtx = ctx;
+  else
+    g_object_unref (ctx);
+
+  return self;
+}
+
+- (void)finalize
+{
+  g_object_unref (coreMediaCtx);
+
+  [super finalize];
+}
+
+- (GstBuffer *)createGstBufferForCoreVideoBuffer:(CFTypeRef)cvbuf
+{
+  return gst_core_video_buffer_new (coreMediaCtx, (CVBufferRef) cvbuf, NULL);
+}
+
+- (GstBuffer *)createGstBufferForSampleBuffer:(CFTypeRef)sbuf
+{
+  return gst_core_media_buffer_new (coreMediaCtx, sbuf);
+}
+
+@end
diff --git a/sys/applemedia-nonpublic/celapi.c b/sys/applemedia-nonpublic/celapi.c
new file mode 100644 (file)
index 0000000..9c4727e
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "celapi.h"
+
+#include "dynapi-internal.h"
+
+#define CELESTIAL_FRAMEWORK_PATH "/System/Library/PrivateFrameworks/" \
+    "Celestial.framework/Celestial"
+
+G_DEFINE_TYPE (GstCelApi, gst_cel_api, GST_TYPE_DYN_API);
+
+static void
+gst_cel_api_init (GstCelApi * self)
+{
+}
+
+static void
+gst_cel_api_class_init (GstCelApiClass * klass)
+{
+}
+
+#define SYM_SPEC(name) GST_DYN_SYM_SPEC (GstCelApi, name)
+
+GstCelApi *
+gst_cel_api_obtain (GError ** error)
+{
+  static const GstDynSymSpec symbols[] = {
+    SYM_SPEC (FigCreateCaptureDevicesAndStreamsForPreset),
+
+    SYM_SPEC (kFigCaptureDeviceProperty_MultiplexStreams),
+    SYM_SPEC (kFigCapturePortType_Bottom),
+    SYM_SPEC (kFigCapturePortType_Camera),
+    SYM_SPEC (kFigCapturePortType_FrontFacingCamera),
+    SYM_SPEC (kFigCapturePortType_Top),
+    SYM_SPEC (kFigCapturePropertyValue_AFEarlyOutAllowPeakAtStart),
+    SYM_SPEC (kFigCapturePropertyValue_AFEarlyOutDecrementAmount),
+    SYM_SPEC (kFigCapturePropertyValue_AFEarlyOutEnable),
+    SYM_SPEC (kFigCapturePropertyValue_AFEarlyOutThreshold),
+    SYM_SPEC (kFigCapturePropertyValue_AFPositionCurrent),
+    SYM_SPEC (kFigCapturePropertyValue_AFPositionInfinity),
+    SYM_SPEC (kFigCapturePropertyValue_AFPositionMacro),
+    SYM_SPEC (kFigCapturePropertyValue_AFSearchPositionArray),
+    SYM_SPEC (kFigCapturePropertyValue_AGC),
+    SYM_SPEC (kFigCapturePropertyValue_CLPFControl),
+    SYM_SPEC (kFigCapturePropertyValue_ColorRangeFull),
+    SYM_SPEC (kFigCapturePropertyValue_ColorRangeSDVideo),
+    SYM_SPEC (kFigCapturePropertyValue_ModuleDate),
+    SYM_SPEC (kFigCapturePropertyValue_ModuleIntegratorInfo),
+    SYM_SPEC (kFigCapturePropertyValue_SensorID),
+    SYM_SPEC (kFigCapturePropertyValue_SigmaFilterControl),
+    SYM_SPEC (kFigCapturePropertyValue_YLPFControl),
+    SYM_SPEC (kFigCapturePropertyValue_hStart),
+    SYM_SPEC (kFigCapturePropertyValue_height),
+    SYM_SPEC (kFigCapturePropertyValue_ispDGain),
+    SYM_SPEC (kFigCapturePropertyValue_sensorDGain),
+    SYM_SPEC (kFigCapturePropertyValue_shutterSpeedDenominator),
+    SYM_SPEC (kFigCapturePropertyValue_shutterSpeedNumerator),
+    SYM_SPEC (kFigCapturePropertyValue_vStart),
+    SYM_SPEC (kFigCapturePropertyValue_weight),
+    SYM_SPEC (kFigCapturePropertyValue_width),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_AEBracketedCaptureParams),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_BLCCompensation),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_BLCDebugMode),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_BandHighFactor),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_BandLowFactor),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_CCMWarmUpWeight),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_EdgeColorSuppressionSlope),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_EdgeColorSuppressionThreshold),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_EnableAESceneDynamicMetering),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_EnableCCMWarmUp),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_EnableHistogram1MetaData),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_EnableHistogram2MetaData),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_EnableHistogram3MetaData),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_EnableHistogram4MetaData),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_EnableHistogram),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_HistogramBinMode),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_HistogramDataType),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_ImageCropRect),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_LPExposure),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_LPGain),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_LowWeight),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_MaxWeight),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_MediumWeight),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_MinWeight),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_WeightDropOff),
+    SYM_SPEC (kFigCaptureStreamPropertyValue_WeightReduction),
+    SYM_SPEC (kFigCaptureStreamProperty_AEConvergenceSpeed),
+    SYM_SPEC (kFigCaptureStreamProperty_AEOutlierClipCount),
+    SYM_SPEC (kFigCaptureStreamProperty_AESceneDynamicMetering),
+    SYM_SPEC (kFigCaptureStreamProperty_AEStability),
+    SYM_SPEC (kFigCaptureStreamProperty_AEWindowManualWeightMatrix),
+    SYM_SPEC (kFigCaptureStreamProperty_AEWindowParams),
+    SYM_SPEC (kFigCaptureStreamProperty_AFEarlyOutParams),
+    SYM_SPEC (kFigCaptureStreamProperty_AFParams),
+    SYM_SPEC (kFigCaptureStreamProperty_AFSearchPositions),
+    SYM_SPEC (kFigCaptureStreamProperty_AFWindowParams),
+    SYM_SPEC (kFigCaptureStreamProperty_AGC),
+    SYM_SPEC (kFigCaptureStreamProperty_AWBWindowParams),
+    SYM_SPEC (kFigCaptureStreamProperty_AdditionalPTSOffset),
+    SYM_SPEC (kFigCaptureStreamProperty_AlternateAWB),
+    SYM_SPEC (kFigCaptureStreamProperty_Apply3AWindowSettings),
+    SYM_SPEC (kFigCaptureStreamProperty_AttachRAW),
+    SYM_SPEC (kFigCaptureStreamProperty_CCMWarmUp),
+    SYM_SPEC (kFigCaptureStreamProperty_ClientMaxBufferCountHint),
+    SYM_SPEC (kFigCaptureStreamProperty_ColorRange),
+    SYM_SPEC (kFigCaptureStreamProperty_ColorSaturation),
+    SYM_SPEC (kFigCaptureStreamProperty_ColorTables),
+    SYM_SPEC (kFigCaptureStreamProperty_EdgeColorSuppressionParams),
+    SYM_SPEC (kFigCaptureStreamProperty_ExposureBias),
+    SYM_SPEC (kFigCaptureStreamProperty_FastSwitchMode),
+    SYM_SPEC (kFigCaptureStreamProperty_FlashMode),
+    SYM_SPEC (kFigCaptureStreamProperty_HistogramParams),
+    SYM_SPEC (kFigCaptureStreamProperty_LockAENow),
+    SYM_SPEC (kFigCaptureStreamProperty_LockAWBNow),
+    SYM_SPEC (kFigCaptureStreamProperty_ManualAENow),
+    SYM_SPEC (kFigCaptureStreamProperty_ManualFocusNow),
+    SYM_SPEC (kFigCaptureStreamProperty_MaxIntegrationTime),
+    SYM_SPEC (kFigCaptureStreamProperty_ModuleInfo),
+    SYM_SPEC (kFigCaptureStreamProperty_NoiseReductionControls),
+    SYM_SPEC (kFigCaptureStreamProperty_PortType),
+    SYM_SPEC (kFigCaptureStreamProperty_PreFrameAE),
+    SYM_SPEC (kFigCaptureStreamProperty_RawImageProcessNow),
+    SYM_SPEC (kFigCaptureStreamProperty_RedEyeReductionParams),
+    SYM_SPEC (kFigCaptureStreamProperty_ResetParams),
+    SYM_SPEC (kFigCaptureStreamProperty_ScalerSharpening),
+    SYM_SPEC (kFigCaptureStreamProperty_SetGainCap),
+    SYM_SPEC (kFigCaptureStreamProperty_SharpeningControl),
+    SYM_SPEC (kFigCaptureStreamProperty_TorchLevel),
+    SYM_SPEC (kFigCaptureStreamProperty_UnlockAENow),
+    SYM_SPEC (kFigCaptureStreamProperty_UnlockAWBNow),
+    SYM_SPEC (kFigCaptureStreamProperty_UseFlashAFAssist),
+    SYM_SPEC (kFigCaptureStreamProperty_UseFlashRedEyeReduction),
+    SYM_SPEC (kFigCaptureStreamProperty_UseHardwareShutter),
+    SYM_SPEC (kFigCaptureStreamProperty_VideoRecordingInProgress),
+    SYM_SPEC (kFigRecorderCapturePreset_AudioRecording),
+    SYM_SPEC (kFigRecorderCapturePreset_AudioVideoRecording),
+    SYM_SPEC (kFigRecorderCapturePreset_PhotoCapture),
+    SYM_SPEC (kFigRecorderCapturePreset_VideoRecording),
+
+    {NULL, 0},
+  };
+
+  return _gst_dyn_api_new (gst_cel_api_get_type (), CELESTIAL_FRAMEWORK_PATH,
+      symbols, error);
+}
diff --git a/sys/applemedia-nonpublic/celapi.h b/sys/applemedia-nonpublic/celapi.h
new file mode 100644 (file)
index 0000000..78855f9
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_CEL_API_H__
+#define __GST_CEL_API_H__
+
+#include "mtapi.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GstCelApi GstCelApi;
+typedef struct _GstCelApiClass GstCelApiClass;
+
+enum
+{
+  kCelError_ResourceBusy = -12780
+};
+
+struct _GstCelApi
+{
+  GstDynApi parent;
+
+  OSStatus (* FigCreateCaptureDevicesAndStreamsForPreset)
+      (CFAllocatorRef allocator, CFStringRef capturePreset,
+      CFDictionaryRef audioOptions,
+      FigCaptureDeviceRef * outVideoDevice,
+      FigCaptureStreamRef * outVideoStream,
+      FigCaptureDeviceRef * outAudioDevice,
+      FigCaptureStreamRef * outAudioStream);
+
+  CFStringRef * kFigCaptureDeviceProperty_MultiplexStreams;
+  CFStringRef * kFigCapturePortType_Bottom;
+  CFStringRef * kFigCapturePortType_Camera;
+  CFStringRef * kFigCapturePortType_FrontFacingCamera;
+  CFStringRef * kFigCapturePortType_Top;
+  CFStringRef * kFigCapturePropertyValue_AFEarlyOutAllowPeakAtStart;
+  CFStringRef * kFigCapturePropertyValue_AFEarlyOutDecrementAmount;
+  CFStringRef * kFigCapturePropertyValue_AFEarlyOutEnable;
+  CFStringRef * kFigCapturePropertyValue_AFEarlyOutThreshold;
+  CFStringRef * kFigCapturePropertyValue_AFPositionCurrent;
+  CFStringRef * kFigCapturePropertyValue_AFPositionInfinity;
+  CFStringRef * kFigCapturePropertyValue_AFPositionMacro;
+  CFStringRef * kFigCapturePropertyValue_AFSearchPositionArray;
+  CFStringRef * kFigCapturePropertyValue_AGC;
+  CFStringRef * kFigCapturePropertyValue_CLPFControl;
+  CFStringRef * kFigCapturePropertyValue_ColorRangeFull;
+  CFStringRef * kFigCapturePropertyValue_ColorRangeSDVideo;
+  CFStringRef * kFigCapturePropertyValue_ModuleDate;
+  CFStringRef * kFigCapturePropertyValue_ModuleIntegratorInfo;
+  CFStringRef * kFigCapturePropertyValue_SensorID;
+  CFStringRef * kFigCapturePropertyValue_SigmaFilterControl;
+  CFStringRef * kFigCapturePropertyValue_YLPFControl;
+  CFStringRef * kFigCapturePropertyValue_hStart;
+  CFStringRef * kFigCapturePropertyValue_height;
+  CFStringRef * kFigCapturePropertyValue_ispDGain;
+  CFStringRef * kFigCapturePropertyValue_sensorDGain;
+  CFStringRef * kFigCapturePropertyValue_shutterSpeedDenominator;
+  CFStringRef * kFigCapturePropertyValue_shutterSpeedNumerator;
+  CFStringRef * kFigCapturePropertyValue_vStart;
+  CFStringRef * kFigCapturePropertyValue_weight;
+  CFStringRef * kFigCapturePropertyValue_width;
+  CFStringRef * kFigCaptureStreamPropertyValue_AEBracketedCaptureParams;
+  CFStringRef * kFigCaptureStreamPropertyValue_BLCCompensation;
+  CFStringRef * kFigCaptureStreamPropertyValue_BLCDebugMode;
+  CFStringRef * kFigCaptureStreamPropertyValue_BandHighFactor;
+  CFStringRef * kFigCaptureStreamPropertyValue_BandLowFactor;
+  CFStringRef * kFigCaptureStreamPropertyValue_CCMWarmUpWeight;
+  CFStringRef * kFigCaptureStreamPropertyValue_EdgeColorSuppressionSlope;
+  CFStringRef * kFigCaptureStreamPropertyValue_EdgeColorSuppressionThreshold;
+  CFStringRef * kFigCaptureStreamPropertyValue_EnableAESceneDynamicMetering;
+  CFStringRef * kFigCaptureStreamPropertyValue_EnableCCMWarmUp;
+  CFStringRef * kFigCaptureStreamPropertyValue_EnableHistogram1MetaData;
+  CFStringRef * kFigCaptureStreamPropertyValue_EnableHistogram2MetaData;
+  CFStringRef * kFigCaptureStreamPropertyValue_EnableHistogram3MetaData;
+  CFStringRef * kFigCaptureStreamPropertyValue_EnableHistogram4MetaData;
+  CFStringRef * kFigCaptureStreamPropertyValue_EnableHistogram;
+  CFStringRef * kFigCaptureStreamPropertyValue_HistogramBinMode;
+  CFStringRef * kFigCaptureStreamPropertyValue_HistogramDataType;
+  CFStringRef * kFigCaptureStreamPropertyValue_ImageCropRect;
+  CFStringRef * kFigCaptureStreamPropertyValue_LPExposure;
+  CFStringRef * kFigCaptureStreamPropertyValue_LPGain;
+  CFStringRef * kFigCaptureStreamPropertyValue_LowWeight;
+  CFStringRef * kFigCaptureStreamPropertyValue_MaxWeight;
+  CFStringRef * kFigCaptureStreamPropertyValue_MediumWeight;
+  CFStringRef * kFigCaptureStreamPropertyValue_MinWeight;
+  CFStringRef * kFigCaptureStreamPropertyValue_WeightDropOff;
+  CFStringRef * kFigCaptureStreamPropertyValue_WeightReduction;
+  CFStringRef * kFigCaptureStreamProperty_AEConvergenceSpeed;
+  CFStringRef * kFigCaptureStreamProperty_AEOutlierClipCount;
+  CFStringRef * kFigCaptureStreamProperty_AESceneDynamicMetering;
+  CFStringRef * kFigCaptureStreamProperty_AEStability;
+  CFStringRef * kFigCaptureStreamProperty_AEWindowManualWeightMatrix;
+  CFStringRef * kFigCaptureStreamProperty_AEWindowParams;
+  CFStringRef * kFigCaptureStreamProperty_AFEarlyOutParams;
+  CFStringRef * kFigCaptureStreamProperty_AFParams;
+  CFStringRef * kFigCaptureStreamProperty_AFSearchPositions;
+  CFStringRef * kFigCaptureStreamProperty_AFWindowParams;
+  CFStringRef * kFigCaptureStreamProperty_AGC;
+  CFStringRef * kFigCaptureStreamProperty_AWBWindowParams;
+  CFStringRef * kFigCaptureStreamProperty_AdditionalPTSOffset;
+  CFStringRef * kFigCaptureStreamProperty_AlternateAWB;
+  CFStringRef * kFigCaptureStreamProperty_Apply3AWindowSettings;
+  CFStringRef * kFigCaptureStreamProperty_AttachRAW;
+  CFStringRef * kFigCaptureStreamProperty_CCMWarmUp;
+  CFStringRef * kFigCaptureStreamProperty_ClientMaxBufferCountHint;
+  CFStringRef * kFigCaptureStreamProperty_ColorRange;
+  CFStringRef * kFigCaptureStreamProperty_ColorSaturation;
+  CFStringRef * kFigCaptureStreamProperty_ColorTables;
+  CFStringRef * kFigCaptureStreamProperty_EdgeColorSuppressionParams;
+  CFStringRef * kFigCaptureStreamProperty_ExposureBias;
+  CFStringRef * kFigCaptureStreamProperty_FastSwitchMode;
+  CFStringRef * kFigCaptureStreamProperty_FlashMode;
+  CFStringRef * kFigCaptureStreamProperty_HistogramParams;
+  CFStringRef * kFigCaptureStreamProperty_LockAENow;
+  CFStringRef * kFigCaptureStreamProperty_LockAWBNow;
+  CFStringRef * kFigCaptureStreamProperty_ManualAENow;
+  CFStringRef * kFigCaptureStreamProperty_ManualFocusNow;
+  CFStringRef * kFigCaptureStreamProperty_MaxIntegrationTime;
+  CFStringRef * kFigCaptureStreamProperty_ModuleInfo;
+  CFStringRef * kFigCaptureStreamProperty_NoiseReductionControls;
+  CFStringRef * kFigCaptureStreamProperty_PortType;
+  CFStringRef * kFigCaptureStreamProperty_PreFrameAE;
+  CFStringRef * kFigCaptureStreamProperty_RawImageProcessNow;
+  CFStringRef * kFigCaptureStreamProperty_RedEyeReductionParams;
+  CFStringRef * kFigCaptureStreamProperty_ResetParams;
+  CFStringRef * kFigCaptureStreamProperty_ScalerSharpening;
+  CFStringRef * kFigCaptureStreamProperty_SetGainCap;
+  CFStringRef * kFigCaptureStreamProperty_SharpeningControl;
+  CFStringRef * kFigCaptureStreamProperty_TorchLevel;
+  CFStringRef * kFigCaptureStreamProperty_UnlockAENow;
+  CFStringRef * kFigCaptureStreamProperty_UnlockAWBNow;
+  CFStringRef * kFigCaptureStreamProperty_UseFlashAFAssist;
+  CFStringRef * kFigCaptureStreamProperty_UseFlashRedEyeReduction;
+  CFStringRef * kFigCaptureStreamProperty_UseHardwareShutter;
+  CFStringRef * kFigCaptureStreamProperty_VideoRecordingInProgress;
+  CFStringRef * kFigRecorderCapturePreset_AudioRecording;
+  CFStringRef * kFigRecorderCapturePreset_AudioVideoRecording;
+  CFStringRef * kFigRecorderCapturePreset_PhotoCapture;
+  CFStringRef * kFigRecorderCapturePreset_VideoRecording;
+};
+
+struct _GstCelApiClass
+{
+  GstDynApiClass parent_class;
+};
+
+GType gst_cel_api_get_type (void);
+
+GstCelApi * gst_cel_api_obtain (GError ** error);
+
+G_END_DECLS
+
+#endif
diff --git a/sys/applemedia-nonpublic/celvideosrc.c b/sys/applemedia-nonpublic/celvideosrc.c
new file mode 100644 (file)
index 0000000..90c1246
--- /dev/null
@@ -0,0 +1,881 @@
+/*
+ * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "celvideosrc.h"
+
+#include "coremediabuffer.h"
+
+#include <gst/video/video.h>
+
+#define DEFAULT_DEVICE_INDEX  -1
+#define DEFAULT_DO_STATS      FALSE
+
+#define QUEUE_READY_LOCK(instance) GST_OBJECT_LOCK (instance)
+#define QUEUE_READY_UNLOCK(instance) GST_OBJECT_UNLOCK (instance)
+#define QUEUE_READY_WAIT(instance) \
+    g_cond_wait (instance->ready_cond, GST_OBJECT_GET_LOCK (instance))
+#define QUEUE_READY_NOTIFY(instance) g_cond_signal (instance->ready_cond)
+
+GST_DEBUG_CATEGORY (gst_cel_video_src_debug);
+#define GST_CAT_DEFAULT gst_cel_video_src_debug
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("NV12") ";"
+        GST_VIDEO_CAPS_YUV ("YUY2"))
+    );
+
+enum
+{
+  PROP_0,
+  PROP_DEVICE_INDEX,
+  PROP_DO_STATS,
+  PROP_FPS
+};
+
+typedef struct
+{
+  guint index;
+
+  GstVideoFormat video_format;
+  guint32 fourcc;
+  gint width;
+  gint height;
+  gint fps_n;
+  gint fps_d;
+} GstCelVideoFormat;
+
+static gboolean gst_cel_video_src_open_device (GstCelVideoSrc * self);
+static void gst_cel_video_src_close_device (GstCelVideoSrc * self);
+static void gst_cel_video_src_ensure_device_caps_and_formats
+    (GstCelVideoSrc * self);
+static void gst_cel_video_src_release_device_caps_and_formats
+    (GstCelVideoSrc * self);
+static gboolean gst_cel_video_src_select_format (GstCelVideoSrc * self,
+    GstCelVideoFormat * format);
+
+static gboolean gst_cel_video_src_parse_stream_format
+    (GstCelVideoSrc * self, guint index, CFDictionaryRef stream_format,
+    GstCelVideoFormat * format);
+static OSStatus gst_cel_video_src_set_stream_property_i32
+    (GstCelVideoSrc * self, CFStringRef name, SInt32 value);
+static OSStatus gst_cel_video_src_set_stream_property_value
+    (GstCelVideoSrc * self, CFStringRef name, CFTypeRef value);
+
+static GstPushSrcClass *parent_class;
+
+GST_BOILERPLATE (GstCelVideoSrc, gst_cel_video_src, GstPushSrc,
+    GST_TYPE_PUSH_SRC);
+
+static void
+gst_cel_video_src_init (GstCelVideoSrc * self, GstCelVideoSrcClass * gclass)
+{
+  GstBaseSrc *base_src = GST_BASE_SRC_CAST (self);
+
+  gst_base_src_set_live (base_src, TRUE);
+  gst_base_src_set_format (base_src, GST_FORMAT_TIME);
+
+  self->ready_cond = g_cond_new ();
+}
+
+static void
+gst_cel_video_src_dispose (GObject * object)
+{
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_cel_video_src_finalize (GObject * object)
+{
+  GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (object);
+
+  g_cond_free (self->ready_cond);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_cel_video_src_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (object);
+
+  switch (prop_id) {
+    case PROP_DEVICE_INDEX:
+      g_value_set_int (value, self->device_index);
+      break;
+    case PROP_DO_STATS:
+      g_value_set_boolean (value, self->do_stats);
+      break;
+    case PROP_FPS:
+      GST_OBJECT_LOCK (object);
+      g_value_set_int (value, self->fps);
+      GST_OBJECT_UNLOCK (object);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_cel_video_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (object);
+
+  switch (prop_id) {
+    case PROP_DEVICE_INDEX:
+      self->device_index = g_value_get_int (value);
+      break;
+    case PROP_DO_STATS:
+      self->do_stats = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstStateChangeReturn
+gst_cel_video_src_change_state (GstElement * element, GstStateChange transition)
+{
+  GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (element);
+  GstStateChangeReturn ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      if (!gst_cel_video_src_open_device (self))
+        goto open_failed;
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      gst_cel_video_src_close_device (self);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+
+  /* ERRORS */
+open_failed:
+  {
+    return GST_STATE_CHANGE_FAILURE;
+  }
+}
+
+static GstCaps *
+gst_cel_video_src_get_caps (GstBaseSrc * basesrc)
+{
+  GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (basesrc);
+  GstCaps *result;
+
+  if (self->device != NULL) {
+    gst_cel_video_src_ensure_device_caps_and_formats (self);
+
+    result = gst_caps_ref (self->device_caps);
+  } else {
+    result = NULL;
+  }
+
+  if (result != NULL) {
+    gchar *str;
+
+    str = gst_caps_to_string (result);
+    GST_DEBUG_OBJECT (self, "returning: %s", str);
+    g_free (str);
+  }
+
+  return result;
+}
+
+static gboolean
+gst_cel_video_src_set_caps (GstBaseSrc * basesrc, GstCaps * caps)
+{
+  GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (basesrc);
+  GstVideoFormat video_format;
+  gint width, height, fps_n, fps_d;
+  guint i;
+  GstCelVideoFormat *selected_format;
+
+  if (self->device == NULL)
+    goto no_device;
+
+  if (!gst_video_format_parse_caps (caps, &video_format, &width, &height))
+    goto invalid_format;
+  if (!gst_video_parse_caps_framerate (caps, &fps_n, &fps_d))
+    goto invalid_format;
+
+  gst_cel_video_src_ensure_device_caps_and_formats (self);
+
+  selected_format = NULL;
+
+  for (i = 0; i != self->device_formats->len; i++) {
+    GstCelVideoFormat *format;
+
+    format = &g_array_index (self->device_formats, GstCelVideoFormat, i);
+    if (format->video_format == video_format &&
+        format->width == width && format->height == height &&
+        format->fps_n == fps_n && format->fps_d == fps_d) {
+      selected_format = format;
+      break;
+    }
+  }
+
+  if (selected_format == NULL)
+    goto invalid_format;
+
+  GST_DEBUG_OBJECT (self, "selecting format %u", selected_format->index);
+
+  if (!gst_cel_video_src_select_format (self, selected_format))
+    goto select_failed;
+
+  gst_cel_video_src_release_device_caps_and_formats (self);
+
+  return TRUE;
+
+  /* ERRORS */
+no_device:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, FAILED, ("no device"), (NULL));
+    return FALSE;
+  }
+invalid_format:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, FAILED, ("invalid format"), (NULL));
+    return FALSE;
+  }
+select_failed:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, FAILED, ("failed to select format"),
+        (NULL));
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_cel_video_src_start (GstBaseSrc * basesrc)
+{
+  GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (basesrc);
+
+  g_atomic_int_set (&self->is_running, TRUE);
+  self->offset = 0;
+
+  self->last_sampling = GST_CLOCK_TIME_NONE;
+  self->count = 0;
+  self->fps = -1;
+
+  return TRUE;
+}
+
+static gboolean
+gst_cel_video_src_stop (GstBaseSrc * basesrc)
+{
+  return TRUE;
+}
+
+static gboolean
+gst_cel_video_src_query (GstBaseSrc * basesrc, GstQuery * query)
+{
+  GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (basesrc);
+  gboolean result = FALSE;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_LATENCY:{
+      GstClockTime min_latency, max_latency;
+
+      if (self->device == NULL || !GST_CLOCK_TIME_IS_VALID (self->duration))
+        goto beach;
+
+      min_latency = max_latency = self->duration;
+
+      GST_DEBUG_OBJECT (self, "reporting latency of min %" GST_TIME_FORMAT
+          " max %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
+
+      gst_query_set_latency (query, TRUE, min_latency, max_latency);
+      result = TRUE;
+      break;
+    }
+    default:
+      result = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
+      break;
+  }
+
+beach:
+  return result;
+}
+
+static gboolean
+gst_cel_video_src_unlock (GstBaseSrc * basesrc)
+{
+  GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (basesrc);
+
+  g_atomic_int_set (&self->is_running, FALSE);
+
+  QUEUE_READY_LOCK (self);
+  QUEUE_READY_NOTIFY (self);
+  QUEUE_READY_UNLOCK (self);
+
+  return TRUE;
+}
+
+static gboolean
+gst_cel_video_src_unlock_stop (GstBaseSrc * basesrc)
+{
+  return TRUE;
+}
+
+static void
+gst_cel_video_src_on_queue_ready (void *triggerRefcon,
+    CMBufferQueueTriggerToken triggerToken)
+{
+  GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (triggerRefcon);
+
+  QUEUE_READY_LOCK (self);
+  self->queue_is_ready = TRUE;
+  QUEUE_READY_NOTIFY (self);
+  QUEUE_READY_UNLOCK (self);
+}
+
+static void
+gst_cel_video_src_timestamp_buffer (GstCelVideoSrc * self, GstBuffer * buf)
+{
+  GstClock *clock;
+  GstClockTime ts;
+
+  GST_OBJECT_LOCK (self);
+  if ((clock = GST_ELEMENT_CLOCK (self)) != NULL) {
+    ts = gst_clock_get_time (clock);
+
+    if (ts > GST_ELEMENT (self)->base_time)
+      ts -= GST_ELEMENT (self)->base_time;
+    else
+      ts = 0;
+
+    if (ts > self->duration)
+      ts -= self->duration;
+    else
+      ts = 0;
+  } else {
+    ts = GST_CLOCK_TIME_NONE;
+  }
+  GST_OBJECT_UNLOCK (self);
+
+  GST_BUFFER_OFFSET (buf) = self->offset;
+  GST_BUFFER_OFFSET_END (buf) = self->offset + 1;
+  GST_BUFFER_TIMESTAMP (buf) = ts;
+  GST_BUFFER_DURATION (buf) = self->duration;
+
+  if (self->offset == 0)
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
+
+  self->offset++;
+}
+
+static void
+gst_cel_video_src_update_statistics (GstCelVideoSrc * self)
+{
+  GstClock *clock;
+
+  GST_OBJECT_LOCK (self);
+  clock = GST_ELEMENT_CLOCK (self);
+  if (clock != NULL)
+    gst_object_ref (clock);
+  GST_OBJECT_UNLOCK (self);
+
+  if (clock != NULL) {
+    GstClockTime now = gst_clock_get_time (clock);
+    gst_object_unref (clock);
+
+    self->count++;
+
+    if (GST_CLOCK_TIME_IS_VALID (self->last_sampling)) {
+      if (now - self->last_sampling >= GST_SECOND) {
+        GST_OBJECT_LOCK (self);
+        self->fps = self->count;
+        GST_OBJECT_UNLOCK (self);
+
+        g_object_notify (G_OBJECT (self), "fps");
+
+        self->last_sampling = now;
+        self->count = 0;
+      }
+    } else {
+      self->last_sampling = now;
+    }
+  }
+}
+
+static GstFlowReturn
+gst_cel_video_src_create (GstPushSrc * pushsrc, GstBuffer ** buf)
+{
+  GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (pushsrc);
+  GstCMApi *cm = self->ctx->cm;
+  CMSampleBufferRef sbuf;
+
+  sbuf = cm->CMBufferQueueDequeueAndRetain (self->queue);
+
+  while (sbuf == NULL) {
+    QUEUE_READY_LOCK (self);
+    while (!self->queue_is_ready && g_atomic_int_get (&self->is_running))
+      QUEUE_READY_WAIT (self);
+    self->queue_is_ready = FALSE;
+    QUEUE_READY_UNLOCK (self);
+
+    if (G_UNLIKELY (!g_atomic_int_get (&self->is_running)))
+      goto shutting_down;
+
+    sbuf = cm->CMBufferQueueDequeueAndRetain (self->queue);
+  }
+
+  if (G_UNLIKELY (!g_atomic_int_get (&self->is_running)))
+    goto shutting_down;
+
+  *buf = gst_core_media_buffer_new (self->ctx, sbuf);
+  gst_cel_video_src_timestamp_buffer (self, *buf);
+
+  cm->FigSampleBufferRelease (sbuf);
+
+  if (self->do_stats)
+    gst_cel_video_src_update_statistics (self);
+
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+shutting_down:
+  {
+    cm->FigSampleBufferRelease (sbuf);
+    return GST_FLOW_FLUSHING;
+  }
+}
+
+static gboolean
+gst_cel_video_src_open_device (GstCelVideoSrc * self)
+{
+  GstCoreMediaCtx *ctx = NULL;
+  GError *error = NULL;
+  GstCMApi *cm = NULL;
+  GstMTApi *mt = NULL;
+  GstCelApi *cel = NULL;
+  OSStatus status;
+  FigCaptureDeviceRef device = NULL;
+  FigBaseObjectRef device_base;
+  FigBaseVTable *device_vt;
+  CFArrayRef stream_array = NULL;
+  CFIndex stream_index;
+  FigCaptureStreamRef stream = NULL;
+  FigBaseObjectRef stream_base;
+  FigBaseVTable *stream_vt;
+  CMBufferQueueRef queue = NULL;
+  CMTime ignored_time;
+
+  ctx = gst_core_media_ctx_new (GST_API_CORE_VIDEO | GST_API_CORE_MEDIA
+      | GST_API_MEDIA_TOOLBOX | GST_API_CELESTIAL, &error);
+  if (error != NULL)
+    goto api_error;
+  cm = ctx->cm;
+  mt = ctx->mt;
+  cel = ctx->cel;
+
+  status = cel->FigCreateCaptureDevicesAndStreamsForPreset (NULL,
+      *(cel->kFigRecorderCapturePreset_VideoRecording), NULL,
+      &device, &stream, NULL, NULL);
+  if (status == kCelError_ResourceBusy)
+    goto device_busy;
+  else if (status != noErr)
+    goto unexpected_error;
+
+  device_base = mt->FigCaptureDeviceGetFigBaseObject (device);
+  device_vt = cm->FigBaseObjectGetVTable (device_base);
+
+  status = device_vt->base->CopyProperty (device_base,
+      *(mt->kFigCaptureDeviceProperty_StreamArray), NULL,
+      (CFTypeRef *) & stream_array);
+  if (status != noErr)
+    goto unexpected_error;
+
+  if (self->device_index >= 0)
+    stream_index = self->device_index;
+  else
+    stream_index = 0;
+
+  if (stream_index >= CFArrayGetCount (stream_array))
+    goto invalid_device_index;
+
+  CFRelease (stream);
+  stream = (FigCaptureStreamRef) CFArrayGetValueAtIndex (stream_array,
+      stream_index);
+  CFRetain (stream);
+
+  stream_base = mt->FigCaptureStreamGetFigBaseObject (stream);
+  stream_vt = cm->FigBaseObjectGetVTable (stream_base);
+
+  status = stream_vt->base->CopyProperty (stream_base,
+      *(mt->kFigCaptureStreamProperty_BufferQueue), NULL, &queue);
+  if (status != noErr)
+    goto unexpected_error;
+
+  self->queue_is_ready = FALSE;
+
+  ignored_time = cm->CMTimeMake (1, 1);
+  status = cm->CMBufferQueueInstallTrigger (queue,
+      gst_cel_video_src_on_queue_ready, self,
+      kCMBufferQueueTrigger_WhenDataBecomesReady, ignored_time,
+      &self->ready_trigger);
+  if (status != noErr)
+    goto unexpected_error;
+
+  self->ctx = ctx;
+
+  self->device = device;
+  self->device_iface = device_vt->derived;
+  self->device_base = device_base;
+  self->device_base_iface = device_vt->base;
+  self->stream = stream;
+  self->stream_iface = stream_vt->derived;
+  self->stream_base = stream_base;
+  self->stream_base_iface = stream_vt->base;
+
+  self->queue = queue;
+  self->duration = GST_CLOCK_TIME_NONE;
+
+  CFRelease (stream_array);
+
+  return TRUE;
+
+  /* ERRORS */
+api_error:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, FAILED, ("API error"),
+        ("%s", error->message));
+    g_clear_error (&error);
+    goto any_error;
+  }
+device_busy:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, BUSY,
+        ("device is already in use"), (NULL));
+    goto any_error;
+  }
+invalid_device_index:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
+        ("invalid video capture device index"), (NULL));
+    goto any_error;
+  }
+unexpected_error:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
+        ("unexpected error while opening device (%d)", (gint) status), (NULL));
+    goto any_error;
+  }
+any_error:
+  {
+    if (stream != NULL)
+      CFRelease (stream);
+    if (stream_array != NULL)
+      CFRelease (stream_array);
+    if (device != NULL)
+      CFRelease (device);
+
+    if (ctx != NULL) {
+      cm->FigBufferQueueRelease (queue);
+      g_object_unref (ctx);
+    }
+
+    return FALSE;
+  }
+}
+
+static void
+gst_cel_video_src_close_device (GstCelVideoSrc * self)
+{
+  gst_cel_video_src_release_device_caps_and_formats (self);
+
+  self->stream_iface->Stop (self->stream);
+  self->stream_base_iface->Finalize (self->stream_base);
+  CFRelease (self->stream);
+  self->stream = NULL;
+  self->stream_iface = NULL;
+  self->stream_base = NULL;
+  self->stream_base_iface = NULL;
+
+  self->device_base_iface->Finalize (self->device_base);
+  CFRelease (self->device);
+  self->device = NULL;
+  self->device_iface = NULL;
+  self->device_base = NULL;
+  self->device_base_iface = NULL;
+
+  self->ctx->cm->CMBufferQueueRemoveTrigger (self->queue, self->ready_trigger);
+  self->ctx->cm->FigBufferQueueRelease (self->queue);
+  self->ready_trigger = NULL;
+  self->queue = NULL;
+
+  g_object_unref (self->ctx);
+  self->ctx = NULL;
+}
+
+static void
+gst_cel_video_src_ensure_device_caps_and_formats (GstCelVideoSrc * self)
+{
+  OSStatus status;
+  CFArrayRef stream_formats = NULL;
+  CFIndex format_count, i;
+
+  if (self->device_caps != NULL)
+    goto already_probed;
+
+  self->device_caps = gst_caps_new_empty ();
+  self->device_formats = g_array_new (FALSE, FALSE, sizeof (GstCelVideoFormat));
+
+  status = self->stream_base_iface->CopyProperty (self->stream_base,
+      *(self->ctx->mt->kFigCaptureStreamProperty_SupportedFormatsArray),
+      NULL, (CFTypeRef *) & stream_formats);
+  if (status != noErr)
+    goto beach;
+
+  format_count = CFArrayGetCount (stream_formats);
+  GST_DEBUG_OBJECT (self, "device supports %d formats", (gint) format_count);
+
+  for (i = 0; i != format_count; i++) {
+    CFDictionaryRef sformat;
+    GstCelVideoFormat format;
+
+    sformat = CFArrayGetValueAtIndex (stream_formats, i);
+
+    if (gst_cel_video_src_parse_stream_format (self, i, sformat, &format)) {
+      gst_caps_append_structure (self->device_caps,
+          gst_structure_new ("video/x-raw-yuv",
+              "format", GST_TYPE_FOURCC, format.fourcc,
+              "width", G_TYPE_INT, format.width,
+              "height", G_TYPE_INT, format.height,
+              "framerate", GST_TYPE_FRACTION, format.fps_n, format.fps_d,
+              "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, NULL));
+      g_array_append_val (self->device_formats, format);
+    } else {
+      GST_WARNING_OBJECT (self, "ignoring unknown format #%d", (gint) i);
+    }
+  }
+
+  CFRelease (stream_formats);
+
+already_probed:
+beach:
+  return;
+}
+
+static void
+gst_cel_video_src_release_device_caps_and_formats (GstCelVideoSrc * self)
+{
+  if (self->device_caps != NULL) {
+    gst_caps_unref (self->device_caps);
+    self->device_caps = NULL;
+  }
+
+  if (self->device_formats != NULL) {
+    g_array_free (self->device_formats, TRUE);
+    self->device_formats = NULL;
+  }
+}
+
+static gboolean
+gst_cel_video_src_select_format (GstCelVideoSrc * self,
+    GstCelVideoFormat * format)
+{
+  gboolean result = FALSE;
+  GstMTApi *mt = self->ctx->mt;
+  GstCelApi *cel = self->ctx->cel;
+  OSStatus status;
+  SInt32 framerate;
+
+  status = gst_cel_video_src_set_stream_property_i32 (self,
+      *(mt->kFigCaptureStreamProperty_FormatIndex), format->index);
+  if (status != noErr)
+    goto beach;
+
+  framerate = format->fps_n / format->fps_d;
+
+  status = gst_cel_video_src_set_stream_property_i32 (self,
+      *(mt->kFigCaptureStreamProperty_MinimumFrameRate), framerate);
+  if (status != noErr)
+    goto beach;
+
+  status = gst_cel_video_src_set_stream_property_i32 (self,
+      *(mt->kFigCaptureStreamProperty_MaximumFrameRate), framerate);
+  if (status != noErr)
+    goto beach;
+
+  status = gst_cel_video_src_set_stream_property_value (self,
+      *(cel->kFigCaptureStreamProperty_ColorRange),
+      *(cel->kFigCapturePropertyValue_ColorRangeSDVideo));
+  if (status != noErr)
+    goto beach;
+
+  status = self->stream_iface->Start (self->stream);
+  if (status != noErr)
+    goto beach;
+
+  GST_DEBUG_OBJECT (self, "configured format %d (%d x %d @ %d Hz)",
+      format->index, format->width, format->height, (gint) framerate);
+
+  self->duration =
+      gst_util_uint64_scale (GST_SECOND, format->fps_d, format->fps_n);
+
+  result = TRUE;
+
+beach:
+  return result;
+}
+
+static gboolean
+gst_cel_video_src_parse_stream_format (GstCelVideoSrc * self,
+    guint index, CFDictionaryRef stream_format, GstCelVideoFormat * format)
+{
+  GstCMApi *cm = self->ctx->cm;
+  GstMTApi *mt = self->ctx->mt;
+  CMFormatDescriptionRef desc;
+  CMVideoDimensions dim;
+  UInt32 subtype;
+  CFNumberRef framerate_value;
+  SInt32 fps_n;
+
+  format->index = index;
+
+  desc = CFDictionaryGetValue (stream_format,
+      *(mt->kFigSupportedFormat_FormatDescription));
+
+  dim = cm->CMVideoFormatDescriptionGetDimensions (desc);
+  format->width = dim.width;
+  format->height = dim.height;
+
+  subtype = cm->CMFormatDescriptionGetMediaSubType (desc);
+
+  switch (subtype) {
+    case kComponentVideoUnsigned:
+      format->video_format = GST_VIDEO_FORMAT_YUY2;
+      format->fourcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
+      break;
+    case kYUV420vCodecType:
+      format->video_format = GST_VIDEO_FORMAT_NV12;
+      format->fourcc = GST_MAKE_FOURCC ('N', 'V', '1', '2');
+      break;
+    default:
+      goto unsupported_format;
+  }
+
+  framerate_value = CFDictionaryGetValue (stream_format,
+      *(mt->kFigSupportedFormat_VideoMaxFrameRate));
+  CFNumberGetValue (framerate_value, kCFNumberSInt32Type, &fps_n);
+  format->fps_n = fps_n;
+  format->fps_d = 1;
+
+  return TRUE;
+
+unsupported_format:
+  return FALSE;
+}
+
+static OSStatus
+gst_cel_video_src_set_stream_property_i32 (GstCelVideoSrc * self,
+    CFStringRef name, SInt32 value)
+{
+  OSStatus status;
+  CFNumberRef number;
+
+  number = CFNumberCreate (NULL, kCFNumberSInt32Type, &value);
+  status = self->stream_base_iface->SetProperty (self->stream_base, name,
+      number);
+  CFRelease (number);
+
+  return status;
+}
+
+static OSStatus
+gst_cel_video_src_set_stream_property_value (GstCelVideoSrc * self,
+    CFStringRef name, CFTypeRef value)
+{
+  return self->stream_base_iface->SetProperty (self->stream_base, name, value);
+}
+
+static void
+gst_cel_video_src_base_init (gpointer gclass)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
+
+  gst_element_class_set_metadata (element_class,
+      "Video Source (Celestial)", "Source/Video",
+      "Reads frames from an iOS Celestial device",
+      "Ole André Vadla Ravnås <oleavr@soundrop.com>");
+
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&src_template));
+}
+
+static void
+gst_cel_video_src_class_init (GstCelVideoSrcClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+  GstBaseSrcClass *gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
+  GstPushSrcClass *gstpushsrc_class = GST_PUSH_SRC_CLASS (klass);
+
+  gobject_class->dispose = gst_cel_video_src_dispose;
+  gobject_class->finalize = gst_cel_video_src_finalize;
+  gobject_class->get_property = gst_cel_video_src_get_property;
+  gobject_class->set_property = gst_cel_video_src_set_property;
+
+  gstelement_class->change_state = gst_cel_video_src_change_state;
+
+  gstbasesrc_class->get_caps = gst_cel_video_src_get_caps;
+  gstbasesrc_class->set_caps = gst_cel_video_src_set_caps;
+  gstbasesrc_class->start = gst_cel_video_src_start;
+  gstbasesrc_class->stop = gst_cel_video_src_stop;
+  gstbasesrc_class->query = gst_cel_video_src_query;
+  gstbasesrc_class->unlock = gst_cel_video_src_unlock;
+  gstbasesrc_class->unlock_stop = gst_cel_video_src_unlock_stop;
+
+  gstpushsrc_class->create = gst_cel_video_src_create;
+
+  g_object_class_install_property (gobject_class, PROP_DEVICE_INDEX,
+      g_param_spec_int ("device-index", "Device Index",
+          "The zero-based device index",
+          -1, G_MAXINT, DEFAULT_DEVICE_INDEX,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_DO_STATS,
+      g_param_spec_boolean ("do-stats", "Enable statistics",
+          "Enable logging of statistics", DEFAULT_DO_STATS,
+          G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_FPS,
+      g_param_spec_int ("fps", "Frames per second",
+          "Last measured framerate, if statistics are enabled",
+          -1, G_MAXINT, -1, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  GST_DEBUG_CATEGORY_INIT (gst_cel_video_src_debug, "celvideosrc",
+      0, "iOS Celestial video source");
+}
diff --git a/sys/applemedia-nonpublic/celvideosrc.h b/sys/applemedia-nonpublic/celvideosrc.h
new file mode 100644 (file)
index 0000000..5fa656c
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_CEL_VIDEO_SRC_H__
+#define __GST_CEL_VIDEO_SRC_H__
+
+#include <gst/base/gstpushsrc.h>
+
+#include "coremediactx.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_CEL_VIDEO_SRC \
+  (gst_cel_video_src_get_type ())
+#define GST_CEL_VIDEO_SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CEL_VIDEO_SRC, GstCelVideoSrc))
+#define GST_CEL_VIDEO_SRC_CAST(obj) \
+  ((GstCelVideoSrc *) (obj))
+#define GST_CEL_VIDEO_SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CEL_VIDEO_SRC, GstCelVideoSrcClass))
+#define GST_IS_CEL_VIDEO_SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CEL_VIDEO_SRC))
+#define GST_IS_CEL_VIDEO_SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CEL_VIDEO_SRC))
+
+typedef struct _GstCelVideoSrc         GstCelVideoSrc;
+typedef struct _GstCelVideoSrcClass    GstCelVideoSrcClass;
+
+struct _GstCelVideoSrc
+{
+  GstPushSrc push_src;
+
+  gint device_index;
+  gboolean do_stats;
+
+  GstCoreMediaCtx *ctx;
+
+  FigCaptureDeviceRef device;
+  FigCaptureDeviceIface *device_iface;
+  FigBaseObjectRef device_base;
+  FigBaseIface *device_base_iface;
+  FigCaptureStreamRef stream;
+  FigCaptureStreamIface *stream_iface;
+  FigBaseObjectRef stream_base;
+  FigBaseIface *stream_base_iface;
+
+  CMBufferQueueRef queue;
+  CMBufferQueueTriggerToken ready_trigger;
+  GstCaps *device_caps;
+  GArray *device_formats;
+  GstClockTime duration;
+
+  volatile gint is_running;
+  guint64 offset;
+
+  GCond *ready_cond;
+  volatile gboolean queue_is_ready;
+
+  GstClockTime last_sampling;
+  guint count;
+  gint fps;
+};
+
+struct _GstCelVideoSrcClass
+{
+  GstPushSrcClass parent_class;
+};
+
+GType gst_cel_video_src_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_CEL_VIDEO_SRC_H__ */
diff --git a/sys/applemedia-nonpublic/cmapi.c b/sys/applemedia-nonpublic/cmapi.c
new file mode 100644 (file)
index 0000000..15c28ed
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "cmapi.h"
+
+#include "dynapi-internal.h"
+
+#include <gmodule.h>
+
+#define CM_FRAMEWORK_PATH "/System/Library/Frameworks/" \
+    "CoreMedia.framework/CoreMedia"
+#define CM_FRAMEWORK_PATH_OLD "/System/Library/PrivateFrameworks/" \
+    "CoreMedia.framework/CoreMedia"
+
+G_DEFINE_TYPE (GstCMApi, gst_cm_api, GST_TYPE_DYN_API);
+
+static void
+gst_cm_api_init (GstCMApi * self)
+{
+}
+
+static void
+gst_cm_api_class_init (GstCMApiClass * klass)
+{
+}
+
+#define SYM_SPEC(name) GST_DYN_SYM_SPEC (GstCMApi, name)
+
+GstCMApi *
+gst_cm_api_obtain (GError ** error)
+{
+  static const GstDynSymSpec symbols[] = {
+    SYM_SPEC (FigBaseObjectGetVTable),
+
+    SYM_SPEC (CMGetAttachment),
+
+    SYM_SPEC (FigFormatDescriptionRelease),
+    SYM_SPEC (FigFormatDescriptionRetain),
+    SYM_SPEC (CMFormatDescriptionEqual),
+    SYM_SPEC (CMFormatDescriptionGetExtension),
+    SYM_SPEC (CMFormatDescriptionGetMediaType),
+    SYM_SPEC (CMFormatDescriptionGetMediaSubType),
+
+    SYM_SPEC (CMVideoFormatDescriptionCreate),
+    SYM_SPEC
+        (FigVideoFormatDescriptionCreateWithSampleDescriptionExtensionAtom),
+    SYM_SPEC (CMVideoFormatDescriptionGetDimensions),
+
+    SYM_SPEC (CMTimeMake),
+
+    SYM_SPEC (CMSampleBufferCreate),
+    SYM_SPEC (CMSampleBufferDataIsReady),
+    SYM_SPEC (CMSampleBufferGetDataBuffer),
+    SYM_SPEC (CMSampleBufferGetFormatDescription),
+    SYM_SPEC (CMSampleBufferGetImageBuffer),
+    SYM_SPEC (CMSampleBufferGetNumSamples),
+    SYM_SPEC (CMSampleBufferGetSampleAttachmentsArray),
+    SYM_SPEC (CMSampleBufferGetSampleSize),
+    SYM_SPEC (FigSampleBufferRelease),
+    SYM_SPEC (FigSampleBufferRetain),
+
+    SYM_SPEC (CMBlockBufferCreateWithMemoryBlock),
+    SYM_SPEC (CMBlockBufferGetDataLength),
+    SYM_SPEC (CMBlockBufferGetDataPointer),
+    SYM_SPEC (FigBlockBufferRelease),
+    SYM_SPEC (FigBlockBufferRetain),
+
+    SYM_SPEC (CMBufferQueueDequeueAndRetain),
+    SYM_SPEC (CMBufferQueueGetBufferCount),
+    SYM_SPEC (CMBufferQueueInstallTrigger),
+    SYM_SPEC (CMBufferQueueIsEmpty),
+    SYM_SPEC (FigBufferQueueRelease),
+    SYM_SPEC (CMBufferQueueRemoveTrigger),
+    SYM_SPEC (CMBufferQueueSetValidationCallback),
+
+    SYM_SPEC (kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms),
+    SYM_SPEC (kCMSampleAttachmentKey_DependsOnOthers),
+    SYM_SPEC (kCMTimeInvalid),
+
+    {NULL, 0},
+  };
+  GstCMApi *result;
+  GModule *module;
+
+  /* We cannot stat() the library as it may not be present on the filesystem.
+   * This is the case on newer versions of iOS where system libraries are all
+   * part of dyld_shared_cache... */
+  module = g_module_open (CM_FRAMEWORK_PATH, 0);
+  if (module != NULL) {
+    result = _gst_dyn_api_new (gst_cm_api_get_type (), CM_FRAMEWORK_PATH,
+        symbols, error);
+    g_module_close (module);
+  } else {
+    GstDynSymSpec *old_symbols;
+    guint i;
+
+    old_symbols = g_memdup (symbols, sizeof (symbols));
+    for (i = 0; old_symbols[i].name != NULL; i++) {
+      const gchar *name = old_symbols[i].name;
+      const gchar *translated_name;
+
+      if (g_str_has_prefix (name, "CM"))
+        translated_name = g_strconcat ("Fig", name + 2, NULL);
+      else if (g_str_has_prefix (name, "kCM"))
+        translated_name = g_strconcat ("kFig", name + 3, NULL);
+      else
+        translated_name = g_strdup (name);
+
+      old_symbols[i].name = translated_name;
+    }
+
+    result = _gst_dyn_api_new (gst_cm_api_get_type (), CM_FRAMEWORK_PATH_OLD,
+        old_symbols, error);
+
+    for (i = 0; old_symbols[i].name != NULL; i++)
+      g_free ((gpointer) old_symbols[i].name);
+    g_free (old_symbols);
+  }
+
+  return result;
+}
diff --git a/sys/applemedia-nonpublic/cmapi.h b/sys/applemedia-nonpublic/cmapi.h
new file mode 100644 (file)
index 0000000..92565fc
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_CM_API_H__
+#define __GST_CM_API_H__
+
+#include "dynapi.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include "cvapi.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GstCMApi GstCMApi;
+typedef struct _GstCMApiClass GstCMApiClass;
+
+typedef CFTypeRef FigBaseObjectRef;
+typedef struct _FigBaseVTable FigBaseVTable;
+typedef struct _FigBaseIface FigBaseIface;
+
+typedef CFTypeRef CMFormatDescriptionRef;
+typedef struct _CMVideoDimensions CMVideoDimensions;
+typedef struct _CMTime CMTime;
+
+typedef CFTypeRef CMBufferQueueRef;
+typedef SInt32 CMBufferQueueTriggerCondition;
+typedef struct _CMBufferQueueTriggerToken *CMBufferQueueTriggerToken;
+typedef CFTypeRef CMSampleBufferRef;
+typedef CFTypeRef CMBlockBufferRef;
+
+typedef void (* CMBufferQueueTriggerCallback) (void *triggerRefcon,
+    CMBufferQueueTriggerToken triggerToken);
+typedef Boolean (* CMBufferQueueValidationCallback) (CMBufferQueueRef queue,
+    CMSampleBufferRef buf, void *refCon);
+
+enum _FigMediaType
+{
+  kFigMediaTypeVideo = 'vide'
+};
+
+enum _FigCodecType
+{
+  kComponentVideoUnsigned           = 'yuvs',
+  kFigVideoCodecType_JPEG_OpenDML   = 'dmb1',
+  kYUV420vCodecType                 = '420v'
+};
+
+enum _CMBufferQueueTriggerCondition
+{
+  kCMBufferQueueTrigger_WhenDurationBecomesLessThan             = 1,
+  kCMBufferQueueTrigger_WhenDurationBecomesLessThanOrEqualTo    = 2,
+  kCMBufferQueueTrigger_WhenDurationBecomesGreaterThan          = 3,
+  kCMBufferQueueTrigger_WhenDurationBecomesGreaterThanOrEqualTo = 4,
+  kCMBufferQueueTrigger_WhenMinPresentationTimeStampChanges     = 5,
+  kCMBufferQueueTrigger_WhenMaxPresentationTimeStampChanges     = 6,
+  kCMBufferQueueTrigger_WhenDataBecomesReady                    = 7,
+  kCMBufferQueueTrigger_WhenEndOfDataReached                    = 8,
+  kCMBufferQueueTrigger_WhenReset                               = 9,
+  kCMBufferQueueTrigger_WhenBufferCountBecomesLessThan          = 10,
+  kCMBufferQueueTrigger_WhenBufferCountBecomesGreaterThan       = 11
+};
+
+struct _FigBaseVTable
+{
+  gsize unk;
+  FigBaseIface * base;
+  void * derived;
+};
+
+struct _FigBaseIface
+{
+  gsize unk1;
+  gsize unk2;
+  gsize unk3;
+  OSStatus (* Invalidate) (FigBaseObjectRef obj);
+  OSStatus (* Finalize) (FigBaseObjectRef obj);
+  gpointer unk4;
+  OSStatus (* CopyProperty) (FigBaseObjectRef obj, CFTypeRef key, void *unk,
+      CFTypeRef * value);
+  OSStatus (* SetProperty) (FigBaseObjectRef obj, CFTypeRef key,
+      CFTypeRef value);
+};
+
+struct _CMVideoDimensions
+{
+  UInt32 width;
+  UInt32 height;
+};
+
+struct _CMTime
+{
+  UInt8 data[24];
+};
+
+struct _GstCMApi
+{
+  GstDynApi parent;
+
+  FigBaseVTable * (* FigBaseObjectGetVTable) (FigBaseObjectRef obj);
+
+  void * (* CMGetAttachment) (CFTypeRef obj, CFStringRef attachmentKey,
+      UInt32 * foundWherePtr);
+
+  void (* FigFormatDescriptionRelease) (CMFormatDescriptionRef desc);
+  CMFormatDescriptionRef (* FigFormatDescriptionRetain) (
+      CMFormatDescriptionRef desc);
+  Boolean (* CMFormatDescriptionEqual) (CMFormatDescriptionRef desc1,
+      CMFormatDescriptionRef desc2);
+  CFTypeRef (* CMFormatDescriptionGetExtension) (
+      const CMFormatDescriptionRef desc, CFStringRef extensionKey);
+  UInt32 (* CMFormatDescriptionGetMediaType) (
+      const CMFormatDescriptionRef desc);
+  UInt32 (* CMFormatDescriptionGetMediaSubType) (
+      const CMFormatDescriptionRef desc);
+
+  OSStatus (* CMVideoFormatDescriptionCreate) (
+      CFAllocatorRef allocator, UInt32 formatId, UInt32 width, UInt32 height,
+      CFDictionaryRef extensions, CMFormatDescriptionRef * desc);
+  OSStatus (* FigVideoFormatDescriptionCreateWithSampleDescriptionExtensionAtom)
+      (CFAllocatorRef allocator, UInt32 formatId, UInt32 width, UInt32 height,
+      UInt32 atomId, const UInt8 * data, CFIndex len, void *unk1,
+      CMFormatDescriptionRef * formatDesc);
+  CMVideoDimensions (* CMVideoFormatDescriptionGetDimensions) (
+      const CMFormatDescriptionRef desc);
+
+  CMTime (* CMTimeMake) (int64_t value, int32_t timescale);
+
+  OSStatus (* CMSampleBufferCreate) (CFAllocatorRef allocator,
+      CMBlockBufferRef blockBuf, Boolean dataReady,
+      void *makeDataReadyCallback,
+      void *makeDataReadyRefcon,
+      CMFormatDescriptionRef fmtDesc, size_t numSamples,
+      size_t numSampleTimingEntries,
+      const void *sampleTimingArray,
+      size_t numSampleSizeEntries, const size_t *sampleSizeArray,
+      CMSampleBufferRef * sampleBuffer);
+  Boolean (* CMSampleBufferDataIsReady) (
+      const CMSampleBufferRef buf);
+  CMBlockBufferRef (* CMSampleBufferGetDataBuffer) (
+      const CMSampleBufferRef buf);
+  CMFormatDescriptionRef (* CMSampleBufferGetFormatDescription) (
+      const CMSampleBufferRef buf);
+  CVImageBufferRef (* CMSampleBufferGetImageBuffer) (
+      const CMSampleBufferRef buf);
+  SInt32 (* CMSampleBufferGetNumSamples) (
+      const CMSampleBufferRef buf);
+  CFArrayRef (* CMSampleBufferGetSampleAttachmentsArray) (
+      const CMSampleBufferRef buf, SInt32 sampleIndex);
+  SInt32 (* CMSampleBufferGetSampleSize) (
+      const CMSampleBufferRef buf, SInt32 sampleIndex);
+  void (* FigSampleBufferRelease) (CMSampleBufferRef buf);
+  CMSampleBufferRef (* FigSampleBufferRetain) (CMSampleBufferRef buf);
+
+  OSStatus (* CMBlockBufferCreateWithMemoryBlock)
+      (CFAllocatorRef allocator, void * memoryBlock, size_t blockLength,
+      CFAllocatorRef dataAllocator, void *customBlockSource,
+      size_t offsetToData, size_t dataLength,
+      int flags, CMBlockBufferRef * blockBuffer);
+  SInt32 (* CMBlockBufferGetDataLength) (const CMBlockBufferRef buf);
+  OSStatus (* CMBlockBufferGetDataPointer) (
+      const CMBlockBufferRef buf, UInt32 unk1, UInt32 unk2, UInt32 unk3,
+      Byte ** dataPtr);
+  void (* FigBlockBufferRelease) (CMBlockBufferRef buf);
+  CMBlockBufferRef (* FigBlockBufferRetain) (CMBlockBufferRef buf);
+
+  CMSampleBufferRef (* CMBufferQueueDequeueAndRetain)
+      (CMBufferQueueRef queue);
+  CFIndex (* CMBufferQueueGetBufferCount) (CMBufferQueueRef queue);
+  OSStatus (* CMBufferQueueInstallTrigger) (CMBufferQueueRef queue,
+      CMBufferQueueTriggerCallback triggerCallback, void * triggerRefCon,
+      CMBufferQueueTriggerCondition triggerCondition, CMTime triggerTime,
+      CMBufferQueueTriggerToken * triggerTokenOut);
+  Boolean (* CMBufferQueueIsEmpty) (CMBufferQueueRef queue);
+  void (* FigBufferQueueRelease) (CMBufferQueueRef queue);
+  OSStatus (* CMBufferQueueRemoveTrigger) (CMBufferQueueRef queue,
+      CMBufferQueueTriggerToken triggerToken);
+  OSStatus (* CMBufferQueueSetValidationCallback) (CMBufferQueueRef queue,
+      CMBufferQueueValidationCallback func, void *refCon);
+
+  CFStringRef * kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms;
+  CFStringRef * kCMSampleAttachmentKey_DependsOnOthers;
+  CMTime * kCMTimeInvalid;
+};
+
+struct _GstCMApiClass
+{
+  GstDynApiClass parent_class;
+};
+
+GType gst_cm_api_get_type (void);
+
+GstCMApi * gst_cm_api_obtain (GError ** error);
+
+G_END_DECLS
+
+#endif
diff --git a/sys/applemedia-nonpublic/coremediabuffer.c b/sys/applemedia-nonpublic/coremediabuffer.c
new file mode 100644 (file)
index 0000000..a8136ba
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2009 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "coremediabuffer.h"
+
+static void
+gst_core_media_meta_free (GstCoreMediaMeta * meta, GstBuffer * buf)
+{
+  if (meta->image_buf != NULL) {
+    GstCVApi *cv = meta->ctx->cv;
+    cv->CVPixelBufferUnlockBaseAddress (meta->image_buf,
+        kCVPixelBufferLock_ReadOnly);
+  }
+  meta->ctx->cm->FigSampleBufferRelease (meta->sample_buf);
+  g_object_unref (meta->ctx);
+}
+
+GType
+gst_core_media_meta_api_get_type (void)
+{
+  static volatile GType type;
+  static const gchar *tags[] = { "memory", NULL };
+
+  if (g_once_init_enter (&type)) {
+    GType _type = gst_meta_api_type_register ("GstCoreMediaMetaAPI", tags);
+    g_once_init_leave (&type, _type);
+  }
+  return type;
+}
+
+static const GstMetaInfo *
+gst_core_media_meta_get_info (void)
+{
+  static const GstMetaInfo *core_media_meta_info = NULL;
+
+  if (g_once_init_enter (&core_media_meta_info)) {
+    const GstMetaInfo *meta = gst_meta_register (GST_CORE_MEDIA_META_API_TYPE,
+        "GstCoreMediaMeta", sizeof (GstCoreMediaMeta),
+        (GstMetaInitFunction) NULL,
+        (GstMetaFreeFunction) gst_core_media_meta_free,
+        (GstMetaTransformFunction) NULL);
+    g_once_init_leave (&core_media_meta_info, meta);
+  }
+  return core_media_meta_info;
+}
+
+GstBuffer *
+gst_core_media_buffer_new (GstCoreMediaCtx * ctx, CMSampleBufferRef sample_buf)
+{
+  GstCVApi *cv = ctx->cv;
+  GstCMApi *cm = ctx->cm;
+  CVImageBufferRef image_buf;
+  CVPixelBufferRef pixel_buf;
+  CMBlockBufferRef block_buf;
+  Byte *data = NULL;
+  UInt32 size;
+  OSStatus status;
+  GstBuffer *buf;
+  GstCoreMediaMeta *meta;
+
+  image_buf = cm->CMSampleBufferGetImageBuffer (sample_buf);
+  pixel_buf = NULL;
+  block_buf = cm->CMSampleBufferGetDataBuffer (sample_buf);
+
+  if (image_buf != NULL &&
+      CFGetTypeID (image_buf) == cv->CVPixelBufferGetTypeID ()) {
+    pixel_buf = (CVPixelBufferRef) image_buf;
+
+    if (cv->CVPixelBufferLockBaseAddress (pixel_buf,
+            kCVPixelBufferLock_ReadOnly) != kCVReturnSuccess) {
+      goto error;
+    }
+
+    if (cv->CVPixelBufferIsPlanar (pixel_buf)) {
+      gint plane_count, plane_idx;
+
+      data = cv->CVPixelBufferGetBaseAddressOfPlane (pixel_buf, 0);
+
+      size = 0;
+      plane_count = cv->CVPixelBufferGetPlaneCount (pixel_buf);
+      for (plane_idx = 0; plane_idx != plane_count; plane_idx++) {
+        size += cv->CVPixelBufferGetBytesPerRowOfPlane (pixel_buf, plane_idx) *
+            cv->CVPixelBufferGetHeightOfPlane (pixel_buf, plane_idx);
+      }
+    } else {
+      data = cv->CVPixelBufferGetBaseAddress (pixel_buf);
+      size = cv->CVPixelBufferGetBytesPerRow (pixel_buf) *
+          cv->CVPixelBufferGetHeight (pixel_buf);
+    }
+  } else if (block_buf != NULL) {
+    status = cm->CMBlockBufferGetDataPointer (block_buf, 0, 0, 0, &data);
+    if (status != noErr)
+      goto error;
+    size = cm->CMBlockBufferGetDataLength (block_buf);
+  } else {
+    goto error;
+  }
+
+  buf = gst_buffer_new ();
+
+  meta = (GstCoreMediaMeta *) gst_buffer_add_meta (buf,
+      gst_core_media_meta_get_info (), NULL);
+  meta->ctx = g_object_ref (ctx);
+  meta->sample_buf = cm->FigSampleBufferRetain (sample_buf);
+  meta->image_buf = image_buf;
+  meta->pixel_buf = pixel_buf;
+  meta->block_buf = block_buf;
+
+  gst_buffer_append_memory (buf,
+      gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, data,
+          size, 0, size, NULL, NULL));
+
+  return buf;
+
+error:
+  return NULL;
+}
+
+CVPixelBufferRef
+gst_core_media_buffer_get_pixel_buffer (GstBuffer * buf)
+{
+  GstCoreMediaMeta *meta = (GstCoreMediaMeta *) gst_buffer_get_meta (buf,
+      GST_CORE_MEDIA_META_API_TYPE);
+  g_return_val_if_fail (meta != NULL, NULL);
+
+  return meta->ctx->cv->CVPixelBufferRetain (meta->pixel_buf);
+}
diff --git a/sys/applemedia-nonpublic/coremediabuffer.h b/sys/applemedia-nonpublic/coremediabuffer.h
new file mode 100644 (file)
index 0000000..dffb43f
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2009 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_CORE_MEDIA_BUFFER_H__
+#define __GST_CORE_MEDIA_BUFFER_H__
+
+#include <gst/gst.h>
+
+#include "coremediactx.h"
+
+G_BEGIN_DECLS
+
+#define GST_CORE_MEDIA_META_API_TYPE (gst_core_media_meta_api_get_type())
+#define gst_buffer_get_core_media_meta(b) \
+  ((GstCoreMediaMeta*)gst_buffer_get_meta((b),GST_CORE_MEDIA_META_API_TYPE))
+
+typedef struct _GstCoreMediaMeta
+{
+  GstMeta meta;
+
+  GstCoreMediaCtx * ctx;
+  CMSampleBufferRef sample_buf;
+  CVImageBufferRef image_buf;
+  CVPixelBufferRef pixel_buf;
+  CMBlockBufferRef block_buf;
+} GstCoreMediaMeta;
+
+
+GstBuffer * gst_core_media_buffer_new      (GstCoreMediaCtx * ctx,
+                                            CMSampleBufferRef sample_buf);
+CVPixelBufferRef gst_core_media_buffer_get_pixel_buffer
+                                           (GstBuffer * buf);
+GType gst_core_media_meta_api_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_CORE_MEDIA_BUFFER_H__ */
diff --git a/sys/applemedia-nonpublic/coremediactx.c b/sys/applemedia-nonpublic/coremediactx.c
new file mode 100644 (file)
index 0000000..ba02e4b
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "coremediactx.h"
+
+#include <gst/gst.h>
+
+typedef struct _GstApiProvider GstApiProvider;
+
+typedef gpointer (*GstApiProviderObtainFunc) (GError ** error);
+
+struct _GstApiProvider
+{
+  GstCoreMediaApi api;
+  GstApiProviderObtainFunc obtain;
+  guint offset;
+};
+
+#define API_PROVIDER(AN, a_n) \
+  { GST_API_##AN, (GstApiProviderObtainFunc) gst_##a_n##_api_obtain, \
+    G_STRUCT_OFFSET (GstCoreMediaCtx, a_n) }
+
+static const GstApiProvider api_provider[] = {
+  API_PROVIDER (CORE_VIDEO, cv),
+  API_PROVIDER (CORE_MEDIA, cm),
+#ifdef HAVE_IOS
+  API_PROVIDER (MEDIA_TOOLBOX, mt),
+  API_PROVIDER (CELESTIAL, cel)
+#else
+  API_PROVIDER (MIO, mio),
+#endif
+};
+
+G_DEFINE_TYPE (GstCoreMediaCtx, gst_core_media_ctx, G_TYPE_OBJECT);
+
+static void
+gst_core_media_ctx_init (GstCoreMediaCtx * self)
+{
+}
+
+static void
+gst_core_media_ctx_dispose (GObject * object)
+{
+  GstCoreMediaCtx *self = GST_CORE_MEDIA_CTX_CAST (object);
+  guint i;
+
+  for (i = 0; i != G_N_ELEMENTS (api_provider); i++) {
+    const GstApiProvider *ap = &api_provider[i];
+    gpointer *api_ptr = (gpointer *) ((guint8 *) self + ap->offset);
+
+    if (*api_ptr != NULL) {
+      g_object_unref (*api_ptr);
+      *api_ptr = NULL;
+    }
+  }
+
+  G_OBJECT_CLASS (gst_core_media_ctx_parent_class)->dispose (object);
+}
+
+static void
+gst_core_media_ctx_class_init (GstCoreMediaCtxClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->dispose = gst_core_media_ctx_dispose;
+}
+
+GstCoreMediaCtx *
+gst_core_media_ctx_new (GstCoreMediaApi required_apis, GError ** error)
+{
+  GstCoreMediaCtx *ctx;
+  GArray *error_messages;
+  guint i;
+
+  ctx = g_object_new (GST_TYPE_CORE_MEDIA_CTX, NULL);
+
+  error_messages = g_array_new (TRUE, FALSE, sizeof (gchar *));
+
+  for (i = 0; i != G_N_ELEMENTS (api_provider); i++) {
+    const GstApiProvider *ap = &api_provider[i];
+
+    if ((required_apis & ap->api) != 0) {
+      gpointer *api_ptr = (gpointer *) ((guint8 *) ctx + ap->offset);
+      GError *tmp_error = NULL;
+
+      *api_ptr = ap->obtain (&tmp_error);
+      if (tmp_error != NULL) {
+        gchar *message_copy = g_strdup (tmp_error->message);
+        g_array_append_val (error_messages, message_copy);
+        g_clear_error (&tmp_error);
+      }
+    }
+  }
+
+  if (error_messages->len != 0) {
+    gchar *errors_joined;
+
+    errors_joined = g_strjoinv ("\n\t* ", (gchar **) error_messages->data);
+    g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
+        "Could not obtain required API%s:%s%s",
+        (error_messages->len == 1) ? "" : "s",
+        (error_messages->len == 1) ? " " : "\n\t* ", errors_joined);
+    g_free (errors_joined);
+
+    g_object_unref (ctx);
+    ctx = NULL;
+  }
+
+  for (i = 0; i != error_messages->len; i++)
+    g_free (g_array_index (error_messages, gchar *, i));
+  g_array_free (error_messages, TRUE);
+
+  return ctx;
+}
diff --git a/sys/applemedia-nonpublic/coremediactx.h b/sys/applemedia-nonpublic/coremediactx.h
new file mode 100644 (file)
index 0000000..45640bd
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_CORE_MEDIA_CTX_H__
+#define __GST_CORE_MEDIA_CTX_H__
+
+#include "cvapi.h"
+#include "cmapi.h"
+
+#include "mioapi.h"
+
+#include "mtapi.h"
+#include "celapi.h"
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_CORE_MEDIA_CTX \
+  (gst_core_media_ctx_get_type ())
+#define GST_CORE_MEDIA_CTX(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CORE_MEDIA_CTX, GstCoreMediaCtx))
+#define GST_CORE_MEDIA_CTX_CAST(obj) \
+  ((GstCoreMediaCtx *) (obj))
+#define GST_CORE_MEDIA_CTX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CORE_MEDIA_CTX, GstCoreMediaCtxClass))
+#define GST_IS_CORE_MEDIA_CTX(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CORE_MEDIA_CTX))
+#define GST_IS_CORE_MEDIA_CTX_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CORE_MEDIA_CTX))
+
+typedef struct _GstCoreMediaCtx GstCoreMediaCtx;
+typedef struct _GstCoreMediaCtxClass GstCoreMediaCtxClass;
+
+typedef enum _GstCoreMediaApi GstCoreMediaApi;
+
+struct _GstCoreMediaCtx
+{
+  GObject parent;
+
+  /* Common */
+  GstCVApi *cv;
+  GstCMApi *cm;
+
+  /* OS X */
+  GstMIOApi *mio;
+
+  /* iPhone */
+  GstMTApi *mt;
+  GstCelApi *cel;
+};
+
+struct _GstCoreMediaCtxClass
+{
+  GObjectClass parent_class;
+};
+
+enum _GstCoreMediaApi
+{
+  GST_API_CORE_VIDEO    = (1 << 0),
+  GST_API_CORE_MEDIA    = (1 << 1),
+  GST_API_VIDEO_TOOLBOX = (1 << 2),
+
+  GST_API_MIO           = (1 << 3),
+
+  GST_API_MEDIA_TOOLBOX = (1 << 4),
+  GST_API_CELESTIAL     = (1 << 5)
+};
+
+GType gst_core_media_ctx_get_type (void);
+
+GstCoreMediaCtx * gst_core_media_ctx_new (GstCoreMediaApi required_apis,
+    GError ** error);
+
+G_END_DECLS
+
+#endif
diff --git a/sys/applemedia-nonpublic/corevideobuffer.c b/sys/applemedia-nonpublic/corevideobuffer.c
new file mode 100644 (file)
index 0000000..072fe6b
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "corevideobuffer.h"
+
+static void
+gst_core_video_meta_free (GstCoreVideoMeta * meta, GstBuffer * buf)
+{
+  GstCVApi *cv = meta->ctx->cv;
+
+  if (meta->pixbuf != NULL) {
+    cv->CVPixelBufferUnlockBaseAddress (meta->pixbuf,
+        kCVPixelBufferLock_ReadOnly);
+  }
+
+  cv->CVBufferRelease (meta->cvbuf);
+  g_object_unref (meta->ctx);
+}
+
+GType
+gst_core_video_meta_api_get_type (void)
+{
+  static volatile GType type;
+  static const gchar *tags[] = { "memory", NULL };
+
+  if (g_once_init_enter (&type)) {
+    GType _type = gst_meta_api_type_register ("GstCoreVideoMetaAPI", tags);
+    g_once_init_leave (&type, _type);
+  }
+  return type;
+}
+
+static const GstMetaInfo *
+gst_core_video_meta_get_info (void)
+{
+  static const GstMetaInfo *core_video_meta_info = NULL;
+
+  if (g_once_init_enter (&core_video_meta_info)) {
+    const GstMetaInfo *meta = gst_meta_register (GST_CORE_VIDEO_META_API_TYPE,
+        "GstCoreVideoMeta", sizeof (GstCoreVideoMeta),
+        (GstMetaInitFunction) NULL,
+        (GstMetaFreeFunction) gst_core_video_meta_free,
+        (GstMetaTransformFunction) NULL);
+    g_once_init_leave (&core_video_meta_info, meta);
+  }
+  return core_video_meta_info;
+}
+
+GstBuffer *
+gst_core_video_buffer_new (GstCoreMediaCtx * ctx, CVBufferRef cvbuf,
+    GstVideoInfo * vinfo)
+{
+  GstCVApi *cv = ctx->cv;
+  void *data;
+  size_t size;
+  CVPixelBufferRef pixbuf = NULL;
+  GstBuffer *buf;
+  GstCoreVideoMeta *meta;
+  guint width, height, n_planes, i;
+  gsize offset[GST_VIDEO_MAX_PLANES];
+  gint stride[GST_VIDEO_MAX_PLANES];
+
+  if (CFGetTypeID (cvbuf) != cv->CVPixelBufferGetTypeID ())
+    /* TODO: Do we need to handle other buffer types? */
+    goto error;
+
+  pixbuf = (CVPixelBufferRef) cvbuf;
+
+  if (cv->CVPixelBufferLockBaseAddress (pixbuf,
+          kCVPixelBufferLock_ReadOnly) != kCVReturnSuccess) {
+    goto error;
+  }
+
+  buf = gst_buffer_new ();
+
+  /* add the corevideo meta to free the underlying corevideo buffer */
+  meta = (GstCoreVideoMeta *) gst_buffer_add_meta (buf,
+      gst_core_video_meta_get_info (), NULL);
+  meta->ctx = g_object_ref (ctx);
+  meta->cvbuf = cv->CVBufferRetain (cvbuf);
+  meta->pixbuf = pixbuf;
+
+  /* set stride, offset and size */
+  memset (&offset, 0, sizeof (offset));
+  memset (&stride, 0, sizeof (stride));
+
+  data = cv->CVPixelBufferGetBaseAddress (pixbuf);
+  height = cv->CVPixelBufferGetHeight (pixbuf);
+  if (cv->CVPixelBufferIsPlanar (pixbuf)) {
+    GstVideoInfo tmp_vinfo;
+
+    n_planes = cv->CVPixelBufferGetPlaneCount (pixbuf);
+    for (i = 0; i < n_planes; ++i)
+      stride[i] = cv->CVPixelBufferGetBytesPerRowOfPlane (pixbuf, i);
+
+    /* FIXME: don't hardcode NV12 */
+    gst_video_info_init (&tmp_vinfo);
+    gst_video_info_set_format (&tmp_vinfo,
+        GST_VIDEO_FORMAT_NV12, stride[0], height);
+    offset[1] = tmp_vinfo.offset[1];
+    size = tmp_vinfo.size;
+  } else {
+    n_planes = 1;
+    size = cv->CVPixelBufferGetBytesPerRow (pixbuf) * height;
+  }
+
+  gst_buffer_append_memory (buf,
+      gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, data,
+          size, 0, size, NULL, NULL));
+
+  if (vinfo) {
+    GstVideoMeta *video_meta;
+
+    width = vinfo->width;
+    video_meta =
+        gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE,
+        GST_VIDEO_FORMAT_NV12, width, height, n_planes, offset, stride);
+  }
+
+  return buf;
+
+error:
+  return NULL;
+}
diff --git a/sys/applemedia-nonpublic/corevideobuffer.h b/sys/applemedia-nonpublic/corevideobuffer.h
new file mode 100644 (file)
index 0000000..844d655
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_CORE_VIDEO_BUFFER_H__
+#define __GST_CORE_VIDEO_BUFFER_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideometa.h>
+
+#include "coremediactx.h"
+
+G_BEGIN_DECLS
+
+#define GST_CORE_VIDEO_META_API_TYPE (gst_core_video_meta_api_get_type())
+#define gst_buffer_get_core_video_meta(b) \
+  ((GstCoreVideoMeta*)gst_buffer_get_meta((b),GST_CORE_VIDEO_META_API_TYPE))
+
+typedef struct _GstCoreVideoMeta
+{
+  GstMeta meta;
+
+  GstCoreMediaCtx *ctx;
+  CVBufferRef cvbuf;
+  CVPixelBufferRef pixbuf;
+} GstCoreVideoMeta;
+
+GstBuffer * gst_core_video_buffer_new      (GstCoreMediaCtx * ctx,
+                                            CVBufferRef cvbuf,
+                                            GstVideoInfo *info);
+GType gst_core_video_meta_api_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_CORE_VIDEO_BUFFER_H__ */
diff --git a/sys/applemedia-nonpublic/cvapi.c b/sys/applemedia-nonpublic/cvapi.c
new file mode 100644 (file)
index 0000000..998428a
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "cvapi.h"
+
+#include "dynapi-internal.h"
+
+#define CV_FRAMEWORK_PATH "/System/Library/Frameworks/CoreVideo.framework/" \
+    "CoreVideo"
+
+G_DEFINE_TYPE (GstCVApi, gst_cv_api, GST_TYPE_DYN_API);
+
+static void
+gst_cv_api_init (GstCVApi * self)
+{
+}
+
+static void
+gst_cv_api_class_init (GstCVApiClass * klass)
+{
+}
+
+#define SYM_SPEC(name) GST_DYN_SYM_SPEC (GstCVApi, name)
+#define SYM_SPEC_OPTIONAL(name) GST_DYN_SYM_SPEC_OPTIONAL (GstCVApi, name)
+
+GstCVApi *
+gst_cv_api_obtain (GError ** error)
+{
+  static const GstDynSymSpec symbols[] = {
+    SYM_SPEC (CVBufferRelease),
+    SYM_SPEC (CVBufferRetain),
+
+    SYM_SPEC (CVPixelBufferCreateWithBytes),
+    SYM_SPEC (CVPixelBufferCreateWithPlanarBytes),
+    SYM_SPEC (CVPixelBufferGetBaseAddress),
+    SYM_SPEC (CVPixelBufferGetBaseAddressOfPlane),
+    SYM_SPEC (CVPixelBufferGetBytesPerRow),
+    SYM_SPEC (CVPixelBufferGetBytesPerRowOfPlane),
+    SYM_SPEC (CVPixelBufferGetHeight),
+    SYM_SPEC (CVPixelBufferGetHeightOfPlane),
+    SYM_SPEC_OPTIONAL (CVPixelBufferGetIOSurface),
+    SYM_SPEC (CVPixelBufferGetPlaneCount),
+    SYM_SPEC (CVPixelBufferGetTypeID),
+    SYM_SPEC (CVPixelBufferIsPlanar),
+    SYM_SPEC (CVPixelBufferLockBaseAddress),
+    SYM_SPEC (CVPixelBufferRelease),
+    SYM_SPEC (CVPixelBufferRetain),
+    SYM_SPEC (CVPixelBufferUnlockBaseAddress),
+
+    SYM_SPEC (kCVPixelBufferPixelFormatTypeKey),
+    SYM_SPEC (kCVPixelBufferWidthKey),
+    SYM_SPEC (kCVPixelBufferHeightKey),
+    SYM_SPEC (kCVPixelBufferBytesPerRowAlignmentKey),
+    SYM_SPEC (kCVPixelBufferPlaneAlignmentKey),
+
+    {NULL, 0},
+  };
+
+  return _gst_dyn_api_new (gst_cv_api_get_type (), CV_FRAMEWORK_PATH, symbols,
+      error);
+}
diff --git a/sys/applemedia-nonpublic/cvapi.h b/sys/applemedia-nonpublic/cvapi.h
new file mode 100644 (file)
index 0000000..63c8cba
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_CV_API_H__
+#define __GST_CV_API_H__
+
+#include "dynapi.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstCVApi GstCVApi;
+typedef struct _GstCVApiClass GstCVApiClass;
+
+typedef int32_t CVReturn;
+
+typedef uint64_t CVOptionFlags;
+
+typedef struct _CVBuffer * CVBufferRef;
+typedef CVBufferRef CVImageBufferRef;
+typedef CVImageBufferRef CVPixelBufferRef;
+
+typedef void (* CVPixelBufferReleaseBytesCallback) (void * releaseRefCon,
+    const void * baseAddress);
+
+enum _CVReturn
+{
+  kCVReturnSuccess = 0
+};
+
+enum _CVPixelFormatType
+{
+  kCVPixelFormatType_420YpCbCr8Planar             = 'y420',
+  kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange = '420v',
+  kCVPixelFormatType_422YpCbCr8Deprecated         = 'yuvs',
+  kCVPixelFormatType_422YpCbCr8                   = '2vuy'
+};
+
+enum _CVPixelBufferLockFlags
+{
+  kCVPixelBufferLock_ReadOnly = 0x00000001
+};
+
+struct _GstCVApi
+{
+  GstDynApi parent;
+
+  void (* CVBufferRelease) (CVBufferRef buffer);
+  CVBufferRef (* CVBufferRetain) (CVBufferRef buffer);
+
+  CVReturn (* CVPixelBufferCreateWithBytes)
+      (CFAllocatorRef allocator, size_t width, size_t height,
+      OSType pixelFormatType, void * baseAddress, size_t bytesPerRow,
+      CVPixelBufferReleaseBytesCallback releaseCallback,
+      void * releaseRefCon, CFDictionaryRef pixelBufferAttributes,
+      CVPixelBufferRef * pixelBufferOut);
+  CVReturn (* CVPixelBufferCreateWithPlanarBytes)
+      (CFAllocatorRef allocator, size_t width, size_t height,
+      OSType pixelFormatType, void * dataPtr, size_t dataSize,
+      size_t numberOfPlanes, void *planeBaseAddress[],
+      size_t planeWidth[], size_t planeHeight[],
+      size_t planeBytesPerRow[],
+      CVPixelBufferReleaseBytesCallback releaseCallback,
+      void * releaseRefCon, CFDictionaryRef pixelBufferAttributes,
+      CVPixelBufferRef * pixelBufferOut);
+  void * (* CVPixelBufferGetBaseAddress)
+      (CVPixelBufferRef pixelBuffer);
+  void * (* CVPixelBufferGetBaseAddressOfPlane)
+      (CVPixelBufferRef pixelBuffer, size_t planeIndex);
+  size_t (* CVPixelBufferGetBytesPerRow)
+      (CVPixelBufferRef pixelBuffer);
+  size_t (* CVPixelBufferGetBytesPerRowOfPlane)
+      (CVPixelBufferRef pixelBuffer, size_t planeIndex);
+  size_t (* CVPixelBufferGetHeight) (CVPixelBufferRef pixelBuffer);
+  size_t (* CVPixelBufferGetHeightOfPlane)
+      (CVPixelBufferRef pixelBuffer, size_t planeIndex);
+  void * (* CVPixelBufferGetIOSurface)
+      (CVPixelBufferRef pixelBuffer);
+  size_t (* CVPixelBufferGetPlaneCount)
+      (CVPixelBufferRef pixelBuffer);
+  CFTypeID (* CVPixelBufferGetTypeID) (void);
+  Boolean (* CVPixelBufferIsPlanar) (CVPixelBufferRef pixelBuffer);
+  CVReturn (* CVPixelBufferLockBaseAddress)
+      (CVPixelBufferRef pixelBuffer, CVOptionFlags lockFlags);
+  void (* CVPixelBufferRelease) (CVPixelBufferRef pixelBuffer);
+  CVPixelBufferRef (* CVPixelBufferRetain)
+      (CVPixelBufferRef pixelBuffer);
+  CVReturn (* CVPixelBufferUnlockBaseAddress)
+      (CVPixelBufferRef pixelBuffer, CVOptionFlags unlockFlags);
+
+  CFStringRef * kCVPixelBufferPixelFormatTypeKey;
+  CFStringRef * kCVPixelBufferWidthKey;
+  CFStringRef * kCVPixelBufferHeightKey;
+  CFStringRef * kCVPixelBufferBytesPerRowAlignmentKey;
+  CFStringRef * kCVPixelBufferPlaneAlignmentKey;
+};
+
+struct _GstCVApiClass
+{
+  GstDynApiClass parent_class;
+};
+
+GType gst_cv_api_get_type (void);
+
+GstCVApi * gst_cv_api_obtain (GError ** error);
+
+G_END_DECLS
+
+#endif
diff --git a/sys/applemedia-nonpublic/dynapi-internal.h b/sys/applemedia-nonpublic/dynapi-internal.h
new file mode 100644 (file)
index 0000000..adcd4f1
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_DYN_API_INTERNAL_H__
+#define __GST_DYN_API_INTERNAL_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstDynSymSpec       GstDynSymSpec;
+
+struct _GstDynSymSpec
+{
+  const gchar * name;
+  guint offset;
+  gboolean is_required;
+};
+
+gpointer _gst_dyn_api_new (GType derived_type, const gchar * filename,
+    const GstDynSymSpec * symbols, GError ** error);
+
+G_END_DECLS
+
+#endif
+
diff --git a/sys/applemedia-nonpublic/dynapi.c b/sys/applemedia-nonpublic/dynapi.c
new file mode 100644 (file)
index 0000000..2317f80
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "dynapi.h"
+
+#include "dynapi-internal.h"
+
+#include <gmodule.h>
+#include <gst/gst.h>
+
+GST_DEBUG_CATEGORY (gst_dyn_api_debug);
+#define GST_CAT_DEFAULT gst_dyn_api_debug
+
+enum
+{
+  PROP_0,
+  PROP_FILENAME
+};
+
+struct _GstDynApiPrivate
+{
+  gchar *filename;
+  GModule *module;
+};
+
+G_DEFINE_TYPE (GstDynApi, gst_dyn_api, G_TYPE_OBJECT);
+
+static void
+gst_dyn_api_init (GstDynApi * self)
+{
+  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GST_TYPE_DYN_API,
+      GstDynApiPrivate);
+}
+
+static void
+gst_dyn_api_dispose (GObject * object)
+{
+  GstDynApi *self = GST_DYN_API_CAST (object);
+  GstDynApiPrivate *priv = self->priv;
+
+  if (priv->module != NULL) {
+    g_module_close (priv->module);
+    priv->module = NULL;
+  }
+
+  G_OBJECT_CLASS (gst_dyn_api_parent_class)->dispose (object);
+}
+
+static void
+gst_dyn_api_finalize (GObject * object)
+{
+  GstDynApi *self = GST_DYN_API_CAST (object);
+  GstDynApiPrivate *priv = self->priv;
+
+  g_free (priv->filename);
+
+  G_OBJECT_CLASS (gst_dyn_api_parent_class)->finalize (object);
+}
+
+static void
+gst_dyn_api_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstDynApi *self = GST_DYN_API (object);
+
+  switch (prop_id) {
+    case PROP_FILENAME:
+      g_value_set_string (value, self->priv->filename);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_dyn_api_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstDynApi *self = GST_DYN_API (object);
+
+  switch (prop_id) {
+    case PROP_FILENAME:
+      g_free (self->priv->filename);
+      self->priv->filename = g_value_dup_string (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_dyn_api_class_init (GstDynApiClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->dispose = gst_dyn_api_dispose;
+  gobject_class->finalize = gst_dyn_api_finalize;
+  gobject_class->get_property = gst_dyn_api_get_property;
+  gobject_class->set_property = gst_dyn_api_set_property;
+
+  g_type_class_add_private (klass, sizeof (GstDynApiPrivate));
+
+  g_object_class_install_property (gobject_class, PROP_FILENAME,
+      g_param_spec_string ("filename", "Filename", "Filename", NULL,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+}
+
+gpointer
+_gst_dyn_api_new (GType derived_type, const gchar * filename,
+    const GstDynSymSpec * symbols, GError ** error)
+{
+  GstDynApi *api;
+  GstDynApiPrivate *priv;
+  guint i;
+  GArray *names_not_found;
+
+  api = g_object_new (derived_type, "filename", filename, NULL);
+  priv = api->priv;
+
+  priv->module = g_module_open (priv->filename, 0);
+  if (priv->module == NULL)
+    goto open_failed;
+
+  names_not_found = g_array_new (TRUE, FALSE, sizeof (gchar *));
+
+  for (i = 0; symbols[i].name != NULL; i++) {
+    const GstDynSymSpec *s = &symbols[i];
+    if (!g_module_symbol (priv->module, s->name,
+            (gpointer *) (((guint8 *) api) + s->offset)) && s->is_required) {
+      g_array_append_val (names_not_found, s->name);
+    }
+  }
+
+  if (names_not_found->len > 0)
+    goto one_or_more_name_not_found;
+
+  g_array_free (names_not_found, TRUE);
+
+  return api;
+
+  /* ERRORS */
+open_failed:
+  {
+    gchar *basename;
+
+    basename = g_path_get_basename (filename);
+    g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
+        "failed to open %s", basename);
+    g_free (basename);
+
+    goto any_error;
+  }
+one_or_more_name_not_found:
+  {
+    gchar *basename, *names_joined;
+
+    basename = g_path_get_basename (filename);
+    names_joined = g_strjoinv (", ", (gchar **) names_not_found->data);
+    g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
+        "missing %u symbol%s in %s: %s",
+        names_not_found->len, (names_not_found->len == 1) ? "" : "s",
+        basename, names_joined);
+    g_free (names_joined);
+    g_free (basename);
+    g_array_free (names_not_found, TRUE);
+
+    goto any_error;
+  }
+any_error:
+  {
+    g_object_unref (api);
+
+    return NULL;
+  }
+}
diff --git a/sys/applemedia-nonpublic/dynapi.h b/sys/applemedia-nonpublic/dynapi.h
new file mode 100644 (file)
index 0000000..b8eda85
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_DYN_API_H__
+#define __GST_DYN_API_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_DYN_API \
+  (gst_dyn_api_get_type ())
+#define GST_DYN_API(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DYN_API, GstDynApi))
+#define GST_DYN_API_CAST(obj) \
+  ((GstDynApi *) (obj))
+#define GST_DYN_API_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_DYN_API, GstDynApiClass))
+#define GST_IS_DYN_API(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DYN_API))
+#define GST_IS_DYN_API_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_DYN_API))
+
+#define GST_DYN_SYM_SPEC(type, name) \
+  { G_STRINGIFY (name), G_STRUCT_OFFSET (type, name), TRUE }
+#define GST_DYN_SYM_SPEC_OPTIONAL(type, name) \
+  { G_STRINGIFY (name), G_STRUCT_OFFSET (type, name), FALSE }
+
+typedef struct _GstDynApi GstDynApi;
+typedef struct _GstDynApiClass GstDynApiClass;
+typedef struct _GstDynApiPrivate GstDynApiPrivate;
+
+struct _GstDynApi
+{
+  GObject parent;
+
+  GstDynApiPrivate * priv;
+};
+
+struct _GstDynApiClass
+{
+  GObjectClass parent_class;
+};
+
+GType gst_dyn_api_get_type (void);
+
+G_END_DECLS
+
+#endif
diff --git a/sys/applemedia-nonpublic/mioapi.c b/sys/applemedia-nonpublic/mioapi.c
new file mode 100644 (file)
index 0000000..30d3d35
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "mioapi.h"
+
+#include "dynapi-internal.h"
+
+#define MIO_FRAMEWORK_PATH "/System/Library/PrivateFrameworks/" \
+    "CoreMediaIOServices.framework/CoreMediaIOServices"
+
+GType gst_mio_api_get_type (void);
+
+G_DEFINE_TYPE (GstMIOApi, gst_mio_api, GST_TYPE_DYN_API);
+
+static void
+gst_mio_api_init (GstMIOApi * self)
+{
+}
+
+static void
+gst_mio_api_class_init (GstMIOApiClass * klass)
+{
+}
+
+#define SYM_SPEC(name) GST_DYN_SYM_SPEC (GstMIOApi, name)
+
+GstMIOApi *
+gst_mio_api_obtain (GError ** error)
+{
+  static const GstDynSymSpec symbols[] = {
+    SYM_SPEC (TundraGraphCreate),
+    SYM_SPEC (TundraGraphRelease),
+    SYM_SPEC (TundraGraphCreateNode),
+    SYM_SPEC (TundraGraphGetNodeInfo),
+    SYM_SPEC (TundraGraphSetProperty),
+    SYM_SPEC (TundraGraphConnectNodeInput),
+    SYM_SPEC (TundraGraphInitialize),
+    SYM_SPEC (TundraGraphUninitialize),
+    SYM_SPEC (TundraGraphStart),
+    SYM_SPEC (TundraGraphStop),
+
+    SYM_SPEC (TundraObjectGetPropertyDataSize),
+    SYM_SPEC (TundraObjectGetPropertyData),
+    SYM_SPEC (TundraObjectIsPropertySettable),
+    SYM_SPEC (TundraObjectSetPropertyData),
+
+    SYM_SPEC (kTundraSampleBufferAttachmentKey_SequenceNumber),
+    SYM_SPEC (kTundraSampleBufferAttachmentKey_HostTime),
+
+    {NULL, 0},
+  };
+
+  return _gst_dyn_api_new (gst_mio_api_get_type (), MIO_FRAMEWORK_PATH, symbols,
+      error);
+}
+
+gpointer
+gst_mio_object_get_pointer (gint obj, TundraTargetSpec * pspec, GstMIOApi * mio)
+{
+  gpointer ptr;
+  guint sz;
+  TundraStatus status;
+
+  sz = sizeof (ptr);
+  status = mio->TundraObjectGetPropertyData (obj, pspec, 0, NULL, &sz, &ptr);
+  if (status != kTundraSuccess)
+    goto error;
+
+  return ptr;
+
+error:
+  return NULL;
+}
+
+gchar *
+gst_mio_object_get_string (gint obj, TundraTargetSpec * pspec, GstMIOApi * mio)
+{
+  gchar *result = NULL;
+  CFStringRef str;
+  guint size;
+  TundraStatus status;
+  CFRange range;
+
+  size = sizeof (str);
+  status = mio->TundraObjectGetPropertyData (obj, pspec, 0, NULL, &size, &str);
+  if (status != kTundraSuccess)
+    goto error;
+
+  range.location = 0;
+  range.length = CFStringGetLength (str);
+  result = g_malloc0 (range.length + 1);
+  CFStringGetBytes (str, range, kCFStringEncodingUTF8, 0, FALSE,
+      (UInt8 *) result, range.length, NULL);
+  CFRelease (str);
+
+  return result;
+
+error:
+  return NULL;
+}
+
+guint32
+gst_mio_object_get_uint32 (gint obj, TundraTargetSpec * pspec, GstMIOApi * mio)
+{
+  guint32 val;
+  guint size;
+  TundraStatus status;
+
+  size = sizeof (val);
+  status = mio->TundraObjectGetPropertyData (obj, pspec, 0, NULL, &size, &val);
+  if (status != kTundraSuccess)
+    goto error;
+
+  return val;
+
+error:
+  return 0;
+}
+
+GArray *
+gst_mio_object_get_array (gint obj, TundraTargetSpec * pspec,
+    guint element_size, GstMIOApi * mio)
+{
+  return gst_mio_object_get_array_full (obj, pspec, 0, NULL, element_size, mio);
+}
+
+GArray *
+gst_mio_object_get_array_full (gint obj, TundraTargetSpec * pspec,
+    guint ctx_size, gpointer ctx, guint element_size, GstMIOApi * mio)
+{
+  GArray *arr = NULL;
+  guint size, num_elements;
+  TundraStatus status;
+
+  status = mio->TundraObjectGetPropertyDataSize (obj, pspec, ctx_size, ctx,
+      &size);
+  if (status != kTundraSuccess)
+    goto error;
+  else if (size % element_size != 0)
+    goto error;
+
+  num_elements = size / element_size;
+  arr = g_array_sized_new (FALSE, TRUE, element_size, num_elements);
+  g_array_set_size (arr, num_elements);
+
+  status = mio->TundraObjectGetPropertyData (obj, pspec, ctx_size, ctx,
+      &size, arr->data);
+  if (status != kTundraSuccess)
+    goto error;
+
+  return arr;
+
+error:
+  if (arr != NULL)
+    g_array_free (arr, TRUE);
+  return NULL;
+}
+
+gchar *
+gst_mio_object_get_fourcc (gint obj, TundraTargetSpec * pspec, GstMIOApi * mio)
+{
+  guint32 fcc;
+  guint size;
+  TundraStatus status;
+
+  size = sizeof (fcc);
+  status = mio->TundraObjectGetPropertyData (obj, pspec, 0, NULL, &size, &fcc);
+  if (status != kTundraSuccess)
+    goto error;
+
+  return gst_mio_fourcc_to_string (fcc);
+
+error:
+  return NULL;
+}
+
+gpointer
+gst_mio_object_get_raw (gint obj, TundraTargetSpec * pspec, guint * size,
+    GstMIOApi * mio)
+{
+  gpointer data = NULL;
+  guint sz;
+  TundraStatus status;
+
+  status = mio->TundraObjectGetPropertyDataSize (obj, pspec, 0, NULL, &sz);
+  if (status != kTundraSuccess)
+    goto error;
+
+  data = g_malloc0 (sz);
+
+  status = mio->TundraObjectGetPropertyData (obj, pspec, 0, NULL, &sz, data);
+  if (status != kTundraSuccess)
+    goto error;
+
+  if (size != NULL)
+    *size = sz;
+  return data;
+
+error:
+  g_free (data);
+  if (size != NULL)
+    *size = 0;
+  return NULL;
+}
+
+gchar *
+gst_mio_fourcc_to_string (guint32 fcc)
+{
+  gchar *result;
+
+  result = g_malloc0 (5);
+  result[0] = (fcc >> 24) & 0xff;
+  result[1] = (fcc >> 16) & 0xff;
+  result[2] = (fcc >> 8) & 0xff;
+  result[3] = (fcc >> 0) & 0xff;
+
+  return result;
+}
diff --git a/sys/applemedia-nonpublic/mioapi.h b/sys/applemedia-nonpublic/mioapi.h
new file mode 100644 (file)
index 0000000..fe2cbd8
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_MIO_API_H__
+#define __GST_MIO_API_H__
+
+#include "cmapi.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstMIOApi GstMIOApi;
+typedef struct _GstMIOApiClass GstMIOApiClass;
+
+#define TUNDRA_SYSTEM_OBJECT_ID 1
+
+typedef int TundraObjectID;
+typedef int TundraDeviceID;
+typedef int TundraUnitID;
+
+typedef enum _TundraStatus TundraStatus;
+typedef enum _TundraVendor TundraVendor;
+typedef enum _TundraScope TundraScope;
+typedef enum _TundraUnit TundraUnit;
+typedef enum _TundraProperty TundraProperty;
+
+typedef enum _TundraDeviceTransportType TundraDeviceTransportType;
+
+typedef struct _TundraTargetSpec TundraTargetSpec;
+typedef struct _TundraFramerate TundraFramerate;
+
+typedef struct _TundraGraph TundraGraph;
+typedef struct _TundraNode TundraNode;
+
+typedef struct _TundraOutputDelegate TundraOutputDelegate;
+
+enum _TundraStatus
+{
+  kTundraSuccess = 0,
+  kTundraNotSupported = -67456
+};
+
+enum _TundraVendor
+{
+  kTundraVendorApple = 'appl'
+};
+
+enum _TundraScope
+{
+  kTundraScopeGlobal = 'glob',
+  kTundraScopeDAL    = 'dal ',
+  kTundraScope2PRC   = '2prc', /* TODO: Investigate this one */
+  kTundraScopeInput  = 'inpt',
+  kTundraScopeVSyn   = 'vsyn'
+};
+
+enum _TundraUnit
+{
+  kTundraUnitInput  = 'tinp',
+  kTundraUnitOutput = 'tout',
+  kTundraUnitSync   = 'tefc'
+};
+
+enum _TundraProperty
+{
+  kTundraSystemPropertyDevices = 'dev#',
+
+  kTundraObjectPropertyClass = 'clas',
+  kTundraObjectPropertyCreator = 'oplg',
+  kTundraObjectPropertyName = 'lnam',
+  kTundraObjectPropertyUID = 'uid ',
+  kTundraObjectPropertyVendor = 'lmak',
+
+  kTundraDevicePropertyConfigApp = 'capp', /* CFString: com.apple.mediaio.TundraDeviceSetup */
+  kTundraDevicePropertyExclusiveMode = 'ixna',
+  kTundraDevicePropertyHogMode = 'oink',
+  kTundraDevicePropertyModelUID = 'muid',
+  kTundraDevicePropertyStreams = 'stm#',
+  kTundraDevicePropertySuspendedByUser = 'sbyu',
+  kTundraDevicePropertyTransportType = 'tran',
+
+  kTundraStreamPropertyFormatDescriptions = 'pfta',
+  kTundraStreamPropertyFormatDescription = 'pft ',
+  kTundraStreamPropertyFrameRates = 'nfr#',
+  kTundraStreamPropertyFrameRate = 'nfrt'
+};
+
+struct _TundraTargetSpec
+{
+  FourCharCode name;
+  FourCharCode scope;
+  FourCharCode vendor;
+  FourCharCode unk1;
+  FourCharCode unk2;
+};
+
+struct _TundraFramerate
+{
+  gdouble value;
+};
+
+enum _TundraUnitProperty
+{
+  kTundraInputPropertyDeviceID                = 302,
+
+  kTundraOutputPropertyDelegate               = 5903,
+
+  kTundraInputUnitProperty_SourcePath         = 6780,
+
+  kTundraSyncPropertyClockProvider            = 7100,
+  kTundraSyncPropertyMasterSynchronizer       = 7102,
+  kTundraSyncPropertySynchronizationDirection = 7104
+};
+
+enum _TundraDeviceTransportType
+{
+  kTundraDeviceTransportInvalid = 0,
+  kTundraDeviceTransportBuiltin = 'bltn',
+  kTundraDeviceTransportScreen  = 'scrn',
+  kTundraDeviceTransportUSB     = 'usb ',
+};
+
+typedef TundraStatus (* TundraOutputRenderFunc) (gpointer instance,
+    gpointer unk1, gpointer unk2, gpointer unk3, CMSampleBufferRef sampleBuf);
+typedef TundraStatus (* TundraOutputInitializeFunc) (gpointer instance);
+typedef TundraStatus (* TundraOutputUninitializeFunc) (gpointer instance);
+typedef TundraStatus (* TundraOutputStartFunc) (gpointer instance);
+typedef TundraStatus (* TundraOutputStopFunc) (gpointer instance);
+typedef TundraStatus (* TundraOutputResetFunc) (gpointer instance);
+typedef TundraStatus (* TundraOutputDeallocateFunc) (gpointer instance);
+typedef gboolean (* TundraOutputCanRenderNowFunc) (gpointer instance,
+    guint * unk);
+typedef CFArrayRef (* TundraOutputAvailableFormatsFunc) (gpointer instance,
+    gboolean ensureOnly);
+typedef TundraStatus (* TundraOutputCopyClockFunc) (gpointer instance);
+typedef TundraStatus (* TundraOutputGetPropertyInfoFunc) (gpointer instance,
+    guint propId);
+typedef TundraStatus (* TundraOutputGetPropertyFunc) (gpointer instance,
+    guint propId);
+typedef TundraStatus (* TundraOutputSetPropertyFunc) (gpointer instance,
+    guint propId);
+
+#pragma pack(push, 1)
+
+struct _TundraOutputDelegate
+{
+  int unk1;
+  gpointer instance;
+  TundraOutputRenderFunc Render;
+  TundraOutputInitializeFunc Initialize;
+  TundraOutputUninitializeFunc Uninitialize;
+  TundraOutputStartFunc Start;
+  TundraOutputStopFunc Stop;
+  TundraOutputResetFunc Reset;
+  TundraOutputDeallocateFunc Deallocate;
+  TundraOutputCanRenderNowFunc CanRenderNow;
+  TundraOutputAvailableFormatsFunc AvailableFormats;
+  TundraOutputCopyClockFunc CopyClock;
+  TundraOutputGetPropertyInfoFunc GetPropertyInfo;
+  TundraOutputGetPropertyFunc GetProperty;
+  TundraOutputSetPropertyFunc SetProperty;
+};
+
+#pragma pack(pop)
+
+struct _GstMIOApi
+{
+  GstDynApi parent;
+
+  TundraStatus (* TundraGraphCreate) (CFAllocatorRef allocator,
+      TundraGraph ** graph);
+  void (* TundraGraphRelease) (TundraGraph * graph);
+  TundraStatus (* TundraGraphCreateNode) (TundraGraph * graph,
+      gint nodeId, UInt32 unk1, UInt32 unk2, TundraTargetSpec * spec,
+      UInt32 unk3, TundraUnitID * node);
+  TundraStatus (* TundraGraphGetNodeInfo) (TundraGraph * graph,
+      gint nodeId, UInt32 unk1, UInt32 unk2, UInt32 unk3, UInt32 unk4,
+      gpointer * info);
+  TundraStatus (* TundraGraphSetProperty) (TundraGraph * graph,
+      gint nodeId, UInt32 unk1, guint propId, UInt32 unk2, UInt32 unk3,
+      gpointer data, guint size);
+  TundraStatus (* TundraGraphConnectNodeInput) (TundraGraph * graph,
+      TundraUnitID from_node, guint from_bus,
+      TundraUnitID to_node, guint to_bus);
+  TundraStatus (* TundraGraphInitialize) (TundraGraph * graph);
+  TundraStatus (* TundraGraphUninitialize) (TundraGraph * graph);
+  TundraStatus (* TundraGraphStart) (TundraGraph * graph);
+  TundraStatus (* TundraGraphStop) (TundraGraph * graph);
+
+  TundraStatus (* TundraObjectGetPropertyDataSize) (TundraObjectID obj,
+      TundraTargetSpec * spec, UInt32 contextSize, void * context, guint * size);
+  TundraStatus (* TundraObjectGetPropertyData) (TundraObjectID obj,
+      TundraTargetSpec * spec, UInt32 contextSize, void * context, guint * size,
+      gpointer data);
+  TundraStatus (* TundraObjectIsPropertySettable) (TundraObjectID obj,
+      TundraTargetSpec * spec, Boolean *isSettable);
+  TundraStatus (* TundraObjectSetPropertyData) (TundraObjectID obj,
+      TundraTargetSpec * spec, gpointer unk1, gpointer unk2, guint size,
+      gpointer data);
+
+  CFStringRef * kTundraSampleBufferAttachmentKey_SequenceNumber;
+  CFStringRef * kTundraSampleBufferAttachmentKey_HostTime;
+};
+
+struct _GstMIOApiClass
+{
+  GstDynApiClass parent_class;
+};
+
+GstMIOApi * gst_mio_api_obtain (GError ** error);
+
+gpointer gst_mio_object_get_pointer (gint obj, TundraTargetSpec * pspec,
+    GstMIOApi * mio);
+gchar * gst_mio_object_get_string (gint obj, TundraTargetSpec * pspec,
+    GstMIOApi * mio);
+guint32 gst_mio_object_get_uint32 (gint obj, TundraTargetSpec * pspec,
+    GstMIOApi * mio);
+gchar * gst_mio_object_get_fourcc (gint obj, TundraTargetSpec * pspec,
+    GstMIOApi * mio);
+GArray * gst_mio_object_get_array (gint obj, TundraTargetSpec * pspec,
+    guint element_size, GstMIOApi * mio);
+GArray * gst_mio_object_get_array_full (gint obj, TundraTargetSpec * pspec,
+    guint ctx_size, gpointer ctx, guint element_size, GstMIOApi * mio);
+gpointer gst_mio_object_get_raw (gint obj, TundraTargetSpec * pspec,
+    guint * size, GstMIOApi * mio);
+
+gchar * gst_mio_fourcc_to_string (guint32 fcc);
+
+G_END_DECLS
+
+#endif
diff --git a/sys/applemedia-nonpublic/miovideodevice.c b/sys/applemedia-nonpublic/miovideodevice.c
new file mode 100644 (file)
index 0000000..252c718
--- /dev/null
@@ -0,0 +1,846 @@
+/*
+ * Copyright (C) 2009 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *               2009 Knut Inge Hvidsten <knuhvids@cisco.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "miovideodevice.h"
+
+#include <gst/video/video.h>
+
+#include <unistd.h>
+
+GST_DEBUG_CATEGORY_EXTERN (gst_mio_video_src_debug);
+#define GST_CAT_DEFAULT gst_mio_video_src_debug
+
+enum
+{
+  PROP_0,
+  PROP_CONTEXT,
+  PROP_HANDLE,
+  PROP_UID,
+  PROP_NAME,
+  PROP_TRANSPORT
+};
+
+G_DEFINE_TYPE (GstMIOVideoDevice, gst_mio_video_device, G_TYPE_OBJECT);
+
+typedef struct _GstMIOVideoFormat GstMIOVideoFormat;
+typedef struct _GstMIOSetFormatCtx GstMIOSetFormatCtx;
+typedef struct _GstMIOFindRateCtx GstMIOFindRateCtx;
+
+struct _GstMIOVideoFormat
+{
+  TundraObjectID stream;
+  CMFormatDescriptionRef desc;
+
+  UInt32 type;
+  CMVideoDimensions dim;
+};
+
+struct _GstMIOSetFormatCtx
+{
+  UInt32 format;
+  gint width, height;
+  gint fps_n, fps_d;
+  gboolean success;
+};
+
+struct _GstMIOFindRateCtx
+{
+  gdouble needle;
+  gdouble closest_match;
+  gboolean success;
+};
+
+static void gst_mio_video_device_collect_format (GstMIOVideoDevice * self,
+    GstMIOVideoFormat * format, gpointer user_data);
+static GstStructure *gst_mio_video_device_format_basics_to_structure
+    (GstMIOVideoDevice * self, GstMIOVideoFormat * format);
+static gboolean gst_mio_video_device_add_framerates_to_structure
+    (GstMIOVideoDevice * self, GstMIOVideoFormat * format, GstStructure * s);
+static void gst_mio_video_device_add_pixel_aspect_to_structure
+    (GstMIOVideoDevice * self, GstMIOVideoFormat * format, GstStructure * s);
+
+static void gst_mio_video_device_append_framerate (GstMIOVideoDevice * self,
+    GstMIOVideoFormat * format, TundraFramerate * rate, gpointer user_data);
+static void gst_mio_video_device_framerate_to_fraction_value
+    (TundraFramerate * rate, GValue * fract);
+static gdouble gst_mio_video_device_round_to_whole_hundreths (gdouble value);
+static void gst_mio_video_device_guess_pixel_aspect_ratio
+    (gint width, gint height, gint * par_width, gint * par_height);
+
+static void gst_mio_video_device_activate_matching_format
+    (GstMIOVideoDevice * self, GstMIOVideoFormat * format, gpointer user_data);
+static void gst_mio_video_device_find_closest_framerate
+    (GstMIOVideoDevice * self, GstMIOVideoFormat * format,
+    TundraFramerate * rate, gpointer user_data);
+
+typedef void (*GstMIOVideoDeviceEachFormatFunc) (GstMIOVideoDevice * self,
+    GstMIOVideoFormat * format, gpointer user_data);
+typedef void (*GstMIOVideoDeviceEachFramerateFunc) (GstMIOVideoDevice * self,
+    GstMIOVideoFormat * format, TundraFramerate * rate, gpointer user_data);
+static void gst_mio_video_device_formats_foreach (GstMIOVideoDevice * self,
+    GstMIOVideoDeviceEachFormatFunc func, gpointer user_data);
+static void gst_mio_video_device_format_framerates_foreach
+    (GstMIOVideoDevice * self, GstMIOVideoFormat * format,
+    GstMIOVideoDeviceEachFramerateFunc func, gpointer user_data);
+
+static gint gst_mio_video_device_compare (GstMIOVideoDevice * a,
+    GstMIOVideoDevice * b);
+static gint gst_mio_video_device_calculate_score (GstMIOVideoDevice * device);
+
+static void
+gst_mio_video_device_init (GstMIOVideoDevice * self)
+{
+}
+
+static void
+gst_mio_video_device_dispose (GObject * object)
+{
+  GstMIOVideoDevice *self = GST_MIO_VIDEO_DEVICE_CAST (object);
+
+  if (self->cached_caps != NULL) {
+    gst_caps_unref (self->cached_caps);
+    self->cached_caps = NULL;
+  }
+
+  G_OBJECT_CLASS (gst_mio_video_device_parent_class)->dispose (object);
+}
+
+static void
+gst_mio_video_device_finalize (GObject * object)
+{
+  GstMIOVideoDevice *self = GST_MIO_VIDEO_DEVICE_CAST (object);
+
+  g_free (self->cached_uid);
+  g_free (self->cached_name);
+
+  G_OBJECT_CLASS (gst_mio_video_device_parent_class)->finalize (object);
+}
+
+static void
+gst_mio_video_device_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstMIOVideoDevice *self = GST_MIO_VIDEO_DEVICE (object);
+
+  switch (prop_id) {
+    case PROP_CONTEXT:
+      g_value_set_pointer (value, self->ctx);
+      break;
+    case PROP_HANDLE:
+      g_value_set_int (value, gst_mio_video_device_get_handle (self));
+      break;
+    case PROP_UID:
+      g_value_set_string (value, gst_mio_video_device_get_uid (self));
+      break;
+    case PROP_NAME:
+      g_value_set_string (value, gst_mio_video_device_get_name (self));
+      break;
+    case PROP_TRANSPORT:
+      g_value_set_uint (value, gst_mio_video_device_get_transport_type (self));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_mio_video_device_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstMIOVideoDevice *self = GST_MIO_VIDEO_DEVICE (object);
+
+  switch (prop_id) {
+    case PROP_CONTEXT:
+      self->ctx = g_value_get_pointer (value);
+      break;
+    case PROP_HANDLE:
+      self->handle = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+TundraObjectID
+gst_mio_video_device_get_handle (GstMIOVideoDevice * self)
+{
+  return self->handle;
+}
+
+const gchar *
+gst_mio_video_device_get_uid (GstMIOVideoDevice * self)
+{
+  if (self->cached_uid == NULL) {
+    TundraTargetSpec pspec = { 0, };
+
+    pspec.name = kTundraObjectPropertyUID;
+    pspec.scope = kTundraScopeGlobal;
+    self->cached_uid =
+        gst_mio_object_get_string (self->handle, &pspec, self->ctx->mio);
+  }
+
+  return self->cached_uid;
+}
+
+const gchar *
+gst_mio_video_device_get_name (GstMIOVideoDevice * self)
+{
+  if (self->cached_name == NULL) {
+    TundraTargetSpec pspec = { 0, };
+
+    pspec.name = kTundraObjectPropertyName;
+    pspec.scope = kTundraScopeGlobal;
+    self->cached_name =
+        gst_mio_object_get_string (self->handle, &pspec, self->ctx->mio);
+  }
+
+  return self->cached_name;
+}
+
+TundraDeviceTransportType
+gst_mio_video_device_get_transport_type (GstMIOVideoDevice * self)
+{
+  if (self->cached_transport == kTundraDeviceTransportInvalid) {
+    TundraTargetSpec pspec = { 0, };
+
+    pspec.name = kTundraDevicePropertyTransportType;
+    pspec.scope = kTundraScopeGlobal;
+    self->cached_transport =
+        gst_mio_object_get_uint32 (self->handle, &pspec, self->ctx->mio);
+  }
+
+  return self->cached_transport;
+}
+
+gboolean
+gst_mio_video_device_open (GstMIOVideoDevice * self)
+{
+  /* nothing for now */
+  return TRUE;
+}
+
+void
+gst_mio_video_device_close (GstMIOVideoDevice * self)
+{
+  /* nothing for now */
+}
+
+GstCaps *
+gst_mio_video_device_get_available_caps (GstMIOVideoDevice * self)
+{
+  if (self->cached_caps == NULL) {
+    GstCaps *caps;
+
+    caps = gst_caps_new_empty ();
+    gst_mio_video_device_formats_foreach (self,
+        gst_mio_video_device_collect_format, caps);
+
+    self->cached_caps = caps;
+  }
+
+  return self->cached_caps;
+}
+
+static void
+gst_mio_video_device_collect_format (GstMIOVideoDevice * self,
+    GstMIOVideoFormat * format, gpointer user_data)
+{
+  GstCaps *caps = user_data;
+  GstStructure *s;
+
+  s = gst_mio_video_device_format_basics_to_structure (self, format);
+  if (s == NULL)
+    goto unsupported_format;
+
+  if (!gst_mio_video_device_add_framerates_to_structure (self, format, s))
+    goto no_framerates;
+
+  gst_mio_video_device_add_pixel_aspect_to_structure (self, format, s);
+
+  gst_caps_append_structure (caps, s);
+
+  return;
+
+  /* ERRORS */
+unsupported_format:
+  {
+    gchar *fcc;
+
+    fcc = gst_mio_fourcc_to_string (format->type);
+    GST_WARNING ("skipping unsupported format %s", fcc);
+    g_free (fcc);
+
+    return;
+  }
+no_framerates:
+  {
+    GST_WARNING ("no framerates?");
+
+    gst_structure_free (s);
+
+    return;
+  }
+}
+
+static GstStructure *
+gst_mio_video_device_format_basics_to_structure (GstMIOVideoDevice * self,
+    GstMIOVideoFormat * format)
+{
+  GstStructure *s;
+
+  switch (format->type) {
+    case kCVPixelFormatType_422YpCbCr8:
+    case kCVPixelFormatType_422YpCbCr8Deprecated:
+    {
+      guint fcc;
+
+      if (format->type == kCVPixelFormatType_422YpCbCr8)
+        fcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
+      else
+        fcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
+
+      s = gst_structure_new ("video/x-raw-yuv",
+          "format", GST_TYPE_FOURCC, fcc,
+          "width", G_TYPE_INT, format->dim.width,
+          "height", G_TYPE_INT, format->dim.height, NULL);
+      break;
+    }
+    case kFigVideoCodecType_JPEG_OpenDML:
+    {
+      s = gst_structure_new ("image/jpeg",
+          "width", G_TYPE_INT, format->dim.width,
+          "height", G_TYPE_INT, format->dim.height, NULL);
+      break;
+    }
+    default:
+      s = NULL;
+      break;
+  }
+
+  return s;
+}
+
+static gboolean
+gst_mio_video_device_add_framerates_to_structure (GstMIOVideoDevice * self,
+    GstMIOVideoFormat * format, GstStructure * s)
+{
+  GValue rates = { 0, };
+  const GValue *rates_value;
+
+  g_value_init (&rates, GST_TYPE_LIST);
+
+  gst_mio_video_device_format_framerates_foreach (self, format,
+      gst_mio_video_device_append_framerate, &rates);
+  if (gst_value_list_get_size (&rates) == 0)
+    goto no_framerates;
+
+  if (gst_value_list_get_size (&rates) > 1)
+    rates_value = &rates;
+  else
+    rates_value = gst_value_list_get_value (&rates, 0);
+  gst_structure_set_value (s, "framerate", rates_value);
+
+  g_value_unset (&rates);
+
+  return TRUE;
+
+  /* ERRORS */
+no_framerates:
+  {
+    g_value_unset (&rates);
+    return FALSE;
+  }
+}
+
+static void
+gst_mio_video_device_add_pixel_aspect_to_structure (GstMIOVideoDevice * self,
+    GstMIOVideoFormat * format, GstStructure * s)
+{
+  gint par_width, par_height;
+
+  gst_mio_video_device_guess_pixel_aspect_ratio
+      (format->dim.width, format->dim.height, &par_width, &par_height);
+
+  gst_structure_set (s, "pixel-aspect-ratio",
+      GST_TYPE_FRACTION, par_width, par_height, NULL);
+}
+
+static void
+gst_mio_video_device_append_framerate (GstMIOVideoDevice * self,
+    GstMIOVideoFormat * format, TundraFramerate * rate, gpointer user_data)
+{
+  GValue *rates = user_data;
+  GValue value = { 0, };
+
+  g_value_init (&value, GST_TYPE_FRACTION);
+  gst_mio_video_device_framerate_to_fraction_value (rate, &value);
+  gst_value_list_append_value (rates, &value);
+  g_value_unset (&value);
+}
+
+static void
+gst_mio_video_device_framerate_to_fraction_value (TundraFramerate * rate,
+    GValue * fract)
+{
+  gdouble rounded;
+  gint n, d;
+
+  rounded = gst_mio_video_device_round_to_whole_hundreths (rate->value);
+  gst_util_double_to_fraction (rounded, &n, &d);
+  gst_value_set_fraction (fract, n, d);
+}
+
+static gdouble
+gst_mio_video_device_round_to_whole_hundreths (gdouble value)
+{
+  gdouble m, x, y, z;
+
+  m = 0.01;
+  x = value;
+  y = floor ((x / m) + 0.5);
+  z = y * m;
+
+  return z;
+}
+
+static void
+gst_mio_video_device_guess_pixel_aspect_ratio (gint width, gint height,
+    gint * par_width, gint * par_height)
+{
+  /*
+   * As we dont have access to the actual pixel aspect, we will try to do a
+   * best-effort guess. The guess is based on most sensors being either 4/3
+   * or 16/9, and most pixel aspects being close to 1/1.
+   */
+
+  if (width == 768 && height == 448) {  /* special case for w448p */
+    *par_width = 28;
+    *par_height = 27;
+  } else {
+    if (((gdouble) width / (gdouble) height) < 1.2778) {
+      *par_width = 12;
+      *par_height = 11;
+    } else {
+      *par_width = 1;
+      *par_height = 1;
+    }
+  }
+}
+
+gboolean
+gst_mio_video_device_set_caps (GstMIOVideoDevice * self, GstCaps * caps)
+{
+  GstVideoFormat format;
+  GstMIOSetFormatCtx ctx = { 0, };
+
+  if (gst_video_format_parse_caps (caps, &format, &ctx.width, &ctx.height)) {
+    if (format == GST_VIDEO_FORMAT_UYVY)
+      ctx.format = kCVPixelFormatType_422YpCbCr8;
+    else if (format == GST_VIDEO_FORMAT_YUY2)
+      ctx.format = kCVPixelFormatType_422YpCbCr8Deprecated;
+    else
+      g_assert_not_reached ();
+  } else {
+    GstStructure *s;
+
+    s = gst_caps_get_structure (caps, 0);
+    g_assert (gst_structure_has_name (s, "image/jpeg"));
+    gst_structure_get_int (s, "width", &ctx.width);
+    gst_structure_get_int (s, "height", &ctx.height);
+
+    ctx.format = kFigVideoCodecType_JPEG_OpenDML;
+  }
+
+  gst_video_parse_caps_framerate (caps, &ctx.fps_n, &ctx.fps_d);
+
+  gst_mio_video_device_formats_foreach (self,
+      gst_mio_video_device_activate_matching_format, &ctx);
+
+  return ctx.success;
+}
+
+static void
+gst_mio_video_device_activate_matching_format (GstMIOVideoDevice * self,
+    GstMIOVideoFormat * format, gpointer user_data)
+{
+  GstMIOSetFormatCtx *ctx = user_data;
+  GstMIOFindRateCtx find_ctx;
+  TundraTargetSpec spec = { 0, };
+  TundraStatus status;
+
+  if (format->type != ctx->format)
+    return;
+  else if (format->dim.width != ctx->width)
+    return;
+  else if (format->dim.height != ctx->height)
+    return;
+
+  find_ctx.needle = (gdouble) ctx->fps_n / (gdouble) ctx->fps_d;
+  find_ctx.closest_match = 0.0;
+  find_ctx.success = FALSE;
+  gst_mio_video_device_format_framerates_foreach (self, format,
+      gst_mio_video_device_find_closest_framerate, &find_ctx);
+  if (!find_ctx.success)
+    goto no_matching_framerate_found;
+
+  spec.scope = kTundraScopeInput;
+
+  spec.name = kTundraStreamPropertyFormatDescription;
+  status = self->ctx->mio->TundraObjectSetPropertyData (format->stream, &spec,
+      NULL, NULL, sizeof (format->desc), &format->desc);
+  if (status != kTundraSuccess)
+    goto failed_to_set_format;
+
+  spec.name = kTundraStreamPropertyFrameRate;
+  status = self->ctx->mio->TundraObjectSetPropertyData (format->stream, &spec,
+      NULL, NULL, sizeof (find_ctx.closest_match), &find_ctx.closest_match);
+  if (status != kTundraSuccess)
+    goto failed_to_set_framerate;
+
+  self->selected_format = format->desc;
+  self->selected_fps_n = ctx->fps_n;
+  self->selected_fps_d = ctx->fps_d;
+
+  ctx->success = TRUE;
+  return;
+
+  /* ERRORS */
+no_matching_framerate_found:
+  {
+    GST_ERROR ("no matching framerate found");
+    return;
+  }
+failed_to_set_format:
+  {
+    GST_ERROR ("failed to set format: 0x%08x", status);
+    return;
+  }
+failed_to_set_framerate:
+  {
+    GST_ERROR ("failed to set framerate: 0x%08x", status);
+    return;
+  }
+}
+
+static void
+gst_mio_video_device_find_closest_framerate (GstMIOVideoDevice * self,
+    GstMIOVideoFormat * format, TundraFramerate * rate, gpointer user_data)
+{
+  GstMIOFindRateCtx *ctx = user_data;
+
+  if (fabs (rate->value - ctx->needle) <= 0.1) {
+    ctx->closest_match = rate->value;
+    ctx->success = TRUE;
+  }
+}
+
+CMFormatDescriptionRef
+gst_mio_video_device_get_selected_format (GstMIOVideoDevice * self)
+{
+  return self->selected_format;
+}
+
+GstClockTime
+gst_mio_video_device_get_duration (GstMIOVideoDevice * self)
+{
+  return gst_util_uint64_scale_int (GST_SECOND,
+      self->selected_fps_d, self->selected_fps_n);
+}
+
+static void
+gst_mio_video_device_formats_foreach (GstMIOVideoDevice * self,
+    GstMIOVideoDeviceEachFormatFunc func, gpointer user_data)
+{
+  GstCMApi *cm = self->ctx->cm;
+  GstMIOApi *mio = self->ctx->mio;
+  TundraTargetSpec spec = { 0, };
+  GArray *streams;
+  guint stream_idx;
+
+  spec.name = kTundraDevicePropertyStreams;
+  spec.scope = kTundraScopeInput;
+  streams = gst_mio_object_get_array (self->handle, &spec,
+      sizeof (TundraObjectID), mio);
+
+  /* TODO: We only consider the first stream for now */
+  for (stream_idx = 0; stream_idx != MIN (streams->len, 1); stream_idx++) {
+    TundraObjectID stream;
+    CFArrayRef formats;
+    CFIndex num_formats, fmt_idx;
+
+    stream = g_array_index (streams, TundraObjectID, stream_idx);
+
+    spec.name = kTundraStreamPropertyFormatDescriptions;
+    spec.scope = kTundraScopeInput;
+
+    formats = gst_mio_object_get_pointer (stream, &spec, mio);
+    num_formats = CFArrayGetCount (formats);
+
+    for (fmt_idx = 0; fmt_idx != num_formats; fmt_idx++) {
+      GstMIOVideoFormat fmt;
+
+      fmt.stream = stream;
+      fmt.desc = (CMFormatDescriptionRef)
+          CFArrayGetValueAtIndex (formats, fmt_idx);
+      if (cm->CMFormatDescriptionGetMediaType (fmt.desc) != kFigMediaTypeVideo)
+        continue;
+      fmt.type = cm->CMFormatDescriptionGetMediaSubType (fmt.desc);
+      fmt.dim = cm->CMVideoFormatDescriptionGetDimensions (fmt.desc);
+
+      func (self, &fmt, user_data);
+    }
+  }
+
+  g_array_free (streams, TRUE);
+}
+
+static void
+gst_mio_video_device_format_framerates_foreach (GstMIOVideoDevice * self,
+    GstMIOVideoFormat * format, GstMIOVideoDeviceEachFramerateFunc func,
+    gpointer user_data)
+{
+  TundraTargetSpec spec = { 0, };
+  GArray *rates;
+  guint rate_idx;
+
+  spec.name = kTundraStreamPropertyFrameRates;
+  spec.scope = kTundraScopeInput;
+  rates = gst_mio_object_get_array_full (format->stream, &spec,
+      sizeof (format->desc), &format->desc, sizeof (TundraFramerate),
+      self->ctx->mio);
+
+  for (rate_idx = 0; rate_idx != rates->len; rate_idx++) {
+    TundraFramerate *rate;
+
+    rate = &g_array_index (rates, TundraFramerate, rate_idx);
+
+    func (self, format, rate, user_data);
+  }
+
+  g_array_free (rates, TRUE);
+}
+
+void
+gst_mio_video_device_print_debug_info (GstMIOVideoDevice * self)
+{
+  GstCMApi *cm = self->ctx->cm;
+  GstMIOApi *mio = self->ctx->mio;
+  TundraTargetSpec spec = { 0, };
+  gchar *str;
+  GArray *streams;
+  guint stream_idx;
+
+  g_print ("Device %p with handle %d\n", self, self->handle);
+
+  spec.scope = kTundraScopeGlobal;
+
+  spec.name = kTundraObjectPropertyClass;
+  str = gst_mio_object_get_fourcc (self->handle, &spec, mio);
+  g_print ("  Class: '%s'\n", str);
+  g_free (str);
+
+  spec.name = kTundraObjectPropertyCreator;
+  str = gst_mio_object_get_string (self->handle, &spec, mio);
+  g_print ("  Creator: \"%s\"\n", str);
+  g_free (str);
+
+  spec.name = kTundraDevicePropertyModelUID;
+  str = gst_mio_object_get_string (self->handle, &spec, mio);
+  g_print ("  Model UID: \"%s\"\n", str);
+  g_free (str);
+
+  spec.name = kTundraDevicePropertyTransportType;
+  str = gst_mio_object_get_fourcc (self->handle, &spec, mio);
+  g_print ("  Transport Type: '%s'\n", str);
+  g_free (str);
+
+  g_print ("  Streams:\n");
+  spec.name = kTundraDevicePropertyStreams;
+  spec.scope = kTundraScopeInput;
+  streams = gst_mio_object_get_array (self->handle, &spec,
+      sizeof (TundraObjectID), mio);
+  for (stream_idx = 0; stream_idx != streams->len; stream_idx++) {
+    TundraObjectID stream;
+    CFArrayRef formats;
+    CFIndex num_formats, fmt_idx;
+
+    stream = g_array_index (streams, TundraObjectID, stream_idx);
+
+    g_print ("    stream[%u] = %d\n", stream_idx, stream);
+
+    spec.scope = kTundraScopeInput;
+    spec.name = kTundraStreamPropertyFormatDescriptions;
+
+    formats = gst_mio_object_get_pointer (stream, &spec, mio);
+    num_formats = CFArrayGetCount (formats);
+
+    g_print ("      <%u formats>\n", (guint) num_formats);
+
+    for (fmt_idx = 0; fmt_idx != num_formats; fmt_idx++) {
+      CMFormatDescriptionRef fmt;
+      gchar *media_type;
+      gchar *media_sub_type;
+      CMVideoDimensions dim;
+      GArray *rates;
+      guint rate_idx;
+
+      fmt = CFArrayGetValueAtIndex (formats, fmt_idx);
+      media_type = gst_mio_fourcc_to_string
+          (cm->CMFormatDescriptionGetMediaType (fmt));
+      media_sub_type = gst_mio_fourcc_to_string
+          (cm->CMFormatDescriptionGetMediaSubType (fmt));
+      dim = cm->CMVideoFormatDescriptionGetDimensions (fmt);
+
+      g_print ("      format[%u]: MediaType='%s' MediaSubType='%s' %ux%u\n",
+          (guint) fmt_idx, media_type, media_sub_type,
+          (guint) dim.width, (guint) dim.height);
+
+      spec.name = kTundraStreamPropertyFrameRates;
+      rates = gst_mio_object_get_array_full (stream, &spec, sizeof (fmt), &fmt,
+          sizeof (TundraFramerate), mio);
+      for (rate_idx = 0; rate_idx != rates->len; rate_idx++) {
+        TundraFramerate *rate;
+
+        rate = &g_array_index (rates, TundraFramerate, rate_idx);
+        g_print ("        %f\n", rate->value);
+      }
+      g_array_free (rates, TRUE);
+
+      g_free (media_sub_type);
+      g_free (media_type);
+    }
+  }
+
+  g_array_free (streams, TRUE);
+}
+
+static void
+gst_mio_video_device_class_init (GstMIOVideoDeviceClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->dispose = gst_mio_video_device_dispose;
+  gobject_class->finalize = gst_mio_video_device_finalize;
+  gobject_class->get_property = gst_mio_video_device_get_property;
+  gobject_class->set_property = gst_mio_video_device_set_property;
+
+  g_object_class_install_property (gobject_class, PROP_CONTEXT,
+      g_param_spec_pointer ("context", "CoreMedia Context",
+          "CoreMedia context to use",
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_HANDLE,
+      g_param_spec_int ("handle", "Handle",
+          "MIO handle of this video capture device",
+          G_MININT, G_MAXINT, -1,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_UID,
+      g_param_spec_string ("uid", "Unique ID",
+          "Unique ID of this video capture device", NULL,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_NAME,
+      g_param_spec_string ("name", "Device Name",
+          "Name of this video capture device", NULL,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_TRANSPORT,
+      g_param_spec_uint ("transport", "Transport",
+          "Transport type of this video capture device",
+          0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+}
+
+GList *
+gst_mio_video_device_list_create (GstCoreMediaCtx * ctx)
+{
+  GList *devices = NULL;
+  TundraTargetSpec pspec = { 0, };
+  GArray *handles;
+  guint handle_idx;
+
+  pspec.name = kTundraSystemPropertyDevices;
+  pspec.scope = kTundraScopeGlobal;
+  handles = gst_mio_object_get_array (TUNDRA_SYSTEM_OBJECT_ID, &pspec,
+      sizeof (TundraObjectID), ctx->mio);
+  if (handles == NULL)
+    goto beach;
+
+  for (handle_idx = 0; handle_idx != handles->len; handle_idx++) {
+    TundraObjectID handle;
+    GstMIOVideoDevice *device;
+
+    handle = g_array_index (handles, TundraObjectID, handle_idx);
+    device = g_object_new (GST_TYPE_MIO_VIDEO_DEVICE,
+        "context", ctx, "handle", handle, NULL);
+
+    /* TODO: Skip screen input devices for now */
+    if (gst_mio_video_device_get_transport_type (device) !=
+        kTundraDeviceTransportScreen) {
+      devices = g_list_prepend (devices, device);
+    } else {
+      g_object_unref (device);
+    }
+  }
+
+  devices = g_list_sort (devices, (GCompareFunc) gst_mio_video_device_compare);
+
+  g_array_free (handles, TRUE);
+
+beach:
+  return devices;
+}
+
+void
+gst_mio_video_device_list_destroy (GList * devices)
+{
+  g_list_foreach (devices, (GFunc) g_object_unref, NULL);
+  g_list_free (devices);
+}
+
+static gint
+gst_mio_video_device_compare (GstMIOVideoDevice * a, GstMIOVideoDevice * b)
+{
+  gint score_a, score_b;
+
+  score_a = gst_mio_video_device_calculate_score (a);
+  score_b = gst_mio_video_device_calculate_score (b);
+
+  if (score_a > score_b)
+    return -1;
+  else if (score_a < score_b)
+    return 1;
+
+  return g_ascii_strcasecmp (gst_mio_video_device_get_name (a),
+      gst_mio_video_device_get_name (b));
+}
+
+static gint
+gst_mio_video_device_calculate_score (GstMIOVideoDevice * device)
+{
+  switch (gst_mio_video_device_get_transport_type (device)) {
+    case kTundraDeviceTransportScreen:
+      return 0;
+    case kTundraDeviceTransportBuiltin:
+      return 1;
+    case kTundraDeviceTransportUSB:
+      return 2;
+    default:
+      return 3;
+  }
+}
diff --git a/sys/applemedia-nonpublic/miovideodevice.h b/sys/applemedia-nonpublic/miovideodevice.h
new file mode 100644 (file)
index 0000000..87b86f3
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2009 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_MIO_VIDEO_DEVICE_H__
+#define __GST_MIO_VIDEO_DEVICE_H__
+
+#include <gst/gst.h>
+
+#include "coremediactx.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_MIO_VIDEO_DEVICE \
+  (gst_mio_video_device_get_type ())
+#define GST_MIO_VIDEO_DEVICE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MIO_VIDEO_DEVICE, GstMIOVideoDevice))
+#define GST_MIO_VIDEO_DEVICE_CAST(obj) \
+  ((GstMIOVideoDevice *) (obj))
+#define GST_MIO_VIDEO_DEVICE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MIO_VIDEO_DEVICE, GstMIOVideoDeviceClass))
+#define GST_IS_MIO_VIDEO_DEVICE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MIO_VIDEO_DEVICE))
+#define GST_IS_MIO_VIDEO_DEVICE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MIO_VIDEO_DEVICE))
+
+typedef struct _GstMIOVideoDevice         GstMIOVideoDevice;
+typedef struct _GstMIOVideoDeviceClass    GstMIOVideoDeviceClass;
+
+struct _GstMIOVideoDevice
+{
+  GObject parent;
+
+  GstCoreMediaCtx *ctx;
+  TundraObjectID handle;
+
+  gchar *cached_uid;
+  gchar *cached_name;
+  TundraDeviceTransportType cached_transport;
+  GstCaps *cached_caps;
+  CMFormatDescriptionRef selected_format;
+  gint selected_fps_n, selected_fps_d;
+};
+
+struct _GstMIOVideoDeviceClass
+{
+  GObjectClass parent_class;
+};
+
+GType gst_mio_video_device_get_type (void);
+
+TundraObjectID gst_mio_video_device_get_handle (GstMIOVideoDevice * self);
+const gchar * gst_mio_video_device_get_uid (GstMIOVideoDevice * self);
+const gchar * gst_mio_video_device_get_name (GstMIOVideoDevice * self);
+TundraDeviceTransportType gst_mio_video_device_get_transport_type (
+    GstMIOVideoDevice * self);
+
+gboolean gst_mio_video_device_open (GstMIOVideoDevice * self);
+void gst_mio_video_device_close (GstMIOVideoDevice * self);
+
+GstCaps * gst_mio_video_device_get_available_caps (GstMIOVideoDevice * self);
+gboolean gst_mio_video_device_set_caps (GstMIOVideoDevice * self,
+    GstCaps * caps);
+CMFormatDescriptionRef gst_mio_video_device_get_selected_format (
+    GstMIOVideoDevice * self);
+GstClockTime gst_mio_video_device_get_duration (GstMIOVideoDevice * self);
+
+void gst_mio_video_device_print_debug_info (GstMIOVideoDevice * self);
+
+GList * gst_mio_video_device_list_create (GstCoreMediaCtx * ctx);
+void gst_mio_video_device_list_destroy (GList * devices);
+
+G_END_DECLS
+
+#endif /* __GST_MIO_VIDEO_DEVICE_H__ */
diff --git a/sys/applemedia-nonpublic/miovideosrc.c b/sys/applemedia-nonpublic/miovideosrc.c
new file mode 100644 (file)
index 0000000..041d7eb
--- /dev/null
@@ -0,0 +1,1201 @@
+/*
+ * Copyright (C) 2009 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* FIXME 1.x: suppress warnings for deprecated API such as GStaticRecMutex
+ * with newer GLib versions (>= 2.31.0) */
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#include "miovideosrc.h"
+
+#include "coremediabuffer.h"
+
+#include <gst/interfaces/propertyprobe.h>
+#include <gst/video/video.h>
+
+#include <CoreVideo/CVHostTime.h>
+
+#define DEFAULT_DEVICE_INDEX -1
+
+#define FRAME_QUEUE_SIZE      2
+
+#define FRAME_QUEUE_LOCK(instance) g_mutex_lock (instance->qlock)
+#define FRAME_QUEUE_UNLOCK(instance) g_mutex_unlock (instance->qlock)
+#define FRAME_QUEUE_WAIT(instance) \
+    g_cond_wait (instance->qcond, instance->qlock)
+#define FRAME_QUEUE_NOTIFY(instance) g_cond_signal (instance->qcond)
+
+#define GST_MIO_REQUIRED_APIS \
+    (GST_API_CORE_VIDEO | GST_API_CORE_MEDIA | GST_API_MIO)
+
+GST_DEBUG_CATEGORY (gst_mio_video_src_debug);
+#define GST_CAT_DEFAULT gst_mio_video_src_debug
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("UYVY") ";"
+        GST_VIDEO_CAPS_YUV ("YUY2") ";"
+        "image/jpeg, "
+        "width = " GST_VIDEO_SIZE_RANGE ", "
+        "height = " GST_VIDEO_SIZE_RANGE ", "
+        "framerate = " GST_VIDEO_FPS_RANGE ";")
+    );
+
+enum
+{
+  PROP_0,
+  PROP_DEVICE_UID,
+  PROP_DEVICE_NAME,
+  PROP_DEVICE_INDEX
+};
+
+typedef gboolean (*GstMIOCallback) (GstMIOVideoSrc * self, gpointer data);
+#define GST_MIO_CALLBACK(cb) ((GstMIOCallback) (cb))
+
+static gboolean gst_mio_video_src_open_device (GstMIOVideoSrc * self);
+static void gst_mio_video_src_close_device (GstMIOVideoSrc * self);
+static gboolean gst_mio_video_src_build_capture_graph_for
+    (GstMIOVideoSrc * self, GstMIOVideoDevice * device);
+static TundraStatus gst_mio_video_src_configure_output_node
+    (GstMIOVideoSrc * self, TundraGraph * graph, guint node_id);
+
+static void gst_mio_video_src_start_dispatcher (GstMIOVideoSrc * self);
+static void gst_mio_video_src_stop_dispatcher (GstMIOVideoSrc * self);
+static gpointer gst_mio_video_src_dispatcher_thread (gpointer data);
+static gboolean gst_mio_video_src_perform (GstMIOVideoSrc * self,
+    GstMIOCallback cb, gpointer data);
+static gboolean gst_mio_video_src_perform_proxy (gpointer data);
+
+static void gst_mio_video_src_probe_interface_init (gpointer g_iface,
+    gpointer iface_data);
+
+static void gst_mio_video_src_init_interfaces (GType type);
+
+GST_BOILERPLATE_FULL (GstMIOVideoSrc, gst_mio_video_src, GstPushSrc,
+    GST_TYPE_PUSH_SRC, gst_mio_video_src_init_interfaces);
+
+static void
+gst_mio_video_src_init (GstMIOVideoSrc * self, GstMIOVideoSrcClass * gclass)
+{
+  GstBaseSrc *base_src = GST_BASE_SRC_CAST (self);
+  guint64 host_freq;
+
+  gst_base_src_set_live (base_src, TRUE);
+  gst_base_src_set_format (base_src, GST_FORMAT_TIME);
+
+  host_freq = gst_gdouble_to_guint64 (CVGetHostClockFrequency ());
+  if (host_freq <= GST_SECOND) {
+    self->cv_ratio_n = GST_SECOND / host_freq;
+    self->cv_ratio_d = 1;
+  } else {
+    self->cv_ratio_n = 1;
+    self->cv_ratio_d = host_freq / GST_SECOND;
+  }
+
+  self->queue = g_queue_new ();
+  self->qlock = g_mutex_new ();
+  self->qcond = g_cond_new ();
+}
+
+static void
+gst_mio_video_src_finalize (GObject * object)
+{
+  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (object);
+
+  g_cond_free (self->qcond);
+  g_mutex_free (self->qlock);
+  g_queue_free (self->queue);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_mio_video_src_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (object);
+
+  switch (prop_id) {
+    case PROP_DEVICE_UID:
+      g_value_set_string (value, self->device_uid);
+      break;
+    case PROP_DEVICE_NAME:
+      g_value_set_string (value, self->device_name);
+      break;
+    case PROP_DEVICE_INDEX:
+      g_value_set_int (value, self->device_index);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_mio_video_src_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (object);
+
+  switch (prop_id) {
+    case PROP_DEVICE_UID:
+      g_free (self->device_uid);
+      self->device_uid = g_value_dup_string (value);
+      break;
+    case PROP_DEVICE_NAME:
+      g_free (self->device_name);
+      self->device_name = g_value_dup_string (value);
+      break;
+    case PROP_DEVICE_INDEX:
+      self->device_index = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstStateChangeReturn
+gst_mio_video_src_change_state (GstElement * element, GstStateChange transition)
+{
+  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (element);
+  GstStateChangeReturn ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      gst_mio_video_src_start_dispatcher (self);
+      if (!gst_mio_video_src_perform (self,
+              GST_MIO_CALLBACK (gst_mio_video_src_open_device), NULL)) {
+        goto open_failed;
+      }
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      gst_mio_video_src_perform (self,
+          GST_MIO_CALLBACK (gst_mio_video_src_close_device), NULL);
+
+      gst_mio_video_src_stop_dispatcher (self);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+
+  /* ERRORS */
+open_failed:
+  {
+    gst_mio_video_src_stop_dispatcher (self);
+    return GST_STATE_CHANGE_FAILURE;
+  }
+}
+
+static GstCaps *
+gst_mio_video_src_get_caps (GstBaseSrc * basesrc)
+{
+  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (basesrc);
+  GstCaps *result;
+
+  if (self->device != NULL) {
+    result =
+        gst_caps_ref (gst_mio_video_device_get_available_caps (self->device));
+  } else {
+    result = NULL;              /* BaseSrc will return template caps */
+  }
+
+  return result;
+}
+
+static gboolean
+gst_mio_video_src_do_set_caps (GstMIOVideoSrc * self, GstCaps * caps)
+{
+  TundraStatus status;
+
+  if (self->device == NULL)
+    goto no_device;
+
+  if (!gst_mio_video_device_set_caps (self->device, caps))
+    goto invalid_format;
+
+  if (!gst_mio_video_src_build_capture_graph_for (self, self->device))
+    goto graph_build_error;
+
+  status = self->ctx->mio->TundraGraphInitialize (self->graph);
+  if (status != kTundraSuccess)
+    goto graph_init_error;
+
+  status = self->ctx->mio->TundraGraphStart (self->graph);
+  if (status != kTundraSuccess)
+    goto graph_start_error;
+
+  return TRUE;
+
+  /* ERRORS */
+no_device:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, FAILED, ("no device"), (NULL));
+    return FALSE;
+  }
+invalid_format:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, FAILED, ("invalid format"), (NULL));
+    return FALSE;
+  }
+graph_build_error:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
+        ("failed to build capture graph"), (NULL));
+    return FALSE;
+  }
+graph_init_error:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
+        ("failed to initialize capture graph: %08x", status), (NULL));
+    return FALSE;
+  }
+graph_start_error:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
+        ("failed to start capture graph: %08x", status), (NULL));
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_mio_video_src_set_caps (GstBaseSrc * basesrc, GstCaps * caps)
+{
+  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (basesrc);
+
+  {
+    gchar *str;
+
+    str = gst_caps_to_string (caps);
+    GST_DEBUG_OBJECT (self, "caps: %s", str);
+    g_free (str);
+  }
+
+  return gst_mio_video_src_perform (self,
+      GST_MIO_CALLBACK (gst_mio_video_src_do_set_caps), caps);
+}
+
+static gboolean
+gst_mio_video_src_start (GstBaseSrc * basesrc)
+{
+  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (basesrc);
+
+  self->running = TRUE;
+  self->prev_offset = GST_BUFFER_OFFSET_NONE;
+  self->prev_format = NULL;
+
+  return TRUE;
+}
+
+static gboolean
+gst_mio_video_src_do_stop (GstMIOVideoSrc * self)
+{
+  TundraStatus status;
+
+  if (self->graph == NULL)
+    goto nothing_to_stop;
+
+  status = self->ctx->mio->TundraGraphStop (self->graph);
+  if (status != kTundraSuccess)
+    goto graph_failed_to_stop;
+
+  while (!g_queue_is_empty (self->queue))
+    gst_buffer_unref (g_queue_pop_head (self->queue));
+
+  self->ctx->cm->FigFormatDescriptionRelease (self->prev_format);
+  self->prev_format = NULL;
+
+  return TRUE;
+
+nothing_to_stop:
+  return TRUE;
+
+graph_failed_to_stop:
+  GST_WARNING_OBJECT (self, "failed to stop capture graph: %d", status);
+  return FALSE;
+}
+
+static gboolean
+gst_mio_video_src_stop (GstBaseSrc * basesrc)
+{
+  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (basesrc);
+
+  return gst_mio_video_src_perform (self,
+      GST_MIO_CALLBACK (gst_mio_video_src_do_stop), NULL);
+}
+
+static gboolean
+gst_mio_video_src_query (GstBaseSrc * basesrc, GstQuery * query)
+{
+  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (basesrc);
+  gboolean result = FALSE;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_LATENCY:{
+      GstClockTime min_latency, max_latency;
+
+      if (self->device == NULL)
+        goto beach;
+
+      if (gst_mio_video_device_get_selected_format (self->device) == NULL)
+        goto beach;
+
+      min_latency = max_latency =
+          gst_mio_video_device_get_duration (self->device);
+
+      GST_DEBUG_OBJECT (self, "reporting latency of min %" GST_TIME_FORMAT
+          " max %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
+
+      gst_query_set_latency (query, TRUE, min_latency, max_latency);
+      result = TRUE;
+      break;
+    }
+    default:
+      result = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
+      break;
+  }
+
+beach:
+  return result;
+}
+
+static gboolean
+gst_mio_video_src_unlock (GstBaseSrc * basesrc)
+{
+  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (basesrc);
+
+  FRAME_QUEUE_LOCK (self);
+  self->running = FALSE;
+  FRAME_QUEUE_NOTIFY (self);
+  FRAME_QUEUE_UNLOCK (self);
+
+  return TRUE;
+}
+
+static gboolean
+gst_mio_video_src_unlock_stop (GstBaseSrc * basesrc)
+{
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_mio_video_src_create (GstPushSrc * pushsrc, GstBuffer ** buf)
+{
+  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (pushsrc);
+  GstCMApi *cm = self->ctx->cm;
+  CMFormatDescriptionRef format;
+
+  FRAME_QUEUE_LOCK (self);
+  while (self->running && g_queue_is_empty (self->queue))
+    FRAME_QUEUE_WAIT (self);
+  *buf = g_queue_pop_tail (self->queue);
+  FRAME_QUEUE_UNLOCK (self);
+
+  if (G_UNLIKELY (!self->running))
+    goto shutting_down;
+
+  format = cm->CMSampleBufferGetFormatDescription
+      (GST_CORE_MEDIA_BUFFER (*buf)->sample_buf);
+  if (self->prev_format != NULL &&
+      !cm->CMFormatDescriptionEqual (format, self->prev_format)) {
+    goto unexpected_format;
+  }
+  cm->FigFormatDescriptionRelease (self->prev_format);
+  self->prev_format = cm->FigFormatDescriptionRetain (format);
+
+  if (self->prev_offset == GST_BUFFER_OFFSET_NONE ||
+      GST_BUFFER_OFFSET (*buf) - self->prev_offset != 1) {
+    GST_BUFFER_FLAG_SET (*buf, GST_BUFFER_FLAG_DISCONT);
+  }
+  self->prev_offset = GST_BUFFER_OFFSET (*buf);
+
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+shutting_down:
+  {
+    if (*buf != NULL) {
+      gst_buffer_unref (*buf);
+      *buf = NULL;
+    }
+
+    return GST_FLOW_FLUSHING;
+  }
+unexpected_format:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, READ,
+        ("capture format changed unexpectedly"),
+        ("another application likely reconfigured the device"));
+
+    if (*buf != NULL) {
+      gst_buffer_unref (*buf);
+      *buf = NULL;
+    }
+
+    return GST_FLOW_ERROR;
+  }
+}
+
+static gboolean
+gst_mio_video_src_open_device (GstMIOVideoSrc * self)
+{
+  GError *error = NULL;
+  GList *devices = NULL, *walk;
+  guint device_idx;
+
+  self->ctx = gst_core_media_ctx_new (GST_API_CORE_VIDEO | GST_API_CORE_MEDIA
+      | GST_API_MIO, &error);
+  if (error != NULL)
+    goto api_error;
+
+  devices = gst_mio_video_device_list_create (self->ctx);
+  if (devices == NULL)
+    goto no_devices;
+
+  for (walk = devices, device_idx = 0; walk != NULL; walk = walk->next) {
+    GstMIOVideoDevice *device = walk->data;
+    gboolean match;
+
+    if (self->device_uid != NULL) {
+      match = g_ascii_strcasecmp (gst_mio_video_device_get_uid (device),
+          self->device_uid) == 0;
+    } else if (self->device_name != NULL) {
+      match = g_ascii_strcasecmp (gst_mio_video_device_get_name (device),
+          self->device_name) == 0;
+    } else if (self->device_index >= 0) {
+      match = device_idx == self->device_index;
+    } else {
+      match = TRUE;             /* pick the first entry */
+    }
+
+    if (self->device != NULL)
+      match = FALSE;
+
+    GST_DEBUG_OBJECT (self, "%c device[%u] = handle: %d name: '%s' uid: '%s'",
+        (match) ? '*' : '-', device_idx,
+        gst_mio_video_device_get_handle (device),
+        gst_mio_video_device_get_name (device),
+        gst_mio_video_device_get_uid (device));
+
+    /*gst_mio_video_device_print_debug_info (device); */
+
+    if (match)
+      self->device = g_object_ref (device);
+
+    device_idx++;
+  }
+
+  if (self->device == NULL)
+    goto no_such_device;
+
+  if (!gst_mio_video_device_open (self->device))
+    goto device_busy_or_gone;
+
+  gst_mio_video_device_list_destroy (devices);
+  return TRUE;
+
+  /* ERRORS */
+api_error:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, FAILED, ("API error"),
+        ("%s", error->message));
+    g_clear_error (&error);
+    goto any_error;
+  }
+no_devices:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
+        ("no video capture devices found"), (NULL));
+    goto any_error;
+  }
+no_such_device:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
+        ("specified video capture device not found"), (NULL));
+    goto any_error;
+  }
+device_busy_or_gone:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, BUSY,
+        ("failed to start capture (device already in use or gone)"), (NULL));
+    goto any_error;
+  }
+any_error:
+  {
+    if (devices != NULL) {
+      gst_mio_video_device_list_destroy (devices);
+    }
+    if (self->ctx != NULL) {
+      g_object_unref (self->ctx);
+      self->ctx = NULL;
+    }
+    return FALSE;
+  }
+}
+
+static void
+gst_mio_video_src_close_device (GstMIOVideoSrc * self)
+{
+  self->ctx->mio->TundraGraphUninitialize (self->graph);
+  self->ctx->mio->TundraGraphRelease (self->graph);
+  self->graph = NULL;
+
+  gst_mio_video_device_close (self->device);
+  g_object_unref (self->device);
+  self->device = NULL;
+
+  g_object_unref (self->ctx);
+  self->ctx = NULL;
+}
+
+#define CHECK_TUNDRA_ERROR(fn)      \
+  if (status != kTundraSuccess) {   \
+    last_function_name = fn;        \
+    goto tundra_error;              \
+  }
+
+static gboolean
+gst_mio_video_src_build_capture_graph_for (GstMIOVideoSrc * self,
+    GstMIOVideoDevice * device)
+{
+  GstMIOApi *mio = self->ctx->mio;
+  const gchar *last_function_name;
+  TundraGraph *graph = NULL;
+  TundraTargetSpec spec = { 0, };
+  TundraUnitID input_node = -1;
+  gpointer input_info;
+  TundraObjectID device_handle;
+  TundraUnitID sync_node = -1;
+  guint8 is_master;
+  guint sync_direction;
+  TundraUnitID output_node = -1;
+  TundraStatus status;
+
+  const gint node_id_input = 1;
+  const gint node_id_sync = 22;
+  const gint node_id_output = 16;
+
+  /*
+   * Graph
+   */
+  status = mio->TundraGraphCreate (kCFAllocatorDefault, &graph);
+  CHECK_TUNDRA_ERROR ("TundraGraphCreate");
+
+  /*
+   * Node: input
+   */
+  spec.name = kTundraUnitInput;
+  spec.scope = kTundraScopeDAL;
+  spec.vendor = kTundraVendorApple;
+  status = mio->TundraGraphCreateNode (graph, node_id_input, 0, 0, &spec, 0,
+      &input_node);
+  CHECK_TUNDRA_ERROR ("TundraGraphCreateNode(input)");
+
+  /* store node info for setting clock provider */
+  input_info = NULL;
+  status = mio->TundraGraphGetNodeInfo (graph, input_node, 0, 0, 0, 0,
+      &input_info);
+  CHECK_TUNDRA_ERROR ("TundraGraphGetNodeInfo(input)");
+
+  /* set device handle */
+  device_handle = gst_mio_video_device_get_handle (device);
+  status = mio->TundraGraphSetProperty (graph, node_id_input, 0,
+      kTundraInputPropertyDeviceID, 0, 0, &device_handle,
+      sizeof (device_handle));
+  CHECK_TUNDRA_ERROR ("TundraGraphSetProperty(input, DeviceID)");
+
+  /*
+   * Node: sync
+   */
+  spec.name = kTundraUnitSync;
+  spec.scope = kTundraScopeVSyn;
+  status = mio->TundraGraphCreateNode (graph, node_id_sync, 0, 0, &spec, 0,
+      &sync_node);
+  CHECK_TUNDRA_ERROR ("TundraGraphCreateNode(sync)");
+  status = mio->TundraGraphSetProperty (graph, node_id_sync, 0,
+      kTundraSyncPropertyClockProvider, 0, 0, &input_info, sizeof (input_info));
+  CHECK_TUNDRA_ERROR ("TundraGraphSetProperty(sync, ClockProvider)");
+  is_master = TRUE;
+  status = mio->TundraGraphSetProperty (graph, node_id_sync, 0,
+      kTundraSyncPropertyMasterSynchronizer, 0, 0,
+      &is_master, sizeof (is_master));
+  CHECK_TUNDRA_ERROR ("TundraGraphSetProperty(sync, MasterSynchronizer)");
+  sync_direction = 0;
+  status = mio->TundraGraphSetProperty (graph, node_id_sync, 0,
+      kTundraSyncPropertySynchronizationDirection, 0, 0,
+      &sync_direction, sizeof (sync_direction));
+  CHECK_TUNDRA_ERROR ("TundraGraphSetProperty(sync, SynchronizationDirection)");
+
+  /*
+   * Node: output
+   */
+  spec.name = kTundraUnitOutput;
+  spec.scope = kTundraScope2PRC;
+  status = mio->TundraGraphCreateNode (graph, node_id_output, 0, 0, &spec, 0,
+      &output_node);
+  CHECK_TUNDRA_ERROR ("TundraGraphCreateNode(output)");
+  status = gst_mio_video_src_configure_output_node (self, graph,
+      node_id_output);
+  CHECK_TUNDRA_ERROR ("TundraGraphSetProperty(output, Delegate)");
+
+  /*
+   * Connect the nodes
+   */
+  status = mio->TundraGraphConnectNodeInput (graph, input_node, 0,
+      sync_node, 0);
+  CHECK_TUNDRA_ERROR ("TundraGraphConnectNodeInput(input, sync)");
+  status = mio->TundraGraphConnectNodeInput (graph, sync_node, 0,
+      output_node, 0);
+  CHECK_TUNDRA_ERROR ("TundraGraphConnectNodeInput(sync, output)");
+
+  self->graph = graph;
+
+  return TRUE;
+
+tundra_error:
+  {
+    GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
+        ("%s failed (status=%d)", last_function_name, (gint) status), (NULL));
+    goto any_error;
+  }
+any_error:
+  {
+    mio->TundraGraphRelease (graph);
+    return FALSE;
+  }
+}
+
+static GstClockTime
+gst_mio_video_src_get_timestamp (GstMIOVideoSrc * self, CMSampleBufferRef sbuf)
+{
+  GstClock *clock;
+  GstClockTime base_time;
+  GstClockTime timestamp;
+
+  GST_OBJECT_LOCK (self);
+  if ((clock = GST_ELEMENT_CLOCK (self)) != NULL) {
+    gst_object_ref (clock);
+  }
+  base_time = GST_ELEMENT_CAST (self)->base_time;
+  GST_OBJECT_UNLOCK (self);
+
+  if (G_UNLIKELY (clock == NULL))
+    goto no_clock;
+
+  timestamp = GST_CLOCK_TIME_NONE;
+
+  /*
+   * If the current clock is GstSystemClock, we know that it's using the
+   * CoreAudio/CoreVideo clock. As such we may use the timestamp attached
+   * to the CMSampleBuffer.
+   */
+  if (G_TYPE_FROM_INSTANCE (clock) == GST_TYPE_SYSTEM_CLOCK) {
+    CFNumberRef number;
+    UInt64 ht;
+
+    number = self->ctx->cm->CMGetAttachment (sbuf,
+        *self->ctx->mio->kTundraSampleBufferAttachmentKey_HostTime, NULL);
+    if (number != NULL && CFNumberGetValue (number, kCFNumberSInt64Type, &ht)) {
+      timestamp = gst_util_uint64_scale_int (ht,
+          self->cv_ratio_n, self->cv_ratio_d);
+    }
+  }
+
+  if (!GST_CLOCK_TIME_IS_VALID (timestamp)) {
+    timestamp = gst_clock_get_time (clock);
+  }
+
+  if (timestamp > base_time)
+    timestamp -= base_time;
+  else
+    timestamp = 0;
+
+  gst_object_unref (clock);
+
+  return timestamp;
+
+no_clock:
+  return GST_CLOCK_TIME_NONE;
+}
+
+static TundraStatus
+gst_mio_video_src_output_render (gpointer instance, gpointer unk1,
+    gpointer unk2, gpointer unk3, CMSampleBufferRef sample_buf)
+{
+  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (instance);
+  GstBuffer *buf;
+  CFNumberRef number;
+  UInt32 seq;
+
+  buf = gst_core_media_buffer_new (self->ctx, sample_buf);
+  if (G_UNLIKELY (buf == NULL))
+    goto buffer_creation_failed;
+
+  number = self->ctx->cm->CMGetAttachment (sample_buf,
+      *self->ctx->mio->kTundraSampleBufferAttachmentKey_SequenceNumber, NULL);
+  if (number != NULL && CFNumberGetValue (number, kCFNumberSInt32Type, &seq)) {
+    GST_BUFFER_OFFSET (buf) = seq;
+    GST_BUFFER_OFFSET_END (buf) = seq + 1;
+  }
+
+  GST_BUFFER_TIMESTAMP (buf) = gst_mio_video_src_get_timestamp (self,
+      sample_buf);
+
+  if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
+    GST_BUFFER_DURATION (buf) =
+        gst_mio_video_device_get_duration (self->device);
+  }
+
+  FRAME_QUEUE_LOCK (self);
+  if (g_queue_get_length (self->queue) == FRAME_QUEUE_SIZE)
+    gst_buffer_unref (g_queue_pop_tail (self->queue));
+  g_queue_push_head (self->queue, buf);
+  FRAME_QUEUE_NOTIFY (self);
+  FRAME_QUEUE_UNLOCK (self);
+
+  return kTundraSuccess;
+
+buffer_creation_failed:
+  GST_WARNING_OBJECT (instance, "failed to create buffer");
+  return kTundraSuccess;
+}
+
+static TundraStatus
+gst_mio_video_src_output_initialize (gpointer instance)
+{
+  GST_DEBUG_OBJECT (instance, "%s", G_STRFUNC);
+
+  return kTundraSuccess;
+}
+
+static TundraStatus
+gst_mio_video_src_output_uninitialize (gpointer instance)
+{
+  GST_DEBUG_OBJECT (instance, "%s", G_STRFUNC);
+
+  return kTundraSuccess;
+}
+
+static TundraStatus
+gst_mio_video_src_output_start (gpointer instance)
+{
+  GST_DEBUG_OBJECT (instance, "%s", G_STRFUNC);
+
+  return kTundraSuccess;
+}
+
+static TundraStatus
+gst_mio_video_src_output_stop (gpointer instance)
+{
+  return kTundraSuccess;
+}
+
+static TundraStatus
+gst_mio_video_src_output_reset (gpointer instance)
+{
+  GST_DEBUG_OBJECT (instance, "%s", G_STRFUNC);
+
+  return kTundraSuccess;
+}
+
+static TundraStatus
+gst_mio_video_src_output_deallocate (gpointer instance)
+{
+  GST_DEBUG_OBJECT (instance, "%s", G_STRFUNC);
+
+  return kTundraSuccess;
+}
+
+static gboolean
+gst_mio_video_src_output_can_render_now (gpointer instance, guint * unk)
+{
+  if (unk != NULL)
+    *unk = 0;
+
+  return TRUE;
+}
+
+static CFArrayRef
+gst_mio_video_src_output_available_formats (gpointer instance,
+    gboolean ensure_only)
+{
+  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC (instance);
+  CMFormatDescriptionRef format_desc;
+
+  GST_DEBUG_OBJECT (self, "%s: ensure_only=%d", G_STRFUNC, ensure_only);
+
+  if (ensure_only)
+    return NULL;
+
+  g_assert (self->device != NULL);
+  format_desc = gst_mio_video_device_get_selected_format (self->device);
+  g_assert (format_desc != NULL);
+
+  return CFArrayCreate (kCFAllocatorDefault, (const void **) &format_desc, 1,
+      &kCFTypeArrayCallBacks);
+}
+
+static TundraStatus
+gst_mio_video_src_output_copy_clock (gpointer instance)
+{
+  GST_DEBUG_OBJECT (instance, "%s", G_STRFUNC);
+
+  return kTundraSuccess;
+}
+
+static TundraStatus
+gst_mio_video_src_output_get_property_info (gpointer instance, guint prop_id)
+{
+  GST_DEBUG_OBJECT (instance, "%s: prop_id=%u", G_STRFUNC, prop_id);
+
+  if (prop_id == kTundraInputUnitProperty_SourcePath)
+    return kTundraSuccess;
+
+  return kTundraNotSupported;
+}
+
+static TundraStatus
+gst_mio_video_src_output_get_property (gpointer instance, guint prop_id)
+{
+  GST_DEBUG_OBJECT (instance, "%s", G_STRFUNC);
+
+  if (prop_id == kTundraInputUnitProperty_SourcePath)
+    return kTundraSuccess;
+
+  return kTundraNotSupported;
+}
+
+static TundraStatus
+gst_mio_video_src_output_set_property (gpointer instance, guint prop_id)
+{
+  GST_DEBUG_OBJECT (instance, "%s: prop_id=%u", G_STRFUNC, prop_id);
+
+  if (prop_id == kTundraInputUnitProperty_SourcePath)
+    return kTundraSuccess;
+
+  return kTundraNotSupported;
+}
+
+static TundraStatus
+gst_mio_video_src_configure_output_node (GstMIOVideoSrc * self,
+    TundraGraph * graph, guint node_id)
+{
+  TundraStatus status;
+  TundraOutputDelegate d = { 0, };
+
+  d.unk1 = 2;
+  d.instance = self;
+  d.Render = gst_mio_video_src_output_render;
+  d.Initialize = gst_mio_video_src_output_initialize;
+  d.Uninitialize = gst_mio_video_src_output_uninitialize;
+  d.Start = gst_mio_video_src_output_start;
+  d.Stop = gst_mio_video_src_output_stop;
+  d.Reset = gst_mio_video_src_output_reset;
+  d.Deallocate = gst_mio_video_src_output_deallocate;
+  d.CanRenderNow = gst_mio_video_src_output_can_render_now;
+  d.AvailableFormats = gst_mio_video_src_output_available_formats;
+  d.CopyClock = gst_mio_video_src_output_copy_clock;
+  d.GetPropertyInfo = gst_mio_video_src_output_get_property_info;
+  d.GetProperty = gst_mio_video_src_output_get_property;
+  d.SetProperty = gst_mio_video_src_output_set_property;
+
+  status = self->ctx->mio->TundraGraphSetProperty (graph, node_id, 0,
+      kTundraOutputPropertyDelegate, 0, 0, &d, sizeof (d));
+
+  return status;
+}
+
+static void
+gst_mio_video_src_start_dispatcher (GstMIOVideoSrc * self)
+{
+  g_assert (self->dispatcher_ctx == NULL && self->dispatcher_loop == NULL);
+  g_assert (self->dispatcher_thread == NULL);
+
+  self->dispatcher_ctx = g_main_context_new ();
+  self->dispatcher_loop = g_main_loop_new (self->dispatcher_ctx, TRUE);
+  self->dispatcher_thread =
+      g_thread_create (gst_mio_video_src_dispatcher_thread, self, TRUE, NULL);
+}
+
+static void
+gst_mio_video_src_stop_dispatcher (GstMIOVideoSrc * self)
+{
+  g_assert (self->dispatcher_ctx != NULL && self->dispatcher_loop != NULL);
+  g_assert (self->dispatcher_thread != NULL);
+
+  g_main_loop_quit (self->dispatcher_loop);
+  g_thread_join (self->dispatcher_thread);
+  self->dispatcher_thread = NULL;
+
+  g_main_loop_unref (self->dispatcher_loop);
+  self->dispatcher_loop = NULL;
+
+  g_main_context_unref (self->dispatcher_ctx);
+  self->dispatcher_ctx = NULL;
+}
+
+static gpointer
+gst_mio_video_src_dispatcher_thread (gpointer data)
+{
+  GstMIOVideoSrc *self = data;
+
+  g_main_loop_run (self->dispatcher_loop);
+
+  return NULL;
+}
+
+typedef struct
+{
+  GstMIOVideoSrc *self;
+  GstMIOCallback callback;
+  gpointer data;
+  gboolean result;
+
+  GMutex *mutex;
+  GCond *cond;
+  gboolean finished;
+} GstMIOPerformCtx;
+
+static gboolean
+gst_mio_video_src_perform (GstMIOVideoSrc * self, GstMIOCallback cb,
+    gpointer data)
+{
+  GstMIOPerformCtx ctx;
+  GSource *source;
+
+  ctx.self = self;
+  ctx.callback = cb;
+  ctx.data = data;
+  ctx.result = FALSE;
+
+  ctx.mutex = g_mutex_new ();
+  ctx.cond = g_cond_new ();
+  ctx.finished = FALSE;
+
+  source = g_idle_source_new ();
+  g_source_set_callback (source, gst_mio_video_src_perform_proxy, &ctx, NULL);
+  g_source_attach (source, self->dispatcher_ctx);
+
+  g_mutex_lock (ctx.mutex);
+  while (!ctx.finished)
+    g_cond_wait (ctx.cond, ctx.mutex);
+  g_mutex_unlock (ctx.mutex);
+
+  g_source_destroy (source);
+  g_source_unref (source);
+
+  g_cond_free (ctx.cond);
+  g_mutex_free (ctx.mutex);
+
+  return ctx.result;
+}
+
+static gboolean
+gst_mio_video_src_perform_proxy (gpointer data)
+{
+  GstMIOPerformCtx *ctx = data;
+
+  ctx->result = ctx->callback (ctx->self, ctx->data);
+
+  g_mutex_lock (ctx->mutex);
+  ctx->finished = TRUE;
+  g_cond_signal (ctx->cond);
+  g_mutex_unlock (ctx->mutex);
+
+  return FALSE;
+}
+
+static const GList *
+gst_mio_video_src_probe_get_properties (GstPropertyProbe * probe)
+{
+  static gsize init_value = 0;
+
+  if (g_once_init_enter (&init_value)) {
+    GObjectClass *klass;
+    GList *props = NULL;
+
+    klass = G_OBJECT_GET_CLASS (probe);
+
+    props = g_list_append (props,
+        g_object_class_find_property (klass, "device-uid"));
+    props = g_list_append (props,
+        g_object_class_find_property (klass, "device-name"));
+    props = g_list_append (props,
+        g_object_class_find_property (klass, "device-index"));
+
+    g_once_init_leave (&init_value, GPOINTER_TO_SIZE (props));
+  }
+
+  return GSIZE_TO_POINTER (init_value);
+}
+
+static GValueArray *
+gst_mio_video_src_probe_get_values (GstPropertyProbe * probe, guint prop_id,
+    const GParamSpec * pspec)
+{
+  GValueArray *values;
+  GstCoreMediaCtx *ctx = NULL;
+  GError *error = NULL;
+  GList *devices = NULL, *walk;
+  guint device_idx;
+
+  values = g_value_array_new (3);
+
+  ctx = gst_core_media_ctx_new (GST_MIO_REQUIRED_APIS, &error);
+  if (error != NULL)
+    goto beach;
+
+  devices = gst_mio_video_device_list_create (ctx);
+  if (devices == NULL)
+    goto beach;
+
+  for (walk = devices, device_idx = 0; walk != NULL; walk = walk->next) {
+    GstMIOVideoDevice *device = walk->data;
+    GValue value = { 0, };
+
+    switch (prop_id) {
+      case PROP_DEVICE_UID:
+      case PROP_DEVICE_NAME:
+      {
+        const gchar *str;
+
+        if (prop_id == PROP_DEVICE_UID)
+          str = gst_mio_video_device_get_uid (device);
+        else
+          str = gst_mio_video_device_get_name (device);
+
+        g_value_init (&value, G_TYPE_STRING);
+        g_value_set_string (&value, str);
+
+        break;
+      }
+      case PROP_DEVICE_INDEX:
+      {
+        g_value_init (&value, G_TYPE_INT);
+        g_value_set_int (&value, device_idx);
+
+        break;
+      }
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
+        goto beach;
+    }
+
+    g_value_array_append (values, &value);
+    g_value_unset (&value);
+
+    device_idx++;
+  }
+
+beach:
+  if (devices != NULL)
+    gst_mio_video_device_list_destroy (devices);
+  if (ctx != NULL)
+    g_object_unref (ctx);
+  g_clear_error (&error);
+
+  return values;
+}
+
+static void
+gst_mio_video_src_base_init (gpointer gclass)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
+
+  gst_element_class_set_metadata (element_class,
+      "Video Source (MIO)", "Source/Video",
+      "Reads frames from a Mac OS X MIO device",
+      "Ole André Vadla Ravnås <oleavr@soundrop.com>");
+
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&src_template));
+}
+
+static void
+gst_mio_video_src_class_init (GstMIOVideoSrcClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+  GstBaseSrcClass *gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
+  GstPushSrcClass *gstpushsrc_class = GST_PUSH_SRC_CLASS (klass);
+
+  gobject_class->finalize = gst_mio_video_src_finalize;
+  gobject_class->get_property = gst_mio_video_src_get_property;
+  gobject_class->set_property = gst_mio_video_src_set_property;
+
+  gstelement_class->change_state = gst_mio_video_src_change_state;
+
+  gstbasesrc_class->get_caps = gst_mio_video_src_get_caps;
+  gstbasesrc_class->set_caps = gst_mio_video_src_set_caps;
+  gstbasesrc_class->start = gst_mio_video_src_start;
+  gstbasesrc_class->stop = gst_mio_video_src_stop;
+  gstbasesrc_class->query = gst_mio_video_src_query;
+  gstbasesrc_class->unlock = gst_mio_video_src_unlock;
+  gstbasesrc_class->unlock_stop = gst_mio_video_src_unlock_stop;
+
+  gstpushsrc_class->create = gst_mio_video_src_create;
+
+  g_object_class_install_property (gobject_class, PROP_DEVICE_UID,
+      g_param_spec_string ("device-uid", "Device UID",
+          "Unique ID of the desired device", NULL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
+      g_param_spec_string ("device-name", "Device Name",
+          "Name of the desired device", NULL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_DEVICE_INDEX,
+      g_param_spec_int ("device-index", "Device Index",
+          "Zero-based device index of the desired device",
+          -1, G_MAXINT, DEFAULT_DEVICE_INDEX,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+  GST_DEBUG_CATEGORY_INIT (gst_mio_video_src_debug, "miovideosrc",
+      0, "Mac OS X CoreMedia video source");
+}
+
+static void
+gst_mio_video_src_init_interfaces (GType type)
+{
+  static const GInterfaceInfo probe_info = {
+    gst_mio_video_src_probe_interface_init,
+    NULL,
+    NULL
+  };
+
+  g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE, &probe_info);
+}
+
+static void
+gst_mio_video_src_probe_interface_init (gpointer g_iface, gpointer iface_data)
+{
+  GstPropertyProbeInterface *iface = g_iface;
+
+  iface->get_properties = gst_mio_video_src_probe_get_properties;
+  iface->get_values = gst_mio_video_src_probe_get_values;
+}
diff --git a/sys/applemedia-nonpublic/miovideosrc.h b/sys/applemedia-nonpublic/miovideosrc.h
new file mode 100644 (file)
index 0000000..3fe82e7
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2009 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_MIO_VIDEO_SRC_H__
+#define __GST_MIO_VIDEO_SRC_H__
+
+#include <gst/base/gstpushsrc.h>
+
+#include "coremediactx.h"
+#include "miovideodevice.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_MIO_VIDEO_SRC \
+  (gst_mio_video_src_get_type ())
+#define GST_MIO_VIDEO_SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MIO_VIDEO_SRC, GstMIOVideoSrc))
+#define GST_MIO_VIDEO_SRC_CAST(obj) \
+  ((GstMIOVideoSrc *) (obj))
+#define GST_MIO_VIDEO_SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MIO_VIDEO_SRC, GstMIOVideoSrcClass))
+#define GST_IS_MIO_VIDEO_SRC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MIO_VIDEO_SRC))
+#define GST_IS_MIO_VIDEO_SRC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MIO_VIDEO_SRC))
+
+typedef struct _GstMIOVideoSrc         GstMIOVideoSrc;
+typedef struct _GstMIOVideoSrcClass    GstMIOVideoSrcClass;
+
+struct _GstMIOVideoSrc
+{
+  GstPushSrc push_src;
+
+  gint cv_ratio_n;
+  gint cv_ratio_d;
+
+  gchar *device_uid;
+  gchar *device_name;
+  gint device_index;
+
+  GThread *dispatcher_thread;
+  GMainLoop *dispatcher_loop;
+  GMainContext *dispatcher_ctx;
+
+  GstCoreMediaCtx *ctx;
+  GstMIOVideoDevice *device;
+
+  TundraGraph *graph;
+
+  volatile gboolean running;
+  GQueue *queue;
+  GMutex *qlock;
+  GCond *qcond;
+  guint64 prev_offset;
+  CMFormatDescriptionRef prev_format;
+};
+
+struct _GstMIOVideoSrcClass
+{
+  GstPushSrcClass parent_class;
+};
+
+GType gst_mio_video_src_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_MIO_VIDEO_SRC_H__ */
diff --git a/sys/applemedia-nonpublic/mtapi.c b/sys/applemedia-nonpublic/mtapi.c
new file mode 100644 (file)
index 0000000..f8cd242
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "mtapi.h"
+
+#include "dynapi-internal.h"
+
+#define MT_FRAMEWORK_PATH "/System/Library/PrivateFrameworks/" \
+    "MediaToolbox.framework/MediaToolbox"
+
+G_DEFINE_TYPE (GstMTApi, gst_mt_api, GST_TYPE_DYN_API);
+
+static void
+gst_mt_api_init (GstMTApi * self)
+{
+}
+
+static void
+gst_mt_api_class_init (GstMTApiClass * klass)
+{
+}
+
+#define SYM_SPEC(name) GST_DYN_SYM_SPEC (GstMTApi, name)
+
+GstMTApi *
+gst_mt_api_obtain (GError ** error)
+{
+  static const GstDynSymSpec symbols[] = {
+    SYM_SPEC (FigCaptureDeviceGetFigBaseObject),
+    SYM_SPEC (FigCaptureStreamGetFigBaseObject),
+
+    SYM_SPEC (kFigCaptureDeviceProperty_Clock),
+    SYM_SPEC (kFigCaptureDeviceProperty_StreamArray),
+    SYM_SPEC (kFigCaptureStreamProperty_AudioLevelArray),
+    SYM_SPEC (kFigCaptureStreamProperty_AudioLevelMeteringEnable),
+    SYM_SPEC (kFigCaptureStreamProperty_AudioLevelUnits),
+    SYM_SPEC (kFigCaptureStreamProperty_AutoAENow),
+    SYM_SPEC (kFigCaptureStreamProperty_AutoFocusNow),
+    SYM_SPEC (kFigCaptureStreamProperty_BufferAllocator),
+    SYM_SPEC (kFigCaptureStreamProperty_BufferQueue),
+    SYM_SPEC (kFigCaptureStreamProperty_FixedFrameRate),
+    SYM_SPEC (kFigCaptureStreamProperty_FormatDescription),
+    SYM_SPEC (kFigCaptureStreamProperty_FormatIndex),
+    SYM_SPEC (kFigCaptureStreamProperty_FrameDuration),
+    SYM_SPEC (kFigCaptureStreamProperty_MaximumFrameRate),
+    SYM_SPEC (kFigCaptureStreamProperty_MinimumFrameRate),
+    SYM_SPEC (kFigCaptureStreamProperty_NeedSampleBufferDurations),
+    SYM_SPEC (kFigCaptureStreamProperty_StillImageBufferQueue),
+    SYM_SPEC (kFigCaptureStreamProperty_StillImageCaptureNow),
+    SYM_SPEC (kFigCaptureStreamProperty_SupportedFormatsArray),
+    SYM_SPEC (kFigSupportedFormat_AudioMaxSampleRate),
+    SYM_SPEC (kFigSupportedFormat_AudioMinSampleRate),
+    SYM_SPEC (kFigSupportedFormat_FormatDescription),
+    SYM_SPEC (kFigSupportedFormat_VideoIsBinned),
+    SYM_SPEC (kFigSupportedFormat_VideoMaxFrameRate),
+    SYM_SPEC (kFigSupportedFormat_VideoMinFrameRate),
+    SYM_SPEC (kFigSupportedFormat_VideoScaleFactor),
+
+    {NULL, 0},
+  };
+
+  return _gst_dyn_api_new (gst_mt_api_get_type (), MT_FRAMEWORK_PATH, symbols,
+      error);
+}
diff --git a/sys/applemedia-nonpublic/mtapi.h b/sys/applemedia-nonpublic/mtapi.h
new file mode 100644 (file)
index 0000000..91d90e9
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_MT_API_H__
+#define __GST_MT_API_H__
+
+#include "cmapi.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GstMTApi GstMTApi;
+typedef struct _GstMTApiClass GstMTApiClass;
+
+typedef struct _FigCaptureDevice * FigCaptureDeviceRef;
+typedef struct _FigCaptureStream * FigCaptureStreamRef;
+typedef struct _FigCaptureDeviceIface FigCaptureDeviceIface;
+typedef struct _FigCaptureStreamIface FigCaptureStreamIface;
+
+struct _FigCaptureDeviceIface
+{
+  gsize unk;
+  OSStatus (* Func1) (FigCaptureDeviceRef stream);
+};
+
+struct _FigCaptureStreamIface
+{
+  gsize unk;
+  OSStatus (* Start) (FigCaptureStreamRef stream);
+  OSStatus (* Stop) (FigCaptureStreamRef stream);
+};
+
+struct _GstMTApi
+{
+  GstDynApi parent;
+
+  FigBaseObjectRef (* FigCaptureDeviceGetFigBaseObject)
+    (FigCaptureDeviceRef device);
+  FigBaseObjectRef (* FigCaptureStreamGetFigBaseObject)
+    (FigCaptureStreamRef stream);
+
+  CFStringRef * kFigCaptureDeviceProperty_Clock;
+  CFStringRef * kFigCaptureDeviceProperty_StreamArray;
+  CFStringRef * kFigCaptureStreamProperty_AudioLevelArray;
+  CFStringRef * kFigCaptureStreamProperty_AudioLevelMeteringEnable;
+  CFStringRef * kFigCaptureStreamProperty_AudioLevelUnits;
+  CFStringRef * kFigCaptureStreamProperty_AutoAENow;
+  CFStringRef * kFigCaptureStreamProperty_AutoFocusNow;
+  CFStringRef * kFigCaptureStreamProperty_BufferAllocator;
+  CFStringRef * kFigCaptureStreamProperty_BufferQueue;
+  CFStringRef * kFigCaptureStreamProperty_FixedFrameRate;
+  CFStringRef * kFigCaptureStreamProperty_FormatDescription;
+  CFStringRef * kFigCaptureStreamProperty_FormatIndex;
+  CFStringRef * kFigCaptureStreamProperty_FrameDuration;
+  CFStringRef * kFigCaptureStreamProperty_MaximumFrameRate;
+  CFStringRef * kFigCaptureStreamProperty_MinimumFrameRate;
+  CFStringRef * kFigCaptureStreamProperty_NeedSampleBufferDurations;
+  CFStringRef * kFigCaptureStreamProperty_StillImageBufferQueue;
+  CFStringRef * kFigCaptureStreamProperty_StillImageCaptureNow;
+  CFStringRef * kFigCaptureStreamProperty_SupportedFormatsArray;
+  CFStringRef * kFigSupportedFormat_AudioMaxSampleRate;
+  CFStringRef * kFigSupportedFormat_AudioMinSampleRate;
+  CFStringRef * kFigSupportedFormat_FormatDescription;
+  CFStringRef * kFigSupportedFormat_VideoIsBinned;
+  CFStringRef * kFigSupportedFormat_VideoMaxFrameRate;
+  CFStringRef * kFigSupportedFormat_VideoMinFrameRate;
+  CFStringRef * kFigSupportedFormat_VideoScaleFactor;
+};
+
+struct _GstMTApiClass
+{
+  GstDynApiClass parent_class;
+};
+
+GType gst_mt_api_get_type (void);
+
+GstMTApi * gst_mt_api_obtain (GError ** error);
+
+G_END_DECLS
+
+#endif
diff --git a/sys/applemedia-nonpublic/plugin.m b/sys/applemedia-nonpublic/plugin.m
new file mode 100644 (file)
index 0000000..5ece9a5
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2009-2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_IOS
+#include "celvideosrc.h"
+#else
+#include "miovideosrc.h"
+#include <Foundation/Foundation.h>
+#endif
+
+#ifndef HAVE_IOS
+static void
+enable_mt_mode (void)
+{
+  NSThread * th = [[NSThread alloc] init];
+  [th start];
+  [th release];
+  g_assert ([NSThread isMultiThreaded]);
+}
+#endif
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  gboolean res = TRUE;
+
+#ifdef HAVE_IOS
+  res &= gst_element_register (plugin, "celvideosrc", GST_RANK_NONE,
+      GST_TYPE_CEL_VIDEO_SRC);
+#else
+  enable_mt_mode ();
+
+#if 0
+  res &= gst_element_register (plugin, "miovideosrc", GST_RANK_NONE,
+      GST_TYPE_MIO_VIDEO_SRC);
+#endif
+#endif
+
+  return res;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    applemedia,
+    "Elements for capture and codec access on Apple OS X and iOS using private Frameworks",
+    plugin_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/")
index 977a767cc01a19e279034824929f0b95cfb21f77..997542841561c67495d82f8b6698dd7a73f2d81c 100644 (file)
@@ -42,10 +42,7 @@ libgstapplemedia_la_LDFLAGS =                        \
 
 noinst_HEADERS =                               \
        qtkitvideosrc.h                         \
-       miovideosrc.h                           \
-       miovideodevice.h                        \
        avfvideosrc.h                           \
-       celvideosrc.h                           \
        vth264decbin.h                          \
        vth264encbin.h                          \
        vtenc.h                                 \
@@ -57,9 +54,6 @@ noinst_HEADERS =                              \
        coremediactx.h                          \
        cvapi.h                                 \
        cmapi.h                                 \
-       mioapi.h                                \
-       mtapi.h                                 \
-       celapi.h                                \
        vtapi.h                                 \
        dynapi.h                                \
        dynapi-internal.h
@@ -67,10 +61,7 @@ noinst_HEADERS =                             \
 if HAVE_IOS
 
 libgstapplemedia_la_SOURCES +=                 \
-       avfvideosrc.m                           \
-       celvideosrc.c                           \
-       mtapi.c                                 \
-       celapi.c
+       avfvideosrc.m
 
 libgstapplemedia_la_LDFLAGS +=                 \
        -Wl,-framework -Wl,CoreMedia            \
@@ -82,8 +73,7 @@ else
 libgstapplemedia_la_SOURCES +=                 \
        qtkitvideosrc.m                         \
        vtenc.c                                 \
-       vtdec.c                                 \
-       mioapi.c
+       vtdec.c
 
 libgstapplemedia_la_LDFLAGS +=                 \
        -Wl,-framework -Wl,Cocoa                \
diff --git a/sys/applemedia/celapi.c b/sys/applemedia/celapi.c
deleted file mode 100644 (file)
index 9c4727e..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "celapi.h"
-
-#include "dynapi-internal.h"
-
-#define CELESTIAL_FRAMEWORK_PATH "/System/Library/PrivateFrameworks/" \
-    "Celestial.framework/Celestial"
-
-G_DEFINE_TYPE (GstCelApi, gst_cel_api, GST_TYPE_DYN_API);
-
-static void
-gst_cel_api_init (GstCelApi * self)
-{
-}
-
-static void
-gst_cel_api_class_init (GstCelApiClass * klass)
-{
-}
-
-#define SYM_SPEC(name) GST_DYN_SYM_SPEC (GstCelApi, name)
-
-GstCelApi *
-gst_cel_api_obtain (GError ** error)
-{
-  static const GstDynSymSpec symbols[] = {
-    SYM_SPEC (FigCreateCaptureDevicesAndStreamsForPreset),
-
-    SYM_SPEC (kFigCaptureDeviceProperty_MultiplexStreams),
-    SYM_SPEC (kFigCapturePortType_Bottom),
-    SYM_SPEC (kFigCapturePortType_Camera),
-    SYM_SPEC (kFigCapturePortType_FrontFacingCamera),
-    SYM_SPEC (kFigCapturePortType_Top),
-    SYM_SPEC (kFigCapturePropertyValue_AFEarlyOutAllowPeakAtStart),
-    SYM_SPEC (kFigCapturePropertyValue_AFEarlyOutDecrementAmount),
-    SYM_SPEC (kFigCapturePropertyValue_AFEarlyOutEnable),
-    SYM_SPEC (kFigCapturePropertyValue_AFEarlyOutThreshold),
-    SYM_SPEC (kFigCapturePropertyValue_AFPositionCurrent),
-    SYM_SPEC (kFigCapturePropertyValue_AFPositionInfinity),
-    SYM_SPEC (kFigCapturePropertyValue_AFPositionMacro),
-    SYM_SPEC (kFigCapturePropertyValue_AFSearchPositionArray),
-    SYM_SPEC (kFigCapturePropertyValue_AGC),
-    SYM_SPEC (kFigCapturePropertyValue_CLPFControl),
-    SYM_SPEC (kFigCapturePropertyValue_ColorRangeFull),
-    SYM_SPEC (kFigCapturePropertyValue_ColorRangeSDVideo),
-    SYM_SPEC (kFigCapturePropertyValue_ModuleDate),
-    SYM_SPEC (kFigCapturePropertyValue_ModuleIntegratorInfo),
-    SYM_SPEC (kFigCapturePropertyValue_SensorID),
-    SYM_SPEC (kFigCapturePropertyValue_SigmaFilterControl),
-    SYM_SPEC (kFigCapturePropertyValue_YLPFControl),
-    SYM_SPEC (kFigCapturePropertyValue_hStart),
-    SYM_SPEC (kFigCapturePropertyValue_height),
-    SYM_SPEC (kFigCapturePropertyValue_ispDGain),
-    SYM_SPEC (kFigCapturePropertyValue_sensorDGain),
-    SYM_SPEC (kFigCapturePropertyValue_shutterSpeedDenominator),
-    SYM_SPEC (kFigCapturePropertyValue_shutterSpeedNumerator),
-    SYM_SPEC (kFigCapturePropertyValue_vStart),
-    SYM_SPEC (kFigCapturePropertyValue_weight),
-    SYM_SPEC (kFigCapturePropertyValue_width),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_AEBracketedCaptureParams),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_BLCCompensation),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_BLCDebugMode),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_BandHighFactor),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_BandLowFactor),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_CCMWarmUpWeight),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_EdgeColorSuppressionSlope),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_EdgeColorSuppressionThreshold),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_EnableAESceneDynamicMetering),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_EnableCCMWarmUp),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_EnableHistogram1MetaData),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_EnableHistogram2MetaData),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_EnableHistogram3MetaData),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_EnableHistogram4MetaData),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_EnableHistogram),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_HistogramBinMode),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_HistogramDataType),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_ImageCropRect),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_LPExposure),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_LPGain),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_LowWeight),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_MaxWeight),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_MediumWeight),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_MinWeight),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_WeightDropOff),
-    SYM_SPEC (kFigCaptureStreamPropertyValue_WeightReduction),
-    SYM_SPEC (kFigCaptureStreamProperty_AEConvergenceSpeed),
-    SYM_SPEC (kFigCaptureStreamProperty_AEOutlierClipCount),
-    SYM_SPEC (kFigCaptureStreamProperty_AESceneDynamicMetering),
-    SYM_SPEC (kFigCaptureStreamProperty_AEStability),
-    SYM_SPEC (kFigCaptureStreamProperty_AEWindowManualWeightMatrix),
-    SYM_SPEC (kFigCaptureStreamProperty_AEWindowParams),
-    SYM_SPEC (kFigCaptureStreamProperty_AFEarlyOutParams),
-    SYM_SPEC (kFigCaptureStreamProperty_AFParams),
-    SYM_SPEC (kFigCaptureStreamProperty_AFSearchPositions),
-    SYM_SPEC (kFigCaptureStreamProperty_AFWindowParams),
-    SYM_SPEC (kFigCaptureStreamProperty_AGC),
-    SYM_SPEC (kFigCaptureStreamProperty_AWBWindowParams),
-    SYM_SPEC (kFigCaptureStreamProperty_AdditionalPTSOffset),
-    SYM_SPEC (kFigCaptureStreamProperty_AlternateAWB),
-    SYM_SPEC (kFigCaptureStreamProperty_Apply3AWindowSettings),
-    SYM_SPEC (kFigCaptureStreamProperty_AttachRAW),
-    SYM_SPEC (kFigCaptureStreamProperty_CCMWarmUp),
-    SYM_SPEC (kFigCaptureStreamProperty_ClientMaxBufferCountHint),
-    SYM_SPEC (kFigCaptureStreamProperty_ColorRange),
-    SYM_SPEC (kFigCaptureStreamProperty_ColorSaturation),
-    SYM_SPEC (kFigCaptureStreamProperty_ColorTables),
-    SYM_SPEC (kFigCaptureStreamProperty_EdgeColorSuppressionParams),
-    SYM_SPEC (kFigCaptureStreamProperty_ExposureBias),
-    SYM_SPEC (kFigCaptureStreamProperty_FastSwitchMode),
-    SYM_SPEC (kFigCaptureStreamProperty_FlashMode),
-    SYM_SPEC (kFigCaptureStreamProperty_HistogramParams),
-    SYM_SPEC (kFigCaptureStreamProperty_LockAENow),
-    SYM_SPEC (kFigCaptureStreamProperty_LockAWBNow),
-    SYM_SPEC (kFigCaptureStreamProperty_ManualAENow),
-    SYM_SPEC (kFigCaptureStreamProperty_ManualFocusNow),
-    SYM_SPEC (kFigCaptureStreamProperty_MaxIntegrationTime),
-    SYM_SPEC (kFigCaptureStreamProperty_ModuleInfo),
-    SYM_SPEC (kFigCaptureStreamProperty_NoiseReductionControls),
-    SYM_SPEC (kFigCaptureStreamProperty_PortType),
-    SYM_SPEC (kFigCaptureStreamProperty_PreFrameAE),
-    SYM_SPEC (kFigCaptureStreamProperty_RawImageProcessNow),
-    SYM_SPEC (kFigCaptureStreamProperty_RedEyeReductionParams),
-    SYM_SPEC (kFigCaptureStreamProperty_ResetParams),
-    SYM_SPEC (kFigCaptureStreamProperty_ScalerSharpening),
-    SYM_SPEC (kFigCaptureStreamProperty_SetGainCap),
-    SYM_SPEC (kFigCaptureStreamProperty_SharpeningControl),
-    SYM_SPEC (kFigCaptureStreamProperty_TorchLevel),
-    SYM_SPEC (kFigCaptureStreamProperty_UnlockAENow),
-    SYM_SPEC (kFigCaptureStreamProperty_UnlockAWBNow),
-    SYM_SPEC (kFigCaptureStreamProperty_UseFlashAFAssist),
-    SYM_SPEC (kFigCaptureStreamProperty_UseFlashRedEyeReduction),
-    SYM_SPEC (kFigCaptureStreamProperty_UseHardwareShutter),
-    SYM_SPEC (kFigCaptureStreamProperty_VideoRecordingInProgress),
-    SYM_SPEC (kFigRecorderCapturePreset_AudioRecording),
-    SYM_SPEC (kFigRecorderCapturePreset_AudioVideoRecording),
-    SYM_SPEC (kFigRecorderCapturePreset_PhotoCapture),
-    SYM_SPEC (kFigRecorderCapturePreset_VideoRecording),
-
-    {NULL, 0},
-  };
-
-  return _gst_dyn_api_new (gst_cel_api_get_type (), CELESTIAL_FRAMEWORK_PATH,
-      symbols, error);
-}
diff --git a/sys/applemedia/celapi.h b/sys/applemedia/celapi.h
deleted file mode 100644 (file)
index 78855f9..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef __GST_CEL_API_H__
-#define __GST_CEL_API_H__
-
-#include "mtapi.h"
-
-G_BEGIN_DECLS
-
-typedef struct _GstCelApi GstCelApi;
-typedef struct _GstCelApiClass GstCelApiClass;
-
-enum
-{
-  kCelError_ResourceBusy = -12780
-};
-
-struct _GstCelApi
-{
-  GstDynApi parent;
-
-  OSStatus (* FigCreateCaptureDevicesAndStreamsForPreset)
-      (CFAllocatorRef allocator, CFStringRef capturePreset,
-      CFDictionaryRef audioOptions,
-      FigCaptureDeviceRef * outVideoDevice,
-      FigCaptureStreamRef * outVideoStream,
-      FigCaptureDeviceRef * outAudioDevice,
-      FigCaptureStreamRef * outAudioStream);
-
-  CFStringRef * kFigCaptureDeviceProperty_MultiplexStreams;
-  CFStringRef * kFigCapturePortType_Bottom;
-  CFStringRef * kFigCapturePortType_Camera;
-  CFStringRef * kFigCapturePortType_FrontFacingCamera;
-  CFStringRef * kFigCapturePortType_Top;
-  CFStringRef * kFigCapturePropertyValue_AFEarlyOutAllowPeakAtStart;
-  CFStringRef * kFigCapturePropertyValue_AFEarlyOutDecrementAmount;
-  CFStringRef * kFigCapturePropertyValue_AFEarlyOutEnable;
-  CFStringRef * kFigCapturePropertyValue_AFEarlyOutThreshold;
-  CFStringRef * kFigCapturePropertyValue_AFPositionCurrent;
-  CFStringRef * kFigCapturePropertyValue_AFPositionInfinity;
-  CFStringRef * kFigCapturePropertyValue_AFPositionMacro;
-  CFStringRef * kFigCapturePropertyValue_AFSearchPositionArray;
-  CFStringRef * kFigCapturePropertyValue_AGC;
-  CFStringRef * kFigCapturePropertyValue_CLPFControl;
-  CFStringRef * kFigCapturePropertyValue_ColorRangeFull;
-  CFStringRef * kFigCapturePropertyValue_ColorRangeSDVideo;
-  CFStringRef * kFigCapturePropertyValue_ModuleDate;
-  CFStringRef * kFigCapturePropertyValue_ModuleIntegratorInfo;
-  CFStringRef * kFigCapturePropertyValue_SensorID;
-  CFStringRef * kFigCapturePropertyValue_SigmaFilterControl;
-  CFStringRef * kFigCapturePropertyValue_YLPFControl;
-  CFStringRef * kFigCapturePropertyValue_hStart;
-  CFStringRef * kFigCapturePropertyValue_height;
-  CFStringRef * kFigCapturePropertyValue_ispDGain;
-  CFStringRef * kFigCapturePropertyValue_sensorDGain;
-  CFStringRef * kFigCapturePropertyValue_shutterSpeedDenominator;
-  CFStringRef * kFigCapturePropertyValue_shutterSpeedNumerator;
-  CFStringRef * kFigCapturePropertyValue_vStart;
-  CFStringRef * kFigCapturePropertyValue_weight;
-  CFStringRef * kFigCapturePropertyValue_width;
-  CFStringRef * kFigCaptureStreamPropertyValue_AEBracketedCaptureParams;
-  CFStringRef * kFigCaptureStreamPropertyValue_BLCCompensation;
-  CFStringRef * kFigCaptureStreamPropertyValue_BLCDebugMode;
-  CFStringRef * kFigCaptureStreamPropertyValue_BandHighFactor;
-  CFStringRef * kFigCaptureStreamPropertyValue_BandLowFactor;
-  CFStringRef * kFigCaptureStreamPropertyValue_CCMWarmUpWeight;
-  CFStringRef * kFigCaptureStreamPropertyValue_EdgeColorSuppressionSlope;
-  CFStringRef * kFigCaptureStreamPropertyValue_EdgeColorSuppressionThreshold;
-  CFStringRef * kFigCaptureStreamPropertyValue_EnableAESceneDynamicMetering;
-  CFStringRef * kFigCaptureStreamPropertyValue_EnableCCMWarmUp;
-  CFStringRef * kFigCaptureStreamPropertyValue_EnableHistogram1MetaData;
-  CFStringRef * kFigCaptureStreamPropertyValue_EnableHistogram2MetaData;
-  CFStringRef * kFigCaptureStreamPropertyValue_EnableHistogram3MetaData;
-  CFStringRef * kFigCaptureStreamPropertyValue_EnableHistogram4MetaData;
-  CFStringRef * kFigCaptureStreamPropertyValue_EnableHistogram;
-  CFStringRef * kFigCaptureStreamPropertyValue_HistogramBinMode;
-  CFStringRef * kFigCaptureStreamPropertyValue_HistogramDataType;
-  CFStringRef * kFigCaptureStreamPropertyValue_ImageCropRect;
-  CFStringRef * kFigCaptureStreamPropertyValue_LPExposure;
-  CFStringRef * kFigCaptureStreamPropertyValue_LPGain;
-  CFStringRef * kFigCaptureStreamPropertyValue_LowWeight;
-  CFStringRef * kFigCaptureStreamPropertyValue_MaxWeight;
-  CFStringRef * kFigCaptureStreamPropertyValue_MediumWeight;
-  CFStringRef * kFigCaptureStreamPropertyValue_MinWeight;
-  CFStringRef * kFigCaptureStreamPropertyValue_WeightDropOff;
-  CFStringRef * kFigCaptureStreamPropertyValue_WeightReduction;
-  CFStringRef * kFigCaptureStreamProperty_AEConvergenceSpeed;
-  CFStringRef * kFigCaptureStreamProperty_AEOutlierClipCount;
-  CFStringRef * kFigCaptureStreamProperty_AESceneDynamicMetering;
-  CFStringRef * kFigCaptureStreamProperty_AEStability;
-  CFStringRef * kFigCaptureStreamProperty_AEWindowManualWeightMatrix;
-  CFStringRef * kFigCaptureStreamProperty_AEWindowParams;
-  CFStringRef * kFigCaptureStreamProperty_AFEarlyOutParams;
-  CFStringRef * kFigCaptureStreamProperty_AFParams;
-  CFStringRef * kFigCaptureStreamProperty_AFSearchPositions;
-  CFStringRef * kFigCaptureStreamProperty_AFWindowParams;
-  CFStringRef * kFigCaptureStreamProperty_AGC;
-  CFStringRef * kFigCaptureStreamProperty_AWBWindowParams;
-  CFStringRef * kFigCaptureStreamProperty_AdditionalPTSOffset;
-  CFStringRef * kFigCaptureStreamProperty_AlternateAWB;
-  CFStringRef * kFigCaptureStreamProperty_Apply3AWindowSettings;
-  CFStringRef * kFigCaptureStreamProperty_AttachRAW;
-  CFStringRef * kFigCaptureStreamProperty_CCMWarmUp;
-  CFStringRef * kFigCaptureStreamProperty_ClientMaxBufferCountHint;
-  CFStringRef * kFigCaptureStreamProperty_ColorRange;
-  CFStringRef * kFigCaptureStreamProperty_ColorSaturation;
-  CFStringRef * kFigCaptureStreamProperty_ColorTables;
-  CFStringRef * kFigCaptureStreamProperty_EdgeColorSuppressionParams;
-  CFStringRef * kFigCaptureStreamProperty_ExposureBias;
-  CFStringRef * kFigCaptureStreamProperty_FastSwitchMode;
-  CFStringRef * kFigCaptureStreamProperty_FlashMode;
-  CFStringRef * kFigCaptureStreamProperty_HistogramParams;
-  CFStringRef * kFigCaptureStreamProperty_LockAENow;
-  CFStringRef * kFigCaptureStreamProperty_LockAWBNow;
-  CFStringRef * kFigCaptureStreamProperty_ManualAENow;
-  CFStringRef * kFigCaptureStreamProperty_ManualFocusNow;
-  CFStringRef * kFigCaptureStreamProperty_MaxIntegrationTime;
-  CFStringRef * kFigCaptureStreamProperty_ModuleInfo;
-  CFStringRef * kFigCaptureStreamProperty_NoiseReductionControls;
-  CFStringRef * kFigCaptureStreamProperty_PortType;
-  CFStringRef * kFigCaptureStreamProperty_PreFrameAE;
-  CFStringRef * kFigCaptureStreamProperty_RawImageProcessNow;
-  CFStringRef * kFigCaptureStreamProperty_RedEyeReductionParams;
-  CFStringRef * kFigCaptureStreamProperty_ResetParams;
-  CFStringRef * kFigCaptureStreamProperty_ScalerSharpening;
-  CFStringRef * kFigCaptureStreamProperty_SetGainCap;
-  CFStringRef * kFigCaptureStreamProperty_SharpeningControl;
-  CFStringRef * kFigCaptureStreamProperty_TorchLevel;
-  CFStringRef * kFigCaptureStreamProperty_UnlockAENow;
-  CFStringRef * kFigCaptureStreamProperty_UnlockAWBNow;
-  CFStringRef * kFigCaptureStreamProperty_UseFlashAFAssist;
-  CFStringRef * kFigCaptureStreamProperty_UseFlashRedEyeReduction;
-  CFStringRef * kFigCaptureStreamProperty_UseHardwareShutter;
-  CFStringRef * kFigCaptureStreamProperty_VideoRecordingInProgress;
-  CFStringRef * kFigRecorderCapturePreset_AudioRecording;
-  CFStringRef * kFigRecorderCapturePreset_AudioVideoRecording;
-  CFStringRef * kFigRecorderCapturePreset_PhotoCapture;
-  CFStringRef * kFigRecorderCapturePreset_VideoRecording;
-};
-
-struct _GstCelApiClass
-{
-  GstDynApiClass parent_class;
-};
-
-GType gst_cel_api_get_type (void);
-
-GstCelApi * gst_cel_api_obtain (GError ** error);
-
-G_END_DECLS
-
-#endif
diff --git a/sys/applemedia/celvideosrc.c b/sys/applemedia/celvideosrc.c
deleted file mode 100644 (file)
index 90c1246..0000000
+++ /dev/null
@@ -1,881 +0,0 @@
-/*
- * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "celvideosrc.h"
-
-#include "coremediabuffer.h"
-
-#include <gst/video/video.h>
-
-#define DEFAULT_DEVICE_INDEX  -1
-#define DEFAULT_DO_STATS      FALSE
-
-#define QUEUE_READY_LOCK(instance) GST_OBJECT_LOCK (instance)
-#define QUEUE_READY_UNLOCK(instance) GST_OBJECT_UNLOCK (instance)
-#define QUEUE_READY_WAIT(instance) \
-    g_cond_wait (instance->ready_cond, GST_OBJECT_GET_LOCK (instance))
-#define QUEUE_READY_NOTIFY(instance) g_cond_signal (instance->ready_cond)
-
-GST_DEBUG_CATEGORY (gst_cel_video_src_debug);
-#define GST_CAT_DEFAULT gst_cel_video_src_debug
-
-static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
-    GST_PAD_SRC,
-    GST_PAD_ALWAYS,
-    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("NV12") ";"
-        GST_VIDEO_CAPS_YUV ("YUY2"))
-    );
-
-enum
-{
-  PROP_0,
-  PROP_DEVICE_INDEX,
-  PROP_DO_STATS,
-  PROP_FPS
-};
-
-typedef struct
-{
-  guint index;
-
-  GstVideoFormat video_format;
-  guint32 fourcc;
-  gint width;
-  gint height;
-  gint fps_n;
-  gint fps_d;
-} GstCelVideoFormat;
-
-static gboolean gst_cel_video_src_open_device (GstCelVideoSrc * self);
-static void gst_cel_video_src_close_device (GstCelVideoSrc * self);
-static void gst_cel_video_src_ensure_device_caps_and_formats
-    (GstCelVideoSrc * self);
-static void gst_cel_video_src_release_device_caps_and_formats
-    (GstCelVideoSrc * self);
-static gboolean gst_cel_video_src_select_format (GstCelVideoSrc * self,
-    GstCelVideoFormat * format);
-
-static gboolean gst_cel_video_src_parse_stream_format
-    (GstCelVideoSrc * self, guint index, CFDictionaryRef stream_format,
-    GstCelVideoFormat * format);
-static OSStatus gst_cel_video_src_set_stream_property_i32
-    (GstCelVideoSrc * self, CFStringRef name, SInt32 value);
-static OSStatus gst_cel_video_src_set_stream_property_value
-    (GstCelVideoSrc * self, CFStringRef name, CFTypeRef value);
-
-static GstPushSrcClass *parent_class;
-
-GST_BOILERPLATE (GstCelVideoSrc, gst_cel_video_src, GstPushSrc,
-    GST_TYPE_PUSH_SRC);
-
-static void
-gst_cel_video_src_init (GstCelVideoSrc * self, GstCelVideoSrcClass * gclass)
-{
-  GstBaseSrc *base_src = GST_BASE_SRC_CAST (self);
-
-  gst_base_src_set_live (base_src, TRUE);
-  gst_base_src_set_format (base_src, GST_FORMAT_TIME);
-
-  self->ready_cond = g_cond_new ();
-}
-
-static void
-gst_cel_video_src_dispose (GObject * object)
-{
-  G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static void
-gst_cel_video_src_finalize (GObject * object)
-{
-  GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (object);
-
-  g_cond_free (self->ready_cond);
-
-  G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-gst_cel_video_src_get_property (GObject * object, guint prop_id,
-    GValue * value, GParamSpec * pspec)
-{
-  GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (object);
-
-  switch (prop_id) {
-    case PROP_DEVICE_INDEX:
-      g_value_set_int (value, self->device_index);
-      break;
-    case PROP_DO_STATS:
-      g_value_set_boolean (value, self->do_stats);
-      break;
-    case PROP_FPS:
-      GST_OBJECT_LOCK (object);
-      g_value_set_int (value, self->fps);
-      GST_OBJECT_UNLOCK (object);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-}
-
-static void
-gst_cel_video_src_set_property (GObject * object, guint prop_id,
-    const GValue * value, GParamSpec * pspec)
-{
-  GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (object);
-
-  switch (prop_id) {
-    case PROP_DEVICE_INDEX:
-      self->device_index = g_value_get_int (value);
-      break;
-    case PROP_DO_STATS:
-      self->do_stats = g_value_get_boolean (value);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-}
-
-static GstStateChangeReturn
-gst_cel_video_src_change_state (GstElement * element, GstStateChange transition)
-{
-  GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (element);
-  GstStateChangeReturn ret;
-
-  switch (transition) {
-    case GST_STATE_CHANGE_NULL_TO_READY:
-      if (!gst_cel_video_src_open_device (self))
-        goto open_failed;
-      break;
-    default:
-      break;
-  }
-
-  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-
-  switch (transition) {
-    case GST_STATE_CHANGE_READY_TO_NULL:
-      gst_cel_video_src_close_device (self);
-      break;
-    default:
-      break;
-  }
-
-  return ret;
-
-  /* ERRORS */
-open_failed:
-  {
-    return GST_STATE_CHANGE_FAILURE;
-  }
-}
-
-static GstCaps *
-gst_cel_video_src_get_caps (GstBaseSrc * basesrc)
-{
-  GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (basesrc);
-  GstCaps *result;
-
-  if (self->device != NULL) {
-    gst_cel_video_src_ensure_device_caps_and_formats (self);
-
-    result = gst_caps_ref (self->device_caps);
-  } else {
-    result = NULL;
-  }
-
-  if (result != NULL) {
-    gchar *str;
-
-    str = gst_caps_to_string (result);
-    GST_DEBUG_OBJECT (self, "returning: %s", str);
-    g_free (str);
-  }
-
-  return result;
-}
-
-static gboolean
-gst_cel_video_src_set_caps (GstBaseSrc * basesrc, GstCaps * caps)
-{
-  GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (basesrc);
-  GstVideoFormat video_format;
-  gint width, height, fps_n, fps_d;
-  guint i;
-  GstCelVideoFormat *selected_format;
-
-  if (self->device == NULL)
-    goto no_device;
-
-  if (!gst_video_format_parse_caps (caps, &video_format, &width, &height))
-    goto invalid_format;
-  if (!gst_video_parse_caps_framerate (caps, &fps_n, &fps_d))
-    goto invalid_format;
-
-  gst_cel_video_src_ensure_device_caps_and_formats (self);
-
-  selected_format = NULL;
-
-  for (i = 0; i != self->device_formats->len; i++) {
-    GstCelVideoFormat *format;
-
-    format = &g_array_index (self->device_formats, GstCelVideoFormat, i);
-    if (format->video_format == video_format &&
-        format->width == width && format->height == height &&
-        format->fps_n == fps_n && format->fps_d == fps_d) {
-      selected_format = format;
-      break;
-    }
-  }
-
-  if (selected_format == NULL)
-    goto invalid_format;
-
-  GST_DEBUG_OBJECT (self, "selecting format %u", selected_format->index);
-
-  if (!gst_cel_video_src_select_format (self, selected_format))
-    goto select_failed;
-
-  gst_cel_video_src_release_device_caps_and_formats (self);
-
-  return TRUE;
-
-  /* ERRORS */
-no_device:
-  {
-    GST_ELEMENT_ERROR (self, RESOURCE, FAILED, ("no device"), (NULL));
-    return FALSE;
-  }
-invalid_format:
-  {
-    GST_ELEMENT_ERROR (self, RESOURCE, FAILED, ("invalid format"), (NULL));
-    return FALSE;
-  }
-select_failed:
-  {
-    GST_ELEMENT_ERROR (self, RESOURCE, FAILED, ("failed to select format"),
-        (NULL));
-    return FALSE;
-  }
-}
-
-static gboolean
-gst_cel_video_src_start (GstBaseSrc * basesrc)
-{
-  GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (basesrc);
-
-  g_atomic_int_set (&self->is_running, TRUE);
-  self->offset = 0;
-
-  self->last_sampling = GST_CLOCK_TIME_NONE;
-  self->count = 0;
-  self->fps = -1;
-
-  return TRUE;
-}
-
-static gboolean
-gst_cel_video_src_stop (GstBaseSrc * basesrc)
-{
-  return TRUE;
-}
-
-static gboolean
-gst_cel_video_src_query (GstBaseSrc * basesrc, GstQuery * query)
-{
-  GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (basesrc);
-  gboolean result = FALSE;
-
-  switch (GST_QUERY_TYPE (query)) {
-    case GST_QUERY_LATENCY:{
-      GstClockTime min_latency, max_latency;
-
-      if (self->device == NULL || !GST_CLOCK_TIME_IS_VALID (self->duration))
-        goto beach;
-
-      min_latency = max_latency = self->duration;
-
-      GST_DEBUG_OBJECT (self, "reporting latency of min %" GST_TIME_FORMAT
-          " max %" GST_TIME_FORMAT,
-          GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
-
-      gst_query_set_latency (query, TRUE, min_latency, max_latency);
-      result = TRUE;
-      break;
-    }
-    default:
-      result = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
-      break;
-  }
-
-beach:
-  return result;
-}
-
-static gboolean
-gst_cel_video_src_unlock (GstBaseSrc * basesrc)
-{
-  GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (basesrc);
-
-  g_atomic_int_set (&self->is_running, FALSE);
-
-  QUEUE_READY_LOCK (self);
-  QUEUE_READY_NOTIFY (self);
-  QUEUE_READY_UNLOCK (self);
-
-  return TRUE;
-}
-
-static gboolean
-gst_cel_video_src_unlock_stop (GstBaseSrc * basesrc)
-{
-  return TRUE;
-}
-
-static void
-gst_cel_video_src_on_queue_ready (void *triggerRefcon,
-    CMBufferQueueTriggerToken triggerToken)
-{
-  GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (triggerRefcon);
-
-  QUEUE_READY_LOCK (self);
-  self->queue_is_ready = TRUE;
-  QUEUE_READY_NOTIFY (self);
-  QUEUE_READY_UNLOCK (self);
-}
-
-static void
-gst_cel_video_src_timestamp_buffer (GstCelVideoSrc * self, GstBuffer * buf)
-{
-  GstClock *clock;
-  GstClockTime ts;
-
-  GST_OBJECT_LOCK (self);
-  if ((clock = GST_ELEMENT_CLOCK (self)) != NULL) {
-    ts = gst_clock_get_time (clock);
-
-    if (ts > GST_ELEMENT (self)->base_time)
-      ts -= GST_ELEMENT (self)->base_time;
-    else
-      ts = 0;
-
-    if (ts > self->duration)
-      ts -= self->duration;
-    else
-      ts = 0;
-  } else {
-    ts = GST_CLOCK_TIME_NONE;
-  }
-  GST_OBJECT_UNLOCK (self);
-
-  GST_BUFFER_OFFSET (buf) = self->offset;
-  GST_BUFFER_OFFSET_END (buf) = self->offset + 1;
-  GST_BUFFER_TIMESTAMP (buf) = ts;
-  GST_BUFFER_DURATION (buf) = self->duration;
-
-  if (self->offset == 0)
-    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
-
-  self->offset++;
-}
-
-static void
-gst_cel_video_src_update_statistics (GstCelVideoSrc * self)
-{
-  GstClock *clock;
-
-  GST_OBJECT_LOCK (self);
-  clock = GST_ELEMENT_CLOCK (self);
-  if (clock != NULL)
-    gst_object_ref (clock);
-  GST_OBJECT_UNLOCK (self);
-
-  if (clock != NULL) {
-    GstClockTime now = gst_clock_get_time (clock);
-    gst_object_unref (clock);
-
-    self->count++;
-
-    if (GST_CLOCK_TIME_IS_VALID (self->last_sampling)) {
-      if (now - self->last_sampling >= GST_SECOND) {
-        GST_OBJECT_LOCK (self);
-        self->fps = self->count;
-        GST_OBJECT_UNLOCK (self);
-
-        g_object_notify (G_OBJECT (self), "fps");
-
-        self->last_sampling = now;
-        self->count = 0;
-      }
-    } else {
-      self->last_sampling = now;
-    }
-  }
-}
-
-static GstFlowReturn
-gst_cel_video_src_create (GstPushSrc * pushsrc, GstBuffer ** buf)
-{
-  GstCelVideoSrc *self = GST_CEL_VIDEO_SRC_CAST (pushsrc);
-  GstCMApi *cm = self->ctx->cm;
-  CMSampleBufferRef sbuf;
-
-  sbuf = cm->CMBufferQueueDequeueAndRetain (self->queue);
-
-  while (sbuf == NULL) {
-    QUEUE_READY_LOCK (self);
-    while (!self->queue_is_ready && g_atomic_int_get (&self->is_running))
-      QUEUE_READY_WAIT (self);
-    self->queue_is_ready = FALSE;
-    QUEUE_READY_UNLOCK (self);
-
-    if (G_UNLIKELY (!g_atomic_int_get (&self->is_running)))
-      goto shutting_down;
-
-    sbuf = cm->CMBufferQueueDequeueAndRetain (self->queue);
-  }
-
-  if (G_UNLIKELY (!g_atomic_int_get (&self->is_running)))
-    goto shutting_down;
-
-  *buf = gst_core_media_buffer_new (self->ctx, sbuf);
-  gst_cel_video_src_timestamp_buffer (self, *buf);
-
-  cm->FigSampleBufferRelease (sbuf);
-
-  if (self->do_stats)
-    gst_cel_video_src_update_statistics (self);
-
-  return GST_FLOW_OK;
-
-  /* ERRORS */
-shutting_down:
-  {
-    cm->FigSampleBufferRelease (sbuf);
-    return GST_FLOW_FLUSHING;
-  }
-}
-
-static gboolean
-gst_cel_video_src_open_device (GstCelVideoSrc * self)
-{
-  GstCoreMediaCtx *ctx = NULL;
-  GError *error = NULL;
-  GstCMApi *cm = NULL;
-  GstMTApi *mt = NULL;
-  GstCelApi *cel = NULL;
-  OSStatus status;
-  FigCaptureDeviceRef device = NULL;
-  FigBaseObjectRef device_base;
-  FigBaseVTable *device_vt;
-  CFArrayRef stream_array = NULL;
-  CFIndex stream_index;
-  FigCaptureStreamRef stream = NULL;
-  FigBaseObjectRef stream_base;
-  FigBaseVTable *stream_vt;
-  CMBufferQueueRef queue = NULL;
-  CMTime ignored_time;
-
-  ctx = gst_core_media_ctx_new (GST_API_CORE_VIDEO | GST_API_CORE_MEDIA
-      | GST_API_MEDIA_TOOLBOX | GST_API_CELESTIAL, &error);
-  if (error != NULL)
-    goto api_error;
-  cm = ctx->cm;
-  mt = ctx->mt;
-  cel = ctx->cel;
-
-  status = cel->FigCreateCaptureDevicesAndStreamsForPreset (NULL,
-      *(cel->kFigRecorderCapturePreset_VideoRecording), NULL,
-      &device, &stream, NULL, NULL);
-  if (status == kCelError_ResourceBusy)
-    goto device_busy;
-  else if (status != noErr)
-    goto unexpected_error;
-
-  device_base = mt->FigCaptureDeviceGetFigBaseObject (device);
-  device_vt = cm->FigBaseObjectGetVTable (device_base);
-
-  status = device_vt->base->CopyProperty (device_base,
-      *(mt->kFigCaptureDeviceProperty_StreamArray), NULL,
-      (CFTypeRef *) & stream_array);
-  if (status != noErr)
-    goto unexpected_error;
-
-  if (self->device_index >= 0)
-    stream_index = self->device_index;
-  else
-    stream_index = 0;
-
-  if (stream_index >= CFArrayGetCount (stream_array))
-    goto invalid_device_index;
-
-  CFRelease (stream);
-  stream = (FigCaptureStreamRef) CFArrayGetValueAtIndex (stream_array,
-      stream_index);
-  CFRetain (stream);
-
-  stream_base = mt->FigCaptureStreamGetFigBaseObject (stream);
-  stream_vt = cm->FigBaseObjectGetVTable (stream_base);
-
-  status = stream_vt->base->CopyProperty (stream_base,
-      *(mt->kFigCaptureStreamProperty_BufferQueue), NULL, &queue);
-  if (status != noErr)
-    goto unexpected_error;
-
-  self->queue_is_ready = FALSE;
-
-  ignored_time = cm->CMTimeMake (1, 1);
-  status = cm->CMBufferQueueInstallTrigger (queue,
-      gst_cel_video_src_on_queue_ready, self,
-      kCMBufferQueueTrigger_WhenDataBecomesReady, ignored_time,
-      &self->ready_trigger);
-  if (status != noErr)
-    goto unexpected_error;
-
-  self->ctx = ctx;
-
-  self->device = device;
-  self->device_iface = device_vt->derived;
-  self->device_base = device_base;
-  self->device_base_iface = device_vt->base;
-  self->stream = stream;
-  self->stream_iface = stream_vt->derived;
-  self->stream_base = stream_base;
-  self->stream_base_iface = stream_vt->base;
-
-  self->queue = queue;
-  self->duration = GST_CLOCK_TIME_NONE;
-
-  CFRelease (stream_array);
-
-  return TRUE;
-
-  /* ERRORS */
-api_error:
-  {
-    GST_ELEMENT_ERROR (self, RESOURCE, FAILED, ("API error"),
-        ("%s", error->message));
-    g_clear_error (&error);
-    goto any_error;
-  }
-device_busy:
-  {
-    GST_ELEMENT_ERROR (self, RESOURCE, BUSY,
-        ("device is already in use"), (NULL));
-    goto any_error;
-  }
-invalid_device_index:
-  {
-    GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
-        ("invalid video capture device index"), (NULL));
-    goto any_error;
-  }
-unexpected_error:
-  {
-    GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
-        ("unexpected error while opening device (%d)", (gint) status), (NULL));
-    goto any_error;
-  }
-any_error:
-  {
-    if (stream != NULL)
-      CFRelease (stream);
-    if (stream_array != NULL)
-      CFRelease (stream_array);
-    if (device != NULL)
-      CFRelease (device);
-
-    if (ctx != NULL) {
-      cm->FigBufferQueueRelease (queue);
-      g_object_unref (ctx);
-    }
-
-    return FALSE;
-  }
-}
-
-static void
-gst_cel_video_src_close_device (GstCelVideoSrc * self)
-{
-  gst_cel_video_src_release_device_caps_and_formats (self);
-
-  self->stream_iface->Stop (self->stream);
-  self->stream_base_iface->Finalize (self->stream_base);
-  CFRelease (self->stream);
-  self->stream = NULL;
-  self->stream_iface = NULL;
-  self->stream_base = NULL;
-  self->stream_base_iface = NULL;
-
-  self->device_base_iface->Finalize (self->device_base);
-  CFRelease (self->device);
-  self->device = NULL;
-  self->device_iface = NULL;
-  self->device_base = NULL;
-  self->device_base_iface = NULL;
-
-  self->ctx->cm->CMBufferQueueRemoveTrigger (self->queue, self->ready_trigger);
-  self->ctx->cm->FigBufferQueueRelease (self->queue);
-  self->ready_trigger = NULL;
-  self->queue = NULL;
-
-  g_object_unref (self->ctx);
-  self->ctx = NULL;
-}
-
-static void
-gst_cel_video_src_ensure_device_caps_and_formats (GstCelVideoSrc * self)
-{
-  OSStatus status;
-  CFArrayRef stream_formats = NULL;
-  CFIndex format_count, i;
-
-  if (self->device_caps != NULL)
-    goto already_probed;
-
-  self->device_caps = gst_caps_new_empty ();
-  self->device_formats = g_array_new (FALSE, FALSE, sizeof (GstCelVideoFormat));
-
-  status = self->stream_base_iface->CopyProperty (self->stream_base,
-      *(self->ctx->mt->kFigCaptureStreamProperty_SupportedFormatsArray),
-      NULL, (CFTypeRef *) & stream_formats);
-  if (status != noErr)
-    goto beach;
-
-  format_count = CFArrayGetCount (stream_formats);
-  GST_DEBUG_OBJECT (self, "device supports %d formats", (gint) format_count);
-
-  for (i = 0; i != format_count; i++) {
-    CFDictionaryRef sformat;
-    GstCelVideoFormat format;
-
-    sformat = CFArrayGetValueAtIndex (stream_formats, i);
-
-    if (gst_cel_video_src_parse_stream_format (self, i, sformat, &format)) {
-      gst_caps_append_structure (self->device_caps,
-          gst_structure_new ("video/x-raw-yuv",
-              "format", GST_TYPE_FOURCC, format.fourcc,
-              "width", G_TYPE_INT, format.width,
-              "height", G_TYPE_INT, format.height,
-              "framerate", GST_TYPE_FRACTION, format.fps_n, format.fps_d,
-              "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, NULL));
-      g_array_append_val (self->device_formats, format);
-    } else {
-      GST_WARNING_OBJECT (self, "ignoring unknown format #%d", (gint) i);
-    }
-  }
-
-  CFRelease (stream_formats);
-
-already_probed:
-beach:
-  return;
-}
-
-static void
-gst_cel_video_src_release_device_caps_and_formats (GstCelVideoSrc * self)
-{
-  if (self->device_caps != NULL) {
-    gst_caps_unref (self->device_caps);
-    self->device_caps = NULL;
-  }
-
-  if (self->device_formats != NULL) {
-    g_array_free (self->device_formats, TRUE);
-    self->device_formats = NULL;
-  }
-}
-
-static gboolean
-gst_cel_video_src_select_format (GstCelVideoSrc * self,
-    GstCelVideoFormat * format)
-{
-  gboolean result = FALSE;
-  GstMTApi *mt = self->ctx->mt;
-  GstCelApi *cel = self->ctx->cel;
-  OSStatus status;
-  SInt32 framerate;
-
-  status = gst_cel_video_src_set_stream_property_i32 (self,
-      *(mt->kFigCaptureStreamProperty_FormatIndex), format->index);
-  if (status != noErr)
-    goto beach;
-
-  framerate = format->fps_n / format->fps_d;
-
-  status = gst_cel_video_src_set_stream_property_i32 (self,
-      *(mt->kFigCaptureStreamProperty_MinimumFrameRate), framerate);
-  if (status != noErr)
-    goto beach;
-
-  status = gst_cel_video_src_set_stream_property_i32 (self,
-      *(mt->kFigCaptureStreamProperty_MaximumFrameRate), framerate);
-  if (status != noErr)
-    goto beach;
-
-  status = gst_cel_video_src_set_stream_property_value (self,
-      *(cel->kFigCaptureStreamProperty_ColorRange),
-      *(cel->kFigCapturePropertyValue_ColorRangeSDVideo));
-  if (status != noErr)
-    goto beach;
-
-  status = self->stream_iface->Start (self->stream);
-  if (status != noErr)
-    goto beach;
-
-  GST_DEBUG_OBJECT (self, "configured format %d (%d x %d @ %d Hz)",
-      format->index, format->width, format->height, (gint) framerate);
-
-  self->duration =
-      gst_util_uint64_scale (GST_SECOND, format->fps_d, format->fps_n);
-
-  result = TRUE;
-
-beach:
-  return result;
-}
-
-static gboolean
-gst_cel_video_src_parse_stream_format (GstCelVideoSrc * self,
-    guint index, CFDictionaryRef stream_format, GstCelVideoFormat * format)
-{
-  GstCMApi *cm = self->ctx->cm;
-  GstMTApi *mt = self->ctx->mt;
-  CMFormatDescriptionRef desc;
-  CMVideoDimensions dim;
-  UInt32 subtype;
-  CFNumberRef framerate_value;
-  SInt32 fps_n;
-
-  format->index = index;
-
-  desc = CFDictionaryGetValue (stream_format,
-      *(mt->kFigSupportedFormat_FormatDescription));
-
-  dim = cm->CMVideoFormatDescriptionGetDimensions (desc);
-  format->width = dim.width;
-  format->height = dim.height;
-
-  subtype = cm->CMFormatDescriptionGetMediaSubType (desc);
-
-  switch (subtype) {
-    case kComponentVideoUnsigned:
-      format->video_format = GST_VIDEO_FORMAT_YUY2;
-      format->fourcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
-      break;
-    case kYUV420vCodecType:
-      format->video_format = GST_VIDEO_FORMAT_NV12;
-      format->fourcc = GST_MAKE_FOURCC ('N', 'V', '1', '2');
-      break;
-    default:
-      goto unsupported_format;
-  }
-
-  framerate_value = CFDictionaryGetValue (stream_format,
-      *(mt->kFigSupportedFormat_VideoMaxFrameRate));
-  CFNumberGetValue (framerate_value, kCFNumberSInt32Type, &fps_n);
-  format->fps_n = fps_n;
-  format->fps_d = 1;
-
-  return TRUE;
-
-unsupported_format:
-  return FALSE;
-}
-
-static OSStatus
-gst_cel_video_src_set_stream_property_i32 (GstCelVideoSrc * self,
-    CFStringRef name, SInt32 value)
-{
-  OSStatus status;
-  CFNumberRef number;
-
-  number = CFNumberCreate (NULL, kCFNumberSInt32Type, &value);
-  status = self->stream_base_iface->SetProperty (self->stream_base, name,
-      number);
-  CFRelease (number);
-
-  return status;
-}
-
-static OSStatus
-gst_cel_video_src_set_stream_property_value (GstCelVideoSrc * self,
-    CFStringRef name, CFTypeRef value)
-{
-  return self->stream_base_iface->SetProperty (self->stream_base, name, value);
-}
-
-static void
-gst_cel_video_src_base_init (gpointer gclass)
-{
-  GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
-
-  gst_element_class_set_metadata (element_class,
-      "Video Source (Celestial)", "Source/Video",
-      "Reads frames from an iOS Celestial device",
-      "Ole André Vadla Ravnås <oleavr@soundrop.com>");
-
-  gst_element_class_add_pad_template (element_class,
-      gst_static_pad_template_get (&src_template));
-}
-
-static void
-gst_cel_video_src_class_init (GstCelVideoSrcClass * klass)
-{
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
-  GstBaseSrcClass *gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
-  GstPushSrcClass *gstpushsrc_class = GST_PUSH_SRC_CLASS (klass);
-
-  gobject_class->dispose = gst_cel_video_src_dispose;
-  gobject_class->finalize = gst_cel_video_src_finalize;
-  gobject_class->get_property = gst_cel_video_src_get_property;
-  gobject_class->set_property = gst_cel_video_src_set_property;
-
-  gstelement_class->change_state = gst_cel_video_src_change_state;
-
-  gstbasesrc_class->get_caps = gst_cel_video_src_get_caps;
-  gstbasesrc_class->set_caps = gst_cel_video_src_set_caps;
-  gstbasesrc_class->start = gst_cel_video_src_start;
-  gstbasesrc_class->stop = gst_cel_video_src_stop;
-  gstbasesrc_class->query = gst_cel_video_src_query;
-  gstbasesrc_class->unlock = gst_cel_video_src_unlock;
-  gstbasesrc_class->unlock_stop = gst_cel_video_src_unlock_stop;
-
-  gstpushsrc_class->create = gst_cel_video_src_create;
-
-  g_object_class_install_property (gobject_class, PROP_DEVICE_INDEX,
-      g_param_spec_int ("device-index", "Device Index",
-          "The zero-based device index",
-          -1, G_MAXINT, DEFAULT_DEVICE_INDEX,
-          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_class, PROP_DO_STATS,
-      g_param_spec_boolean ("do-stats", "Enable statistics",
-          "Enable logging of statistics", DEFAULT_DO_STATS,
-          G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_class, PROP_FPS,
-      g_param_spec_int ("fps", "Frames per second",
-          "Last measured framerate, if statistics are enabled",
-          -1, G_MAXINT, -1, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
-  GST_DEBUG_CATEGORY_INIT (gst_cel_video_src_debug, "celvideosrc",
-      0, "iOS Celestial video source");
-}
diff --git a/sys/applemedia/celvideosrc.h b/sys/applemedia/celvideosrc.h
deleted file mode 100644 (file)
index 5fa656c..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef __GST_CEL_VIDEO_SRC_H__
-#define __GST_CEL_VIDEO_SRC_H__
-
-#include <gst/base/gstpushsrc.h>
-
-#include "coremediactx.h"
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_CEL_VIDEO_SRC \
-  (gst_cel_video_src_get_type ())
-#define GST_CEL_VIDEO_SRC(obj) \
-  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CEL_VIDEO_SRC, GstCelVideoSrc))
-#define GST_CEL_VIDEO_SRC_CAST(obj) \
-  ((GstCelVideoSrc *) (obj))
-#define GST_CEL_VIDEO_SRC_CLASS(klass) \
-  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CEL_VIDEO_SRC, GstCelVideoSrcClass))
-#define GST_IS_CEL_VIDEO_SRC(obj) \
-  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CEL_VIDEO_SRC))
-#define GST_IS_CEL_VIDEO_SRC_CLASS(klass) \
-  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CEL_VIDEO_SRC))
-
-typedef struct _GstCelVideoSrc         GstCelVideoSrc;
-typedef struct _GstCelVideoSrcClass    GstCelVideoSrcClass;
-
-struct _GstCelVideoSrc
-{
-  GstPushSrc push_src;
-
-  gint device_index;
-  gboolean do_stats;
-
-  GstCoreMediaCtx *ctx;
-
-  FigCaptureDeviceRef device;
-  FigCaptureDeviceIface *device_iface;
-  FigBaseObjectRef device_base;
-  FigBaseIface *device_base_iface;
-  FigCaptureStreamRef stream;
-  FigCaptureStreamIface *stream_iface;
-  FigBaseObjectRef stream_base;
-  FigBaseIface *stream_base_iface;
-
-  CMBufferQueueRef queue;
-  CMBufferQueueTriggerToken ready_trigger;
-  GstCaps *device_caps;
-  GArray *device_formats;
-  GstClockTime duration;
-
-  volatile gint is_running;
-  guint64 offset;
-
-  GCond *ready_cond;
-  volatile gboolean queue_is_ready;
-
-  GstClockTime last_sampling;
-  guint count;
-  gint fps;
-};
-
-struct _GstCelVideoSrcClass
-{
-  GstPushSrcClass parent_class;
-};
-
-GType gst_cel_video_src_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GST_CEL_VIDEO_SRC_H__ */
index 804a2f386b53c3ecfc06a45f5347c94521103461..55e7119a360d8b060733baa594fb23da33ae9c13 100644 (file)
@@ -44,12 +44,6 @@ static const GstApiProvider api_provider[] = {
   API_PROVIDER (CORE_VIDEO, cv),
   API_PROVIDER (CORE_MEDIA, cm),
   API_PROVIDER (VIDEO_TOOLBOX, vt),
-#ifdef HAVE_IOS
-  API_PROVIDER (MEDIA_TOOLBOX, mt),
-  API_PROVIDER (CELESTIAL, cel)
-#else
-  API_PROVIDER (MIO, mio),
-#endif
 };
 
 G_DEFINE_TYPE (GstCoreMediaCtx, gst_core_media_ctx, G_TYPE_OBJECT);
index f058bef8c5226fe6826844c822adc7f769ef8ad3..45fcf30562a2ecaf060fb73137996d5f4d6d49a0 100644 (file)
 #include "cmapi.h"
 #include "vtapi.h"
 
-#include "mioapi.h"
-
-#include "mtapi.h"
-#include "celapi.h"
-
 #include <glib.h>
 
 G_BEGIN_DECLS
@@ -59,13 +54,6 @@ struct _GstCoreMediaCtx
   GstCVApi *cv;
   GstCMApi *cm;
   GstVTApi *vt;
-
-  /* OS X */
-  GstMIOApi *mio;
-
-  /* iPhone */
-  GstMTApi *mt;
-  GstCelApi *cel;
 };
 
 struct _GstCoreMediaCtxClass
@@ -78,11 +66,6 @@ enum _GstCoreMediaApi
   GST_API_CORE_VIDEO    = (1 << 0),
   GST_API_CORE_MEDIA    = (1 << 1),
   GST_API_VIDEO_TOOLBOX = (1 << 2),
-
-  GST_API_MIO           = (1 << 3),
-
-  GST_API_MEDIA_TOOLBOX = (1 << 4),
-  GST_API_CELESTIAL     = (1 << 5)
 };
 
 GType gst_core_media_ctx_get_type (void);
diff --git a/sys/applemedia/mioapi.c b/sys/applemedia/mioapi.c
deleted file mode 100644 (file)
index 30d3d35..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "mioapi.h"
-
-#include "dynapi-internal.h"
-
-#define MIO_FRAMEWORK_PATH "/System/Library/PrivateFrameworks/" \
-    "CoreMediaIOServices.framework/CoreMediaIOServices"
-
-GType gst_mio_api_get_type (void);
-
-G_DEFINE_TYPE (GstMIOApi, gst_mio_api, GST_TYPE_DYN_API);
-
-static void
-gst_mio_api_init (GstMIOApi * self)
-{
-}
-
-static void
-gst_mio_api_class_init (GstMIOApiClass * klass)
-{
-}
-
-#define SYM_SPEC(name) GST_DYN_SYM_SPEC (GstMIOApi, name)
-
-GstMIOApi *
-gst_mio_api_obtain (GError ** error)
-{
-  static const GstDynSymSpec symbols[] = {
-    SYM_SPEC (TundraGraphCreate),
-    SYM_SPEC (TundraGraphRelease),
-    SYM_SPEC (TundraGraphCreateNode),
-    SYM_SPEC (TundraGraphGetNodeInfo),
-    SYM_SPEC (TundraGraphSetProperty),
-    SYM_SPEC (TundraGraphConnectNodeInput),
-    SYM_SPEC (TundraGraphInitialize),
-    SYM_SPEC (TundraGraphUninitialize),
-    SYM_SPEC (TundraGraphStart),
-    SYM_SPEC (TundraGraphStop),
-
-    SYM_SPEC (TundraObjectGetPropertyDataSize),
-    SYM_SPEC (TundraObjectGetPropertyData),
-    SYM_SPEC (TundraObjectIsPropertySettable),
-    SYM_SPEC (TundraObjectSetPropertyData),
-
-    SYM_SPEC (kTundraSampleBufferAttachmentKey_SequenceNumber),
-    SYM_SPEC (kTundraSampleBufferAttachmentKey_HostTime),
-
-    {NULL, 0},
-  };
-
-  return _gst_dyn_api_new (gst_mio_api_get_type (), MIO_FRAMEWORK_PATH, symbols,
-      error);
-}
-
-gpointer
-gst_mio_object_get_pointer (gint obj, TundraTargetSpec * pspec, GstMIOApi * mio)
-{
-  gpointer ptr;
-  guint sz;
-  TundraStatus status;
-
-  sz = sizeof (ptr);
-  status = mio->TundraObjectGetPropertyData (obj, pspec, 0, NULL, &sz, &ptr);
-  if (status != kTundraSuccess)
-    goto error;
-
-  return ptr;
-
-error:
-  return NULL;
-}
-
-gchar *
-gst_mio_object_get_string (gint obj, TundraTargetSpec * pspec, GstMIOApi * mio)
-{
-  gchar *result = NULL;
-  CFStringRef str;
-  guint size;
-  TundraStatus status;
-  CFRange range;
-
-  size = sizeof (str);
-  status = mio->TundraObjectGetPropertyData (obj, pspec, 0, NULL, &size, &str);
-  if (status != kTundraSuccess)
-    goto error;
-
-  range.location = 0;
-  range.length = CFStringGetLength (str);
-  result = g_malloc0 (range.length + 1);
-  CFStringGetBytes (str, range, kCFStringEncodingUTF8, 0, FALSE,
-      (UInt8 *) result, range.length, NULL);
-  CFRelease (str);
-
-  return result;
-
-error:
-  return NULL;
-}
-
-guint32
-gst_mio_object_get_uint32 (gint obj, TundraTargetSpec * pspec, GstMIOApi * mio)
-{
-  guint32 val;
-  guint size;
-  TundraStatus status;
-
-  size = sizeof (val);
-  status = mio->TundraObjectGetPropertyData (obj, pspec, 0, NULL, &size, &val);
-  if (status != kTundraSuccess)
-    goto error;
-
-  return val;
-
-error:
-  return 0;
-}
-
-GArray *
-gst_mio_object_get_array (gint obj, TundraTargetSpec * pspec,
-    guint element_size, GstMIOApi * mio)
-{
-  return gst_mio_object_get_array_full (obj, pspec, 0, NULL, element_size, mio);
-}
-
-GArray *
-gst_mio_object_get_array_full (gint obj, TundraTargetSpec * pspec,
-    guint ctx_size, gpointer ctx, guint element_size, GstMIOApi * mio)
-{
-  GArray *arr = NULL;
-  guint size, num_elements;
-  TundraStatus status;
-
-  status = mio->TundraObjectGetPropertyDataSize (obj, pspec, ctx_size, ctx,
-      &size);
-  if (status != kTundraSuccess)
-    goto error;
-  else if (size % element_size != 0)
-    goto error;
-
-  num_elements = size / element_size;
-  arr = g_array_sized_new (FALSE, TRUE, element_size, num_elements);
-  g_array_set_size (arr, num_elements);
-
-  status = mio->TundraObjectGetPropertyData (obj, pspec, ctx_size, ctx,
-      &size, arr->data);
-  if (status != kTundraSuccess)
-    goto error;
-
-  return arr;
-
-error:
-  if (arr != NULL)
-    g_array_free (arr, TRUE);
-  return NULL;
-}
-
-gchar *
-gst_mio_object_get_fourcc (gint obj, TundraTargetSpec * pspec, GstMIOApi * mio)
-{
-  guint32 fcc;
-  guint size;
-  TundraStatus status;
-
-  size = sizeof (fcc);
-  status = mio->TundraObjectGetPropertyData (obj, pspec, 0, NULL, &size, &fcc);
-  if (status != kTundraSuccess)
-    goto error;
-
-  return gst_mio_fourcc_to_string (fcc);
-
-error:
-  return NULL;
-}
-
-gpointer
-gst_mio_object_get_raw (gint obj, TundraTargetSpec * pspec, guint * size,
-    GstMIOApi * mio)
-{
-  gpointer data = NULL;
-  guint sz;
-  TundraStatus status;
-
-  status = mio->TundraObjectGetPropertyDataSize (obj, pspec, 0, NULL, &sz);
-  if (status != kTundraSuccess)
-    goto error;
-
-  data = g_malloc0 (sz);
-
-  status = mio->TundraObjectGetPropertyData (obj, pspec, 0, NULL, &sz, data);
-  if (status != kTundraSuccess)
-    goto error;
-
-  if (size != NULL)
-    *size = sz;
-  return data;
-
-error:
-  g_free (data);
-  if (size != NULL)
-    *size = 0;
-  return NULL;
-}
-
-gchar *
-gst_mio_fourcc_to_string (guint32 fcc)
-{
-  gchar *result;
-
-  result = g_malloc0 (5);
-  result[0] = (fcc >> 24) & 0xff;
-  result[1] = (fcc >> 16) & 0xff;
-  result[2] = (fcc >> 8) & 0xff;
-  result[3] = (fcc >> 0) & 0xff;
-
-  return result;
-}
diff --git a/sys/applemedia/mioapi.h b/sys/applemedia/mioapi.h
deleted file mode 100644 (file)
index fe2cbd8..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef __GST_MIO_API_H__
-#define __GST_MIO_API_H__
-
-#include "cmapi.h"
-
-#include <CoreFoundation/CoreFoundation.h>
-
-G_BEGIN_DECLS
-
-typedef struct _GstMIOApi GstMIOApi;
-typedef struct _GstMIOApiClass GstMIOApiClass;
-
-#define TUNDRA_SYSTEM_OBJECT_ID 1
-
-typedef int TundraObjectID;
-typedef int TundraDeviceID;
-typedef int TundraUnitID;
-
-typedef enum _TundraStatus TundraStatus;
-typedef enum _TundraVendor TundraVendor;
-typedef enum _TundraScope TundraScope;
-typedef enum _TundraUnit TundraUnit;
-typedef enum _TundraProperty TundraProperty;
-
-typedef enum _TundraDeviceTransportType TundraDeviceTransportType;
-
-typedef struct _TundraTargetSpec TundraTargetSpec;
-typedef struct _TundraFramerate TundraFramerate;
-
-typedef struct _TundraGraph TundraGraph;
-typedef struct _TundraNode TundraNode;
-
-typedef struct _TundraOutputDelegate TundraOutputDelegate;
-
-enum _TundraStatus
-{
-  kTundraSuccess = 0,
-  kTundraNotSupported = -67456
-};
-
-enum _TundraVendor
-{
-  kTundraVendorApple = 'appl'
-};
-
-enum _TundraScope
-{
-  kTundraScopeGlobal = 'glob',
-  kTundraScopeDAL    = 'dal ',
-  kTundraScope2PRC   = '2prc', /* TODO: Investigate this one */
-  kTundraScopeInput  = 'inpt',
-  kTundraScopeVSyn   = 'vsyn'
-};
-
-enum _TundraUnit
-{
-  kTundraUnitInput  = 'tinp',
-  kTundraUnitOutput = 'tout',
-  kTundraUnitSync   = 'tefc'
-};
-
-enum _TundraProperty
-{
-  kTundraSystemPropertyDevices = 'dev#',
-
-  kTundraObjectPropertyClass = 'clas',
-  kTundraObjectPropertyCreator = 'oplg',
-  kTundraObjectPropertyName = 'lnam',
-  kTundraObjectPropertyUID = 'uid ',
-  kTundraObjectPropertyVendor = 'lmak',
-
-  kTundraDevicePropertyConfigApp = 'capp', /* CFString: com.apple.mediaio.TundraDeviceSetup */
-  kTundraDevicePropertyExclusiveMode = 'ixna',
-  kTundraDevicePropertyHogMode = 'oink',
-  kTundraDevicePropertyModelUID = 'muid',
-  kTundraDevicePropertyStreams = 'stm#',
-  kTundraDevicePropertySuspendedByUser = 'sbyu',
-  kTundraDevicePropertyTransportType = 'tran',
-
-  kTundraStreamPropertyFormatDescriptions = 'pfta',
-  kTundraStreamPropertyFormatDescription = 'pft ',
-  kTundraStreamPropertyFrameRates = 'nfr#',
-  kTundraStreamPropertyFrameRate = 'nfrt'
-};
-
-struct _TundraTargetSpec
-{
-  FourCharCode name;
-  FourCharCode scope;
-  FourCharCode vendor;
-  FourCharCode unk1;
-  FourCharCode unk2;
-};
-
-struct _TundraFramerate
-{
-  gdouble value;
-};
-
-enum _TundraUnitProperty
-{
-  kTundraInputPropertyDeviceID                = 302,
-
-  kTundraOutputPropertyDelegate               = 5903,
-
-  kTundraInputUnitProperty_SourcePath         = 6780,
-
-  kTundraSyncPropertyClockProvider            = 7100,
-  kTundraSyncPropertyMasterSynchronizer       = 7102,
-  kTundraSyncPropertySynchronizationDirection = 7104
-};
-
-enum _TundraDeviceTransportType
-{
-  kTundraDeviceTransportInvalid = 0,
-  kTundraDeviceTransportBuiltin = 'bltn',
-  kTundraDeviceTransportScreen  = 'scrn',
-  kTundraDeviceTransportUSB     = 'usb ',
-};
-
-typedef TundraStatus (* TundraOutputRenderFunc) (gpointer instance,
-    gpointer unk1, gpointer unk2, gpointer unk3, CMSampleBufferRef sampleBuf);
-typedef TundraStatus (* TundraOutputInitializeFunc) (gpointer instance);
-typedef TundraStatus (* TundraOutputUninitializeFunc) (gpointer instance);
-typedef TundraStatus (* TundraOutputStartFunc) (gpointer instance);
-typedef TundraStatus (* TundraOutputStopFunc) (gpointer instance);
-typedef TundraStatus (* TundraOutputResetFunc) (gpointer instance);
-typedef TundraStatus (* TundraOutputDeallocateFunc) (gpointer instance);
-typedef gboolean (* TundraOutputCanRenderNowFunc) (gpointer instance,
-    guint * unk);
-typedef CFArrayRef (* TundraOutputAvailableFormatsFunc) (gpointer instance,
-    gboolean ensureOnly);
-typedef TundraStatus (* TundraOutputCopyClockFunc) (gpointer instance);
-typedef TundraStatus (* TundraOutputGetPropertyInfoFunc) (gpointer instance,
-    guint propId);
-typedef TundraStatus (* TundraOutputGetPropertyFunc) (gpointer instance,
-    guint propId);
-typedef TundraStatus (* TundraOutputSetPropertyFunc) (gpointer instance,
-    guint propId);
-
-#pragma pack(push, 1)
-
-struct _TundraOutputDelegate
-{
-  int unk1;
-  gpointer instance;
-  TundraOutputRenderFunc Render;
-  TundraOutputInitializeFunc Initialize;
-  TundraOutputUninitializeFunc Uninitialize;
-  TundraOutputStartFunc Start;
-  TundraOutputStopFunc Stop;
-  TundraOutputResetFunc Reset;
-  TundraOutputDeallocateFunc Deallocate;
-  TundraOutputCanRenderNowFunc CanRenderNow;
-  TundraOutputAvailableFormatsFunc AvailableFormats;
-  TundraOutputCopyClockFunc CopyClock;
-  TundraOutputGetPropertyInfoFunc GetPropertyInfo;
-  TundraOutputGetPropertyFunc GetProperty;
-  TundraOutputSetPropertyFunc SetProperty;
-};
-
-#pragma pack(pop)
-
-struct _GstMIOApi
-{
-  GstDynApi parent;
-
-  TundraStatus (* TundraGraphCreate) (CFAllocatorRef allocator,
-      TundraGraph ** graph);
-  void (* TundraGraphRelease) (TundraGraph * graph);
-  TundraStatus (* TundraGraphCreateNode) (TundraGraph * graph,
-      gint nodeId, UInt32 unk1, UInt32 unk2, TundraTargetSpec * spec,
-      UInt32 unk3, TundraUnitID * node);
-  TundraStatus (* TundraGraphGetNodeInfo) (TundraGraph * graph,
-      gint nodeId, UInt32 unk1, UInt32 unk2, UInt32 unk3, UInt32 unk4,
-      gpointer * info);
-  TundraStatus (* TundraGraphSetProperty) (TundraGraph * graph,
-      gint nodeId, UInt32 unk1, guint propId, UInt32 unk2, UInt32 unk3,
-      gpointer data, guint size);
-  TundraStatus (* TundraGraphConnectNodeInput) (TundraGraph * graph,
-      TundraUnitID from_node, guint from_bus,
-      TundraUnitID to_node, guint to_bus);
-  TundraStatus (* TundraGraphInitialize) (TundraGraph * graph);
-  TundraStatus (* TundraGraphUninitialize) (TundraGraph * graph);
-  TundraStatus (* TundraGraphStart) (TundraGraph * graph);
-  TundraStatus (* TundraGraphStop) (TundraGraph * graph);
-
-  TundraStatus (* TundraObjectGetPropertyDataSize) (TundraObjectID obj,
-      TundraTargetSpec * spec, UInt32 contextSize, void * context, guint * size);
-  TundraStatus (* TundraObjectGetPropertyData) (TundraObjectID obj,
-      TundraTargetSpec * spec, UInt32 contextSize, void * context, guint * size,
-      gpointer data);
-  TundraStatus (* TundraObjectIsPropertySettable) (TundraObjectID obj,
-      TundraTargetSpec * spec, Boolean *isSettable);
-  TundraStatus (* TundraObjectSetPropertyData) (TundraObjectID obj,
-      TundraTargetSpec * spec, gpointer unk1, gpointer unk2, guint size,
-      gpointer data);
-
-  CFStringRef * kTundraSampleBufferAttachmentKey_SequenceNumber;
-  CFStringRef * kTundraSampleBufferAttachmentKey_HostTime;
-};
-
-struct _GstMIOApiClass
-{
-  GstDynApiClass parent_class;
-};
-
-GstMIOApi * gst_mio_api_obtain (GError ** error);
-
-gpointer gst_mio_object_get_pointer (gint obj, TundraTargetSpec * pspec,
-    GstMIOApi * mio);
-gchar * gst_mio_object_get_string (gint obj, TundraTargetSpec * pspec,
-    GstMIOApi * mio);
-guint32 gst_mio_object_get_uint32 (gint obj, TundraTargetSpec * pspec,
-    GstMIOApi * mio);
-gchar * gst_mio_object_get_fourcc (gint obj, TundraTargetSpec * pspec,
-    GstMIOApi * mio);
-GArray * gst_mio_object_get_array (gint obj, TundraTargetSpec * pspec,
-    guint element_size, GstMIOApi * mio);
-GArray * gst_mio_object_get_array_full (gint obj, TundraTargetSpec * pspec,
-    guint ctx_size, gpointer ctx, guint element_size, GstMIOApi * mio);
-gpointer gst_mio_object_get_raw (gint obj, TundraTargetSpec * pspec,
-    guint * size, GstMIOApi * mio);
-
-gchar * gst_mio_fourcc_to_string (guint32 fcc);
-
-G_END_DECLS
-
-#endif
diff --git a/sys/applemedia/miovideodevice.c b/sys/applemedia/miovideodevice.c
deleted file mode 100644 (file)
index 252c718..0000000
+++ /dev/null
@@ -1,846 +0,0 @@
-/*
- * Copyright (C) 2009 Ole André Vadla Ravnås <oleavr@soundrop.com>
- *               2009 Knut Inge Hvidsten <knuhvids@cisco.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "miovideodevice.h"
-
-#include <gst/video/video.h>
-
-#include <unistd.h>
-
-GST_DEBUG_CATEGORY_EXTERN (gst_mio_video_src_debug);
-#define GST_CAT_DEFAULT gst_mio_video_src_debug
-
-enum
-{
-  PROP_0,
-  PROP_CONTEXT,
-  PROP_HANDLE,
-  PROP_UID,
-  PROP_NAME,
-  PROP_TRANSPORT
-};
-
-G_DEFINE_TYPE (GstMIOVideoDevice, gst_mio_video_device, G_TYPE_OBJECT);
-
-typedef struct _GstMIOVideoFormat GstMIOVideoFormat;
-typedef struct _GstMIOSetFormatCtx GstMIOSetFormatCtx;
-typedef struct _GstMIOFindRateCtx GstMIOFindRateCtx;
-
-struct _GstMIOVideoFormat
-{
-  TundraObjectID stream;
-  CMFormatDescriptionRef desc;
-
-  UInt32 type;
-  CMVideoDimensions dim;
-};
-
-struct _GstMIOSetFormatCtx
-{
-  UInt32 format;
-  gint width, height;
-  gint fps_n, fps_d;
-  gboolean success;
-};
-
-struct _GstMIOFindRateCtx
-{
-  gdouble needle;
-  gdouble closest_match;
-  gboolean success;
-};
-
-static void gst_mio_video_device_collect_format (GstMIOVideoDevice * self,
-    GstMIOVideoFormat * format, gpointer user_data);
-static GstStructure *gst_mio_video_device_format_basics_to_structure
-    (GstMIOVideoDevice * self, GstMIOVideoFormat * format);
-static gboolean gst_mio_video_device_add_framerates_to_structure
-    (GstMIOVideoDevice * self, GstMIOVideoFormat * format, GstStructure * s);
-static void gst_mio_video_device_add_pixel_aspect_to_structure
-    (GstMIOVideoDevice * self, GstMIOVideoFormat * format, GstStructure * s);
-
-static void gst_mio_video_device_append_framerate (GstMIOVideoDevice * self,
-    GstMIOVideoFormat * format, TundraFramerate * rate, gpointer user_data);
-static void gst_mio_video_device_framerate_to_fraction_value
-    (TundraFramerate * rate, GValue * fract);
-static gdouble gst_mio_video_device_round_to_whole_hundreths (gdouble value);
-static void gst_mio_video_device_guess_pixel_aspect_ratio
-    (gint width, gint height, gint * par_width, gint * par_height);
-
-static void gst_mio_video_device_activate_matching_format
-    (GstMIOVideoDevice * self, GstMIOVideoFormat * format, gpointer user_data);
-static void gst_mio_video_device_find_closest_framerate
-    (GstMIOVideoDevice * self, GstMIOVideoFormat * format,
-    TundraFramerate * rate, gpointer user_data);
-
-typedef void (*GstMIOVideoDeviceEachFormatFunc) (GstMIOVideoDevice * self,
-    GstMIOVideoFormat * format, gpointer user_data);
-typedef void (*GstMIOVideoDeviceEachFramerateFunc) (GstMIOVideoDevice * self,
-    GstMIOVideoFormat * format, TundraFramerate * rate, gpointer user_data);
-static void gst_mio_video_device_formats_foreach (GstMIOVideoDevice * self,
-    GstMIOVideoDeviceEachFormatFunc func, gpointer user_data);
-static void gst_mio_video_device_format_framerates_foreach
-    (GstMIOVideoDevice * self, GstMIOVideoFormat * format,
-    GstMIOVideoDeviceEachFramerateFunc func, gpointer user_data);
-
-static gint gst_mio_video_device_compare (GstMIOVideoDevice * a,
-    GstMIOVideoDevice * b);
-static gint gst_mio_video_device_calculate_score (GstMIOVideoDevice * device);
-
-static void
-gst_mio_video_device_init (GstMIOVideoDevice * self)
-{
-}
-
-static void
-gst_mio_video_device_dispose (GObject * object)
-{
-  GstMIOVideoDevice *self = GST_MIO_VIDEO_DEVICE_CAST (object);
-
-  if (self->cached_caps != NULL) {
-    gst_caps_unref (self->cached_caps);
-    self->cached_caps = NULL;
-  }
-
-  G_OBJECT_CLASS (gst_mio_video_device_parent_class)->dispose (object);
-}
-
-static void
-gst_mio_video_device_finalize (GObject * object)
-{
-  GstMIOVideoDevice *self = GST_MIO_VIDEO_DEVICE_CAST (object);
-
-  g_free (self->cached_uid);
-  g_free (self->cached_name);
-
-  G_OBJECT_CLASS (gst_mio_video_device_parent_class)->finalize (object);
-}
-
-static void
-gst_mio_video_device_get_property (GObject * object, guint prop_id,
-    GValue * value, GParamSpec * pspec)
-{
-  GstMIOVideoDevice *self = GST_MIO_VIDEO_DEVICE (object);
-
-  switch (prop_id) {
-    case PROP_CONTEXT:
-      g_value_set_pointer (value, self->ctx);
-      break;
-    case PROP_HANDLE:
-      g_value_set_int (value, gst_mio_video_device_get_handle (self));
-      break;
-    case PROP_UID:
-      g_value_set_string (value, gst_mio_video_device_get_uid (self));
-      break;
-    case PROP_NAME:
-      g_value_set_string (value, gst_mio_video_device_get_name (self));
-      break;
-    case PROP_TRANSPORT:
-      g_value_set_uint (value, gst_mio_video_device_get_transport_type (self));
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-}
-
-static void
-gst_mio_video_device_set_property (GObject * object, guint prop_id,
-    const GValue * value, GParamSpec * pspec)
-{
-  GstMIOVideoDevice *self = GST_MIO_VIDEO_DEVICE (object);
-
-  switch (prop_id) {
-    case PROP_CONTEXT:
-      self->ctx = g_value_get_pointer (value);
-      break;
-    case PROP_HANDLE:
-      self->handle = g_value_get_int (value);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-}
-
-TundraObjectID
-gst_mio_video_device_get_handle (GstMIOVideoDevice * self)
-{
-  return self->handle;
-}
-
-const gchar *
-gst_mio_video_device_get_uid (GstMIOVideoDevice * self)
-{
-  if (self->cached_uid == NULL) {
-    TundraTargetSpec pspec = { 0, };
-
-    pspec.name = kTundraObjectPropertyUID;
-    pspec.scope = kTundraScopeGlobal;
-    self->cached_uid =
-        gst_mio_object_get_string (self->handle, &pspec, self->ctx->mio);
-  }
-
-  return self->cached_uid;
-}
-
-const gchar *
-gst_mio_video_device_get_name (GstMIOVideoDevice * self)
-{
-  if (self->cached_name == NULL) {
-    TundraTargetSpec pspec = { 0, };
-
-    pspec.name = kTundraObjectPropertyName;
-    pspec.scope = kTundraScopeGlobal;
-    self->cached_name =
-        gst_mio_object_get_string (self->handle, &pspec, self->ctx->mio);
-  }
-
-  return self->cached_name;
-}
-
-TundraDeviceTransportType
-gst_mio_video_device_get_transport_type (GstMIOVideoDevice * self)
-{
-  if (self->cached_transport == kTundraDeviceTransportInvalid) {
-    TundraTargetSpec pspec = { 0, };
-
-    pspec.name = kTundraDevicePropertyTransportType;
-    pspec.scope = kTundraScopeGlobal;
-    self->cached_transport =
-        gst_mio_object_get_uint32 (self->handle, &pspec, self->ctx->mio);
-  }
-
-  return self->cached_transport;
-}
-
-gboolean
-gst_mio_video_device_open (GstMIOVideoDevice * self)
-{
-  /* nothing for now */
-  return TRUE;
-}
-
-void
-gst_mio_video_device_close (GstMIOVideoDevice * self)
-{
-  /* nothing for now */
-}
-
-GstCaps *
-gst_mio_video_device_get_available_caps (GstMIOVideoDevice * self)
-{
-  if (self->cached_caps == NULL) {
-    GstCaps *caps;
-
-    caps = gst_caps_new_empty ();
-    gst_mio_video_device_formats_foreach (self,
-        gst_mio_video_device_collect_format, caps);
-
-    self->cached_caps = caps;
-  }
-
-  return self->cached_caps;
-}
-
-static void
-gst_mio_video_device_collect_format (GstMIOVideoDevice * self,
-    GstMIOVideoFormat * format, gpointer user_data)
-{
-  GstCaps *caps = user_data;
-  GstStructure *s;
-
-  s = gst_mio_video_device_format_basics_to_structure (self, format);
-  if (s == NULL)
-    goto unsupported_format;
-
-  if (!gst_mio_video_device_add_framerates_to_structure (self, format, s))
-    goto no_framerates;
-
-  gst_mio_video_device_add_pixel_aspect_to_structure (self, format, s);
-
-  gst_caps_append_structure (caps, s);
-
-  return;
-
-  /* ERRORS */
-unsupported_format:
-  {
-    gchar *fcc;
-
-    fcc = gst_mio_fourcc_to_string (format->type);
-    GST_WARNING ("skipping unsupported format %s", fcc);
-    g_free (fcc);
-
-    return;
-  }
-no_framerates:
-  {
-    GST_WARNING ("no framerates?");
-
-    gst_structure_free (s);
-
-    return;
-  }
-}
-
-static GstStructure *
-gst_mio_video_device_format_basics_to_structure (GstMIOVideoDevice * self,
-    GstMIOVideoFormat * format)
-{
-  GstStructure *s;
-
-  switch (format->type) {
-    case kCVPixelFormatType_422YpCbCr8:
-    case kCVPixelFormatType_422YpCbCr8Deprecated:
-    {
-      guint fcc;
-
-      if (format->type == kCVPixelFormatType_422YpCbCr8)
-        fcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
-      else
-        fcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
-
-      s = gst_structure_new ("video/x-raw-yuv",
-          "format", GST_TYPE_FOURCC, fcc,
-          "width", G_TYPE_INT, format->dim.width,
-          "height", G_TYPE_INT, format->dim.height, NULL);
-      break;
-    }
-    case kFigVideoCodecType_JPEG_OpenDML:
-    {
-      s = gst_structure_new ("image/jpeg",
-          "width", G_TYPE_INT, format->dim.width,
-          "height", G_TYPE_INT, format->dim.height, NULL);
-      break;
-    }
-    default:
-      s = NULL;
-      break;
-  }
-
-  return s;
-}
-
-static gboolean
-gst_mio_video_device_add_framerates_to_structure (GstMIOVideoDevice * self,
-    GstMIOVideoFormat * format, GstStructure * s)
-{
-  GValue rates = { 0, };
-  const GValue *rates_value;
-
-  g_value_init (&rates, GST_TYPE_LIST);
-
-  gst_mio_video_device_format_framerates_foreach (self, format,
-      gst_mio_video_device_append_framerate, &rates);
-  if (gst_value_list_get_size (&rates) == 0)
-    goto no_framerates;
-
-  if (gst_value_list_get_size (&rates) > 1)
-    rates_value = &rates;
-  else
-    rates_value = gst_value_list_get_value (&rates, 0);
-  gst_structure_set_value (s, "framerate", rates_value);
-
-  g_value_unset (&rates);
-
-  return TRUE;
-
-  /* ERRORS */
-no_framerates:
-  {
-    g_value_unset (&rates);
-    return FALSE;
-  }
-}
-
-static void
-gst_mio_video_device_add_pixel_aspect_to_structure (GstMIOVideoDevice * self,
-    GstMIOVideoFormat * format, GstStructure * s)
-{
-  gint par_width, par_height;
-
-  gst_mio_video_device_guess_pixel_aspect_ratio
-      (format->dim.width, format->dim.height, &par_width, &par_height);
-
-  gst_structure_set (s, "pixel-aspect-ratio",
-      GST_TYPE_FRACTION, par_width, par_height, NULL);
-}
-
-static void
-gst_mio_video_device_append_framerate (GstMIOVideoDevice * self,
-    GstMIOVideoFormat * format, TundraFramerate * rate, gpointer user_data)
-{
-  GValue *rates = user_data;
-  GValue value = { 0, };
-
-  g_value_init (&value, GST_TYPE_FRACTION);
-  gst_mio_video_device_framerate_to_fraction_value (rate, &value);
-  gst_value_list_append_value (rates, &value);
-  g_value_unset (&value);
-}
-
-static void
-gst_mio_video_device_framerate_to_fraction_value (TundraFramerate * rate,
-    GValue * fract)
-{
-  gdouble rounded;
-  gint n, d;
-
-  rounded = gst_mio_video_device_round_to_whole_hundreths (rate->value);
-  gst_util_double_to_fraction (rounded, &n, &d);
-  gst_value_set_fraction (fract, n, d);
-}
-
-static gdouble
-gst_mio_video_device_round_to_whole_hundreths (gdouble value)
-{
-  gdouble m, x, y, z;
-
-  m = 0.01;
-  x = value;
-  y = floor ((x / m) + 0.5);
-  z = y * m;
-
-  return z;
-}
-
-static void
-gst_mio_video_device_guess_pixel_aspect_ratio (gint width, gint height,
-    gint * par_width, gint * par_height)
-{
-  /*
-   * As we dont have access to the actual pixel aspect, we will try to do a
-   * best-effort guess. The guess is based on most sensors being either 4/3
-   * or 16/9, and most pixel aspects being close to 1/1.
-   */
-
-  if (width == 768 && height == 448) {  /* special case for w448p */
-    *par_width = 28;
-    *par_height = 27;
-  } else {
-    if (((gdouble) width / (gdouble) height) < 1.2778) {
-      *par_width = 12;
-      *par_height = 11;
-    } else {
-      *par_width = 1;
-      *par_height = 1;
-    }
-  }
-}
-
-gboolean
-gst_mio_video_device_set_caps (GstMIOVideoDevice * self, GstCaps * caps)
-{
-  GstVideoFormat format;
-  GstMIOSetFormatCtx ctx = { 0, };
-
-  if (gst_video_format_parse_caps (caps, &format, &ctx.width, &ctx.height)) {
-    if (format == GST_VIDEO_FORMAT_UYVY)
-      ctx.format = kCVPixelFormatType_422YpCbCr8;
-    else if (format == GST_VIDEO_FORMAT_YUY2)
-      ctx.format = kCVPixelFormatType_422YpCbCr8Deprecated;
-    else
-      g_assert_not_reached ();
-  } else {
-    GstStructure *s;
-
-    s = gst_caps_get_structure (caps, 0);
-    g_assert (gst_structure_has_name (s, "image/jpeg"));
-    gst_structure_get_int (s, "width", &ctx.width);
-    gst_structure_get_int (s, "height", &ctx.height);
-
-    ctx.format = kFigVideoCodecType_JPEG_OpenDML;
-  }
-
-  gst_video_parse_caps_framerate (caps, &ctx.fps_n, &ctx.fps_d);
-
-  gst_mio_video_device_formats_foreach (self,
-      gst_mio_video_device_activate_matching_format, &ctx);
-
-  return ctx.success;
-}
-
-static void
-gst_mio_video_device_activate_matching_format (GstMIOVideoDevice * self,
-    GstMIOVideoFormat * format, gpointer user_data)
-{
-  GstMIOSetFormatCtx *ctx = user_data;
-  GstMIOFindRateCtx find_ctx;
-  TundraTargetSpec spec = { 0, };
-  TundraStatus status;
-
-  if (format->type != ctx->format)
-    return;
-  else if (format->dim.width != ctx->width)
-    return;
-  else if (format->dim.height != ctx->height)
-    return;
-
-  find_ctx.needle = (gdouble) ctx->fps_n / (gdouble) ctx->fps_d;
-  find_ctx.closest_match = 0.0;
-  find_ctx.success = FALSE;
-  gst_mio_video_device_format_framerates_foreach (self, format,
-      gst_mio_video_device_find_closest_framerate, &find_ctx);
-  if (!find_ctx.success)
-    goto no_matching_framerate_found;
-
-  spec.scope = kTundraScopeInput;
-
-  spec.name = kTundraStreamPropertyFormatDescription;
-  status = self->ctx->mio->TundraObjectSetPropertyData (format->stream, &spec,
-      NULL, NULL, sizeof (format->desc), &format->desc);
-  if (status != kTundraSuccess)
-    goto failed_to_set_format;
-
-  spec.name = kTundraStreamPropertyFrameRate;
-  status = self->ctx->mio->TundraObjectSetPropertyData (format->stream, &spec,
-      NULL, NULL, sizeof (find_ctx.closest_match), &find_ctx.closest_match);
-  if (status != kTundraSuccess)
-    goto failed_to_set_framerate;
-
-  self->selected_format = format->desc;
-  self->selected_fps_n = ctx->fps_n;
-  self->selected_fps_d = ctx->fps_d;
-
-  ctx->success = TRUE;
-  return;
-
-  /* ERRORS */
-no_matching_framerate_found:
-  {
-    GST_ERROR ("no matching framerate found");
-    return;
-  }
-failed_to_set_format:
-  {
-    GST_ERROR ("failed to set format: 0x%08x", status);
-    return;
-  }
-failed_to_set_framerate:
-  {
-    GST_ERROR ("failed to set framerate: 0x%08x", status);
-    return;
-  }
-}
-
-static void
-gst_mio_video_device_find_closest_framerate (GstMIOVideoDevice * self,
-    GstMIOVideoFormat * format, TundraFramerate * rate, gpointer user_data)
-{
-  GstMIOFindRateCtx *ctx = user_data;
-
-  if (fabs (rate->value - ctx->needle) <= 0.1) {
-    ctx->closest_match = rate->value;
-    ctx->success = TRUE;
-  }
-}
-
-CMFormatDescriptionRef
-gst_mio_video_device_get_selected_format (GstMIOVideoDevice * self)
-{
-  return self->selected_format;
-}
-
-GstClockTime
-gst_mio_video_device_get_duration (GstMIOVideoDevice * self)
-{
-  return gst_util_uint64_scale_int (GST_SECOND,
-      self->selected_fps_d, self->selected_fps_n);
-}
-
-static void
-gst_mio_video_device_formats_foreach (GstMIOVideoDevice * self,
-    GstMIOVideoDeviceEachFormatFunc func, gpointer user_data)
-{
-  GstCMApi *cm = self->ctx->cm;
-  GstMIOApi *mio = self->ctx->mio;
-  TundraTargetSpec spec = { 0, };
-  GArray *streams;
-  guint stream_idx;
-
-  spec.name = kTundraDevicePropertyStreams;
-  spec.scope = kTundraScopeInput;
-  streams = gst_mio_object_get_array (self->handle, &spec,
-      sizeof (TundraObjectID), mio);
-
-  /* TODO: We only consider the first stream for now */
-  for (stream_idx = 0; stream_idx != MIN (streams->len, 1); stream_idx++) {
-    TundraObjectID stream;
-    CFArrayRef formats;
-    CFIndex num_formats, fmt_idx;
-
-    stream = g_array_index (streams, TundraObjectID, stream_idx);
-
-    spec.name = kTundraStreamPropertyFormatDescriptions;
-    spec.scope = kTundraScopeInput;
-
-    formats = gst_mio_object_get_pointer (stream, &spec, mio);
-    num_formats = CFArrayGetCount (formats);
-
-    for (fmt_idx = 0; fmt_idx != num_formats; fmt_idx++) {
-      GstMIOVideoFormat fmt;
-
-      fmt.stream = stream;
-      fmt.desc = (CMFormatDescriptionRef)
-          CFArrayGetValueAtIndex (formats, fmt_idx);
-      if (cm->CMFormatDescriptionGetMediaType (fmt.desc) != kFigMediaTypeVideo)
-        continue;
-      fmt.type = cm->CMFormatDescriptionGetMediaSubType (fmt.desc);
-      fmt.dim = cm->CMVideoFormatDescriptionGetDimensions (fmt.desc);
-
-      func (self, &fmt, user_data);
-    }
-  }
-
-  g_array_free (streams, TRUE);
-}
-
-static void
-gst_mio_video_device_format_framerates_foreach (GstMIOVideoDevice * self,
-    GstMIOVideoFormat * format, GstMIOVideoDeviceEachFramerateFunc func,
-    gpointer user_data)
-{
-  TundraTargetSpec spec = { 0, };
-  GArray *rates;
-  guint rate_idx;
-
-  spec.name = kTundraStreamPropertyFrameRates;
-  spec.scope = kTundraScopeInput;
-  rates = gst_mio_object_get_array_full (format->stream, &spec,
-      sizeof (format->desc), &format->desc, sizeof (TundraFramerate),
-      self->ctx->mio);
-
-  for (rate_idx = 0; rate_idx != rates->len; rate_idx++) {
-    TundraFramerate *rate;
-
-    rate = &g_array_index (rates, TundraFramerate, rate_idx);
-
-    func (self, format, rate, user_data);
-  }
-
-  g_array_free (rates, TRUE);
-}
-
-void
-gst_mio_video_device_print_debug_info (GstMIOVideoDevice * self)
-{
-  GstCMApi *cm = self->ctx->cm;
-  GstMIOApi *mio = self->ctx->mio;
-  TundraTargetSpec spec = { 0, };
-  gchar *str;
-  GArray *streams;
-  guint stream_idx;
-
-  g_print ("Device %p with handle %d\n", self, self->handle);
-
-  spec.scope = kTundraScopeGlobal;
-
-  spec.name = kTundraObjectPropertyClass;
-  str = gst_mio_object_get_fourcc (self->handle, &spec, mio);
-  g_print ("  Class: '%s'\n", str);
-  g_free (str);
-
-  spec.name = kTundraObjectPropertyCreator;
-  str = gst_mio_object_get_string (self->handle, &spec, mio);
-  g_print ("  Creator: \"%s\"\n", str);
-  g_free (str);
-
-  spec.name = kTundraDevicePropertyModelUID;
-  str = gst_mio_object_get_string (self->handle, &spec, mio);
-  g_print ("  Model UID: \"%s\"\n", str);
-  g_free (str);
-
-  spec.name = kTundraDevicePropertyTransportType;
-  str = gst_mio_object_get_fourcc (self->handle, &spec, mio);
-  g_print ("  Transport Type: '%s'\n", str);
-  g_free (str);
-
-  g_print ("  Streams:\n");
-  spec.name = kTundraDevicePropertyStreams;
-  spec.scope = kTundraScopeInput;
-  streams = gst_mio_object_get_array (self->handle, &spec,
-      sizeof (TundraObjectID), mio);
-  for (stream_idx = 0; stream_idx != streams->len; stream_idx++) {
-    TundraObjectID stream;
-    CFArrayRef formats;
-    CFIndex num_formats, fmt_idx;
-
-    stream = g_array_index (streams, TundraObjectID, stream_idx);
-
-    g_print ("    stream[%u] = %d\n", stream_idx, stream);
-
-    spec.scope = kTundraScopeInput;
-    spec.name = kTundraStreamPropertyFormatDescriptions;
-
-    formats = gst_mio_object_get_pointer (stream, &spec, mio);
-    num_formats = CFArrayGetCount (formats);
-
-    g_print ("      <%u formats>\n", (guint) num_formats);
-
-    for (fmt_idx = 0; fmt_idx != num_formats; fmt_idx++) {
-      CMFormatDescriptionRef fmt;
-      gchar *media_type;
-      gchar *media_sub_type;
-      CMVideoDimensions dim;
-      GArray *rates;
-      guint rate_idx;
-
-      fmt = CFArrayGetValueAtIndex (formats, fmt_idx);
-      media_type = gst_mio_fourcc_to_string
-          (cm->CMFormatDescriptionGetMediaType (fmt));
-      media_sub_type = gst_mio_fourcc_to_string
-          (cm->CMFormatDescriptionGetMediaSubType (fmt));
-      dim = cm->CMVideoFormatDescriptionGetDimensions (fmt);
-
-      g_print ("      format[%u]: MediaType='%s' MediaSubType='%s' %ux%u\n",
-          (guint) fmt_idx, media_type, media_sub_type,
-          (guint) dim.width, (guint) dim.height);
-
-      spec.name = kTundraStreamPropertyFrameRates;
-      rates = gst_mio_object_get_array_full (stream, &spec, sizeof (fmt), &fmt,
-          sizeof (TundraFramerate), mio);
-      for (rate_idx = 0; rate_idx != rates->len; rate_idx++) {
-        TundraFramerate *rate;
-
-        rate = &g_array_index (rates, TundraFramerate, rate_idx);
-        g_print ("        %f\n", rate->value);
-      }
-      g_array_free (rates, TRUE);
-
-      g_free (media_sub_type);
-      g_free (media_type);
-    }
-  }
-
-  g_array_free (streams, TRUE);
-}
-
-static void
-gst_mio_video_device_class_init (GstMIOVideoDeviceClass * klass)
-{
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
-  gobject_class->dispose = gst_mio_video_device_dispose;
-  gobject_class->finalize = gst_mio_video_device_finalize;
-  gobject_class->get_property = gst_mio_video_device_get_property;
-  gobject_class->set_property = gst_mio_video_device_set_property;
-
-  g_object_class_install_property (gobject_class, PROP_CONTEXT,
-      g_param_spec_pointer ("context", "CoreMedia Context",
-          "CoreMedia context to use",
-          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_class, PROP_HANDLE,
-      g_param_spec_int ("handle", "Handle",
-          "MIO handle of this video capture device",
-          G_MININT, G_MAXINT, -1,
-          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_class, PROP_UID,
-      g_param_spec_string ("uid", "Unique ID",
-          "Unique ID of this video capture device", NULL,
-          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_class, PROP_NAME,
-      g_param_spec_string ("name", "Device Name",
-          "Name of this video capture device", NULL,
-          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_class, PROP_TRANSPORT,
-      g_param_spec_uint ("transport", "Transport",
-          "Transport type of this video capture device",
-          0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-}
-
-GList *
-gst_mio_video_device_list_create (GstCoreMediaCtx * ctx)
-{
-  GList *devices = NULL;
-  TundraTargetSpec pspec = { 0, };
-  GArray *handles;
-  guint handle_idx;
-
-  pspec.name = kTundraSystemPropertyDevices;
-  pspec.scope = kTundraScopeGlobal;
-  handles = gst_mio_object_get_array (TUNDRA_SYSTEM_OBJECT_ID, &pspec,
-      sizeof (TundraObjectID), ctx->mio);
-  if (handles == NULL)
-    goto beach;
-
-  for (handle_idx = 0; handle_idx != handles->len; handle_idx++) {
-    TundraObjectID handle;
-    GstMIOVideoDevice *device;
-
-    handle = g_array_index (handles, TundraObjectID, handle_idx);
-    device = g_object_new (GST_TYPE_MIO_VIDEO_DEVICE,
-        "context", ctx, "handle", handle, NULL);
-
-    /* TODO: Skip screen input devices for now */
-    if (gst_mio_video_device_get_transport_type (device) !=
-        kTundraDeviceTransportScreen) {
-      devices = g_list_prepend (devices, device);
-    } else {
-      g_object_unref (device);
-    }
-  }
-
-  devices = g_list_sort (devices, (GCompareFunc) gst_mio_video_device_compare);
-
-  g_array_free (handles, TRUE);
-
-beach:
-  return devices;
-}
-
-void
-gst_mio_video_device_list_destroy (GList * devices)
-{
-  g_list_foreach (devices, (GFunc) g_object_unref, NULL);
-  g_list_free (devices);
-}
-
-static gint
-gst_mio_video_device_compare (GstMIOVideoDevice * a, GstMIOVideoDevice * b)
-{
-  gint score_a, score_b;
-
-  score_a = gst_mio_video_device_calculate_score (a);
-  score_b = gst_mio_video_device_calculate_score (b);
-
-  if (score_a > score_b)
-    return -1;
-  else if (score_a < score_b)
-    return 1;
-
-  return g_ascii_strcasecmp (gst_mio_video_device_get_name (a),
-      gst_mio_video_device_get_name (b));
-}
-
-static gint
-gst_mio_video_device_calculate_score (GstMIOVideoDevice * device)
-{
-  switch (gst_mio_video_device_get_transport_type (device)) {
-    case kTundraDeviceTransportScreen:
-      return 0;
-    case kTundraDeviceTransportBuiltin:
-      return 1;
-    case kTundraDeviceTransportUSB:
-      return 2;
-    default:
-      return 3;
-  }
-}
diff --git a/sys/applemedia/miovideodevice.h b/sys/applemedia/miovideodevice.h
deleted file mode 100644 (file)
index 87b86f3..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2009 Ole André Vadla Ravnås <oleavr@soundrop.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef __GST_MIO_VIDEO_DEVICE_H__
-#define __GST_MIO_VIDEO_DEVICE_H__
-
-#include <gst/gst.h>
-
-#include "coremediactx.h"
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_MIO_VIDEO_DEVICE \
-  (gst_mio_video_device_get_type ())
-#define GST_MIO_VIDEO_DEVICE(obj) \
-  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MIO_VIDEO_DEVICE, GstMIOVideoDevice))
-#define GST_MIO_VIDEO_DEVICE_CAST(obj) \
-  ((GstMIOVideoDevice *) (obj))
-#define GST_MIO_VIDEO_DEVICE_CLASS(klass) \
-  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MIO_VIDEO_DEVICE, GstMIOVideoDeviceClass))
-#define GST_IS_MIO_VIDEO_DEVICE(obj) \
-  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MIO_VIDEO_DEVICE))
-#define GST_IS_MIO_VIDEO_DEVICE_CLASS(klass) \
-  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MIO_VIDEO_DEVICE))
-
-typedef struct _GstMIOVideoDevice         GstMIOVideoDevice;
-typedef struct _GstMIOVideoDeviceClass    GstMIOVideoDeviceClass;
-
-struct _GstMIOVideoDevice
-{
-  GObject parent;
-
-  GstCoreMediaCtx *ctx;
-  TundraObjectID handle;
-
-  gchar *cached_uid;
-  gchar *cached_name;
-  TundraDeviceTransportType cached_transport;
-  GstCaps *cached_caps;
-  CMFormatDescriptionRef selected_format;
-  gint selected_fps_n, selected_fps_d;
-};
-
-struct _GstMIOVideoDeviceClass
-{
-  GObjectClass parent_class;
-};
-
-GType gst_mio_video_device_get_type (void);
-
-TundraObjectID gst_mio_video_device_get_handle (GstMIOVideoDevice * self);
-const gchar * gst_mio_video_device_get_uid (GstMIOVideoDevice * self);
-const gchar * gst_mio_video_device_get_name (GstMIOVideoDevice * self);
-TundraDeviceTransportType gst_mio_video_device_get_transport_type (
-    GstMIOVideoDevice * self);
-
-gboolean gst_mio_video_device_open (GstMIOVideoDevice * self);
-void gst_mio_video_device_close (GstMIOVideoDevice * self);
-
-GstCaps * gst_mio_video_device_get_available_caps (GstMIOVideoDevice * self);
-gboolean gst_mio_video_device_set_caps (GstMIOVideoDevice * self,
-    GstCaps * caps);
-CMFormatDescriptionRef gst_mio_video_device_get_selected_format (
-    GstMIOVideoDevice * self);
-GstClockTime gst_mio_video_device_get_duration (GstMIOVideoDevice * self);
-
-void gst_mio_video_device_print_debug_info (GstMIOVideoDevice * self);
-
-GList * gst_mio_video_device_list_create (GstCoreMediaCtx * ctx);
-void gst_mio_video_device_list_destroy (GList * devices);
-
-G_END_DECLS
-
-#endif /* __GST_MIO_VIDEO_DEVICE_H__ */
diff --git a/sys/applemedia/miovideosrc.c b/sys/applemedia/miovideosrc.c
deleted file mode 100644 (file)
index 041d7eb..0000000
+++ /dev/null
@@ -1,1201 +0,0 @@
-/*
- * Copyright (C) 2009 Ole André Vadla Ravnås <oleavr@soundrop.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-/* FIXME 1.x: suppress warnings for deprecated API such as GStaticRecMutex
- * with newer GLib versions (>= 2.31.0) */
-#define GLIB_DISABLE_DEPRECATION_WARNINGS
-
-#include "miovideosrc.h"
-
-#include "coremediabuffer.h"
-
-#include <gst/interfaces/propertyprobe.h>
-#include <gst/video/video.h>
-
-#include <CoreVideo/CVHostTime.h>
-
-#define DEFAULT_DEVICE_INDEX -1
-
-#define FRAME_QUEUE_SIZE      2
-
-#define FRAME_QUEUE_LOCK(instance) g_mutex_lock (instance->qlock)
-#define FRAME_QUEUE_UNLOCK(instance) g_mutex_unlock (instance->qlock)
-#define FRAME_QUEUE_WAIT(instance) \
-    g_cond_wait (instance->qcond, instance->qlock)
-#define FRAME_QUEUE_NOTIFY(instance) g_cond_signal (instance->qcond)
-
-#define GST_MIO_REQUIRED_APIS \
-    (GST_API_CORE_VIDEO | GST_API_CORE_MEDIA | GST_API_MIO)
-
-GST_DEBUG_CATEGORY (gst_mio_video_src_debug);
-#define GST_CAT_DEFAULT gst_mio_video_src_debug
-
-static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
-    GST_PAD_SRC,
-    GST_PAD_ALWAYS,
-    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("UYVY") ";"
-        GST_VIDEO_CAPS_YUV ("YUY2") ";"
-        "image/jpeg, "
-        "width = " GST_VIDEO_SIZE_RANGE ", "
-        "height = " GST_VIDEO_SIZE_RANGE ", "
-        "framerate = " GST_VIDEO_FPS_RANGE ";")
-    );
-
-enum
-{
-  PROP_0,
-  PROP_DEVICE_UID,
-  PROP_DEVICE_NAME,
-  PROP_DEVICE_INDEX
-};
-
-typedef gboolean (*GstMIOCallback) (GstMIOVideoSrc * self, gpointer data);
-#define GST_MIO_CALLBACK(cb) ((GstMIOCallback) (cb))
-
-static gboolean gst_mio_video_src_open_device (GstMIOVideoSrc * self);
-static void gst_mio_video_src_close_device (GstMIOVideoSrc * self);
-static gboolean gst_mio_video_src_build_capture_graph_for
-    (GstMIOVideoSrc * self, GstMIOVideoDevice * device);
-static TundraStatus gst_mio_video_src_configure_output_node
-    (GstMIOVideoSrc * self, TundraGraph * graph, guint node_id);
-
-static void gst_mio_video_src_start_dispatcher (GstMIOVideoSrc * self);
-static void gst_mio_video_src_stop_dispatcher (GstMIOVideoSrc * self);
-static gpointer gst_mio_video_src_dispatcher_thread (gpointer data);
-static gboolean gst_mio_video_src_perform (GstMIOVideoSrc * self,
-    GstMIOCallback cb, gpointer data);
-static gboolean gst_mio_video_src_perform_proxy (gpointer data);
-
-static void gst_mio_video_src_probe_interface_init (gpointer g_iface,
-    gpointer iface_data);
-
-static void gst_mio_video_src_init_interfaces (GType type);
-
-GST_BOILERPLATE_FULL (GstMIOVideoSrc, gst_mio_video_src, GstPushSrc,
-    GST_TYPE_PUSH_SRC, gst_mio_video_src_init_interfaces);
-
-static void
-gst_mio_video_src_init (GstMIOVideoSrc * self, GstMIOVideoSrcClass * gclass)
-{
-  GstBaseSrc *base_src = GST_BASE_SRC_CAST (self);
-  guint64 host_freq;
-
-  gst_base_src_set_live (base_src, TRUE);
-  gst_base_src_set_format (base_src, GST_FORMAT_TIME);
-
-  host_freq = gst_gdouble_to_guint64 (CVGetHostClockFrequency ());
-  if (host_freq <= GST_SECOND) {
-    self->cv_ratio_n = GST_SECOND / host_freq;
-    self->cv_ratio_d = 1;
-  } else {
-    self->cv_ratio_n = 1;
-    self->cv_ratio_d = host_freq / GST_SECOND;
-  }
-
-  self->queue = g_queue_new ();
-  self->qlock = g_mutex_new ();
-  self->qcond = g_cond_new ();
-}
-
-static void
-gst_mio_video_src_finalize (GObject * object)
-{
-  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (object);
-
-  g_cond_free (self->qcond);
-  g_mutex_free (self->qlock);
-  g_queue_free (self->queue);
-
-  G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-gst_mio_video_src_get_property (GObject * object, guint prop_id, GValue * value,
-    GParamSpec * pspec)
-{
-  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (object);
-
-  switch (prop_id) {
-    case PROP_DEVICE_UID:
-      g_value_set_string (value, self->device_uid);
-      break;
-    case PROP_DEVICE_NAME:
-      g_value_set_string (value, self->device_name);
-      break;
-    case PROP_DEVICE_INDEX:
-      g_value_set_int (value, self->device_index);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-}
-
-static void
-gst_mio_video_src_set_property (GObject * object, guint prop_id,
-    const GValue * value, GParamSpec * pspec)
-{
-  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (object);
-
-  switch (prop_id) {
-    case PROP_DEVICE_UID:
-      g_free (self->device_uid);
-      self->device_uid = g_value_dup_string (value);
-      break;
-    case PROP_DEVICE_NAME:
-      g_free (self->device_name);
-      self->device_name = g_value_dup_string (value);
-      break;
-    case PROP_DEVICE_INDEX:
-      self->device_index = g_value_get_int (value);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-  }
-}
-
-static GstStateChangeReturn
-gst_mio_video_src_change_state (GstElement * element, GstStateChange transition)
-{
-  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (element);
-  GstStateChangeReturn ret;
-
-  switch (transition) {
-    case GST_STATE_CHANGE_NULL_TO_READY:
-      gst_mio_video_src_start_dispatcher (self);
-      if (!gst_mio_video_src_perform (self,
-              GST_MIO_CALLBACK (gst_mio_video_src_open_device), NULL)) {
-        goto open_failed;
-      }
-      break;
-    default:
-      break;
-  }
-
-  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-
-  switch (transition) {
-    case GST_STATE_CHANGE_READY_TO_NULL:
-      gst_mio_video_src_perform (self,
-          GST_MIO_CALLBACK (gst_mio_video_src_close_device), NULL);
-
-      gst_mio_video_src_stop_dispatcher (self);
-      break;
-    default:
-      break;
-  }
-
-  return ret;
-
-  /* ERRORS */
-open_failed:
-  {
-    gst_mio_video_src_stop_dispatcher (self);
-    return GST_STATE_CHANGE_FAILURE;
-  }
-}
-
-static GstCaps *
-gst_mio_video_src_get_caps (GstBaseSrc * basesrc)
-{
-  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (basesrc);
-  GstCaps *result;
-
-  if (self->device != NULL) {
-    result =
-        gst_caps_ref (gst_mio_video_device_get_available_caps (self->device));
-  } else {
-    result = NULL;              /* BaseSrc will return template caps */
-  }
-
-  return result;
-}
-
-static gboolean
-gst_mio_video_src_do_set_caps (GstMIOVideoSrc * self, GstCaps * caps)
-{
-  TundraStatus status;
-
-  if (self->device == NULL)
-    goto no_device;
-
-  if (!gst_mio_video_device_set_caps (self->device, caps))
-    goto invalid_format;
-
-  if (!gst_mio_video_src_build_capture_graph_for (self, self->device))
-    goto graph_build_error;
-
-  status = self->ctx->mio->TundraGraphInitialize (self->graph);
-  if (status != kTundraSuccess)
-    goto graph_init_error;
-
-  status = self->ctx->mio->TundraGraphStart (self->graph);
-  if (status != kTundraSuccess)
-    goto graph_start_error;
-
-  return TRUE;
-
-  /* ERRORS */
-no_device:
-  {
-    GST_ELEMENT_ERROR (self, RESOURCE, FAILED, ("no device"), (NULL));
-    return FALSE;
-  }
-invalid_format:
-  {
-    GST_ELEMENT_ERROR (self, RESOURCE, FAILED, ("invalid format"), (NULL));
-    return FALSE;
-  }
-graph_build_error:
-  {
-    GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
-        ("failed to build capture graph"), (NULL));
-    return FALSE;
-  }
-graph_init_error:
-  {
-    GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
-        ("failed to initialize capture graph: %08x", status), (NULL));
-    return FALSE;
-  }
-graph_start_error:
-  {
-    GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
-        ("failed to start capture graph: %08x", status), (NULL));
-    return FALSE;
-  }
-}
-
-static gboolean
-gst_mio_video_src_set_caps (GstBaseSrc * basesrc, GstCaps * caps)
-{
-  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (basesrc);
-
-  {
-    gchar *str;
-
-    str = gst_caps_to_string (caps);
-    GST_DEBUG_OBJECT (self, "caps: %s", str);
-    g_free (str);
-  }
-
-  return gst_mio_video_src_perform (self,
-      GST_MIO_CALLBACK (gst_mio_video_src_do_set_caps), caps);
-}
-
-static gboolean
-gst_mio_video_src_start (GstBaseSrc * basesrc)
-{
-  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (basesrc);
-
-  self->running = TRUE;
-  self->prev_offset = GST_BUFFER_OFFSET_NONE;
-  self->prev_format = NULL;
-
-  return TRUE;
-}
-
-static gboolean
-gst_mio_video_src_do_stop (GstMIOVideoSrc * self)
-{
-  TundraStatus status;
-
-  if (self->graph == NULL)
-    goto nothing_to_stop;
-
-  status = self->ctx->mio->TundraGraphStop (self->graph);
-  if (status != kTundraSuccess)
-    goto graph_failed_to_stop;
-
-  while (!g_queue_is_empty (self->queue))
-    gst_buffer_unref (g_queue_pop_head (self->queue));
-
-  self->ctx->cm->FigFormatDescriptionRelease (self->prev_format);
-  self->prev_format = NULL;
-
-  return TRUE;
-
-nothing_to_stop:
-  return TRUE;
-
-graph_failed_to_stop:
-  GST_WARNING_OBJECT (self, "failed to stop capture graph: %d", status);
-  return FALSE;
-}
-
-static gboolean
-gst_mio_video_src_stop (GstBaseSrc * basesrc)
-{
-  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (basesrc);
-
-  return gst_mio_video_src_perform (self,
-      GST_MIO_CALLBACK (gst_mio_video_src_do_stop), NULL);
-}
-
-static gboolean
-gst_mio_video_src_query (GstBaseSrc * basesrc, GstQuery * query)
-{
-  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (basesrc);
-  gboolean result = FALSE;
-
-  switch (GST_QUERY_TYPE (query)) {
-    case GST_QUERY_LATENCY:{
-      GstClockTime min_latency, max_latency;
-
-      if (self->device == NULL)
-        goto beach;
-
-      if (gst_mio_video_device_get_selected_format (self->device) == NULL)
-        goto beach;
-
-      min_latency = max_latency =
-          gst_mio_video_device_get_duration (self->device);
-
-      GST_DEBUG_OBJECT (self, "reporting latency of min %" GST_TIME_FORMAT
-          " max %" GST_TIME_FORMAT,
-          GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
-
-      gst_query_set_latency (query, TRUE, min_latency, max_latency);
-      result = TRUE;
-      break;
-    }
-    default:
-      result = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
-      break;
-  }
-
-beach:
-  return result;
-}
-
-static gboolean
-gst_mio_video_src_unlock (GstBaseSrc * basesrc)
-{
-  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (basesrc);
-
-  FRAME_QUEUE_LOCK (self);
-  self->running = FALSE;
-  FRAME_QUEUE_NOTIFY (self);
-  FRAME_QUEUE_UNLOCK (self);
-
-  return TRUE;
-}
-
-static gboolean
-gst_mio_video_src_unlock_stop (GstBaseSrc * basesrc)
-{
-  return TRUE;
-}
-
-static GstFlowReturn
-gst_mio_video_src_create (GstPushSrc * pushsrc, GstBuffer ** buf)
-{
-  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (pushsrc);
-  GstCMApi *cm = self->ctx->cm;
-  CMFormatDescriptionRef format;
-
-  FRAME_QUEUE_LOCK (self);
-  while (self->running && g_queue_is_empty (self->queue))
-    FRAME_QUEUE_WAIT (self);
-  *buf = g_queue_pop_tail (self->queue);
-  FRAME_QUEUE_UNLOCK (self);
-
-  if (G_UNLIKELY (!self->running))
-    goto shutting_down;
-
-  format = cm->CMSampleBufferGetFormatDescription
-      (GST_CORE_MEDIA_BUFFER (*buf)->sample_buf);
-  if (self->prev_format != NULL &&
-      !cm->CMFormatDescriptionEqual (format, self->prev_format)) {
-    goto unexpected_format;
-  }
-  cm->FigFormatDescriptionRelease (self->prev_format);
-  self->prev_format = cm->FigFormatDescriptionRetain (format);
-
-  if (self->prev_offset == GST_BUFFER_OFFSET_NONE ||
-      GST_BUFFER_OFFSET (*buf) - self->prev_offset != 1) {
-    GST_BUFFER_FLAG_SET (*buf, GST_BUFFER_FLAG_DISCONT);
-  }
-  self->prev_offset = GST_BUFFER_OFFSET (*buf);
-
-  return GST_FLOW_OK;
-
-  /* ERRORS */
-shutting_down:
-  {
-    if (*buf != NULL) {
-      gst_buffer_unref (*buf);
-      *buf = NULL;
-    }
-
-    return GST_FLOW_FLUSHING;
-  }
-unexpected_format:
-  {
-    GST_ELEMENT_ERROR (self, RESOURCE, READ,
-        ("capture format changed unexpectedly"),
-        ("another application likely reconfigured the device"));
-
-    if (*buf != NULL) {
-      gst_buffer_unref (*buf);
-      *buf = NULL;
-    }
-
-    return GST_FLOW_ERROR;
-  }
-}
-
-static gboolean
-gst_mio_video_src_open_device (GstMIOVideoSrc * self)
-{
-  GError *error = NULL;
-  GList *devices = NULL, *walk;
-  guint device_idx;
-
-  self->ctx = gst_core_media_ctx_new (GST_API_CORE_VIDEO | GST_API_CORE_MEDIA
-      | GST_API_MIO, &error);
-  if (error != NULL)
-    goto api_error;
-
-  devices = gst_mio_video_device_list_create (self->ctx);
-  if (devices == NULL)
-    goto no_devices;
-
-  for (walk = devices, device_idx = 0; walk != NULL; walk = walk->next) {
-    GstMIOVideoDevice *device = walk->data;
-    gboolean match;
-
-    if (self->device_uid != NULL) {
-      match = g_ascii_strcasecmp (gst_mio_video_device_get_uid (device),
-          self->device_uid) == 0;
-    } else if (self->device_name != NULL) {
-      match = g_ascii_strcasecmp (gst_mio_video_device_get_name (device),
-          self->device_name) == 0;
-    } else if (self->device_index >= 0) {
-      match = device_idx == self->device_index;
-    } else {
-      match = TRUE;             /* pick the first entry */
-    }
-
-    if (self->device != NULL)
-      match = FALSE;
-
-    GST_DEBUG_OBJECT (self, "%c device[%u] = handle: %d name: '%s' uid: '%s'",
-        (match) ? '*' : '-', device_idx,
-        gst_mio_video_device_get_handle (device),
-        gst_mio_video_device_get_name (device),
-        gst_mio_video_device_get_uid (device));
-
-    /*gst_mio_video_device_print_debug_info (device); */
-
-    if (match)
-      self->device = g_object_ref (device);
-
-    device_idx++;
-  }
-
-  if (self->device == NULL)
-    goto no_such_device;
-
-  if (!gst_mio_video_device_open (self->device))
-    goto device_busy_or_gone;
-
-  gst_mio_video_device_list_destroy (devices);
-  return TRUE;
-
-  /* ERRORS */
-api_error:
-  {
-    GST_ELEMENT_ERROR (self, RESOURCE, FAILED, ("API error"),
-        ("%s", error->message));
-    g_clear_error (&error);
-    goto any_error;
-  }
-no_devices:
-  {
-    GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
-        ("no video capture devices found"), (NULL));
-    goto any_error;
-  }
-no_such_device:
-  {
-    GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
-        ("specified video capture device not found"), (NULL));
-    goto any_error;
-  }
-device_busy_or_gone:
-  {
-    GST_ELEMENT_ERROR (self, RESOURCE, BUSY,
-        ("failed to start capture (device already in use or gone)"), (NULL));
-    goto any_error;
-  }
-any_error:
-  {
-    if (devices != NULL) {
-      gst_mio_video_device_list_destroy (devices);
-    }
-    if (self->ctx != NULL) {
-      g_object_unref (self->ctx);
-      self->ctx = NULL;
-    }
-    return FALSE;
-  }
-}
-
-static void
-gst_mio_video_src_close_device (GstMIOVideoSrc * self)
-{
-  self->ctx->mio->TundraGraphUninitialize (self->graph);
-  self->ctx->mio->TundraGraphRelease (self->graph);
-  self->graph = NULL;
-
-  gst_mio_video_device_close (self->device);
-  g_object_unref (self->device);
-  self->device = NULL;
-
-  g_object_unref (self->ctx);
-  self->ctx = NULL;
-}
-
-#define CHECK_TUNDRA_ERROR(fn)      \
-  if (status != kTundraSuccess) {   \
-    last_function_name = fn;        \
-    goto tundra_error;              \
-  }
-
-static gboolean
-gst_mio_video_src_build_capture_graph_for (GstMIOVideoSrc * self,
-    GstMIOVideoDevice * device)
-{
-  GstMIOApi *mio = self->ctx->mio;
-  const gchar *last_function_name;
-  TundraGraph *graph = NULL;
-  TundraTargetSpec spec = { 0, };
-  TundraUnitID input_node = -1;
-  gpointer input_info;
-  TundraObjectID device_handle;
-  TundraUnitID sync_node = -1;
-  guint8 is_master;
-  guint sync_direction;
-  TundraUnitID output_node = -1;
-  TundraStatus status;
-
-  const gint node_id_input = 1;
-  const gint node_id_sync = 22;
-  const gint node_id_output = 16;
-
-  /*
-   * Graph
-   */
-  status = mio->TundraGraphCreate (kCFAllocatorDefault, &graph);
-  CHECK_TUNDRA_ERROR ("TundraGraphCreate");
-
-  /*
-   * Node: input
-   */
-  spec.name = kTundraUnitInput;
-  spec.scope = kTundraScopeDAL;
-  spec.vendor = kTundraVendorApple;
-  status = mio->TundraGraphCreateNode (graph, node_id_input, 0, 0, &spec, 0,
-      &input_node);
-  CHECK_TUNDRA_ERROR ("TundraGraphCreateNode(input)");
-
-  /* store node info for setting clock provider */
-  input_info = NULL;
-  status = mio->TundraGraphGetNodeInfo (graph, input_node, 0, 0, 0, 0,
-      &input_info);
-  CHECK_TUNDRA_ERROR ("TundraGraphGetNodeInfo(input)");
-
-  /* set device handle */
-  device_handle = gst_mio_video_device_get_handle (device);
-  status = mio->TundraGraphSetProperty (graph, node_id_input, 0,
-      kTundraInputPropertyDeviceID, 0, 0, &device_handle,
-      sizeof (device_handle));
-  CHECK_TUNDRA_ERROR ("TundraGraphSetProperty(input, DeviceID)");
-
-  /*
-   * Node: sync
-   */
-  spec.name = kTundraUnitSync;
-  spec.scope = kTundraScopeVSyn;
-  status = mio->TundraGraphCreateNode (graph, node_id_sync, 0, 0, &spec, 0,
-      &sync_node);
-  CHECK_TUNDRA_ERROR ("TundraGraphCreateNode(sync)");
-  status = mio->TundraGraphSetProperty (graph, node_id_sync, 0,
-      kTundraSyncPropertyClockProvider, 0, 0, &input_info, sizeof (input_info));
-  CHECK_TUNDRA_ERROR ("TundraGraphSetProperty(sync, ClockProvider)");
-  is_master = TRUE;
-  status = mio->TundraGraphSetProperty (graph, node_id_sync, 0,
-      kTundraSyncPropertyMasterSynchronizer, 0, 0,
-      &is_master, sizeof (is_master));
-  CHECK_TUNDRA_ERROR ("TundraGraphSetProperty(sync, MasterSynchronizer)");
-  sync_direction = 0;
-  status = mio->TundraGraphSetProperty (graph, node_id_sync, 0,
-      kTundraSyncPropertySynchronizationDirection, 0, 0,
-      &sync_direction, sizeof (sync_direction));
-  CHECK_TUNDRA_ERROR ("TundraGraphSetProperty(sync, SynchronizationDirection)");
-
-  /*
-   * Node: output
-   */
-  spec.name = kTundraUnitOutput;
-  spec.scope = kTundraScope2PRC;
-  status = mio->TundraGraphCreateNode (graph, node_id_output, 0, 0, &spec, 0,
-      &output_node);
-  CHECK_TUNDRA_ERROR ("TundraGraphCreateNode(output)");
-  status = gst_mio_video_src_configure_output_node (self, graph,
-      node_id_output);
-  CHECK_TUNDRA_ERROR ("TundraGraphSetProperty(output, Delegate)");
-
-  /*
-   * Connect the nodes
-   */
-  status = mio->TundraGraphConnectNodeInput (graph, input_node, 0,
-      sync_node, 0);
-  CHECK_TUNDRA_ERROR ("TundraGraphConnectNodeInput(input, sync)");
-  status = mio->TundraGraphConnectNodeInput (graph, sync_node, 0,
-      output_node, 0);
-  CHECK_TUNDRA_ERROR ("TundraGraphConnectNodeInput(sync, output)");
-
-  self->graph = graph;
-
-  return TRUE;
-
-tundra_error:
-  {
-    GST_ELEMENT_ERROR (self, RESOURCE, FAILED,
-        ("%s failed (status=%d)", last_function_name, (gint) status), (NULL));
-    goto any_error;
-  }
-any_error:
-  {
-    mio->TundraGraphRelease (graph);
-    return FALSE;
-  }
-}
-
-static GstClockTime
-gst_mio_video_src_get_timestamp (GstMIOVideoSrc * self, CMSampleBufferRef sbuf)
-{
-  GstClock *clock;
-  GstClockTime base_time;
-  GstClockTime timestamp;
-
-  GST_OBJECT_LOCK (self);
-  if ((clock = GST_ELEMENT_CLOCK (self)) != NULL) {
-    gst_object_ref (clock);
-  }
-  base_time = GST_ELEMENT_CAST (self)->base_time;
-  GST_OBJECT_UNLOCK (self);
-
-  if (G_UNLIKELY (clock == NULL))
-    goto no_clock;
-
-  timestamp = GST_CLOCK_TIME_NONE;
-
-  /*
-   * If the current clock is GstSystemClock, we know that it's using the
-   * CoreAudio/CoreVideo clock. As such we may use the timestamp attached
-   * to the CMSampleBuffer.
-   */
-  if (G_TYPE_FROM_INSTANCE (clock) == GST_TYPE_SYSTEM_CLOCK) {
-    CFNumberRef number;
-    UInt64 ht;
-
-    number = self->ctx->cm->CMGetAttachment (sbuf,
-        *self->ctx->mio->kTundraSampleBufferAttachmentKey_HostTime, NULL);
-    if (number != NULL && CFNumberGetValue (number, kCFNumberSInt64Type, &ht)) {
-      timestamp = gst_util_uint64_scale_int (ht,
-          self->cv_ratio_n, self->cv_ratio_d);
-    }
-  }
-
-  if (!GST_CLOCK_TIME_IS_VALID (timestamp)) {
-    timestamp = gst_clock_get_time (clock);
-  }
-
-  if (timestamp > base_time)
-    timestamp -= base_time;
-  else
-    timestamp = 0;
-
-  gst_object_unref (clock);
-
-  return timestamp;
-
-no_clock:
-  return GST_CLOCK_TIME_NONE;
-}
-
-static TundraStatus
-gst_mio_video_src_output_render (gpointer instance, gpointer unk1,
-    gpointer unk2, gpointer unk3, CMSampleBufferRef sample_buf)
-{
-  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC_CAST (instance);
-  GstBuffer *buf;
-  CFNumberRef number;
-  UInt32 seq;
-
-  buf = gst_core_media_buffer_new (self->ctx, sample_buf);
-  if (G_UNLIKELY (buf == NULL))
-    goto buffer_creation_failed;
-
-  number = self->ctx->cm->CMGetAttachment (sample_buf,
-      *self->ctx->mio->kTundraSampleBufferAttachmentKey_SequenceNumber, NULL);
-  if (number != NULL && CFNumberGetValue (number, kCFNumberSInt32Type, &seq)) {
-    GST_BUFFER_OFFSET (buf) = seq;
-    GST_BUFFER_OFFSET_END (buf) = seq + 1;
-  }
-
-  GST_BUFFER_TIMESTAMP (buf) = gst_mio_video_src_get_timestamp (self,
-      sample_buf);
-
-  if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
-    GST_BUFFER_DURATION (buf) =
-        gst_mio_video_device_get_duration (self->device);
-  }
-
-  FRAME_QUEUE_LOCK (self);
-  if (g_queue_get_length (self->queue) == FRAME_QUEUE_SIZE)
-    gst_buffer_unref (g_queue_pop_tail (self->queue));
-  g_queue_push_head (self->queue, buf);
-  FRAME_QUEUE_NOTIFY (self);
-  FRAME_QUEUE_UNLOCK (self);
-
-  return kTundraSuccess;
-
-buffer_creation_failed:
-  GST_WARNING_OBJECT (instance, "failed to create buffer");
-  return kTundraSuccess;
-}
-
-static TundraStatus
-gst_mio_video_src_output_initialize (gpointer instance)
-{
-  GST_DEBUG_OBJECT (instance, "%s", G_STRFUNC);
-
-  return kTundraSuccess;
-}
-
-static TundraStatus
-gst_mio_video_src_output_uninitialize (gpointer instance)
-{
-  GST_DEBUG_OBJECT (instance, "%s", G_STRFUNC);
-
-  return kTundraSuccess;
-}
-
-static TundraStatus
-gst_mio_video_src_output_start (gpointer instance)
-{
-  GST_DEBUG_OBJECT (instance, "%s", G_STRFUNC);
-
-  return kTundraSuccess;
-}
-
-static TundraStatus
-gst_mio_video_src_output_stop (gpointer instance)
-{
-  return kTundraSuccess;
-}
-
-static TundraStatus
-gst_mio_video_src_output_reset (gpointer instance)
-{
-  GST_DEBUG_OBJECT (instance, "%s", G_STRFUNC);
-
-  return kTundraSuccess;
-}
-
-static TundraStatus
-gst_mio_video_src_output_deallocate (gpointer instance)
-{
-  GST_DEBUG_OBJECT (instance, "%s", G_STRFUNC);
-
-  return kTundraSuccess;
-}
-
-static gboolean
-gst_mio_video_src_output_can_render_now (gpointer instance, guint * unk)
-{
-  if (unk != NULL)
-    *unk = 0;
-
-  return TRUE;
-}
-
-static CFArrayRef
-gst_mio_video_src_output_available_formats (gpointer instance,
-    gboolean ensure_only)
-{
-  GstMIOVideoSrc *self = GST_MIO_VIDEO_SRC (instance);
-  CMFormatDescriptionRef format_desc;
-
-  GST_DEBUG_OBJECT (self, "%s: ensure_only=%d", G_STRFUNC, ensure_only);
-
-  if (ensure_only)
-    return NULL;
-
-  g_assert (self->device != NULL);
-  format_desc = gst_mio_video_device_get_selected_format (self->device);
-  g_assert (format_desc != NULL);
-
-  return CFArrayCreate (kCFAllocatorDefault, (const void **) &format_desc, 1,
-      &kCFTypeArrayCallBacks);
-}
-
-static TundraStatus
-gst_mio_video_src_output_copy_clock (gpointer instance)
-{
-  GST_DEBUG_OBJECT (instance, "%s", G_STRFUNC);
-
-  return kTundraSuccess;
-}
-
-static TundraStatus
-gst_mio_video_src_output_get_property_info (gpointer instance, guint prop_id)
-{
-  GST_DEBUG_OBJECT (instance, "%s: prop_id=%u", G_STRFUNC, prop_id);
-
-  if (prop_id == kTundraInputUnitProperty_SourcePath)
-    return kTundraSuccess;
-
-  return kTundraNotSupported;
-}
-
-static TundraStatus
-gst_mio_video_src_output_get_property (gpointer instance, guint prop_id)
-{
-  GST_DEBUG_OBJECT (instance, "%s", G_STRFUNC);
-
-  if (prop_id == kTundraInputUnitProperty_SourcePath)
-    return kTundraSuccess;
-
-  return kTundraNotSupported;
-}
-
-static TundraStatus
-gst_mio_video_src_output_set_property (gpointer instance, guint prop_id)
-{
-  GST_DEBUG_OBJECT (instance, "%s: prop_id=%u", G_STRFUNC, prop_id);
-
-  if (prop_id == kTundraInputUnitProperty_SourcePath)
-    return kTundraSuccess;
-
-  return kTundraNotSupported;
-}
-
-static TundraStatus
-gst_mio_video_src_configure_output_node (GstMIOVideoSrc * self,
-    TundraGraph * graph, guint node_id)
-{
-  TundraStatus status;
-  TundraOutputDelegate d = { 0, };
-
-  d.unk1 = 2;
-  d.instance = self;
-  d.Render = gst_mio_video_src_output_render;
-  d.Initialize = gst_mio_video_src_output_initialize;
-  d.Uninitialize = gst_mio_video_src_output_uninitialize;
-  d.Start = gst_mio_video_src_output_start;
-  d.Stop = gst_mio_video_src_output_stop;
-  d.Reset = gst_mio_video_src_output_reset;
-  d.Deallocate = gst_mio_video_src_output_deallocate;
-  d.CanRenderNow = gst_mio_video_src_output_can_render_now;
-  d.AvailableFormats = gst_mio_video_src_output_available_formats;
-  d.CopyClock = gst_mio_video_src_output_copy_clock;
-  d.GetPropertyInfo = gst_mio_video_src_output_get_property_info;
-  d.GetProperty = gst_mio_video_src_output_get_property;
-  d.SetProperty = gst_mio_video_src_output_set_property;
-
-  status = self->ctx->mio->TundraGraphSetProperty (graph, node_id, 0,
-      kTundraOutputPropertyDelegate, 0, 0, &d, sizeof (d));
-
-  return status;
-}
-
-static void
-gst_mio_video_src_start_dispatcher (GstMIOVideoSrc * self)
-{
-  g_assert (self->dispatcher_ctx == NULL && self->dispatcher_loop == NULL);
-  g_assert (self->dispatcher_thread == NULL);
-
-  self->dispatcher_ctx = g_main_context_new ();
-  self->dispatcher_loop = g_main_loop_new (self->dispatcher_ctx, TRUE);
-  self->dispatcher_thread =
-      g_thread_create (gst_mio_video_src_dispatcher_thread, self, TRUE, NULL);
-}
-
-static void
-gst_mio_video_src_stop_dispatcher (GstMIOVideoSrc * self)
-{
-  g_assert (self->dispatcher_ctx != NULL && self->dispatcher_loop != NULL);
-  g_assert (self->dispatcher_thread != NULL);
-
-  g_main_loop_quit (self->dispatcher_loop);
-  g_thread_join (self->dispatcher_thread);
-  self->dispatcher_thread = NULL;
-
-  g_main_loop_unref (self->dispatcher_loop);
-  self->dispatcher_loop = NULL;
-
-  g_main_context_unref (self->dispatcher_ctx);
-  self->dispatcher_ctx = NULL;
-}
-
-static gpointer
-gst_mio_video_src_dispatcher_thread (gpointer data)
-{
-  GstMIOVideoSrc *self = data;
-
-  g_main_loop_run (self->dispatcher_loop);
-
-  return NULL;
-}
-
-typedef struct
-{
-  GstMIOVideoSrc *self;
-  GstMIOCallback callback;
-  gpointer data;
-  gboolean result;
-
-  GMutex *mutex;
-  GCond *cond;
-  gboolean finished;
-} GstMIOPerformCtx;
-
-static gboolean
-gst_mio_video_src_perform (GstMIOVideoSrc * self, GstMIOCallback cb,
-    gpointer data)
-{
-  GstMIOPerformCtx ctx;
-  GSource *source;
-
-  ctx.self = self;
-  ctx.callback = cb;
-  ctx.data = data;
-  ctx.result = FALSE;
-
-  ctx.mutex = g_mutex_new ();
-  ctx.cond = g_cond_new ();
-  ctx.finished = FALSE;
-
-  source = g_idle_source_new ();
-  g_source_set_callback (source, gst_mio_video_src_perform_proxy, &ctx, NULL);
-  g_source_attach (source, self->dispatcher_ctx);
-
-  g_mutex_lock (ctx.mutex);
-  while (!ctx.finished)
-    g_cond_wait (ctx.cond, ctx.mutex);
-  g_mutex_unlock (ctx.mutex);
-
-  g_source_destroy (source);
-  g_source_unref (source);
-
-  g_cond_free (ctx.cond);
-  g_mutex_free (ctx.mutex);
-
-  return ctx.result;
-}
-
-static gboolean
-gst_mio_video_src_perform_proxy (gpointer data)
-{
-  GstMIOPerformCtx *ctx = data;
-
-  ctx->result = ctx->callback (ctx->self, ctx->data);
-
-  g_mutex_lock (ctx->mutex);
-  ctx->finished = TRUE;
-  g_cond_signal (ctx->cond);
-  g_mutex_unlock (ctx->mutex);
-
-  return FALSE;
-}
-
-static const GList *
-gst_mio_video_src_probe_get_properties (GstPropertyProbe * probe)
-{
-  static gsize init_value = 0;
-
-  if (g_once_init_enter (&init_value)) {
-    GObjectClass *klass;
-    GList *props = NULL;
-
-    klass = G_OBJECT_GET_CLASS (probe);
-
-    props = g_list_append (props,
-        g_object_class_find_property (klass, "device-uid"));
-    props = g_list_append (props,
-        g_object_class_find_property (klass, "device-name"));
-    props = g_list_append (props,
-        g_object_class_find_property (klass, "device-index"));
-
-    g_once_init_leave (&init_value, GPOINTER_TO_SIZE (props));
-  }
-
-  return GSIZE_TO_POINTER (init_value);
-}
-
-static GValueArray *
-gst_mio_video_src_probe_get_values (GstPropertyProbe * probe, guint prop_id,
-    const GParamSpec * pspec)
-{
-  GValueArray *values;
-  GstCoreMediaCtx *ctx = NULL;
-  GError *error = NULL;
-  GList *devices = NULL, *walk;
-  guint device_idx;
-
-  values = g_value_array_new (3);
-
-  ctx = gst_core_media_ctx_new (GST_MIO_REQUIRED_APIS, &error);
-  if (error != NULL)
-    goto beach;
-
-  devices = gst_mio_video_device_list_create (ctx);
-  if (devices == NULL)
-    goto beach;
-
-  for (walk = devices, device_idx = 0; walk != NULL; walk = walk->next) {
-    GstMIOVideoDevice *device = walk->data;
-    GValue value = { 0, };
-
-    switch (prop_id) {
-      case PROP_DEVICE_UID:
-      case PROP_DEVICE_NAME:
-      {
-        const gchar *str;
-
-        if (prop_id == PROP_DEVICE_UID)
-          str = gst_mio_video_device_get_uid (device);
-        else
-          str = gst_mio_video_device_get_name (device);
-
-        g_value_init (&value, G_TYPE_STRING);
-        g_value_set_string (&value, str);
-
-        break;
-      }
-      case PROP_DEVICE_INDEX:
-      {
-        g_value_init (&value, G_TYPE_INT);
-        g_value_set_int (&value, device_idx);
-
-        break;
-      }
-      default:
-        G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
-        goto beach;
-    }
-
-    g_value_array_append (values, &value);
-    g_value_unset (&value);
-
-    device_idx++;
-  }
-
-beach:
-  if (devices != NULL)
-    gst_mio_video_device_list_destroy (devices);
-  if (ctx != NULL)
-    g_object_unref (ctx);
-  g_clear_error (&error);
-
-  return values;
-}
-
-static void
-gst_mio_video_src_base_init (gpointer gclass)
-{
-  GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
-
-  gst_element_class_set_metadata (element_class,
-      "Video Source (MIO)", "Source/Video",
-      "Reads frames from a Mac OS X MIO device",
-      "Ole André Vadla Ravnås <oleavr@soundrop.com>");
-
-  gst_element_class_add_pad_template (element_class,
-      gst_static_pad_template_get (&src_template));
-}
-
-static void
-gst_mio_video_src_class_init (GstMIOVideoSrcClass * klass)
-{
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
-  GstBaseSrcClass *gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
-  GstPushSrcClass *gstpushsrc_class = GST_PUSH_SRC_CLASS (klass);
-
-  gobject_class->finalize = gst_mio_video_src_finalize;
-  gobject_class->get_property = gst_mio_video_src_get_property;
-  gobject_class->set_property = gst_mio_video_src_set_property;
-
-  gstelement_class->change_state = gst_mio_video_src_change_state;
-
-  gstbasesrc_class->get_caps = gst_mio_video_src_get_caps;
-  gstbasesrc_class->set_caps = gst_mio_video_src_set_caps;
-  gstbasesrc_class->start = gst_mio_video_src_start;
-  gstbasesrc_class->stop = gst_mio_video_src_stop;
-  gstbasesrc_class->query = gst_mio_video_src_query;
-  gstbasesrc_class->unlock = gst_mio_video_src_unlock;
-  gstbasesrc_class->unlock_stop = gst_mio_video_src_unlock_stop;
-
-  gstpushsrc_class->create = gst_mio_video_src_create;
-
-  g_object_class_install_property (gobject_class, PROP_DEVICE_UID,
-      g_param_spec_string ("device-uid", "Device UID",
-          "Unique ID of the desired device", NULL,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
-      g_param_spec_string ("device-name", "Device Name",
-          "Name of the desired device", NULL,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_class, PROP_DEVICE_INDEX,
-      g_param_spec_int ("device-index", "Device Index",
-          "Zero-based device index of the desired device",
-          -1, G_MAXINT, DEFAULT_DEVICE_INDEX,
-          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
-
-  GST_DEBUG_CATEGORY_INIT (gst_mio_video_src_debug, "miovideosrc",
-      0, "Mac OS X CoreMedia video source");
-}
-
-static void
-gst_mio_video_src_init_interfaces (GType type)
-{
-  static const GInterfaceInfo probe_info = {
-    gst_mio_video_src_probe_interface_init,
-    NULL,
-    NULL
-  };
-
-  g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE, &probe_info);
-}
-
-static void
-gst_mio_video_src_probe_interface_init (gpointer g_iface, gpointer iface_data)
-{
-  GstPropertyProbeInterface *iface = g_iface;
-
-  iface->get_properties = gst_mio_video_src_probe_get_properties;
-  iface->get_values = gst_mio_video_src_probe_get_values;
-}
diff --git a/sys/applemedia/miovideosrc.h b/sys/applemedia/miovideosrc.h
deleted file mode 100644 (file)
index 3fe82e7..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2009 Ole André Vadla Ravnås <oleavr@soundrop.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef __GST_MIO_VIDEO_SRC_H__
-#define __GST_MIO_VIDEO_SRC_H__
-
-#include <gst/base/gstpushsrc.h>
-
-#include "coremediactx.h"
-#include "miovideodevice.h"
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_MIO_VIDEO_SRC \
-  (gst_mio_video_src_get_type ())
-#define GST_MIO_VIDEO_SRC(obj) \
-  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MIO_VIDEO_SRC, GstMIOVideoSrc))
-#define GST_MIO_VIDEO_SRC_CAST(obj) \
-  ((GstMIOVideoSrc *) (obj))
-#define GST_MIO_VIDEO_SRC_CLASS(klass) \
-  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MIO_VIDEO_SRC, GstMIOVideoSrcClass))
-#define GST_IS_MIO_VIDEO_SRC(obj) \
-  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MIO_VIDEO_SRC))
-#define GST_IS_MIO_VIDEO_SRC_CLASS(klass) \
-  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MIO_VIDEO_SRC))
-
-typedef struct _GstMIOVideoSrc         GstMIOVideoSrc;
-typedef struct _GstMIOVideoSrcClass    GstMIOVideoSrcClass;
-
-struct _GstMIOVideoSrc
-{
-  GstPushSrc push_src;
-
-  gint cv_ratio_n;
-  gint cv_ratio_d;
-
-  gchar *device_uid;
-  gchar *device_name;
-  gint device_index;
-
-  GThread *dispatcher_thread;
-  GMainLoop *dispatcher_loop;
-  GMainContext *dispatcher_ctx;
-
-  GstCoreMediaCtx *ctx;
-  GstMIOVideoDevice *device;
-
-  TundraGraph *graph;
-
-  volatile gboolean running;
-  GQueue *queue;
-  GMutex *qlock;
-  GCond *qcond;
-  guint64 prev_offset;
-  CMFormatDescriptionRef prev_format;
-};
-
-struct _GstMIOVideoSrcClass
-{
-  GstPushSrcClass parent_class;
-};
-
-GType gst_mio_video_src_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GST_MIO_VIDEO_SRC_H__ */
index 5b0d52d506119962f8ff71606d74f227e6041be5..da98244ef9430e76e4bd8f7aa9627292d343384b 100644 (file)
 
 #ifdef HAVE_IOS
 #include "avfvideosrc.h"
-#include "celvideosrc.h"
 #else
 #include "qtkitvideosrc.h"
-#include "miovideosrc.h"
 #include <Foundation/Foundation.h>
 #endif
 #include "vth264decbin.h"
@@ -53,17 +51,11 @@ plugin_init (GstPlugin * plugin)
 #ifdef HAVE_IOS
   res = gst_element_register (plugin, "avfvideosrc", GST_RANK_NONE,
       GST_TYPE_AVF_VIDEO_SRC);
-  res &= gst_element_register (plugin, "celvideosrc", GST_RANK_NONE,
-      GST_TYPE_CEL_VIDEO_SRC);
 #else
   enable_mt_mode ();
 
   res = gst_element_register (plugin, "qtkitvideosrc", GST_RANK_PRIMARY,
       GST_TYPE_QTKIT_VIDEO_SRC);
-#if 0
-  res &= gst_element_register (plugin, "miovideosrc", GST_RANK_NONE,
-      GST_TYPE_MIO_VIDEO_SRC);
-#endif
 #endif
 
 #if 0