vtenc: Port to the real VideoToolbox API instead of using our dlopen() wrapper

It's a public framework since a long time.
This commit is contained in:
Sebastian Dröge 2014-09-16 15:02:46 +03:00
parent 5dc2843c86
commit f2eedb9cee
12 changed files with 65 additions and 1094 deletions

View file

@ -5,22 +5,14 @@ libgstapplemedia_la_SOURCES = \
vtutil.c \
corevideobuffer.c \
coremediabuffer.c \
coremediactx.c \
vtapi.c \
atdec.c \
dynapi.c
atdec.c
libgstapplemedia_la_CPPFLAGS = \
-Dgst_dyn_api_get_type=gst_dyn_api_priv_get_type \
-Dgst_dyn_api_debug=gst_dyn_api_priv_debug \
-D_gst_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
-Dgst_core_video_buffer_get_type=gst_core_video_buffer_priv_get_type
libgstapplemedia_la_CFLAGS = \
$(GST_CFLAGS) \
@ -64,11 +56,7 @@ noinst_HEADERS = \
vtutil.h \
corevideobuffer.h \
coremediabuffer.h \
coremediactx.h \
vtapi.h \
atdec.h \
dynapi.h \
dynapi-internal.h \
iosassetsrc.h \
avfassetsrc.h

View file

@ -1,127 +0,0 @@
/*
* Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#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 (VIDEO_TOOLBOX, vt),
};
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;
}

View file

@ -1,72 +0,0 @@
/*
* Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_CORE_MEDIA_CTX_H__
#define __GST_CORE_MEDIA_CTX_H__
#include "vtapi.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 */
GstVTApi *vt;
};
struct _GstCoreMediaCtxClass
{
GObjectClass parent_class;
};
enum _GstCoreMediaApi
{
GST_API_VIDEO_TOOLBOX = (1 << 0),
};
GType gst_core_media_ctx_get_type (void);
GstCoreMediaCtx * gst_core_media_ctx_new (GstCoreMediaApi required_apis,
GError ** error);
G_END_DECLS
#endif

View file

