From 3ba8b3c0adaacb5fb92cc4e6fe33fc6ab66af906 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 23 Nov 2011 11:21:15 +0100 Subject: [PATCH 01/24] spacescope: use the drawhelpers and add a draw-style property Like in wavescope support drawing dots and lines. --- gst/audiovisualizers/gstspacescope.c | 148 +++++++++++++++++++++++++-- gst/audiovisualizers/gstspacescope.h | 6 ++ 2 files changed, 144 insertions(+), 10 deletions(-) diff --git a/gst/audiovisualizers/gstspacescope.c b/gst/audiovisualizers/gstspacescope.c index fe8169dc46..f7b7f7d303 100644 --- a/gst/audiovisualizers/gstspacescope.c +++ b/gst/audiovisualizers/gstspacescope.c @@ -35,6 +35,7 @@ #include "config.h" #endif +#include #include "gstspacescope.h" static GstStaticPadTemplate gst_space_scope_src_template = @@ -55,6 +56,47 @@ GST_STATIC_PAD_TEMPLATE ("sink", GST_DEBUG_CATEGORY_STATIC (space_scope_debug); #define GST_CAT_DEFAULT space_scope_debug +enum +{ + PROP_0, + PROP_STYLE +}; + +enum +{ + STYLE_DOTS = 0, + STYLE_LINES, + NUM_STYLES +}; + +#define GST_TYPE_SPACE_SCOPE_STYLE (gst_space_scope_style_get_type ()) +static GType +gst_space_scope_style_get_type (void) +{ + static GType gtype = 0; + + if (gtype == 0) { + static const GEnumValue values[] = { + {STYLE_DOTS, "draw dots (default)", "dots"}, + {STYLE_LINES, "draw lines", "lines"}, + {0, NULL, NULL} + }; + + gtype = g_enum_register_static ("GstSpaceScopeStyle", values); + } + return gtype; +} + +static void gst_space_scope_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_space_scope_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static void render_dots (GstBaseAudioVisualizer * scope, guint32 * vdata, + gint16 * adata, guint num_samples); +static void render_lines (GstBaseAudioVisualizer * scope, guint32 * vdata, + gint16 * adata, guint num_samples); + static gboolean gst_space_scope_render (GstBaseAudioVisualizer * scope, GstBuffer * audio, GstBuffer * video); @@ -80,10 +122,20 @@ gst_space_scope_base_init (gpointer g_class) static void gst_space_scope_class_init (GstSpaceScopeClass * g_class) { + GObjectClass *gobject_class = (GObjectClass *) g_class; GstBaseAudioVisualizerClass *scope_class = (GstBaseAudioVisualizerClass *) g_class; + gobject_class->set_property = gst_space_scope_set_property; + gobject_class->get_property = gst_space_scope_get_property; + scope_class->render = GST_DEBUG_FUNCPTR (gst_space_scope_render); + + g_object_class_install_property (gobject_class, PROP_STYLE, + g_param_spec_enum ("style", "drawing style", + "Drawing styles for the space scope display.", + GST_TYPE_SPACE_SCOPE_STYLE, STYLE_DOTS, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } static void @@ -92,19 +144,57 @@ gst_space_scope_init (GstSpaceScope * scope, GstSpaceScopeClass * g_class) /* do nothing */ } -static gboolean -gst_space_scope_render (GstBaseAudioVisualizer * scope, GstBuffer * audio, - GstBuffer * video) +static void +gst_space_scope_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) { - guint32 *vdata = (guint32 *) GST_BUFFER_DATA (video); - gint16 *adata = (gint16 *) GST_BUFFER_DATA (audio); - guint i, s, x, y, off, ox, oy; - guint num_samples; + GstSpaceScope *scope = GST_SPACE_SCOPE (object); + + switch (prop_id) { + case PROP_STYLE: + scope->style = g_value_get_enum (value); + switch (scope->style) { + case STYLE_DOTS: + scope->process = render_dots; + break; + case STYLE_LINES: + scope->process = render_lines; + break; + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_space_scope_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstSpaceScope *scope = GST_SPACE_SCOPE (object); + + switch (prop_id) { + case PROP_STYLE: + g_value_set_enum (value, scope->style); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +#include "gstdrawhelpers.h" + +static void +render_dots (GstBaseAudioVisualizer * scope, guint32 * vdata, gint16 * adata, + guint num_samples) +{ + guint i, s, x, y, ox, oy; gfloat dx, dy; guint w = scope->width; /* draw dots 1st channel x, 2nd channel y */ - num_samples = GST_BUFFER_SIZE (audio) / (scope->channels * sizeof (gint16)); dx = scope->width / 65536.0; ox = scope->width / 2; dy = scope->height / 65536.0; @@ -113,9 +203,47 @@ gst_space_scope_render (GstBaseAudioVisualizer * scope, GstBuffer * audio, for (i = 0; i < num_samples; i++) { x = (guint) (ox + (gfloat) adata[s++] * dx); y = (guint) (oy + (gfloat) adata[s++] * dy); - off = (y * w) + x; - vdata[off] = 0x00FFFFFF; + draw_dot (vdata, x, y, w, 0x00FFFFFF); } +} + +static void +render_lines (GstBaseAudioVisualizer * scope, guint32 * vdata, gint16 * adata, + guint num_samples) +{ + guint i, s, x, y, ox, oy; + gfloat dx, dy; + guint w = scope->width; + gint x2, y2; + + /* draw lines 1st channel x, 2nd channel y */ + dx = scope->width / 65536.0; + ox = scope->width / 2; + dy = scope->height / 65536.0; + oy = scope->height / 2; + s = 0; + x2 = (guint) (ox + (gfloat) adata[s++] * dx); + y2 = (guint) (oy + (gfloat) adata[s++] * dy); + for (i = 1; i < num_samples; i++) { + x = (guint) (ox + (gfloat) adata[s++] * dx); + y = (guint) (oy + (gfloat) adata[s++] * dy); + draw_line (vdata, x2, x, y2, y, w, 0x00FFFFFF); + x2 = x; + y2 = y; + } +} + +static gboolean +gst_space_scope_render (GstBaseAudioVisualizer * base, GstBuffer * audio, + GstBuffer * video) +{ + GstSpaceScope *scope = GST_SPACE_SCOPE (base); + guint32 *vdata = (guint32 *) GST_BUFFER_DATA (video); + gint16 *adata = (gint16 *) GST_BUFFER_DATA (audio); + guint num_samples; + + num_samples = GST_BUFFER_SIZE (audio) / (base->channels * sizeof (gint16)); + scope->process (base, vdata, adata, num_samples); return TRUE; } diff --git a/gst/audiovisualizers/gstspacescope.h b/gst/audiovisualizers/gstspacescope.h index 0beae5a1f7..62600f4b4b 100644 --- a/gst/audiovisualizers/gstspacescope.h +++ b/gst/audiovisualizers/gstspacescope.h @@ -33,9 +33,15 @@ G_BEGIN_DECLS typedef struct _GstSpaceScope GstSpaceScope; typedef struct _GstSpaceScopeClass GstSpaceScopeClass; +typedef void (*GstSpaceScopeProcessFunc) (GstBaseAudioVisualizer *, guint32 *, gint16 *, guint); + struct _GstSpaceScope { GstBaseAudioVisualizer parent; + + /* < private > */ + GstSpaceScopeProcessFunc process; + gint style; }; struct _GstSpaceScopeClass From 03f1f0214e6f1a109f76c03b695e5ae4377f094c Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Wed, 23 Nov 2011 11:31:44 +0100 Subject: [PATCH 02/24] audiovisualizers: update README and TODO comments --- gst/audiovisualizers/README | 18 +++++++++++------- gst/audiovisualizers/gstdrawhelpers.h | 2 ++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/gst/audiovisualizers/README b/gst/audiovisualizers/README index 0d0f08a245..79d88020d9 100644 --- a/gst/audiovisualizers/README +++ b/gst/audiovisualizers/README @@ -8,13 +8,15 @@ subclass). The baseclass takes care of that. = API = -* should we add some basic drawing helpers to the baseclass +* we have a couple of drawing helpers in gstdrawhelpers.h + (would be nice if we could use cairo) draw_point (x,y,color); + draw_line (x1,x2,y1,y2,color); +* some more we could add: draw_hline (x1,x2,y,color); draw_vline (x,y1,y2,color); draw_rect (x1,x2,y1,y2,color); draw_box (x1,x2,y1,y2,color); // filled - - would be nice if we could use cairo * shading effects - would be nice to use a generic 3x3 matrix operation, we don't run inplace anyway @@ -22,6 +24,7 @@ subclass). The baseclass takes care of that. = Elements to port = gst-plugin-ugly/gst/synaestesia -> synaescope +gst-plugin-bad/gst/smoothwave -> wavescope gst-plugin-good/gst/monoscope -> blend into what we have in wavescope = Elements to add = @@ -41,11 +44,12 @@ GST_DEBUG="*:2,*scope*:4" GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-inspect scopes GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-launch audiotestsrc ! audioconvert ! wavescope ! colorspace ! ximagesink -GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-launch filesrc location=/home/ensonic/Musik/xotox-hypnocat.mp3 ! decodebin2 ! audioconvert ! wavescope ! colorspace ! ximagesink -GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-launch filesrc location=/home/ensonic/Musik/xotox-hypnocat.mp3 ! decodebin2 ! audioconvert ! spectrascope ! colorspace ! ximagesink +GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-launch filesrc location=$HOME/Music/1.mp3 ! decodebin2 ! audioconvert ! wavescope ! colorspace ! ximagesink -GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-launch filesrc location=/home/ensonic/Musik/Gridlock/Trace/04\ Uh4.17.mp3 ! decodebin2 ! audioconvert ! spectrascope ! colorspace ! ximagesink -GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-launch filesrc location=/home/ensonic/Musik/Gridlock/Trace/04\ Uh4.17.mp3 ! decodebin2 ! audioconvert ! spectrascope shader=fade-and-move-up shade-amount=0x00040302 ! colorspace ! ximagesink +GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-launch filesrc location=$HOME/Music/1.mp3 ! decodebin2 ! audioconvert ! spacescope style=lines shade-amount=0x00080402 ! ximagesink -GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-launch filesrc location=/home/ensonic/Musik/Gridlock/Trace/04\ Uh4.17.mp3 ! decodebin2 ! tee name=t ! queue ! audioconvert ! synaesthesia ! ximagesink t. ! queue ! synaescope shade-amount=0x00040404 ! colorspace ! ximagesink +GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-launch filesrc location=$HOME/Music/1.mp3 ! decodebin2 ! audioconvert ! spectrascope ! colorspace ! ximagesink +GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-launch filesrc location=$HOME/Music/1.mp3 ! decodebin2 ! audioconvert ! spectrascope shader=fade-and-move-up shade-amount=0x00040302 ! colorspace ! ximagesink + +GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-launch filesrc location=$HOME/Music/1.mp3 ! decodebin2 ! tee name=t ! queue ! audioconvert ! synaesthesia ! ximagesink t. ! queue ! synaescope shade-amount=0x00040404 ! colorspace ! ximagesink diff --git a/gst/audiovisualizers/gstdrawhelpers.h b/gst/audiovisualizers/gstdrawhelpers.h index d3597ff621..990cedaf65 100644 --- a/gst/audiovisualizers/gstdrawhelpers.h +++ b/gst/audiovisualizers/gstdrawhelpers.h @@ -18,6 +18,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* FIXME: add versions that don't ignore alpha */ + #define draw_dot(_vd, _x, _y, _st, _c) G_STMT_START { \ _vd[(_y * _st) + _x] = _c; \ } G_STMT_END From f5a142068f7bd5c92e7ca116db14bf278458339c Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 23 Nov 2011 11:55:06 +0100 Subject: [PATCH 03/24] pkgconfig: Fix gstreamer-basevideo-uninstalled.pc.in --- pkgconfig/gstreamer-basevideo-uninstalled.pc.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgconfig/gstreamer-basevideo-uninstalled.pc.in b/pkgconfig/gstreamer-basevideo-uninstalled.pc.in index 50a64c439f..21e040f811 100644 --- a/pkgconfig/gstreamer-basevideo-uninstalled.pc.in +++ b/pkgconfig/gstreamer-basevideo-uninstalled.pc.in @@ -1,12 +1,12 @@ prefix= exec_prefix= -libdir=${pcfiledir}/../gst-libs/gst/basevideo +libdir=${pcfiledir}/../gst-libs/gst/video includedir=${pcfiledir}/../gst-libs Name: GStreamer base video, Uninstalled Description: Base class, interface and utilities for video elements, Uninstalled Requires: gstreamer-@GST_MAJORMINOR@ gstreamer-base-@GST_MAJORMINOR@ Version: @VERSION@ -Libs: -L${libdir} ${libdir}/libgstbasevideo-@GST_MAJORMINOR@.la +Libs: -L${libdir} ${libdir}/libgstvideo-@GST_MAJORMINOR@.la Cflags: -I${includedir} From 296874561f41687b5432af5f2619b6bf0c34b5f1 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Wed, 23 Nov 2011 11:59:42 +0100 Subject: [PATCH 04/24] pkgconfig: aaand fix my last commit --- pkgconfig/gstreamer-basevideo-uninstalled.pc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgconfig/gstreamer-basevideo-uninstalled.pc.in b/pkgconfig/gstreamer-basevideo-uninstalled.pc.in index 21e040f811..151e66f482 100644 --- a/pkgconfig/gstreamer-basevideo-uninstalled.pc.in +++ b/pkgconfig/gstreamer-basevideo-uninstalled.pc.in @@ -7,6 +7,6 @@ Name: GStreamer base video, Uninstalled Description: Base class, interface and utilities for video elements, Uninstalled Requires: gstreamer-@GST_MAJORMINOR@ gstreamer-base-@GST_MAJORMINOR@ Version: @VERSION@ -Libs: -L${libdir} ${libdir}/libgstvideo-@GST_MAJORMINOR@.la +Libs: -L${libdir} ${libdir}/libgstbasevideo-@GST_MAJORMINOR@.la Cflags: -I${includedir} From 461f1971ddca8123c1d7d8b3a591b8bf6f2f0c1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Stadler?= Date: Wed, 23 Nov 2011 12:41:32 +0100 Subject: [PATCH 05/24] frei0r: normalize boolean property default values to TRUE/FALSE Glib barks at us with a warning when we pass e.g. 4. --- gst/frei0r/gstfrei0r.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gst/frei0r/gstfrei0r.c b/gst/frei0r/gstfrei0r.c index c7a9c71d59..a6763cd01c 100644 --- a/gst/frei0r/gstfrei0r.c +++ b/gst/frei0r/gstfrei0r.c @@ -105,7 +105,8 @@ gst_frei0r_klass_install_properties (GObjectClass * gobject_class, case F0R_PARAM_BOOL: g_object_class_install_property (gobject_class, count++, g_param_spec_boolean (prop_name, param_info->name, - param_info->explanation, properties[i].default_value.data.b, + param_info->explanation, + properties[i].default_value.data.b ? TRUE : FALSE, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); properties[i].n_prop_ids = 1; break; From b80f52a729cbebeb67808765d990ae83544d86f7 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Wed, 23 Nov 2011 11:58:54 +0000 Subject: [PATCH 06/24] opusdec: add in-band FEC support This allows reconstruction of lost packets if FEC info is included in the next packet, at the cost of extra latency. Since we do not know if the stream has FEC (and this can change at runtime), we always incur the latency, even if we never lose any frame, or see any FEC information. Off by default. --- ext/opus/gstopusdec.c | 123 ++++++++++++++++++++++++++++++++++++------ ext/opus/gstopusdec.h | 4 ++ 2 files changed, 110 insertions(+), 17 deletions(-) diff --git a/ext/opus/gstopusdec.c b/ext/opus/gstopusdec.c index 89eec6941e..7d70fea184 100644 --- a/ext/opus/gstopusdec.c +++ b/ext/opus/gstopusdec.c @@ -67,6 +67,14 @@ GST_STATIC_PAD_TEMPLATE ("sink", GST_STATIC_CAPS ("audio/x-opus") ); +#define DEFAULT_USE_INBAND_FEC FALSE + +enum +{ + PROP_0, + PROP_USE_INBAND_FEC +}; + GST_BOILERPLATE (GstOpusDec, gst_opus_dec, GstAudioDecoder, GST_TYPE_AUDIO_DECODER); @@ -78,6 +86,11 @@ static GstFlowReturn gst_opus_dec_handle_frame (GstAudioDecoder * dec, GstBuffer * buffer); static gboolean gst_opus_dec_set_format (GstAudioDecoder * bdec, GstCaps * caps); +static void gst_opus_dec_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void gst_opus_dec_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); + static void gst_opus_dec_base_init (gpointer g_class) @@ -97,17 +110,27 @@ gst_opus_dec_base_init (gpointer g_class) static void gst_opus_dec_class_init (GstOpusDecClass * klass) { + GObjectClass *gobject_class; GstAudioDecoderClass *adclass; GstElementClass *gstelement_class; + gobject_class = (GObjectClass *) klass; adclass = (GstAudioDecoderClass *) klass; gstelement_class = (GstElementClass *) klass; + gobject_class->set_property = gst_opus_dec_set_property; + gobject_class->get_property = gst_opus_dec_get_property; + adclass->start = GST_DEBUG_FUNCPTR (gst_opus_dec_start); adclass->stop = GST_DEBUG_FUNCPTR (gst_opus_dec_stop); adclass->handle_frame = GST_DEBUG_FUNCPTR (gst_opus_dec_handle_frame); adclass->set_format = GST_DEBUG_FUNCPTR (gst_opus_dec_set_format); + g_object_class_install_property (gobject_class, PROP_USE_INBAND_FEC, + g_param_spec_boolean ("use-inband-fec", "Use in-band FEC", + "Use forward error correction if available", DEFAULT_USE_INBAND_FEC, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + GST_DEBUG_CATEGORY_INIT (opusdec_debug, "opusdec", 0, "opus decoding element"); } @@ -123,6 +146,8 @@ gst_opus_dec_reset (GstOpusDec * dec) gst_buffer_replace (&dec->streamheader, NULL); gst_buffer_replace (&dec->vorbiscomment, NULL); + gst_buffer_replace (&dec->last_buffer, NULL); + dec->primed = FALSE; dec->pre_skip = 0; } @@ -132,6 +157,7 @@ gst_opus_dec_init (GstOpusDec * dec, GstOpusDecClass * g_class) { dec->sample_rate = 0; dec->n_channels = 0; + dec->use_inband_fec = FALSE; gst_opus_dec_reset (dec); } @@ -146,6 +172,11 @@ gst_opus_dec_start (GstAudioDecoder * dec) /* we know about concealment */ gst_audio_decoder_set_plc_aware (dec, TRUE); + if (odec->use_inband_fec) { + gst_audio_decoder_set_latency (dec, 2 * GST_MSECOND + GST_MSECOND / 2, + 120 * GST_MSECOND); + } + return TRUE; } @@ -222,7 +253,7 @@ gst_opus_dec_setup_from_peer_caps (GstOpusDec * dec) } static GstFlowReturn -opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buf) +opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer) { GstFlowReturn res = GST_FLOW_OK; gint size; @@ -232,6 +263,7 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buf) int n, err; int samples; unsigned int packet_size; + GstBuffer *buf; if (dec->state == NULL) { gst_opus_dec_setup_from_peer_caps (dec); @@ -243,30 +275,37 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buf) goto creation_failed; } + if (buffer) { + GST_DEBUG_OBJECT (dec, "Received buffer of size %u", + GST_BUFFER_SIZE (buffer)); + } else { + GST_DEBUG_OBJECT (dec, "Received missing buffer"); + } + + /* if using in-band FEC, we introdude one extra frame's delay as we need + to potentially wait for next buffer to decode a missing buffer */ + if (dec->use_inband_fec && !dec->primed) { + GST_DEBUG_OBJECT (dec, "First buffer received in FEC mode, early out"); + goto done; + } + + /* That's the buffer we'll be sending to the opus decoder. */ + buf = dec->use_inband_fec && dec->last_buffer ? dec->last_buffer : buffer; + if (buf) { data = GST_BUFFER_DATA (buf); size = GST_BUFFER_SIZE (buf); - - GST_DEBUG_OBJECT (dec, "received buffer of size %u", size); + GST_DEBUG_OBJECT (dec, "Using buffer of size %u", size); } else { /* concealment data, pass NULL as the bits parameters */ - GST_DEBUG_OBJECT (dec, "creating concealment data"); + GST_DEBUG_OBJECT (dec, "Using NULL buffer"); data = NULL; size = 0; } - if (data) { - samples = - opus_packet_get_samples_per_frame (data, - dec->sample_rate) * opus_packet_get_nb_frames (data, size); - packet_size = samples * dec->n_channels * 2; - GST_DEBUG_OBJECT (dec, "bandwidth %d", opus_packet_get_bandwidth (data)); - GST_DEBUG_OBJECT (dec, "samples %d", samples); - } else { - /* use maximum size (120 ms) as we do now know in advance how many samples - will be returned */ - samples = 120 * dec->sample_rate / 1000; - } + /* use maximum size (120 ms) as the number of returned samples is + not constant over the stream. */ + samples = 120 * dec->sample_rate / 1000; packet_size = samples * dec->n_channels * 2; res = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_DECODER_SRC_PAD (dec), @@ -280,7 +319,19 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buf) out_data = (gint16 *) GST_BUFFER_DATA (outbuf); - n = opus_decode (dec->state, data, size, out_data, samples, 0); + if (dec->use_inband_fec) { + if (dec->last_buffer) { + /* normal delayed decode */ + n = opus_decode (dec->state, data, size, out_data, samples, 0); + } else { + /* FEC reconstruction decode */ + n = opus_decode (dec->state, data, size, out_data, samples, 1); + } + } else { + /* normal decode */ + n = opus_decode (dec->state, data, size, out_data, samples, 0); + } + if (n < 0) { GST_ELEMENT_ERROR (dec, STREAM, DECODE, ("Decoding error: %d", n), (NULL)); return GST_FLOW_ERROR; @@ -311,6 +362,12 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buf) if (res != GST_FLOW_OK) GST_DEBUG_OBJECT (dec, "flow: %s", gst_flow_get_name (res)); +done: + if (dec->use_inband_fec) { + gst_buffer_replace (&dec->last_buffer, buffer); + dec->primed = TRUE; + } + return res; creation_failed: @@ -437,3 +494,35 @@ gst_opus_dec_handle_frame (GstAudioDecoder * adec, GstBuffer * buf) return res; } + +static void +gst_opus_dec_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstOpusDec *dec = GST_OPUS_DEC (object); + + switch (prop_id) { + case PROP_USE_INBAND_FEC: + g_value_set_boolean (value, dec->use_inband_fec); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_opus_dec_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstOpusDec *dec = GST_OPUS_DEC (object); + + switch (prop_id) { + case PROP_USE_INBAND_FEC: + dec->use_inband_fec = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} diff --git a/ext/opus/gstopusdec.h b/ext/opus/gstopusdec.h index eee27dc554..081e575247 100644 --- a/ext/opus/gstopusdec.h +++ b/ext/opus/gstopusdec.h @@ -54,6 +54,10 @@ struct _GstOpusDec { int sample_rate; int n_channels; guint32 pre_skip; + + gboolean use_inband_fec; + GstBuffer *last_buffer; + gboolean primed; }; struct _GstOpusDecClass { From 4bd5ef9bc5c09a363ebd7fc7e1236a77e939bc69 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Wed, 23 Nov 2011 13:22:12 +0000 Subject: [PATCH 07/24] opusdec: implement replay gain It would ideally be better to leave this to a rgvolume element, but we don't control the pipeline. So do it by default, and allow disabling it via a property, so the correct volume should always be output. --- ext/opus/gstopusdec.c | 55 +++++++++++++++++++++++++++++++++++++++++-- ext/opus/gstopusdec.h | 4 ++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/ext/opus/gstopusdec.c b/ext/opus/gstopusdec.c index 7d70fea184..e85a6b7471 100644 --- a/ext/opus/gstopusdec.c +++ b/ext/opus/gstopusdec.c @@ -41,6 +41,7 @@ # include "config.h" #endif +#include #include #include #include "gstopusheader.h" @@ -67,12 +68,16 @@ GST_STATIC_PAD_TEMPLATE ("sink", GST_STATIC_CAPS ("audio/x-opus") ); +#define DB_TO_LINEAR(x) pow (10., (x) / 20.) + #define DEFAULT_USE_INBAND_FEC FALSE +#define DEFAULT_APPLY_GAIN TRUE enum { PROP_0, - PROP_USE_INBAND_FEC + PROP_USE_INBAND_FEC, + PROP_APPLY_GAIN }; GST_BOILERPLATE (GstOpusDec, gst_opus_dec, GstAudioDecoder, @@ -131,6 +136,11 @@ gst_opus_dec_class_init (GstOpusDecClass * klass) "Use forward error correction if available", DEFAULT_USE_INBAND_FEC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_APPLY_GAIN, + g_param_spec_boolean ("apply-gain", "Apply gain", + "Apply gain if any is specified in the header", DEFAULT_APPLY_GAIN, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + GST_DEBUG_CATEGORY_INIT (opusdec_debug, "opusdec", 0, "opus decoding element"); } @@ -150,6 +160,7 @@ gst_opus_dec_reset (GstOpusDec * dec) dec->primed = FALSE; dec->pre_skip = 0; + dec->r128_gain = 0; } static void @@ -158,6 +169,7 @@ gst_opus_dec_init (GstOpusDec * dec, GstOpusDecClass * g_class) dec->sample_rate = 0; dec->n_channels = 0; dec->use_inband_fec = FALSE; + dec->apply_gain = DEFAULT_APPLY_GAIN; gst_opus_dec_reset (dec); } @@ -190,6 +202,18 @@ gst_opus_dec_stop (GstAudioDecoder * dec) return TRUE; } +static double +gst_opus_dec_get_r128_gain (gint16 r128_gain) +{ + return r128_gain / (double) (1 << 8); +} + +static double +gst_opus_dec_get_r128_volume (gint16 r128_gain) +{ + return DB_TO_LINEAR (gst_opus_dec_get_r128_gain (r128_gain)); +} + static GstFlowReturn gst_opus_dec_parse_header (GstOpusDec * dec, GstBuffer * buf) { @@ -198,7 +222,11 @@ gst_opus_dec_parse_header (GstOpusDec * dec, GstBuffer * buf) g_return_val_if_fail (GST_BUFFER_SIZE (buf) >= 19, GST_FLOW_ERROR); dec->pre_skip = GST_READ_UINT16_LE (GST_BUFFER_DATA (buf) + 10); - GST_INFO_OBJECT (dec, "Found pre-skip of %u samples", dec->pre_skip); + dec->r128_gain = GST_READ_UINT16_LE (GST_BUFFER_DATA (buf) + 14); + dec->r128_gain_volume = gst_opus_dec_get_r128_volume (dec->r128_gain); + GST_INFO_OBJECT (dec, + "Found pre-skip of %u samples, R128 gain %d (volume %f)", + dec->pre_skip, dec->r128_gain, dec->r128_gain_volume); return GST_FLOW_OK; } @@ -357,6 +385,23 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer) } } + /* Apply gain */ + /* Would be better off leaving this to a volume element, as this is + a naive conversion that does too many int/float conversions. + However, we don't have control over the pipeline... + So make it optional if the user program wants to use a volume, + but do it by default so the correct volume goes out by default */ + if (dec->apply_gain && outbuf && dec->r128_gain) { + unsigned int i, nsamples = GST_BUFFER_SIZE (outbuf) / 2; + double volume = dec->r128_gain_volume; + gint16 *samples = (gint16 *) GST_BUFFER_DATA (outbuf); + GST_DEBUG_OBJECT (dec, "Applying gain: volume %f", volume); + for (i = 0; i < nsamples; ++i) { + int sample = (int) (samples[i] * volume + 0.5); + samples[i] = sample < -32768 ? -32768 : sample > 32767 ? 32767 : sample; + } + } + res = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (dec), outbuf, 1); if (res != GST_FLOW_OK) @@ -505,6 +550,9 @@ gst_opus_dec_get_property (GObject * object, guint prop_id, GValue * value, case PROP_USE_INBAND_FEC: g_value_set_boolean (value, dec->use_inband_fec); break; + case PROP_APPLY_GAIN: + g_value_set_boolean (value, dec->apply_gain); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -521,6 +569,9 @@ gst_opus_dec_set_property (GObject * object, guint prop_id, case PROP_USE_INBAND_FEC: dec->use_inband_fec = g_value_get_boolean (value); break; + case PROP_APPLY_GAIN: + dec->apply_gain = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/ext/opus/gstopusdec.h b/ext/opus/gstopusdec.h index 081e575247..b074787d7f 100644 --- a/ext/opus/gstopusdec.h +++ b/ext/opus/gstopusdec.h @@ -54,6 +54,10 @@ struct _GstOpusDec { int sample_rate; int n_channels; guint32 pre_skip; + gint16 r128_gain; + + gboolean apply_gain; + double r128_gain_volume; gboolean use_inband_fec; GstBuffer *last_buffer; From 4286414e002016e6f3837696b0dec708d59787dc Mon Sep 17 00:00:00 2001 From: Krzysztof Krakowiak Date: Wed, 23 Nov 2011 13:47:11 +0100 Subject: [PATCH 08/24] modplug: fix modules playing as mono instead of stereo replaced broken if-return logic for fixating rate and number of channels that caused that modules were always (after successful fixation of rate) played as mono (instead of stereo) by correct one with appropiate warnings. https://bugzilla.gnome.org/show_bug.cgi?id=619035 --- ext/modplug/gstmodplug.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/modplug/gstmodplug.cc b/ext/modplug/gstmodplug.cc index 6faaa0c837..75988fd759 100644 --- a/ext/modplug/gstmodplug.cc +++ b/ext/modplug/gstmodplug.cc @@ -466,10 +466,10 @@ gst_modplug_fixate (GstPad * pad, GstCaps * caps) GstStructure *structure; structure = gst_caps_get_structure (caps, 0); - if (gst_structure_fixate_field_nearest_int (structure, "rate", 44100)) - return; - if (gst_structure_fixate_field_nearest_int (structure, "channels", 2)) - return; + if (!gst_structure_fixate_field_nearest_int (structure, "rate", 44100)) + GST_WARNING_OBJECT (pad, "Failed to fixate rate to 44100"); + if (!gst_structure_fixate_field_nearest_int (structure, "channels", 2)) + GST_WARNING_OBJECT (pad, "Failed to fixate number of channels to stereo"); } static gboolean From da43e59aabfbb7e684bea27ce34734c4ee62fda1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 23 Nov 2011 16:01:35 +0000 Subject: [PATCH 09/24] smooth: fix printf format compiler warning in debug message https://bugzilla.gnome.org/show_bug.cgi?id=664631 --- gst/smooth/gstsmooth.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gst/smooth/gstsmooth.c b/gst/smooth/gstsmooth.c index 66eade1d78..2ac87d6fc0 100644 --- a/gst/smooth/gstsmooth.c +++ b/gst/smooth/gstsmooth.c @@ -188,9 +188,8 @@ gst_smooth_transform (GstBaseTransform * btrans, GstBuffer * inbuf, GstBuffer * outbuf) { GstSmooth *smooth; - guchar *idata, *odata; - gulong size; - gint lumsize, chromsize; + guint8 *idata, *odata; + guint size, lumsize, chromsize; smooth = GST_SMOOTH (btrans); idata = GST_BUFFER_DATA (inbuf); From 8b5fbcaedd42ea4f2c49193323c24bb8a462e128 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Wed, 23 Nov 2011 23:29:10 +0100 Subject: [PATCH 10/24] dtsdec: port to audiodecoder --- ext/dts/Makefile.am | 5 +- ext/dts/gstdtsdec.c | 618 ++++++++++++++++---------------------------- ext/dts/gstdtsdec.h | 20 +- 3 files changed, 236 insertions(+), 407 deletions(-) diff --git a/ext/dts/Makefile.am b/ext/dts/Makefile.am index f93e87deab..f58f149729 100644 --- a/ext/dts/Makefile.am +++ b/ext/dts/Makefile.am @@ -1,8 +1,9 @@ plugin_LTLIBRARIES = libgstdtsdec.la libgstdtsdec_la_SOURCES = gstdtsdec.c -libgstdtsdec_la_CFLAGS = $(GST_CFLAGS) $(ORC_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) -libgstdtsdec_la_LIBADD = $(DTS_LIBS) $(ORC_LIBS) $(GST_PLUGINS_BASE_LIBS) \ +libgstdtsdec_la_CFLAGS = -DGST_USE_UNSTABLE_API \ + $(GST_CFLAGS) $(ORC_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) +libgstdtsdec_la_LIBADD = $(DTS_LIBS) $(ORC_LIBS) $(GST_PLUGINS_BASE_LIBS) \ -lgstaudio-@GST_MAJORMINOR@ libgstdtsdec_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstdtsdec_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/ext/dts/gstdtsdec.c b/ext/dts/gstdtsdec.c index 2039c58ba9..2a762e9030 100644 --- a/ext/dts/gstdtsdec.c +++ b/ext/dts/gstdtsdec.c @@ -127,14 +127,20 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", "rate = (int) [ 4000, 96000 ], " "channels = (int) [ 1, 6 ]") ); -GST_BOILERPLATE (GstDtsDec, gst_dtsdec, GstElement, GST_TYPE_ELEMENT); +GST_BOILERPLATE (GstDtsDec, gst_dtsdec, GstAudioDecoder, + GST_TYPE_AUDIO_DECODER); + +static gboolean gst_dtsdec_start (GstAudioDecoder * dec); +static gboolean gst_dtsdec_stop (GstAudioDecoder * dec); +static gboolean gst_dtsdec_set_format (GstAudioDecoder * bdec, GstCaps * caps); +static gboolean gst_dtsdec_parse (GstAudioDecoder * dec, GstAdapter * adapter, + gint * offset, gint * length); +static GstFlowReturn gst_dtsdec_handle_frame (GstAudioDecoder * dec, + GstBuffer * buffer); +static GstFlowReturn gst_dtsdec_pre_push (GstAudioDecoder * bdec, + GstBuffer ** buffer); -static gboolean gst_dtsdec_sink_setcaps (GstPad * pad, GstCaps * caps); -static gboolean gst_dtsdec_sink_event (GstPad * pad, GstEvent * event); static GstFlowReturn gst_dtsdec_chain (GstPad * pad, GstBuffer * buf); -static GstFlowReturn gst_dtsdec_chain_raw (GstPad * pad, GstBuffer * buf); -static GstStateChangeReturn gst_dtsdec_change_state (GstElement * element, - GstStateChange transition); static void gst_dtsdec_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); @@ -164,16 +170,21 @@ static void gst_dtsdec_class_init (GstDtsDecClass * klass) { GObjectClass *gobject_class; - GstElementClass *gstelement_class; + GstAudioDecoderClass *gstbase_class; guint cpuflags; gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; + gstbase_class = (GstAudioDecoderClass *) klass; gobject_class->set_property = gst_dtsdec_set_property; gobject_class->get_property = gst_dtsdec_get_property; - gstelement_class->change_state = gst_dtsdec_change_state; + gstbase_class->start = GST_DEBUG_FUNCPTR (gst_dtsdec_start); + gstbase_class->stop = GST_DEBUG_FUNCPTR (gst_dtsdec_stop); + gstbase_class->set_format = GST_DEBUG_FUNCPTR (gst_dtsdec_set_format); + gstbase_class->parse = GST_DEBUG_FUNCPTR (gst_dtsdec_parse); + gstbase_class->handle_frame = GST_DEBUG_FUNCPTR (gst_dtsdec_handle_frame); + gstbase_class->pre_push = GST_DEBUG_FUNCPTR (gst_dtsdec_pre_push); /** * GstDtsDec::drc @@ -209,23 +220,104 @@ gst_dtsdec_class_init (GstDtsDecClass * klass) static void gst_dtsdec_init (GstDtsDec * dtsdec, GstDtsDecClass * g_class) { - /* create the sink and src pads */ - dtsdec->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink"); - gst_pad_set_setcaps_function (dtsdec->sinkpad, - GST_DEBUG_FUNCPTR (gst_dtsdec_sink_setcaps)); - gst_pad_set_chain_function (dtsdec->sinkpad, - GST_DEBUG_FUNCPTR (gst_dtsdec_chain)); - gst_pad_set_event_function (dtsdec->sinkpad, - GST_DEBUG_FUNCPTR (gst_dtsdec_sink_event)); - gst_element_add_pad (GST_ELEMENT (dtsdec), dtsdec->sinkpad); - - dtsdec->srcpad = gst_pad_new_from_static_template (&src_factory, "src"); - gst_element_add_pad (GST_ELEMENT (dtsdec), dtsdec->srcpad); - dtsdec->request_channels = DCA_CHANNEL; dtsdec->dynamic_range_compression = FALSE; - gst_segment_init (&dtsdec->segment, GST_FORMAT_UNDEFINED); + /* retrieve and intercept base class chain. + * Quite HACKish, but that's dvd specs for you, + * since one buffer needs to be split into 2 frames */ + dtsdec->base_chain = GST_PAD_CHAINFUNC (GST_AUDIO_DECODER_SINK_PAD (dtsdec)); + gst_pad_set_chain_function (GST_AUDIO_DECODER_SINK_PAD (dtsdec), + GST_DEBUG_FUNCPTR (gst_dtsdec_chain)); +} + +static gboolean +gst_dtsdec_start (GstAudioDecoder * dec) +{ + GstDtsDec *dts = GST_DTSDEC (dec); + GstDtsDecClass *klass; + + GST_DEBUG_OBJECT (dec, "start"); + + klass = GST_DTSDEC_CLASS (G_OBJECT_GET_CLASS (dts)); + dts->state = dca_init (klass->dts_cpuflags); + dts->samples = dca_samples (dts->state); + dts->bit_rate = -1; + dts->sample_rate = -1; + dts->stream_channels = DCA_CHANNEL; + dts->using_channels = DCA_CHANNEL; + dts->level = 1; + dts->bias = 0; + dts->flag_update = TRUE; + + /* call upon legacy upstream byte support (e.g. seeking) */ + gst_audio_decoder_set_byte_time (dec, TRUE); + + return TRUE; +} + +static gboolean +gst_dtsdec_stop (GstAudioDecoder * dec) +{ + GstDtsDec *dts = GST_DTSDEC (dec); + + GST_DEBUG_OBJECT (dec, "stop"); + + dts->samples = NULL; + if (dts->state) { + dca_free (dts->state); + dts->state = NULL; + } + if (dts->pending_tags) { + gst_tag_list_free (dts->pending_tags); + dts->pending_tags = NULL; + } + + return TRUE; +} + +static GstFlowReturn +gst_dtsdec_parse (GstAudioDecoder * bdec, GstAdapter * adapter, + gint * _offset, gint * len) +{ + GstDtsDec *dts; + guint8 *data; + gint av, size; + gint length = 0, flags, sample_rate, bit_rate, frame_length; + GstFlowReturn result = GST_FLOW_UNEXPECTED; + + dts = GST_DTSDEC (bdec); + + size = av = gst_adapter_available (adapter); + data = (guint8 *) gst_adapter_peek (adapter, av); + + /* find and read header */ + bit_rate = dts->bit_rate; + sample_rate = dts->sample_rate; + flags = 0; + while (av >= 7) { + length = dca_syncinfo (dts->state, data, &flags, + &sample_rate, &bit_rate, &frame_length); + + if (length == 0) { + /* shift window to re-find sync */ + data++; + size--; + } else if (length <= size) { + GST_LOG_OBJECT (dts, "Sync: frame size %d", length); + result = GST_FLOW_OK; + break; + } else { + GST_LOG_OBJECT (dts, "Not enough data available (needed %d had %d)", + length, size); + break; + } + } + + *_offset = av - size; + *len = length; + + return result; } static gint @@ -327,105 +419,6 @@ gst_dtsdec_channels (uint32_t flags, GstAudioChannelPosition ** pos) return chans; } -static void -clear_queued (GstDtsDec * dec) -{ - g_list_foreach (dec->queued, (GFunc) gst_mini_object_unref, NULL); - g_list_free (dec->queued); - dec->queued = NULL; -} - -static GstFlowReturn -flush_queued (GstDtsDec * dec) -{ - GstFlowReturn ret = GST_FLOW_OK; - - while (dec->queued) { - GstBuffer *buf = GST_BUFFER_CAST (dec->queued->data); - - GST_LOG_OBJECT (dec, "pushing buffer %p, timestamp %" - GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, buf, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); - - /* iterate ouput queue an push downstream */ - ret = gst_pad_push (dec->srcpad, buf); - - dec->queued = g_list_delete_link (dec->queued, dec->queued); - } - return ret; -} - -static GstFlowReturn -gst_dtsdec_drain (GstDtsDec * dec) -{ - GstFlowReturn ret = GST_FLOW_OK; - - if (dec->segment.rate < 0.0) { - /* if we have some queued frames for reverse playback, flush - * them now */ - ret = flush_queued (dec); - } - return ret; -} - -static GstFlowReturn -gst_dtsdec_push (GstDtsDec * dtsdec, - GstPad * srcpad, int flags, sample_t * samples, GstClockTime timestamp) -{ - GstBuffer *buf; - int chans, n, c; - GstFlowReturn result; - - flags &= (DCA_CHANNEL_MASK | DCA_LFE); - chans = gst_dtsdec_channels (flags, NULL); - if (!chans) { - GST_ELEMENT_ERROR (GST_ELEMENT (dtsdec), STREAM, DECODE, (NULL), - ("Invalid channel flags: %d", flags)); - return GST_FLOW_ERROR; - } - - result = - gst_pad_alloc_buffer_and_set_caps (srcpad, 0, - 256 * chans * (SAMPLE_WIDTH / 8), GST_PAD_CAPS (srcpad), &buf); - if (result != GST_FLOW_OK) - return result; - - for (n = 0; n < 256; n++) { - for (c = 0; c < chans; c++) { - ((sample_t *) GST_BUFFER_DATA (buf))[n * chans + c] = - samples[c * 256 + n]; - } - } - GST_BUFFER_TIMESTAMP (buf) = timestamp; - GST_BUFFER_DURATION (buf) = 256 * GST_SECOND / dtsdec->sample_rate; - - result = GST_FLOW_OK; - if ((buf = gst_audio_buffer_clip (buf, &dtsdec->segment, - dtsdec->sample_rate, (SAMPLE_WIDTH / 8) * chans))) { - /* set discont when needed */ - if (dtsdec->discont) { - GST_LOG_OBJECT (dtsdec, "marking DISCONT"); - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); - dtsdec->discont = FALSE; - } - - if (dtsdec->segment.rate > 0.0) { - GST_DEBUG_OBJECT (dtsdec, - "Pushing buffer with ts %" GST_TIME_FORMAT " duration %" - GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); - - result = gst_pad_push (srcpad, buf); - } else { - /* reverse playback, queue frame till later when we get a discont. */ - GST_DEBUG_OBJECT (dtsdec, "queued frame"); - dtsdec->queued = g_list_prepend (dtsdec->queued, buf); - } - } - return result; -} - static gboolean gst_dtsdec_renegotiate (GstDtsDec * dts) { @@ -446,7 +439,7 @@ gst_dtsdec_renegotiate (GstDtsDec * dts) gst_audio_set_channel_positions (gst_caps_get_structure (caps, 0), pos); g_free (pos); - if (!gst_pad_set_caps (dts->srcpad, caps)) + if (!gst_pad_set_caps (GST_AUDIO_DECODER_SRC_PAD (dts), caps)) goto done; result = TRUE; @@ -458,100 +451,70 @@ done: return result; } -static gboolean -gst_dtsdec_sink_event (GstPad * pad, GstEvent * event) -{ - GstDtsDec *dtsdec = GST_DTSDEC (gst_pad_get_parent (pad)); - gboolean ret = FALSE; - - GST_LOG_OBJECT (dtsdec, "%s event", GST_EVENT_TYPE_NAME (event)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT:{ - GstFormat format; - gboolean update; - gint64 start, end, pos; - gdouble rate; - - gst_event_parse_new_segment (event, &update, &rate, &format, &start, &end, - &pos); - - /* drain queued buffers before activating the segment so that we can clip - * against the old segment first */ - gst_dtsdec_drain (dtsdec); - - if (format != GST_FORMAT_TIME || !GST_CLOCK_TIME_IS_VALID (start)) { - GST_WARNING ("No time in newsegment event %p (format is %s)", - event, gst_format_get_name (format)); - gst_event_unref (event); - dtsdec->sent_segment = FALSE; - /* set some dummy values, FIXME: do proper conversion */ - dtsdec->time = start = pos = 0; - format = GST_FORMAT_TIME; - end = -1; - } else { - dtsdec->time = start; - dtsdec->sent_segment = TRUE; - ret = gst_pad_push_event (dtsdec->srcpad, event); - } - - gst_segment_set_newsegment (&dtsdec->segment, update, rate, format, start, - end, pos); - break; - } - case GST_EVENT_TAG: - ret = gst_pad_push_event (dtsdec->srcpad, event); - break; - case GST_EVENT_EOS: - gst_dtsdec_drain (dtsdec); - ret = gst_pad_push_event (dtsdec->srcpad, event); - break; - case GST_EVENT_FLUSH_START: - ret = gst_pad_push_event (dtsdec->srcpad, event); - break; - case GST_EVENT_FLUSH_STOP: - if (dtsdec->cache) { - gst_buffer_unref (dtsdec->cache); - dtsdec->cache = NULL; - } - clear_queued (dtsdec); - gst_segment_init (&dtsdec->segment, GST_FORMAT_UNDEFINED); - ret = gst_pad_push_event (dtsdec->srcpad, event); - break; - default: - ret = gst_pad_push_event (dtsdec->srcpad, event); - break; - } - - gst_object_unref (dtsdec); - return ret; -} - static void gst_dtsdec_update_streaminfo (GstDtsDec * dts) { GstTagList *taglist; - taglist = gst_tag_list_new (); - - gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, - GST_TAG_AUDIO_CODEC, "DTS DCA", NULL); - if (dts->bit_rate > 3) { + taglist = gst_tag_list_new (); /* 1 => open bitrate, 2 => variable bitrate, 3 => lossless */ gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, GST_TAG_BITRATE, (guint) dts->bit_rate, NULL); - } - gst_element_found_tags_for_pad (GST_ELEMENT (dts), dts->srcpad, taglist); + if (dts->pending_tags) { + gst_tag_list_free (dts->pending_tags); + dts->pending_tags = NULL; + } + + dts->pending_tags = taglist; + } } static GstFlowReturn -gst_dtsdec_handle_frame (GstDtsDec * dts, guint8 * data, - guint length, gint flags, gint sample_rate, gint bit_rate) +gst_dtsdec_pre_push (GstAudioDecoder * bdec, GstBuffer ** buffer) { + GstDtsDec *dts = GST_DTSDEC (bdec); + + if (G_UNLIKELY (dts->pending_tags)) { + gst_element_found_tags_for_pad (GST_ELEMENT (dts), + GST_AUDIO_DECODER_SRC_PAD (dts), dts->pending_tags); + dts->pending_tags = NULL; + } + + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_dtsdec_handle_frame (GstAudioDecoder * bdec, GstBuffer * buffer) +{ + GstDtsDec *dts; gint channels, i, num_blocks; gboolean need_renegotiation = FALSE; + guint8 *data; + gint size, chans; + gint length = 0, flags, sample_rate, bit_rate, frame_length; + GstFlowReturn result = GST_FLOW_UNEXPECTED; + GstBuffer *outbuf; + + dts = GST_DTSDEC (bdec); + + /* parsed stuff already, so this should work out fine */ + data = GST_BUFFER_DATA (buffer); + size = GST_BUFFER_SIZE (buffer); + g_assert (size >= 7); + + bit_rate = dts->bit_rate; + sample_rate = dts->sample_rate; + flags = 0; + length = dca_syncinfo (dts->state, data, &flags, &sample_rate, &bit_rate, + &frame_length); + g_assert (length == size); + + if (flags != dts->prev_flags) { + dts->prev_flags = flags; + dts->flag_update = TRUE; + } /* go over stream properties, renegotiate or update streaminfo if needed */ if (dts->sample_rate != sample_rate) { @@ -581,7 +544,7 @@ gst_dtsdec_handle_frame (GstDtsDec * dts, guint8 * data, dts->flag_update = FALSE; - caps = gst_pad_get_allowed_caps (dts->srcpad); + caps = gst_pad_get_allowed_caps (GST_AUDIO_DECODER_SRC_PAD (dts)); if (caps && gst_caps_get_size (caps) > 0) { GstCaps *copy = gst_caps_copy_nth (caps, 0); GstStructure *structure = gst_caps_get_structure (copy, 0); @@ -618,14 +581,16 @@ gst_dtsdec_handle_frame (GstDtsDec * dts, guint8 * data, } else { flags = dts->using_channels; } + /* process */ flags |= DCA_ADJUST_LEVEL; dts->level = 1; if (dca_frame (dts->state, data, &flags, &dts->level, dts->bias)) { - GST_WARNING_OBJECT (dts, "dts_frame error"); - dts->discont = TRUE; - return GST_FLOW_OK; + GST_AUDIO_DECODER_ERROR (dts, 1, STREAM, DECODE, (NULL), + ("dts_frame error"), result); + goto exit; } + channels = flags & (DCA_CHANNEL_MASK | DCA_LFE); if (dts->using_channels != channels) { need_renegotiation = TRUE; @@ -636,42 +601,71 @@ gst_dtsdec_handle_frame (GstDtsDec * dts, guint8 * data, if (need_renegotiation) { GST_DEBUG ("dtsdec: sample_rate:%d stream_chans:0x%x using_chans:0x%x", dts->sample_rate, dts->stream_channels, dts->using_channels); - if (!gst_dtsdec_renegotiate (dts)) { - GST_ELEMENT_ERROR (dts, CORE, NEGOTIATION, (NULL), (NULL)); - return GST_FLOW_ERROR; - } + if (!gst_dtsdec_renegotiate (dts)) + goto failed_negotiation; } if (dts->dynamic_range_compression == FALSE) { dca_dynrng (dts->state, NULL, NULL); } + flags &= (DCA_CHANNEL_MASK | DCA_LFE); + chans = gst_dtsdec_channels (flags, NULL); + if (!chans) + goto invalid_flags; + /* handle decoded data, one block is 256 samples */ num_blocks = dca_blocks_num (dts->state); + result = + gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_DECODER_SRC_PAD (dts), 0, + 256 * chans * (SAMPLE_WIDTH / 8) * num_blocks, + GST_PAD_CAPS (GST_AUDIO_DECODER_SRC_PAD (dts)), &outbuf); + if (result != GST_FLOW_OK) + goto exit; + + data = GST_BUFFER_DATA (outbuf); for (i = 0; i < num_blocks; i++) { if (dca_block (dts->state)) { - /* Ignore errors, but mark a discont */ - GST_WARNING_OBJECT (dts, "dts_block error %d", i); - dts->discont = TRUE; + /* also marks discont */ + GST_AUDIO_DECODER_ERROR (dts, 1, STREAM, DECODE, (NULL), + ("error decoding block %d", i), result); + if (result != GST_FLOW_OK) + goto exit; } else { - GstFlowReturn ret; + gint n, c; - /* push on */ - ret = gst_dtsdec_push (dts, dts->srcpad, dts->using_channels, - dts->samples, dts->time); - if (ret != GST_FLOW_OK) - return ret; + for (n = 0; n < 256; n++) { + for (c = 0; c < chans; c++) { + ((sample_t *) data)[n * chans + c] = dts->samples[c * 256 + n]; + } + } } - dts->time += GST_SECOND * 256 / dts->sample_rate; + data += 256 * chans * (SAMPLE_WIDTH / 8); } - return GST_FLOW_OK; + result = gst_audio_decoder_finish_frame (bdec, outbuf, 1); + +exit: + return result; + + /* ERRORS */ +failed_negotiation: + { + GST_ELEMENT_ERROR (dts, CORE, NEGOTIATION, (NULL), (NULL)); + return GST_FLOW_ERROR; + } +invalid_flags: + { + GST_ELEMENT_ERROR (GST_ELEMENT (dts), STREAM, DECODE, (NULL), + ("Invalid channel flags: %d", flags)); + return GST_FLOW_ERROR; + } } static gboolean -gst_dtsdec_sink_setcaps (GstPad * pad, GstCaps * caps) +gst_dtsdec_set_format (GstAudioDecoder * bdec, GstCaps * caps) { - GstDtsDec *dts = GST_DTSDEC (gst_pad_get_parent (pad)); + GstDtsDec *dts = GST_DTSDEC (bdec); GstStructure *structure; structure = gst_caps_get_structure (caps, 0); @@ -681,8 +675,6 @@ gst_dtsdec_sink_setcaps (GstPad * pad, GstCaps * caps) else dts->dvdmode = FALSE; - gst_object_unref (dts); - return TRUE; } @@ -693,17 +685,6 @@ gst_dtsdec_chain (GstPad * pad, GstBuffer * buf) GstDtsDec *dts = GST_DTSDEC (GST_PAD_PARENT (pad)); gint first_access; - if (GST_BUFFER_IS_DISCONT (buf)) { - GST_LOG_OBJECT (dts, "received DISCONT"); - gst_dtsdec_drain (dts); - /* clear cache on discont and mark a discont in the element */ - if (dts->cache) { - gst_buffer_unref (dts->cache); - dts->cache = NULL; - } - dts->discont = TRUE; - } - if (dts->dvdmode) { gint size = GST_BUFFER_SIZE (buf); guint8 *data = GST_BUFFER_DATA (buf); @@ -726,33 +707,38 @@ gst_dtsdec_chain (GstPad * pad, GstBuffer * buf) goto bad_first_access_parameter; subbuf = gst_buffer_create_sub (buf, offset, len); + gst_buffer_copy_metadata (subbuf, buf, GST_BUFFER_COPY_ALL); GST_BUFFER_TIMESTAMP (subbuf) = GST_CLOCK_TIME_NONE; - ret = gst_dtsdec_chain_raw (pad, subbuf); - if (ret != GST_FLOW_OK) + ret = dts->base_chain (pad, subbuf); + if (ret != GST_FLOW_OK) { + gst_buffer_unref (buf); goto done; + } offset += len; len = size - offset; if (len > 0) { subbuf = gst_buffer_create_sub (buf, offset, len); + gst_buffer_copy_metadata (subbuf, buf, GST_BUFFER_COPY_ALL); GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf); - ret = gst_dtsdec_chain_raw (pad, subbuf); + ret = dts->base_chain (pad, subbuf); } + gst_buffer_unref (buf); } else { /* first_access = 0 or 1, so if there's a timestamp it applies to the first byte */ subbuf = gst_buffer_create_sub (buf, offset, size - offset); + gst_buffer_copy_metadata (subbuf, buf, GST_BUFFER_COPY_ALL); GST_BUFFER_TIMESTAMP (subbuf) = GST_BUFFER_TIMESTAMP (buf); - ret = gst_dtsdec_chain_raw (pad, subbuf); + ret = dts->base_chain (pad, subbuf); + gst_buffer_unref (buf); } } else { - gst_buffer_ref (buf); - ret = gst_dtsdec_chain_raw (pad, buf); + ret = dts->base_chain (pad, buf); } done: - gst_buffer_unref (buf); return ret; /* ERRORS */ @@ -772,154 +758,6 @@ bad_first_access_parameter: } } -static GstFlowReturn -gst_dtsdec_chain_raw (GstPad * pad, GstBuffer * buf) -{ - GstDtsDec *dts; - guint8 *data; - gint size; - gint length = 0, flags, sample_rate, bit_rate, frame_length; - GstFlowReturn result = GST_FLOW_OK; - - dts = GST_DTSDEC (GST_PAD_PARENT (pad)); - - if (!dts->sent_segment) { - GstSegment segment; - - /* Create a basic segment. Usually, we'll get a new-segment sent by - * another element that will know more information (a demuxer). If we're - * just looking at a raw AC3 stream, we won't - so we need to send one - * here, but we don't know much info, so just send a minimal TIME - * new-segment event - */ - gst_segment_init (&segment, GST_FORMAT_TIME); - gst_pad_push_event (dts->srcpad, gst_event_new_new_segment (FALSE, - segment.rate, segment.format, segment.start, - segment.duration, segment.start)); - dts->sent_segment = TRUE; - } - - /* merge with cache, if any. Also make sure timestamps match */ - if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { - dts->time = GST_BUFFER_TIMESTAMP (buf); - GST_DEBUG_OBJECT (dts, - "Received buffer with ts %" GST_TIME_FORMAT " duration %" - GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), - GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); - } - - if (dts->cache) { - buf = gst_buffer_join (dts->cache, buf); - dts->cache = NULL; - } - data = GST_BUFFER_DATA (buf); - size = GST_BUFFER_SIZE (buf); - - /* find and read header */ - bit_rate = dts->bit_rate; - sample_rate = dts->sample_rate; - flags = 0; - while (size >= 7) { - length = dca_syncinfo (dts->state, data, &flags, - &sample_rate, &bit_rate, &frame_length); - - if (length == 0) { - /* shift window to re-find sync */ - data++; - size--; - } else if (length <= size) { - GST_DEBUG ("Sync: frame size %d", length); - - if (flags != dts->prev_flags) - dts->flag_update = TRUE; - dts->prev_flags = flags; - - result = gst_dtsdec_handle_frame (dts, data, length, - flags, sample_rate, bit_rate); - if (result != GST_FLOW_OK) { - size = 0; - break; - } - size -= length; - data += length; - } else { - GST_LOG ("Not enough data available (needed %d had %d)", length, size); - break; - } - } - - /* keep cache */ - if (length == 0) { - GST_LOG ("No sync found"); - } - - if (size > 0) { - dts->cache = gst_buffer_create_sub (buf, - GST_BUFFER_SIZE (buf) - size, size); - } - - gst_buffer_unref (buf); - - return result; -} - -static GstStateChangeReturn -gst_dtsdec_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstDtsDec *dts = GST_DTSDEC (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY:{ - GstDtsDecClass *klass; - - klass = GST_DTSDEC_CLASS (G_OBJECT_GET_CLASS (dts)); - dts->state = dca_init (klass->dts_cpuflags); - break; - } - case GST_STATE_CHANGE_READY_TO_PAUSED: - dts->samples = dca_samples (dts->state); - dts->bit_rate = -1; - dts->sample_rate = -1; - dts->stream_channels = DCA_CHANNEL; - dts->using_channels = DCA_CHANNEL; - dts->level = 1; - dts->bias = 0; - dts->time = 0; - dts->sent_segment = FALSE; - dts->flag_update = TRUE; - gst_segment_init (&dts->segment, GST_FORMAT_UNDEFINED); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - dts->samples = NULL; - if (dts->cache) { - gst_buffer_unref (dts->cache); - dts->cache = NULL; - } - clear_queued (dts); - break; - case GST_STATE_CHANGE_READY_TO_NULL: - dca_free (dts->state); - dts->state = NULL; - break; - default: - break; - } - - return ret; -} - static void gst_dtsdec_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) diff --git a/ext/dts/gstdtsdec.h b/ext/dts/gstdtsdec.h index a7c8f71802..be6005a0a6 100644 --- a/ext/dts/gstdtsdec.h +++ b/ext/dts/gstdtsdec.h @@ -22,6 +22,7 @@ #define __GST_DTSDEC_H__ #include +#include G_BEGIN_DECLS @@ -40,16 +41,11 @@ typedef struct _GstDtsDec GstDtsDec; typedef struct _GstDtsDecClass GstDtsDecClass; struct _GstDtsDec { - GstElement element; + GstAudioDecoder element; - /* pads */ - GstPad *sinkpad; - GstPad *srcpad; - GstSegment segment; + GstPadChainFunction base_chain; gboolean dvdmode; - gboolean sent_segment; - gboolean discont; gboolean flag_update; gboolean prev_flags; @@ -71,17 +67,11 @@ struct _GstDtsDec { dts_state_t *state; #endif - - /* Data left over from the previous buffer */ - GstBuffer *cache; - GstClockTime time; - - /* reverse playback */ - GList *queued; + GstTagList *pending_tags; }; struct _GstDtsDecClass { - GstElementClass parent_class; + GstAudioDecoderClass parent_class; guint32 dts_cpuflags; }; From 9680108d77d523f387a0a8e0cddae80db982d4a0 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Wed, 23 Nov 2011 23:30:00 +0100 Subject: [PATCH 11/24] faac: do not leak buffer when no encoded data yet or encoding error --- ext/faac/gstfaac.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ext/faac/gstfaac.c b/ext/faac/gstfaac.c index eb132d3b4c..7ab22446dc 100644 --- a/ext/faac/gstfaac.c +++ b/ext/faac/gstfaac.c @@ -666,9 +666,11 @@ gst_faac_handle_frame (GstAudioEncoder * enc, GstBuffer * in_buf) goto encode_failed; GST_LOG_OBJECT (faac, "encoder return: %d", ret_size); - if (ret_size > 0) { + if (G_LIKELY (ret_size > 0)) { GST_BUFFER_SIZE (out_buf) = ret_size; ret = gst_audio_encoder_finish_frame (enc, out_buf, faac->samples); + } else { + gst_buffer_unref (out_buf); } return ret; @@ -676,6 +678,7 @@ gst_faac_handle_frame (GstAudioEncoder * enc, GstBuffer * in_buf) /* ERRORS */ encode_failed: { + gst_buffer_unref (out_buf); GST_ELEMENT_ERROR (faac, LIBRARY, ENCODE, (NULL), (NULL)); return GST_FLOW_ERROR; } From e7cd0869709a75bd6954128169498c038526e922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 24 Nov 2011 10:04:30 +0100 Subject: [PATCH 12/24] mpeg4videoparse: Implement ::get_sink_caps vfunc to propagate downstream caps constraints upstream --- gst/mpeg4videoparse/mpeg4videoparse.c | 35 +++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/gst/mpeg4videoparse/mpeg4videoparse.c b/gst/mpeg4videoparse/mpeg4videoparse.c index 4f3c7e3c1d..6a2c075708 100644 --- a/gst/mpeg4videoparse/mpeg4videoparse.c +++ b/gst/mpeg4videoparse/mpeg4videoparse.c @@ -72,6 +72,7 @@ static GstFlowReturn gst_mpeg4vparse_parse_frame (GstBaseParse * parse, static GstFlowReturn gst_mpeg4vparse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame); static gboolean gst_mpeg4vparse_set_caps (GstBaseParse * parse, GstCaps * caps); +static GstCaps *gst_mpeg4vparse_get_caps (GstBaseParse * parse); static void gst_mpeg4vparse_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); @@ -164,6 +165,7 @@ gst_mpeg4vparse_class_init (GstMpeg4VParseClass * klass) parse_class->pre_push_frame = GST_DEBUG_FUNCPTR (gst_mpeg4vparse_pre_push_frame); parse_class->set_sink_caps = GST_DEBUG_FUNCPTR (gst_mpeg4vparse_set_caps); + parse_class->get_sink_caps = GST_DEBUG_FUNCPTR (gst_mpeg4vparse_get_caps); } static void @@ -604,6 +606,39 @@ gst_mpeg4vparse_set_caps (GstBaseParse * parse, GstCaps * caps) return TRUE; } +static GstCaps * +gst_mpeg4vparse_get_caps (GstBaseParse * parse) +{ + GstCaps *peercaps; + GstCaps *res; + + peercaps = gst_pad_get_allowed_caps (GST_BASE_PARSE_SRC_PAD (parse)); + if (peercaps) { + guint i, n; + + /* Remove the parsed field */ + peercaps = gst_caps_make_writable (peercaps); + n = gst_caps_get_size (peercaps); + for (i = 0; i < n; i++) { + GstStructure *s = gst_caps_get_structure (peercaps, i); + + gst_structure_remove_field (s, "parsed"); + } + + res = + gst_caps_intersect_full (peercaps, + gst_pad_get_pad_template_caps (GST_BASE_PARSE_SRC_PAD (parse)), + GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (peercaps); + } else { + res = + gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_PARSE_SRC_PAD + (parse))); + } + + return res; +} + static gboolean plugin_init (GstPlugin * plugin) { From b10c1f277f2bab2058d398f60f392682083db541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 24 Nov 2011 10:08:27 +0100 Subject: [PATCH 13/24] diracparse: Implement ::get_sink_caps vfunc to propagate downstream caps constraints upstream --- gst/videoparsers/gstdiracparse.c | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/gst/videoparsers/gstdiracparse.c b/gst/videoparsers/gstdiracparse.c index ef99b7ae90..205e6144a3 100644 --- a/gst/videoparsers/gstdiracparse.c +++ b/gst/videoparsers/gstdiracparse.c @@ -54,6 +54,7 @@ static gboolean gst_dirac_parse_start (GstBaseParse * parse); static gboolean gst_dirac_parse_stop (GstBaseParse * parse); static gboolean gst_dirac_parse_set_sink_caps (GstBaseParse * parse, GstCaps * caps); +static GstCaps *gst_dirac_parse_get_sink_caps (GstBaseParse * parse); static gboolean gst_dirac_parse_check_valid_frame (GstBaseParse * parse, GstBaseParseFrame * frame, guint * framesize, gint * skipsize); static GstFlowReturn gst_dirac_parse_parse_frame (GstBaseParse * parse, @@ -127,6 +128,8 @@ gst_dirac_parse_class_init (GstDiracParseClass * klass) base_parse_class->stop = GST_DEBUG_FUNCPTR (gst_dirac_parse_stop); base_parse_class->set_sink_caps = GST_DEBUG_FUNCPTR (gst_dirac_parse_set_sink_caps); + base_parse_class->get_sink_caps = + GST_DEBUG_FUNCPTR (gst_dirac_parse_get_sink_caps); base_parse_class->check_valid_frame = GST_DEBUG_FUNCPTR (gst_dirac_parse_check_valid_frame); base_parse_class->parse_frame = @@ -378,3 +381,35 @@ gst_dirac_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame) return GST_FLOW_OK; } + +static GstCaps * +gst_dirac_parse_get_sink_caps (GstBaseParse * parse) +{ + GstCaps *peercaps; + GstCaps *res; + + peercaps = gst_pad_get_allowed_caps (GST_BASE_PARSE_SRC_PAD (parse)); + if (peercaps) { + guint i, n; + + /* Remove the parsed field */ + peercaps = gst_caps_make_writable (peercaps); + n = gst_caps_get_size (peercaps); + for (i = 0; i < n; i++) { + GstStructure *s = gst_caps_get_structure (peercaps, i); + gst_structure_remove_field (s, "parsed"); + } + + res = + gst_caps_intersect_full (peercaps, + gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse)), + GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (peercaps); + } else { + res = + gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD + (parse))); + } + + return res; +} From 61fad46dca27291f59951213625299863b68a722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 24 Nov 2011 10:09:59 +0100 Subject: [PATCH 14/24] h263parse: Implement ::get_sink_caps vfunc to propagate downstream caps constraints upstream --- gst/videoparsers/gsth263parse.c | 34 +++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/gst/videoparsers/gsth263parse.c b/gst/videoparsers/gsth263parse.c index 4a5633f3bc..e13a946054 100644 --- a/gst/videoparsers/gsth263parse.c +++ b/gst/videoparsers/gsth263parse.c @@ -58,6 +58,7 @@ static gboolean gst_h263_parse_check_valid_frame (GstBaseParse * parse, GstBaseParseFrame * frame, guint * framesize, gint * skipsize); static GstFlowReturn gst_h263_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame); +static GstCaps *gst_h263_parse_get_sink_caps (GstBaseParse * parse); static void gst_h263_parse_base_init (gpointer g_class) @@ -89,6 +90,7 @@ gst_h263_parse_class_init (GstH263ParseClass * klass) parse_class->check_valid_frame = GST_DEBUG_FUNCPTR (gst_h263_parse_check_valid_frame); parse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_h263_parse_parse_frame); + parse_class->get_sink_caps = GST_DEBUG_FUNCPTR (gst_h263_parse_get_sink_caps); } static void @@ -359,3 +361,35 @@ out: return res; } + +static GstCaps * +gst_h263_parse_get_sink_caps (GstBaseParse * parse) +{ + GstCaps *peercaps; + GstCaps *res; + + peercaps = gst_pad_get_allowed_caps (GST_BASE_PARSE_SRC_PAD (parse)); + if (peercaps) { + guint i, n; + + /* Remove parsed field */ + peercaps = gst_caps_make_writable (peercaps); + n = gst_caps_get_size (peercaps); + for (i = 0; i < n; i++) { + GstStructure *s = gst_caps_get_structure (peercaps, i); + gst_structure_remove_field (s, "parsed"); + } + + res = + gst_caps_intersect_full (peercaps, + gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse)), + GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (peercaps); + } else { + res = + gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD + (parse))); + } + + return res; +} From dc2c61faf5ef285fd82faa8bfbb553a5c895421d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 24 Nov 2011 10:14:06 +0100 Subject: [PATCH 15/24] mpegvideoparse: Implement ::get_sink_caps vfunc to propagate downstream caps constraints upstream --- gst/videoparsers/gstmpegvideoparse.c | 34 ++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/gst/videoparsers/gstmpegvideoparse.c b/gst/videoparsers/gstmpegvideoparse.c index 66a8929f77..ca392a70db 100644 --- a/gst/videoparsers/gstmpegvideoparse.c +++ b/gst/videoparsers/gstmpegvideoparse.c @@ -71,6 +71,7 @@ static gboolean gst_mpegv_parse_check_valid_frame (GstBaseParse * parse, static GstFlowReturn gst_mpegv_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame); static gboolean gst_mpegv_parse_set_caps (GstBaseParse * parse, GstCaps * caps); +static GstCaps *gst_mpegv_parse_get_caps (GstBaseParse * parse); static GstFlowReturn gst_mpegv_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame); @@ -166,6 +167,7 @@ gst_mpegv_parse_class_init (GstMpegvParseClass * klass) GST_DEBUG_FUNCPTR (gst_mpegv_parse_check_valid_frame); parse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_mpegv_parse_parse_frame); parse_class->set_sink_caps = GST_DEBUG_FUNCPTR (gst_mpegv_parse_set_caps); + parse_class->get_sink_caps = GST_DEBUG_FUNCPTR (gst_mpegv_parse_get_caps); parse_class->pre_push_frame = GST_DEBUG_FUNCPTR (gst_mpegv_parse_pre_push_frame); } @@ -762,3 +764,35 @@ gst_mpegv_parse_set_caps (GstBaseParse * parse, GstCaps * caps) /* let's not interfere and accept regardless of config parsing success */ return TRUE; } + +static GstCaps * +gst_mpegv_parse_get_caps (GstBaseParse * parse) +{ + GstCaps *peercaps; + GstCaps *res; + + peercaps = gst_pad_get_allowed_caps (GST_BASE_PARSE_SRC_PAD (parse)); + if (peercaps) { + guint i, n; + + /* Remove the parsed field */ + peercaps = gst_caps_make_writable (peercaps); + n = gst_caps_get_size (peercaps); + for (i = 0; i < n; i++) { + GstStructure *s = gst_caps_get_structure (peercaps, i); + gst_structure_remove_field (s, "parsed"); + } + + res = + gst_caps_intersect_full (peercaps, + gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse)), + GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (peercaps); + } else { + res = + gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD + (parse))); + } + + return res; +} From ca6ae54d5f812a3c81c5e89971f465f0d56454dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 24 Nov 2011 10:26:25 +0100 Subject: [PATCH 16/24] mpeg4videoparse: Use the sinkpad template caps as a fallback, not the srcpad ones --- gst/mpeg4videoparse/mpeg4videoparse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst/mpeg4videoparse/mpeg4videoparse.c b/gst/mpeg4videoparse/mpeg4videoparse.c index 6a2c075708..3b056b3c17 100644 --- a/gst/mpeg4videoparse/mpeg4videoparse.c +++ b/gst/mpeg4videoparse/mpeg4videoparse.c @@ -632,7 +632,7 @@ gst_mpeg4vparse_get_caps (GstBaseParse * parse) gst_caps_unref (peercaps); } else { res = - gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_PARSE_SRC_PAD + gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse))); } From 1d0f770545fe5ba9ab68d21b22b64ddfc5f11d05 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Wed, 2 Nov 2011 13:25:56 +0000 Subject: [PATCH 17/24] colorspace: fix width/height mismatches https://bugzilla.gnome.org/show_bug.cgi?id=663238 --- gst/colorspace/colorspace.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gst/colorspace/colorspace.c b/gst/colorspace/colorspace.c index 118008ed0a..15b6caf418 100644 --- a/gst/colorspace/colorspace.c +++ b/gst/colorspace/colorspace.c @@ -1956,7 +1956,7 @@ convert_YUY2_I420 (ColorspaceConvert * convert, guint8 * dest, } /* now handle last line */ - if (convert->width & 1) { + if (convert->height & 1) { getline_YUY2 (convert, convert->tmpline, src, convert->height - 1); putline_I420 (convert, dest, convert->tmpline, convert->height - 1); } @@ -1969,10 +1969,10 @@ convert_YUY2_AYUV (ColorspaceConvert * convert, guint8 * dest, cogorc_convert_YUY2_AYUV (FRAME_GET_LINE (dest, 0, 0), convert->dest_stride[0], FRAME_GET_LINE (src, 0, 0), convert->src_stride[0], (convert->width + 1) / 2, - convert->width & 1 ? convert->height - 1 : convert->height); + convert->height & 1 ? convert->height - 1 : convert->height); /* now handle last line */ - if (convert->width & 1) { + if (convert->height & 1) { getline_YUY2 (convert, convert->tmpline, src, convert->height - 1); putline_AYUV (convert, dest, convert->tmpline, convert->height - 1); } @@ -2030,10 +2030,10 @@ convert_UYVY_AYUV (ColorspaceConvert * convert, guint8 * dest, cogorc_convert_UYVY_AYUV (FRAME_GET_LINE (dest, 0, 0), convert->dest_stride[0], FRAME_GET_LINE (src, 0, 0), convert->src_stride[0], (convert->width + 1) / 2, - convert->width & 1 ? convert->height - 1 : convert->height); + convert->height & 1 ? convert->height - 1 : convert->height); /* now handle last line */ - if (convert->width & 1) { + if (convert->height & 1) { getline_UYVY (convert, convert->tmpline, src, convert->height - 1); putline_AYUV (convert, dest, convert->tmpline, convert->height - 1); } @@ -2110,7 +2110,7 @@ convert_AYUV_Y42B (ColorspaceConvert * convert, guint8 * dest, convert->dest_stride[1], FRAME_GET_LINE (dest, 2, 0), convert->dest_stride[2], FRAME_GET_LINE (src, 0, 0), convert->src_stride[0], (convert->width + 1) / 2, - convert->width & 1 ? convert->height - 1 : convert->height); + convert->height & 1 ? convert->height - 1 : convert->height); /* now handle last line */ if (convert->height & 1) { From f1477522deb8dfa8f568d2065de68d96573b3ca5 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Wed, 23 Nov 2011 16:36:54 +0000 Subject: [PATCH 18/24] opusenc: remove useless setup field --- ext/opus/gstopusenc.c | 4 ---- ext/opus/gstopusenc.h | 1 - 2 files changed, 5 deletions(-) diff --git a/ext/opus/gstopusenc.c b/ext/opus/gstopusenc.c index 29b9faf756..71e19b045a 100644 --- a/ext/opus/gstopusenc.c +++ b/ext/opus/gstopusenc.c @@ -458,8 +458,6 @@ gst_opus_enc_setup (GstOpusEnc * enc) GST_DEBUG_OBJECT (enc, "setup"); - enc->setup = FALSE; - enc->state = opus_encoder_create (enc->sample_rate, enc->n_channels, enc->audio_or_voip ? OPUS_APPLICATION_AUDIO : OPUS_APPLICATION_VOIP, &error); @@ -479,8 +477,6 @@ gst_opus_enc_setup (GstOpusEnc * enc) GST_LOG_OBJECT (enc, "we have frame size %d", enc->frame_size); - enc->setup = TRUE; - return TRUE; encoder_creation_failed: diff --git a/ext/opus/gstopusenc.h b/ext/opus/gstopusenc.h index 772f6f4cc7..58c617c5a1 100644 --- a/ext/opus/gstopusenc.h +++ b/ext/opus/gstopusenc.h @@ -72,7 +72,6 @@ struct _GstOpusEnc { gint n_channels; gint sample_rate; - gboolean setup; gboolean header_sent; GSList *headers; From 745cc8d4e463eab33a89f4e7a3e18d00645ea370 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Wed, 23 Nov 2011 17:32:03 +0000 Subject: [PATCH 19/24] opusdec: shuffle supported sample rates to favor 48000 --- ext/opus/gstopusdec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/opus/gstopusdec.c b/ext/opus/gstopusdec.c index e85a6b7471..7ac2bda279 100644 --- a/ext/opus/gstopusdec.c +++ b/ext/opus/gstopusdec.c @@ -55,7 +55,7 @@ GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS ("audio/x-raw-int, " - "rate = (int) { 8000, 12000, 16000, 24000, 48000 }, " + "rate = (int) { 48000, 24000, 16000, 12000, 8000 }, " "channels = (int) [ 1, 2 ], " "endianness = (int) BYTE_ORDER, " "signed = (boolean) true, " "width = (int) 16, " "depth = (int) 16") From 5da03cd2a4ea2666e7b810f4864322a1f5f5cafe Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Wed, 23 Nov 2011 17:49:58 +0000 Subject: [PATCH 20/24] opus: switch to multistream API It's very similar to the basic API, and is a superset ot it, which will allow encoding and decoding more than 2 channels. --- ext/opus/gstopusdec.c | 23 ++++++++++++++++++----- ext/opus/gstopusdec.h | 6 ++++-- ext/opus/gstopusenc.c | 40 +++++++++++++++++++++++++--------------- ext/opus/gstopusenc.h | 4 ++-- 4 files changed, 49 insertions(+), 24 deletions(-) diff --git a/ext/opus/gstopusdec.c b/ext/opus/gstopusdec.c index 7ac2bda279..f8b39ba08c 100644 --- a/ext/opus/gstopusdec.c +++ b/ext/opus/gstopusdec.c @@ -150,7 +150,7 @@ gst_opus_dec_reset (GstOpusDec * dec) { dec->packetno = 0; if (dec->state) { - opus_decoder_destroy (dec->state); + opus_multistream_decoder_destroy (dec->state); dec->state = NULL; } @@ -228,6 +228,16 @@ gst_opus_dec_parse_header (GstOpusDec * dec, GstBuffer * buf) "Found pre-skip of %u samples, R128 gain %d (volume %f)", dec->pre_skip, dec->r128_gain, dec->r128_gain_volume); + dec->channel_mapping_family = GST_BUFFER_DATA (buf)[18]; + if (dec->channel_mapping_family != 0) { + GST_ELEMENT_ERROR (dec, STREAM, DECODE, + ("Decoding error: unsupported channel nmapping family %d", + dec->channel_mapping_family), (NULL)); + return GST_FLOW_ERROR; + } + dec->channel_mapping[0] = 0; + dec->channel_mapping[1] = 1; + return GST_FLOW_OK; } @@ -298,7 +308,8 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer) GST_DEBUG_OBJECT (dec, "Creating decoder with %d channels, %d Hz", dec->n_channels, dec->sample_rate); - dec->state = opus_decoder_create (dec->sample_rate, dec->n_channels, &err); + dec->state = opus_multistream_decoder_create (dec->sample_rate, + dec->n_channels, 1, 1, dec->channel_mapping, &err); if (!dec->state || err != OPUS_OK) goto creation_failed; } @@ -350,14 +361,16 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer) if (dec->use_inband_fec) { if (dec->last_buffer) { /* normal delayed decode */ - n = opus_decode (dec->state, data, size, out_data, samples, 0); + n = opus_multistream_decode (dec->state, data, size, out_data, samples, + 0); } else { /* FEC reconstruction decode */ - n = opus_decode (dec->state, data, size, out_data, samples, 1); + n = opus_multistream_decode (dec->state, data, size, out_data, samples, + 1); } } else { /* normal decode */ - n = opus_decode (dec->state, data, size, out_data, samples, 0); + n = opus_multistream_decode (dec->state, data, size, out_data, samples, 0); } if (n < 0) { diff --git a/ext/opus/gstopusdec.h b/ext/opus/gstopusdec.h index b074787d7f..aa04b814d9 100644 --- a/ext/opus/gstopusdec.h +++ b/ext/opus/gstopusdec.h @@ -23,7 +23,7 @@ #include #include -#include +#include G_BEGIN_DECLS @@ -44,7 +44,7 @@ typedef struct _GstOpusDecClass GstOpusDecClass; struct _GstOpusDec { GstAudioDecoder element; - OpusDecoder *state; + OpusMSDecoder *state; guint64 packetno; @@ -55,6 +55,8 @@ struct _GstOpusDec { int n_channels; guint32 pre_skip; gint16 r128_gain; + guint8 channel_mapping_family; + guint8 channel_mapping[256]; gboolean apply_gain; double r128_gain_volume; diff --git a/ext/opus/gstopusenc.c b/ext/opus/gstopusenc.c index 71e19b045a..93e00aa38f 100644 --- a/ext/opus/gstopusenc.c +++ b/ext/opus/gstopusenc.c @@ -355,7 +355,7 @@ gst_opus_enc_stop (GstAudioEncoder * benc) GST_DEBUG_OBJECT (enc, "stop"); enc->header_sent = FALSE; if (enc->state) { - opus_encoder_destroy (enc->state); + opus_multistream_encoder_destroy (enc->state); enc->state = NULL; } gst_tag_list_free (enc->tags); @@ -435,7 +435,7 @@ gst_opus_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info) /* handle reconfigure */ if (enc->state) { - opus_encoder_destroy (enc->state); + opus_multistream_encoder_destroy (enc->state); enc->state = NULL; } if (!gst_opus_enc_setup (enc)) @@ -455,24 +455,34 @@ static gboolean gst_opus_enc_setup (GstOpusEnc * enc) { int error = OPUS_OK; + unsigned char mapping[256]; + int n; GST_DEBUG_OBJECT (enc, "setup"); - enc->state = opus_encoder_create (enc->sample_rate, enc->n_channels, + for (n = 0; n < enc->n_channels; ++n) + mapping[n] = n; + + enc->state = + opus_multistream_encoder_create (enc->sample_rate, enc->n_channels, + (enc->n_channels + 1) / 2, enc->n_channels / 2, mapping, enc->audio_or_voip ? OPUS_APPLICATION_AUDIO : OPUS_APPLICATION_VOIP, &error); if (!enc->state || error != OPUS_OK) goto encoder_creation_failed; - opus_encoder_ctl (enc->state, OPUS_SET_BITRATE (enc->bitrate), 0); - opus_encoder_ctl (enc->state, OPUS_SET_BANDWIDTH (enc->bandwidth), 0); - opus_encoder_ctl (enc->state, OPUS_SET_VBR (!enc->cbr), 0); - opus_encoder_ctl (enc->state, OPUS_SET_VBR_CONSTRAINT (enc->constrained_vbr), + opus_multistream_encoder_ctl (enc->state, OPUS_SET_BITRATE (enc->bitrate), 0); + opus_multistream_encoder_ctl (enc->state, OPUS_SET_BANDWIDTH (enc->bandwidth), 0); - opus_encoder_ctl (enc->state, OPUS_SET_COMPLEXITY (enc->complexity), 0); - opus_encoder_ctl (enc->state, OPUS_SET_INBAND_FEC (enc->inband_fec), 0); - opus_encoder_ctl (enc->state, OPUS_SET_DTX (enc->dtx), 0); - opus_encoder_ctl (enc->state, + opus_multistream_encoder_ctl (enc->state, OPUS_SET_VBR (!enc->cbr), 0); + opus_multistream_encoder_ctl (enc->state, + OPUS_SET_VBR_CONSTRAINT (enc->constrained_vbr), 0); + opus_multistream_encoder_ctl (enc->state, + OPUS_SET_COMPLEXITY (enc->complexity), 0); + opus_multistream_encoder_ctl (enc->state, + OPUS_SET_INBAND_FEC (enc->inband_fec), 0); + opus_multistream_encoder_ctl (enc->state, OPUS_SET_DTX (enc->dtx), 0); + opus_multistream_encoder_ctl (enc->state, OPUS_SET_PACKET_LOSS_PERC (enc->packet_loss_percentage), 0); GST_LOG_OBJECT (enc, "we have frame size %d", enc->frame_size); @@ -557,8 +567,8 @@ gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf) enc->frame_samples); outsize = - opus_encode (enc->state, (const gint16 *) data, enc->frame_samples, - GST_BUFFER_DATA (outbuf), enc->max_payload_size); + opus_multistream_encode (enc->state, (const gint16 *) data, + enc->frame_samples, GST_BUFFER_DATA (outbuf), enc->max_payload_size); if (outsize < 0) { GST_ERROR_OBJECT (enc, "Encoding failed: %d", outsize); @@ -694,7 +704,7 @@ gst_opus_enc_set_property (GObject * object, guint prop_id, g_mutex_lock (enc->property_lock); \ enc->prop = g_value_get_##type (value); \ if (enc->state) { \ - opus_encoder_ctl (enc->state, OPUS_SET_##ctl (enc->prop)); \ + opus_multistream_encoder_ctl (enc->state, OPUS_SET_##ctl (enc->prop)); \ } \ g_mutex_unlock (enc->property_lock); \ } while(0) @@ -720,7 +730,7 @@ gst_opus_enc_set_property (GObject * object, guint prop_id, /* this one has an opposite meaning to the opus ctl... */ g_mutex_lock (enc->property_lock); enc->cbr = g_value_get_boolean (value); - opus_encoder_ctl (enc->state, OPUS_SET_VBR (!enc->cbr)); + opus_multistream_encoder_ctl (enc->state, OPUS_SET_VBR (!enc->cbr)); g_mutex_unlock (enc->property_lock); break; case PROP_CONSTRAINED_VBR: diff --git a/ext/opus/gstopusenc.h b/ext/opus/gstopusenc.h index 58c617c5a1..8304e82556 100644 --- a/ext/opus/gstopusenc.h +++ b/ext/opus/gstopusenc.h @@ -26,7 +26,7 @@ #include #include -#include +#include G_BEGIN_DECLS @@ -50,7 +50,7 @@ typedef struct _GstOpusEncClass GstOpusEncClass; struct _GstOpusEnc { GstAudioEncoder element; - OpusEncoder *state; + OpusMSEncoder *state; /* Locks those properties which may be changed at play time */ GMutex *property_lock; From 0ca385a97030d96044cbcd9ccb269bc4e470423c Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Thu, 24 Nov 2011 13:29:56 +0000 Subject: [PATCH 21/24] opus: multichannel support --- ext/opus/Makefile.am | 4 +- ext/opus/gstopuscommon.c | 72 ++++++++++++++++++++ ext/opus/gstopuscommon.h | 33 +++++++++ ext/opus/gstopusdec.c | 141 +++++++++++++++++++++++---------------- ext/opus/gstopusdec.h | 3 + ext/opus/gstopusenc.c | 100 +++++++++++++++++++++++---- ext/opus/gstopusenc.h | 3 + ext/opus/gstopusheader.c | 92 ++++++++++++++++++++----- ext/opus/gstopusheader.h | 12 +++- ext/opus/gstopusparse.c | 81 +++++++++++++--------- ext/opus/gstopusparse.h | 2 + 11 files changed, 421 insertions(+), 122 deletions(-) create mode 100644 ext/opus/gstopuscommon.c create mode 100644 ext/opus/gstopuscommon.h diff --git a/ext/opus/Makefile.am b/ext/opus/Makefile.am index 88845a3cab..cb0a9b338a 100644 --- a/ext/opus/Makefile.am +++ b/ext/opus/Makefile.am @@ -1,6 +1,6 @@ plugin_LTLIBRARIES = libgstopus.la -libgstopus_la_SOURCES = gstopus.c gstopusdec.c gstopusenc.c gstopusparse.c gstopusheader.c +libgstopus_la_SOURCES = gstopus.c gstopusdec.c gstopusenc.c gstopusparse.c gstopusheader.c gstopuscommon.c libgstopus_la_CFLAGS = \ -DGST_USE_UNSTABLE_API \ $(GST_PLUGINS_BASE_CFLAGS) \ @@ -15,4 +15,4 @@ libgstopus_la_LIBADD = \ libgstopus_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(LIBM) libgstopus_la_LIBTOOLFLAGS = --tag=disable-static -noinst_HEADERS = gstopusenc.h gstopusdec.h gstopusparse.h gstopusheader.h +noinst_HEADERS = gstopusenc.h gstopusdec.h gstopusparse.h gstopusheader.h gstopuscommon.h diff --git a/ext/opus/gstopuscommon.c b/ext/opus/gstopuscommon.c new file mode 100644 index 0000000000..fc3e0376b9 --- /dev/null +++ b/ext/opus/gstopuscommon.c @@ -0,0 +1,72 @@ +/* GStreamer + * Copyright (C) 2009 Sebastian Dröge + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gstopuscommon.h" + +/* http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9 */ +/* copy of the same structure in the vorbis plugin */ +const GstAudioChannelPosition gst_opus_channel_positions[][8] = { + { /* Mono */ + GST_AUDIO_CHANNEL_POSITION_FRONT_MONO}, + { /* Stereo */ + GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, + { /* Stereo + Centre */ + GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, + { /* Quadraphonic */ + GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, + GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, + GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, + }, + { /* Stereo + Centre + rear stereo */ + GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, + GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, + GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, + }, + { /* Full 5.1 Surround */ + GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, + GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, + GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, + GST_AUDIO_CHANNEL_POSITION_LFE, + }, + { /* 6.1 Surround, in Vorbis spec since 2010-01-13 */ + GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, + GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, + GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT, + GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, + GST_AUDIO_CHANNEL_POSITION_LFE}, + { /* 7.1 Surround, in Vorbis spec since 2010-01-13 */ + GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, + GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, + GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT, + GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, + GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, + GST_AUDIO_CHANNEL_POSITION_LFE}, +}; diff --git a/ext/opus/gstopuscommon.h b/ext/opus/gstopuscommon.h new file mode 100644 index 0000000000..96a303e303 --- /dev/null +++ b/ext/opus/gstopuscommon.h @@ -0,0 +1,33 @@ +/* GStreamer Opus Encoder + * Copyright (C) 2009 Sebastian Dröge + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __GST_OPUS_COMMON_H__ +#define __GST_OPUS_COMMON_H__ + +#include +#include + +G_BEGIN_DECLS + +extern const GstAudioChannelPosition gst_opus_channel_positions[][8]; + +G_END_DECLS + +#endif /* __GST_OPUS_COMMON_H__ */ diff --git a/ext/opus/gstopusdec.c b/ext/opus/gstopusdec.c index f8b39ba08c..58283973a2 100644 --- a/ext/opus/gstopusdec.c +++ b/ext/opus/gstopusdec.c @@ -45,6 +45,7 @@ #include #include #include "gstopusheader.h" +#include "gstopuscommon.h" #include "gstopusdec.h" GST_DEBUG_CATEGORY_STATIC (opusdec_debug); @@ -56,7 +57,7 @@ GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_ALWAYS, GST_STATIC_CAPS ("audio/x-raw-int, " "rate = (int) { 48000, 24000, 16000, 12000, 8000 }, " - "channels = (int) [ 1, 2 ], " + "channels = (int) [ 1, 8 ], " "endianness = (int) BYTE_ORDER, " "signed = (boolean) true, " "width = (int) 16, " "depth = (int) 16") ); @@ -217,26 +218,91 @@ gst_opus_dec_get_r128_volume (gint16 r128_gain) static GstFlowReturn gst_opus_dec_parse_header (GstOpusDec * dec, GstBuffer * buf) { - g_return_val_if_fail (gst_opus_header_is_header (buf, "OpusHead", 8), - GST_FLOW_ERROR); - g_return_val_if_fail (GST_BUFFER_SIZE (buf) >= 19, GST_FLOW_ERROR); + const guint8 *data = GST_BUFFER_DATA (buf); + GstCaps *caps; + GstStructure *s; + const GstAudioChannelPosition *pos = NULL; - dec->pre_skip = GST_READ_UINT16_LE (GST_BUFFER_DATA (buf) + 10); - dec->r128_gain = GST_READ_UINT16_LE (GST_BUFFER_DATA (buf) + 14); + g_return_val_if_fail (gst_opus_header_is_id_header (buf), GST_FLOW_ERROR); + g_return_val_if_fail (dec->n_channels != data[9], GST_FLOW_ERROR); + + dec->n_channels = data[9]; + dec->pre_skip = GST_READ_UINT16_LE (data + 10); + dec->r128_gain = GST_READ_UINT16_LE (data + 14); dec->r128_gain_volume = gst_opus_dec_get_r128_volume (dec->r128_gain); GST_INFO_OBJECT (dec, "Found pre-skip of %u samples, R128 gain %d (volume %f)", dec->pre_skip, dec->r128_gain, dec->r128_gain_volume); - dec->channel_mapping_family = GST_BUFFER_DATA (buf)[18]; - if (dec->channel_mapping_family != 0) { - GST_ELEMENT_ERROR (dec, STREAM, DECODE, - ("Decoding error: unsupported channel nmapping family %d", - dec->channel_mapping_family), (NULL)); - return GST_FLOW_ERROR; + dec->channel_mapping_family = data[18]; + if (dec->channel_mapping_family == 0) { + /* implicit mapping */ + GST_INFO_OBJECT (dec, "Channel mapping family 0, implicit mapping"); + dec->n_streams = dec->n_stereo_streams = 1; + dec->channel_mapping[0] = 0; + dec->channel_mapping[1] = 1; + } else { + dec->n_streams = data[19]; + dec->n_stereo_streams = data[20]; + memcpy (dec->channel_mapping, data + 21, dec->n_channels); + + if (dec->channel_mapping_family == 1) { + GST_INFO_OBJECT (dec, "Channel mapping family 1, Vorbis mapping"); + switch (dec->n_channels) { + case 1: + case 2: + /* nothing */ + break; + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + pos = gst_opus_channel_positions[dec->n_channels - 1]; + break; + default:{ + gint i; + GstAudioChannelPosition *posn = + g_new (GstAudioChannelPosition, dec->n_channels); + + GST_ELEMENT_WARNING (GST_ELEMENT (dec), STREAM, DECODE, + (NULL), ("Using NONE channel layout for more than 8 channels")); + + for (i = 0; i < dec->n_channels; i++) + posn[i] = GST_AUDIO_CHANNEL_POSITION_NONE; + + pos = posn; + } + } + } else { + GST_INFO_OBJECT (dec, "Channel mapping family %d", + dec->channel_mapping_family); + } } - dec->channel_mapping[0] = 0; - dec->channel_mapping[1] = 1; + + /* negotiate width with downstream */ + caps = gst_pad_get_allowed_caps (GST_AUDIO_DECODER_SRC_PAD (dec)); + s = gst_caps_get_structure (caps, 0); + gst_structure_fixate_field_nearest_int (s, "rate", 48000); + gst_structure_get_int (s, "rate", &dec->sample_rate); + gst_structure_fixate_field_nearest_int (s, "channels", dec->n_channels); + gst_structure_get_int (s, "channels", &dec->n_channels); + + GST_INFO_OBJECT (dec, "Negotiated %d channels, %d Hz", dec->n_channels, + dec->sample_rate); + + if (pos) { + gst_audio_set_channel_positions (gst_caps_get_structure (caps, 0), pos); + } + + if (dec->n_channels > 8) { + g_free ((GstAudioChannelPosition *) pos); + } + + GST_INFO_OBJECT (dec, "Setting src caps to %" GST_PTR_FORMAT, caps); + gst_pad_set_caps (GST_AUDIO_DECODER_SRC_PAD (dec), caps); + gst_caps_unref (caps); return GST_FLOW_OK; } @@ -248,48 +314,6 @@ gst_opus_dec_parse_comments (GstOpusDec * dec, GstBuffer * buf) return GST_FLOW_OK; } -static void -gst_opus_dec_setup_from_peer_caps (GstOpusDec * dec) -{ - GstPad *srcpad, *peer; - GstStructure *s; - GstCaps *caps; - const GstCaps *template_caps; - const GstCaps *peer_caps; - - srcpad = GST_AUDIO_DECODER_SRC_PAD (dec); - peer = gst_pad_get_peer (srcpad); - - if (peer) { - template_caps = gst_pad_get_pad_template_caps (srcpad); - peer_caps = gst_pad_get_caps (peer); - GST_DEBUG_OBJECT (dec, "Peer caps: %" GST_PTR_FORMAT, peer_caps); - caps = gst_caps_intersect (template_caps, peer_caps); - gst_pad_fixate_caps (peer, caps); - GST_DEBUG_OBJECT (dec, "Fixated caps: %" GST_PTR_FORMAT, caps); - - s = gst_caps_get_structure (caps, 0); - if (!gst_structure_get_int (s, "channels", &dec->n_channels)) { - dec->n_channels = 2; - GST_WARNING_OBJECT (dec, "Failed to get channels, using default %d", - dec->n_channels); - } else { - GST_DEBUG_OBJECT (dec, "Got channels %d", dec->n_channels); - } - if (!gst_structure_get_int (s, "rate", &dec->sample_rate)) { - dec->sample_rate = 48000; - GST_WARNING_OBJECT (dec, "Failed to get rate, using default %d", - dec->sample_rate); - } else { - GST_DEBUG_OBJECT (dec, "Got sample rate %d", dec->sample_rate); - } - - gst_pad_set_caps (GST_AUDIO_DECODER_SRC_PAD (dec), caps); - } else { - GST_WARNING_OBJECT (dec, "Failed to get src pad peer"); - } -} - static GstFlowReturn opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer) { @@ -304,12 +328,11 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer) GstBuffer *buf; if (dec->state == NULL) { - gst_opus_dec_setup_from_peer_caps (dec); - GST_DEBUG_OBJECT (dec, "Creating decoder with %d channels, %d Hz", dec->n_channels, dec->sample_rate); dec->state = opus_multistream_decoder_create (dec->sample_rate, - dec->n_channels, 1, 1, dec->channel_mapping, &err); + dec->n_channels, dec->n_streams, dec->n_stereo_streams, + dec->channel_mapping, &err); if (!dec->state || err != OPUS_OK) goto creation_failed; } diff --git a/ext/opus/gstopusdec.h b/ext/opus/gstopusdec.h index aa04b814d9..3ccfa26969 100644 --- a/ext/opus/gstopusdec.h +++ b/ext/opus/gstopusdec.h @@ -55,6 +55,9 @@ struct _GstOpusDec { int n_channels; guint32 pre_skip; gint16 r128_gain; + + guint8 n_streams; + guint8 n_stereo_streams; guint8 channel_mapping_family; guint8 channel_mapping[256]; diff --git a/ext/opus/gstopusenc.c b/ext/opus/gstopusenc.c index 93e00aa38f..6dad531156 100644 --- a/ext/opus/gstopusenc.c +++ b/ext/opus/gstopusenc.c @@ -49,6 +49,7 @@ #include #include #include "gstopusheader.h" +#include "gstopuscommon.h" #include "gstopusenc.h" GST_DEBUG_CATEGORY_STATIC (opusenc_debug); @@ -116,8 +117,8 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("audio/x-raw-int, " - "rate = (int) { 8000, 12000, 16000, 24000, 48000 }, " - "channels = (int) [ 1, 2 ], " + "rate = (int) { 48000, 24000, 16000, 12000, 8000 }, " + "channels = (int) [ 1, 8 ], " "endianness = (int) BYTE_ORDER, " "signed = (boolean) TRUE, " "width = (int) 16, " "depth = (int) 16") ); @@ -419,6 +420,82 @@ gst_opus_enc_get_frame_samples (GstOpusEnc * enc) return frame_samples; } +static void +gst_opus_enc_setup_channel_mapping (GstOpusEnc * enc, const GstAudioInfo * info) +{ +#define MAPS(idx,pos) (GST_AUDIO_INFO_POSITION (info, (idx)) == GST_AUDIO_CHANNEL_POSITION_##pos) + + int n; + + GST_DEBUG_OBJECT (enc, "Setting up channel mapping for %d channels", + enc->n_channels); + + /* Start by setting up a default trivial mapping */ + for (n = 0; n < 255; ++n) + enc->channel_mapping[n] = n; + + /* For one channel, use the basic RTP mapping */ + if (enc->n_channels == 1) { + GST_INFO_OBJECT (enc, "Mono, trivial RTP mapping"); + enc->channel_mapping_family = 0; + enc->channel_mapping[0] = 0; + return; + } + + /* For two channels, use the basic RTP mapping if the channels are + mapped as left/right. */ + if (enc->n_channels == 2) { + if (MAPS (0, FRONT_LEFT) && MAPS (1, FRONT_RIGHT)) { + GST_INFO_OBJECT (enc, "Stereo, canonical mapping"); + enc->channel_mapping_family = 0; + /* The channel mapping is implicit for family 0, that's why we do not + attempt to create one for right/left - this will be mapped to the + Vorbis mapping below. */ + } else { + GST_DEBUG_OBJECT (enc, "Stereo, but not canonical mapping, continuing"); + } + } + + /* For channels between 1 and 8, we use the Vorbis mapping if we can + find a permutation that matches it. Mono will have been taken care + of earlier, but this code also handles it. */ + if (enc->n_channels >= 1 && enc->n_channels <= 8) { + GST_DEBUG_OBJECT (enc, + "In range for the Vorbis mapping, checking channel positions"); + for (n = 0; n < enc->n_channels; ++n) { + GstAudioChannelPosition pos = GST_AUDIO_INFO_POSITION (info, n); + int c; + + GST_DEBUG_OBJECT (enc, "Channel %d has position %d", n, pos); + for (c = 0; c < enc->n_channels; ++c) { + if (gst_opus_channel_positions[enc->n_channels - 1][c] == pos) { + GST_DEBUG_OBJECT (enc, "Found in Vorbis mapping as channel %d", c); + break; + } + } + if (c == enc->n_channels) { + /* We did not find that position, so use undefined */ + GST_WARNING_OBJECT (enc, + "Position %d not found in Vorbis mapping, using unknown mapping", + pos); + enc->channel_mapping_family = 255; + return; + } + GST_DEBUG_OBJECT (enc, "Mapping output channel %d to %d", c, n); + enc->channel_mapping[c] = n; + } + GST_INFO_OBJECT (enc, "Permutation found, using Vorbis mapping"); + enc->channel_mapping_family = 1; + return; + } + + /* For other cases, we use undefined, with the default trivial mapping */ + GST_WARNING_OBJECT (enc, "Unknown mapping"); + enc->channel_mapping_family = 255; + +#undef MAPS +} + static gboolean gst_opus_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info) { @@ -430,6 +507,7 @@ gst_opus_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info) enc->n_channels = GST_AUDIO_INFO_CHANNELS (info); enc->sample_rate = GST_AUDIO_INFO_RATE (info); + gst_opus_enc_setup_channel_mapping (enc, info); GST_DEBUG_OBJECT (benc, "Setup with %d channels, %d Hz", enc->n_channels, enc->sample_rate); @@ -455,17 +533,12 @@ static gboolean gst_opus_enc_setup (GstOpusEnc * enc) { int error = OPUS_OK; - unsigned char mapping[256]; - int n; GST_DEBUG_OBJECT (enc, "setup"); - for (n = 0; n < enc->n_channels; ++n) - mapping[n] = n; - enc->state = opus_multistream_encoder_create (enc->sample_rate, enc->n_channels, - (enc->n_channels + 1) / 2, enc->n_channels / 2, mapping, + (enc->n_channels + 1) / 2, enc->n_channels / 2, enc->channel_mapping, enc->audio_or_voip ? OPUS_APPLICATION_AUDIO : OPUS_APPLICATION_VOIP, &error); if (!enc->state || error != OPUS_OK) @@ -557,18 +630,19 @@ gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf) GstBuffer *outbuf; ret = gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), - GST_BUFFER_OFFSET_NONE, enc->max_payload_size, + GST_BUFFER_OFFSET_NONE, enc->max_payload_size * enc->n_channels, GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (enc)), &outbuf); if (GST_FLOW_OK != ret) goto done; GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", - enc->frame_samples); + enc->frame_samples, (int) bytes); outsize = opus_multistream_encode (enc->state, (const gint16 *) data, - enc->frame_samples, GST_BUFFER_DATA (outbuf), enc->max_payload_size); + enc->frame_samples, GST_BUFFER_DATA (outbuf), + enc->max_payload_size * enc->n_channels); if (outsize < 0) { GST_ERROR_OBJECT (enc, "Encoding failed: %d", outsize); @@ -582,6 +656,7 @@ gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf) goto done; } + GST_DEBUG_OBJECT (enc, "Output packet is %u bytes", outsize); GST_BUFFER_SIZE (outbuf) = outsize; ret = @@ -621,7 +696,8 @@ gst_opus_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf) enc->headers = NULL; gst_opus_header_create_caps (&caps, &enc->headers, enc->n_channels, - enc->sample_rate, gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc))); + enc->sample_rate, enc->channel_mapping_family, enc->channel_mapping, + gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc))); /* negotiate with these caps */ diff --git a/ext/opus/gstopusenc.h b/ext/opus/gstopusenc.h index 8304e82556..8c2c3c6e82 100644 --- a/ext/opus/gstopusenc.h +++ b/ext/opus/gstopusenc.h @@ -77,6 +77,9 @@ struct _GstOpusEnc { GSList *headers; GstTagList *tags; + + guint8 channel_mapping_family; + guint8 channel_mapping[256]; }; struct _GstOpusEncClass { diff --git a/ext/opus/gstopusheader.c b/ext/opus/gstopusheader.c index 3551055840..0379c909f4 100644 --- a/ext/opus/gstopusheader.c +++ b/ext/opus/gstopusheader.c @@ -27,7 +27,8 @@ #include "gstopusheader.h" static GstBuffer * -gst_opus_enc_create_id_buffer (gint nchannels, gint sample_rate) +gst_opus_enc_create_id_buffer (gint nchannels, gint sample_rate, + guint8 channel_mapping_family, const guint8 * channel_mapping) { GstBuffer *buffer; GstByteWriter bw; @@ -41,7 +42,12 @@ gst_opus_enc_create_id_buffer (gint nchannels, gint sample_rate) gst_byte_writer_put_uint16_le (&bw, 0); /* pre-skip *//* TODO: endianness ? */ gst_byte_writer_put_uint32_le (&bw, sample_rate); gst_byte_writer_put_uint16_le (&bw, 0); /* output gain *//* TODO: endianness ? */ - gst_byte_writer_put_uint8 (&bw, 0); /* channel mapping *//* TODO: what is this ? */ + gst_byte_writer_put_uint8 (&bw, channel_mapping_family); + if (channel_mapping_family > 0) { + gst_byte_writer_put_uint8 (&bw, (nchannels + 1) / 2); + gst_byte_writer_put_uint8 (&bw, nchannels / 2); + gst_byte_writer_put_data (&bw, channel_mapping, nchannels); + } buffer = gst_byte_writer_reset_and_get_buffer (&bw); @@ -136,23 +142,11 @@ _gst_caps_set_buffer_array (GstCaps * caps, const gchar * field, } void -gst_opus_header_create_caps (GstCaps ** caps, GSList ** headers, gint nchannels, - gint sample_rate, const GstTagList * tags) +gst_opus_header_create_caps_from_headers (GstCaps ** caps, GSList ** headers, + GstBuffer * buf1, GstBuffer * buf2) { - GstBuffer *buf1, *buf2; - g_return_if_fail (caps); g_return_if_fail (headers && !*headers); - g_return_if_fail (nchannels > 0); - g_return_if_fail (sample_rate >= 0); /* 0 -> unset */ - - /* Opus streams in Ogg begin with two headers; the initial header (with - most of the codec setup parameters) which is mandated by the Ogg - bitstream spec. The second header holds any comment fields. */ - - /* create header buffers */ - buf1 = gst_opus_enc_create_id_buffer (nchannels, sample_rate); - buf2 = gst_opus_enc_create_metadata_buffer (tags); /* mark and put on caps */ *caps = gst_caps_from_string ("audio/x-opus"); @@ -162,9 +156,75 @@ gst_opus_header_create_caps (GstCaps ** caps, GSList ** headers, gint nchannels, *headers = g_slist_prepend (*headers, buf1); } +void +gst_opus_header_create_caps (GstCaps ** caps, GSList ** headers, gint nchannels, + gint sample_rate, guint8 channel_mapping_family, + const guint8 * channel_mapping, const GstTagList * tags) +{ + GstBuffer *buf1, *buf2; + + g_return_if_fail (caps); + g_return_if_fail (headers && !*headers); + g_return_if_fail (nchannels > 0); + g_return_if_fail (sample_rate >= 0); /* 0 -> unset */ + g_return_if_fail (channel_mapping_family == 0 || channel_mapping); + + /* Opus streams in Ogg begin with two headers; the initial header (with + most of the codec setup parameters) which is mandated by the Ogg + bitstream spec. The second header holds any comment fields. */ + + /* create header buffers */ + buf1 = + gst_opus_enc_create_id_buffer (nchannels, sample_rate, + channel_mapping_family, channel_mapping); + buf2 = gst_opus_enc_create_metadata_buffer (tags); + + gst_opus_header_create_caps_from_headers (caps, headers, buf1, buf2); +} + gboolean gst_opus_header_is_header (GstBuffer * buf, const char *magic, guint magic_size) { return (GST_BUFFER_SIZE (buf) >= magic_size && !memcmp (magic, GST_BUFFER_DATA (buf), magic_size)); } + +gboolean +gst_opus_header_is_id_header (GstBuffer * buf) +{ + gsize size = GST_BUFFER_SIZE (buf); + const guint8 *data = GST_BUFFER_DATA (buf); + guint8 channels, channel_mapping_family, n_streams, n_stereo_streams; + + if (size < 19) + return FALSE; + if (!gst_opus_header_is_header (buf, "OpusHead", 8)) + return FALSE; + channels = data[9]; + if (channels == 0) + return FALSE; + channel_mapping_family = data[18]; + if (channel_mapping_family == 0) { + if (channels > 2) + return FALSE; + } else { + channels = data[9]; + if (size < 21 + channels) + return FALSE; + n_streams = data[19]; + n_stereo_streams = data[20]; + if (n_streams == 0) + return FALSE; + if (n_stereo_streams > n_streams) + return FALSE; + if (n_streams + n_stereo_streams > 255) + return FALSE; + } + return TRUE; +} + +gboolean +gst_opus_header_is_comment_header (GstBuffer * buf) +{ + return gst_opus_header_is_header (buf, "OpusTags", 8); +} diff --git a/ext/opus/gstopusheader.h b/ext/opus/gstopusheader.h index 4594264ccd..3b2cfc265f 100644 --- a/ext/opus/gstopusheader.h +++ b/ext/opus/gstopusheader.h @@ -25,8 +25,16 @@ G_BEGIN_DECLS -extern void gst_opus_header_create_caps (GstCaps **caps, GSList **headers, gint nchannels, gint sample_rate, const GstTagList *tags); -extern gboolean gst_opus_header_is_header (GstBuffer * buf, const char *magic, guint magic_size); +extern void gst_opus_header_create_caps_from_headers (GstCaps **caps, GSList **headers, + GstBuffer *id_header, GstBuffer *comment_header); +extern void gst_opus_header_create_caps (GstCaps **caps, GSList **headers, + gint nchannels, gint sample_rate, + guint8 channel_mapping_family, const guint8 *channel_mapping, + const GstTagList *tags); +extern gboolean gst_opus_header_is_header (GstBuffer * buf, + const char *magic, guint magic_size); +extern gboolean gst_opus_header_is_id_header (GstBuffer * buf); +extern gboolean gst_opus_header_is_comment_header (GstBuffer * buf); G_END_DECLS diff --git a/ext/opus/gstopusparse.c b/ext/opus/gstopusparse.c index 278cead432..8627f93028 100644 --- a/ext/opus/gstopusparse.c +++ b/ext/opus/gstopusparse.c @@ -37,6 +37,7 @@ # include "config.h" #endif +#include #include #include "gstopusheader.h" #include "gstopusparse.h" @@ -136,7 +137,6 @@ gst_opus_parse_check_valid_frame (GstBaseParse * base, gsize size; guint32 packet_size; int ret = FALSE; - int channels; const unsigned char *frames[48]; unsigned char toc; short frame_sizes[48]; @@ -152,8 +152,8 @@ gst_opus_parse_check_valid_frame (GstBaseParse * base, GST_DEBUG_OBJECT (parse, "Checking for frame, %u bytes in buffer", size); /* check for headers */ - is_idheader = gst_opus_header_is_header (frame->buffer, "OpusHead", 8); - is_commentheader = gst_opus_header_is_header (frame->buffer, "OpusTags", 8); + is_idheader = gst_opus_header_is_id_header (frame->buffer); + is_commentheader = gst_opus_header_is_comment_header (frame->buffer); is_header = is_idheader || is_commentheader; if (!is_header) { @@ -193,27 +193,6 @@ gst_opus_parse_check_valid_frame (GstBaseParse * base, data += packet_offset; } - if (!parse->header_sent) { - GstCaps *caps; - - /* Opus streams can decode to 1 or 2 channels, so use the header - value if we have one, or 2 otherwise */ - if (is_idheader) { - channels = data[9]; - } else { - channels = 2; - } - - g_slist_foreach (parse->headers, (GFunc) gst_buffer_unref, NULL); - parse->headers = NULL; - - gst_opus_header_create_caps (&caps, &parse->headers, channels, 0, NULL); - - gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps); - - parse->header_sent = TRUE; - } - if (is_header) { *skip = 0; *frame_size = size; @@ -291,16 +270,56 @@ gst_opus_parse_parse_frame (GstBaseParse * base, GstBaseParseFrame * frame) { guint64 duration; GstOpusParse *parse; + gboolean is_idheader, is_commentheader; parse = GST_OPUS_PARSE (base); - if (gst_opus_header_is_header (frame->buffer, "OpusHead", 8) - || gst_opus_header_is_header (frame->buffer, "OpusTags", 8)) { - GST_BUFFER_TIMESTAMP (frame->buffer) = 0; - GST_BUFFER_DURATION (frame->buffer) = GST_CLOCK_TIME_NONE; - GST_BUFFER_OFFSET_END (frame->buffer) = GST_CLOCK_TIME_NONE; - GST_BUFFER_OFFSET (frame->buffer) = GST_CLOCK_TIME_NONE; - return GST_FLOW_OK; + is_idheader = gst_opus_header_is_id_header (frame->buffer); + is_commentheader = gst_opus_header_is_comment_header (frame->buffer); + + if (!parse->header_sent) { + GstCaps *caps; + guint8 channels, channel_mapping_family, channel_mapping[256]; + const guint8 *data = GST_BUFFER_DATA (frame->buffer); + + /* Opus streams can decode to 1 or 2 channels, so use the header + value if we have one, or 2 otherwise */ + if (is_idheader) { + channels = data[9]; + channel_mapping_family = data[18]; + /* header probing will already have done the size check */ + memcpy (channel_mapping, GST_BUFFER_DATA (frame->buffer) + 21, channels); + gst_buffer_replace (&parse->id_header, frame->buffer); + GST_DEBUG_OBJECT (parse, "Found ID header, keeping"); + return GST_BASE_PARSE_FLOW_DROPPED; + } else if (is_commentheader) { + gst_buffer_replace (&parse->comment_header, frame->buffer); + GST_DEBUG_OBJECT (parse, "Found comment header, keeping"); + return GST_BASE_PARSE_FLOW_DROPPED; + } + + g_slist_foreach (parse->headers, (GFunc) gst_buffer_unref, NULL); + parse->headers = NULL; + + if (parse->id_header && parse->comment_header) { + gst_opus_header_create_caps_from_headers (&caps, &parse->headers, + parse->id_header, parse->comment_header); + } else { + GST_INFO_OBJECT (parse, + "No headers, blindly setting up canonical stereo"); + channels = 2; + channel_mapping_family = 0; + channel_mapping[0] = 0; + channel_mapping[1] = 1; + gst_opus_header_create_caps (&caps, &parse->headers, channels, 0, + channel_mapping_family, channel_mapping, NULL); + } + + gst_buffer_replace (&parse->id_header, NULL); + gst_buffer_replace (&parse->comment_header, NULL); + + gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps); + parse->header_sent = TRUE; } GST_BUFFER_TIMESTAMP (frame->buffer) = parse->next_ts; diff --git a/ext/opus/gstopusparse.h b/ext/opus/gstopusparse.h index 60ea5c536b..f0fd24194f 100644 --- a/ext/opus/gstopusparse.h +++ b/ext/opus/gstopusparse.h @@ -46,6 +46,8 @@ struct _GstOpusParse { gboolean header_sent; GSList *headers; GstClockTime next_ts; + GstBuffer *id_header; + GstBuffer *comment_header; }; struct _GstOpusParseClass { From 78337fc198429e704ac7c4e9582ef26c4fcfa066 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Thu, 24 Nov 2011 13:38:59 +0000 Subject: [PATCH 22/24] opus: pre-skip and output gain are little endian, remove reminder note --- ext/opus/gstopusheader.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/opus/gstopusheader.c b/ext/opus/gstopusheader.c index 0379c909f4..1aa3b0d01b 100644 --- a/ext/opus/gstopusheader.c +++ b/ext/opus/gstopusheader.c @@ -39,9 +39,9 @@ gst_opus_enc_create_id_buffer (gint nchannels, gint sample_rate, gst_byte_writer_put_data (&bw, (const guint8 *) "OpusHead", 8); gst_byte_writer_put_uint8 (&bw, 0); /* version number */ gst_byte_writer_put_uint8 (&bw, nchannels); - gst_byte_writer_put_uint16_le (&bw, 0); /* pre-skip *//* TODO: endianness ? */ + gst_byte_writer_put_uint16_le (&bw, 0); /* pre-skip */ gst_byte_writer_put_uint32_le (&bw, sample_rate); - gst_byte_writer_put_uint16_le (&bw, 0); /* output gain *//* TODO: endianness ? */ + gst_byte_writer_put_uint16_le (&bw, 0); /* output gain */ gst_byte_writer_put_uint8 (&bw, channel_mapping_family); if (channel_mapping_family > 0) { gst_byte_writer_put_uint8 (&bw, (nchannels + 1) / 2); From c61f85da82e1d0bb2b12d9b49b6c508f402f9c74 Mon Sep 17 00:00:00 2001 From: Stefan Sauer Date: Thu, 24 Nov 2011 19:03:23 +0100 Subject: [PATCH 23/24] audiovisualizers: add aa-line code and user for wave/space-scope --- gst/audiovisualizers/README | 11 +++++ gst/audiovisualizers/gstdrawhelpers.h | 63 +++++++++++++++++++++++++++ gst/audiovisualizers/gstspacescope.c | 11 ++--- gst/audiovisualizers/gstwavescope.c | 9 ++-- 4 files changed, 85 insertions(+), 9 deletions(-) diff --git a/gst/audiovisualizers/README b/gst/audiovisualizers/README index 79d88020d9..d1a8c05eb2 100644 --- a/gst/audiovisualizers/README +++ b/gst/audiovisualizers/README @@ -3,6 +3,10 @@ video-rate. It receives audio-data at the sampling-rate. It needs to render video-frames at frame-rate. The rendering needs n audio samples (depends on subclass). The baseclass takes care of that. +Some effects could be enhanced by running geometrictransform elements +afterwards. A blur and/or videozoom element would be great (vertigotv looks +great but has some negotiation issues). + = Feedback = * put 'Audio' to klass as well ? @@ -32,6 +36,12 @@ spectrascope - done spacescope - stereo wavescope - left->x, right->y - done - polar mapping +multiscope : +- like wave/space scope, but run the signal through two filters to split it into + bass, mid and high (200 Hz, 2000 Hz) +- draw 3 wave-scopes into red/gree/blue +- when drawing only draw that component to mix colors +- eventually use the spacescope-position to rotate/shift the wave = TODO = - element maker template @@ -47,6 +57,7 @@ GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-launch audiotestsrc ! audioconvert ! w GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-launch filesrc location=$HOME/Music/1.mp3 ! decodebin2 ! audioconvert ! wavescope ! colorspace ! ximagesink GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-launch filesrc location=$HOME/Music/1.mp3 ! decodebin2 ! audioconvert ! spacescope style=lines shade-amount=0x00080402 ! ximagesink +GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-launch filesrc location=$HOME/Music/1.mp3 ! decodebin2 ! audioconvert ! spacescope style=lines shade-amount=0x00080402 ! vertigotv ! ximagesink GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-launch filesrc location=$HOME/Music/1.mp3 ! decodebin2 ! audioconvert ! spectrascope ! colorspace ! ximagesink GST_PLUGIN_PATH=$GST_PLUGIN_PATH:$PWD gst-launch filesrc location=$HOME/Music/1.mp3 ! decodebin2 ! audioconvert ! spectrascope shader=fade-and-move-up shade-amount=0x00040302 ! colorspace ! ximagesink diff --git a/gst/audiovisualizers/gstdrawhelpers.h b/gst/audiovisualizers/gstdrawhelpers.h index 990cedaf65..2c2cd36efb 100644 --- a/gst/audiovisualizers/gstdrawhelpers.h +++ b/gst/audiovisualizers/gstdrawhelpers.h @@ -37,3 +37,66 @@ draw_dot (_vd, _x, _y, _st, _c); \ } \ } G_STMT_END + +#define draw_line_aa(_vd, _x1, _x2, _y1, _y2, _st, _c) G_STMT_START { \ + guint _i, _j, _x, _y; \ + gint _dx = _x2 - _x1, _dy = _y2 - _y1; \ + gfloat _f, _rx, _ry, _fx, _fy; \ + guint32 _oc, _nc, _c1, _c2, _c3; \ + \ + _j = abs (_dx) > abs (_dy) ? abs (_dx) : abs (_dy); \ + for (_i = 0; _i < _j; _i++) { \ + _f = (gfloat) _i / (gfloat) _j; \ + _rx = _x1 + _dx * _f; \ + _ry = _y1 + _dy * _f; \ + _x = (guint)_rx; \ + _y = (guint)_ry; \ + _fx = _rx - (gfloat)_x; \ + _fy = _ry - (gfloat)_y; \ + \ + _f = ((1.0 - _fx) + (1.0 - _fy)) / 2.0; \ + _oc = _vd[(_y * _st) + _x]; \ + _c3 = (_oc & 0xff) + ((_c & 0xff) * _f); \ + _c3 = MIN(_c3, 255); \ + _c2 = ((_oc & 0xff00) >> 8) + (((_c & 0xff00) >> 8) * _f); \ + _c2 = MIN(_c2, 255); \ + _c1 = ((_oc & 0xff0000) >> 16) + (((_c & 0xff0000) >> 16) * _f); \ + _c1 = MIN(_c1, 255); \ + _nc = 0x00 | (_c1 << 16) | (_c2 << 8) | _c3; \ + _vd[(_y * _st) + _x] = _nc; \ + \ + _f = (_fx + (1.0 - _fy)) / 2.0; \ + _oc = _vd[(_y * _st) + _x + 1]; \ + _c3 = (_oc & 0xff) + ((_c & 0xff) * _f); \ + _c3 = MIN(_c3, 255); \ + _c2 = ((_oc & 0xff00) >> 8) + (((_c & 0xff00) >> 8) * _f); \ + _c2 = MIN(_c2, 255); \ + _c1 = ((_oc & 0xff0000) >> 16) + (((_c & 0xff0000) >> 16) * _f); \ + _c1 = MIN(_c1, 255); \ + _nc = 0x00 | (_c1 << 16) | (_c2 << 8) | _c3; \ + _vd[(_y * _st) + _x + 1] = _nc; \ + \ + _f = ((1.0 - _fx) + _fy) / 2.0; \ + _oc = _vd[((_y + 1) * _st) + _x]; \ + _c3 = (_oc & 0xff) + ((_c & 0xff) * _f); \ + _c3 = MIN(_c3, 255); \ + _c2 = ((_oc & 0xff00) >> 8) + (((_c & 0xff00) >> 8) * _f); \ + _c2 = MIN(_c2, 255); \ + _c1 = ((_oc & 0xff0000) >> 16) + (((_c & 0xff0000) >> 16) * _f); \ + _c1 = MIN(_c1, 255); \ + _nc = 0x00 | (_c1 << 16) | (_c2 << 8) | _c3; \ + _vd[((_y + 1) * _st) + _x] = _nc; \ + \ + _f = (_fx + _fy) / 2.0; \ + _oc = _vd[((_y + 1) * _st) + _x + 1]; \ + _c3 = (_oc & 0xff) + ((_c & 0xff) * _f); \ + _c3 = MIN(_c3, 255); \ + _c2 = ((_oc & 0xff00) >> 8) + (((_c & 0xff00) >> 8) * _f); \ + _c2 = MIN(_c2, 255); \ + _c1 = ((_oc & 0xff0000) >> 16) + (((_c & 0xff0000) >> 16) * _f); \ + _c1 = MIN(_c1, 255); \ + _nc = 0x00 | (_c1 << 16) | (_c2 << 8) | _c3; \ + _vd[((_y + 1) * _st) + _x + 1] = _nc; \ + } \ +} G_STMT_END + diff --git a/gst/audiovisualizers/gstspacescope.c b/gst/audiovisualizers/gstspacescope.c index f7b7f7d303..101d0a9ae7 100644 --- a/gst/audiovisualizers/gstspacescope.c +++ b/gst/audiovisualizers/gstspacescope.c @@ -214,20 +214,21 @@ render_lines (GstBaseAudioVisualizer * scope, guint32 * vdata, gint16 * adata, guint i, s, x, y, ox, oy; gfloat dx, dy; guint w = scope->width; + guint h = scope->height; gint x2, y2; /* draw lines 1st channel x, 2nd channel y */ - dx = scope->width / 65536.0; - ox = scope->width / 2; - dy = scope->height / 65536.0; - oy = scope->height / 2; + dx = (w - 1) / 65536.0; + ox = (w - 1) / 2; + dy = (h - 1) / 65536.0; + oy = (h - 1) / 2; s = 0; x2 = (guint) (ox + (gfloat) adata[s++] * dx); y2 = (guint) (oy + (gfloat) adata[s++] * dy); for (i = 1; i < num_samples; i++) { x = (guint) (ox + (gfloat) adata[s++] * dx); y = (guint) (oy + (gfloat) adata[s++] * dy); - draw_line (vdata, x2, x, y2, y, w, 0x00FFFFFF); + draw_line_aa (vdata, x2, x, y2, y, w, 0x00FFFFFF); x2 = x; y2 = y; } diff --git a/gst/audiovisualizers/gstwavescope.c b/gst/audiovisualizers/gstwavescope.c index ab97e7dfc5..433a935e3c 100644 --- a/gst/audiovisualizers/gstwavescope.c +++ b/gst/audiovisualizers/gstwavescope.c @@ -218,12 +218,13 @@ render_lines (GstBaseAudioVisualizer * scope, guint32 * vdata, gint16 * adata, guint i, c, s, x, y, oy; gfloat dx, dy; guint w = scope->width; + guint h = scope->height; gint x2, y2; /* draw lines */ - dx = (gfloat) w / (gfloat) num_samples; - dy = scope->height / 65536.0; - oy = scope->height / 2; + dx = (gfloat) (w - 1) / (gfloat) num_samples; + dy = (h - 1) / 65536.0; + oy = (h - 1) / 2; for (c = 0; c < channels; c++) { s = c; x2 = 0; @@ -232,7 +233,7 @@ render_lines (GstBaseAudioVisualizer * scope, guint32 * vdata, gint16 * adata, x = (guint) ((gfloat) i * dx); y = (guint) (oy + (gfloat) adata[s] * dy); s += channels; - draw_line (vdata, x2, x, y2, y, w, 0x00FFFFFF); + draw_line_aa (vdata, x2, x, y2, y, w, 0x00FFFFFF); x2 = x; y2 = y; } From cdcc39455cc92ba5e6988056b03ac9c350a9bb6a Mon Sep 17 00:00:00 2001 From: Luciana Fujii Pontello Date: Tue, 30 Aug 2011 23:39:36 -0300 Subject: [PATCH 24/24] Add pvrvideosink element PVRVideoSink uses PVR2D library to blit images. Author: Alessandro Decina Author: Luciana Fujii --- configure.ac | 18 + sys/Makefile.am | 11 +- sys/pvr2d/Makefile.am | 22 + sys/pvr2d/gstpvr.c | 85 ++ sys/pvr2d/gstpvr.h | 42 + sys/pvr2d/gstpvrbufferpool.c | 320 ++++++ sys/pvr2d/gstpvrbufferpool.h | 89 ++ sys/pvr2d/gstpvrvideosink.c | 1548 ++++++++++++++++++++++++++ sys/pvr2d/gstpvrvideosink.h | 157 +++ sys/pvr2d/pvr_includes/dri2_ws.h | 176 +++ sys/pvr2d/pvr_includes/img_defs.h | 123 ++ sys/pvr2d/pvr_includes/img_types.h | 143 +++ sys/pvr2d/pvr_includes/pvr2d.h | 669 +++++++++++ sys/pvr2d/pvr_includes/services.h | 1211 ++++++++++++++++++++ sys/pvr2d/pvr_includes/servicesext.h | 855 ++++++++++++++ sys/pvr2d/pvr_includes/wsegl.h | 285 +++++ 16 files changed, 5752 insertions(+), 2 deletions(-) create mode 100644 sys/pvr2d/Makefile.am create mode 100644 sys/pvr2d/gstpvr.c create mode 100644 sys/pvr2d/gstpvr.h create mode 100644 sys/pvr2d/gstpvrbufferpool.c create mode 100644 sys/pvr2d/gstpvrbufferpool.h create mode 100644 sys/pvr2d/gstpvrvideosink.c create mode 100644 sys/pvr2d/gstpvrvideosink.h create mode 100755 sys/pvr2d/pvr_includes/dri2_ws.h create mode 100755 sys/pvr2d/pvr_includes/img_defs.h create mode 100755 sys/pvr2d/pvr_includes/img_types.h create mode 100755 sys/pvr2d/pvr_includes/pvr2d.h create mode 100644 sys/pvr2d/pvr_includes/services.h create mode 100755 sys/pvr2d/pvr_includes/servicesext.h create mode 100755 sys/pvr2d/pvr_includes/wsegl.h diff --git a/configure.ac b/configure.ac index 4c40173a33..7f9d9715d8 100644 --- a/configure.ac +++ b/configure.ac @@ -229,6 +229,8 @@ if test "x$BUILD_EXAMPLES" = "xyes"; then fi AM_CONDITIONAL(HAVE_GTK, test "x$HAVE_GTK" = "xyes") + + dnl Needed for GtkBuilder to autoconnect signals PKG_CHECK_MODULES(GMODULE_EXPORT, gmodule-export-2.0, HAVE_GMODULE_EXPORT=yes, HAVE_GMODULE_EXPORT=no) @@ -1401,6 +1403,20 @@ AG_GST_CHECK_FEATURE(OPUS, [opus], opus, [ AC_SUBST(OPUS_LIBS) ]) +dnl *** pvr *** +translit(dnm, m, l) AM_CONDITIONAL(USE_PVR, true) +AG_GST_CHECK_FEATURE(PVR, [pvrvideosink], pvr, [ + PKG_CHECK_MODULES([PVR], [libtimemmgr], HAVE_PVR=yes, HAVE_PVR=no) + AC_SUBST(PVR_CFLAGS) + AC_SUBST(PVR_LIBS) +]) + + AC_ARG_WITH([pvr-external-headers], + AC_HELP_STRING([--with-pvr-external-headers], [Use system installed PVR2D headers]), + [AS_IF([test "x$with_pvr_external_headers" = "xno"], + [PVR_CFLAGS="$PVR_CFLAGS -I\$(srcdir)/pvr_includes"])], + [PVR_CFLAGS="$PVR_CFLAGS -I\$(srcdir)/pvr_includes"]) + dnl *** rsvg *** translit(dnm, m, l) AM_CONDITIONAL(USE_RSVG, true) AG_GST_CHECK_FEATURE(RSVG, [rsvg decoder], rsvg, [ @@ -1792,6 +1808,7 @@ AM_CONDITIONAL(USE_OFA, false) AM_CONDITIONAL(USE_OPENAL, false) AM_CONDITIONAL(USE_OPENCV, false) AM_CONDITIONAL(USE_OPUS, false) +AM_CONDITIONAL(USE_PVR, false) AM_CONDITIONAL(USE_RSVG, false) AM_CONDITIONAL(USE_TIMIDITY, false) AM_CONDITIONAL(USE_WILDMIDI, false) @@ -1991,6 +2008,7 @@ sys/vcd/Makefile sys/vdpau/Makefile sys/vdpau/gstvdp/Makefile sys/vdpau/basevideodecoder/Makefile +sys/pvr2d/Makefile sys/wasapi/Makefile sys/wininet/Makefile sys/winks/Makefile diff --git a/sys/Makefile.am b/sys/Makefile.am index 5df060c861..a48b0d25b2 100644 --- a/sys/Makefile.am +++ b/sys/Makefile.am @@ -101,6 +101,7 @@ else VDPAU_DIR= endif + if USE_SHM SHM_DIR=shm else @@ -113,9 +114,15 @@ else AVC_DIR= endif -SUBDIRS = $(ACM_DIR) $(APPLE_MEDIA_DIR) $(AVC_DIR) $(D3DVIDEOSINK_DIR) $(DECKLINK_DIR) $(DIRECTDRAW_DIR) $(DIRECTSOUND_DIR) $(DVB_DIR) $(FBDEV_DIR) $(LINSYS_DIR) $(OSX_VIDEO_DIR) $(QT_DIR) $(SHM_DIR) $(VCD_DIR) $(VDPAU_DIR) $(WININET_DIR) +if USE_PVR +PVR_DIR=pvr2d +else +PVR_DIR= +endif + +SUBDIRS = $(ACM_DIR) $(APPLE_MEDIA_DIR) $(AVC_DIR) $(D3DVIDEOSINK_DIR) $(DECKLINK_DIR) $(DIRECTDRAW_DIR) $(DIRECTSOUND_DIR) $(DVB_DIR) $(FBDEV_DIR) $(LINSYS_DIR) $(OSX_VIDEO_DIR) $(QT_DIR) $(SHM_DIR) $(VCD_DIR) $(VDPAU_DIR) $(WININET_DIR) $(PVR_DIR) DIST_SUBDIRS = acmenc acmmp3dec applemedia avc d3dvideosink decklink directdraw directsound dvb linsys fbdev dshowdecwrapper dshowsrcwrapper dshowvideosink \ - osxvideo qtwrapper shm vcd vdpau wasapi wininet winks winscreencap + osxvideo qtwrapper shm vcd vdpau wasapi wininet winks winscreencap pvr2d include $(top_srcdir)/common/parallel-subdirs.mak diff --git a/sys/pvr2d/Makefile.am b/sys/pvr2d/Makefile.am new file mode 100644 index 0000000000..b450710631 --- /dev/null +++ b/sys/pvr2d/Makefile.am @@ -0,0 +1,22 @@ +plugin_LTLIBRARIES = libgstpvr.la + +libgstpvr_la_SOURCES = \ + gstpvr.c \ + gstpvrbufferpool.c \ + gstpvrvideosink.c + +libgstpvr_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(PVR_CFLAGS) + +libgstpvr_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) \ + $(GST_PLUGINS_BASE_LIBS) $(X11_LIBS) -lgstvideo-$(GST_MAJORMINOR) \ + -lgstinterfaces-$(GST_MAJORMINOR) -lpvr2d -lpvrPVR2D_DRIWSEGL\ + $(PVR_LIBS) \ + $(LIBM) + +libgstpvr_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstpvr_la_LIBTOOLFLAGS = --tag=disable-static + +noinst_HEADERS = \ + gstpvr.h \ + gstpvrbufferpool.h \ + gstpvrvideosink.h diff --git a/sys/pvr2d/gstpvr.c b/sys/pvr2d/gstpvr.c new file mode 100644 index 0000000000..0112d1ee7f --- /dev/null +++ b/sys/pvr2d/gstpvr.c @@ -0,0 +1,85 @@ +/* + * GStreamer + * Copyright (c) 2010, Texas Instruments Incorporated + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation + * version 2.1 of the License. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "gstpvr.h" +#include "gstpvrvideosink.h" + +GST_DEBUG_CATEGORY (gst_debug_pvrvideosink); + +static gboolean +plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT (gst_debug_pvrvideosink, "pvrvideosink", 0, + "pvrvideosink"); + + return gst_element_register (plugin, "pvrvideosink", GST_RANK_PRIMARY, + GST_TYPE_PVRVIDEOSINK); +} + +void * +gst_ducati_alloc_1d (gint sz) +{ + MemAllocBlock block = { + .pixelFormat = PIXEL_FMT_PAGE, + .dim.len = sz, + }; + return MemMgr_Alloc (&block, 1); +} + +void * +gst_ducati_alloc_2d (gint width, gint height, guint * sz) +{ + MemAllocBlock block[] = { { + .pixelFormat = PIXEL_FMT_8BIT, + .dim = {.area = { + .width = width, + .height = ALIGN2 (height, 1), + }}, + .stride = 4096}, { + .pixelFormat = PIXEL_FMT_16BIT, + .dim = {.area = { + .width = width, + .height = ALIGN2 (height, 1) / 2, + }}, + .stride = 4096} + }; + if (sz) { + *sz = (4096 * ALIGN2 (height, 1) * 3) / 2; + } + return MemMgr_Alloc (block, 2); +} + +/* PACKAGE: this is usually set by autotools depending on some _INIT macro + * in configure.ac and then written into and defined in config.h, but we can + * just set it ourselves here in case someone doesn't use autotools to + * compile this code. GST_PLUGIN_DEFINE needs PACKAGE to be defined. + */ +#ifndef PACKAGE +# define PACKAGE "ducati" +#endif + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "pvr", + "Pvr2d based plugin", + plugin_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/") diff --git a/sys/pvr2d/gstpvr.h b/sys/pvr2d/gstpvr.h new file mode 100644 index 0000000000..d2c57af003 --- /dev/null +++ b/sys/pvr2d/gstpvr.h @@ -0,0 +1,42 @@ +/* + * GStreamer + * Copyright (c) 2010, Texas Instruments Incorporated + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation + * version 2.1 of the License. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __GST_DUCATI_H__ +#define __GST_DUCATI_H__ + +#include +#include + +#include +#include +#include + +#include + +G_BEGIN_DECLS + +/* align x to next highest multiple of 2^n */ +#define ALIGN2(x,n) (((x) + ((1 << (n)) - 1)) & ~((1 << (n)) - 1)) + +void * gst_ducati_alloc_1d (gint sz); +void * gst_ducati_alloc_2d (gint width, gint height, guint * sz); + +G_END_DECLS + +#endif /* __GST_DUCATI_H__ */ diff --git a/sys/pvr2d/gstpvrbufferpool.c b/sys/pvr2d/gstpvrbufferpool.c new file mode 100644 index 0000000000..03bcafb688 --- /dev/null +++ b/sys/pvr2d/gstpvrbufferpool.c @@ -0,0 +1,320 @@ +/* + * GStreamer + * Copyright (c) 2010, Texas Instruments Incorporated + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation + * version 2.1 of the License. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "gstpvrbufferpool.h" + +GST_DEBUG_CATEGORY_EXTERN (gst_debug_pvrvideosink); +#define GST_CAT_DEFAULT gst_debug_pvrvideosink + +/* + * GstDucatiBuffer + */ + +static GstBufferClass *buffer_parent_class; + +/* Get the original buffer, or whatever is the best output buffer. + * Consumes the input reference, produces the output reference + */ +GstBuffer * +gst_ducati_buffer_get (GstDucatiBuffer * self) +{ + if (self->orig) { + // TODO copy to orig buffer.. if needed. + gst_buffer_unref (self->orig); + self->orig = NULL; + } + return GST_BUFFER (self); +} + +PVR2DMEMINFO * +gst_ducati_buffer_get_meminfo (GstDucatiBuffer * self) +{ + return self->src_mem; +} + + +static GstDucatiBuffer * +gst_ducati_buffer_new (GstPvrBufferPool * pool) +{ + PVR2DERROR pvr_error; + GstDucatiBuffer *self = (GstDucatiBuffer *) + gst_mini_object_new (GST_TYPE_DUCATIBUFFER); + + GST_LOG_OBJECT (pool->element, "creating buffer %p in pool %p", self, pool); + + self->pool = (GstPvrBufferPool *) + gst_mini_object_ref (GST_MINI_OBJECT (pool)); + + GST_BUFFER_DATA (self) = gst_ducati_alloc_1d (pool->size); + GST_BUFFER_SIZE (self) = pool->size; + GST_LOG_OBJECT (pool->element, "width=%d, height=%d and size=%d", + pool->padded_width, pool->padded_height, pool->size); + + pvr_error = + PVR2DMemWrap (pool->pvr_context, GST_BUFFER_DATA (self), 0, pool->size, + NULL, &(self->src_mem)); + if (pvr_error != PVR2D_OK) { + GST_LOG_OBJECT (pool->element, "Failed to Wrap buffer memory" + "returned %d", pvr_error); + } else { + self->wrapped = TRUE; + } + + gst_buffer_set_caps (GST_BUFFER (self), pool->caps); + + return self; +} + + +static void +gst_ducati_buffer_finalize (GstDucatiBuffer * self) +{ + PVR2DERROR pvr_error; + GstPvrBufferPool *pool = self->pool; + gboolean resuscitated = FALSE; + + GST_LOG_OBJECT (pool->element, "finalizing buffer %p", self); + + GST_PVR_BUFFERPOOL_LOCK (pool); + g_queue_remove (pool->used_buffers, self); + if (pool->running) { + resuscitated = TRUE; + + GST_LOG_OBJECT (pool->element, "reviving buffer %p", self); + + g_queue_push_head (pool->free_buffers, self); + } else { + GST_LOG_OBJECT (pool->element, "the pool is shutting down"); + } + GST_PVR_BUFFERPOOL_UNLOCK (pool); + + if (resuscitated) { + GST_LOG_OBJECT (pool->element, "reviving buffer %p, %d", self, index); + gst_buffer_ref (GST_BUFFER (self)); + GST_BUFFER_SIZE (self) = 0; + } + + if (!resuscitated) { + GST_LOG_OBJECT (pool->element, + "buffer %p (data %p, len %u) not recovered, freeing", + self, GST_BUFFER_DATA (self), GST_BUFFER_SIZE (self)); + + if (self->wrapped) { + pvr_error = PVR2DMemFree (pool->pvr_context, self->src_mem); + if (pvr_error != PVR2D_OK) { + GST_ERROR_OBJECT (pool->element, "Failed to Unwrap buffer memory" + "returned %d", pvr_error); + } + self->wrapped = FALSE; + } + MemMgr_Free ((void *) GST_BUFFER_DATA (self)); + GST_BUFFER_DATA (self) = NULL; + gst_mini_object_unref (GST_MINI_OBJECT (pool)); + GST_MINI_OBJECT_CLASS (buffer_parent_class)->finalize (GST_MINI_OBJECT + (self)); + } +} + +static void +gst_ducati_buffer_class_init (gpointer g_class, gpointer class_data) +{ + GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class); + + buffer_parent_class = g_type_class_peek_parent (g_class); + + mini_object_class->finalize = (GstMiniObjectFinalizeFunction) + GST_DEBUG_FUNCPTR (gst_ducati_buffer_finalize); +} + +GType +gst_ducati_buffer_get_type (void) +{ + static GType type; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo info = { + .class_size = sizeof (GstBufferClass), + .class_init = gst_ducati_buffer_class_init, + .instance_size = sizeof (GstDucatiBuffer), + }; + type = g_type_register_static (GST_TYPE_BUFFER, + "GstDucatiBufferPvrsink", &info, 0); + } + return type; +} + +/* + * GstDucatiBufferPool + */ + +static GstMiniObjectClass *bufferpool_parent_class = NULL; + +/** create new bufferpool + * @element : the element that owns this pool + * @caps: the caps to set on the buffer + * @num_buffers: the requested number of buffers in the pool + */ +GstPvrBufferPool * +gst_pvr_bufferpool_new (GstElement * element, GstCaps * caps, gint num_buffers, + gint size, PVR2DCONTEXTHANDLE pvr_context) +{ + GstPvrBufferPool *self = (GstPvrBufferPool *) + gst_mini_object_new (GST_TYPE_PVRBUFFERPOOL); + GstStructure *s = gst_caps_get_structure (caps, 0); + + self->element = gst_object_ref (element); + gst_structure_get_int (s, "width", &self->padded_width); + gst_structure_get_int (s, "height", &self->padded_height); + self->caps = gst_caps_ref (caps); + self->size = size; + self->pvr_context = pvr_context; + + self->free_buffers = g_queue_new (); + self->used_buffers = g_queue_new (); + self->lock = g_mutex_new (); + self->running = TRUE; + + return self; +} + +static void +unwrap_buffer (gpointer buffer, gpointer user_data) +{ + PVR2DERROR pvr_error; + GstDucatiBuffer *buf = GST_DUCATIBUFFER (buffer); + GstPvrBufferPool *pool = (GstPvrBufferPool *) user_data; + + if (buf->wrapped) { + pvr_error = PVR2DMemFree (pool->pvr_context, buf->src_mem); + if (pvr_error != PVR2D_OK) { + GST_ERROR_OBJECT (pool->element, "Failed to Unwrap buffer memory" + "returned %d", pvr_error); + } + buf->wrapped = FALSE; + } +} + +void +gst_pvr_bufferpool_stop_running (GstPvrBufferPool * self, gboolean unwrap) +{ + gboolean empty = FALSE; + + g_return_if_fail (self); + + GST_PVR_BUFFERPOOL_LOCK (self); + self->running = FALSE; + GST_PVR_BUFFERPOOL_UNLOCK (self); + + GST_DEBUG_OBJECT (self->element, "free available buffers"); + + /* free all buffers on the freelist */ + while (!empty) { + GstDucatiBuffer *buf; + GST_PVR_BUFFERPOOL_LOCK (self); + buf = g_queue_pop_head (self->free_buffers); + GST_PVR_BUFFERPOOL_UNLOCK (self); + if (buf) + gst_buffer_unref (GST_BUFFER (buf)); + else + empty = TRUE; + } + + if (unwrap) + g_queue_foreach (self->used_buffers, unwrap_buffer, self); + + gst_mini_object_unref (GST_MINI_OBJECT (self)); +} + +/** get buffer from bufferpool, allocate new buffer if needed */ +GstDucatiBuffer * +gst_pvr_bufferpool_get (GstPvrBufferPool * self, GstBuffer * orig) +{ + GstDucatiBuffer *buf = NULL; + + g_return_val_if_fail (self, NULL); + + GST_PVR_BUFFERPOOL_LOCK (self); + if (self->running) { + /* re-use a buffer off the freelist if any are available + */ + buf = g_queue_pop_head (self->free_buffers); + if (!buf) + buf = gst_ducati_buffer_new (self); + buf->orig = orig; + g_queue_push_head (self->used_buffers, buf); + } + GST_PVR_BUFFERPOOL_UNLOCK (self); + + if (buf && orig) { + GST_BUFFER_TIMESTAMP (buf) = GST_BUFFER_TIMESTAMP (orig); + GST_BUFFER_DURATION (buf) = GST_BUFFER_DURATION (orig); + } + GST_BUFFER_SIZE (buf) = self->size; + + return buf; +} + +static void +gst_pvr_bufferpool_finalize (GstPvrBufferPool * self) +{ + GST_DEBUG_OBJECT (self->element, "destroy bufferpool"); + g_mutex_free (self->lock); + self->lock = NULL; + + g_queue_free (self->free_buffers); + self->free_buffers = NULL; + g_queue_free (self->used_buffers); + self->used_buffers = NULL; + + gst_caps_unref (self->caps); + self->caps = NULL; + gst_object_unref (self->element); + self->element = NULL; + + GST_MINI_OBJECT_CLASS (bufferpool_parent_class)->finalize (GST_MINI_OBJECT + (self)); +} + +static void +gst_pvr_bufferpool_class_init (gpointer g_class, gpointer class_data) +{ + GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class); + + bufferpool_parent_class = g_type_class_peek_parent (g_class); + + mini_object_class->finalize = (GstMiniObjectFinalizeFunction) + GST_DEBUG_FUNCPTR (gst_pvr_bufferpool_finalize); +} + +GType +gst_pvr_bufferpool_get_type (void) +{ + static GType type; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo info = { + .class_size = sizeof (GstMiniObjectClass), + .class_init = gst_pvr_bufferpool_class_init, + .instance_size = sizeof (GstPvrBufferPool), + }; + type = g_type_register_static (GST_TYPE_MINI_OBJECT, + "GstPvrBufferPool", &info, 0); + } + return type; +} diff --git a/sys/pvr2d/gstpvrbufferpool.h b/sys/pvr2d/gstpvrbufferpool.h new file mode 100644 index 0000000000..1d90472b64 --- /dev/null +++ b/sys/pvr2d/gstpvrbufferpool.h @@ -0,0 +1,89 @@ +/* + * GStreamer + * Copyright (c) 2010, 2011 Texas Instruments Incorporated + * Copyright (c) 2011, Collabora Ltda + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation + * version 2.1 of the License. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __GSTPVRBUFFERPOOL_H__ +#define __GSTPVRBUFFERPOOL_H__ + +#include "gstpvr.h" +#include + +G_BEGIN_DECLS + +GType gst_ducati_buffer_get_type (void); +#define GST_TYPE_DUCATIBUFFER (gst_ducati_buffer_get_type()) +#define GST_IS_DUCATIBUFFER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_DUCATIBUFFER)) +#define GST_DUCATIBUFFER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_DUCATIBUFFER, GstDucatiBuffer)) + +GType gst_pvr_bufferpool_get_type (void); +#define GST_TYPE_PVRBUFFERPOOL (gst_pvr_bufferpool_get_type()) +#define GST_IS_PVRBUFFERPOOL(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PVRBUFFERPOOL)) +#define GST_PVRBUFFERPOOL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PVRBUFFERPOOL, \ + GstPvrBufferPool)) + +typedef struct _GstPvrBufferPool GstPvrBufferPool; +typedef struct _GstDucatiBuffer GstDucatiBuffer; + +struct _GstPvrBufferPool +{ + GstMiniObject parent; + + /* output (padded) size including any codec padding: */ + gint padded_width, padded_height; + gint size; + PVR2DCONTEXTHANDLE pvr_context; + + GstCaps *caps; + GMutex *lock; + gboolean running; /* with lock */ + GstElement *element; /* the element that owns us.. */ + GQueue *free_buffers; + GQueue *used_buffers; + guint buffer_count; +}; + +GstPvrBufferPool * gst_pvr_bufferpool_new (GstElement * element, + GstCaps * caps, gint num_buffers, gint size, + PVR2DCONTEXTHANDLE pvr_context); +void gst_pvr_bufferpool_stop_running (GstPvrBufferPool * pool, gboolean unwrap); +GstDucatiBuffer * gst_pvr_bufferpool_get (GstPvrBufferPool * self, + GstBuffer * orig); + +#define GST_PVR_BUFFERPOOL_LOCK(self) g_mutex_lock ((self)->lock) +#define GST_PVR_BUFFERPOOL_UNLOCK(self) g_mutex_unlock ((self)->lock) + +struct _GstDucatiBuffer { + GstBuffer parent; + + GstPvrBufferPool *pool; /* buffer-pool that this buffer belongs to */ + GstBuffer *orig; /* original buffer, if we need to copy output */ + PVR2DMEMINFO *src_mem; /* Memory wrapped by pvr */ + gboolean wrapped; +}; + +GstBuffer * gst_ducati_buffer_get (GstDucatiBuffer * self); +PVR2DMEMINFO * gst_ducati_buffer_get_meminfo (GstDucatiBuffer * self); + +G_END_DECLS + +#endif /* __GSTPVRBUFFERPOOL_H__ */ diff --git a/sys/pvr2d/gstpvrvideosink.c b/sys/pvr2d/gstpvrvideosink.c new file mode 100644 index 0000000000..3bfa3ad2df --- /dev/null +++ b/sys/pvr2d/gstpvrvideosink.c @@ -0,0 +1,1548 @@ +/* GStreamer + * + * Copyright (C) 2011 Collabora Ltda + * Copyright (C) 2011 Texas Instruments + * @author: Luciana Fujii Pontello + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* Object header */ +#include "gstpvrvideosink.h" + +#include "gstpvrbufferpool.h" +#include +#include + +/* Debugging category */ +#include + +#define LINUX +#include +#include +#include +#include + +#define DEFAULT_QUEUE_SIZE 12 +#define DEFAULT_MIN_QUEUED_BUFS 1 + +GST_DEBUG_CATEGORY_EXTERN (gst_debug_pvrvideosink); +#define GST_CAT_DEFAULT gst_debug_pvrvideosink + +#define PVR2DMEMINFO_INITIALISE(d, s) \ +{ \ + (d)->hPrivateData = (IMG_VOID *)(s); \ + (d)->hPrivateMapData = (IMG_VOID *)(s->hKernelMemInfo); \ + (d)->ui32DevAddr = (IMG_UINT32) (s)->sDevVAddr.uiAddr; \ + (d)->ui32MemSize = (s)->uAllocSize; \ + (d)->pBase = (s)->pvLinAddr;\ + (d)->ulFlags = (s)->ui32Flags;\ +} + +/* end of internal definitions */ + +static void gst_pvrvideosink_reset (GstPVRVideoSink * pvrvideosink); +static GstFlowReturn gst_pvrvideosink_buffer_alloc (GstBaseSink * bsink, + guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf); +static void gst_pvrvideosink_xwindow_draw_borders (GstPVRVideoSink * + pvrvideosink, GstXWindow * xwindow, GstVideoRectangle rect); +static void gst_pvrvideosink_expose (GstXOverlay * overlay); +static void gst_pvrvideosink_xwindow_destroy (GstPVRVideoSink * pvrvideosink, + GstXWindow * xwindow); + +static GstStaticPadTemplate gst_pvrvideosink_sink_template_factory = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-raw-yuv, " + "format = (fourcc) NV12, " + "width = " GST_VIDEO_SIZE_RANGE ", " + "height = " GST_VIDEO_SIZE_RANGE ", " + "framerate = " GST_VIDEO_FPS_RANGE)); + +enum +{ + PROP_0, + PROP_FORCE_ASPECT_RATIO, + PROP_WINDOW_WIDTH, + PROP_WINDOW_HEIGHT +}; + +static GstVideoSinkClass *parent_class = NULL; + +/* ============================================================= */ +/* */ +/* Private Methods */ +/* */ +/* ============================================================= */ + +/* pvrvideo buffers */ + +#define GST_TYPE_PVRVIDEO_BUFFER (gst_pvrvideo_buffer_get_type()) + +#define GST_IS_PVRVIDEO_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_PVRVIDEO_BUFFER)) +#define GST_PVRVIDEO_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_PVRVIDEO_BUFFER, GstPVRVideoBuffer)) +#define GST_PVRVIDEO_BUFFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_PVRVIDEO_BUFFER, GstPVRVideoBufferClass)) + +static void +gst_pvrvideosink_xwindow_update_geometry (GstPVRVideoSink * pvrvideosink) +{ + XWindowAttributes attr; + WSEGLError glerror; + WSEGLDrawableParams source_params; + PVRSRV_CLIENT_MEM_INFO *client_mem_info; + + /* Update the window geometry */ + g_mutex_lock (pvrvideosink->dcontext->x_lock); + if (G_UNLIKELY (pvrvideosink->xwindow == NULL)) { + g_mutex_unlock (pvrvideosink->dcontext->x_lock); + return; + } + pvrvideosink->redraw_borders = TRUE; + + XGetWindowAttributes (pvrvideosink->dcontext->x_display, + pvrvideosink->xwindow->window, &attr); + + pvrvideosink->xwindow->width = attr.width; + pvrvideosink->xwindow->height = attr.height; + + if (!pvrvideosink->have_render_rect) { + pvrvideosink->render_rect.x = pvrvideosink->render_rect.y = 0; + pvrvideosink->render_rect.w = attr.width; + pvrvideosink->render_rect.h = attr.height; + } + if (pvrvideosink->dcontext != NULL) { + glerror = + pvrvideosink->dcontext-> + wsegl_table->pfnWSEGL_DeleteDrawable (pvrvideosink->dcontext-> + drawable_handle); + if (glerror != WSEGL_SUCCESS) { + GST_ERROR_OBJECT (pvrvideosink, "Error destroying drawable"); + return; + } + glerror = + pvrvideosink->dcontext-> + wsegl_table->pfnWSEGL_CreateWindowDrawable (pvrvideosink->dcontext-> + display_handle, pvrvideosink->dcontext->glconfig, + &pvrvideosink->dcontext->drawable_handle, + (NativeWindowType) pvrvideosink->xwindow->window, + &pvrvideosink->dcontext->rotation); + if (glerror != WSEGL_SUCCESS) { + GST_ERROR_OBJECT (pvrvideosink, "Error creating drawable"); + return; + } + glerror = + pvrvideosink->dcontext-> + wsegl_table->pfnWSEGL_GetDrawableParameters (pvrvideosink->dcontext-> + drawable_handle, &source_params, &pvrvideosink->render_params); + if (glerror != WSEGL_SUCCESS) { + GST_ERROR_OBJECT (pvrvideosink, "Error getting Drawable params"); + return; + } + + client_mem_info = + (PVRSRV_CLIENT_MEM_INFO *) pvrvideosink->render_params.hPrivateData; + PVR2DMEMINFO_INITIALISE (&pvrvideosink->dcontext->dst_mem, client_mem_info); + } + + g_mutex_unlock (pvrvideosink->dcontext->x_lock); +} + +/* This function handles XEvents that might be in the queue. It generates + GstEvent that will be sent upstream in the pipeline to handle interactivity + and navigation. It will also listen for configure events on the window to + trigger caps renegotiation so on the fly software scaling can work. */ +static void +gst_pvrvideosink_handle_xevents (GstPVRVideoSink * pvrvideosink) +{ + XEvent e; + gboolean exposed = FALSE; + gboolean configured = FALSE; + + g_mutex_lock (pvrvideosink->flow_lock); + g_mutex_lock (pvrvideosink->dcontext->x_lock); + + /* Handle Expose */ + while (XCheckWindowEvent (pvrvideosink->dcontext->x_display, + pvrvideosink->xwindow->window, ExposureMask | StructureNotifyMask, + &e)) { + switch (e.type) { + case Expose: + exposed = TRUE; + break; + case ConfigureNotify: + g_mutex_unlock (pvrvideosink->dcontext->x_lock); + gst_pvrvideosink_xwindow_update_geometry (pvrvideosink); + g_mutex_lock (pvrvideosink->dcontext->x_lock); + configured = TRUE; + break; + default: + break; + } + } + + if (exposed || configured) { + g_mutex_unlock (pvrvideosink->dcontext->x_lock); + g_mutex_unlock (pvrvideosink->flow_lock); + + gst_pvrvideosink_expose (GST_X_OVERLAY (pvrvideosink)); + + g_mutex_lock (pvrvideosink->flow_lock); + g_mutex_lock (pvrvideosink->dcontext->x_lock); + } + + /* Handle Display events */ + while (XPending (pvrvideosink->dcontext->x_display)) { + XNextEvent (pvrvideosink->dcontext->x_display, &e); + + switch (e.type) { + case ClientMessage:{ + Atom wm_delete; + + wm_delete = XInternAtom (pvrvideosink->dcontext->x_display, + "WM_DELETE_WINDOW", True); + if (wm_delete != None && wm_delete == (Atom) e.xclient.data.l[0]) { + /* Handle window deletion by posting an error on the bus */ + GST_ELEMENT_ERROR (pvrvideosink, RESOURCE, NOT_FOUND, + ("Output window was closed"), (NULL)); + + g_mutex_unlock (pvrvideosink->dcontext->x_lock); + gst_pvrvideosink_xwindow_destroy (pvrvideosink, + pvrvideosink->xwindow); + pvrvideosink->xwindow = NULL; + g_mutex_lock (pvrvideosink->dcontext->x_lock); + } + break; + } + default: + break; + } + } + + g_mutex_unlock (pvrvideosink->dcontext->x_lock); + g_mutex_unlock (pvrvideosink->flow_lock); +} + +static gpointer +gst_pvrvideosink_event_thread (GstPVRVideoSink * pvrvideosink) +{ + GST_OBJECT_LOCK (pvrvideosink); + while (pvrvideosink->running) { + GST_OBJECT_UNLOCK (pvrvideosink); + + if (pvrvideosink->xwindow) { + gst_pvrvideosink_handle_xevents (pvrvideosink); + } + g_usleep (G_USEC_PER_SEC / 20); + + GST_OBJECT_LOCK (pvrvideosink); + } + GST_OBJECT_UNLOCK (pvrvideosink); + + return NULL; +} + +static void +gst_pvrvideosink_manage_event_thread (GstPVRVideoSink * pvrvideosink) +{ + GThread *thread = NULL; + + /* don't start the thread too early */ + if (pvrvideosink->dcontext == NULL) { + return; + } + + GST_OBJECT_LOCK (pvrvideosink); + if (!pvrvideosink->event_thread) { + /* Setup our event listening thread */ + GST_DEBUG_OBJECT (pvrvideosink, "run xevent thread"); + pvrvideosink->running = TRUE; + pvrvideosink->event_thread = g_thread_create ( + (GThreadFunc) gst_pvrvideosink_event_thread, pvrvideosink, TRUE, NULL); + } + GST_OBJECT_UNLOCK (pvrvideosink); + + /* Wait for our event thread to finish */ + if (thread) + g_thread_join (thread); +} + + +static GstDrawContext * +gst_pvrvideosink_get_dcontext (GstPVRVideoSink * pvrvideosink) +{ + GstDrawContext *dcontext; + PVR2DERROR pvr_error; + gint refresh_rate; + DRI2WSDisplay *displayImpl; + WSEGLError glerror; + const WSEGLCaps *glcaps; + + dcontext = g_new0 (GstDrawContext, 1); + dcontext->p_blt_info = 0; + dcontext->x_lock = g_mutex_new (); + + dcontext->p_blt_info = g_new0 (PVR2D_3DBLT_EXT, 1); + if (!dcontext->p_blt_info) { + GST_ERROR_OBJECT (pvrvideosink, "Alloc of bltinfo failed"); + return NULL; + } + dcontext->p_blt2d_info = g_new0 (PVR2DBLTINFO, 1); + + dcontext->x_display = XOpenDisplay (NULL); + + dcontext->wsegl_table = WSEGL_GetFunctionTablePointer (); + glerror = dcontext->wsegl_table->pfnWSEGL_IsDisplayValid ( + (NativeDisplayType) dcontext->x_display); + + if (glerror != WSEGL_SUCCESS) { + GST_ERROR_OBJECT (pvrvideosink, "Display is not valid"); + return NULL; + } + + glerror = dcontext->wsegl_table->pfnWSEGL_InitialiseDisplay ( + (NativeDisplayType) dcontext->x_display, &dcontext->display_handle, + &glcaps, &dcontext->glconfig); + if (glerror != WSEGL_SUCCESS) { + GST_ERROR_OBJECT (pvrvideosink, "Error initializing display"); + return NULL; + } + + displayImpl = (DRI2WSDisplay *) dcontext->display_handle; + dcontext->pvr_context = displayImpl->hContext; + + pvr_error = PVR2DGetScreenMode (dcontext->pvr_context, + &dcontext->display_format, &dcontext->display_width, + &dcontext->display_height, &dcontext->stride, &refresh_rate); + if (pvr_error != PVR2D_OK) { + GST_ERROR_OBJECT (pvrvideosink, "Failed) to get screen mode" + "returned %d", pvr_error); + return NULL; + } + dcontext->screen_num = DefaultScreen (dcontext->x_display); + dcontext->black = XBlackPixel (dcontext->x_display, dcontext->screen_num); + + return dcontext; +} + +static void +gst_pvrvideosink_xwindow_set_title (GstPVRVideoSink * pvrvideosink, + GstXWindow * xwindow, const gchar * media_title) +{ + if (media_title) { + g_free (pvrvideosink->media_title); + pvrvideosink->media_title = g_strdup (media_title); + } + if (xwindow) { + /* we have a window */ + if (xwindow->internal) { + XTextProperty xproperty; + const gchar *app_name; + const gchar *title = NULL; + gchar *title_mem = NULL; + + /* set application name as a title */ + app_name = g_get_application_name (); + + if (app_name && pvrvideosink->media_title) { + title = title_mem = g_strconcat (pvrvideosink->media_title, " : ", + app_name, NULL); + } else if (app_name) { + title = app_name; + } else if (pvrvideosink->media_title) { + title = pvrvideosink->media_title; + } + + if (title) { + if ((XStringListToTextProperty (((char **) &title), 1, + &xproperty)) != 0) { + XSetWMName (pvrvideosink->dcontext->x_display, xwindow->window, + &xproperty); + XFree (xproperty.value); + } + + g_free (title_mem); + } + } + } +} + +static GstXWindow * +gst_pvrvideosink_create_window (GstPVRVideoSink * pvrvideosink, gint width, + gint height) +{ + WSEGLError glerror; + WSEGLDrawableParams source_params; + Window root; + GstXWindow *xwindow; + GstDrawContext *dcontext; + XGCValues values; + Atom wm_delete; + PVRSRV_CLIENT_MEM_INFO *client_mem_info; + + GST_DEBUG_OBJECT (pvrvideosink, "begin"); + + dcontext = pvrvideosink->dcontext; + xwindow = g_new0 (GstXWindow, 1); + + xwindow->internal = TRUE; + pvrvideosink->render_rect.x = pvrvideosink->render_rect.y = 0; + pvrvideosink->render_rect.w = width; + pvrvideosink->render_rect.h = height; + xwindow->width = width; + xwindow->height = height; + xwindow->internal = TRUE; + + g_mutex_lock (pvrvideosink->dcontext->x_lock); + + root = DefaultRootWindow (dcontext->x_display); + xwindow->window = XCreateSimpleWindow (dcontext->x_display, root, 0, 0, + width, height, 2, 2, pvrvideosink->dcontext->black); + XSelectInput (dcontext->x_display, xwindow->window, + ExposureMask | StructureNotifyMask); + + /* Tell the window manager we'd like delete client messages instead of + * being killed */ + wm_delete = XInternAtom (pvrvideosink->dcontext->x_display, + "WM_DELETE_WINDOW", True); + if (wm_delete != None) { + (void) XSetWMProtocols (pvrvideosink->dcontext->x_display, xwindow->window, + &wm_delete, 1); + } + + XMapWindow (dcontext->x_display, xwindow->window); + + /* We have to do that to prevent X from redrawing the background on + * ConfigureNotify. This takes away flickering of video when resizing. */ + XSetWindowBackgroundPixmap (pvrvideosink->dcontext->x_display, + xwindow->window, None); + + gst_pvrvideosink_xwindow_set_title (pvrvideosink, xwindow, NULL); + + xwindow->gc = XCreateGC (pvrvideosink->dcontext->x_display, + xwindow->window, 0, &values); + + g_mutex_unlock (pvrvideosink->dcontext->x_lock); + + glerror = + dcontext->wsegl_table->pfnWSEGL_CreateWindowDrawable (dcontext-> + display_handle, dcontext->glconfig, &(dcontext->drawable_handle), + (NativeWindowType) xwindow->window, &(dcontext->rotation)); + + if (glerror != WSEGL_SUCCESS) { + GST_ERROR_OBJECT (pvrvideosink, "Error creating drawable"); + return NULL; + } + glerror = + dcontext->wsegl_table->pfnWSEGL_GetDrawableParameters (dcontext-> + drawable_handle, &source_params, &pvrvideosink->render_params); + client_mem_info = + (PVRSRV_CLIENT_MEM_INFO *) pvrvideosink->render_params.hPrivateData; + PVR2DMEMINFO_INITIALISE (&dcontext->dst_mem, client_mem_info); + + GST_DEBUG_OBJECT (pvrvideosink, "end"); + return xwindow; +} + +static void +gst_pvrvideosink_blit (GstPVRVideoSink * pvrvideosink, GstBuffer * buffer) +{ + PVR2DERROR pvr_error; + GstDrawContext *dcontext = pvrvideosink->dcontext; + GstCaps *caps; + GstStructure *structure; + gint video_width; + gint video_height; + gboolean ret; + gboolean draw_border = FALSE; + PPVR2D_3DBLT_EXT p_blt_3d; + PVR2DMEMINFO *src_mem; + PVR2DFORMAT pvr_format = pvrvideosink->format == GST_VIDEO_FORMAT_NV12 ? + PVR2D_YUV420_2PLANE : PVR2D_ARGB8888; + GstVideoRectangle result; + + GST_DEBUG_OBJECT (pvrvideosink, "begin"); + g_mutex_lock (pvrvideosink->flow_lock); + if (buffer == NULL) + buffer = pvrvideosink->current_buffer; + + if (buffer == NULL) { + g_mutex_unlock (pvrvideosink->flow_lock); + return; + } + + caps = GST_BUFFER_CAPS (buffer); + src_mem = gst_ducati_buffer_get_meminfo ((GstDucatiBuffer *) buffer); + p_blt_3d = dcontext->p_blt_info; + + structure = gst_caps_get_structure (caps, 0); + ret = gst_structure_get_int (structure, "width", &video_width); + ret &= gst_structure_get_int (structure, "height", &video_height); + if (!ret) { + GST_ERROR_OBJECT (pvrvideosink, "Failed to get dimensions of the buffer"); + goto done; + } + + g_mutex_lock (pvrvideosink->dcontext->x_lock); + + /* Draw borders when displaying the first frame. After this + draw borders only on expose event or after a size change. */ + if (!(pvrvideosink->current_buffer) || pvrvideosink->redraw_borders) { + draw_border = TRUE; + } + + /* Store a reference to the last image we put, lose the previous one */ + if (buffer && pvrvideosink->current_buffer != buffer) { + if (pvrvideosink->current_buffer) { + GST_LOG_OBJECT (pvrvideosink, "unreffing %p", + pvrvideosink->current_buffer); + gst_buffer_unref (GST_BUFFER_CAST (pvrvideosink->current_buffer)); + } + GST_LOG_OBJECT (pvrvideosink, "reffing %p as our current buffer", buffer); + pvrvideosink->current_buffer = gst_buffer_ref (buffer); + } + + if (pvrvideosink->keep_aspect) { + GstVideoRectangle src, dst; + + src.w = GST_VIDEO_SINK_WIDTH (pvrvideosink); + src.h = GST_VIDEO_SINK_HEIGHT (pvrvideosink); + dst.w = pvrvideosink->render_rect.w; + dst.h = pvrvideosink->render_rect.h; + gst_video_sink_center_rect (src, dst, &result, TRUE); + result.x += pvrvideosink->render_rect.x; + result.y += pvrvideosink->render_rect.y; + } else { + memcpy (&result, &pvrvideosink->render_rect, sizeof (GstVideoRectangle)); + } + + p_blt_3d->sDst.pSurfMemInfo = &dcontext->dst_mem; + p_blt_3d->sDst.SurfOffset = 0; + p_blt_3d->sDst.Stride = + gst_video_format_get_row_stride (GST_VIDEO_FORMAT_BGRx, 0, + pvrvideosink->render_params.ui32Stride); + p_blt_3d->sDst.Format = PVR2D_ARGB8888; + p_blt_3d->sDst.SurfWidth = pvrvideosink->xwindow->width; + p_blt_3d->sDst.SurfHeight = pvrvideosink->xwindow->height; + + p_blt_3d->rcDest.left = result.x; + p_blt_3d->rcDest.top = result.y; + p_blt_3d->rcDest.right = result.w + result.x; + p_blt_3d->rcDest.bottom = result.h + result.y; + + p_blt_3d->sSrc.pSurfMemInfo = src_mem; + p_blt_3d->sSrc.SurfOffset = 0; + p_blt_3d->sSrc.Stride = pvrvideosink->rowstride; + p_blt_3d->sSrc.Format = pvr_format; + p_blt_3d->sSrc.SurfWidth = video_width; + p_blt_3d->sSrc.SurfHeight = video_height; + + p_blt_3d->rcSource.left = 0; + p_blt_3d->rcSource.top = 0; + p_blt_3d->rcSource.right = video_width; + p_blt_3d->rcSource.bottom = video_height; + + p_blt_3d->hUseCode = NULL; + + if (pvrvideosink->format == GST_VIDEO_FORMAT_NV12) + p_blt_3d->bDisableDestInput = TRUE; + else + /* blit fails for RGB without this... not sure why yet... */ + p_blt_3d->bDisableDestInput = FALSE; + + pvr_error = PVR2DBlt3DExt (pvrvideosink->dcontext->pvr_context, + dcontext->p_blt_info); + + switch (pvr_error) { + case PVR2D_OK: + break; + case PVR2DERROR_DEVICE_UNAVAILABLE: + GST_ERROR_OBJECT (pvrvideosink, "Failed to blit, device unavailable"); + goto done; + break; + case PVR2DERROR_INVALID_CONTEXT: + GST_ERROR_OBJECT (pvrvideosink, "Failed to blit, invalid context"); + goto done; + break; + case PVR2DERROR_INVALID_PARAMETER: + GST_ERROR_OBJECT (pvrvideosink, "Failed to blit, invalid parameter"); + goto done; + break; + case PVR2DERROR_HW_FEATURE_NOT_SUPPORTED: + GST_ERROR_OBJECT (pvrvideosink, "Failed to blit, " + "hardware feature not supported"); + goto done; + break; + case PVR2DERROR_GENERIC_ERROR: + GST_ERROR_OBJECT (pvrvideosink, "Failed to blit, generic error"); + goto done; + break; + default: + GST_ERROR_OBJECT (pvrvideosink, "Failed to blit, " + "undefined error %d", pvr_error); + goto done; + break; + } + dcontext->wsegl_table->pfnWSEGL_SwapDrawable (dcontext->drawable_handle, 1); + + if (draw_border) { + gst_pvrvideosink_xwindow_draw_borders (pvrvideosink, pvrvideosink->xwindow, + result); + pvrvideosink->redraw_borders = FALSE; + } + g_mutex_unlock (pvrvideosink->dcontext->x_lock); + +done: + GST_DEBUG_OBJECT (pvrvideosink, "end"); + g_mutex_unlock (pvrvideosink->flow_lock); +} + +static void +gst_pvrvideosink_destroy_drawable (GstPVRVideoSink * pvrvideosink) +{ + if (pvrvideosink->dcontext != NULL) { + if (pvrvideosink->dcontext->drawable_handle) + pvrvideosink->dcontext-> + wsegl_table->pfnWSEGL_DeleteDrawable (pvrvideosink->dcontext-> + drawable_handle); + + pvrvideosink->dcontext->wsegl_table->pfnWSEGL_CloseDisplay (pvrvideosink-> + dcontext->display_handle); + } +} + +/* We are called with the x_lock taken */ +static void +gst_pvrvideosink_pvrfill_rectangle (GstPVRVideoSink * pvrvideosink, + GstVideoRectangle rect) +{ + PVR2DERROR pvr_error; + PPVR2DBLTINFO p_blt2d_info = 0; + GstDrawContext *dcontext = pvrvideosink->dcontext; + + GST_DEBUG_OBJECT (pvrvideosink, "begin"); + + p_blt2d_info = dcontext->p_blt2d_info; + + p_blt2d_info->pDstMemInfo = &dcontext->dst_mem; + p_blt2d_info->BlitFlags = PVR2D_BLIT_DISABLE_ALL; + p_blt2d_info->DstOffset = 0; + p_blt2d_info->CopyCode = PVR2DROPclear; + p_blt2d_info->DstStride = + gst_video_format_get_row_stride (GST_VIDEO_FORMAT_BGRx, 0, + pvrvideosink->render_params.ui32Stride); + p_blt2d_info->DstFormat = PVR2D_ARGB8888; + p_blt2d_info->DstSurfWidth = pvrvideosink->xwindow->width; + p_blt2d_info->DstSurfHeight = pvrvideosink->xwindow->height; + p_blt2d_info->DstX = rect.x; + p_blt2d_info->DstY = rect.y; + p_blt2d_info->DSizeX = rect.w; + p_blt2d_info->DSizeY = rect.h; + + pvr_error = PVR2DBlt (pvrvideosink->dcontext->pvr_context, p_blt2d_info); + + switch (pvr_error) { + case PVR2D_OK: + break; + case PVR2DERROR_DEVICE_UNAVAILABLE: + GST_ERROR_OBJECT (pvrvideosink, "Failed to blit, device unavailable"); + goto done; + break; + case PVR2DERROR_INVALID_CONTEXT: + GST_ERROR_OBJECT (pvrvideosink, "Failed to blit, invalid context"); + goto done; + break; + case PVR2DERROR_INVALID_PARAMETER: + GST_ERROR_OBJECT (pvrvideosink, "Failed to blit, invalid parameter"); + goto done; + break; + case PVR2DERROR_HW_FEATURE_NOT_SUPPORTED: + GST_ERROR_OBJECT (pvrvideosink, "Failed to blit, " + "hardware feature not supported"); + goto done; + break; + case PVR2DERROR_GENERIC_ERROR: + GST_ERROR_OBJECT (pvrvideosink, "Failed to blit, generic error"); + goto done; + break; + default: + GST_ERROR_OBJECT (pvrvideosink, "Failed to blit, " + "undefined error %d", pvr_error); + goto done; + break; + } + dcontext->wsegl_table->pfnWSEGL_SwapDrawable (dcontext->drawable_handle, 1); + +done: + GST_DEBUG_OBJECT (pvrvideosink, "end"); +} + +/* We are called with the x_lock taken */ +static void +gst_pvrvideosink_xwindow_draw_borders (GstPVRVideoSink * pvrvideosink, + GstXWindow * xwindow, GstVideoRectangle rect) +{ + gint t1, t2; + GstVideoRectangle result; + + g_return_if_fail (GST_IS_PVRVIDEOSINK (pvrvideosink)); + g_return_if_fail (xwindow != NULL); + + /* Left border */ + result.x = pvrvideosink->render_rect.x; + result.y = pvrvideosink->render_rect.y; + result.w = rect.x - pvrvideosink->render_rect.x; + result.h = pvrvideosink->render_rect.h; + if (rect.x > pvrvideosink->render_rect.x) + gst_pvrvideosink_pvrfill_rectangle (pvrvideosink, result); + + /* Right border */ + t1 = rect.x + rect.w; + t2 = pvrvideosink->render_rect.x + pvrvideosink->render_rect.w; + result.x = t1; + result.y = pvrvideosink->render_rect.y; + result.w = t2 - t1; + result.h = pvrvideosink->render_rect.h; + if (t1 < t2) + gst_pvrvideosink_pvrfill_rectangle (pvrvideosink, result); + + /* Top border */ + result.x = pvrvideosink->render_rect.x; + result.y = pvrvideosink->render_rect.y; + result.w = pvrvideosink->render_rect.w; + result.h = rect.y - pvrvideosink->render_rect.y; + if (rect.y > pvrvideosink->render_rect.y) + gst_pvrvideosink_pvrfill_rectangle (pvrvideosink, result); + + /* Bottom border */ + t1 = rect.y + rect.h; + t2 = pvrvideosink->render_rect.y + pvrvideosink->render_rect.h; + result.x = pvrvideosink->render_rect.x; + result.y = t1; + result.w = pvrvideosink->render_rect.w; + result.h = t2 - t1; + if (t1 < t2) + gst_pvrvideosink_pvrfill_rectangle (pvrvideosink, result); +} + +/* Element stuff */ + +static gboolean +gst_pvrvideosink_setcaps (GstBaseSink * bsink, GstCaps * caps) +{ + GstPVRVideoSink *pvrvideosink; + gboolean ret = TRUE; + GstStructure *structure; + gint new_width, new_height; + const GValue *fps; + GstQuery *query; + + pvrvideosink = GST_PVRVIDEOSINK (bsink); + + GST_DEBUG_OBJECT (pvrvideosink, + "sinkconnect possible caps with given caps %", caps); + + structure = gst_caps_get_structure (caps, 0); + + ret = gst_video_format_parse_caps_strided (caps, &pvrvideosink->format, + &new_width, &new_height, &pvrvideosink->rowstride); + if (pvrvideosink->rowstride == 0) + pvrvideosink->rowstride = + gst_video_format_get_row_stride (pvrvideosink->format, 0, new_width); + fps = gst_structure_get_value (structure, "framerate"); + ret &= (fps != NULL); + if (!ret) { + GST_ERROR_OBJECT (pvrvideosink, "problem at parsing caps"); + return FALSE; + } + + if (pvrvideosink->current_caps) { + GST_DEBUG_OBJECT (pvrvideosink, "already have caps set"); + if (gst_caps_is_equal (pvrvideosink->current_caps, caps)) { + GST_DEBUG_OBJECT (pvrvideosink, "caps are equal!"); + return TRUE; + } + GST_DEBUG_OBJECT (pvrvideosink, "caps are different"); + } + + g_mutex_lock (pvrvideosink->pool_lock); + if (pvrvideosink->buffer_pool) { + if (!gst_caps_is_equal (pvrvideosink->buffer_pool->caps, caps)) { + GST_INFO_OBJECT (pvrvideosink, "in set caps, pool->caps != caps"); + gst_pvr_bufferpool_stop_running (pvrvideosink->buffer_pool, FALSE); + pvrvideosink->buffer_pool = NULL; + } + } + g_mutex_unlock (pvrvideosink->pool_lock); + + /* query to find if anyone upstream using these buffers has any + * minimum requirements: + */ + query = gst_query_new_buffers (caps); + if (gst_element_query (GST_ELEMENT (pvrvideosink), query)) { + gint min_buffers; + + gst_query_parse_buffers_count (query, &min_buffers); + + GST_DEBUG_OBJECT (pvrvideosink, "min_buffers=%d", min_buffers); + + /* XXX need to account for some buffers used by queue, etc.. probably + * queue should handle query, pass on to sink pad, and then add some + * number of buffers to the min, so this value is dynamic depending + * on the pipeline? + */ + if (min_buffers != -1) { + min_buffers += 3 + pvrvideosink->min_queued_bufs; + pvrvideosink->num_buffers_can_change = FALSE; + } + + if (min_buffers > pvrvideosink->num_buffers) { + pvrvideosink->num_buffers = min_buffers; + } + } + gst_query_unref (query); + + /* Notify application to set xwindow id now */ + g_mutex_lock (pvrvideosink->flow_lock); + if (!pvrvideosink->xwindow) { + g_mutex_unlock (pvrvideosink->flow_lock); + gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (pvrvideosink)); + } else { + g_mutex_unlock (pvrvideosink->flow_lock); + } + GST_VIDEO_SINK_WIDTH (pvrvideosink) = new_width; + GST_VIDEO_SINK_HEIGHT (pvrvideosink) = new_height; + + g_mutex_lock (pvrvideosink->flow_lock); + if (!pvrvideosink->xwindow) + pvrvideosink->xwindow = gst_pvrvideosink_create_window (pvrvideosink, + new_width, new_height); + g_mutex_unlock (pvrvideosink->flow_lock); + + pvrvideosink->fps_n = gst_value_get_fraction_numerator (fps); + pvrvideosink->fps_d = gst_value_get_fraction_denominator (fps); + + pvrvideosink->current_caps = gst_caps_ref (caps); + + return TRUE; +} + +static GstCaps * +gst_pvrvideosink_getcaps (GstBaseSink * bsink) +{ + GstPVRVideoSink *pvrvideosink; + GstCaps *caps; + + pvrvideosink = GST_PVRVIDEOSINK (bsink); + + caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK + (pvrvideosink)->sinkpad)); + return caps; +} + +static GstStateChangeReturn +gst_pvrvideosink_change_state (GstElement * element, GstStateChange transition) +{ + GstPVRVideoSink *pvrvideosink; + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + GstDrawContext *dcontext; + + pvrvideosink = GST_PVRVIDEOSINK (element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + if (pvrvideosink->dcontext == NULL) { + dcontext = gst_pvrvideosink_get_dcontext (pvrvideosink); + if (dcontext == NULL) + return GST_STATE_CHANGE_FAILURE; + GST_OBJECT_LOCK (pvrvideosink); + pvrvideosink->dcontext = dcontext; + GST_OBJECT_UNLOCK (pvrvideosink); + } + gst_pvrvideosink_manage_event_thread (pvrvideosink); + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + g_mutex_lock (pvrvideosink->pool_lock); + pvrvideosink->pool_invalid = FALSE; + g_mutex_unlock (pvrvideosink->pool_lock); + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + g_mutex_lock (pvrvideosink->pool_lock); + pvrvideosink->pool_invalid = TRUE; + g_mutex_unlock (pvrvideosink->pool_lock); + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + switch (transition) { + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + pvrvideosink->fps_n = 0; + pvrvideosink->fps_d = 1; + GST_VIDEO_SINK_WIDTH (pvrvideosink) = 0; + GST_VIDEO_SINK_HEIGHT (pvrvideosink) = 0; + break; + case GST_STATE_CHANGE_READY_TO_NULL: + gst_pvrvideosink_reset (pvrvideosink); + break; + default: + break; + } + + return ret; +} + +static void +gst_pvrvideosink_get_times (GstBaseSink * bsink, GstBuffer * buf, + GstClockTime * start, GstClockTime * end) +{ + GstPVRVideoSink *pvrvideosink; + + pvrvideosink = GST_PVRVIDEOSINK (bsink); + + if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { + *start = GST_BUFFER_TIMESTAMP (buf); + if (GST_BUFFER_DURATION_IS_VALID (buf)) { + *end = *start + GST_BUFFER_DURATION (buf); + } else { + if (pvrvideosink->fps_n > 0) { + *end = *start + + gst_util_uint64_scale_int (GST_SECOND, pvrvideosink->fps_d, + pvrvideosink->fps_n); + } + } + } +} + +static GstFlowReturn +gst_pvrvideosink_show_frame (GstBaseSink * vsink, GstBuffer * buf) +{ + GstPVRVideoSink *pvrvideosink; + GstBuffer *newbuf = NULL; + g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR); + + pvrvideosink = GST_PVRVIDEOSINK (vsink); + + GST_DEBUG_OBJECT (pvrvideosink, "render buffer: %p", buf); + + if (!GST_IS_BUFFER (buf)) { + GstFlowReturn ret; + + /* special case check for sub-buffers: In certain cases, places like + * GstBaseTransform, which might check that the buffer is writable + * before copying metadata, timestamp, and such, will find that the + * buffer has more than one reference to it. In these cases, they + * will create a sub-buffer with an offset=0 and length equal to the + * original buffer size. + * + * This could happen in two scenarios: (1) a tee in the pipeline, and + * (2) because the refcnt is incremented in gst_mini_object_free() + * before the finalize function is called, and decremented after it + * returns.. but returning this buffer to the buffer pool in the + * finalize function, could wake up a thread blocked in _buffer_alloc() + * which could run and get a buffer w/ refcnt==2 before the thread + * originally unref'ing the buffer returns from finalize function and + * decrements the refcnt back to 1! + */ + if (buf->parent && + (GST_BUFFER_DATA (buf) == GST_BUFFER_DATA (buf->parent)) && + (GST_BUFFER_SIZE (buf) == GST_BUFFER_SIZE (buf->parent))) { + GST_DEBUG_OBJECT (pvrvideosink, "I have a sub-buffer!"); + return gst_pvrvideosink_show_frame (vsink, buf->parent); + } + + GST_DEBUG_OBJECT (pvrvideosink, + "slow-path.. I got a %s so I need to memcpy", + g_type_name (G_OBJECT_TYPE (buf))); + + ret = gst_pvrvideosink_buffer_alloc (GST_BASE_SINK (vsink), + GST_BUFFER_OFFSET (buf), GST_BUFFER_SIZE (buf), GST_BUFFER_CAPS (buf), + &newbuf); + + if (GST_FLOW_OK != ret) { + GST_DEBUG_OBJECT (pvrvideosink, "dropping frame!!"); + return GST_FLOW_OK; + } + + memcpy (GST_BUFFER_DATA (newbuf), + GST_BUFFER_DATA (buf), + MIN (GST_BUFFER_SIZE (newbuf), GST_BUFFER_SIZE (buf))); + + GST_DEBUG_OBJECT (pvrvideosink, "render copied buffer: %p", newbuf); + + buf = newbuf; + } + + gst_pvrvideosink_blit (pvrvideosink, buf); + + if (newbuf) { + gst_buffer_unref (newbuf); + } + + return GST_FLOW_OK; +} + + +/* Buffer management + * + * The buffer_alloc function must either return a buffer with given size and + * caps or create a buffer with different caps attached to the buffer. This + * last option is called reverse negotiation, ie, where the sink suggests a + * different format from the upstream peer. + * + * We try to do reverse negotiation when our geometry changes and we like a + * resized buffer. + */ +static GstFlowReturn +gst_pvrvideosink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, + GstCaps * caps, GstBuffer ** buf) +{ + GstPVRVideoSink *pvrvideosink; + GstDucatiBuffer *pvrvideo = NULL; + GstStructure *structure = NULL; + GstFlowReturn ret = GST_FLOW_OK; + gint width, height; + + pvrvideosink = GST_PVRVIDEOSINK (bsink); + + GST_DEBUG_OBJECT (pvrvideosink, "begin"); + + if (G_UNLIKELY (!caps)) { + GST_WARNING_OBJECT (pvrvideosink, + "have no caps, doing fallback allocation"); + *buf = NULL; + ret = GST_FLOW_OK; + goto beach; + } + + g_mutex_lock (pvrvideosink->pool_lock); + if (G_UNLIKELY (pvrvideosink->pool_invalid)) { + GST_DEBUG_OBJECT (pvrvideosink, "the pool is flushing"); + ret = GST_FLOW_WRONG_STATE; + g_mutex_unlock (pvrvideosink->pool_lock); + goto beach; + } else { + g_mutex_unlock (pvrvideosink->pool_lock); + } + + GST_LOG_OBJECT (pvrvideosink, + "a buffer of %d bytes was requested with caps %" GST_PTR_FORMAT + " and offset %" G_GUINT64_FORMAT, size, caps, offset); + + /* get struct to see what is requested */ + structure = gst_caps_get_structure (caps, 0); + if (!gst_structure_get_int (structure, "width", &width) || + !gst_structure_get_int (structure, "height", &height)) { + GST_WARNING_OBJECT (pvrvideosink, "invalid caps for buffer allocation %" + GST_PTR_FORMAT, caps); + ret = GST_FLOW_NOT_NEGOTIATED; + goto beach; + } + + g_mutex_lock (pvrvideosink->pool_lock); + /* initialize the buffer pool if not initialized yet */ + if (G_UNLIKELY (!pvrvideosink->buffer_pool || + pvrvideosink->buffer_pool->size != size)) { + if (pvrvideosink->buffer_pool) { + GST_INFO_OBJECT (pvrvideosink, "in buffer alloc, pool->size != size"); + gst_pvr_bufferpool_stop_running (pvrvideosink->buffer_pool, FALSE); + } + + GST_LOG_OBJECT (pvrvideosink, "Creating a buffer pool with %d buffers", + pvrvideosink->num_buffers); + if (!(pvrvideosink->buffer_pool = + gst_pvr_bufferpool_new (GST_ELEMENT (pvrvideosink), + caps, pvrvideosink->num_buffers, size, + pvrvideosink->dcontext->pvr_context))) { + g_mutex_unlock (pvrvideosink->pool_lock); + return GST_FLOW_ERROR; + } + } + pvrvideo = gst_pvr_bufferpool_get (pvrvideosink->buffer_pool, NULL); + g_mutex_unlock (pvrvideosink->pool_lock); + + *buf = GST_BUFFER_CAST (pvrvideo); + +beach: + return ret; +} + +/* Interfaces stuff */ + +static gboolean +gst_pvrvideosink_interface_supported (GstImplementsInterface * iface, + GType type) +{ + if (type == GST_TYPE_X_OVERLAY) + return TRUE; + else + return FALSE; +} + +static void +gst_pvrvideosink_interface_init (GstImplementsInterfaceClass * klass) +{ + klass->supported = gst_pvrvideosink_interface_supported; +} + +/* This function destroys a GstXWindow */ +static void +gst_pvrvideosink_xwindow_destroy (GstPVRVideoSink * pvrvideosink, + GstXWindow * xwindow) +{ + g_return_if_fail (xwindow != NULL); + + g_mutex_lock (pvrvideosink->dcontext->x_lock); + + /* If we did not create that window we just free the GC and let it live */ + if (xwindow->internal) + XDestroyWindow (pvrvideosink->dcontext->x_display, xwindow->window); + else + XSelectInput (pvrvideosink->dcontext->x_display, xwindow->window, 0); + + XFreeGC (pvrvideosink->dcontext->x_display, xwindow->gc); + + XSync (pvrvideosink->dcontext->x_display, FALSE); + + g_mutex_unlock (pvrvideosink->dcontext->x_lock); + + g_free (xwindow); +} + +static void +gst_pvrvideosink_set_window_handle (GstXOverlay * overlay, guintptr id) +{ + XID xwindow_id = id; + GstPVRVideoSink *pvrvideosink = GST_PVRVIDEOSINK (overlay); + GstXWindow *xwindow = NULL; + + g_return_if_fail (GST_IS_PVRVIDEOSINK (pvrvideosink)); + + g_mutex_lock (pvrvideosink->flow_lock); + + /* If we already use that window return */ + if (pvrvideosink->xwindow && (xwindow_id == pvrvideosink->xwindow->window)) { + g_mutex_unlock (pvrvideosink->flow_lock); + return; + } + + /* If the element has not initialized the X11 context try to do so */ + if (!pvrvideosink->dcontext && !(pvrvideosink->dcontext = + gst_pvrvideosink_get_dcontext (pvrvideosink))) { + g_mutex_unlock (pvrvideosink->flow_lock); + /* we have thrown a GST_ELEMENT_ERROR now */ + return; + } + + /* Clear image pool as the images are unusable anyway */ + g_mutex_lock (pvrvideosink->pool_lock); + if (pvrvideosink->buffer_pool) { + gst_pvr_bufferpool_stop_running (pvrvideosink->buffer_pool, FALSE); + pvrvideosink->buffer_pool = NULL; + } + g_mutex_unlock (pvrvideosink->pool_lock); + + /* If a window is there already we destroy it */ + if (pvrvideosink->xwindow) { + gst_pvrvideosink_xwindow_destroy (pvrvideosink, pvrvideosink->xwindow); + pvrvideosink->xwindow = NULL; + } + + /* If the xid is 0 we will create an internal one in buffer_alloc */ + if (xwindow_id != 0) { + XWindowAttributes attr; + WSEGLError glerror; + WSEGLDrawableParams source_params; + PVRSRV_CLIENT_MEM_INFO *client_mem_info; + + xwindow = g_new0 (GstXWindow, 1); + xwindow->window = xwindow_id; + + /* Set the event we want to receive and create a GC */ + g_mutex_lock (pvrvideosink->dcontext->x_lock); + + XGetWindowAttributes (pvrvideosink->dcontext->x_display, xwindow->window, + &attr); + + xwindow->width = attr.width; + xwindow->height = attr.height; + xwindow->internal = FALSE; + if (!pvrvideosink->have_render_rect) { + pvrvideosink->render_rect.x = pvrvideosink->render_rect.y = 0; + pvrvideosink->render_rect.w = attr.width; + pvrvideosink->render_rect.h = attr.height; + } + XSelectInput (pvrvideosink->dcontext->x_display, xwindow->window, + ExposureMask | StructureNotifyMask); + + XSetWindowBackgroundPixmap (pvrvideosink->dcontext->x_display, + xwindow->window, None); + + XMapWindow (pvrvideosink->dcontext->x_display, xwindow->window); + xwindow->gc = XCreateGC (pvrvideosink->dcontext->x_display, + xwindow->window, 0, NULL); + g_mutex_unlock (pvrvideosink->dcontext->x_lock); + + glerror = + pvrvideosink->dcontext-> + wsegl_table->pfnWSEGL_CreateWindowDrawable (pvrvideosink->dcontext-> + display_handle, pvrvideosink->dcontext->glconfig, + &(pvrvideosink->dcontext->drawable_handle), + (NativeWindowType) xwindow->window, + &(pvrvideosink->dcontext->rotation)); + + if (glerror != WSEGL_SUCCESS) { + GST_ERROR_OBJECT (pvrvideosink, "Error creating drawable"); + return; + } + glerror = + pvrvideosink->dcontext-> + wsegl_table->pfnWSEGL_GetDrawableParameters (pvrvideosink->dcontext-> + drawable_handle, &source_params, &pvrvideosink->render_params); + + client_mem_info = + (PVRSRV_CLIENT_MEM_INFO *) pvrvideosink->render_params.hPrivateData; + PVR2DMEMINFO_INITIALISE (&pvrvideosink->dcontext->dst_mem, client_mem_info); + } + + if (xwindow) + pvrvideosink->xwindow = xwindow; + + g_mutex_unlock (pvrvideosink->flow_lock); +} + +static void +gst_pvrvideosink_expose (GstXOverlay * overlay) +{ + GstPVRVideoSink *pvrvideosink = GST_PVRVIDEOSINK (overlay); + + gst_pvrvideosink_blit (pvrvideosink, NULL); +} + +static void +gst_pvrvideosink_set_event_handling (GstXOverlay * overlay, + gboolean handle_events) +{ + GstPVRVideoSink *pvrvideosink = GST_PVRVIDEOSINK (overlay); + + g_mutex_lock (pvrvideosink->flow_lock); + + if (G_UNLIKELY (!pvrvideosink->xwindow)) { + g_mutex_unlock (pvrvideosink->flow_lock); + return; + } + + g_mutex_lock (pvrvideosink->dcontext->x_lock); + + XSelectInput (pvrvideosink->dcontext->x_display, + pvrvideosink->xwindow->window, ExposureMask | StructureNotifyMask); + + g_mutex_unlock (pvrvideosink->dcontext->x_lock); + + g_mutex_unlock (pvrvideosink->flow_lock); +} + +static void +gst_pvrvideosink_set_render_rectangle (GstXOverlay * overlay, gint x, gint y, + gint width, gint height) +{ + GstPVRVideoSink *pvrvideosink = GST_PVRVIDEOSINK (overlay); + + /* FIXME: how about some locking? */ + if (width >= 0 && height >= 0) { + pvrvideosink->render_rect.x = x; + pvrvideosink->render_rect.y = y; + pvrvideosink->render_rect.w = width; + pvrvideosink->render_rect.h = height; + pvrvideosink->have_render_rect = TRUE; + } else { + pvrvideosink->render_rect.x = 0; + pvrvideosink->render_rect.y = 0; + pvrvideosink->render_rect.w = pvrvideosink->xwindow->width; + pvrvideosink->render_rect.h = pvrvideosink->xwindow->height; + pvrvideosink->have_render_rect = FALSE; + } +} + +static void +gst_pvrvideosink_xoverlay_init (GstXOverlayClass * iface) +{ + iface->set_window_handle = gst_pvrvideosink_set_window_handle; + iface->expose = gst_pvrvideosink_expose; + iface->handle_events = gst_pvrvideosink_set_event_handling; + iface->set_render_rectangle = gst_pvrvideosink_set_render_rectangle; +} + +/* =========================================== */ +/* */ +/* Init & Class init */ +/* */ +/* =========================================== */ + +static void +gst_pvrvideosink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstPVRVideoSink *pvrvideosink; + + g_return_if_fail (GST_IS_PVRVIDEOSINK (object)); + + pvrvideosink = GST_PVRVIDEOSINK (object); + + switch (prop_id) { + case PROP_FORCE_ASPECT_RATIO: + pvrvideosink->keep_aspect = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_pvrvideosink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstPVRVideoSink *pvrvideosink; + + g_return_if_fail (GST_IS_PVRVIDEOSINK (object)); + + pvrvideosink = GST_PVRVIDEOSINK (object); + + switch (prop_id) { + case PROP_FORCE_ASPECT_RATIO: + g_value_set_boolean (value, pvrvideosink->keep_aspect); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_pvrvideosink_dcontext_clear (GstPVRVideoSink * pvrvideosink) +{ + GstDrawContext *dcontext; + + GST_OBJECT_LOCK (pvrvideosink); + if (!pvrvideosink->dcontext) { + GST_OBJECT_UNLOCK (pvrvideosink); + return; + } + + dcontext = pvrvideosink->dcontext; + pvrvideosink->dcontext = NULL; + GST_OBJECT_UNLOCK (pvrvideosink); + + if (dcontext->p_blt_info) + g_free (dcontext->p_blt_info); + + g_mutex_lock (dcontext->x_lock); + XCloseDisplay (dcontext->x_display); + g_mutex_unlock (dcontext->x_lock); + g_mutex_free (dcontext->x_lock); + + g_free (dcontext); +} + +static void +gst_pvrvideosink_reset (GstPVRVideoSink * pvrvideosink) +{ + GThread *thread; + + GST_OBJECT_LOCK (pvrvideosink); + pvrvideosink->running = FALSE; + thread = pvrvideosink->event_thread; + pvrvideosink->event_thread = NULL; + GST_OBJECT_UNLOCK (pvrvideosink); + + if (thread) + g_thread_join (thread); + + if (pvrvideosink->current_buffer) { + gst_buffer_unref (pvrvideosink->current_buffer); + pvrvideosink->current_buffer = NULL; + } + + g_mutex_lock (pvrvideosink->pool_lock); + pvrvideosink->pool_invalid = TRUE; + if (pvrvideosink->buffer_pool) { + gst_pvr_bufferpool_stop_running (pvrvideosink->buffer_pool, TRUE); + pvrvideosink->buffer_pool = NULL; + } + g_mutex_unlock (pvrvideosink->pool_lock); + memset (&pvrvideosink->render_params, 0, sizeof (WSEGLDrawableParams)); + + pvrvideosink->render_rect.x = pvrvideosink->render_rect.y = 0; + pvrvideosink->render_rect.w = pvrvideosink->render_rect.h = 0; + pvrvideosink->have_render_rect = FALSE; + + gst_pvrvideosink_destroy_drawable (pvrvideosink); + + if (pvrvideosink->xwindow) { + gst_pvrvideosink_xwindow_destroy (pvrvideosink, pvrvideosink->xwindow); + pvrvideosink->xwindow = NULL; + } + + gst_pvrvideosink_dcontext_clear (pvrvideosink); +} + +static void +gst_pvrvideosink_finalize (GObject * object) +{ + GstPVRVideoSink *pvrvideosink; + + pvrvideosink = GST_PVRVIDEOSINK (object); + + gst_pvrvideosink_reset (pvrvideosink); + + if (pvrvideosink->flow_lock) { + g_mutex_free (pvrvideosink->flow_lock); + pvrvideosink->flow_lock = NULL; + } + if (pvrvideosink->pool_lock) { + g_mutex_free (pvrvideosink->pool_lock); + pvrvideosink->pool_lock = NULL; + } + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_pvrvideosink_init (GstPVRVideoSink * pvrvideosink) +{ + pvrvideosink->running = FALSE; + + pvrvideosink->fps_n = 0; + pvrvideosink->fps_d = 1; + + pvrvideosink->flow_lock = g_mutex_new (); + pvrvideosink->pool_lock = g_mutex_new (); + pvrvideosink->buffer_pool = NULL; + pvrvideosink->pool_invalid = TRUE; + + pvrvideosink->keep_aspect = FALSE; + pvrvideosink->current_caps = NULL; + pvrvideosink->num_buffers = DEFAULT_QUEUE_SIZE; + pvrvideosink->num_buffers_can_change = TRUE; + pvrvideosink->min_queued_bufs = DEFAULT_MIN_QUEUED_BUFS; + pvrvideosink->dcontext = NULL; + pvrvideosink->xwindow = NULL; + pvrvideosink->redraw_borders = TRUE; + pvrvideosink->current_buffer = NULL; + pvrvideosink->event_thread = NULL; + memset (&pvrvideosink->render_params, 0, sizeof (WSEGLDrawableParams)); +} + +static void +gst_pvrvideosink_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_set_details_simple (element_class, + "PVR Video sink", "Sink/Video", + "A PVR videosink", + "Luciana Fujii Pontello finalize = gst_pvrvideosink_finalize; + gobject_class->set_property = gst_pvrvideosink_set_property; + gobject_class->get_property = gst_pvrvideosink_get_property; + + g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO, + g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio", + "When enabled, reverse caps negotiation (scaling) will respect " + "original aspect ratio", FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + gstelement_class->change_state = gst_pvrvideosink_change_state; + + gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_pvrvideosink_setcaps); + gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_pvrvideosink_getcaps); + gstbasesink_class->buffer_alloc = + GST_DEBUG_FUNCPTR (gst_pvrvideosink_buffer_alloc); + gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_pvrvideosink_get_times); + + gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_pvrvideosink_show_frame); +} + +/* ============================================================= */ +/* */ +/* Public Methods */ +/* */ +/* ============================================================= */ + +/* =========================================== */ +/* */ +/* Object typing & Creation */ +/* */ +/* =========================================== */ + +GType +gst_pvrvideosink_get_type (void) +{ + static GType pvrvideosink_type = 0; + + if (!pvrvideosink_type) { + static const GTypeInfo pvrvideosink_info = { + sizeof (GstPVRVideoSinkClass), + gst_pvrvideosink_base_init, + NULL, + (GClassInitFunc) gst_pvrvideosink_class_init, + NULL, + NULL, + sizeof (GstPVRVideoSink), 0, (GInstanceInitFunc) gst_pvrvideosink_init, + }; + static const GInterfaceInfo iface_info = { + (GInterfaceInitFunc) gst_pvrvideosink_interface_init, NULL, NULL, + }; + static const GInterfaceInfo overlay_info = { + (GInterfaceInitFunc) gst_pvrvideosink_xoverlay_init, NULL, NULL, + }; + + pvrvideosink_type = g_type_register_static (GST_TYPE_VIDEO_SINK, + "GstPVRVideoSink", &pvrvideosink_info, 0); + + g_type_add_interface_static (pvrvideosink_type, + GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info); + g_type_add_interface_static (pvrvideosink_type, GST_TYPE_X_OVERLAY, + &overlay_info); + } + + return pvrvideosink_type; +} diff --git a/sys/pvr2d/gstpvrvideosink.h b/sys/pvr2d/gstpvrvideosink.h new file mode 100644 index 0000000000..45f6a129e9 --- /dev/null +++ b/sys/pvr2d/gstpvrvideosink.h @@ -0,0 +1,157 @@ +/* GStreamer + * + * Copyright (C) 2011 - Collabora Ltda + * Copyright (C) 2011 - Texas Instruments + * @author: Luciana Fujii Pontello + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_PVRVIDEOSINK_H__ +#define __GST_PVRVIDEOSINK_H__ + +#include +#include +#include "gstpvrbufferpool.h" + +#include +#include +#include +#include +#include +#include +#include + +G_BEGIN_DECLS +#define GST_TYPE_PVRVIDEOSINK (gst_pvrvideosink_get_type()) +#define GST_PVRVIDEOSINK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_PVRVIDEOSINK, GstPVRVideoSink)) +#define GST_PVRVIDEOSINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_PVRVIDEOSINK, GstPVRVideoSinkClass)) +#define GST_IS_PVRVIDEOSINK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_PVRVIDEOSINK)) +#define GST_IS_PVRVIDEOSINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_PVRVIDEOSINK)) +typedef struct _GstDrawContext GstDrawContext; +typedef struct _GstXWindow GstXWindow; + +typedef struct _GstPVRVideoBuffer GstPVRVideoBuffer; +typedef struct _GstPVRVideoBufferClass GstPVRVideoBufferClass; + +typedef struct _GstPVRVideoSink GstPVRVideoSink; +typedef struct _GstPVRVideoSinkClass GstPVRVideoSinkClass; + +struct _GstDrawContext +{ + /* PVR2D */ + PVR2DCONTEXTHANDLE pvr_context; + PVR2DMEMINFO dst_mem; + PPVR2D_3DBLT_EXT p_blt_info; + PPVR2DBLTINFO p_blt2d_info; + + long stride; + PVR2DFORMAT display_format; + long display_width; + long display_height; + + /* WSEGL */ + const WSEGL_FunctionTable *wsegl_table; + + WSEGLDisplayHandle display_handle; + const WSEGLCaps **glcaps; + WSEGLConfig *glconfig; + WSEGLDrawableHandle drawable_handle; + WSEGLRotationAngle rotation; + + GMutex *x_lock; + Display *x_display; + gint screen_num; + gulong black; +}; + +struct _GstXWindow +{ + Window window; + gint width, height; + gboolean internal; + GC gc; +}; + + +/** + * GstPVRVideoSink: + * @running: used to inform @event_thread if it should run/shutdown + * @fps_n: the framerate fraction numerator + * @fps_d: the framerate fraction denominator + * @flow_lock: used to protect data flow routines from external calls such as + * events from @event_thread or methods from the #GstXOverlay interface + * @pool_lock: used to protect the buffer pool + * @x_lock: used to protect X calls + * @buffer_pool: a list of #GstPVRVideoBuffer that could be reused at next buffer + * allocation call + * @keep_aspect: used to remember if reverse negotiation scaling should respect + * aspect ratio + * + * The #GstPVRVideoSink data structure. + */ +struct _GstPVRVideoSink +{ + /* Our element stuff */ + GstVideoSink videosink; + + gboolean running; + + /* Framerate numerator and denominator */ + GstVideoFormat format; + gint fps_n; + gint fps_d; + gint rowstride; + + GThread *event_thread; + GMutex *flow_lock; + + GMutex *pool_lock; + GstPvrBufferPool *buffer_pool; + gboolean pool_invalid; + gint num_buffers; + gboolean num_buffers_can_change; + gint min_queued_bufs; + + gboolean keep_aspect; + + GstCaps *current_caps; + GstDrawContext *dcontext; + GstXWindow *xwindow; + + GstVideoRectangle render_rect; + gboolean have_render_rect; + + gchar *media_title; + gboolean redraw_borders; + GstBuffer *current_buffer; + + WSEGLDrawableParams render_params; +}; + +struct _GstPVRVideoSinkClass +{ + GstVideoSinkClass parent_class; +}; + +GType gst_pvrvideosink_get_type (void); + +G_END_DECLS +#endif /* __GST_PVRVIDEOSINK_H__ */ diff --git a/sys/pvr2d/pvr_includes/dri2_ws.h b/sys/pvr2d/pvr_includes/dri2_ws.h new file mode 100755 index 0000000000..743d5bb9c7 --- /dev/null +++ b/sys/pvr2d/pvr_includes/dri2_ws.h @@ -0,0 +1,176 @@ +/********************************************************************** +* +* Copyright(c) Imagination Technologies Ltd. +* +* The contents of this file are subject to the MIT license as set out below. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT +* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +* This License is also included in this distribution in the file called +* "COPYING". +* +******************************************************************************/ + + + +#if !defined(__DRI2_WS_H__) +#define __DRI2_WS_H__ + +#define DRI2WS_DISPFLAG_DEFAULT_DISPLAY 0x00000001 + +/* +// Constants (macros) related to back-buffering. +*/ + +#define XWS_FLIP_BUFFERS 3 +#define DRI2_FLIP_BUFFERS_NUM XWS_FLIP_BUFFERS +#define XWS_FLIP_BUFFER_INDEX (XWS_MAX_FLIP_BUFFERS - 1) + +#define XWS_BLIT_BUFFERS 2 +#define DRI2_BLIT_BUFFERS_NUM XWS_BLIT_BUFFERS +#define XWS_BLIT_BUFFER_INDEX (XWS_MAX_BLIT_BUFFERS - 1) + +#if 0 +#define MIN(a,b) ((a)<(b)?(a):(b)) +#define MAX(a,b) ((a)>(b)?(a):(b)) +#endif + +#define XWS_MAX_BUFFERS MAX(XWS_FLIP_BUFFERS, XWS_BLIT_BUFFERS) +#define DRI2_MAX_BUFFERS_NUM XWS_MAX_BUFFERS + + +#define __DRI_BUFFER_EMPTY 103 + +/** Used for ugly ugly ugly swap interval passing to dri2 driver and receiving current frame index */ +#define __DRI_BUFFER_PVR_CTRL 0x80 /* 100000XX <- last 2 bits for swap interval value */ +#define __DRI_BUFFER_PVR_CTRL_RET 0x90 /* 11000000 */ + + + +#define DRI2_BACK_BUFFER_EXPORT_TYPE_BUFFERS 1 +#define DRI2_BACK_BUFFER_EXPORT_TYPE_SWAPCHAIN 2 + +#define UNREFERENCED_PARAMETER(x) (x) = (x) + + +/* + * Structure used to pass information about back buffers between client application and + * X.Org. Watch out for equivalent structure in pvr_video lib + */ +typedef struct _PVRDRI2BackBuffersExport_ +{ + /* Type of export. _BUFFERS mean set of handles, _SWAPCHAIN mean Swap chain ID */ + unsigned int ui32Type; + PVR2D_HANDLE hBuffers[DRI2_MAX_BUFFERS_NUM]; + unsigned int ui32BuffersCount; + unsigned int ui32SwapChainID; +} PVRDRI2BackBuffersExport; + +/* +// Private window system display information +*/ +typedef struct DRI2WS_Display_TAG +{ + unsigned int ui32RefCount; + + Display *display; + int screen; + unsigned int ui32Flags; + + unsigned int ui32Width; + unsigned int ui32Height; + unsigned int ui32StrideInBytes; + unsigned int ui32BytesPerPixel; + WSEGLPixelFormat ePixelFormat; + + PVR2DFORMAT ePVR2DPixelFormat; + PVR2DCONTEXTHANDLE hContext; + PVR2DMEMINFO *psMemInfo; + + int iDRMfd; +} DRI2WSDisplay; + + +typedef enum DRI2WS_DrawableType_TAG +{ + DRI2_DRAWABLE_UNKNOWN = 0, + DRI2_DRAWABLE_WINDOW = 1, + DRI2_DRAWABLE_PIXMAP = 2, +} DRI2WS_DrawableType; + + +/* +// Private window system drawable information +*/ +typedef struct DRI2WS_Drawable_TAG +{ + DRI2WS_DrawableType eDrawableType; + + Window nativeWin; + + /** Index of current render-to back buffer (received from Xserver) */ + unsigned int ui32BackBufferCurrent; + + /** Number of buffers */ + unsigned int ui32BackBufferNum; + + /** Swap interval (works only in fliping/fullscreen case, values 0-3) */ + unsigned int ui32SwapInterval; + + /** PVR2D Handles received from Xserver (back buffers export structure) */ + PVR2D_HANDLE hPVR2DBackBufferExport; + + /** Stamp of current back buffer */ + unsigned char ucBackBufferExportStamp; + + /** Array of PVR2D Handles received from Xserver (our back buffers) */ + PVR2D_HANDLE hPVR2DBackBuffer[XWS_MAX_BUFFERS]; + + /** Array of PVR2D mapped back buffers */ + PVR2DMEMINFO *psMemBackBuffer[XWS_MAX_BUFFERS]; + + /** Stamp of current back buffer */ + unsigned char ucFrontBufferStamp; + + /** Array of PVR2D Handles received from Xserver (our back buffers) */ + PVR2D_HANDLE hPVR2DFrontBuffer; + + /** Array of PVR2D mapped back buffers */ + PVR2DMEMINFO *psMemFrontBuffer; + + /** ID of flip/swap chain received from X.Org */ + unsigned int ui32FlipChainID; + + /** PVR2D Handle of flip chain used to get buffers to draw to */ + PVR2DFLIPCHAINHANDLE hFlipChain; + + int iWidth; + int iHeight; + + WSEGLPixelFormat ePixelFormat; + unsigned int ui32BytesPerPixel; + unsigned int ui32StrideInPixels; + unsigned int ui32StrideInBytes; + PVR2DFORMAT ePVR2DPixelFormat; + + DRI2WSDisplay *psXWSDisplay; + +} DRI2WSDrawable; + +#endif /* __DRI2_WS_H__ */ diff --git a/sys/pvr2d/pvr_includes/img_defs.h b/sys/pvr2d/pvr_includes/img_defs.h new file mode 100755 index 0000000000..64db71105c --- /dev/null +++ b/sys/pvr2d/pvr_includes/img_defs.h @@ -0,0 +1,123 @@ +/********************************************************************** +* +* Copyright(c) Imagination Technologies Ltd. +* +* The contents of this file are subject to the MIT license as set out below. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT +* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +* This License is also included in this distribution in the file called +* "COPYING". +* +******************************************************************************/ + + + +#if !defined (__IMG_DEFS_H__) +#define __IMG_DEFS_H__ + +#include "img_types.h" + +typedef enum img_tag_TriStateSwitch +{ + IMG_ON = 0x00, + IMG_OFF, + IMG_IGNORE + +} img_TriStateSwitch, * img_pTriStateSwitch; + +#define IMG_SUCCESS 0 + +#define IMG_NO_REG 1 + +#if defined (NO_INLINE_FUNCS) + #define INLINE + #define FORCE_INLINE +#else +#if defined (__cplusplus) + #define INLINE inline + #define FORCE_INLINE inline +#else +#if !defined(INLINE) + #define INLINE __inline +#endif + #define FORCE_INLINE static __inline +#endif +#endif + + +#ifndef PVR_UNREFERENCED_PARAMETER +#define PVR_UNREFERENCED_PARAMETER(param) (param) = (param) +#endif + +#ifdef __GNUC__ +#define unref__ __attribute__ ((unused)) +#else +#define unref__ +#endif + +#ifndef _TCHAR_DEFINED +#if defined(UNICODE) +typedef unsigned short TCHAR, *PTCHAR, *PTSTR; +#else +typedef char TCHAR, *PTCHAR, *PTSTR; +#endif +#define _TCHAR_DEFINED +#endif + + + #if defined(__linux__) || defined(__METAG) + + #define IMG_CALLCONV + #define IMG_INTERNAL __attribute__((visibility("hidden"))) + #define IMG_EXPORT __attribute__((visibility("default"))) + #define IMG_IMPORT + #define IMG_RESTRICT __restrict__ + + #else + #error("define an OS") + #endif + +#ifndef IMG_ABORT + #define IMG_ABORT() abort() +#endif + +#ifndef IMG_MALLOC + #define IMG_MALLOC(A) malloc (A) +#endif + +#ifndef IMG_FREE + #define IMG_FREE(A) free (A) +#endif + +#define IMG_CONST const + +#if defined(__GNUC__) +#define IMG_FORMAT_PRINTF(x,y) __attribute__((format(printf,x,y))) +#else +#define IMG_FORMAT_PRINTF(x,y) +#endif + +#if defined (_WIN64) +#define IMG_UNDEF (~0ULL) +#else +#define IMG_UNDEF (~0UL) +#endif + +#endif diff --git a/sys/pvr2d/pvr_includes/img_types.h b/sys/pvr2d/pvr_includes/img_types.h new file mode 100755 index 0000000000..c312c8374e --- /dev/null +++ b/sys/pvr2d/pvr_includes/img_types.h @@ -0,0 +1,143 @@ +/********************************************************************** +* +* Copyright(c) Imagination Technologies Ltd. +* +* The contents of this file are subject to the MIT license as set out below. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT +* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +* This License is also included in this distribution in the file called +* "COPYING". +* +******************************************************************************/ + + + +#ifndef __IMG_TYPES_H__ +#define __IMG_TYPES_H__ + +#if !defined(IMG_ADDRSPACE_CPUVADDR_BITS) +#define IMG_ADDRSPACE_CPUVADDR_BITS 32 +#endif + +#if !defined(IMG_ADDRSPACE_PHYSADDR_BITS) +#define IMG_ADDRSPACE_PHYSADDR_BITS 32 +#endif + +typedef unsigned int IMG_UINT, *IMG_PUINT; +typedef signed int IMG_INT, *IMG_PINT; + +typedef unsigned char IMG_UINT8, *IMG_PUINT8; +typedef unsigned char IMG_BYTE, *IMG_PBYTE; +typedef signed char IMG_INT8, *IMG_PINT8; +typedef char IMG_CHAR, *IMG_PCHAR; + +typedef unsigned short IMG_UINT16, *IMG_PUINT16; +typedef signed short IMG_INT16, *IMG_PINT16; +#if !defined(IMG_UINT32_IS_ULONG) +typedef unsigned int IMG_UINT32, *IMG_PUINT32; +typedef signed int IMG_INT32, *IMG_PINT32; +#else +typedef unsigned long IMG_UINT32, *IMG_PUINT32; +typedef signed long IMG_INT32, *IMG_PINT32; +#endif +#if !defined(IMG_UINT32_MAX) + #define IMG_UINT32_MAX 0xFFFFFFFFUL +#endif + + #if (defined(LINUX) || defined(__METAG)) +#if !defined(USE_CODE) + typedef unsigned long long IMG_UINT64, *IMG_PUINT64; + typedef long long IMG_INT64, *IMG_PINT64; +#endif + #else + + #error("define an OS") + + #endif + +#if !(defined(LINUX) && defined (__KERNEL__)) +typedef float IMG_FLOAT, *IMG_PFLOAT; +typedef double IMG_DOUBLE, *IMG_PDOUBLE; +#endif + +typedef enum tag_img_bool +{ + IMG_FALSE = 0, + IMG_TRUE = 1, + IMG_FORCE_ALIGN = 0x7FFFFFFF +} IMG_BOOL, *IMG_PBOOL; + +typedef void IMG_VOID, *IMG_PVOID; + +typedef IMG_INT32 IMG_RESULT; + +#if defined(_WIN64) +typedef unsigned __int64 IMG_UINTPTR_T; +#else +typedef unsigned int IMG_UINTPTR_T; +#endif + +typedef IMG_PVOID IMG_HANDLE; + +typedef void** IMG_HVOID, * IMG_PHVOID; + +typedef IMG_UINT32 IMG_SIZE_T; + +#define IMG_NULL 0 + +typedef IMG_UINT32 IMG_SID; + + +typedef IMG_PVOID IMG_CPU_VIRTADDR; + +typedef struct _IMG_DEV_VIRTADDR +{ + + IMG_UINT32 uiAddr; +#define IMG_CAST_TO_DEVVADDR_UINT(var) (IMG_UINT32)(var) + +} IMG_DEV_VIRTADDR; + +typedef struct _IMG_CPU_PHYADDR +{ + + IMG_UINTPTR_T uiAddr; +} IMG_CPU_PHYADDR; + +typedef struct _IMG_DEV_PHYADDR +{ +#if IMG_ADDRSPACE_PHYSADDR_BITS == 32 + + IMG_UINTPTR_T uiAddr; +#else + IMG_UINT32 uiAddr; + IMG_UINT32 uiHighAddr; +#endif +} IMG_DEV_PHYADDR; + +typedef struct _IMG_SYS_PHYADDR +{ + + IMG_UINTPTR_T uiAddr; +} IMG_SYS_PHYADDR; + +#include "img_defs.h" + +#endif diff --git a/sys/pvr2d/pvr_includes/pvr2d.h b/sys/pvr2d/pvr_includes/pvr2d.h new file mode 100755 index 0000000000..5dce7cf11c --- /dev/null +++ b/sys/pvr2d/pvr_includes/pvr2d.h @@ -0,0 +1,669 @@ +/********************************************************************** +* +* Copyright(c) Imagination Technologies Ltd. +* +* The contents of this file are subject to the MIT license as set out below. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT +* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +* This License is also included in this distribution in the file called +* "COPYING". +* +******************************************************************************/ + + + +/****************************************************************************** +Modifications :- +$Log: pvr2d.h $ + + --- Revision Logs Removed --- +******************************************************************************/ + +#ifndef _PVR2D_H_ +#define _PVR2D_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* PVR2D Platform-specific definitions */ +#if defined (__linux__) +#define PVR2D_EXPORT __attribute__((visibility("default"))) +#define PVR2D_IMPORT +#else +#define PVR2D_EXPORT +#define PVR2D_IMPORT +#endif + +/* PVR2D header revision */ +#define PVR2D_REV_MAJOR 3 +#define PVR2D_REV_MINOR 5 + +/* Basic types */ +typedef enum +{ + PVR2D_FALSE = 0, + PVR2D_TRUE +} PVR2D_BOOL; + +typedef void* PVR2D_HANDLE; + +typedef char PVR2D_CHAR, *PVR2D_PCHAR; +typedef unsigned char PVR2D_UCHAR, *PVR2D_PUCHAR; +typedef int PVR2D_INT, *PVR2D_PINT; +typedef unsigned int PVR2D_UINT, *PVR2D_PUINT; +typedef long PVR2D_LONG, *PVR2D_PLONG; +typedef unsigned long PVR2D_ULONG, *PVR2D_PULONG; + +typedef void PVR2D_VOID, *PVR2D_PVOID; + + +/* error codes */ +typedef enum +{ + PVR2D_OK = 0, + PVR2DERROR_INVALID_PARAMETER = -1, + PVR2DERROR_DEVICE_UNAVAILABLE = -2, + PVR2DERROR_INVALID_CONTEXT = -3, + PVR2DERROR_MEMORY_UNAVAILABLE = -4, + PVR2DERROR_DEVICE_NOT_PRESENT = -5, + PVR2DERROR_IOCTL_ERROR = -6, + PVR2DERROR_GENERIC_ERROR = -7, + PVR2DERROR_BLT_NOTCOMPLETE = -8, + PVR2DERROR_HW_FEATURE_NOT_SUPPORTED = -9, + PVR2DERROR_NOT_YET_IMPLEMENTED = -10, + PVR2DERROR_MAPPING_FAILED = -11 +}PVR2DERROR; + +/* 32 bit PVR2D pixel format specifier */ +typedef unsigned long PVR2DFORMAT; + +/* Standard PVR2D pixel formats */ +#define PVR2D_1BPP 0x00UL // 1bpp mask surface or palletized 1 bit source with 2x32 bit CLUT +#define PVR2D_RGB565 0x01UL // Common rgb 565 format +#define PVR2D_ARGB4444 0x02UL // Common argb 4444 format +#define PVR2D_RGB888 0x03UL // Common rgb 888 format (not supported) +#define PVR2D_ARGB8888 0x04UL // Common argb 8888 format +#define PVR2D_ARGB1555 0x05UL // Common argb 1555 format +#define PVR2D_ALPHA8 0x06UL // Alpha-only 8 bit per pixel (used with a constant fill colour) +#define PVR2D_ALPHA4 0x07UL // Alpha-only 4 bits per pixel (used with a constant fill colour) +#define PVR2D_PAL2 0x08UL // Palletized 2 bit format (requires 4x32 bit CLUT) +#define PVR2D_PAL4 0x09UL // Palletized 4 bit format (requires 16x32 bit CLUT) +#define PVR2D_PAL8 0x0AUL // Palletized 8 bit format (requires 256x32 bit CLUT) +#define PVR2D_U8 0x10UL // monochrome unsigned 8 bit +#define PVR2D_U88 0x11UL // monochrome unsigned 16 bit +#define PVR2D_S8 0x12UL // signed 8 bit +#define PVR2D_YUV422_YUYV 0x13UL // YUV 422 low-high byte order Y0UY1V +#define PVR2D_YUV422_UYVY 0x14UL // YUV 422 low-high byte order UY0VY1 +#define PVR2D_YUV422_YVYU 0x15UL // YUV 422 low-high byte order Y0VY1U +#define PVR2D_YUV422_VYUY 0x16UL // YUV 422 low-high byte order VY0UY1 +#define PVR2D_YUV420_2PLANE 0x17UL // YUV420 2 Plane +#define PVR2D_YUV420_3PLANE 0x18UL // YUV420 3 Plane +#define PVR2D_2101010ARGB 0x19UL // 32 bit 2 10 10 10 +#define PVR2D_888RSGSBS 0x1AUL +#define PVR2D_16BPP_RAW 0x1BUL // 16 bit raw (no format conversion) +#define PVR2D_32BPP_RAW 0x1CUL // 32 bit raw +#define PVR2D_64BPP_RAW 0x1DUL // 64 bit raw +#define PVR2D_128BPP_RAW 0x1EUL // 128 bit raw + +#define PVR2D_NO_OF_FORMATS 0x1FUL + +/* Format modifier bit field (DstFormat and SrcFormat bits 16..23) */ +#define PVR2D_FORMAT_MASK 0x0000FFFFUL // PVR2D Format bits +#define PVR2D_FORMAT_LAYOUT_MASK 0x000F0000UL // Format layout (strided / twiddled / tiled) +#define PVR2D_FORMAT_FLAGS_MASK 0x0FF00000UL // Surface Flags mask + +/* Layout */ +#define PVR2D_FORMAT_LAYOUT_SHIFT 16 +#define PVR2D_FORMAT_LAYOUT_STRIDED 0x00000000UL +#define PVR2D_FORMAT_LAYOUT_TILED 0x00010000UL +#define PVR2D_FORMAT_LAYOUT_TWIDDLED 0x00020000UL + +/* + PVR2D_SURFACE_PDUMP + This flag requests a surface pdump, to capture the pixel state after host writes. + Not needed if the surface state has resulted from previous SGX 2D/3D core writes. +*/ +#define PVR2D_SURFACE_PDUMP 0x00100000UL // calls PVRSRVPDumpMem to capture the surface (pdump builds only) + +/* + Low level 3D format extension - for blts via the 3D core only. + If the top bit of the format field is set then PVR2D reads it as a PVRSRV_PIXEL_FORMAT. + The outcome is hardware dependant. + There is no guarantee that any specific PVRSRV format will be supported. +*/ +#define PVR2D_FORMAT_PVRSRV 0x80000000 + +/* wrap surface type */ +typedef enum +{ + PVR2D_WRAPFLAG_NONCONTIGUOUS = 0, + PVR2D_WRAPFLAG_CONTIGUOUS = 1, + +}PVR2DWRAPFLAGS; + +#define PVR2D_CONTEXT_FLAGS_PRIORITY_MASK 0x00000003 + +#define PVR2D_CONTEXT_FLAGS_LOW_PRIORITY_CONTEXT 1 +#define PVR2D_CONTEXT_FLAGS_NORMAL_PRIORITY_CONTEXT 0 +#define PVR2D_CONTEXT_FLAGS_HIGH_PRIORITY_CONTEXT 2 + +/* flags for control information of additional blits */ +typedef enum +{ + PVR2D_BLIT_DISABLE_ALL = 0x00000000, /* disable all additional controls */ + PVR2D_BLIT_CK_ENABLE = 0x00000001, /* enable colour key */ + PVR2D_BLIT_GLOBAL_ALPHA_ENABLE = 0x00000002, /* enable standard global alpha */ + PVR2D_BLIT_PERPIXEL_ALPHABLEND_ENABLE = 0x00000004, /* enable per-pixel alpha bleding */ + PVR2D_BLIT_PAT_SURFACE_ENABLE = 0x00000008, /* enable pattern surf (disable fill) */ + PVR2D_BLIT_FULLY_SPECIFIED_ALPHA_ENABLE = 0x00000010, /* enable fully specified alpha */ + PVR2D_BLIT_ROT_90 = 0x00000020, /* apply 90 degree rotation to the blt */ + PVR2D_BLIT_ROT_180 = 0x00000040, /* apply 180 degree rotation to the blt */ + PVR2D_BLIT_ROT_270 = 0x00000080, /* apply 270 degree rotation to the blt */ + PVR2D_BLIT_COPYORDER_TL2BR = 0x00000100, /* copy order overrides */ + PVR2D_BLIT_COPYORDER_BR2TL = 0x00000200, + PVR2D_BLIT_COPYORDER_TR2BL = 0x00000400, + PVR2D_BLIT_COPYORDER_BL2TR = 0x00000800, + PVR2D_BLIT_COLKEY_SOURCE = 0x00001000, /* Key colour is on the source surface */ + PVR2D_BLIT_COLKEY_DEST = 0x00002000, /* Key colour is on the destination surface */ + PVR2D_BLIT_COLKEY_MASKED = 0x00004000, /* Mask enabled for colour key */ + PVR2D_BLIT_COLKEY_OP_PASS = 0x00008000, /* Colour key op = pass */ + PVR2D_BLIT_COLKEY_OP_REJECT = 0x00010000, /* Colour key op = reject */ + PVR2D_BLIT_PATH_2DCORE = 0x00100000, /* Blt via dedicated 2D Core or PTLA */ + PVR2D_BLIT_PATH_3DCORE = 0x00200000, /* Blt via 3D Core */ + PVR2D_BLIT_PATH_SWBLT = 0x00400000, /* Blt via host software */ + PVR2D_BLIT_NO_SRC_SYNC_INFO = 0x00800000, /* Dont send a source sync info*/ + PVR2D_BLIT_ISSUE_STATUS_UPDATES = 0x01000000, /* Issue status updates */ + +} PVR2DBLITFLAGS; + +/* standard alpha-blending functions, AlphaBlendingFunc field of PVR2DBLTINFO */ +typedef enum +{ + PVR2D_ALPHA_OP_SRC_DSTINV = 1, /* source alpha : Cdst = Csrc*Asrc + Cdst*(1-Asrc) */ + PVR2D_ALPHA_OP_SRCP_DSTINV = 2 /* premultiplied source alpha : Cdst = Csrc + Cdst*(1-Asrc) */ +} PVR2D_ALPHABLENDFUNC; + +/* blend ops for fully specified alpha (SGX 2D Core only) */ +typedef enum +{ + PVR2D_BLEND_OP_ZERO = 0, + PVR2D_BLEND_OP_ONE = 1, + PVR2D_BLEND_OP_SRC = 2, + PVR2D_BLEND_OP_DST = 3, + PVR2D_BLEND_OP_GLOBAL = 4, + PVR2D_BLEND_OP_SRC_PLUS_GLOBAL = 5, + PVR2D_BLEND_OP_DST_PLUS_GLOBAL = 6 +}PVR2D_BLEND_OP; + +/* SGX 2D Core Fully specified alpha blend : pAlpha field of PVR2DBLTINFO structure */ +/* a fully specified Alpha Blend operation is defined as */ +/* DST (ALPHA) = (ALPHA_1 * SRC (ALPHA)) + (ALPHA_3 * DST (ALPHA)) */ +/* DST (RGB) = (ALPHA_2 * SRC (RGB)) + (ALPHA_4 * DST (RGB)) */ +/* if the pre-multiplication stage is enabled then the equations become the following: */ +/* PRE_MUL = ((SRC(A)) * (Global Alpha Value)) */ +/* DST (ALPHA) = (ALPHA_1 * SRC (ALPHA)) + (PRE_MUL * DST (ALPHA)) */ +/* DST (RGB) = (ALPHA_2 * SRC (RGB)) + (PRE_MUL * DST (RGB)) */ +/* if the transparent source alpha stage is enabled then a source alpha of zero forces the */ +/* source to be transparent for that pixel regardless of the blend equation being used. */ +typedef struct _PVR2D_ALPHABLT +{ + PVR2D_BLEND_OP eAlpha1; + PVR2D_BOOL bAlpha1Invert; + PVR2D_BLEND_OP eAlpha2; + PVR2D_BOOL bAlpha2Invert; + PVR2D_BLEND_OP eAlpha3; + PVR2D_BOOL bAlpha3Invert; + PVR2D_BLEND_OP eAlpha4; + PVR2D_BOOL bAlpha4Invert; + PVR2D_BOOL bPremulAlpha; /* enable pre-multiplication stage */ + PVR2D_BOOL bTransAlpha; /* enable transparent source alpha stage */ + PVR2D_BOOL bUpdateAlphaLookup; /* enable and update the 1555-Lookup alpha table */ + PVR2D_UCHAR uAlphaLookup0; /* 8 bit alpha when A=0 in a 1555-Lookup surface */ + PVR2D_UCHAR uAlphaLookup1; /* 8 bit alpha when A=1 in a 1555-Lookup surface */ + PVR2D_UCHAR uGlobalRGB; /* Global Alpha Value for RGB, 0=transparent 255=opaque */ + PVR2D_UCHAR uGlobalA; /* Global Alpha Value for Alpha */ + +} PVR2D_ALPHABLT, *PPVR2D_ALPHABLT; + + +/* surface memory info structure */ +typedef struct _PVR2DMEMINFO +{ + PVR2D_VOID *pBase; + PVR2D_ULONG ui32MemSize; + PVR2D_ULONG ui32DevAddr; + PVR2D_ULONG ulFlags; + PVR2D_VOID *hPrivateData; + PVR2D_VOID *hPrivateMapData; + +}PVR2DMEMINFO, *PPVR2DMEMINFO; + + +#define PVR2D_MAX_DEVICE_NAME 20 + +typedef struct _PVR2DDEVICEINFO +{ + PVR2D_ULONG ulDevID; + PVR2D_CHAR szDeviceName[PVR2D_MAX_DEVICE_NAME]; +}PVR2DDEVICEINFO; + + +typedef struct _PVR2DISPLAYINFO +{ + PVR2D_ULONG ulMaxFlipChains; + PVR2D_ULONG ulMaxBuffersInChain; + PVR2DFORMAT eFormat; + PVR2D_ULONG ulWidth; + PVR2D_ULONG ulHeight; + PVR2D_LONG lStride; + PVR2D_ULONG ulMinFlipInterval; + PVR2D_ULONG ulMaxFlipInterval; + +}PVR2DDISPLAYINFO; + + +typedef struct _PVR2MISCDISPLAYINFO +{ + PVR2D_ULONG ulPhysicalWidthmm; + PVR2D_ULONG ulPhysicalHeightmm; + PVR2D_ULONG ulUnused[10]; + +}PVR2DMISCDISPLAYINFO; + + +typedef struct _PVR2DBLTINFO +{ + PVR2D_ULONG CopyCode; /* rop code */ + PVR2D_ULONG Colour; /* fill colour */ + PVR2D_ULONG ColourKey; /* colour key argb8888 (see CKEY_ defs below) */ + PVR2D_UCHAR GlobalAlphaValue; /* global alpha blending */ + PVR2D_UCHAR AlphaBlendingFunc; /* per-pixel alpha-blending function */ + + PVR2DBLITFLAGS BlitFlags; /* additional blit control information */ + + PVR2DMEMINFO *pDstMemInfo; /* destination memory */ + PVR2D_ULONG DstOffset; /* byte offset from start of allocation to destination surface pixel 0,0 */ + PVR2D_LONG DstStride; /* signed stride, the number of bytes from pixel 0,0 to 0,1 */ + PVR2D_LONG DstX, DstY; /* pixel offset from start of dest surface to start of blt rectangle */ + PVR2D_LONG DSizeX,DSizeY; /* blt size */ + PVR2DFORMAT DstFormat; /* dest format */ + PVR2D_ULONG DstSurfWidth; /* size of dest surface in pixels */ + PVR2D_ULONG DstSurfHeight; /* size of dest surface in pixels */ + + PVR2DMEMINFO *pSrcMemInfo; /* source mem, (source fields are also used for patterns) */ + PVR2D_ULONG SrcOffset; /* byte offset from start of allocation to src/pat surface pixel 0,0 */ + PVR2D_LONG SrcStride; /* signed stride, the number of bytes from pixel 0,0 to 0,1 */ + PVR2D_LONG SrcX, SrcY; /* pixel offset from start of surface to start of source rectangle */ + /* for patterns this is the start offset within the pattern */ + PVR2D_LONG SizeX,SizeY; /* source rectangle size or pattern size in pixels */ + PVR2DFORMAT SrcFormat; /* source/pattern format */ + PVR2DMEMINFO *pPalMemInfo; /* source/pattern palette memory containing argb8888 colour table */ + PVR2D_ULONG PalOffset; /* byte offset from start of allocation to start of palette */ + PVR2D_ULONG SrcSurfWidth; /* size of source surface in pixels */ + PVR2D_ULONG SrcSurfHeight; /* size of source surface in pixels */ + + PVR2DMEMINFO *pMaskMemInfo; /* mask memory, 1bpp format implied */ + PVR2D_ULONG MaskOffset; /* byte offset from start of allocation to mask surface pixel 0,0 */ + PVR2D_LONG MaskStride; /* signed stride, the number of bytes from pixel 0,0 to 0,1 */ + PVR2D_LONG MaskX, MaskY; /* mask rect top left (mask size = blt size) */ + PVR2D_ULONG MaskSurfWidth; /* size of mask surface in pixels */ + PVR2D_ULONG MaskSurfHeight; /* size of mask surface in pixels */ + + PPVR2D_ALPHABLT pAlpha; /* fully specified alpha blend (2DCore only) */ + + PVR2D_ULONG uSrcChromaPlane1; /* mem offset from start of source alloc to chroma plane 1 */ + PVR2D_ULONG uSrcChromaPlane2; /* mem offset from start of source alloc to chroma plane 2 */ + PVR2D_ULONG uDstChromaPlane1; /* mem offset from start of dest alloc to chroma plane 1 */ + PVR2D_ULONG uDstChromaPlane2; /* mem offset from start of dest alloc to chroma plane 2 */ + + PVR2D_ULONG ColourKeyMask; /* 32 bit colour key mask, only valid when PVR2D_BLIT_COLKEY_MASKED is set */ + +}PVR2DBLTINFO, *PPVR2DBLTINFO; + +typedef struct _PVR2DRECT +{ + PVR2D_LONG left, top; + PVR2D_LONG right, bottom; +} PVR2DRECT; + +typedef struct +{ + PVR2DMEMINFO *pSurfMemInfo; /* surface memory */ + PVR2D_ULONG SurfOffset; /* byte offset from start of allocation to destination surface pixel 0,0 */ + PVR2D_LONG Stride; /* signed stride */ + PVR2DFORMAT Format; /* format */ + PVR2D_ULONG SurfWidth; /* surface width in pixels */ + PVR2D_ULONG SurfHeight; /* surface height in pixels */ + +} PVR2D_SURFACE, *PPVR2D_SURFACE; + +typedef struct +{ + PVR2D_ULONG uChromaPlane1; /* YUV multiplane - byte offset from start of alloc to chroma plane 1 */ + PVR2D_ULONG uChromaPlane2; /* YUV multiplane - byte offset from start of alloc to chroma plane 2 */ + PVR2D_LONG Reserved[2]; /* Reserved, must be zero */ + +} PVR2D_SURFACE_EXT, *PPVR2D_SURFACE_EXT; + +typedef struct +{ + PVR2D_ULONG *pUseCode; /* USSE code */ + PVR2D_ULONG UseCodeSize; /* usse code size in bytes */ + +} PVR2D_USECODE, *PPVR2D_USECODE; + +typedef struct +{ + PVR2D_SURFACE sDst; /* destination surface */ + PVR2D_SURFACE sSrc; /* source surface */ + PVR2DRECT rcDest; /* destination rectangle */ + PVR2DRECT rcSource; /* source rectangle */ + PVR2D_HANDLE hUseCode; /* custom USE code (NULL implies source copy) */ + PVR2D_ULONG UseParams[2]; /* per-blt params for use code */ + +} PVR2D_3DBLT, *PPVR2D_3DBLT; + +typedef struct +{ + PVR2D_SURFACE sDst; /* destination surface */ + PVR2DRECT rcDest; /* destination rectangle; scaling is supported */ + PVR2D_SURFACE sSrc; /* source surface */ + PVR2DRECT rcSource; /* source rectangle; scaling is supported */ + PPVR2D_SURFACE pSrc2; /* optional second source surface (NULL if not required) */ + PVR2DRECT* prcSource2; /* optional pSrc2 rectangle */ + PVR2D_HANDLE hUseCode; /* custom USSE shader code (NULL implies default source copy) */ + PVR2D_ULONG UseParams[2]; /* per-blt params for usse code */ + PVR2D_ULONG uiNumTemporaryRegisters; /* no. of temporary registers used in custom shader code */ + PVR2D_BOOL bDisableDestInput; /* set true if the destination is output only */ + PPVR2D_SURFACE_EXT pDstExt; /* Extended format params for dest */ + PPVR2D_SURFACE_EXT pSrcExt[2]; /* Extended format params for source 1 and 2 */ + PVR2D_LONG Reserved[4]; /* Reserved, must be zero */ + +} PVR2D_3DBLT_EXT, *PPVR2D_3DBLT_EXT; + + +#define MAKE_COPY_BLIT(src,soff,dest,doff,sx,sy,dx,dy,sz) + +typedef void* PVR2DCONTEXTHANDLE; +typedef void* PVR2DFLIPCHAINHANDLE; + + +// CopyCode field of PVR2DBLTINFO structure: +// the CopyCode field of the PVR2DBLTINFO structure should contain a rop3 or rop4 code. +// a rop3 is an 8 bit code that describes a blt with three inputs : source dest and pattern +// rop4 is a 16 bit code that describes a blt with four inputs : source dest pattern and mask +// common rop3 codes are defined below +// a colour fill blt is processed in the pattern channel as a constant colour with a rop code of 0xF0 +// PVR2D_BLIT_PAT_SURFACE_ENABLE defines whether the pattern channel is a surface or a fill colour. +// a rop4 is defined by two rop3 codes, and the 1 bit-per-pixel mask surface defines which is used. +// a common rop4 is 0xAAF0 which is the mask copy blt used for text glyphs. +// CopyCode is taken to be a rop4 when pMaskMemInfo is non zero, otherwise it is assumed to be a rop3 +// use the PVR2DMASKROP4 macro below to construct a rop4 from two rop3's +// rop3a is the rop used when mask pixel = 1, and rop3b when mask = 0 +#define PVR2DROP4(rop3b, rop3a) ((rop3b<<8)|rop3a) + +/* common rop codes */ +#define PVR2DROPclear 0x00 /* 0 (whiteness) */ +#define PVR2DROPset 0xFF /* 1 (blackness) */ +#define PVR2DROPnoop 0xAA /* dst (used for masked blts) */ + +/* source and dest rop codes */ +#define PVR2DROPand 0x88 /* src AND dst */ +#define PVR2DROPandReverse 0x44 /* src AND NOT dst */ +#define PVR2DROPcopy 0xCC /* src (used for source copy and alpha blts) */ +#define PVR2DROPandInverted 0x22 /* NOT src AND dst */ +#define PVR2DROPxor 0x66 /* src XOR dst */ +#define PVR2DROPor 0xEE /* src OR dst */ +#define PVR2DROPnor 0x11 /* NOT src AND NOT dst */ +#define PVR2DROPequiv 0x99 /* NOT src XOR dst */ +#define PVR2DROPinvert 0x55 /* NOT dst */ +#define PVR2DROPorReverse 0xDD /* src OR NOT dst */ +#define PVR2DROPcopyInverted 0x33 /* NOT src */ +#define PVR2DROPorInverted 0xBB /* NOT src OR dst */ +#define PVR2DROPnand 0x77 /* NOT src OR NOT dst */ + +/* pattern rop codes */ +#define PVR2DPATROPand 0xA0 /* pat AND dst */ +#define PVR2DPATROPandReverse 0x50 /* pat AND NOT dst */ +#define PVR2DPATROPcopy 0xF0 /* pat (used for solid color fills and pattern blts) */ +#define PVR2DPATROPandInverted 0x0A /* NOT pat AND dst */ +#define PVR2DPATROPxor 0x5A /* pat XOR dst */ +#define PVR2DPATROPor 0xFA /* pat OR dst */ +#define PVR2DPATROPnor 0x05 /* NOT pat AND NOT dst */ +#define PVR2DPATROPequiv 0xA5 /* NOT pat XOR dst */ +#define PVR2DPATROPinvert 0x55 /* NOT dst */ +#define PVR2DPATROPorReverse 0xF5 /* pat OR NOT dst */ +#define PVR2DPATROPcopyInverted 0x0F /* NOT pat */ +#define PVR2DPATROPorInverted 0xAF /* NOT pat OR dst */ +#define PVR2DPATROPnand 0x5F /* NOT pat OR NOT dst */ + +/* common rop4 codes */ +#define PVR2DROP4MaskedCopy PVR2DROP4(PVR2DROPnoop,PVR2DROPcopy) /* masked source copy blt (used for rounded window corners etc) */ +#define PVR2DROP4MaskedFill PVR2DROP4(PVR2DROPnoop,PVR2DPATROPcopy) /* masked colour fill blt (used for text) */ + +/* Legacy support */ +#define PVR2DROP3_PATMASK PVR2DPATROPcopy +#define PVR2DROP3_SRCMASK PVR2DROPcopy + +/* pixmap memory alignment */ +#define PVR2D_ALIGNMENT_4 4 /* DWORD alignment */ +#define PVR2D_ALIGNMENT_ANY 0 /* no alignment */ +#define PVR2D_ALIGNMENT_PALETTE 16 /* 16 byte alignment is required for palettes */ + +/* Heap number for PVR2DGetFrameBuffer */ +#define PVR2D_FB_PRIMARY_SURFACE 0 + +#define PVR2D_PRESENT_PROPERTY_SRCSTRIDE (1UL << 0) +#define PVR2D_PRESENT_PROPERTY_DSTSIZE (1UL << 1) +#define PVR2D_PRESENT_PROPERTY_DSTPOS (1UL << 2) +#define PVR2D_PRESENT_PROPERTY_CLIPRECTS (1UL << 3) +#define PVR2D_PRESENT_PROPERTY_INTERVAL (1UL << 4) + +#define PVR2D_CREATE_FLIPCHAIN_SHARED (1UL << 0) +#define PVR2D_CREATE_FLIPCHAIN_QUERY (1UL << 1) +#define PVR2D_CREATE_FLIPCHAIN_OEMOVERLAY (1UL << 2) +#define PVR2D_CREATE_FLIPCHAIN_AS_BLITCHAIN (1UL << 3) + +/* Colour-key colour must be translated into argb8888 format */ +#define CKEY_8888(P) (P) +#define CKEY_4444(P) (((P&0xF000UL)<<16) | ((P&0x0F00UL)<<12) | ((P&0x00F0UL)<<8) | ((P&0x000FUL)<<4)) +#define CKEY_1555(P) (((P&0x8000UL)<<16) | ((P&0x7C00UL)<<9) | ((P&0x3E0UL)<<6) | ((P&0x1FUL)<<3)) +#define CKEY_565(P) (((P&0xF800UL)<<8) | ((P&0x7E0UL)<<5) | ((P&0x1FUL)<<3)) +#define CKEY_MASK_8888 0x00FFFFFFUL +#define CKEY_MASK_4444 0x00F0F0F0UL +#define CKEY_MASK_1555 0x00F8F8F8UL /* Alpha is not normally included in the key test */ +#define CKEY_MASK_565 0x00F8FCF8UL + +/* Fill colours must be translated into argb8888 format */ +#define CFILL_4444(P) (((P&0xF000UL)<<16) | ((P&0x0F00UL)<<12) | ((P&0x00F0UL)<<8) | ((P&0x000FUL)<<4)) +#define CFILL_1555(P) (((P&0x8000UL)<<16) | ((P&0x7C00UL)<<9) | ((P&0x3E0UL)<<6) | ((P&0x1FUL)<<3)) +#define CFILL_565(P) (((P&0xF800UL)<<8) | ((P&0x7E0UL)<<5) | ((P&0x1FUL)<<3)) + +/* PVR2DCreateDeviceContext flags */ +#define PVR2D_XSERVER_PROC 0x00000001UL /*!< Set for the Xserver connection */ + +/* PVR2DMemAlloc flags */ +#define PVR2D_MEM_UNCACHED 0x00000000UL /* Default */ +#define PVR2D_MEM_CACHED 0x00000001UL /* Caller must flush and sync when necessary */ +#define PVR2D_MEM_WRITECOMBINE 0x00000002UL + +/* Functions that the library exports */ + +PVR2D_IMPORT +int PVR2DEnumerateDevices(PVR2DDEVICEINFO *pDevInfo); + +PVR2D_IMPORT +PVR2DERROR PVR2DCreateDeviceContext(PVR2D_ULONG ulDevID, + PVR2DCONTEXTHANDLE* phContext, + PVR2D_ULONG ulFlags); + +PVR2D_IMPORT +PVR2DERROR PVR2DDestroyDeviceContext(PVR2DCONTEXTHANDLE hContext); + +PVR2D_IMPORT +PVR2DERROR PVR2DGetDeviceInfo(PVR2DCONTEXTHANDLE hContext, + PVR2DDISPLAYINFO *pDisplayInfo); + +PVR2D_IMPORT +PVR2DERROR PVR2DGetMiscDisplayInfo(PVR2DCONTEXTHANDLE hContext, + PVR2DMISCDISPLAYINFO *pMiscDisplayInfo); + +PVR2D_IMPORT +PVR2DERROR PVR2DGetScreenMode(PVR2DCONTEXTHANDLE hContext, + PVR2DFORMAT *pFormat, + PVR2D_LONG *plWidth, + PVR2D_LONG *plHeight, + PVR2D_LONG *plStride, + PVR2D_INT *piRefreshRate); + +PVR2D_IMPORT +PVR2DERROR PVR2DGetFrameBuffer(PVR2DCONTEXTHANDLE hContext, + PVR2D_INT nHeap, + PVR2DMEMINFO **ppsMemInfo); + +PVR2D_IMPORT +PVR2DERROR PVR2DMemAlloc(PVR2DCONTEXTHANDLE hContext, + PVR2D_ULONG ulBytes, + PVR2D_ULONG ulAlign, + PVR2D_ULONG ulFlags, + PVR2DMEMINFO **ppsMemInfo); + +PVR2D_IMPORT +PVR2DERROR PVR2DMemExport(PVR2DCONTEXTHANDLE hContext, + PVR2D_ULONG ulFlags, + PVR2DMEMINFO *psMemInfo, + PVR2D_HANDLE *phMemHandle); + +PVR2D_IMPORT +PVR2DERROR PVR2DMemWrap(PVR2DCONTEXTHANDLE hContext, + PVR2D_VOID *pMem, + PVR2D_ULONG ulFlags, + PVR2D_ULONG ulBytes, + PVR2D_ULONG alPageAddress[], + PVR2DMEMINFO **ppsMemInfo); + +PVR2D_IMPORT +PVR2DERROR PVR2DMemMap(PVR2DCONTEXTHANDLE hContext, + PVR2D_ULONG ulFlags, + PVR2D_HANDLE hMemHandle, + PVR2DMEMINFO **ppsDstMem); + +PVR2D_IMPORT +PVR2DERROR PVR2DMemFree(PVR2DCONTEXTHANDLE hContext, + PVR2DMEMINFO *psMemInfo); + +PVR2D_IMPORT +PVR2DERROR PVR2DBlt(PVR2DCONTEXTHANDLE hContext, + PVR2DBLTINFO *pBltInfo); + +PVR2D_IMPORT +PVR2DERROR PVR2DBltClipped(PVR2DCONTEXTHANDLE hContext, + PVR2DBLTINFO *pBltInfo, + PVR2D_ULONG ulNumClipRects, + PVR2DRECT *pClipRects); + +PVR2D_EXPORT +PVR2DERROR PVR2DSet1555Alpha (PVR2DCONTEXTHANDLE hContext, + PVR2D_UCHAR Alpha0, PVR2D_UCHAR Alpha1); + +PVR2D_IMPORT +PVR2DERROR PVR2DQueryBlitsComplete(PVR2DCONTEXTHANDLE hContext, + const PVR2DMEMINFO *pMemInfo, + PVR2D_UINT uiWaitForComplete); + +PVR2D_IMPORT +PVR2DERROR PVR2DSetPresentBltProperties(PVR2DCONTEXTHANDLE hContext, + PVR2D_ULONG ulPropertyMask, + PVR2D_LONG lSrcStride, + PVR2D_ULONG ulDstWidth, + PVR2D_ULONG ulDstHeight, + PVR2D_LONG lDstXPos, + PVR2D_LONG lDstYPos, + PVR2D_ULONG ulNumClipRects, + PVR2DRECT *pClipRects, + PVR2D_ULONG ulSwapInterval); + +PVR2D_IMPORT +PVR2DERROR PVR2DPresentBlt(PVR2DCONTEXTHANDLE hContext, + PVR2DMEMINFO *pMemInfo, + PVR2D_LONG lRenderID); + +PVR2D_IMPORT +PVR2DERROR PVR2DCreateFlipChain(PVR2DCONTEXTHANDLE hContext, + PVR2D_ULONG ulFlags, + PVR2D_ULONG ulNumBuffers, + PVR2D_ULONG ulWidth, + PVR2D_ULONG ulHeight, + PVR2DFORMAT eFormat, + PVR2D_LONG *plStride, + PVR2D_ULONG *pulFlipChainID, + PVR2DFLIPCHAINHANDLE *phFlipChain); + +PVR2D_IMPORT +PVR2DERROR PVR2DDestroyFlipChain(PVR2DCONTEXTHANDLE hContext, + PVR2DFLIPCHAINHANDLE hFlipChain); + +PVR2D_IMPORT +PVR2DERROR PVR2DGetFlipChainBuffers(PVR2DCONTEXTHANDLE hContext, + PVR2DFLIPCHAINHANDLE hFlipChain, + PVR2D_ULONG *pulNumBuffers, + PVR2DMEMINFO *psMemInfo[]); + +PVR2D_IMPORT +PVR2DERROR PVR2DSetPresentFlipProperties(PVR2DCONTEXTHANDLE hContext, + PVR2DFLIPCHAINHANDLE hFlipChain, + PVR2D_ULONG ulPropertyMask, + PVR2D_LONG lDstXPos, + PVR2D_LONG lDstYPos, + PVR2D_ULONG ulNumClipRects, + PVR2DRECT *pClipRects, + PVR2D_ULONG ulSwapInterval); + +PVR2D_IMPORT +PVR2DERROR PVR2DPresentFlip(PVR2DCONTEXTHANDLE hContext, + PVR2DFLIPCHAINHANDLE hFlipChain, + PVR2DMEMINFO *psMemInfo, + PVR2D_LONG lRenderID); + +PVR2D_IMPORT +PVR2DERROR PVR2DGetAPIRev(PVR2D_LONG *lRevMajor, PVR2D_LONG *lRevMinor); + +PVR2D_IMPORT +PVR2DERROR PVR2DLoadUseCode (const PVR2DCONTEXTHANDLE hContext, const PVR2D_UCHAR *pUseCode, + const PVR2D_ULONG UseCodeSize, PVR2D_HANDLE *pUseCodeHandle); +PVR2D_IMPORT +PVR2DERROR PVR2DFreeUseCode (const PVR2DCONTEXTHANDLE hContext, const PVR2D_HANDLE hUseCodeHandle); + +PVR2D_IMPORT +PVR2DERROR PVR2DBlt3D (const PVR2DCONTEXTHANDLE hContext, const PPVR2D_3DBLT pBlt3D); + +PVR2D_IMPORT +PVR2DERROR PVR2DBlt3DExt (const PVR2DCONTEXTHANDLE hContext, const PPVR2D_3DBLT_EXT pBlt3D); + +#ifdef __cplusplus +} +#endif + +#endif /* _PVR2D_H_ */ + +/****************************************************************************** + End of file (pvr2d.h) +******************************************************************************/ diff --git a/sys/pvr2d/pvr_includes/services.h b/sys/pvr2d/pvr_includes/services.h new file mode 100644 index 0000000000..93263a8745 --- /dev/null +++ b/sys/pvr2d/pvr_includes/services.h @@ -0,0 +1,1211 @@ +/********************************************************************** + * + * Copyright (C) Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, without any warranty; without even the + * implied warranty of merchantability or fitness for a particular purpose. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ + +#ifndef __SERVICES_H__ +#define __SERVICES_H__ + +#if defined (__cplusplus) +extern "C" { +#endif + +#include "img_defs.h" +#include "servicesext.h" + +#define PVRSRV_4K_PAGE_SIZE 4096UL + +#define PVRSRV_MAX_CMD_SIZE 1024 + +#define PVRSRV_MAX_DEVICES 16 + +#define EVENTOBJNAME_MAXLENGTH (50) + +#define PVRSRV_MEM_READ (1U<<0) +#define PVRSRV_MEM_WRITE (1U<<1) +#define PVRSRV_MEM_CACHE_CONSISTENT (1U<<2) +#define PVRSRV_MEM_NO_SYNCOBJ (1U<<3) +#define PVRSRV_MEM_INTERLEAVED (1U<<4) +#define PVRSRV_MEM_DUMMY (1U<<5) +#define PVRSRV_MEM_EDM_PROTECT (1U<<6) +#define PVRSRV_MEM_ZERO (1U<<7) +#define PVRSRV_MEM_USER_SUPPLIED_DEVVADDR (1U<<8) +#define PVRSRV_MEM_RAM_BACKED_ALLOCATION (1U<<9) +#define PVRSRV_MEM_NO_RESMAN (1U<<10) +#define PVRSRV_MEM_EXPORTED (1U<<11) + + +#define PVRSRV_HAP_CACHED (1U<<12) +#define PVRSRV_HAP_UNCACHED (1U<<13) +#define PVRSRV_HAP_SMART (1U<<20) /* XXX could we use CACHED|UNCACHED? */ +#define PVRSRV_HAP_WRITECOMBINE (1U<<14) +#define PVRSRV_HAP_CACHETYPE_MASK (PVRSRV_HAP_CACHED|PVRSRV_HAP_UNCACHED|PVRSRV_HAP_SMART|PVRSRV_HAP_WRITECOMBINE) +#define PVRSRV_HAP_KERNEL_ONLY (1U<<15) +#define PVRSRV_HAP_SINGLE_PROCESS (1U<<16) +#define PVRSRV_HAP_MULTI_PROCESS (1U<<17) +#define PVRSRV_HAP_FROM_EXISTING_PROCESS (1U<<18) +#define PVRSRV_HAP_NO_CPU_VIRTUAL (1U<<19) +#define PVRSRV_HAP_GPU_PAGEABLE (1U<<21) +#define PVRSRV_HAP_MAPTYPE_MASK (PVRSRV_HAP_KERNEL_ONLY \ + |PVRSRV_HAP_SINGLE_PROCESS \ + |PVRSRV_HAP_MULTI_PROCESS \ + |PVRSRV_HAP_FROM_EXISTING_PROCESS \ + |PVRSRV_HAP_NO_CPU_VIRTUAL\ + |PVRSRV_HAP_GPU_PAGEABLE) + +#define PVRSRV_MEM_CACHED PVRSRV_HAP_CACHED +#define PVRSRV_MEM_UNCACHED PVRSRV_HAP_UNCACHED +#define PVRSRV_MEM_SMART PVRSRV_HAP_SMART +#define PVRSRV_MEM_WRITECOMBINE PVRSRV_HAP_WRITECOMBINE + +#define PVRSRV_MEM_BACKINGSTORE_FIELD_SHIFT (24) + +#define PVRSRV_MAP_NOUSERVIRTUAL (1UL<<27) +#define PVRSRV_MEM_XPROC (1U<<28) + +#define PVRSRV_NO_CONTEXT_LOSS 0 +#define PVRSRV_SEVERE_LOSS_OF_CONTEXT 1 +#define PVRSRV_PRE_STATE_CHANGE_MASK 0x80 + + +#define PVRSRV_DEFAULT_DEV_COOKIE (1) + + +#define PVRSRV_MISC_INFO_TIMER_PRESENT (1U<<0) +#define PVRSRV_MISC_INFO_CLOCKGATE_PRESENT (1U<<1) +#define PVRSRV_MISC_INFO_MEMSTATS_PRESENT (1U<<2) +#define PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT (1U<<3) +#define PVRSRV_MISC_INFO_DDKVERSION_PRESENT (1U<<4) +#define PVRSRV_MISC_INFO_CPUCACHEOP_PRESENT (1U<<5) +#define PVRSRV_MISC_INFO_FREEMEM_PRESENT (1U<<6) + +#define PVRSRV_MISC_INFO_RESET_PRESENT (1U<<31) + +#define PVRSRV_PDUMP_MAX_FILENAME_SIZE 20 +#define PVRSRV_PDUMP_MAX_COMMENT_SIZE 200 + + +#define PVRSRV_CHANGEDEVMEM_ATTRIBS_CACHECOHERENT 0x00000001 + +#define PVRSRV_MAPEXTMEMORY_FLAGS_ALTERNATEVA 0x00000001 +#define PVRSRV_MAPEXTMEMORY_FLAGS_PHYSCONTIG 0x00000002 + +#define PVRSRV_MODIFYSYNCOPS_FLAGS_WO_INC 0x00000001 +#define PVRSRV_MODIFYSYNCOPS_FLAGS_RO_INC 0x00000002 + +#define SRV_FLAGS_PERSIST 0x1 +#define SRV_FLAGS_PDUMP_ACTIVE 0x2 + +#define PVRSRV_PDUMP_FLAGS_CONTINUOUS 0x1 + +#define PVR_FULL_CACHE_OP_THRESHOLD (0x7D000) + +typedef enum _PVRSRV_DEVICE_TYPE_ +{ + PVRSRV_DEVICE_TYPE_UNKNOWN = 0 , + PVRSRV_DEVICE_TYPE_MBX1 = 1 , + PVRSRV_DEVICE_TYPE_MBX1_LITE = 2 , + + PVRSRV_DEVICE_TYPE_M24VA = 3, + PVRSRV_DEVICE_TYPE_MVDA2 = 4, + PVRSRV_DEVICE_TYPE_MVED1 = 5, + PVRSRV_DEVICE_TYPE_MSVDX = 6, + + PVRSRV_DEVICE_TYPE_SGX = 7, + + PVRSRV_DEVICE_TYPE_VGX = 8, + + + PVRSRV_DEVICE_TYPE_EXT = 9, + + PVRSRV_DEVICE_TYPE_LAST = 9, + + PVRSRV_DEVICE_TYPE_FORCE_I32 = 0x7fffffff + +} PVRSRV_DEVICE_TYPE; + +#define HEAP_ID( _dev_ , _dev_heap_idx_ ) ( ((_dev_)<<24) | ((_dev_heap_idx_)&((1<<24)-1)) ) +#define HEAP_IDX( _heap_id_ ) ( (_heap_id_)&((1<<24) - 1 ) ) +#define HEAP_DEV( _heap_id_ ) ( (_heap_id_)>>24 ) + +#define PVRSRV_UNDEFINED_HEAP_ID (~0LU) + +typedef enum +{ + IMG_EGL = 0x00000001, + IMG_OPENGLES1 = 0x00000002, + IMG_OPENGLES2 = 0x00000003, + IMG_D3DM = 0x00000004, + IMG_SRV_UM = 0x00000005, + IMG_OPENVG = 0x00000006, + IMG_SRVCLIENT = 0x00000007, + IMG_VISTAKMD = 0x00000008, + IMG_VISTA3DNODE = 0x00000009, + IMG_VISTAMVIDEONODE = 0x0000000A, + IMG_VISTAVPBNODE = 0x0000000B, + IMG_OPENGL = 0x0000000C, + IMG_D3D = 0x0000000D, +#if defined(SUPPORT_GRAPHICS_HAL) || defined(SUPPORT_COMPOSER_HAL) + IMG_ANDROID_HAL = 0x0000000E, +#endif +#if defined(SUPPORT_OPENCL) + IMG_OPENCL = 0x0000000F, +#endif + +} IMG_MODULE_ID; + + +#define APPHINT_MAX_STRING_SIZE 256 + +typedef enum +{ + IMG_STRING_TYPE = 1, + IMG_FLOAT_TYPE , + IMG_UINT_TYPE , + IMG_INT_TYPE , + IMG_FLAG_TYPE +}IMG_DATA_TYPE; + + +typedef struct _PVRSRV_DEV_DATA_ *PPVRSRV_DEV_DATA; + +typedef struct _PVRSRV_DEVICE_IDENTIFIER_ +{ + PVRSRV_DEVICE_TYPE eDeviceType; + PVRSRV_DEVICE_CLASS eDeviceClass; + IMG_UINT32 ui32DeviceIndex; + IMG_CHAR *pszPDumpDevName; + IMG_CHAR *pszPDumpRegName; + +} PVRSRV_DEVICE_IDENTIFIER; + + +typedef struct _PVRSRV_CLIENT_DEV_DATA_ +{ + IMG_UINT32 ui32NumDevices; + PVRSRV_DEVICE_IDENTIFIER asDevID[PVRSRV_MAX_DEVICES]; + PVRSRV_ERROR (*apfnDevConnect[PVRSRV_MAX_DEVICES])(PPVRSRV_DEV_DATA); + PVRSRV_ERROR (*apfnDumpTrace[PVRSRV_MAX_DEVICES])(PPVRSRV_DEV_DATA); + +} PVRSRV_CLIENT_DEV_DATA; + + +typedef struct _PVRSRV_CONNECTION_ +{ + IMG_HANDLE hServices; + IMG_UINT32 ui32ProcessID; + PVRSRV_CLIENT_DEV_DATA sClientDevData; + IMG_UINT32 ui32SrvFlags; +}PVRSRV_CONNECTION; + + +typedef struct _PVRSRV_DEV_DATA_ +{ + IMG_CONST PVRSRV_CONNECTION *psConnection; +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hDevCookie; +#else + IMG_HANDLE hDevCookie; +#endif + +} PVRSRV_DEV_DATA; + +typedef struct _PVRSRV_MEMUPDATE_ +{ + IMG_UINT32 ui32UpdateAddr; + IMG_UINT32 ui32UpdateVal; +} PVRSRV_MEMUPDATE; + +typedef struct _PVRSRV_HWREG_ +{ + IMG_UINT32 ui32RegAddr; + IMG_UINT32 ui32RegVal; +} PVRSRV_HWREG; + +typedef struct _PVRSRV_MEMBLK_ +{ + IMG_DEV_VIRTADDR sDevVirtAddr; + IMG_HANDLE hOSMemHandle; + IMG_HANDLE hOSWrapMem; + IMG_HANDLE hBuffer; + IMG_HANDLE hResItem; + IMG_SYS_PHYADDR *psIntSysPAddr; + +} PVRSRV_MEMBLK; + +typedef struct _PVRSRV_KERNEL_MEM_INFO_ *PPVRSRV_KERNEL_MEM_INFO; + +typedef struct _PVRSRV_CLIENT_MEM_INFO_ +{ + + IMG_PVOID pvLinAddr; + + + IMG_PVOID pvLinAddrKM; + + + IMG_DEV_VIRTADDR sDevVAddr; + + + + + + + IMG_CPU_PHYADDR sCpuPAddr; + + + IMG_UINT32 ui32Flags; + + + + + IMG_UINT32 ui32ClientFlags; + + + IMG_SIZE_T uAllocSize; + + + + struct _PVRSRV_CLIENT_SYNC_INFO_ *psClientSyncInfo; + +#if defined (SUPPORT_SID_INTERFACE) + + IMG_SID hMappingInfo; + + + IMG_SID hKernelMemInfo; + + + IMG_SID hResItem; +#else + + IMG_HANDLE hMappingInfo; + + + IMG_HANDLE hKernelMemInfo; + + + IMG_HANDLE hResItem; +#endif + +#if defined(SUPPORT_MEMINFO_IDS) + #if !defined(USE_CODE) + + IMG_UINT64 ui64Stamp; + #else + IMG_UINT32 dummy1; + IMG_UINT32 dummy2; + #endif +#endif + + + + + struct _PVRSRV_CLIENT_MEM_INFO_ *psNext; + +} PVRSRV_CLIENT_MEM_INFO, *PPVRSRV_CLIENT_MEM_INFO; + + +#define PVRSRV_MAX_CLIENT_HEAPS (32) +typedef struct _PVRSRV_HEAP_INFO_ +{ + IMG_UINT32 ui32HeapID; +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hDevMemHeap; +#else + IMG_HANDLE hDevMemHeap; +#endif + IMG_DEV_VIRTADDR sDevVAddrBase; + IMG_UINT32 ui32HeapByteSize; + IMG_UINT32 ui32Attribs; + IMG_UINT32 ui32XTileStride; +}PVRSRV_HEAP_INFO; + + + + +typedef struct _PVRSRV_EVENTOBJECT_ +{ + + IMG_CHAR szName[EVENTOBJNAME_MAXLENGTH]; + +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hOSEventKM; +#else + IMG_HANDLE hOSEventKM; +#endif + +} PVRSRV_EVENTOBJECT; + +typedef enum +{ + PVRSRV_MISC_INFO_CPUCACHEOP_NONE = 0, + PVRSRV_MISC_INFO_CPUCACHEOP_CLEAN, + PVRSRV_MISC_INFO_CPUCACHEOP_FLUSH, + PVRSRV_MISC_INFO_CPUCACHEOP_CUSTOM_FLUSH, + PVRSRV_MISC_INFO_CPUCACHEOP_CUSTOM_INV +} PVRSRV_MISC_INFO_CPUCACHEOP_TYPE; + +typedef struct _PVRSRV_MISC_INFO_ +{ + IMG_UINT32 ui32StateRequest; + IMG_UINT32 ui32StatePresent; + + + IMG_VOID *pvSOCTimerRegisterKM; + IMG_VOID *pvSOCTimerRegisterUM; +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hSOCTimerRegisterOSMemHandle; + IMG_SID hSOCTimerRegisterMappingInfo; +#else + IMG_HANDLE hSOCTimerRegisterOSMemHandle; + IMG_HANDLE hSOCTimerRegisterMappingInfo; +#endif + + + IMG_VOID *pvSOCClockGateRegs; + IMG_UINT32 ui32SOCClockGateRegsSize; + + + IMG_CHAR *pszMemoryStr; + IMG_UINT32 ui32MemoryStrLen; + + + PVRSRV_EVENTOBJECT sGlobalEventObject; +#if defined (SUPPORT_SID_INTERFACE) + IMG_EVENTSID hOSGlobalEvent; +#else + IMG_HANDLE hOSGlobalEvent; +#endif + + + IMG_UINT32 aui32DDKVersion[4]; + + + struct + { + + IMG_BOOL bDeferOp; + + + PVRSRV_MISC_INFO_CPUCACHEOP_TYPE eCacheOpType; + + +#if !defined (SUPPORT_SID_INTERFACE) + union + { + + PVRSRV_CLIENT_MEM_INFO *psClientMemInfo; + + + struct _PVRSRV_KERNEL_MEM_INFO_ *psKernelMemInfo; + } u; +#endif + + + IMG_VOID *pvBaseVAddr; + + + IMG_UINT32 ui32Length; + } sCacheOpCtl; +} PVRSRV_MISC_INFO; + +typedef struct _PVRSRV_SYNC_TOKEN_ +{ + + + struct + { +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hKernelSyncInfo; +#else + IMG_HANDLE hKernelSyncInfo; +#endif + IMG_UINT32 ui32ReadOpsPendingSnapshot; + IMG_UINT32 ui32WriteOpsPendingSnapshot; + } sPrivate; +} PVRSRV_SYNC_TOKEN; + + +typedef enum _PVRSRV_CLIENT_EVENT_ +{ + PVRSRV_CLIENT_EVENT_HWTIMEOUT = 0, +} PVRSRV_CLIENT_EVENT; + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVClientEvent(IMG_CONST PVRSRV_CLIENT_EVENT eEvent, + PVRSRV_DEV_DATA *psDevData, + IMG_PVOID pvData); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVConnect(PVRSRV_CONNECTION **ppsConnection, IMG_UINT32 ui32SrvFlags); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVDisconnect(IMG_CONST PVRSRV_CONNECTION *psConnection); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVEnumerateDevices(IMG_CONST PVRSRV_CONNECTION *psConnection, + IMG_UINT32 *puiNumDevices, + PVRSRV_DEVICE_IDENTIFIER *puiDevIDs); +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVAcquireDeviceData(IMG_CONST PVRSRV_CONNECTION *psConnection, + IMG_UINT32 uiDevIndex, + PVRSRV_DEV_DATA *psDevData, + PVRSRV_DEVICE_TYPE eDeviceType); +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfo (IMG_CONST PVRSRV_CONNECTION *psConnection, PVRSRV_MISC_INFO *psMiscInfo); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVReleaseMiscInfo (IMG_CONST PVRSRV_CONNECTION *psConnection, PVRSRV_MISC_INFO *psMiscInfo); + +#if 1 +IMG_IMPORT +IMG_UINT32 ReadHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset); + +IMG_IMPORT +IMG_VOID WriteHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset, IMG_UINT32 ui32Value); + +IMG_IMPORT IMG_VOID WriteHWRegs(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Count, PVRSRV_HWREG *psHWRegs); +#endif + +IMG_IMPORT +PVRSRV_ERROR PVRSRVPollForValue ( const PVRSRV_CONNECTION *psConnection, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hOSEvent, +#else + IMG_HANDLE hOSEvent, +#endif + volatile IMG_UINT32 *pui32LinMemAddr, + IMG_UINT32 ui32Value, + IMG_UINT32 ui32Mask, + IMG_UINT32 ui32Waitus, + IMG_UINT32 ui32Tries); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVCreateDeviceMemContext(IMG_CONST PVRSRV_DEV_DATA *psDevData, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID *phDevMemContext, +#else + IMG_HANDLE *phDevMemContext, +#endif + IMG_UINT32 *pui32SharedHeapCount, + PVRSRV_HEAP_INFO *psHeapInfo); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVDestroyDeviceMemContext(IMG_CONST PVRSRV_DEV_DATA *psDevData, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hDevMemContext); +#else + IMG_HANDLE hDevMemContext); +#endif + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVGetDeviceMemHeapInfo(IMG_CONST PVRSRV_DEV_DATA *psDevData, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hDevMemContext, +#else + IMG_HANDLE hDevMemContext, +#endif + IMG_UINT32 *pui32SharedHeapCount, + PVRSRV_HEAP_INFO *psHeapInfo); + +#if defined(PVRSRV_LOG_MEMORY_ALLOCS) + #define PVRSRVAllocDeviceMem_log(psDevData, hDevMemHeap, ui32Attribs, ui32Size, ui32Alignment, ppsMemInfo, logStr) \ + (PVR_TRACE(("PVRSRVAllocDeviceMem(" #psDevData "," #hDevMemHeap "," #ui32Attribs "," #ui32Size "," #ui32Alignment "," #ppsMemInfo ")" \ + ": " logStr " (size = 0x%lx)", ui32Size)), \ + PVRSRVAllocDeviceMem(psDevData, hDevMemHeap, ui32Attribs, ui32Size, ui32Alignment, ppsMemInfo)) +#else + #define PVRSRVAllocDeviceMem_log(psDevData, hDevMemHeap, ui32Attribs, ui32Size, ui32Alignment, ppsMemInfo, logStr) \ + PVRSRVAllocDeviceMem(psDevData, hDevMemHeap, ui32Attribs, ui32Size, ui32Alignment, ppsMemInfo) +#endif + + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVAllocDeviceMem(IMG_CONST PVRSRV_DEV_DATA *psDevData, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hDevMemHeap, +#else + IMG_HANDLE hDevMemHeap, +#endif + IMG_UINT32 ui32Attribs, + IMG_SIZE_T ui32Size, + IMG_SIZE_T ui32Alignment, + PVRSRV_CLIENT_MEM_INFO **ppsMemInfo); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVFreeDeviceMem(IMG_CONST PVRSRV_DEV_DATA *psDevData, + PVRSRV_CLIENT_MEM_INFO *psMemInfo); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVRemapToDev(IMG_CONST PVRSRV_DEV_DATA *psDevData, + PVRSRV_CLIENT_MEM_INFO *psMemInfo); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVUnmapFromDev(IMG_CONST PVRSRV_DEV_DATA *psDevData, + PVRSRV_CLIENT_MEM_INFO *psMemInfo); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVExportDeviceMem(IMG_CONST PVRSRV_DEV_DATA *psDevData, + PVRSRV_CLIENT_MEM_INFO *psMemInfo, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID *phMemInfo); +#else + IMG_HANDLE *phMemInfo); +#endif + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVReserveDeviceVirtualMem(IMG_CONST PVRSRV_DEV_DATA *psDevData, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hDevMemHeap, +#else + IMG_HANDLE hDevMemHeap, +#endif + IMG_DEV_VIRTADDR *psDevVAddr, + IMG_SIZE_T ui32Size, + IMG_SIZE_T ui32Alignment, + PVRSRV_CLIENT_MEM_INFO **ppsMemInfo); +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVFreeDeviceVirtualMem(IMG_CONST PVRSRV_DEV_DATA *psDevData, + PVRSRV_CLIENT_MEM_INFO *psMemInfo); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVMapDeviceMemory (IMG_CONST PVRSRV_DEV_DATA *psDevData, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hKernelMemInfo, + IMG_SID hDstDevMemHeap, +#else + IMG_HANDLE hKernelMemInfo, + IMG_HANDLE hDstDevMemHeap, +#endif + PVRSRV_CLIENT_MEM_INFO **ppsDstMemInfo); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVUnmapDeviceMemory (IMG_CONST PVRSRV_DEV_DATA *psDevData, + PVRSRV_CLIENT_MEM_INFO *psMemInfo); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVMapExtMemory (IMG_CONST PVRSRV_DEV_DATA *psDevData, + PVRSRV_CLIENT_MEM_INFO *psMemInfo, + IMG_SYS_PHYADDR *psSysPAddr, + IMG_UINT32 ui32Flags); +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVUnmapExtMemory (IMG_CONST PVRSRV_DEV_DATA *psDevData, + PVRSRV_CLIENT_MEM_INFO *psMemInfo, + IMG_UINT32 ui32Flags); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVWrapExtMemory(IMG_CONST PVRSRV_DEV_DATA *psDevData, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hDevMemContext, +#else + IMG_HANDLE hDevMemContext, +#endif + IMG_SIZE_T ui32ByteSize, + IMG_SIZE_T ui32PageOffset, + IMG_BOOL bPhysContig, + IMG_SYS_PHYADDR *psSysPAddr, + IMG_VOID *pvLinAddr, + IMG_UINT32 ui32Flags, + PVRSRV_CLIENT_MEM_INFO **ppsMemInfo); +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVUnwrapExtMemory (IMG_CONST PVRSRV_DEV_DATA *psDevData, + PVRSRV_CLIENT_MEM_INFO *psMemInfo); + +PVRSRV_ERROR PVRSRVChangeDeviceMemoryAttributes(IMG_CONST PVRSRV_DEV_DATA *psDevData, + PVRSRV_CLIENT_MEM_INFO *psClientMemInfo, + IMG_UINT32 ui32Attribs); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVMapDeviceClassMemory (IMG_CONST PVRSRV_DEV_DATA *psDevData, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hDevMemContext, + IMG_SID hDeviceClassBuffer, +#else + IMG_HANDLE hDevMemContext, + IMG_HANDLE hDeviceClassBuffer, +#endif + PVRSRV_CLIENT_MEM_INFO **ppsMemInfo); +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVUnmapDeviceClassMemory (IMG_CONST PVRSRV_DEV_DATA *psDevData, + PVRSRV_CLIENT_MEM_INFO *psMemInfo); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVMapPhysToUserSpace(IMG_CONST PVRSRV_DEV_DATA *psDevData, + IMG_SYS_PHYADDR sSysPhysAddr, + IMG_UINT32 uiSizeInBytes, + IMG_PVOID *ppvUserAddr, + IMG_UINT32 *puiActualSize, + IMG_PVOID *ppvProcess); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVUnmapPhysToUserSpace(IMG_CONST PVRSRV_DEV_DATA *psDevData, + IMG_PVOID pvUserAddr, + IMG_PVOID pvProcess); + +#if defined(LINUX) +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVExportDeviceMem2(IMG_CONST PVRSRV_DEV_DATA *psDevData, + PVRSRV_CLIENT_MEM_INFO *psMemInfo, + IMG_INT *iFd); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVMapDeviceMemory2(IMG_CONST PVRSRV_DEV_DATA *psDevData, + IMG_INT iFd, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hDstDevMemHeap, +#else + IMG_HANDLE hDstDevMemHeap, +#endif + PVRSRV_CLIENT_MEM_INFO **ppsDstMemInfo); +#endif + +typedef enum _PVRSRV_SYNCVAL_MODE_ +{ + PVRSRV_SYNCVAL_READ = IMG_TRUE, + PVRSRV_SYNCVAL_WRITE = IMG_FALSE, + +} PVRSRV_SYNCVAL_MODE, *PPVRSRV_SYNCVAL_MODE; + +typedef IMG_UINT32 PVRSRV_SYNCVAL; + +IMG_IMPORT PVRSRV_ERROR PVRSRVWaitForOpsComplete(PPVRSRV_CLIENT_MEM_INFO psMemInfo, + PVRSRV_SYNCVAL_MODE eMode, PVRSRV_SYNCVAL OpRequired); + +IMG_IMPORT PVRSRV_ERROR PVRSRVWaitForAllOpsComplete(PPVRSRV_CLIENT_MEM_INFO psMemInfo, + PVRSRV_SYNCVAL_MODE eMode); + +IMG_IMPORT IMG_BOOL PVRSRVTestOpsComplete(PPVRSRV_CLIENT_MEM_INFO psMemInfo, + PVRSRV_SYNCVAL_MODE eMode, PVRSRV_SYNCVAL OpRequired); + +IMG_IMPORT IMG_BOOL PVRSRVTestAllOpsComplete(PPVRSRV_CLIENT_MEM_INFO psMemInfo, + PVRSRV_SYNCVAL_MODE eMode); + +IMG_IMPORT IMG_BOOL PVRSRVTestOpsNotComplete(PPVRSRV_CLIENT_MEM_INFO psMemInfo, + PVRSRV_SYNCVAL_MODE eMode, PVRSRV_SYNCVAL OpRequired); + +IMG_IMPORT IMG_BOOL PVRSRVTestAllOpsNotComplete(PPVRSRV_CLIENT_MEM_INFO psMemInfo, + PVRSRV_SYNCVAL_MODE eMode); + +IMG_IMPORT PVRSRV_SYNCVAL PVRSRVGetPendingOpSyncVal(PPVRSRV_CLIENT_MEM_INFO psMemInfo, + PVRSRV_SYNCVAL_MODE eMode); + + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVEnumerateDeviceClass(IMG_CONST PVRSRV_CONNECTION *psConnection, + PVRSRV_DEVICE_CLASS DeviceClass, + IMG_UINT32 *pui32DevCount, + IMG_UINT32 *pui32DevID); + +IMG_IMPORT +IMG_HANDLE IMG_CALLCONV PVRSRVOpenDCDevice(IMG_CONST PVRSRV_DEV_DATA *psDevData, + IMG_UINT32 ui32DeviceID); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVCloseDCDevice(IMG_CONST PVRSRV_CONNECTION *psConnection, IMG_HANDLE hDevice); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVEnumDCFormats (IMG_HANDLE hDevice, + IMG_UINT32 *pui32Count, + DISPLAY_FORMAT *psFormat); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVEnumDCDims (IMG_HANDLE hDevice, + IMG_UINT32 *pui32Count, + DISPLAY_FORMAT *psFormat, + DISPLAY_DIMS *psDims); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVGetDCSystemBuffer(IMG_HANDLE hDevice, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID *phBuffer); +#else + IMG_HANDLE *phBuffer); +#endif + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVGetDCInfo(IMG_HANDLE hDevice, + DISPLAY_INFO* psDisplayInfo); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVCreateDCSwapChain (IMG_HANDLE hDevice, + IMG_UINT32 ui32Flags, + DISPLAY_SURF_ATTRIBUTES *psDstSurfAttrib, + DISPLAY_SURF_ATTRIBUTES *psSrcSurfAttrib, + IMG_UINT32 ui32BufferCount, + IMG_UINT32 ui32OEMFlags, + IMG_UINT32 *pui32SwapChainID, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID *phSwapChain); +#else + IMG_HANDLE *phSwapChain); +#endif + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVDestroyDCSwapChain (IMG_HANDLE hDevice, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hSwapChain); +#else + IMG_HANDLE hSwapChain); +#endif + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVSetDCDstRect (IMG_HANDLE hDevice, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hSwapChain, +#else + IMG_HANDLE hSwapChain, +#endif + IMG_RECT *psDstRect); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVSetDCSrcRect (IMG_HANDLE hDevice, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hSwapChain, +#else + IMG_HANDLE hSwapChain, +#endif + IMG_RECT *psSrcRect); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVSetDCDstColourKey (IMG_HANDLE hDevice, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hSwapChain, +#else + IMG_HANDLE hSwapChain, +#endif + IMG_UINT32 ui32CKColour); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVSetDCSrcColourKey (IMG_HANDLE hDevice, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hSwapChain, +#else + IMG_HANDLE hSwapChain, +#endif + IMG_UINT32 ui32CKColour); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVGetDCBuffers(IMG_HANDLE hDevice, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hSwapChain, + IMG_SID *phBuffer); +#else + IMG_HANDLE hSwapChain, + IMG_HANDLE *phBuffer); +#endif + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVSwapToDCBuffer (IMG_HANDLE hDevice, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hBuffer, +#else + IMG_HANDLE hBuffer, +#endif + IMG_UINT32 ui32ClipRectCount, + IMG_RECT *psClipRect, + IMG_UINT32 ui32SwapInterval, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hPrivateTag); +#else + IMG_HANDLE hPrivateTag); +#endif + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVSwapToDCSystem (IMG_HANDLE hDevice, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hSwapChain); +#else + IMG_HANDLE hSwapChain); +#endif + + +IMG_IMPORT +IMG_HANDLE IMG_CALLCONV PVRSRVOpenBCDevice(IMG_CONST PVRSRV_DEV_DATA *psDevData, + IMG_UINT32 ui32DeviceID); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVCloseBCDevice(IMG_CONST PVRSRV_CONNECTION *psConnection, + IMG_HANDLE hDevice); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVGetBCBufferInfo(IMG_HANDLE hDevice, + BUFFER_INFO *psBuffer); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVGetBCBuffer(IMG_HANDLE hDevice, + IMG_UINT32 ui32BufferIndex, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID *phBuffer); +#else + IMG_HANDLE *phBuffer); +#endif + + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVPDumpInit(IMG_CONST PVRSRV_CONNECTION *psConnection); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVPDumpStartInitPhase(IMG_CONST PVRSRV_CONNECTION *psConnection); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVPDumpStopInitPhase(IMG_CONST PVRSRV_CONNECTION *psConnection); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVPDumpSyncPol(IMG_CONST PVRSRV_CONNECTION *psConnection, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hKernelSyncInfo, +#else + PVRSRV_CLIENT_SYNC_INFO *psClientSyncInfo, +#endif + IMG_BOOL bIsRead, + IMG_UINT32 ui32Value, + IMG_UINT32 ui32Mask); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVPDumpSyncPol2(IMG_CONST PVRSRV_CONNECTION *psConnection, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hKernelSyncInfo, +#else + PVRSRV_CLIENT_SYNC_INFO *psClientSyncInfo, +#endif + IMG_BOOL bIsRead); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVPDumpMem(IMG_CONST PVRSRV_CONNECTION *psConnection, + IMG_PVOID pvAltLinAddr, + PVRSRV_CLIENT_MEM_INFO *psMemInfo, + IMG_UINT32 ui32Offset, + IMG_UINT32 ui32Bytes, + IMG_UINT32 ui32Flags); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVPDumpSync(IMG_CONST PVRSRV_CONNECTION *psConnection, + IMG_PVOID pvAltLinAddr, + PVRSRV_CLIENT_SYNC_INFO *psClientSyncInfo, + IMG_UINT32 ui32Offset, + IMG_UINT32 ui32Bytes); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVPDumpReg(IMG_CONST PVRSRV_DEV_DATA *psDevData, + IMG_CHAR *pszRegRegion, + IMG_UINT32 ui32RegAddr, + IMG_UINT32 ui32RegValue, + IMG_UINT32 ui32Flags); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVPDumpRegPolWithFlags(const PVRSRV_DEV_DATA *psDevData, + IMG_CHAR *pszRegRegion, + IMG_UINT32 ui32RegAddr, + IMG_UINT32 ui32RegValue, + IMG_UINT32 ui32Mask, + IMG_UINT32 ui32Flags); +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVPDumpRegPol(const PVRSRV_DEV_DATA *psDevData, + IMG_CHAR *pszRegRegion, + IMG_UINT32 ui32RegAddr, + IMG_UINT32 ui32RegValue, + IMG_UINT32 ui32Mask); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVPDumpPDReg(IMG_CONST PVRSRV_CONNECTION *psConnection, + IMG_UINT32 ui32RegAddr, + IMG_UINT32 ui32RegValue); +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVPDumpPDDevPAddr(IMG_CONST PVRSRV_CONNECTION *psConnection, + PVRSRV_CLIENT_MEM_INFO *psMemInfo, + IMG_UINT32 ui32Offset, + IMG_DEV_PHYADDR sPDDevPAddr); + +#if !defined(USE_CODE) +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVPDumpMemPages(IMG_CONST PVRSRV_DEV_DATA *psDevData, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hKernelMemInfo, +#else + IMG_HANDLE hKernelMemInfo, +#endif + IMG_DEV_PHYADDR *pPages, + IMG_UINT32 ui32NumPages, + IMG_DEV_VIRTADDR sDevVAddr, + IMG_UINT32 ui32Start, + IMG_UINT32 ui32Length, + IMG_UINT32 ui32Flags); +#endif + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVPDumpSetFrame(IMG_CONST PVRSRV_CONNECTION *psConnection, + IMG_UINT32 ui32Frame); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVPDumpComment(IMG_CONST PVRSRV_CONNECTION *psConnection, + IMG_CONST IMG_CHAR *pszComment, + IMG_BOOL bContinuous); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVPDumpCommentf(IMG_CONST PVRSRV_CONNECTION *psConnection, + IMG_BOOL bContinuous, + IMG_CONST IMG_CHAR *pszFormat, ...) +#if !defined(USE_CODE) + IMG_FORMAT_PRINTF(3, 4) +#endif +; + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVPDumpCommentWithFlagsf(IMG_CONST PVRSRV_CONNECTION *psConnection, + IMG_UINT32 ui32Flags, + IMG_CONST IMG_CHAR *pszFormat, ...) +#if !defined(USE_CODE) + IMG_FORMAT_PRINTF(3, 4) +#endif +; + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVPDumpDriverInfo(IMG_CONST PVRSRV_CONNECTION *psConnection, + IMG_CHAR *pszString, + IMG_BOOL bContinuous); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVPDumpIsCapturing(IMG_CONST PVRSRV_CONNECTION *psConnection, + IMG_BOOL *pbIsCapturing); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVPDumpRegRead(IMG_CONST PVRSRV_DEV_DATA *psDevData, + IMG_CONST IMG_CHAR *pszRegRegion, + IMG_CONST IMG_CHAR *pszFileName, + IMG_UINT32 ui32FileOffset, + IMG_UINT32 ui32Address, + IMG_UINT32 ui32Size, + IMG_UINT32 ui32PDumpFlags); + + +IMG_IMPORT +IMG_BOOL IMG_CALLCONV PVRSRVPDumpIsCapturingTest(IMG_CONST PVRSRV_CONNECTION *psConnection); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVPDumpCycleCountRegRead(IMG_CONST PVRSRV_DEV_DATA *psDevData, + IMG_UINT32 ui32RegOffset, + IMG_BOOL bLastFrame); + +IMG_IMPORT IMG_HANDLE PVRSRVLoadLibrary(const IMG_CHAR *pszLibraryName); +IMG_IMPORT PVRSRV_ERROR PVRSRVUnloadLibrary(IMG_HANDLE hExtDrv); +IMG_IMPORT PVRSRV_ERROR PVRSRVGetLibFuncAddr(IMG_HANDLE hExtDrv, const IMG_CHAR *pszFunctionName, IMG_VOID **ppvFuncAddr); + +IMG_IMPORT IMG_UINT32 PVRSRVClockus (void); +IMG_IMPORT IMG_VOID PVRSRVWaitus (IMG_UINT32 ui32Timeus); +IMG_IMPORT IMG_VOID PVRSRVReleaseThreadQuanta (void); +IMG_IMPORT IMG_UINT32 IMG_CALLCONV PVRSRVGetCurrentProcessID(void); +IMG_IMPORT IMG_CHAR * IMG_CALLCONV PVRSRVSetLocale(const IMG_CHAR *pszLocale); + + + + + +IMG_IMPORT IMG_VOID IMG_CALLCONV PVRSRVCreateAppHintState(IMG_MODULE_ID eModuleID, + const IMG_CHAR *pszAppName, + IMG_VOID **ppvState); +IMG_IMPORT IMG_VOID IMG_CALLCONV PVRSRVFreeAppHintState(IMG_MODULE_ID eModuleID, + IMG_VOID *pvHintState); + +IMG_IMPORT IMG_BOOL IMG_CALLCONV PVRSRVGetAppHint(IMG_VOID *pvHintState, + const IMG_CHAR *pszHintName, + IMG_DATA_TYPE eDataType, + const IMG_VOID *pvDefault, + IMG_VOID *pvReturn); + +IMG_IMPORT IMG_PVOID IMG_CALLCONV PVRSRVAllocUserModeMem (IMG_SIZE_T ui32Size); +IMG_IMPORT IMG_PVOID IMG_CALLCONV PVRSRVCallocUserModeMem (IMG_SIZE_T ui32Size); +IMG_IMPORT IMG_PVOID IMG_CALLCONV PVRSRVReallocUserModeMem (IMG_PVOID pvBase, IMG_SIZE_T uNewSize); +IMG_IMPORT IMG_VOID IMG_CALLCONV PVRSRVFreeUserModeMem (IMG_PVOID pvMem); +IMG_IMPORT IMG_VOID PVRSRVMemCopy(IMG_VOID *pvDst, const IMG_VOID *pvSrc, IMG_SIZE_T ui32Size); +IMG_IMPORT IMG_VOID PVRSRVMemSet(IMG_VOID *pvDest, IMG_UINT8 ui8Value, IMG_SIZE_T ui32Size); + +struct _PVRSRV_MUTEX_OPAQUE_STRUCT_; +typedef struct _PVRSRV_MUTEX_OPAQUE_STRUCT_ *PVRSRV_MUTEX_HANDLE; + +IMG_IMPORT PVRSRV_ERROR IMG_CALLCONV PVRSRVCreateMutex(PVRSRV_MUTEX_HANDLE *phMutex); +IMG_IMPORT PVRSRV_ERROR IMG_CALLCONV PVRSRVDestroyMutex(PVRSRV_MUTEX_HANDLE hMutex); +IMG_IMPORT IMG_VOID IMG_CALLCONV PVRSRVLockMutex(PVRSRV_MUTEX_HANDLE hMutex); +IMG_IMPORT IMG_VOID IMG_CALLCONV PVRSRVUnlockMutex(PVRSRV_MUTEX_HANDLE hMutex); + +IMG_IMPORT IMG_VOID IMG_CALLCONV PVRSRVLockProcessGlobalMutex(void); +IMG_IMPORT IMG_VOID IMG_CALLCONV PVRSRVUnlockProcessGlobalMutex(void); + + +struct _PVRSRV_SEMAPHORE_OPAQUE_STRUCT_; +typedef struct _PVRSRV_SEMAPHORE_OPAQUE_STRUCT_ *PVRSRV_SEMAPHORE_HANDLE; + + + #define IMG_SEMAPHORE_WAIT_INFINITE ((IMG_UINT64)0xFFFFFFFFFFFFFFFFull) + + +#if !defined(USE_CODE) + +#ifdef INLINE_IS_PRAGMA +#pragma inline(PVRSRVCreateSemaphore) +#endif +static INLINE PVRSRV_ERROR PVRSRVCreateSemaphore(PVRSRV_SEMAPHORE_HANDLE *phSemaphore, IMG_INT iInitialCount) +{ + PVR_UNREFERENCED_PARAMETER(iInitialCount); + *phSemaphore = 0; + return PVRSRV_OK; +} + +#ifdef INLINE_IS_PRAGMA +#pragma inline(PVRSRVDestroySemaphore) +#endif +static INLINE PVRSRV_ERROR PVRSRVDestroySemaphore(PVRSRV_SEMAPHORE_HANDLE hSemaphore) +{ + PVR_UNREFERENCED_PARAMETER(hSemaphore); + return PVRSRV_OK; +} + +#ifdef INLINE_IS_PRAGMA +#pragma inline(PVRSRVWaitSemaphore) +#endif +static INLINE PVRSRV_ERROR PVRSRVWaitSemaphore(PVRSRV_SEMAPHORE_HANDLE hSemaphore, IMG_UINT64 ui64TimeoutMicroSeconds) +{ + PVR_UNREFERENCED_PARAMETER(hSemaphore); + PVR_UNREFERENCED_PARAMETER(ui64TimeoutMicroSeconds); + return PVRSRV_ERROR_INVALID_PARAMS; +} + +#ifdef INLINE_IS_PRAGMA +#pragma inline(PVRSRVPostSemaphore) +#endif +static INLINE IMG_VOID PVRSRVPostSemaphore(PVRSRV_SEMAPHORE_HANDLE hSemaphore, IMG_INT iPostCount) +{ + PVR_UNREFERENCED_PARAMETER(hSemaphore); + PVR_UNREFERENCED_PARAMETER(iPostCount); +} + +#endif + + +#if (defined(DEBUG) && defined(__linux__)) +IMG_IMPORT IMG_PVOID IMG_CALLCONV PVRSRVAllocUserModeMemTracking(IMG_SIZE_T ui32Size, IMG_CHAR *pszFileName, IMG_UINT32 ui32LineNumber); + +IMG_IMPORT IMG_PVOID IMG_CALLCONV PVRSRVCallocUserModeMemTracking(IMG_SIZE_T ui32Size, IMG_CHAR *pszFileName, IMG_UINT32 ui32LineNumber); + +IMG_IMPORT IMG_VOID IMG_CALLCONV PVRSRVFreeUserModeMemTracking(IMG_VOID *pvMem); + +IMG_IMPORT IMG_PVOID IMG_CALLCONV PVRSRVReallocUserModeMemTracking(IMG_VOID *pvMem, IMG_SIZE_T ui32NewSize, + IMG_CHAR *pszFileName, IMG_UINT32 ui32LineNumber); +#endif + +IMG_IMPORT PVRSRV_ERROR PVRSRVEventObjectWait(const PVRSRV_CONNECTION *psConnection, +#if defined (SUPPORT_SID_INTERFACE) + IMG_EVENTSID hOSEvent); +#else + IMG_HANDLE hOSEvent); +#endif + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVCreateSyncInfoModObj(const PVRSRV_CONNECTION *psConnection, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID *phKernelSyncInfoModObj); +#else + IMG_HANDLE *phKernelSyncInfoModObj); +#endif + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVDestroySyncInfoModObj(const PVRSRV_CONNECTION *psConnection, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hKernelSyncInfoModObj); +#else + IMG_HANDLE hKernelSyncInfoModObj); +#endif + + + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVModifyPendingSyncOps(const PVRSRV_CONNECTION *psConnection, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hKernelSyncInfoModObj, +#else + IMG_HANDLE hKernelSyncInfoModObj, +#endif + PVRSRV_CLIENT_SYNC_INFO *psSyncInfo, + IMG_UINT32 ui32ModifyFlags, + IMG_UINT32 *pui32ReadOpsPending, + IMG_UINT32 *pui32WriteOpsPending); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVModifyCompleteSyncOps(const PVRSRV_CONNECTION *psConnection, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hKernelSyncInfoModObj); +#else + IMG_HANDLE hKernelSyncInfoModObj); +#endif + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVSyncOpsTakeToken(const PVRSRV_CONNECTION *psConnection, +#if defined (SUPPORT_SID_INTERFACE) + const IMG_SID hKernelSyncInfo, +#else + const PVRSRV_CLIENT_SYNC_INFO *psSyncInfo, +#endif + PVRSRV_SYNC_TOKEN *psSyncToken); +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVSyncOpsFlushToToken(const PVRSRV_CONNECTION *psConnection, +#if defined (SUPPORT_SID_INTERFACE) + const IMG_SID hKernelSyncInfo, +#else + const PVRSRV_CLIENT_SYNC_INFO *psSyncInfo, +#endif + const PVRSRV_SYNC_TOKEN *psSyncToken, + IMG_BOOL bWait); +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVSyncOpsFlushToModObj(const PVRSRV_CONNECTION *psConnection, +#if defined (SUPPORT_SID_INTERFACE) + IMG_SID hKernelSyncInfoModObj, +#else + IMG_HANDLE hKernelSyncInfoModObj, +#endif + IMG_BOOL bWait); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVSyncOpsFlushToDelta(const PVRSRV_CONNECTION *psConnection, + PVRSRV_CLIENT_SYNC_INFO *psClientSyncInfo, + IMG_UINT32 ui32Delta, + IMG_BOOL bWait); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVAllocSyncInfo(IMG_CONST PVRSRV_DEV_DATA *psDevData, + PVRSRV_CLIENT_SYNC_INFO **ppsSyncInfo); + +IMG_IMPORT +PVRSRV_ERROR IMG_CALLCONV PVRSRVFreeSyncInfo(IMG_CONST PVRSRV_DEV_DATA *psDevData, + PVRSRV_CLIENT_SYNC_INFO *psSyncInfo); + +IMG_IMPORT +const IMG_CHAR *PVRSRVGetErrorString(PVRSRV_ERROR eError); + + +#define TIME_NOT_PASSED_UINT32(a,b,c) (((a) - (b)) < (c)) + +#if defined (__cplusplus) +} +#endif +#endif + diff --git a/sys/pvr2d/pvr_includes/servicesext.h b/sys/pvr2d/pvr_includes/servicesext.h new file mode 100755 index 0000000000..d326245116 --- /dev/null +++ b/sys/pvr2d/pvr_includes/servicesext.h @@ -0,0 +1,855 @@ +/********************************************************************** +* +* Copyright(c) Imagination Technologies Ltd. +* +* The contents of this file are subject to the MIT license as set out below. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT +* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +* This License is also included in this distribution in the file called +* "COPYING". +* +******************************************************************************/ + + + +#if !defined (__SERVICESEXT_H__) +#define __SERVICESEXT_H__ + +#define PVRSRV_LOCKFLG_READONLY (1) + +typedef enum _PVRSRV_ERROR_ +{ + PVRSRV_OK = 0, + PVRSRV_ERROR_OUT_OF_MEMORY, + PVRSRV_ERROR_TOO_FEW_BUFFERS, + PVRSRV_ERROR_INVALID_PARAMS, + PVRSRV_ERROR_INIT_FAILURE, + PVRSRV_ERROR_CANT_REGISTER_CALLBACK, + PVRSRV_ERROR_INVALID_DEVICE, + PVRSRV_ERROR_NOT_OWNER, + PVRSRV_ERROR_BAD_MAPPING, + PVRSRV_ERROR_TIMEOUT, + PVRSRV_ERROR_FLIP_CHAIN_EXISTS, + PVRSRV_ERROR_INVALID_SWAPINTERVAL, + PVRSRV_ERROR_SCENE_INVALID, + PVRSRV_ERROR_STREAM_ERROR, + PVRSRV_ERROR_FAILED_DEPENDENCIES, + PVRSRV_ERROR_CMD_NOT_PROCESSED, + PVRSRV_ERROR_CMD_TOO_BIG, + PVRSRV_ERROR_DEVICE_REGISTER_FAILED, + PVRSRV_ERROR_TOOMANYBUFFERS, + PVRSRV_ERROR_NOT_SUPPORTED, + PVRSRV_ERROR_PROCESSING_BLOCKED, + + PVRSRV_ERROR_CANNOT_FLUSH_QUEUE, + PVRSRV_ERROR_CANNOT_GET_QUEUE_SPACE, + PVRSRV_ERROR_CANNOT_GET_RENDERDETAILS, + PVRSRV_ERROR_RETRY, + + PVRSRV_ERROR_DDK_VERSION_MISMATCH, + PVRSRV_ERROR_BUILD_MISMATCH, + PVRSRV_ERROR_CORE_REVISION_MISMATCH, + + PVRSRV_ERROR_UPLOAD_TOO_BIG, + + PVRSRV_ERROR_INVALID_FLAGS, + PVRSRV_ERROR_FAILED_TO_REGISTER_PROCESS, + + PVRSRV_ERROR_UNABLE_TO_LOAD_LIBRARY, + PVRSRV_ERROR_UNABLE_GET_FUNC_ADDR, + PVRSRV_ERROR_UNLOAD_LIBRARY_FAILED, + + PVRSRV_ERROR_BRIDGE_CALL_FAILED, + PVRSRV_ERROR_IOCTL_CALL_FAILED, + + PVRSRV_ERROR_MMU_CONTEXT_NOT_FOUND, + PVRSRV_ERROR_BUFFER_DEVICE_NOT_FOUND, + PVRSRV_ERROR_BUFFER_DEVICE_ALREADY_PRESENT, + + PVRSRV_ERROR_PCI_DEVICE_NOT_FOUND, + PVRSRV_ERROR_PCI_CALL_FAILED, + PVRSRV_ERROR_PCI_REGION_TOO_SMALL, + PVRSRV_ERROR_PCI_REGION_UNAVAILABLE, + PVRSRV_ERROR_BAD_REGION_SIZE_MISMATCH, + + PVRSRV_ERROR_REGISTER_BASE_NOT_SET, + + PVRSRV_ERROR_FAILED_TO_ALLOC_USER_MEM, + PVRSRV_ERROR_FAILED_TO_ALLOC_VP_MEMORY, + PVRSRV_ERROR_FAILED_TO_MAP_SHARED_PBDESC, + PVRSRV_ERROR_FAILED_TO_GET_PHYS_ADDR, + + PVRSRV_ERROR_FAILED_TO_ALLOC_VIRT_MEMORY, + PVRSRV_ERROR_FAILED_TO_COPY_VIRT_MEMORY, + + PVRSRV_ERROR_FAILED_TO_ALLOC_PAGES, + PVRSRV_ERROR_FAILED_TO_FREE_PAGES, + PVRSRV_ERROR_FAILED_TO_COPY_PAGES, + PVRSRV_ERROR_UNABLE_TO_LOCK_PAGES, + PVRSRV_ERROR_UNABLE_TO_UNLOCK_PAGES, + PVRSRV_ERROR_STILL_MAPPED, + PVRSRV_ERROR_MAPPING_NOT_FOUND, + PVRSRV_ERROR_PHYS_ADDRESS_EXCEEDS_32BIT, + PVRSRV_ERROR_FAILED_TO_MAP_PAGE_TABLE, + + PVRSRV_ERROR_INVALID_SEGMENT_BLOCK, + PVRSRV_ERROR_INVALID_SGXDEVDATA, + PVRSRV_ERROR_INVALID_DEVINFO, + PVRSRV_ERROR_INVALID_MEMINFO, + PVRSRV_ERROR_INVALID_MISCINFO, + PVRSRV_ERROR_UNKNOWN_IOCTL, + PVRSRV_ERROR_INVALID_CONTEXT, + PVRSRV_ERROR_UNABLE_TO_DESTROY_CONTEXT, + PVRSRV_ERROR_INVALID_HEAP, + PVRSRV_ERROR_INVALID_KERNELINFO, + PVRSRV_ERROR_UNKNOWN_POWER_STATE, + PVRSRV_ERROR_INVALID_HANDLE_TYPE, + PVRSRV_ERROR_INVALID_WRAP_TYPE, + PVRSRV_ERROR_INVALID_PHYS_ADDR, + PVRSRV_ERROR_INVALID_CPU_ADDR, + PVRSRV_ERROR_INVALID_HEAPINFO, + PVRSRV_ERROR_INVALID_PERPROC, + PVRSRV_ERROR_FAILED_TO_RETRIEVE_HEAPINFO, + PVRSRV_ERROR_INVALID_MAP_REQUEST, + PVRSRV_ERROR_INVALID_UNMAP_REQUEST, + PVRSRV_ERROR_UNABLE_TO_FIND_MAPPING_HEAP, + PVRSRV_ERROR_MAPPING_STILL_IN_USE, + + PVRSRV_ERROR_EXCEEDED_HW_LIMITS, + PVRSRV_ERROR_NO_STAGING_BUFFER_ALLOCATED, + + PVRSRV_ERROR_UNABLE_TO_CREATE_PERPROC_AREA, + PVRSRV_ERROR_UNABLE_TO_CREATE_EVENT, + PVRSRV_ERROR_UNABLE_TO_ENABLE_EVENT, + PVRSRV_ERROR_UNABLE_TO_REGISTER_EVENT, + PVRSRV_ERROR_UNABLE_TO_DESTROY_EVENT, + PVRSRV_ERROR_UNABLE_TO_CREATE_THREAD, + PVRSRV_ERROR_UNABLE_TO_CLOSE_THREAD, + PVRSRV_ERROR_THREAD_READ_ERROR, + PVRSRV_ERROR_UNABLE_TO_REGISTER_ISR_HANDLER, + PVRSRV_ERROR_UNABLE_TO_INSTALL_ISR, + PVRSRV_ERROR_UNABLE_TO_UNINSTALL_ISR, + PVRSRV_ERROR_ISR_ALREADY_INSTALLED, + PVRSRV_ERROR_ISR_NOT_INSTALLED, + PVRSRV_ERROR_UNABLE_TO_INITIALISE_INTERRUPT, + PVRSRV_ERROR_UNABLE_TO_RETRIEVE_INFO, + PVRSRV_ERROR_UNABLE_TO_DO_BACKWARDS_BLIT, + PVRSRV_ERROR_UNABLE_TO_CLOSE_SERVICES, + PVRSRV_ERROR_UNABLE_TO_REGISTER_CONTEXT, + PVRSRV_ERROR_UNABLE_TO_REGISTER_RESOURCE, + + PVRSRV_ERROR_INVALID_CCB_COMMAND, + + PVRSRV_ERROR_UNABLE_TO_LOCK_RESOURCE, + PVRSRV_ERROR_INVALID_LOCK_ID, + PVRSRV_ERROR_RESOURCE_NOT_LOCKED, + + PVRSRV_ERROR_FLIP_FAILED, + PVRSRV_ERROR_UNBLANK_DISPLAY_FAILED, + + PVRSRV_ERROR_TIMEOUT_POLLING_FOR_VALUE, + + PVRSRV_ERROR_CREATE_RENDER_CONTEXT_FAILED, + PVRSRV_ERROR_UNKNOWN_PRIMARY_FRAG, + PVRSRV_ERROR_UNEXPECTED_SECONDARY_FRAG, + PVRSRV_ERROR_UNEXPECTED_PRIMARY_FRAG, + + PVRSRV_ERROR_UNABLE_TO_INSERT_FENCE_ID, + + PVRSRV_ERROR_BLIT_SETUP_FAILED, + + PVRSRV_ERROR_PDUMP_NOT_AVAILABLE, + PVRSRV_ERROR_PDUMP_BUFFER_FULL, + PVRSRV_ERROR_PDUMP_BUF_OVERFLOW, + PVRSRV_ERROR_PDUMP_NOT_ACTIVE, + PVRSRV_ERROR_INCOMPLETE_LINE_OVERLAPS_PAGES, + + PVRSRV_ERROR_MUTEX_DESTROY_FAILED, + PVRSRV_ERROR_MUTEX_INTERRUPTIBLE_ERROR, + + PVRSRV_ERROR_INSUFFICIENT_SCRIPT_SPACE, + PVRSRV_ERROR_INSUFFICIENT_SPACE_FOR_COMMAND, + + PVRSRV_ERROR_PROCESS_NOT_INITIALISED, + PVRSRV_ERROR_PROCESS_NOT_FOUND, + PVRSRV_ERROR_SRV_CONNECT_FAILED, + PVRSRV_ERROR_SRV_DISCONNECT_FAILED, + PVRSRV_ERROR_DEINT_PHASE_FAILED, + PVRSRV_ERROR_INIT2_PHASE_FAILED, + + PVRSRV_ERROR_UNABLE_TO_FIND_RESOURCE, + + PVRSRV_ERROR_NO_DC_DEVICES_FOUND, + PVRSRV_ERROR_UNABLE_TO_OPEN_DC_DEVICE, + PVRSRV_ERROR_UNABLE_TO_REMOVE_DEVICE, + PVRSRV_ERROR_NO_DEVICEDATA_FOUND, + PVRSRV_ERROR_NO_DEVICENODE_FOUND, + PVRSRV_ERROR_NO_CLIENTNODE_FOUND, + PVRSRV_ERROR_FAILED_TO_PROCESS_QUEUE, + + PVRSRV_ERROR_UNABLE_TO_INIT_TASK, + PVRSRV_ERROR_UNABLE_TO_SCHEDULE_TASK, + PVRSRV_ERROR_UNABLE_TO_KILL_TASK, + + PVRSRV_ERROR_UNABLE_TO_ENABLE_TIMER, + PVRSRV_ERROR_UNABLE_TO_DISABLE_TIMER, + PVRSRV_ERROR_UNABLE_TO_REMOVE_TIMER, + + PVRSRV_ERROR_UNKNOWN_PIXEL_FORMAT, + PVRSRV_ERROR_UNKNOWN_SCRIPT_OPERATION, + + PVRSRV_ERROR_HANDLE_INDEX_OUT_OF_RANGE, + PVRSRV_ERROR_HANDLE_NOT_ALLOCATED, + PVRSRV_ERROR_HANDLE_TYPE_MISMATCH, + PVRSRV_ERROR_UNABLE_TO_ADD_HANDLE, + PVRSRV_ERROR_HANDLE_NOT_SHAREABLE, + PVRSRV_ERROR_HANDLE_NOT_FOUND, + PVRSRV_ERROR_INVALID_SUBHANDLE, + PVRSRV_ERROR_HANDLE_BATCH_IN_USE, + PVRSRV_ERROR_HANDLE_BATCH_COMMIT_FAILURE, + + PVRSRV_ERROR_UNABLE_TO_CREATE_HASH_TABLE, + PVRSRV_ERROR_INSERT_HASH_TABLE_DATA_FAILED, + + PVRSRV_ERROR_UNSUPPORTED_BACKING_STORE, + PVRSRV_ERROR_UNABLE_TO_DESTROY_BM_HEAP, + + PVRSRV_ERROR_UNKNOWN_INIT_SERVER_STATE, + + PVRSRV_ERROR_NO_FREE_DEVICEIDS_AVALIABLE, + PVRSRV_ERROR_INVALID_DEVICEID, + PVRSRV_ERROR_DEVICEID_NOT_FOUND, + + PVRSRV_ERROR_MEMORY_TEST_FAILED, + PVRSRV_ERROR_CPUPADDR_TEST_FAILED, + PVRSRV_ERROR_COPY_TEST_FAILED, + + PVRSRV_ERROR_SEMAPHORE_NOT_INITIALISED, + + PVRSRV_ERROR_UNABLE_TO_RELEASE_CLOCK, + PVRSRV_ERROR_CLOCK_REQUEST_FAILED, + PVRSRV_ERROR_DISABLE_CLOCK_FAILURE, + PVRSRV_ERROR_UNABLE_TO_SET_CLOCK_RATE, + PVRSRV_ERROR_UNABLE_TO_ROUND_CLOCK_RATE, + PVRSRV_ERROR_UNABLE_TO_ENABLE_CLOCK, + PVRSRV_ERROR_UNABLE_TO_GET_CLOCK, + PVRSRV_ERROR_UNABLE_TO_GET_PARENT_CLOCK, + PVRSRV_ERROR_UNABLE_TO_GET_SYSTEM_CLOCK, + + PVRSRV_ERROR_UNKNOWN_SGL_ERROR, + + PVRSRV_ERROR_SYSTEM_POWER_CHANGE_FAILURE, + PVRSRV_ERROR_DEVICE_POWER_CHANGE_FAILURE, + + PVRSRV_ERROR_BAD_SYNC_STATE, + + PVRSRV_ERROR_CACHEOP_FAILED, + + PVRSRV_ERROR_FORCE_I32 = 0x7fffffff + +} PVRSRV_ERROR; + + +typedef enum _PVRSRV_DEVICE_CLASS_ +{ + PVRSRV_DEVICE_CLASS_3D = 0 , + PVRSRV_DEVICE_CLASS_DISPLAY = 1 , + PVRSRV_DEVICE_CLASS_BUFFER = 2 , + PVRSRV_DEVICE_CLASS_VIDEO = 3 , + + PVRSRV_DEVICE_CLASS_FORCE_I32 = 0x7fffffff + +} PVRSRV_DEVICE_CLASS; + + +typedef enum _PVRSRV_SYS_POWER_STATE_ +{ + PVRSRV_SYS_POWER_STATE_Unspecified = -1, + PVRSRV_SYS_POWER_STATE_D0 = 0, + PVRSRV_SYS_POWER_STATE_D1 = 1, + PVRSRV_SYS_POWER_STATE_D2 = 2, + PVRSRV_SYS_POWER_STATE_D3 = 3, + PVRSRV_SYS_POWER_STATE_D4 = 4, + + PVRSRV_SYS_POWER_STATE_FORCE_I32 = 0x7fffffff + +} PVRSRV_SYS_POWER_STATE, *PPVRSRV_SYS_POWER_STATE; + + +typedef enum _PVRSRV_DEV_POWER_STATE_ +{ + PVRSRV_DEV_POWER_STATE_DEFAULT = -1, + PVRSRV_DEV_POWER_STATE_ON = 0, + PVRSRV_DEV_POWER_STATE_IDLE = 1, + PVRSRV_DEV_POWER_STATE_OFF = 2, + + PVRSRV_DEV_POWER_STATE_FORCE_I32 = 0x7fffffff + +} PVRSRV_DEV_POWER_STATE, *PPVRSRV_DEV_POWER_STATE; + + +typedef PVRSRV_ERROR (*PFN_PRE_POWER) (IMG_HANDLE hDevHandle, + PVRSRV_DEV_POWER_STATE eNewPowerState, + PVRSRV_DEV_POWER_STATE eCurrentPowerState); +typedef PVRSRV_ERROR (*PFN_POST_POWER) (IMG_HANDLE hDevHandle, + PVRSRV_DEV_POWER_STATE eNewPowerState, + PVRSRV_DEV_POWER_STATE eCurrentPowerState); + +typedef PVRSRV_ERROR (*PFN_PRE_CLOCKSPEED_CHANGE) (IMG_HANDLE hDevHandle, + IMG_BOOL bIdleDevice, + PVRSRV_DEV_POWER_STATE eCurrentPowerState); +typedef PVRSRV_ERROR (*PFN_POST_CLOCKSPEED_CHANGE) (IMG_HANDLE hDevHandle, + IMG_BOOL bIdleDevice, + PVRSRV_DEV_POWER_STATE eCurrentPowerState); + + +typedef enum _PVRSRV_PIXEL_FORMAT_ { + + PVRSRV_PIXEL_FORMAT_UNKNOWN = 0, + PVRSRV_PIXEL_FORMAT_RGB565 = 1, + PVRSRV_PIXEL_FORMAT_RGB555 = 2, + PVRSRV_PIXEL_FORMAT_RGB888 = 3, + PVRSRV_PIXEL_FORMAT_BGR888 = 4, + PVRSRV_PIXEL_FORMAT_GREY_SCALE = 8, + PVRSRV_PIXEL_FORMAT_PAL12 = 13, + PVRSRV_PIXEL_FORMAT_PAL8 = 14, + PVRSRV_PIXEL_FORMAT_PAL4 = 15, + PVRSRV_PIXEL_FORMAT_PAL2 = 16, + PVRSRV_PIXEL_FORMAT_PAL1 = 17, + PVRSRV_PIXEL_FORMAT_ARGB1555 = 18, + PVRSRV_PIXEL_FORMAT_ARGB4444 = 19, + PVRSRV_PIXEL_FORMAT_ARGB8888 = 20, + PVRSRV_PIXEL_FORMAT_ABGR8888 = 21, + PVRSRV_PIXEL_FORMAT_YV12 = 22, + PVRSRV_PIXEL_FORMAT_I420 = 23, + PVRSRV_PIXEL_FORMAT_IMC2 = 25, + PVRSRV_PIXEL_FORMAT_XRGB8888 = 26, + PVRSRV_PIXEL_FORMAT_XBGR8888 = 27, + PVRSRV_PIXEL_FORMAT_BGRA8888 = 28, + PVRSRV_PIXEL_FORMAT_XRGB4444 = 29, + PVRSRV_PIXEL_FORMAT_ARGB8332 = 30, + PVRSRV_PIXEL_FORMAT_A2RGB10 = 31, + PVRSRV_PIXEL_FORMAT_A2BGR10 = 32, + PVRSRV_PIXEL_FORMAT_P8 = 33, + PVRSRV_PIXEL_FORMAT_L8 = 34, + PVRSRV_PIXEL_FORMAT_A8L8 = 35, + PVRSRV_PIXEL_FORMAT_A4L4 = 36, + PVRSRV_PIXEL_FORMAT_L16 = 37, + PVRSRV_PIXEL_FORMAT_L6V5U5 = 38, + PVRSRV_PIXEL_FORMAT_V8U8 = 39, + PVRSRV_PIXEL_FORMAT_V16U16 = 40, + PVRSRV_PIXEL_FORMAT_QWVU8888 = 41, + PVRSRV_PIXEL_FORMAT_XLVU8888 = 42, + PVRSRV_PIXEL_FORMAT_QWVU16 = 43, + PVRSRV_PIXEL_FORMAT_D16 = 44, + PVRSRV_PIXEL_FORMAT_D24S8 = 45, + PVRSRV_PIXEL_FORMAT_D24X8 = 46, + + + PVRSRV_PIXEL_FORMAT_ABGR16 = 47, + PVRSRV_PIXEL_FORMAT_ABGR16F = 48, + PVRSRV_PIXEL_FORMAT_ABGR32 = 49, + PVRSRV_PIXEL_FORMAT_ABGR32F = 50, + PVRSRV_PIXEL_FORMAT_B10GR11 = 51, + PVRSRV_PIXEL_FORMAT_GR88 = 52, + PVRSRV_PIXEL_FORMAT_BGR32 = 53, + PVRSRV_PIXEL_FORMAT_GR32 = 54, + PVRSRV_PIXEL_FORMAT_E5BGR9 = 55, + + + PVRSRV_PIXEL_FORMAT_RESERVED1 = 56, + PVRSRV_PIXEL_FORMAT_RESERVED2 = 57, + PVRSRV_PIXEL_FORMAT_RESERVED3 = 58, + PVRSRV_PIXEL_FORMAT_RESERVED4 = 59, + PVRSRV_PIXEL_FORMAT_RESERVED5 = 60, + + + PVRSRV_PIXEL_FORMAT_R8G8_B8G8 = 61, + PVRSRV_PIXEL_FORMAT_G8R8_G8B8 = 62, + + + PVRSRV_PIXEL_FORMAT_NV11 = 63, + PVRSRV_PIXEL_FORMAT_NV12 = 64, + + + PVRSRV_PIXEL_FORMAT_YUY2 = 65, + PVRSRV_PIXEL_FORMAT_YUV420 = 66, + PVRSRV_PIXEL_FORMAT_YUV444 = 67, + PVRSRV_PIXEL_FORMAT_VUY444 = 68, + PVRSRV_PIXEL_FORMAT_YUYV = 69, + PVRSRV_PIXEL_FORMAT_YVYU = 70, + PVRSRV_PIXEL_FORMAT_UYVY = 71, + PVRSRV_PIXEL_FORMAT_VYUY = 72, + + PVRSRV_PIXEL_FORMAT_FOURCC_ORG_UYVY = 73, + PVRSRV_PIXEL_FORMAT_FOURCC_ORG_YUYV = 74, + PVRSRV_PIXEL_FORMAT_FOURCC_ORG_YVYU = 75, + PVRSRV_PIXEL_FORMAT_FOURCC_ORG_VYUY = 76, + PVRSRV_PIXEL_FORMAT_FOURCC_ORG_AYUV = 77, + + + PVRSRV_PIXEL_FORMAT_A32B32G32R32 = 78, + PVRSRV_PIXEL_FORMAT_A32B32G32R32F = 79, + PVRSRV_PIXEL_FORMAT_A32B32G32R32_UINT = 80, + PVRSRV_PIXEL_FORMAT_A32B32G32R32_SINT = 81, + + + PVRSRV_PIXEL_FORMAT_B32G32R32 = 82, + PVRSRV_PIXEL_FORMAT_B32G32R32F = 83, + PVRSRV_PIXEL_FORMAT_B32G32R32_UINT = 84, + PVRSRV_PIXEL_FORMAT_B32G32R32_SINT = 85, + + + PVRSRV_PIXEL_FORMAT_G32R32 = 86, + PVRSRV_PIXEL_FORMAT_G32R32F = 87, + PVRSRV_PIXEL_FORMAT_G32R32_UINT = 88, + PVRSRV_PIXEL_FORMAT_G32R32_SINT = 89, + + + PVRSRV_PIXEL_FORMAT_D32F = 90, + PVRSRV_PIXEL_FORMAT_R32 = 91, + PVRSRV_PIXEL_FORMAT_R32F = 92, + PVRSRV_PIXEL_FORMAT_R32_UINT = 93, + PVRSRV_PIXEL_FORMAT_R32_SINT = 94, + + + PVRSRV_PIXEL_FORMAT_A16B16G16R16 = 95, + PVRSRV_PIXEL_FORMAT_A16B16G16R16F = 96, + PVRSRV_PIXEL_FORMAT_A16B16G16R16_SINT = 97, + PVRSRV_PIXEL_FORMAT_A16B16G16R16_SNORM = 98, + PVRSRV_PIXEL_FORMAT_A16B16G16R16_UINT = 99, + PVRSRV_PIXEL_FORMAT_A16B16G16R16_UNORM = 100, + + + PVRSRV_PIXEL_FORMAT_G16R16 = 101, + PVRSRV_PIXEL_FORMAT_G16R16F = 102, + PVRSRV_PIXEL_FORMAT_G16R16_UINT = 103, + PVRSRV_PIXEL_FORMAT_G16R16_UNORM = 104, + PVRSRV_PIXEL_FORMAT_G16R16_SINT = 105, + PVRSRV_PIXEL_FORMAT_G16R16_SNORM = 106, + + + PVRSRV_PIXEL_FORMAT_R16 = 107, + PVRSRV_PIXEL_FORMAT_R16F = 108, + PVRSRV_PIXEL_FORMAT_R16_UINT = 109, + PVRSRV_PIXEL_FORMAT_R16_UNORM = 110, + PVRSRV_PIXEL_FORMAT_R16_SINT = 111, + PVRSRV_PIXEL_FORMAT_R16_SNORM = 112, + + + PVRSRV_PIXEL_FORMAT_X8R8G8B8 = 113, + PVRSRV_PIXEL_FORMAT_X8R8G8B8_UNORM = 114, + PVRSRV_PIXEL_FORMAT_X8R8G8B8_UNORM_SRGB = 115, + + PVRSRV_PIXEL_FORMAT_A8R8G8B8 = 116, + PVRSRV_PIXEL_FORMAT_A8R8G8B8_UNORM = 117, + PVRSRV_PIXEL_FORMAT_A8R8G8B8_UNORM_SRGB = 118, + + PVRSRV_PIXEL_FORMAT_A8B8G8R8 = 119, + PVRSRV_PIXEL_FORMAT_A8B8G8R8_UINT = 120, + PVRSRV_PIXEL_FORMAT_A8B8G8R8_UNORM = 121, + PVRSRV_PIXEL_FORMAT_A8B8G8R8_UNORM_SRGB = 122, + PVRSRV_PIXEL_FORMAT_A8B8G8R8_SINT = 123, + PVRSRV_PIXEL_FORMAT_A8B8G8R8_SNORM = 124, + + + PVRSRV_PIXEL_FORMAT_G8R8 = 125, + PVRSRV_PIXEL_FORMAT_G8R8_UINT = 126, + PVRSRV_PIXEL_FORMAT_G8R8_UNORM = 127, + PVRSRV_PIXEL_FORMAT_G8R8_SINT = 128, + PVRSRV_PIXEL_FORMAT_G8R8_SNORM = 129, + + + PVRSRV_PIXEL_FORMAT_A8 = 130, + PVRSRV_PIXEL_FORMAT_R8 = 131, + PVRSRV_PIXEL_FORMAT_R8_UINT = 132, + PVRSRV_PIXEL_FORMAT_R8_UNORM = 133, + PVRSRV_PIXEL_FORMAT_R8_SINT = 134, + PVRSRV_PIXEL_FORMAT_R8_SNORM = 135, + + + PVRSRV_PIXEL_FORMAT_A2B10G10R10 = 136, + PVRSRV_PIXEL_FORMAT_A2B10G10R10_UNORM = 137, + PVRSRV_PIXEL_FORMAT_A2B10G10R10_UINT = 138, + + + PVRSRV_PIXEL_FORMAT_B10G11R11 = 139, + PVRSRV_PIXEL_FORMAT_B10G11R11F = 140, + + + PVRSRV_PIXEL_FORMAT_X24G8R32 = 141, + PVRSRV_PIXEL_FORMAT_G8R24 = 142, + PVRSRV_PIXEL_FORMAT_X8R24 = 143, + PVRSRV_PIXEL_FORMAT_E5B9G9R9 = 144, + PVRSRV_PIXEL_FORMAT_R1 = 145, + + PVRSRV_PIXEL_FORMAT_RESERVED6 = 146, + PVRSRV_PIXEL_FORMAT_RESERVED7 = 147, + PVRSRV_PIXEL_FORMAT_RESERVED8 = 148, + PVRSRV_PIXEL_FORMAT_RESERVED9 = 149, + PVRSRV_PIXEL_FORMAT_RESERVED10 = 150, + PVRSRV_PIXEL_FORMAT_RESERVED11 = 151, + PVRSRV_PIXEL_FORMAT_RESERVED12 = 152, + PVRSRV_PIXEL_FORMAT_RESERVED13 = 153, + PVRSRV_PIXEL_FORMAT_RESERVED14 = 154, + PVRSRV_PIXEL_FORMAT_RESERVED15 = 155, + PVRSRV_PIXEL_FORMAT_RESERVED16 = 156, + PVRSRV_PIXEL_FORMAT_RESERVED17 = 157, + PVRSRV_PIXEL_FORMAT_RESERVED18 = 158, + PVRSRV_PIXEL_FORMAT_RESERVED19 = 159, + PVRSRV_PIXEL_FORMAT_RESERVED20 = 160, + + + PVRSRV_PIXEL_FORMAT_UBYTE4 = 161, + PVRSRV_PIXEL_FORMAT_SHORT4 = 162, + PVRSRV_PIXEL_FORMAT_SHORT4N = 163, + PVRSRV_PIXEL_FORMAT_USHORT4N = 164, + PVRSRV_PIXEL_FORMAT_SHORT2N = 165, + PVRSRV_PIXEL_FORMAT_SHORT2 = 166, + PVRSRV_PIXEL_FORMAT_USHORT2N = 167, + PVRSRV_PIXEL_FORMAT_UDEC3 = 168, + PVRSRV_PIXEL_FORMAT_DEC3N = 169, + PVRSRV_PIXEL_FORMAT_F16_2 = 170, + PVRSRV_PIXEL_FORMAT_F16_4 = 171, + + + PVRSRV_PIXEL_FORMAT_L_F16 = 172, + PVRSRV_PIXEL_FORMAT_L_F16_REP = 173, + PVRSRV_PIXEL_FORMAT_L_F16_A_F16 = 174, + PVRSRV_PIXEL_FORMAT_A_F16 = 175, + PVRSRV_PIXEL_FORMAT_B16G16R16F = 176, + + PVRSRV_PIXEL_FORMAT_L_F32 = 177, + PVRSRV_PIXEL_FORMAT_A_F32 = 178, + PVRSRV_PIXEL_FORMAT_L_F32_A_F32 = 179, + + + PVRSRV_PIXEL_FORMAT_PVRTC2 = 180, + PVRSRV_PIXEL_FORMAT_PVRTC4 = 181, + PVRSRV_PIXEL_FORMAT_PVRTCII2 = 182, + PVRSRV_PIXEL_FORMAT_PVRTCII4 = 183, + PVRSRV_PIXEL_FORMAT_PVRTCIII = 184, + PVRSRV_PIXEL_FORMAT_PVRO8 = 185, + PVRSRV_PIXEL_FORMAT_PVRO88 = 186, + PVRSRV_PIXEL_FORMAT_PT1 = 187, + PVRSRV_PIXEL_FORMAT_PT2 = 188, + PVRSRV_PIXEL_FORMAT_PT4 = 189, + PVRSRV_PIXEL_FORMAT_PT8 = 190, + PVRSRV_PIXEL_FORMAT_PTW = 191, + PVRSRV_PIXEL_FORMAT_PTB = 192, + PVRSRV_PIXEL_FORMAT_MONO8 = 193, + PVRSRV_PIXEL_FORMAT_MONO16 = 194, + + + PVRSRV_PIXEL_FORMAT_C0_YUYV = 195, + PVRSRV_PIXEL_FORMAT_C0_UYVY = 196, + PVRSRV_PIXEL_FORMAT_C0_YVYU = 197, + PVRSRV_PIXEL_FORMAT_C0_VYUY = 198, + PVRSRV_PIXEL_FORMAT_C1_YUYV = 199, + PVRSRV_PIXEL_FORMAT_C1_UYVY = 200, + PVRSRV_PIXEL_FORMAT_C1_YVYU = 201, + PVRSRV_PIXEL_FORMAT_C1_VYUY = 202, + + + PVRSRV_PIXEL_FORMAT_C0_YUV420_2P_UV = 203, + PVRSRV_PIXEL_FORMAT_C0_YUV420_2P_VU = 204, + PVRSRV_PIXEL_FORMAT_C0_YUV420_3P = 205, + PVRSRV_PIXEL_FORMAT_C1_YUV420_2P_UV = 206, + PVRSRV_PIXEL_FORMAT_C1_YUV420_2P_VU = 207, + PVRSRV_PIXEL_FORMAT_C1_YUV420_3P = 208, + + PVRSRV_PIXEL_FORMAT_A2B10G10R10F = 209, + PVRSRV_PIXEL_FORMAT_B8G8R8_SINT = 210, + PVRSRV_PIXEL_FORMAT_PVRF32SIGNMASK = 211, + + PVRSRV_PIXEL_FORMAT_ABGR4444 = 212, + PVRSRV_PIXEL_FORMAT_ABGR1555 = 213, + PVRSRV_PIXEL_FORMAT_BGR565 = 214, + + PVRSRV_PIXEL_FORMAT_FORCE_I32 = 0x7fffffff + +} PVRSRV_PIXEL_FORMAT; + +typedef enum _PVRSRV_ALPHA_FORMAT_ { + PVRSRV_ALPHA_FORMAT_UNKNOWN = 0x00000000, + PVRSRV_ALPHA_FORMAT_PRE = 0x00000001, + PVRSRV_ALPHA_FORMAT_NONPRE = 0x00000002, + PVRSRV_ALPHA_FORMAT_MASK = 0x0000000F, +} PVRSRV_ALPHA_FORMAT; + +typedef enum _PVRSRV_COLOURSPACE_FORMAT_ { + PVRSRV_COLOURSPACE_FORMAT_UNKNOWN = 0x00000000, + PVRSRV_COLOURSPACE_FORMAT_LINEAR = 0x00010000, + PVRSRV_COLOURSPACE_FORMAT_NONLINEAR = 0x00020000, + PVRSRV_COLOURSPACE_FORMAT_MASK = 0x000F0000, +} PVRSRV_COLOURSPACE_FORMAT; + + +typedef enum _PVRSRV_ROTATION_ { + PVRSRV_ROTATE_0 = 0, + PVRSRV_ROTATE_90 = 1, + PVRSRV_ROTATE_180 = 2, + PVRSRV_ROTATE_270 = 3, + PVRSRV_FLIP_Y + +} PVRSRV_ROTATION; + +#define PVRSRV_CREATE_SWAPCHAIN_SHARED (1<<0) +#define PVRSRV_CREATE_SWAPCHAIN_QUERY (1<<1) +#define PVRSRV_CREATE_SWAPCHAIN_OEMOVERLAY (1<<2) + +typedef struct _PVRSRV_SYNC_DATA_ +{ + + IMG_UINT32 ui32WriteOpsPending; + volatile IMG_UINT32 ui32WriteOpsComplete; + + + IMG_UINT32 ui32ReadOpsPending; + volatile IMG_UINT32 ui32ReadOpsComplete; + + + IMG_UINT32 ui32LastOpDumpVal; + IMG_UINT32 ui32LastReadOpDumpVal; + +} PVRSRV_SYNC_DATA; + +typedef struct _PVRSRV_CLIENT_SYNC_INFO_ +{ + + PVRSRV_SYNC_DATA *psSyncData; + + + + + + IMG_DEV_VIRTADDR sWriteOpsCompleteDevVAddr; + + + IMG_DEV_VIRTADDR sReadOpsCompleteDevVAddr; + + + IMG_HANDLE hMappingInfo; + + + IMG_HANDLE hKernelSyncInfo; + +} PVRSRV_CLIENT_SYNC_INFO, *PPVRSRV_CLIENT_SYNC_INFO; + +typedef struct PVRSRV_RESOURCE_TAG +{ + volatile IMG_UINT32 ui32Lock; + IMG_UINT32 ui32ID; +}PVRSRV_RESOURCE; +typedef PVRSRV_RESOURCE PVRSRV_RES_HANDLE; + + +typedef IMG_VOID (*PFN_CMD_COMPLETE) (IMG_HANDLE); +typedef IMG_VOID (**PPFN_CMD_COMPLETE) (IMG_HANDLE); + +typedef IMG_BOOL (*PFN_CMD_PROC) (IMG_HANDLE, IMG_UINT32, IMG_VOID*); +typedef IMG_BOOL (**PPFN_CMD_PROC) (IMG_HANDLE, IMG_UINT32, IMG_VOID*); + + +typedef struct _IMG_RECT_ +{ + IMG_INT32 x0; + IMG_INT32 y0; + IMG_INT32 x1; + IMG_INT32 y1; +}IMG_RECT; + +typedef struct _IMG_RECT_16_ +{ + IMG_INT16 x0; + IMG_INT16 y0; + IMG_INT16 x1; + IMG_INT16 y1; +}IMG_RECT_16; + + +typedef PVRSRV_ERROR (*PFN_GET_BUFFER_ADDR)(IMG_HANDLE, + IMG_HANDLE, + IMG_SYS_PHYADDR**, + IMG_SIZE_T*, + IMG_VOID**, + IMG_HANDLE*, + IMG_BOOL*, + IMG_UINT32*); + + +typedef struct DISPLAY_DIMS_TAG +{ + IMG_UINT32 ui32ByteStride; + IMG_UINT32 ui32Width; + IMG_UINT32 ui32Height; +} DISPLAY_DIMS; + + +typedef struct DISPLAY_FORMAT_TAG +{ + + PVRSRV_PIXEL_FORMAT pixelformat; +} DISPLAY_FORMAT; + +typedef struct DISPLAY_SURF_ATTRIBUTES_TAG +{ + + PVRSRV_PIXEL_FORMAT pixelformat; + + DISPLAY_DIMS sDims; +} DISPLAY_SURF_ATTRIBUTES; + + +typedef struct DISPLAY_MODE_INFO_TAG +{ + + PVRSRV_PIXEL_FORMAT pixelformat; + + DISPLAY_DIMS sDims; + + IMG_UINT32 ui32RefreshHZ; + + IMG_UINT32 ui32OEMFlags; +} DISPLAY_MODE_INFO; + + + +#define MAX_DISPLAY_NAME_SIZE (50) + +typedef struct DISPLAY_INFO_TAG +{ + + IMG_UINT32 ui32MaxSwapChains; + + IMG_UINT32 ui32MaxSwapChainBuffers; + + IMG_UINT32 ui32MinSwapInterval; + + IMG_UINT32 ui32MaxSwapInterval; + + IMG_UINT32 ui32PhysicalWidthmm; + IMG_UINT32 ui32PhysicalHeightmm; + + IMG_CHAR szDisplayName[MAX_DISPLAY_NAME_SIZE]; +#if defined(SUPPORT_HW_CURSOR) + + IMG_UINT16 ui32CursorWidth; + IMG_UINT16 ui32CursorHeight; +#endif +} DISPLAY_INFO; + +typedef struct ACCESS_INFO_TAG +{ + IMG_UINT32 ui32Size; + IMG_UINT32 ui32FBPhysBaseAddress; + IMG_UINT32 ui32FBMemAvailable; + IMG_UINT32 ui32SysPhysBaseAddress; + IMG_UINT32 ui32SysSize; + IMG_UINT32 ui32DevIRQ; +}ACCESS_INFO; + + +typedef struct PVRSRV_CURSOR_SHAPE_TAG +{ + IMG_UINT16 ui16Width; + IMG_UINT16 ui16Height; + IMG_INT16 i16XHot; + IMG_INT16 i16YHot; + + + IMG_VOID* pvMask; + IMG_INT16 i16MaskByteStride; + + + IMG_VOID* pvColour; + IMG_INT16 i16ColourByteStride; + PVRSRV_PIXEL_FORMAT eColourPixelFormat; +} PVRSRV_CURSOR_SHAPE; + +#define PVRSRV_SET_CURSOR_VISIBILITY (1<<0) +#define PVRSRV_SET_CURSOR_POSITION (1<<1) +#define PVRSRV_SET_CURSOR_SHAPE (1<<2) +#define PVRSRV_SET_CURSOR_ROTATION (1<<3) + +typedef struct PVRSRV_CURSOR_INFO_TAG +{ + + IMG_UINT32 ui32Flags; + + + IMG_BOOL bVisible; + + + IMG_INT16 i16XPos; + IMG_INT16 i16YPos; + + + PVRSRV_CURSOR_SHAPE sCursorShape; + + + IMG_UINT32 ui32Rotation; + +} PVRSRV_CURSOR_INFO; + + +typedef struct _PVRSRV_REGISTRY_INFO_ +{ + IMG_UINT32 ui32DevCookie; + IMG_PCHAR pszKey; + IMG_PCHAR pszValue; + IMG_PCHAR pszBuf; + IMG_UINT32 ui32BufSize; +} PVRSRV_REGISTRY_INFO, *PPVRSRV_REGISTRY_INFO; + + +PVRSRV_ERROR IMG_CALLCONV PVRSRVReadRegistryString (PPVRSRV_REGISTRY_INFO psRegInfo); +PVRSRV_ERROR IMG_CALLCONV PVRSRVWriteRegistryString (PPVRSRV_REGISTRY_INFO psRegInfo); + + +#define PVRSRV_BC_FLAGS_YUVCSC_CONFORMANT_RANGE (0 << 0) +#define PVRSRV_BC_FLAGS_YUVCSC_FULL_RANGE (1 << 0) + +#define PVRSRV_BC_FLAGS_YUVCSC_BT601 (0 << 1) +#define PVRSRV_BC_FLAGS_YUVCSC_BT709 (1 << 1) + +#define MAX_BUFFER_DEVICE_NAME_SIZE (50) + +typedef struct BUFFER_INFO_TAG +{ + IMG_UINT32 ui32BufferCount; + IMG_UINT32 ui32BufferDeviceID; + PVRSRV_PIXEL_FORMAT pixelformat; + IMG_UINT32 ui32ByteStride; + IMG_UINT32 ui32Width; + IMG_UINT32 ui32Height; + IMG_UINT32 ui32Flags; + IMG_CHAR szDeviceName[MAX_BUFFER_DEVICE_NAME_SIZE]; +} BUFFER_INFO; + +typedef enum _OVERLAY_DEINTERLACE_MODE_ +{ + WEAVE=0x0, + BOB_ODD, + BOB_EVEN, + BOB_EVEN_NONINTERLEAVED +} OVERLAY_DEINTERLACE_MODE; + +#endif diff --git a/sys/pvr2d/pvr_includes/wsegl.h b/sys/pvr2d/pvr_includes/wsegl.h new file mode 100755 index 0000000000..e5191ec4dc --- /dev/null +++ b/sys/pvr2d/pvr_includes/wsegl.h @@ -0,0 +1,285 @@ +/********************************************************************** +* +* Copyright(c) Imagination Technologies Ltd. +* +* The contents of this file are subject to the MIT license as set out below. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT +* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +* This License is also included in this distribution in the file called +* "COPYING". +* +******************************************************************************/ + + + +#if !defined(__WSEGL_H__) +#define __WSEGL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* +// WSEGL Platform-specific definitions +*/ +#if defined(__linux__) +#define WSEGL_EXPORT __attribute__((visibility("default"))) +#define WSEGL_IMPORT +#else +#define WSEGL_EXPORT +#define WSEGL_IMPORT +#endif + +/* +// WSEGL API Version Number +*/ + +#define WSEGL_VERSION 2 +#define WSEGL_DEFAULT_DISPLAY 0 +#define WSEGL_DEFAULT_NATIVE_ENGINE 0 + +#define WSEGL_FALSE 0 +#define WSEGL_TRUE 1 +#define WSEGL_NULL 0 + +#define WSEGL_UNREFERENCED_PARAMETER(param) (param) = (param) + +/* +// WSEGL handles +*/ +typedef void *WSEGLDisplayHandle; +typedef void *WSEGLDrawableHandle; + +/* +// Display capability type +*/ +typedef enum WSEGLCapsType_TAG +{ + WSEGL_NO_CAPS = 0, + WSEGL_CAP_MIN_SWAP_INTERVAL = 1, /* System default value = 1 */ + WSEGL_CAP_MAX_SWAP_INTERVAL = 2, /* System default value = 1 */ + WSEGL_CAP_WINDOWS_USE_HW_SYNC = 3, /* System default value = 0 (FALSE) */ + WSEGL_CAP_PIXMAPS_USE_HW_SYNC = 4, /* System default value = 0 (FALSE) */ + +} WSEGLCapsType; + +/* +// Display capability +*/ +typedef struct WSEGLCaps_TAG +{ + WSEGLCapsType eCapsType; + unsigned long ui32CapsValue; + +} WSEGLCaps; + +/* +// Drawable type +*/ +#define WSEGL_NO_DRAWABLE 0x0 +#define WSEGL_DRAWABLE_WINDOW 0x1 +#define WSEGL_DRAWABLE_PIXMAP 0x2 + + +/* +// Pixel format of display/drawable +*/ +typedef enum WSEGLPixelFormat_TAG +{ + /* These must not be re-ordered */ + WSEGL_PIXELFORMAT_RGB565 = 0, + WSEGL_PIXELFORMAT_ARGB4444 = 1, + WSEGL_PIXELFORMAT_ARGB8888 = 2, + WSEGL_PIXELFORMAT_ARGB1555 = 3, + WSEGL_PIXELFORMAT_ABGR8888 = 4, + WSEGL_PIXELFORMAT_XBGR8888 = 5, + + /* These are compatibility names only; new WSEGL + * modules should not use them. + */ + WSEGL_PIXELFORMAT_565 = WSEGL_PIXELFORMAT_RGB565, + WSEGL_PIXELFORMAT_4444 = WSEGL_PIXELFORMAT_ARGB4444, + WSEGL_PIXELFORMAT_8888 = WSEGL_PIXELFORMAT_ARGB8888, + WSEGL_PIXELFORMAT_1555 = WSEGL_PIXELFORMAT_ARGB1555, + +} WSEGLPixelFormat; + +/* +// Transparent of display/drawable +*/ +typedef enum WSEGLTransparentType_TAG +{ + WSEGL_OPAQUE = 0, + WSEGL_COLOR_KEY = 1, + +} WSEGLTransparentType; + +/* +// Display/drawable configuration +*/ +typedef struct WSEGLConfig_TAG +{ + /* + // Type of drawables this configuration applies to - + // OR'd values of drawable types. + */ + unsigned long ui32DrawableType; + + /* Pixel format */ + WSEGLPixelFormat ePixelFormat; + + /* Native Renderable - set to WSEGL_TRUE if native renderable */ + unsigned long ulNativeRenderable; + + /* FrameBuffer Level Parameter */ + unsigned long ulFrameBufferLevel; + + /* Native Visual ID */ + unsigned long ulNativeVisualID; + + /* Native Visual */ + void *hNativeVisual; + + /* Transparent Type */ + WSEGLTransparentType eTransparentType; + + /* Transparent Color - only used if transparent type is COLOR_KEY */ + unsigned long ulTransparentColor; /* packed as 0x00RRGGBB */ + + +} WSEGLConfig; + +/* +// WSEGL errors +*/ +typedef enum WSEGLError_TAG +{ + WSEGL_SUCCESS = 0, + WSEGL_CANNOT_INITIALISE = 1, + WSEGL_BAD_NATIVE_DISPLAY = 2, + WSEGL_BAD_NATIVE_WINDOW = 3, + WSEGL_BAD_NATIVE_PIXMAP = 4, + WSEGL_BAD_NATIVE_ENGINE = 5, + WSEGL_BAD_DRAWABLE = 6, + WSEGL_BAD_MATCH = 7, + WSEGL_OUT_OF_MEMORY = 8, + + /* These are compatibility names only; new WSEGL + * modules should not use them. + */ + WSEGL_BAD_CONFIG = WSEGL_BAD_MATCH, + +} WSEGLError; + +/* +// Drawable orientation (in degrees anti-clockwise) +*/ +typedef enum WSEGLRotationAngle_TAG +{ + WSEGL_ROTATE_0 = 0, + WSEGL_ROTATE_90 = 1, + WSEGL_ROTATE_180 = 2, + WSEGL_ROTATE_270 = 3 + +} WSEGLRotationAngle; + +/* +// Drawable information required by OpenGL-ES driver +*/ +typedef struct WSEGLDrawableParams_TAG +{ + /* Width in pixels of the drawable */ + unsigned long ui32Width; + + /* Height in pixels of the drawable */ + unsigned long ui32Height; + + /* Stride in pixels of the drawable */ + unsigned long ui32Stride; + + /* Pixel format of the drawable */ + WSEGLPixelFormat ePixelFormat; + + /* User space cpu virtual address of the drawable */ + void *pvLinearAddress; + + /* HW address of the drawable */ + unsigned long ui32HWAddress; + + /* Private data for the drawable */ + void *hPrivateData; + + +} WSEGLDrawableParams; + + +/* +// Table of function pointers that is returned by WSEGL_GetFunctionTablePointer() +// +// The first entry in the table is the version number of the wsegl.h header file that +// the module has been written against, and should therefore be set to WSEGL_VERSION +*/ +typedef struct WSEGL_FunctionTable_TAG +{ + unsigned long ui32WSEGLVersion; + + WSEGLError (*pfnWSEGL_IsDisplayValid)(NativeDisplayType); + + WSEGLError (*pfnWSEGL_InitialiseDisplay)(NativeDisplayType, WSEGLDisplayHandle *, const WSEGLCaps **, WSEGLConfig **); + + WSEGLError (*pfnWSEGL_CloseDisplay)(WSEGLDisplayHandle); + + WSEGLError (*pfnWSEGL_CreateWindowDrawable)(WSEGLDisplayHandle, WSEGLConfig *, WSEGLDrawableHandle *, NativeWindowType, WSEGLRotationAngle *); + + WSEGLError (*pfnWSEGL_CreatePixmapDrawable)(WSEGLDisplayHandle, WSEGLConfig *, WSEGLDrawableHandle *, NativePixmapType, WSEGLRotationAngle *); + + WSEGLError (*pfnWSEGL_DeleteDrawable)(WSEGLDrawableHandle); + + WSEGLError (*pfnWSEGL_SwapDrawable)(WSEGLDrawableHandle, unsigned long); + + WSEGLError (*pfnWSEGL_SwapControlInterval)(WSEGLDrawableHandle, unsigned long); + + WSEGLError (*pfnWSEGL_WaitNative)(WSEGLDrawableHandle, unsigned long); + + WSEGLError (*pfnWSEGL_CopyFromDrawable)(WSEGLDrawableHandle, NativePixmapType); + + WSEGLError (*pfnWSEGL_CopyFromPBuffer)(void *, unsigned long, unsigned long, unsigned long, WSEGLPixelFormat, NativePixmapType); + + WSEGLError (*pfnWSEGL_GetDrawableParameters)(WSEGLDrawableHandle, WSEGLDrawableParams *, WSEGLDrawableParams *); + + WSEGLError (*pfnWSEGL_ConnectDrawable)(WSEGLDrawableHandle); + + WSEGLError (*pfnWSEGL_DisconnectDrawable)(WSEGLDrawableHandle); + + +} WSEGL_FunctionTable; + + +WSEGL_IMPORT const WSEGL_FunctionTable *WSEGL_GetFunctionTablePointer(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __WSEGL_H__ */ + +/****************************************************************************** + End of file (wsegl.h) +******************************************************************************/