sys/acmmp3dec/Makefile
sys/androidmedia/Makefile
sys/applemedia/Makefile
+sys/applemedia-nonpublic/Makefile
sys/avc/Makefile
sys/bluez/Makefile
sys/d3dvideosink/Makefile
endif
if USE_APPLE_MEDIA
-APPLE_MEDIA_DIR=applemedia
+APPLE_MEDIA_DIR=applemedia applemedia-nonpublic
else
APPLE_MEDIA_DIR=
endif
--- /dev/null
+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
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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");
+}
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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/")
noinst_HEADERS = \
qtkitvideosrc.h \
- miovideosrc.h \
- miovideodevice.h \
avfvideosrc.h \
- celvideosrc.h \
vth264decbin.h \
vth264encbin.h \
vtenc.h \
coremediactx.h \
cvapi.h \
cmapi.h \
- mioapi.h \
- mtapi.h \
- celapi.h \
vtapi.h \
dynapi.h \
dynapi-internal.h
if HAVE_IOS
libgstapplemedia_la_SOURCES += \
- avfvideosrc.m \
- celvideosrc.c \
- mtapi.c \
- celapi.c
+ avfvideosrc.m
libgstapplemedia_la_LDFLAGS += \
-Wl,-framework -Wl,CoreMedia \
libgstapplemedia_la_SOURCES += \
qtkitvideosrc.m \
vtenc.c \
- vtdec.c \
- mioapi.c
+ vtdec.c
libgstapplemedia_la_LDFLAGS += \
-Wl,-framework -Wl,Cocoa \
+++ /dev/null
-/*
- * 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);
-}
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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");
-}
+++ /dev/null
-/*
- * 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__ */
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);
#include "cmapi.h"
#include "vtapi.h"
-#include "mioapi.h"
-
-#include "mtapi.h"
-#include "celapi.h"
-
#include <glib.h>
G_BEGIN_DECLS
GstCVApi *cv;
GstCMApi *cm;
GstVTApi *vt;
-
- /* OS X */
- GstMIOApi *mio;
-
- /* iPhone */
- GstMTApi *mt;
- GstCelApi *cel;
};
struct _GstCoreMediaCtxClass
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);
+++ /dev/null
-/*
- * 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;
-}
+++ /dev/null
-/*
- * 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
+++ /dev/null
-/*
- * 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;
- }
-}
+++ /dev/null
-/*
- * 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__ */
+++ /dev/null
-/*
- * 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;
-}
+++ /dev/null
-/*
- * 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__ */
#ifdef HAVE_IOS
#include "avfvideosrc.h"
-#include "celvideosrc.h"
#else
#include "qtkitvideosrc.h"
-#include "miovideosrc.h"
#include <Foundation/Foundation.h>
#endif
#include "vth264decbin.h"
#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