@ -1,42 +0,0 @@
/*
* Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_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

View file

@ -1,193 +0,0 @@
/*
* Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "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;
}
}

View file

@ -1,65 +0,0 @@
/*
* Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_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

View file

@ -1,80 +0,0 @@
/*
* Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "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);
}

View file

@ -1,96 +0,0 @@
/*
* Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_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

View file

@ -1,100 +0,0 @@
/*
* Copyright (C) 2010, 2013 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 "vtapi.h"
#include "dynapi-internal.h"
#include <gmodule.h>
#define VT_FRAMEWORK_PATH "/System/Library/Frameworks/" \
"VideoToolbox.framework/VideoToolbox"
#define VT_FRAMEWORK_PATH_OLD "/System/Library/PrivateFrameworks/" \
"VideoToolbox.framework/VideoToolbox"
G_DEFINE_TYPE (GstVTApi, gst_vt_api, GST_TYPE_DYN_API);
static void
gst_vt_api_init (GstVTApi * self)
{
}
static void
gst_vt_api_class_init (GstVTApiClass * klass)
{
}
#define SYM_SPEC(name) GST_DYN_SYM_SPEC (GstVTApi, name)
GstVTApi *
gst_vt_api_obtain (GError ** error)
{
static const GstDynSymSpec symbols[] = {
SYM_SPEC (VTCompressionSessionCompleteFrames),
SYM_SPEC (VTCompressionSessionCopyProperty),
SYM_SPEC (VTCompressionSessionCopySupportedPropertyDictionary),
SYM_SPEC (VTCompressionSessionCreate),
SYM_SPEC (VTCompressionSessionEncodeFrame),
SYM_SPEC (VTCompressionSessionInvalidate),
SYM_SPEC (VTCompressionSessionSetProperty),
SYM_SPEC (VTDecompressionSessionCreate),
SYM_SPEC (VTDecompressionSessionDecodeFrame),
SYM_SPEC (VTDecompressionSessionInvalidate),
SYM_SPEC (VTDecompressionSessionWaitForAsynchronousFrames),
SYM_SPEC (VTDecompressionSessionFinishDelayedFrames),
SYM_SPEC (kVTCompressionPropertyKey_AllowTemporalCompression),
SYM_SPEC (kVTCompressionPropertyKey_AverageDataRate),
SYM_SPEC (kVTCompressionPropertyKey_ExpectedFrameRate),
SYM_SPEC (kVTCompressionPropertyKey_ExpectedDuration),
SYM_SPEC (kVTCompressionPropertyKey_MaxKeyFrameInterval),
SYM_SPEC (kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration),
SYM_SPEC (kVTCompressionPropertyKey_ProfileLevel),
SYM_SPEC (kVTCompressionPropertyKey_Usage),
SYM_SPEC (kVTEncodeFrameOptionKey_ForceKeyFrame),
SYM_SPEC (kVTProfileLevel_H264_Baseline_1_3),
SYM_SPEC (kVTProfileLevel_H264_Baseline_3_0),
SYM_SPEC (kVTProfileLevel_H264_Extended_5_0),
SYM_SPEC (kVTProfileLevel_H264_High_5_0),
SYM_SPEC (kVTProfileLevel_H264_Main_3_0),
SYM_SPEC (kVTProfileLevel_H264_Main_3_1),
SYM_SPEC (kVTProfileLevel_H264_Main_4_0),
SYM_SPEC (kVTProfileLevel_H264_Main_4_1),
SYM_SPEC (kVTProfileLevel_H264_Main_5_0),
{NULL, 0},
};
GstVTApi *result;
GModule *module;
module = g_module_open (VT_FRAMEWORK_PATH, 0);
if (module != NULL) {
result = _gst_dyn_api_new (gst_vt_api_get_type (), VT_FRAMEWORK_PATH,
symbols, error);
g_module_close (module);
} else {
result = _gst_dyn_api_new (gst_vt_api_get_type (), VT_FRAMEWORK_PATH_OLD,
symbols, error);
}
return result;
}

View file

@ -1,165 +0,0 @@
/*
* Copyright (C) 2010 Ole André Vadla Ravnås <oleavr@soundrop.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_VT_API_H__
#define __GST_VT_API_H__
#include "dynapi.h"
#include "CoreMedia/CoreMedia.h"
G_BEGIN_DECLS
typedef struct _GstVTApi GstVTApi;
typedef struct _GstVTApiClass GstVTApiClass;
typedef enum _VTStatus VTStatus;
typedef enum _VTDecodeFrameFlags VTDecodeFrameFlags;
typedef enum _VTDecodeInfoFlags VTDecodeInfoFlags;
typedef guint32 VTFormatId;
typedef CFTypeRef VTCompressionSessionRef;
typedef CFTypeRef VTDecompressionSessionRef;
typedef struct _VTCompressionOutputCallback VTCompressionOutputCallback;
typedef struct _VTDecompressionOutputCallback VTDecompressionOutputCallback;
typedef VTStatus (* VTCompressionOutputCallbackFunc) (void * data, int a2,
int a3, int a4, CMSampleBufferRef sbuf, int a6, int a7);
typedef void (* VTDecompressionOutputCallbackFunc) (void *data1, void *data2,
VTStatus result, VTDecodeInfoFlags info, CVBufferRef cvbuf,
CMTime pts, CMTime dts);
enum _VTStatus
{
kVTSuccess = 0
};
enum _VTFormat
{
kVTFormatH264 = 'avc1',
kVTFormatMPEG2 = 'mp2v',
kVTFormatJPEG = 'jpeg'
};
enum _VTDecodeFrameFlags
{
kVTDecodeFrame_EnableAsynchronousDecompression = 1<<0,
kVTDecodeFrame_DoNotOutputFrame = 1<<1,
/* low-power mode that can not decode faster than 1x realtime. */
kVTDecodeFrame_1xRealTimePlayback = 1<<2,
/* Output frame in PTS order.
* Needs to call VTDecompressionSessionFinishDelayedFrames to dequeue */
kVTDecodeFrame_EnableTemporalProcessing = 1<<3,
};
enum _VTDecodeInfoFlags
{
kVTDecodeInfo_Asynchronous = 1UL << 0,
kVTDecodeInfo_FrameDropped = 1UL << 1,
};
struct _VTCompressionOutputCallback
{
VTCompressionOutputCallbackFunc func;
void * data;
};
struct _VTDecompressionOutputCallback
{
VTDecompressionOutputCallbackFunc func;
void * data;
};
struct _GstVTApi
{
GstDynApi parent;
VTStatus (* VTCompressionSessionCompleteFrames)
(VTCompressionSessionRef session, CMTime completeUntilDisplayTimestamp);
VTStatus (* VTCompressionSessionCopyProperty)
(VTCompressionSessionRef session, CFTypeRef key, void* unk,
CFTypeRef * value);
VTStatus (* VTCompressionSessionCopySupportedPropertyDictionary)
(VTCompressionSessionRef session, CFDictionaryRef * dict);
VTStatus (* VTCompressionSessionCreate)
(CFAllocatorRef allocator, gint width, gint height, VTFormatId formatId,
gsize unk1, CFDictionaryRef sourcePixelBufferAttributes, gsize unk2,
VTCompressionOutputCallback outputCallback,
VTCompressionSessionRef * session);
VTStatus (* VTCompressionSessionEncodeFrame)
(VTCompressionSessionRef session, CVPixelBufferRef pixelBuffer,
CMTime displayTimestamp, CMTime displayDuration,
CFDictionaryRef frameOptions, void * sourceTrackingCallback,
void * sourceFrameRefCon);
void (* VTCompressionSessionInvalidate)
(VTCompressionSessionRef session);
VTStatus (* VTCompressionSessionSetProperty)
(VTCompressionSessionRef session, CFStringRef propName,
CFTypeRef propValue);
VTStatus (* VTDecompressionSessionCreate)
(CFAllocatorRef allocator,
CMFormatDescriptionRef videoFormatDescription,
CFTypeRef sessionOptions,
CFDictionaryRef destinationPixelBufferAttributes,
VTDecompressionOutputCallback * outputCallback,
VTDecompressionSessionRef * session);
VTStatus (* VTDecompressionSessionDecodeFrame)
(VTDecompressionSessionRef session, CMSampleBufferRef sbuf,
VTDecodeFrameFlags decode_flags, void *src_buf,
VTDecodeInfoFlags *info_flags);
void (* VTDecompressionSessionInvalidate)
(VTDecompressionSessionRef session);
VTStatus (* VTDecompressionSessionWaitForAsynchronousFrames)
(VTDecompressionSessionRef session);
VTStatus (* VTDecompressionSessionFinishDelayedFrames)
(VTDecompressionSessionRef session);
CFStringRef * kVTCompressionPropertyKey_AllowTemporalCompression;
CFStringRef * kVTCompressionPropertyKey_AverageDataRate;
CFStringRef * kVTCompressionPropertyKey_ExpectedFrameRate;
CFStringRef * kVTCompressionPropertyKey_ExpectedDuration;
CFStringRef * kVTCompressionPropertyKey_MaxKeyFrameInterval;
CFStringRef * kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration;
CFStringRef * kVTCompressionPropertyKey_ProfileLevel;
CFStringRef * kVTCompressionPropertyKey_Usage;
CFStringRef * kVTEncodeFrameOptionKey_ForceKeyFrame;
CFStringRef * kVTProfileLevel_H264_Baseline_1_3;
CFStringRef * kVTProfileLevel_H264_Baseline_3_0;
CFStringRef * kVTProfileLevel_H264_Extended_5_0;
CFStringRef * kVTProfileLevel_H264_High_5_0;
CFStringRef * kVTProfileLevel_H264_Main_3_0;
CFStringRef * kVTProfileLevel_H264_Main_3_1;
CFStringRef * kVTProfileLevel_H264_Main_4_0;
CFStringRef * kVTProfileLevel_H264_Main_4_1;
CFStringRef * kVTProfileLevel_H264_Main_5_0;
};
struct _GstVTApiClass
{
GstDynApiClass parent_class;
};
GType gst_vt_api_get_type (void);
GstVTApi * gst_vt_api_obtain (GError ** error);
G_END_DECLS
#endif

View file

@ -72,8 +72,6 @@ static void gst_vtenc_destroy_session (GstVTEnc * self,
VTCompressionSessionRef * session);
static void gst_vtenc_session_dump_properties (GstVTEnc * self,
VTCompressionSessionRef session);
static void gst_vtenc_session_configure_usage (GstVTEnc * self,
VTCompressionSessionRef session, gint usage);
static void gst_vtenc_session_configure_expected_framerate (GstVTEnc * self,
VTCompressionSessionRef session, gdouble framerate);
static void gst_vtenc_session_configure_expected_duration (GstVTEnc * self,
@ -84,14 +82,16 @@ static void gst_vtenc_session_configure_max_keyframe_interval_duration
(GstVTEnc * self, VTCompressionSessionRef session, gdouble duration);
static void gst_vtenc_session_configure_bitrate (GstVTEnc * self,
VTCompressionSessionRef session, guint bitrate);
static VTStatus gst_vtenc_session_configure_property_int (GstVTEnc * self,
static OSStatus gst_vtenc_session_configure_property_int (GstVTEnc * self,
VTCompressionSessionRef session, CFStringRef name, gint value);
static VTStatus gst_vtenc_session_configure_property_double (GstVTEnc * self,
static OSStatus gst_vtenc_session_configure_property_double (GstVTEnc * self,
VTCompressionSessionRef session, CFStringRef name, gdouble value);
static GstFlowReturn gst_vtenc_encode_frame (GstVTEnc * self, GstBuffer * buf);
static VTStatus gst_vtenc_enqueue_buffer (void *data, int a2, int a3, int a4,
CMSampleBufferRef sbuf, int a6, int a7);
static void gst_vtenc_enqueue_buffer (void *outputCallbackRefCon,
void *sourceFrameRefCon,
OSStatus status,
VTEncodeInfoFlags infoFlags, CMSampleBufferRef sampleBuffer);
static gboolean gst_vtenc_buffer_is_keyframe (GstVTEnc * self,
CMSampleBufferRef sbuf);
@ -139,7 +139,7 @@ gst_vtenc_base_init (GstVTEncClass * klass)
"height", GST_TYPE_INT_RANGE, min_height, max_height,
"framerate", GST_TYPE_FRACTION_RANGE,
min_fps_n, min_fps_d, max_fps_n, max_fps_d, NULL);
if (codec_details->format_id == kVTFormatH264) {
if (codec_details->format_id == kCMVideoCodecType_H264) {
gst_structure_set (gst_caps_get_structure (src_caps, 0),
"stream-format", G_TYPE_STRING, "avc", NULL);
}
@ -164,11 +164,6 @@ gst_vtenc_class_init (GstVTEncClass * klass)
gstelement_class->change_state = gst_vtenc_change_state;
g_object_class_install_property (gobject_class, PROP_USAGE,
g_param_spec_int ("usage", "Usage",
"Usage enumeration value",
G_MININT, G_MAXINT, VTENC_DEFAULT_USAGE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_BITRATE,
g_param_spec_uint ("bitrate", "Bitrate",
"Target video bitrate in kbps",
@ -203,31 +198,6 @@ gst_vtenc_init (GstVTEnc * self)
self->session = NULL;
}
static gint
gst_vtenc_get_usage (GstVTEnc * self)
{
gint result;
GST_OBJECT_LOCK (self);
result = self->usage;
GST_OBJECT_UNLOCK (self);
return result;
}
static void
gst_vtenc_set_usage (GstVTEnc * self, gint usage)
{
GST_OBJECT_LOCK (self);
self->usage = usage;
if (self->session != NULL)
gst_vtenc_session_configure_usage (self, self->session, usage);
GST_OBJECT_UNLOCK (self);
}
static guint
gst_vtenc_get_bitrate (GstVTEnc * self)
{
@ -260,9 +230,6 @@ gst_vtenc_get_property (GObject * obj, guint prop_id, GValue * value,
GstVTEnc *self = GST_VTENC_CAST (obj);
switch (prop_id) {
case PROP_USAGE:
g_value_set_int (value, gst_vtenc_get_usage (self));
break;
case PROP_BITRATE:
g_value_set_uint (value, gst_vtenc_get_bitrate (self) * 8 / 1000);
break;
@ -279,9 +246,6 @@ gst_vtenc_set_property (GObject * obj, guint prop_id, const GValue * value,
GstVTEnc *self = GST_VTENC_CAST (obj);
switch (prop_id) {
case PROP_USAGE:
gst_vtenc_set_usage (self, g_value_get_int (value));
break;
case PROP_BITRATE:
gst_vtenc_set_bitrate (self, g_value_get_uint (value) * 1000 / 8);
break;
@ -295,14 +259,9 @@ static GstStateChangeReturn
gst_vtenc_change_state (GstElement * element, GstStateChange transition)
{
GstVTEnc *self = GST_VTENC_CAST (element);
GError *error = NULL;
GstStateChangeReturn ret;
if (transition == GST_STATE_CHANGE_NULL_TO_READY) {
self->ctx = gst_core_media_ctx_new (GST_API_VIDEO_TOOLBOX, &error);
if (error != NULL)
goto api_error;
self->cur_outbufs = g_ptr_array_new ();
}
@ -327,20 +286,9 @@ gst_vtenc_change_state (GstElement * element, GstStateChange transition)
g_ptr_array_free (self->cur_outbufs, TRUE);
self->cur_outbufs = NULL;
g_object_unref (self->ctx);
self->ctx = NULL;
}
return ret;
api_error:
{
GST_ELEMENT_ERROR (self, RESOURCE, FAILED, ("API error"),
("%s", error->message));
g_clear_error (&error);
return GST_STATE_CHANGE_FAILURE;
}
}
static gboolean
@ -434,7 +382,7 @@ gst_vtenc_negotiate_downstream (GstVTEnc * self, CMSampleBufferRef sbuf)
"framerate", GST_TYPE_FRACTION,
self->negotiated_fps_n, self->negotiated_fps_d, NULL);
if (self->details->format_id == kVTFormatH264) {
if (self->details->format_id == kCMVideoCodecType_H264) {
CMFormatDescriptionRef fmt;
CFDictionaryRef atoms;
CFStringRef avccKey;
@ -506,8 +454,7 @@ gst_vtenc_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
if (self->options != NULL) {
GST_INFO_OBJECT (self, "received PLI, will force intra");
CFDictionaryAddValue (self->options,
*(self->ctx->vt->kVTEncodeFrameOptionKey_ForceKeyFrame),
kCFBooleanTrue);
kVTEncodeFrameOptionKey_ForceKeyFrame, kCFBooleanTrue);
} else {
GST_INFO_OBJECT (self,
"received PLI but encode not yet started, ignoring");
@ -532,10 +479,8 @@ static VTCompressionSessionRef
gst_vtenc_create_session (GstVTEnc * self)
{
VTCompressionSessionRef session = NULL;
GstVTApi *vt = self->ctx->vt;
CFMutableDictionaryRef pb_attrs;
VTCompressionOutputCallback callback;
VTStatus status;
OSStatus status;
pb_attrs = CFDictionaryCreateMutable (NULL, 0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
@ -544,15 +489,13 @@ gst_vtenc_create_session (GstVTEnc * self)
gst_vtutil_dict_set_i32 (pb_attrs, kCVPixelBufferHeightKey,
self->negotiated_height);
callback.func = gst_vtenc_enqueue_buffer;
callback.data = self;
status = vt->VTCompressionSessionCreate (NULL,
status = VTCompressionSessionCreate (NULL,
self->negotiated_width, self->negotiated_height,
self->details->format_id, 0, pb_attrs, 0, callback, &session);
self->details->format_id, NULL, pb_attrs, NULL, gst_vtenc_enqueue_buffer,
self, &session);
GST_INFO_OBJECT (self, "VTCompressionSessionCreate for %d x %d => %d",
self->negotiated_width, self->negotiated_height, status);
if (status != kVTSuccess)
self->negotiated_width, self->negotiated_height, (int) status);
if (status != noErr)
goto beach;
if (self->dump_properties) {
@ -561,24 +504,21 @@ gst_vtenc_create_session (GstVTEnc * self)
self->dump_properties = FALSE;
}
gst_vtenc_session_configure_usage (self, session, gst_vtenc_get_usage (self));
gst_vtenc_session_configure_expected_framerate (self, session,
(gdouble) self->negotiated_fps_n / (gdouble) self->negotiated_fps_d);
gst_vtenc_session_configure_expected_duration (self, session,
(gdouble) self->negotiated_fps_d / (gdouble) self->negotiated_fps_n);
status = vt->VTCompressionSessionSetProperty (session,
*(vt->kVTCompressionPropertyKey_ProfileLevel),
*(vt->kVTProfileLevel_H264_Baseline_3_0));
status = VTSessionSetProperty (session,
kVTCompressionPropertyKey_ProfileLevel,
kVTProfileLevel_H264_Baseline_3_0);
GST_DEBUG_OBJECT (self, "kVTCompressionPropertyKey_ProfileLevel => %d",
status);
(int) status);
status = vt->VTCompressionSessionSetProperty (session,
*(vt->kVTCompressionPropertyKey_AllowTemporalCompression),
kCFBooleanTrue);
status = VTSessionSetProperty (session,
kVTCompressionPropertyKey_AllowTemporalCompression, kCFBooleanTrue);
GST_DEBUG_OBJECT (self,
"kVTCompressionPropertyKey_AllowTemporalCompression => %d", status);
"kVTCompressionPropertyKey_AllowTemporalCompression => %d", (int) status);
gst_vtenc_session_configure_max_keyframe_interval (self, session, 0);
gst_vtenc_session_configure_max_keyframe_interval_duration (self, session,
@ -596,7 +536,7 @@ beach:
static void
gst_vtenc_destroy_session (GstVTEnc * self, VTCompressionSessionRef * session)
{
self->ctx->vt->VTCompressionSessionInvalidate (*session);
VTCompressionSessionInvalidate (*session);
if (*session != NULL) {
CFRelease (*session);
*session = NULL;
@ -606,7 +546,6 @@ gst_vtenc_destroy_session (GstVTEnc * self, VTCompressionSessionRef * session)
typedef struct
{
GstVTEnc *self;
GstVTApi *vt;
VTCompressionSessionRef session;
} GstVTDumpPropCtx;
@ -616,7 +555,7 @@ gst_vtenc_session_dump_property (CFStringRef prop_name,
{
gchar *name_str;
CFTypeRef prop_value;
VTStatus status;
OSStatus status;
name_str = gst_vtutil_string_to_utf8 (prop_name);
if (dpc->self->dump_attributes) {
@ -627,9 +566,8 @@ gst_vtenc_session_dump_property (CFStringRef prop_name,
g_free (attrs_str);
}
status = dpc->vt->VTCompressionSessionCopyProperty (dpc->session, prop_name,
NULL, &prop_value);
if (status == kVTSuccess) {
status = VTSessionCopyProperty (dpc->session, prop_name, NULL, &prop_value);
if (status == noErr) {
gchar *value_str;
value_str = gst_vtutil_object_to_string (prop_value);
@ -640,7 +578,7 @@ gst_vtenc_session_dump_property (CFStringRef prop_name,
CFRelease (prop_value);
} else {
GST_DEBUG_OBJECT (dpc->self, "%s = <failed to query: %d>",
name_str, status);
name_str, (int) status);
}
g_free (name_str);
@ -650,13 +588,12 @@ static void
gst_vtenc_session_dump_properties (GstVTEnc * self,
VTCompressionSessionRef session)
{
GstVTDumpPropCtx dpc = { self, self->ctx->vt, session };
GstVTDumpPropCtx dpc = { self, session };
CFDictionaryRef dict;
VTStatus status;
OSStatus status;
status = self->ctx->vt->VTCompressionSessionCopySupportedPropertyDictionary
(session, &dict);
if (status != kVTSuccess)
status = VTSessionCopySupportedPropertyDictionary (session, &dict);
if (status != noErr)
goto error;
CFDictionaryApplyFunction (dict,
(CFDictionaryApplierFunction) gst_vtenc_session_dump_property, &dpc);
@ -668,20 +605,12 @@ error:
GST_WARNING_OBJECT (self, "failed to dump properties");
}
static void
gst_vtenc_session_configure_usage (GstVTEnc * self,
VTCompressionSessionRef session, gint usage)
{
gst_vtenc_session_configure_property_int (self, session,
*(self->ctx->vt->kVTCompressionPropertyKey_Usage), usage);
}
static void
gst_vtenc_session_configure_expected_framerate (GstVTEnc * self,
VTCompressionSessionRef session, gdouble framerate)
{
gst_vtenc_session_configure_property_double (self, session,
*(self->ctx->vt->kVTCompressionPropertyKey_ExpectedFrameRate), framerate);
kVTCompressionPropertyKey_ExpectedFrameRate, framerate);
}
static void
@ -689,7 +618,7 @@ gst_vtenc_session_configure_expected_duration (GstVTEnc * self,
VTCompressionSessionRef session, gdouble duration)
{
gst_vtenc_session_configure_property_double (self, session,
*(self->ctx->vt->kVTCompressionPropertyKey_ExpectedDuration), duration);
kVTCompressionPropertyKey_ExpectedDuration, duration);
}
static void
@ -697,8 +626,7 @@ gst_vtenc_session_configure_max_keyframe_interval (GstVTEnc * self,
VTCompressionSessionRef session, gint interval)
{
gst_vtenc_session_configure_property_int (self, session,
*(self->ctx->vt->kVTCompressionPropertyKey_MaxKeyFrameInterval),
interval);
kVTCompressionPropertyKey_MaxKeyFrameInterval, interval);
}
static void
@ -706,8 +634,7 @@ gst_vtenc_session_configure_max_keyframe_interval_duration (GstVTEnc * self,
VTCompressionSessionRef session, gdouble duration)
{
gst_vtenc_session_configure_property_double (self, session,
*(self->ctx->vt->kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration),
duration);
kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration, duration);
}
static void
@ -715,41 +642,41 @@ gst_vtenc_session_configure_bitrate (GstVTEnc * self,
VTCompressionSessionRef session, guint bitrate)
{
gst_vtenc_session_configure_property_int (self, session,
*(self->ctx->vt->kVTCompressionPropertyKey_AverageDataRate), bitrate);
kVTCompressionPropertyKey_AverageBitRate, bitrate);
}
static VTStatus
static OSStatus
gst_vtenc_session_configure_property_int (GstVTEnc * self,
VTCompressionSessionRef session, CFStringRef name, gint value)
{
CFNumberRef num;
VTStatus status;
OSStatus status;
gchar name_str[128];
num = CFNumberCreate (NULL, kCFNumberIntType, &value);
status = self->ctx->vt->VTCompressionSessionSetProperty (session, name, num);
status = VTSessionSetProperty (session, name, num);
CFRelease (num);
CFStringGetCString (name, name_str, sizeof (name_str), kCFStringEncodingUTF8);
GST_DEBUG_OBJECT (self, "%s(%d) => %d", name_str, value, status);
GST_DEBUG_OBJECT (self, "%s(%d) => %d", name_str, value, (int) status);
return status;
}
static VTStatus
static OSStatus
gst_vtenc_session_configure_property_double (GstVTEnc * self,
VTCompressionSessionRef session, CFStringRef name, gdouble value)
{
CFNumberRef num;
VTStatus status;
OSStatus status;
gchar name_str[128];
num = CFNumberCreate (NULL, kCFNumberDoubleType, &value);
status = self->ctx->vt->VTCompressionSessionSetProperty (session, name, num);
status = VTSessionSetProperty (session, name, num);
CFRelease (num);
CFStringGetCString (name, name_str, sizeof (name_str), kCFStringEncodingUTF8);
GST_DEBUG_OBJECT (self, "%s(%f) => %d", name_str, value, status);
GST_DEBUG_OBJECT (self, "%s(%f) => %d", name_str, value, (int) status);
return status;
}
@ -757,11 +684,10 @@ gst_vtenc_session_configure_property_double (GstVTEnc * self,
static GstFlowReturn
gst_vtenc_encode_frame (GstVTEnc * self, GstBuffer * buf)
{
GstVTApi *vt = self->ctx->vt;
CMTime ts, duration;
GstCoreMediaMeta *meta;
CVPixelBufferRef pbuf = NULL;
VTStatus vt_status;
OSStatus vt_status;
GstFlowReturn ret = GST_FLOW_OK;
guint i;
@ -835,20 +761,19 @@ gst_vtenc_encode_frame (GstVTEnc * self, GstBuffer * buf)
GST_OBJECT_LOCK (self);
self->expect_keyframe = CFDictionaryContainsKey (self->options,
*(vt->kVTEncodeFrameOptionKey_ForceKeyFrame));
kVTEncodeFrameOptionKey_ForceKeyFrame);
if (self->expect_keyframe)
gst_vtenc_clear_cached_caps_downstream (self);
vt_status = self->ctx->vt->VTCompressionSessionEncodeFrame (self->session,
vt_status = VTCompressionSessionEncodeFrame (self->session,
pbuf, ts, duration, self->options, NULL, NULL);
if (vt_status != 0) {
GST_WARNING_OBJECT (self, "VTCompressionSessionEncodeFrame returned %d",
vt_status);
(int) vt_status);
}
self->ctx->vt->VTCompressionSessionCompleteFrames (self->session,
kCMTimeInvalid);
VTCompressionSessionCompleteFrames (self->session, kCMTimeInvalid);
GST_OBJECT_UNLOCK (self);
@ -886,30 +811,32 @@ cv_error:
}
}
static VTStatus
gst_vtenc_enqueue_buffer (void *data, int a2, int a3, int a4,
CMSampleBufferRef sbuf, int a6, int a7)
static void
gst_vtenc_enqueue_buffer (void *outputCallbackRefCon,
void *sourceFrameRefCon,
OSStatus status,
VTEncodeInfoFlags infoFlags, CMSampleBufferRef sampleBuffer)
{
GstVTEnc *self = data;
GstVTEnc *self = outputCallbackRefCon;
gboolean is_keyframe;
GstBuffer *buf;
/* This may happen if we don't have enough bitrate */
if (sbuf == NULL)
if (sampleBuffer == NULL)
goto beach;
is_keyframe = gst_vtenc_buffer_is_keyframe (self, sbuf);
is_keyframe = gst_vtenc_buffer_is_keyframe (self, sampleBuffer);
if (self->expect_keyframe) {
if (!is_keyframe)
goto beach;
CFDictionaryRemoveValue (self->options,
*(self->ctx->vt->kVTEncodeFrameOptionKey_ForceKeyFrame));
kVTEncodeFrameOptionKey_ForceKeyFrame);
}
self->expect_keyframe = FALSE;
/* We are dealing with block buffers here, so we don't need
* to enable the use of the video meta API on the core media buffer */
buf = gst_core_media_buffer_new (sbuf, FALSE);
buf = gst_core_media_buffer_new (sampleBuffer, FALSE);
gst_buffer_copy_into (buf, self->cur_inbuf, GST_BUFFER_COPY_TIMESTAMPS,
0, -1);
if (is_keyframe) {
@ -922,7 +849,7 @@ gst_vtenc_enqueue_buffer (void *data, int a2, int a3, int a4,
g_ptr_array_add (self->cur_outbufs, buf);
beach:
return kVTSuccess;
return;
}
static gboolean
@ -1013,7 +940,7 @@ gst_vtenc_register (GstPlugin * plugin,
}
static const GstVTEncoderDetails gst_vtenc_codecs[] = {
{"H.264", "h264", "video/x-h264", kVTFormatH264},
{"H.264", "h264", "video/x-h264", kCMVideoCodecType_H264},
};
void

View file

@ -22,8 +22,7 @@
#include <gst/gst.h>
#include <gst/video/video.h>
#include "coremediactx.h"
#include <VideoToolbox/VideoToolbox.h>
G_BEGIN_DECLS
@ -44,7 +43,7 @@ struct _GstVTEncoderDetails
const gchar * name;
const gchar * element_name;
const gchar * mimetype;
VTFormatId format_id;
CMVideoCodecType format_id;
};
struct _GstVTEncClass
@ -61,11 +60,8 @@ struct _GstVTEnc
GstPad * sinkpad;
GstPad * srcpad;
gint usage;
guint bitrate;
GstCoreMediaCtx * ctx;
gboolean dump_properties;
gboolean dump_attributes;