/* GStreamer SAMI subtitle parser
- * Copyright (c) 2006 Young-Ho Cha <ganadist at chollian net>
+ * Copyright (c) 2006, 2013 Young-Ho Cha <ganadist at gmail com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
*
* 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.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
+#define _GNU_SOURCE
#include "samiparse.h"
-#include <libxml/HTMLparser.h>
+#include <glib.h>
#include <string.h>
+#include <stdlib.h>
#define ITALIC_TAG 'i'
#define SPAN_TAG 's'
#define RT_TAG 't'
#define CLEAR_TAG '0'
+typedef struct _HtmlParser HtmlParser;
+typedef struct _HtmlContext HtmlContext;
typedef struct _GstSamiContext GstSamiContext;
-
+#ifdef SUBPARSE_MODIFICATION
+typedef struct _LanguageStruct GstLangStruct;
+struct _LanguageStruct
+{
+ gchar *language_code;
+ gchar *language_key;
+};
+#define MAX_LANGUAGE 10
+#endif
struct _GstSamiContext
{
GString *buf; /* buffer to collect content */
* that tags can be closed properly on
* 'sync' tags. See _context_push_state()
* and _context_pop_state(). */
- htmlParserCtxtPtr htmlctxt; /* html parser context */
+ HtmlContext *htmlctxt; /* html parser context */
gboolean has_result; /* set when ready to push out result */
gboolean in_sync; /* flag to avoid appending anything except the
* content of the sync elements to buf */
guint64 time1; /* previous start attribute in sync tag */
guint64 time2; /* current start attribute in sync tag */
+#ifdef SUBPARSE_MODIFICATION
+ guint64 time3; /* To store the last current time when language is changed */
+ GList *lang_list; /* Language list for an external subtitle file */
+ gchar *current_language; /* Current language parsed */
+ gchar *desired_language; /* Language set by user */
+ gboolean language_changed; /* language changed signal */
+ gboolean end_body; /* </BODY> reached */
+#endif
+};
+
+struct _HtmlParser
+{
+ void (*start_element) (HtmlContext * ctx,
+ const gchar * name, const gchar ** attr, gpointer user_data);
+ void (*end_element) (HtmlContext * ctx,
+ const gchar * name, gpointer user_data);
+ void (*text) (HtmlContext * ctx,
+ const gchar * text, gsize text_len, gpointer user_data);
+};
+
+struct _HtmlContext
+{
+ const HtmlParser *parser;
+ gpointer user_data;
+ GString *buf;
+};
+
+static HtmlContext *
+html_context_new (HtmlParser * parser, gpointer user_data)
+{
+ HtmlContext *ctxt = (HtmlContext *) g_new0 (HtmlContext, 1);
+ ctxt->parser = parser;
+ ctxt->user_data = user_data;
+ ctxt->buf = g_string_new (NULL);
+ return ctxt;
+}
+
+static void
+html_context_free (HtmlContext * ctxt)
+{
+ g_string_free (ctxt->buf, TRUE);
+ g_free (ctxt);
+}
+
+struct EntityMap
+{
+ const gunichar unescaped;
+ const gchar *escaped;
+};
+
+struct EntityMap XmlEntities[] = {
+ {34, "quot;"},
+ {38, "amp;"},
+ {39, "apos;"},
+ {60, "lt;"},
+ {62, "gt;"},
+ {0, NULL},
};
+struct EntityMap HtmlEntities[] = {
+/* nbsp will handle manually
+{ 160, "nbsp;" }, */
+ {161, "iexcl;"},
+ {162, "cent;"},
+ {163, "pound;"},
+ {164, "curren;"},
+ {165, "yen;"},
+ {166, "brvbar;"},
+ {167, "sect;"},
+ {168, "uml;"},
+ {169, "copy;"},
+ {170, "ordf;"},
+ {171, "laquo;"},
+ {172, "not;"},
+ {173, "shy;"},
+ {174, "reg;"},
+ {175, "macr;"},
+ {176, "deg;"},
+ {177, "plusmn;"},
+ {178, "sup2;"},
+ {179, "sup3;"},
+ {180, "acute;"},
+ {181, "micro;"},
+ {182, "para;"},
+ {183, "middot;"},
+ {184, "cedil;"},
+ {185, "sup1;"},
+ {186, "ordm;"},
+ {187, "raquo;"},
+ {188, "frac14;"},
+ {189, "frac12;"},
+ {190, "frac34;"},
+ {191, "iquest;"},
+ {192, "Agrave;"},
+ {193, "Aacute;"},
+ {194, "Acirc;"},
+ {195, "Atilde;"},
+ {196, "Auml;"},
+ {197, "Aring;"},
+ {198, "AElig;"},
+ {199, "Ccedil;"},
+ {200, "Egrave;"},
+ {201, "Eacute;"},
+ {202, "Ecirc;"},
+ {203, "Euml;"},
+ {204, "Igrave;"},
+ {205, "Iacute;"},
+ {206, "Icirc;"},
+ {207, "Iuml;"},
+ {208, "ETH;"},
+ {209, "Ntilde;"},
+ {210, "Ograve;"},
+ {211, "Oacute;"},
+ {212, "Ocirc;"},
+ {213, "Otilde;"},
+ {214, "Ouml;"},
+ {215, "times;"},
+ {216, "Oslash;"},
+ {217, "Ugrave;"},
+ {218, "Uacute;"},
+ {219, "Ucirc;"},
+ {220, "Uuml;"},
+ {221, "Yacute;"},
+ {222, "THORN;"},
+ {223, "szlig;"},
+ {224, "agrave;"},
+ {225, "aacute;"},
+ {226, "acirc;"},
+ {227, "atilde;"},
+ {228, "auml;"},
+ {229, "aring;"},
+ {230, "aelig;"},
+ {231, "ccedil;"},
+ {232, "egrave;"},
+ {233, "eacute;"},
+ {234, "ecirc;"},
+ {235, "euml;"},
+ {236, "igrave;"},
+ {237, "iacute;"},
+ {238, "icirc;"},
+ {239, "iuml;"},
+ {240, "eth;"},
+ {241, "ntilde;"},
+ {242, "ograve;"},
+ {243, "oacute;"},
+ {244, "ocirc;"},
+ {245, "otilde;"},
+ {246, "ouml;"},
+ {247, "divide;"},
+ {248, "oslash;"},
+ {249, "ugrave;"},
+ {250, "uacute;"},
+ {251, "ucirc;"},
+ {252, "uuml;"},
+ {253, "yacute;"},
+ {254, "thorn;"},
+ {255, "yuml;"},
+ {338, "OElig;"},
+ {339, "oelig;"},
+ {352, "Scaron;"},
+ {353, "scaron;"},
+ {376, "Yuml;"},
+ {402, "fnof;"},
+ {710, "circ;"},
+ {732, "tilde;"},
+ {913, "Alpha;"},
+ {914, "Beta;"},
+ {915, "Gamma;"},
+ {916, "Delta;"},
+ {917, "Epsilon;"},
+ {918, "Zeta;"},
+ {919, "Eta;"},
+ {920, "Theta;"},
+ {921, "Iota;"},
+ {922, "Kappa;"},
+ {923, "Lambda;"},
+ {924, "Mu;"},
+ {925, "Nu;"},
+ {926, "Xi;"},
+ {927, "Omicron;"},
+ {928, "Pi;"},
+ {929, "Rho;"},
+ {931, "Sigma;"},
+ {932, "Tau;"},
+ {933, "Upsilon;"},
+ {934, "Phi;"},
+ {935, "Chi;"},
+ {936, "Psi;"},
+ {937, "Omega;"},
+ {945, "alpha;"},
+ {946, "beta;"},
+ {947, "gamma;"},
+ {948, "delta;"},
+ {949, "epsilon;"},
+ {950, "zeta;"},
+ {951, "eta;"},
+ {952, "theta;"},
+ {953, "iota;"},
+ {954, "kappa;"},
+ {955, "lambda;"},
+ {956, "mu;"},
+ {957, "nu;"},
+ {958, "xi;"},
+ {959, "omicron;"},
+ {960, "pi;"},
+ {961, "rho;"},
+ {962, "sigmaf;"},
+ {963, "sigma;"},
+ {964, "tau;"},
+ {965, "upsilon;"},
+ {966, "phi;"},
+ {967, "chi;"},
+ {968, "psi;"},
+ {969, "omega;"},
+ {977, "thetasym;"},
+ {978, "upsih;"},
+ {982, "piv;"},
+ {8194, "ensp;"},
+ {8195, "emsp;"},
+ {8201, "thinsp;"},
+ {8204, "zwnj;"},
+ {8205, "zwj;"},
+ {8206, "lrm;"},
+ {8207, "rlm;"},
+ {8211, "ndash;"},
+ {8212, "mdash;"},
+ {8216, "lsquo;"},
+ {8217, "rsquo;"},
+ {8218, "sbquo;"},
+ {8220, "ldquo;"},
+ {8221, "rdquo;"},
+ {8222, "bdquo;"},
+ {8224, "dagger;"},
+ {8225, "Dagger;"},
+ {8226, "bull;"},
+ {8230, "hellip;"},
+ {8240, "permil;"},
+ {8242, "prime;"},
+ {8243, "Prime;"},
+ {8249, "lsaquo;"},
+ {8250, "rsaquo;"},
+ {8254, "oline;"},
+ {8260, "frasl;"},
+ {8364, "euro;"},
+ {8465, "image;"},
+ {8472, "weierp;"},
+ {8476, "real;"},
+ {8482, "trade;"},
+ {8501, "alefsym;"},
+ {8592, "larr;"},
+ {8593, "uarr;"},
+ {8594, "rarr;"},
+ {8595, "darr;"},
+ {8596, "harr;"},
+ {8629, "crarr;"},
+ {8656, "lArr;"},
+ {8657, "uArr;"},
+ {8658, "rArr;"},
+ {8659, "dArr;"},
+ {8660, "hArr;"},
+ {8704, "forall;"},
+ {8706, "part;"},
+ {8707, "exist;"},
+ {8709, "empty;"},
+ {8711, "nabla;"},
+ {8712, "isin;"},
+ {8713, "notin;"},
+ {8715, "ni;"},
+ {8719, "prod;"},
+ {8721, "sum;"},
+ {8722, "minus;"},
+ {8727, "lowast;"},
+ {8730, "radic;"},
+ {8733, "prop;"},
+ {8734, "infin;"},
+ {8736, "ang;"},
+ {8743, "and;"},
+ {8744, "or;"},
+ {8745, "cap;"},
+ {8746, "cup;"},
+ {8747, "int;"},
+ {8756, "there4;"},
+ {8764, "sim;"},
+ {8773, "cong;"},
+ {8776, "asymp;"},
+ {8800, "ne;"},
+ {8801, "equiv;"},
+ {8804, "le;"},
+ {8805, "ge;"},
+ {8834, "sub;"},
+ {8835, "sup;"},
+ {8836, "nsub;"},
+ {8838, "sube;"},
+ {8839, "supe;"},
+ {8853, "oplus;"},
+ {8855, "otimes;"},
+ {8869, "perp;"},
+ {8901, "sdot;"},
+ {8968, "lceil;"},
+ {8969, "rceil;"},
+ {8970, "lfloor;"},
+ {8971, "rfloor;"},
+ {9001, "lang;"},
+ {9002, "rang;"},
+ {9674, "loz;"},
+ {9824, "spades;"},
+ {9827, "clubs;"},
+ {9829, "hearts;"},
+ {9830, "diams;"},
+ {0, NULL},
+};
+
+static gchar *
+unescape_string (const gchar * text)
+{
+ gint i;
+ GString *unescaped = g_string_new (NULL);
+
+ while (*text) {
+ if (*text == '&') {
+ text++;
+
+ /* unescape   and */
+ if (!g_ascii_strncasecmp (text, "nbsp", 4)) {
+ unescaped = g_string_append_unichar (unescaped, 160);
+ text += 4;
+ if (*text == ';') {
+ text++;
+ }
+ goto next;
+ }
+
+ /* pass xml entities. these will be processed as pango markup */
+ for (i = 0; XmlEntities[i].escaped; i++) {
+ gssize len = strlen (XmlEntities[i].escaped);
+ if (!g_ascii_strncasecmp (text, XmlEntities[i].escaped, len)) {
+ unescaped = g_string_append_c (unescaped, '&');
+ unescaped =
+ g_string_append_len (unescaped, XmlEntities[i].escaped, len);
+ text += len;
+ goto next;
+ }
+ }
+
+ /* convert html entities */
+ for (i = 0; HtmlEntities[i].escaped; i++) {
+ gssize len = strlen (HtmlEntities[i].escaped);
+ if (!strncmp (text, HtmlEntities[i].escaped, len)) {
+ unescaped =
+ g_string_append_unichar (unescaped, HtmlEntities[i].unescaped);
+ text += len;
+ goto next;
+ }
+ }
+
+ if (*text == '#') {
+ gboolean is_hex = FALSE;
+ gunichar l;
+ gchar *end = NULL;
+
+ text++;
+ if (*text == 'x') {
+ is_hex = TRUE;
+ text++;
+ }
+ errno = 0;
+ if (is_hex) {
+ l = strtoul (text, &end, 16);
+ } else {
+ l = strtoul (text, &end, 10);
+ }
+
+ if (text == end || errno != 0) {
+ /* error occured. pass it */
+ goto next;
+ }
+ unescaped = g_string_append_unichar (unescaped, l);
+ text = end;
+
+ if (*text == ';') {
+ text++;
+ }
+ goto next;
+ }
+
+ /* escape & */
+ unescaped = g_string_append (unescaped, "&");
+
+ next:
+ continue;
+
+ } else if (g_ascii_isspace (*text)) {
+ unescaped = g_string_append_c (unescaped, ' ');
+ /* strip whitespace */
+ do {
+ text++;
+ } while ((*text) && g_ascii_isspace (*text));
+ } else {
+ unescaped = g_string_append_c (unescaped, *text);
+ text++;
+ }
+ }
+
+ return g_string_free (unescaped, FALSE);
+}
+
+static const gchar *
+string_token (const gchar * string, const gchar * delimiter, gchar ** first)
+{
+ gchar *next = strstr (string, delimiter);
+ if (next) {
+ *first = g_strndup (string, next - string);
+ } else {
+ *first = g_strdup (string);
+ }
+ return next;
+}
+
+static void
+html_context_handle_element (HtmlContext * ctxt,
+ const gchar * string, gboolean must_close)
+{
+ gchar *name = NULL;
+ gint count = 0, i;
+ gchar **attrs;
+ const gchar *found, *next;
+#ifdef SUBPARSE_MODIFICATION
+ const gchar *name_temp = NULL;
+ gint j = 0;
+#endif
+ /* split element name and attributes */
+ next = string_token (string, " ", &name);
+
+ if (next) {
+ /* count attributes */
+ found = next + 1;
+ while (TRUE) {
+ found = strchr (found, '=');
+ if (!found)
+ break;
+ found++;
+ count++;
+ }
+ } else {
+ count = 0;
+ }
+
+ attrs = g_new0 (gchar *, (count + 1) * 2);
+
+ for (i = 0; i < count; i += 2) {
+ gchar *attr_name = NULL, *attr_value = NULL;
+ gsize length;
+
+#ifdef SUBPARSE_MODIFICATION
+ /* sometimes count can unnecessarily be high value, because of unrequired "=" in subtitle file.
+ * In that case it should not crash */
+ if (!next)
+ break;
+#endif
+
+ next = string_token (next + 1, "=", &attr_name);
+
+#ifdef SUBPARSE_MODIFICATION
+ /* sometimes count can unnecessarily be high value, because of unrequired "=" in subtitle file.
+ * In that case it should not crash */
+ if (!next)
+ break;
+#endif
+
+ next = string_token (next + 1, " ", &attr_value);
+
+ /* strip " or ' from attribute value */
+ if (attr_value[0] == '"' || attr_value[0] == '\'') {
+ gchar *tmp = g_strdup (attr_value + 1);
+ g_free (attr_value);
+ attr_value = tmp;
+ }
+
+ length = strlen (attr_value);
+ if (attr_value[length - 1] == '"' || attr_value[length - 1] == '\'') {
+ attr_value[length - 1] = '\0';
+ }
+
+ attrs[i] = attr_name;
+ attrs[i + 1] = attr_value;
+ }
+#ifdef SUBPARSE_MODIFICATION
+ /* sometimes spaces can be there in between !-- and P
+ * that also we have to take care */
+ if (!g_ascii_strcasecmp("!--", name)) {
+ gchar* tempchar = (gchar*)(string + 3);
+ while (*tempchar == ' ') {
+ tempchar++;
+ if (*tempchar == 'P' || *tempchar == 'p') {
+ *(name + 3) = *tempchar;
+ *(name + 4) = '\0';
+ next = tempchar + 1;
+ break;
+ }
+ }
+ }
+ if (next && (!g_ascii_strcasecmp("!--P", name))) {
+ gint attrindex = 0;
+ count = 0;
+ /* count attributes */
+ found = next + 1;
+ while (TRUE) {
+ found = (gchar*)strcasestr (found, "lang");
+ if (!found)
+ break;
+ found++;
+ count++;
+ }
+ g_strfreev (attrs);
+
+ attrs = g_new0 (gchar *, count * 2);
+
+ for (i = 0; i < count; i++) {
+ gchar *attr_name = NULL, *attr_value = NULL;
+
+ next = (gchar*)strcasestr (next, "lang:");
+ attr_value = (gchar*)malloc (3);
+ next = next + 5;
+ strncpy (attr_value, next, 2);
+ attr_value[2] = '\0';
+ GST_LOG ("Language value comes as %s", attr_value);
+ name_temp = next;
+ while (TRUE) {
+ if (*name_temp == '{') {
+ int character_count = 0;
+
+ while (TRUE) {
+ name_temp--;
+
+ if (*name_temp == '.') {
+ attr_name = (gchar*) malloc (character_count + 1);
+ break;
+ }
+ else if (*name_temp != ' ')
+ character_count++;
+ }
+ break;
+ }
+ name_temp--;
+ }
+ name_temp++;
+ for (j = 0; *(name_temp + j) != ' '; j++) {
+ attr_name[j] = *(name_temp + j);
+ }
+ attr_name[j] = '\0';
+ attrs[attrindex++] = attr_name;
+ attrs[attrindex++] = attr_value;
+ }
+ } else {
+ count = 0;
+ }
+#endif
+ ctxt->parser->start_element (ctxt, name,
+ (const gchar **) attrs, ctxt->user_data);
+ if (must_close) {
+ ctxt->parser->end_element (ctxt, name, ctxt->user_data);
+ }
+ g_strfreev (attrs);
+ g_free (name);
+}
+
+static void
+html_context_parse (HtmlContext * ctxt, gchar * text, gsize text_len)
+{
+ const gchar *next = NULL;
+ ctxt->buf = g_string_append_len (ctxt->buf, text, text_len);
+ next = ctxt->buf->str;
+ if (!next) {
+ GST_ERROR ("ctxt->buf->str is NULL");
+ return;
+ }
+ while (TRUE) {
+ if (next[0] == '<') {
+ gchar *element = NULL;
+ /* find <blahblah> */
+ if (!strchr (next, '>')) {
+ /* no tag end point. buffer will be process in next time */
+ return;
+ }
+
+ next = string_token (next, ">", &element);
+ next++;
+ if (g_str_has_suffix (next, "/")) {
+ /* handle <blah/> */
+ element[strlen (element) - 1] = '\0';
+ html_context_handle_element (ctxt, element + 1, TRUE);
+ } else if (element[1] == '/') {
+ /* handle </blah> */
+ ctxt->parser->end_element (ctxt, element + 2, ctxt->user_data);
+ } else {
+ /* handle <blah> */
+ html_context_handle_element (ctxt, element + 1, FALSE);
+ }
+ g_free (element);
+ } else if (strchr (next, '<')) {
+ gchar *text = NULL;
+ gsize length;
+ next = string_token (next, "<", &text);
+ text = g_strstrip (text);
+ length = strlen (text);
+ ctxt->parser->text (ctxt, text, length, ctxt->user_data);
+ g_free (text);
+
+ } else {
+ gchar *text = (gchar *) next;
+ gsize length;
+ text = g_strstrip (text);
+ length = strlen (text);
+ ctxt->parser->text (ctxt, text, length, ctxt->user_data);
+ ctxt->buf = g_string_assign (ctxt->buf, "");
+ return;
+ }
+ }
+
+ ctxt->buf = g_string_assign (ctxt->buf, next);
+}
+
static gchar *
has_tag (GString * str, const gchar tag)
{
}
static void
-handle_start_sync (GstSamiContext * sctx, const xmlChar ** atts)
+handle_start_sync (GstSamiContext * sctx, const gchar ** atts)
{
int i;
sami_context_pop_state (sctx, CLEAR_TAG);
if (atts != NULL) {
for (i = 0; (atts[i] != NULL); i += 2) {
- const xmlChar *key, *value;
+ const gchar *key, *value;
key = atts[i];
value = atts[i + 1];
if (!value)
continue;
- if (!xmlStrncmp ((const xmlChar *) "start", key, 5)) {
+ if (!g_ascii_strcasecmp ("start", key)) {
/* Only set a new start time if we don't have text pending */
if (sctx->resultbuf->len == 0)
sctx->time1 = sctx->time2;
sctx->time2 = atoi ((const char *) value) * GST_MSECOND;
+#ifdef SUBPARSE_MODIFICATION
+ sctx->time3 = sctx->time2;
+#endif
+ sctx->time2 = MAX (sctx->time2, sctx->time1);
g_string_append (sctx->resultbuf, sctx->buf->str);
sctx->has_result = (sctx->resultbuf->len != 0) ? TRUE : FALSE;
g_string_truncate (sctx->buf, 0);
}
static void
-handle_start_font (GstSamiContext * sctx, const xmlChar ** atts)
+handle_start_font (GstSamiContext * sctx, const gchar ** atts)
{
int i;
if (atts != NULL) {
g_string_append (sctx->buf, "<span");
for (i = 0; (atts[i] != NULL); i += 2) {
- const xmlChar *key, *value;
+ const gchar *key, *value;
key = atts[i];
value = atts[i + 1];
if (!value)
continue;
- if (!xmlStrncmp ((const xmlChar *) "color", key, 5)) {
+ if (!g_ascii_strcasecmp ("color", key)) {
/*
* There are invalid color value in many
* sami files.
* It will fix hex color value that start without '#'
*/
const gchar *sharp = "";
- int len = xmlStrlen (value);
+ int len = strlen (value);
if (!(*value == '#' && len == 7)) {
gchar *r;
/* check if it looks like hex */
if (strtol ((const char *) value, &r, 16) >= 0 &&
- ((xmlChar *) r == (value + 6) && len == 6)) {
+ ((gchar *) r == (value + 6) && len == 6)) {
sharp = "#";
}
}
/* some colours can be found in many sami files, but X RGB database
* doesn't contain a colour by this name, so map explicitly */
- if (!xmlStrncasecmp (value, (const xmlChar *) "aqua", len)) {
- value = (const xmlChar *) "#00ffff";
- } else if (!xmlStrncasecmp (value, (const xmlChar *) "crimson", len)) {
- value = (const xmlChar *) "#dc143c";
- } else if (!xmlStrncasecmp (value, (const xmlChar *) "fuchsia", len)) {
- value = (const xmlChar *) "#ff00ff";
- } else if (!xmlStrncasecmp (value, (const xmlChar *) "indigo", len)) {
- value = (const xmlChar *) "#4b0082";
- } else if (!xmlStrncasecmp (value, (const xmlChar *) "lime", len)) {
- value = (const xmlChar *) "#00ff00";
- } else if (!xmlStrncasecmp (value, (const xmlChar *) "olive", len)) {
- value = (const xmlChar *) "#808000";
- } else if (!xmlStrncasecmp (value, (const xmlChar *) "silver", len)) {
- value = (const xmlChar *) "#c0c0c0";
- } else if (!xmlStrncasecmp (value, (const xmlChar *) "teal", len)) {
- value = (const xmlChar *) "#008080";
+ if (!g_ascii_strcasecmp ("aqua", value)) {
+ value = "#00ffff";
+ } else if (!g_ascii_strcasecmp ("crimson", value)) {
+ value = "#dc143c";
+ } else if (!g_ascii_strcasecmp ("fuchsia", value)) {
+ value = "#ff00ff";
+ } else if (!g_ascii_strcasecmp ("indigo", value)) {
+ value = "#4b0082";
+ } else if (!g_ascii_strcasecmp ("lime", value)) {
+ value = "#00ff00";
+ } else if (!g_ascii_strcasecmp ("olive", value)) {
+ value = "#808000";
+ } else if (!g_ascii_strcasecmp ("silver", value)) {
+ value = "#c0c0c0";
+ } else if (!g_ascii_strcasecmp ("teal", value)) {
+ value = "#008080";
}
g_string_append_printf (sctx->buf, " foreground=\"%s%s\"", sharp,
value);
- } else if (!xmlStrncasecmp ((const xmlChar *) "face", key, 4)) {
+ } else if (!g_ascii_strcasecmp ("face", key)) {
g_string_append_printf (sctx->buf, " font_family=\"%s\"", value);
}
}
}
}
+#ifdef SUBPARSE_MODIFICATION
+static void
+handle_p (GstSamiContext * sctx, const gchar ** atts)
+{
+ int i;
+
+ if (atts != NULL) {
+ for (i = 0; (atts[i] != NULL); i += 2) {
+ const gchar *key, *value;
+
+ key = atts[i];
+ value = atts[i + 1];
+
+ if (sctx->current_language && value && strcmp(sctx->current_language, value)
+ && (sctx->time1 == sctx->time2))
+ sctx->language_changed = TRUE;
+
+ else if (!sctx->current_language)
+ sctx->current_language = (gchar*) malloc (128);
+
+ if (key && !g_ascii_strcasecmp ("class", key) && value) {
+ strcpy (sctx->current_language, value);
+ if (sctx->desired_language == NULL && key) {
+ sctx->desired_language = g_strdup(value);
+ GST_LOG("no language list was found and desired lang was set to %s",sctx->desired_language);
+ }
+ }
+ if (sctx->language_changed)
+ {
+ sctx->time1 = 0;
+ sctx->time2 = sctx->time3;
+ sctx->language_changed = FALSE;
+ }
+ if (!value)
+ continue;
+ }
+ }
+}
+
static void
-start_sami_element (void *ctx, const xmlChar * name, const xmlChar ** atts)
+handle_start_language_list (GstSamiContext * sctx, const gchar ** atts)
{
- GstSamiContext *sctx = (GstSamiContext *) ctx;
+ int i = 0;
+ int attrIndex = 0;
+ GstLangStruct *new = NULL;
+ GstLangStruct *temp = NULL;
+
+ if (atts != NULL) {
+ if (g_list_length (sctx->lang_list)) {
+ GST_LOG ("We already got the language list");
+ return;
+ }
+ for (i = 0; (atts[attrIndex] != NULL); i++) {
+ const gchar *key, *value;
+
+ key = atts[attrIndex++];
+ value = atts[attrIndex++];
+
+ GST_LOG ("Inside handle_start_language_list key: %s, value: %s", key, value);
+
+ if (!value)
+ continue;
+
+ new = g_new0 (GstLangStruct, 1);
+ new->language_code = (gchar*) malloc (strlen(value) + 1);
+ if (new->language_code && value)
+ strcpy (new->language_code, value);
+ new->language_key = (gchar*) malloc (strlen(key) + 1);
+ if (new->language_key && key)
+ strcpy (new->language_key, key);
+ sctx->lang_list = g_list_append (sctx->lang_list, new);
+ temp = g_list_nth_data (sctx->lang_list, i);
+ if (sctx->desired_language == NULL && key){
+ sctx->desired_language = g_strdup(key);
+ }
+
+ if (temp)
+ GST_LOG ("Inside handle_start_language_list of glist key: %s, value: %s",
+ temp->language_key, temp->language_code);
+ }
+ }
+}
+#endif
+
+static void
+handle_start_element (HtmlContext * ctx, const gchar * name,
+ const char **atts, gpointer user_data)
+{
+ GstSamiContext *sctx = (GstSamiContext *) user_data;
GST_LOG ("name:%s", name);
- if (!xmlStrncmp ((const xmlChar *) "sync", name, 4)) {
+ if (!g_ascii_strcasecmp ("sync", name)) {
handle_start_sync (sctx, atts);
sctx->in_sync = TRUE;
- } else if (!xmlStrncmp ((const xmlChar *) "font", name, 4)) {
+ } else if (!g_ascii_strcasecmp ("font", name)) {
handle_start_font (sctx, atts);
- } else if (!xmlStrncmp ((const xmlChar *) "ruby", name, 4)) {
+ } else if (!g_ascii_strcasecmp ("ruby", name)) {
sami_context_push_state (sctx, RUBY_TAG);
- } else if (!xmlStrncmp ((const xmlChar *) "br", name, 2)) {
- g_string_append_c (sctx->buf, '\n');
+ } else if (!g_ascii_strcasecmp ("br", name)) {
+#ifdef SUBPARSE_MODIFICATION
+ if (sctx->current_language && sctx->desired_language &&
+ !strcmp(sctx->current_language, sctx->desired_language))
+#endif
+ g_string_append_c (sctx->buf, '\n');
/* FIXME: support for furigana/ruby once implemented in pango */
- } else if (!xmlStrncmp ((const xmlChar *) "rt", name, 2)) {
+ } else if (!g_ascii_strcasecmp ("rt", name)) {
if (has_tag (sctx->state, ITALIC_TAG)) {
g_string_append (sctx->rubybuf, "<i>");
}
g_string_append (sctx->rubybuf, "<span size='xx-small' rise='-100'>");
sami_context_push_state (sctx, RT_TAG);
- } else if (!xmlStrncmp ((const xmlChar *) "p", name, 1)) {
- } else if (!xmlStrncmp ((const xmlChar *) "i", name, 1)) {
- g_string_append (sctx->buf, "<i>");
+ } else if (!g_ascii_strcasecmp ("i", name)) {
+#ifdef SUBPARSE_MODIFICATION
+ if (sctx->current_language && sctx->desired_language &&
+ !strcmp(sctx->current_language, sctx->desired_language))
+#endif
+ g_string_append (sctx->buf, "<i>");
sami_context_push_state (sctx, ITALIC_TAG);
+ } else if (!g_ascii_strcasecmp ("p", name)) {
+#ifdef SUBPARSE_MODIFICATION
+ handle_p (sctx, atts);
+ } else if (!g_ascii_strcasecmp ("!--P", name)) {
+ handle_start_language_list (sctx, atts);
+#endif
}
}
static void
-end_sami_element (void *ctx, const xmlChar * name)
+handle_end_element (HtmlContext * ctx, const char *name, gpointer user_data)
{
- GstSamiContext *sctx = (GstSamiContext *) ctx;
+ GstSamiContext *sctx = (GstSamiContext *) user_data;
GST_LOG ("name:%s", name);
- if (!xmlStrncmp ((const xmlChar *) "sync", name, 4)) {
+ if (!g_ascii_strcasecmp ("sync", name)) {
sctx->in_sync = FALSE;
- } else if ((!xmlStrncmp ((const xmlChar *) "body", name, 4)) ||
- (!xmlStrncmp ((const xmlChar *) "sami", name, 4))) {
+ } else if ((!g_ascii_strcasecmp ("body", name)) ||
+ (!g_ascii_strcasecmp ("sami", name))) {
/* We will usually have one buffer left when the body is closed
* as we need the next sync to actually send it */
+
+#ifdef SUBPARSE_MODIFICATION
+ sctx->end_body = TRUE;
+#endif
+
if (sctx->buf->len != 0) {
/* Only set a new start time if we don't have text pending */
if (sctx->resultbuf->len == 0)
sctx->has_result = (sctx->resultbuf->len != 0) ? TRUE : FALSE;
g_string_truncate (sctx->buf, 0);
}
- } else if (!xmlStrncmp ((const xmlChar *) "font", name, 4)) {
+ } else if (!g_ascii_strcasecmp ("font", name)) {
sami_context_pop_state (sctx, SPAN_TAG);
- } else if (!xmlStrncmp ((const xmlChar *) "ruby", name, 4)) {
+ } else if (!g_ascii_strcasecmp ("ruby", name)) {
sami_context_pop_state (sctx, RUBY_TAG);
- } else if (!xmlStrncmp ((const xmlChar *) "i", name, 1)) {
+ } else if (!g_ascii_strcasecmp ("i", name)) {
sami_context_pop_state (sctx, ITALIC_TAG);
}
}
static void
-characters_sami (void *ctx, const xmlChar * ch, int len)
+handle_text (HtmlContext * ctx, const gchar * text, gsize text_len,
+ gpointer user_data)
{
- GstSamiContext *sctx = (GstSamiContext *) ctx;
- gchar *escaped;
- gchar *tmp;
- gint i;
+ GstSamiContext *sctx = (GstSamiContext *) user_data;
/* Skip everything except content of the sync elements */
if (!sctx->in_sync)
return;
-
- escaped = g_markup_escape_text ((const gchar *) ch, len);
- g_strstrip (escaped);
-
- /* Remove double spaces forom the string as those are
- * usually added by newlines and indention */
- tmp = escaped;
- for (i = 0; i <= strlen (escaped); i++) {
- escaped[i] = *tmp;
- if (*tmp != ' ') {
- tmp++;
- continue;
- }
- while (*tmp == ' ')
- tmp++;
- }
-
+#ifdef SUBPARSE_MODIFICATION
+ if (has_tag (sctx->state, RT_TAG) && (sctx->current_language && sctx->desired_language &&
+ !strcmp(sctx->current_language, sctx->desired_language))) {
+#else
if (has_tag (sctx->state, RT_TAG)) {
+#endif
g_string_append_c (sctx->rubybuf, ' ');
- g_string_append (sctx->rubybuf, escaped);
+ g_string_append (sctx->rubybuf, text);
g_string_append_c (sctx->rubybuf, ' ');
} else {
- g_string_append (sctx->buf, escaped);
+#ifdef SUBPARSE_MODIFICATION
+ if (sctx->current_language && sctx->desired_language &&
+ !strcmp(sctx->current_language, sctx->desired_language))
+#endif
+ g_string_append (sctx->buf, text);
}
- g_free (escaped);
}
-static xmlSAXHandler samiSAXHandlerStruct = {
- NULL, /* internalSubset */
- NULL, /* isStandalone */
- NULL, /* hasInternalSubset */
- NULL, /* hasExternalSubset */
- NULL, /* resolveEntity */
- NULL, /* getEntity */
- NULL, /* entityDecl */
- NULL, /* notationDecl */
- NULL, /* attributeDecl */
- NULL, /* elementDecl */
- NULL, /* unparsedEntityDecl */
- NULL, /* setDocumentLocator */
- NULL, /* startDocument */
- NULL, /* endDocument */
- start_sami_element, /* startElement */
- end_sami_element, /* endElement */
- NULL, /* reference */
- characters_sami, /* characters */
- NULL, /* ignorableWhitespace */
- NULL, /* processingInstruction */
- NULL, /* comment */
- NULL, /* xmlParserWarning */
- NULL, /* xmlParserError */
- NULL, /* xmlParserError */
- NULL, /* getParameterEntity */
- NULL, /* cdataBlock */
- NULL, /* externalSubset */
- 1, /* initialized */
- NULL, /* private */
- NULL, /* startElementNsSAX2Func */
- NULL, /* endElementNsSAX2Func */
- NULL /* xmlStructuredErrorFunc */
+static HtmlParser samiParser = {
+ handle_start_element, /* start_element */
+ handle_end_element, /* end_element */
+ handle_text, /* text */
};
-static xmlSAXHandlerPtr samiSAXHandler = &samiSAXHandlerStruct;
-
void
sami_context_init (ParserState * state)
{
GstSamiContext *context;
g_assert (state->user_data == NULL);
- state->user_data = (gpointer) g_new0 (GstSamiContext, 1);
- context = (GstSamiContext *) state->user_data;
- context->htmlctxt = htmlCreatePushParserCtxt (samiSAXHandler, context,
- "", 0, NULL, XML_CHAR_ENCODING_UTF8);
+ context = g_new0 (GstSamiContext, 1);
+
+ context->htmlctxt = html_context_new (&samiParser, context);
context->buf = g_string_new ("");
context->rubybuf = g_string_new ("");
context->resultbuf = g_string_new ("");
context->state = g_string_new ("");
+#ifdef SUBPARSE_MODIFICATION
+ context->current_language = NULL;
+ context->desired_language = NULL;
+ context->lang_list = NULL;
+ context->language_changed = FALSE;
+ context->end_body = FALSE;
+#endif
+ state->user_data = context;
}
void
sami_context_deinit (ParserState * state)
{
GstSamiContext *context = (GstSamiContext *) state->user_data;
-
+#ifdef SUBPARSE_MODIFICATION
+ GstLangStruct *temp = NULL;
+ int i = 0;
+#endif
if (context) {
- htmlParserCtxtPtr htmlctxt = context->htmlctxt;
-
- /* destroy sax context */
- htmlDocPtr doc;
-
- htmlParseChunk (htmlctxt, "", 0, 1);
- doc = htmlctxt->myDoc;
- htmlFreeParserCtxt (htmlctxt);
+ html_context_free (context->htmlctxt);
context->htmlctxt = NULL;
- if (doc)
- xmlFreeDoc (doc);
g_string_free (context->buf, TRUE);
g_string_free (context->rubybuf, TRUE);
g_string_free (context->resultbuf, TRUE);
g_string_free (context->state, TRUE);
+#ifdef SUBPARSE_MODIFICATION
+ if (context->lang_list) {
+ while ((temp = g_list_nth_data (context->lang_list, i))) {
+ if (temp->language_code)
+ free (temp->language_code);
+ temp->language_code = NULL;
+ if (temp->language_key)
+ free (temp->language_key);
+ temp->language_key = NULL;
+ g_free (temp);
+ i++;
+ }
+ g_list_free (context->lang_list);
+ }
+ context->lang_list = NULL;
+
+ if (context->current_language)
+ free (context->current_language);
+ context->current_language = NULL;
+
+ context->desired_language = NULL;
+#endif
g_free (context);
state->user_data = NULL;
}
}
}
-static gchar *
-fix_invalid_entities (const gchar * line)
+#ifdef SUBPARSE_MODIFICATION
+void
+sami_context_change_language (ParserState * state)
{
- const gchar *cp, *pp; /* current pointer, previous pointer */
- gssize size;
- GString *ret = g_string_new (NULL);
-
- pp = line;
- cp = strchr (line, '&');
- while (cp) {
- size = cp - pp;
- ret = g_string_append_len (ret, pp, size);
- cp++;
- if (g_ascii_strncasecmp (cp, "nbsp;", 5)
- && (!g_ascii_strncasecmp (cp, "nbsp", 4))) {
- /* translate " " to " " */
- ret = g_string_append_len (ret, " ", 6);
- cp += 4;
- } else if (g_ascii_strncasecmp (cp, "quot;", 5)
- && g_ascii_strncasecmp (cp, "amp;", 4)
- && g_ascii_strncasecmp (cp, "apos;", 5)
- && g_ascii_strncasecmp (cp, "lt;", 3)
- && g_ascii_strncasecmp (cp, "gt;", 3)
- && g_ascii_strncasecmp (cp, "nbsp;", 5)
- && cp[0] != '#') {
- /* translate "&" to "&" */
- ret = g_string_append_len (ret, "&", 5);
- } else {
- /* do not translate */
- ret = g_string_append_c (ret, '&');
+ GstSamiContext *context = (GstSamiContext *) state->user_data;
+ GST_LOG ("**********desired language was %s**************", context->desired_language);
+ free (context->desired_language);
+ if(state->current_language) {
+ context->desired_language = state->current_language;
+ } else {
+ context->desired_language = state->msl_language;
+ }
+ GST_LOG ("desired language changed to %s", context->desired_language);
+}
+
+gchar *
+sami_convert_to_utf8 (const gchar * str, gsize len, const gchar * encoding,
+ gsize * consumed, GError ** err, GstSubParse * self)
+{
+ gchar *ret = NULL;
+
+ /* The char cast is necessary in glib < 2.24 */
+ ret =
+ g_convert_with_fallback (str, len, "UTF-8", encoding, (char *) "*",
+ consumed, NULL, err);
+
+ if (ret == NULL)
+ {
+ GST_DEBUG_OBJECT (self, "g_convert_with_fallback returns NULL");
+ return ret;
+ }
+
+ /* + 3 to skip UTF-8 BOM if it was added */
+ len = strlen (ret);
+ if (len >= 3 && (guint8) ret[0] == 0xEF && (guint8) ret[1] == 0xBB
+ && (guint8) ret[2] == 0xBF)
+ g_memmove (ret, ret + 3, len + 1 - 3);
+
+ return ret;
+}
+
+gboolean
+sami_validate_langlist_body(GList * lang_list, GstSubParse * self){
+ gchar * file_path_type = NULL;
+ gchar * file_path = NULL;
+ gchar line[1024];
+ FILE * fp = NULL;
+ guint i = 0, found_count = 0;
+ const guint list_len = g_list_length(lang_list);
+ gboolean counter[MAX_LANGUAGE];
+ struct LangStruct
+ {
+ gchar *language_code;
+ gchar *language_key;
+ } * lang;
+
+ GstQuery *cquery;
+ GstStructure *structure;
+ const GValue *value;
+ structure = gst_structure_new ("FileSrcURI",
+ "file-uri", G_TYPE_STRING, NULL, NULL);
+
+ cquery = gst_query_new_application (GST_QUERY_CUSTOM, structure);
+
+ if (!gst_pad_peer_query (self->sinkpad, cquery))
+ {
+ GST_DEBUG_OBJECT (self, "failed to query SMI file path");
+ gst_query_unref (cquery);
+ return FALSE;
+ }
+ structure = gst_query_get_structure (cquery);
+ value = gst_structure_get_value (structure, "file-uri");
+ file_path = g_strdup (g_value_get_string (value));
+
+ if (file_path == NULL){
+ GST_DEBUG_OBJECT (self, "could not parse the SMI file path");
+ gst_query_unref (cquery);
+ return FALSE;
+ }
+ gst_query_unref (cquery);
+
+ GST_INFO_OBJECT (self, "file path comes as %s", file_path);
+
+ file_path_type = g_strndup ((gchar *) file_path, 4);
+ GST_INFO_OBJECT (self, "received file path by query = %s,%s", file_path,file_path_type);
+ if (!g_strcmp0(file_path_type, "file")){
+ file_path += 7;
+ GST_INFO_OBJECT (self, "file path comes as %s", file_path);
+
+ fp = fopen (file_path, "r");
+ if (!fp){
+ GST_DEBUG_OBJECT (self, "failed to open file");
+ return FALSE;
+ }
+
+ for(i=0;i<list_len;i++){
+ counter[i] = FALSE;
}
- pp = cp;
- cp = strchr (pp, '&');
+ while(!feof(fp) && found_count < list_len){
+ GError *err = NULL;
+ gsize * consumed = NULL;
+ gint gap = 0;
+ guint charCount = 0;
+ gchar* result = NULL;
+ gchar* temp = NULL;
+ gchar* temp_lang = NULL;
+ gchar * temp1 = NULL;
+ gchar *con_temp_lang = NULL;
+ gchar *con_temp = NULL;
+ gboolean conversion = TRUE;
+ charCount = fread (line, sizeof(char), 1024, fp);
+ if (!charCount) {
+ GST_WARNING_OBJECT (self, "fread returned zero bytes");
+ continue;
+ }
+ GST_DEBUG("value of detected encoding is %s and self encoding is %s",self->detected_encoding,self->encoding);
+ if (self->detected_encoding && strcmp (self->detected_encoding, "UTF-8") && conversion){
+ result = sami_convert_to_utf8 (line, charCount, self->detected_encoding, consumed, &err, self);
+ }
+ if(result == NULL) {
+ result = line;
+ conversion = FALSE;
+ }
+ con_temp = g_utf8_strdown (result,strlen(result));
+ temp = con_temp;
+ while(con_temp) {
+ con_temp = g_strstr_len(con_temp, strlen(con_temp),"class=");
+ if(con_temp) {
+ temp1 = g_strstr_len(con_temp+1, strlen(con_temp),"class=");
+ }
+ if(temp1 && con_temp){
+ gap = strlen(con_temp)-strlen(temp1);
+ }else if(con_temp) {
+ gap = strlen(con_temp);
+ } else {
+ continue;
+ }
+ if(con_temp){
+ for(i=0;i<list_len;i++){
+ if(counter[i]==TRUE){
+ con_temp=con_temp+1;
+ continue;
+ }
+ lang = (struct LangStruct *) g_list_nth_data(lang_list,i);
+ if(lang) {
+ temp_lang = g_strdup(lang->language_key);
+ con_temp_lang = g_utf8_strdown (temp_lang,strlen(temp_lang));
+ if(g_strstr_len(con_temp,gap,con_temp_lang)){
+ found_count++;
+ counter[i]=TRUE;
+ GST_INFO_OBJECT (self, " valid Language in list : [%s]", lang->language_key);
+ con_temp=con_temp+1;
+ }
+ g_free(temp_lang);
+ g_free(con_temp_lang);
+ }
+ }
+ }
+ }
+ if(conversion)
+ g_free (result);
+ if(temp)
+ g_free(temp);
+
+ }
+
+ if(found_count < list_len){
+ for(i=0;i<list_len;i++){
+ if(counter[i]==FALSE)
+ lang_list = g_list_delete_link(lang_list,g_list_nth(lang_list,i));
+ }
+ }
}
- ret = g_string_append (ret, pp);
- return g_string_free (ret, FALSE);
+ fclose(fp);
+ return TRUE;
}
+#endif
gchar *
parse_sami (ParserState * state, const gchar * line)
{
- gchar *fixed_line;
+ gchar *ret = NULL;
+#ifdef SUBPARSE_MODIFICATION
+ gint64 clip_start = 0, clip_stop = 0;
+ gboolean in_seg = FALSE;
+#endif
GstSamiContext *context = (GstSamiContext *) state->user_data;
- fixed_line = fix_invalid_entities (line);
- htmlParseChunk (context->htmlctxt, fixed_line, strlen (fixed_line), 0);
- g_free (fixed_line);
+ gchar *unescaped = unescape_string (line);
+ html_context_parse (context->htmlctxt, (gchar *) unescaped,
+ strlen (unescaped));
+#ifdef SUBPARSE_MODIFICATION
+ if (context->lang_list)
+ state->language_list = context->lang_list;
- if (context->has_result) {
- gchar *r;
+ if (context->desired_language)
+ state->current_language = context->desired_language;
+#endif
+ g_free (unescaped);
+#ifdef SUBPARSE_MODIFICATION
+ if (context->desired_language && context->current_language) {
+ if ((!strcmp(context->current_language, context->desired_language)) || context->end_body) {
+#endif
+ if (context->has_result) {
+ if (context->rubybuf->len) {
+ context->rubybuf = g_string_append_c (context->rubybuf, '\n');
+ g_string_prepend (context->resultbuf, context->rubybuf->str);
+ context->rubybuf = g_string_truncate (context->rubybuf, 0);
+ }
- if (context->rubybuf->len) {
- context->rubybuf = g_string_append_c (context->rubybuf, '\n');
- g_string_prepend (context->resultbuf, context->rubybuf->str);
- context->rubybuf = g_string_truncate (context->rubybuf, 0);
+ ret = g_string_free (context->resultbuf, FALSE);
+ context->resultbuf = g_string_new ("");
+ state->start_time = context->time1;
+ state->duration = context->time2 - context->time1;
+ context->has_result = FALSE;
+ }
+#ifdef SUBPARSE_MODIFICATION
+ context->end_body = FALSE;
}
+ }
+ /* Check our segment start/stop */
+ in_seg = gst_segment_clip (state->segment, GST_FORMAT_TIME,
+ state->start_time, state->start_time + state->duration, &clip_start,
+ &clip_stop);
- r = g_string_free (context->resultbuf, FALSE);
- context->resultbuf = g_string_new ("");
- state->start_time = context->time1;
- state->duration = context->time2 - context->time1;
- context->has_result = FALSE;
- return r;
+ /* No need to send that text if it's out of segment */
+ if (in_seg) {
+ state->start_time = clip_start;
+ state->duration = clip_stop - clip_start;
+ } else {
+ return NULL;
}
- return NULL;
+#endif
+ return ret;
}
/* GStreamer
* Copyright (C) <2005> Julien Moutte <julien@moutte.net>
* <2009>,<2010> Stefan Kost <stefan.kost@nokia.com>
+ * Copyright (C) 2012, 2013 Samsung Electronics Co., Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms 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.
+ *
+ * * Modifications by Samsung Electronics Co., Ltd.
+ * 1. Add display related properties
+ * 2. Support samsung extension format to improve performance
+ * 3. Support video texture overlay of OSP layer
*/
/**
/* For xv extension header for buffer transfer (output) */
#include "xv_types.h"
+/* headers for drm */
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <X11/Xmd.h>
+#include <dri2/dri2.h>
+#include <tbm_bufmgr.h>
+
+/* for setting vconf about xv state */
+#include <vconf.h>
+#include <vconf-internal-player-keys.h>
+
+
+enum {
+ SECURE_PATH_INIT = -1,
+ SECURE_PATH_OFF = 0,
+ SECURE_PATH_ON = 1
+};
+
+enum {
+ DRM_LEVEL_0 = 0,
+ DRM_LEVEL_1
+ };
+
+enum
+{
+ DISPLAY_STATUS_NULL = 0,
+ DISPLAY_STATUS_HDMI_ACTIVE,
+ DISPLAY_STATUS_UNKNOWN_ACTIVE,
+};
+
+enum
+{
+ XV_STATUS_NULL = 0,
+ XV_STATUS_READY,
+ XV_STATUS_PAUSED,
+ XV_STATUS_PLAYING,
+ XV_STATUS_SEEK,
+};
+
+typedef enum {
+ BUF_SHARE_METHOD_PADDR = 0,
+ BUF_SHARE_METHOD_FD,
+ BUF_SHARE_METHOD_TIZEN_BUFFER,
+ BUF_SHARE_METHOD_FLUSH_BUFFER
+} buf_share_method_t;
+
+#define _CHECK_DISPLAYED_BUFFER_COUNT 15
+#define _EVENT_THREAD_CHECK_INTERVAL 15000 /* us */
+
/* max channel count *********************************************************/
#define SCMN_IMGB_MAX_PLANE (4)
typedef struct
{
/* width of each image plane */
- int w[SCMN_IMGB_MAX_PLANE];
+ int w[SCMN_IMGB_MAX_PLANE];
/* height of each image plane */
- int h[SCMN_IMGB_MAX_PLANE];
+ int h[SCMN_IMGB_MAX_PLANE];
/* stride of each image plane */
- int s[SCMN_IMGB_MAX_PLANE];
+ int s[SCMN_IMGB_MAX_PLANE];
/* elevation of each image plane */
- int e[SCMN_IMGB_MAX_PLANE];
+ int e[SCMN_IMGB_MAX_PLANE];
/* user space address of each image plane */
- void * a[SCMN_IMGB_MAX_PLANE];
+ void *a[SCMN_IMGB_MAX_PLANE];
/* physical address of each image plane, if needs */
- void * p[SCMN_IMGB_MAX_PLANE];
+ void *p[SCMN_IMGB_MAX_PLANE];
/* color space type of image */
- int cs;
+ int cs;
/* left postion, if needs */
- int x;
+ int x;
/* top position, if needs */
- int y;
+ int y;
/* to align memory */
- int __dummy2;
+ int __dummy2;
/* arbitrary data */
- int data[16];
+ int data[16];
+ /* dma buf fd */
+ int dmabuf_fd[SCMN_IMGB_MAX_PLANE];
+ /* buffer share method */
+ int buf_share_method;
+ /* Y plane size in case of ST12 */
+ int y_size;
+ /* UV plane size in case of ST12 */
+ int uv_size;
+ /* Tizen buffer object */
+ void *bo[SCMN_IMGB_MAX_PLANE];
+ /* JPEG data */
+ void *jpeg_data;
+ /* JPEG size */
+ int jpeg_size;
+ /* TZ memory buffer */
+ int tz_enable;
} SCMN_IMGB;
+
+static void _release_flush_buffer(GstXvImageSink *xvimagesink);
+static void _remove_last_buffer(GstXvImageSink *xvimagesink);
+static gboolean gst_xvimagesink_make_flush_buffer(GstXvImageSink *xvimagesink);
#endif /* GST_EXT_XV_ENHANCEMENT */
/* Debugging category */
#ifdef GST_EXT_XV_ENHANCEMENT
#define GST_TYPE_XVIMAGESINK_DISPLAY_MODE (gst_xvimagesink_display_mode_get_type())
+#define GST_TYPE_XVIMAGESINK_CSC_RANGE (gst_xvimagesink_csc_range_get_type())
static GType
gst_xvimagesink_display_mode_get_type(void)
return xvimagesink_display_mode_type;
}
+static GType
+gst_xvimagesink_csc_range_get_type(void)
+{
+ static GType xvimagesink_csc_range_type = 0;
+ static const GEnumValue csc_range_type[] = {
+ { 0, "Narrow range", "NARROW"},
+ { 1, "Wide range", "WIDE"},
+ { 2, NULL, NULL},
+ };
+
+ if (!xvimagesink_csc_range_type) {
+ xvimagesink_csc_range_type = g_enum_register_static("GstXVImageSinkCSCRangeType", csc_range_type);
+ }
+
+ return xvimagesink_csc_range_type;
+}
+
enum {
DEGREE_0,
DEGREE_90,
DISP_GEO_METHOD_ORIGIN_SIZE,
DISP_GEO_METHOD_FULL_SCREEN,
DISP_GEO_METHOD_CROPPED_FULL_SCREEN,
- DISP_GEO_METHOD_CUSTOM_ROI,
+ DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX,
+ DISP_GEO_METHOD_CUSTOM_DST_ROI,
DISP_GEO_METHOD_NUM,
};
-#define DEF_DISPLAY_GEOMETRY_METHOD DISP_GEO_METHOD_LETTER_BOX
+enum {
+ ROI_DISP_GEO_METHOD_FULL_SCREEN = 0,
+ ROI_DISP_GEO_METHOD_LETTER_BOX,
+ ROI_DISP_GEO_METHOD_NUM,
+};
+
+#define DEF_DISPLAY_GEOMETRY_METHOD DISP_GEO_METHOD_LETTER_BOX
+#define DEF_ROI_DISPLAY_GEOMETRY_METHOD ROI_DISP_GEO_METHOD_FULL_SCREEN
+
+enum {
+ FLIP_NONE = 0,
+ FLIP_HORIZONTAL,
+ FLIP_VERTICAL,
+ FLIP_BOTH,
+ FLIP_NUM,
+};
+#define DEF_DISPLAY_FLIP FLIP_NONE
#define GST_TYPE_XVIMAGESINK_DISPLAY_GEOMETRY_METHOD (gst_xvimagesink_display_geometry_method_get_type())
+#define GST_TYPE_XVIMAGESINK_ROI_DISPLAY_GEOMETRY_METHOD (gst_xvimagesink_roi_display_geometry_method_get_type())
+#define GST_TYPE_XVIMAGESINK_FLIP (gst_xvimagesink_flip_get_type())
static GType
gst_xvimagesink_display_geometry_method_get_type(void)
{ 1, "Origin size", "ORIGIN_SIZE"},
{ 2, "Full-screen", "FULL_SCREEN"},
{ 3, "Cropped full-screen", "CROPPED_FULL_SCREEN"},
- { 4, "Explicitely described destination ROI", "CUSTOM_ROI"},
- { 5, NULL, NULL},
+ { 4, "Origin size(if screen size is larger than video size(width/height)) or Letter box(if video size(width/height) is larger than screen size)", "ORIGIN_SIZE_OR_LETTER_BOX"},
+ { 5, "Explicitly described destination ROI", "CUSTOM_DST_ROI"},
+ { 6, NULL, NULL},
};
if (!xvimagesink_display_geometry_method_type) {
return xvimagesink_display_geometry_method_type;
}
+
+static GType
+gst_xvimagesink_roi_display_geometry_method_get_type(void)
+{
+ static GType xvimagesink_roi_display_geometry_method_type = 0;
+ static const GEnumValue roi_display_geometry_method_type[] = {
+ { 0, "ROI-Full-screen", "FULL_SCREEN"},
+ { 1, "ROI-Letter box", "LETTER_BOX"},
+ { 2, NULL, NULL},
+ };
+
+ if (!xvimagesink_roi_display_geometry_method_type) {
+ xvimagesink_roi_display_geometry_method_type = g_enum_register_static("GstXVImageSinkROIDisplayGeometryMethodType", roi_display_geometry_method_type);
+ }
+
+ return xvimagesink_roi_display_geometry_method_type;
+}
+
+static GType
+gst_xvimagesink_flip_get_type(void)
+{
+ static GType xvimagesink_flip_type = 0;
+ static const GEnumValue flip_type[] = {
+ { FLIP_NONE, "Flip NONE", "FLIP_NONE"},
+ { FLIP_HORIZONTAL, "Flip HORIZONTAL", "FLIP_HORIZONTAL"},
+ { FLIP_VERTICAL, "Flip VERTICAL", "FLIP_VERTICAL"},
+ { FLIP_BOTH, "Flip BOTH", "FLIP_BOTH"},
+ { FLIP_NUM, NULL, NULL},
+ };
+
+ if (!xvimagesink_flip_type) {
+ xvimagesink_flip_type = g_enum_register_static("GstXVImageSinkFlipType", flip_type);
+ }
+
+ return xvimagesink_flip_type;
+}
+
+#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
+void
+gst_xvimagesink_BOOLEAN__POINTER (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER) (gpointer data1,
+ gpointer arg_1,
+ gpointer data2);
+ register GMarshalFunc_BOOLEAN__POINTER callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ gboolean v_return;
+
+ g_return_if_fail (return_value != NULL);
+ g_return_if_fail (n_param_values == 2);
+
+ if (G_CCLOSURE_SWAP_DATA (closure)) {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ } else {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_BOOLEAN__POINTER) (marshal_data ? marshal_data : cc->callback);
+
+ v_return = callback (data1,
+ g_marshal_value_peek_pointer (param_values + 1),
+ data2);
+
+ g_value_set_boolean (return_value, v_return);
+}
+
+enum
+{
+ SIGNAL_FRAME_RENDER_ERROR,
+ SIGNAL_DISPLAY_STATUS,
+ SIGNAL_EXTERNAL_RESOLUTION,
+ SIGNAL_WINDOW_STATUS,
+ SIGNAL_QUICKPANEL_STATUS,
+ SIGNAL_MULTIWINDOW_STATUS,
+ LAST_SIGNAL
+};
+static guint gst_xvimagesink_signals[LAST_SIGNAL] = { 0 };
+
#endif /* GST_EXT_XV_ENHANCEMENT */
typedef struct
#define MWM_HINTS_DECORATIONS (1L << 1)
+#ifdef GST_EXT_XV_ENHANCEMENT
+#define MAX_DISPLAY_IN_XVIMAGESINK 20
+static Display *g_display_id[MAX_DISPLAY_IN_XVIMAGESINK] = {0};
+#endif
+
static void gst_xvimagesink_reset (GstXvImageSink * xvimagesink);
static GstBufferClass *xvimage_buffer_parent_class = NULL;
#ifdef GST_EXT_XV_ENHANCEMENT
static XImage *make_transparent_image(Display *d, Window win, int w, int h);
static gboolean set_display_mode(GstXContext *xcontext, int set_mode);
+static gboolean set_csc_range(GstXContext *xcontext, int set_range);
+static void gst_xvimagesink_set_pixmap_handle(GstXOverlay *overlay, guintptr id);
+static unsigned int drm_convert_dmabuf_gemname(GstXvImageSink *xvimagesink, unsigned int dmabuf_fd, unsigned int *gem_handle);
+static void drm_close_gem(GstXvImageSink *xvimagesink, unsigned int *gem_handle);
+static void _add_displaying_buffer(GstXvImageSink *xvimagesink, XV_DATA_PTR img_data, GstBuffer *buffer);
+static void _remove_displaying_buffer(GstXvImageSink *xvimagesink, unsigned int *gem_name);
+static int _is_connected_to_external_display(GstXvImageSink *xvimagesink);
+static void check_hdmi_connected(GstXvImageSink *xvimagesink);
+static int get_window_prop_card32_property (Display* dpy, Window win, Atom atom, Atom type, unsigned int *val, unsigned int len);
+static gboolean check_supportable_port_attr(GstXvImageSink * xvimagesink, gchar* attr_name);
#endif /* GST_EXT_XV_ENHANCEMENT */
/* Default template - initiated with class struct to allow gst-register to work
PROP_WINDOW_HEIGHT,
#ifdef GST_EXT_XV_ENHANCEMENT
PROP_DISPLAY_MODE,
+ PROP_CSC_RANGE,
PROP_ROTATE_ANGLE,
+ PROP_FLIP,
PROP_DISPLAY_GEOMETRY_METHOD,
PROP_VISIBLE,
PROP_ZOOM,
+ PROP_ZOOM_POS_X,
+ PROP_ZOOM_POS_Y,
+ PROP_ORIENTATION,
+ PROP_DST_ROI_MODE,
PROP_DST_ROI_X,
PROP_DST_ROI_Y,
PROP_DST_ROI_W,
PROP_DST_ROI_H,
+ PROP_SRC_CROP_X,
+ PROP_SRC_CROP_Y,
+ PROP_SRC_CROP_W,
+ PROP_SRC_CROP_H,
PROP_STOP_VIDEO,
+ PROP_PIXMAP_CB,
+ PROP_PIXMAP_CB_USER_DATA,
+ PROP_SUBPICTURE,
+ PROP_EXTERNAL_WIDTH,
+ PROP_EXTERNAL_HEIGHT,
+ PROP_ENABLE_FLUSH_BUFFER,
+ PROP_PIXMAP,
+ PROP_HIDED_WINDOW,
+ PROP_QUICKPANEL_ON,
+ PROP_MULTIWINDOW_ACTIVE,
+ PROP_KEEP_EXTERNAL_FULLSCREEN_POST,
+ PROP_KEEP_EXTERNAL_FULLSCREEN_PREV,
#endif /* GST_EXT_XV_ENHANCEMENT */
};
char error_msg[1024];
XGetErrorText (display, xevent->error_code, error_msg, 1024);
- GST_DEBUG ("xvimagesink triggered an XError. error: %s", error_msg);
- error_caught = TRUE;
+#ifndef GST_EXT_XV_ENHANCEMENT
+ GST_DEBUG ("xvimagesink triggered an XError. error: %s, display(%p)", error_msg, display);
+#else
+ {
+ int i = 0;
+ for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
+ if (g_display_id[i] == display) {
+ GST_ERROR ("xvimagesink triggered an XError. error: %s, display(%p), xevent->request_code: %d", error_msg, display, xevent->request_code);
+ error_caught = TRUE;
+ break;
+ }
+ }
+ if (i == MAX_DISPLAY_IN_XVIMAGESINK) {
+ GST_ERROR ("xvimagesink triggered an XError. error: %s, xevent->request_code: %d, but the display(%p) was not created in xvimagesink, skip it...", error_msg, xevent->request_code, display);
+ }
+ }
+#endif
return 0;
}
xvimagesink->aligned_width = xvimage->width;
xvimagesink->aligned_height = xvimage->height;
}
+ if (xvimagesink->subpicture) {
+ GST_LOG("because of subpicture's format, pass xvimage_new");
+ return xvimage;
+ }
#endif /* GST_EXT_XV_ENHANCEMENT */
xvimage->im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
g_mutex_lock (xvimagesink->x_lock);
+#ifdef GST_EXT_XV_ENHANCEMENT
+ XSync (xvimagesink->xcontext->disp, FALSE);
+#endif /* GST_EXT_XV_ENHANCEMENT */
/* Setting an error handler to catch failure */
error_caught = FALSE;
handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
("could not XvShmCreateImage a %dx%d image",
xvimage->width, xvimage->height));
+#ifdef GST_EXT_XV_ENHANCEMENT
+ /* must not change "use_xshm",
+ because it causes memory curruption when buffer created by XvShmCreateImage is destroyed */
+ goto beach_unlocked;
+#else /* GST_EXT_XV_ENHANCEMENT */
/* Retry without XShm */
xvimagesink->xcontext->use_xshm = FALSE;
/* Hold X mutex again to try without XShm */
g_mutex_lock (xvimagesink->x_lock);
goto no_xshm;
+#endif /* GST_EXT_XV_ENHANCEMENT */
}
/* we have to use the returned data_size for our shm size */
#ifdef GST_EXT_XV_ENHANCEMENT
case GST_MAKE_FOURCC ('S', 'T', '1', '2'):
case GST_MAKE_FOURCC ('S', 'N', '1', '2'):
+ case GST_MAKE_FOURCC ('S', 'N', '2', '1'):
case GST_MAKE_FOURCC ('S', 'U', 'Y', 'V'):
case GST_MAKE_FOURCC ('S', 'U', 'Y', '2'):
case GST_MAKE_FOURCC ('S', '4', '2', '0'):
GST_DEBUG_OBJECT (xvimagesink, "XServer ShmAttached to 0x%x, id 0x%lx",
xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg);
} else
+#ifndef GST_EXT_XV_ENHANCEMENT
no_xshm:
+#endif /* GST_EXT_XV_ENHANCEMENT */
#endif /* HAVE_XSHM */
{
xvimage->xvimage = XvCreateImage (xvimagesink->xcontext->disp,
#ifdef GST_EXT_XV_ENHANCEMENT
static Atom atom_rotation = None;
+ static Atom atom_hflip = None;
+ static Atom atom_vflip = None;
+ static Atom atom_contents_rotation = None;
+ gboolean set_hflip = FALSE;
+ gboolean set_vflip = FALSE;
+ XWindowAttributes map_attr;
GstVideoRectangle src_origin = { 0, 0, 0, 0};
GstVideoRectangle src_input = { 0, 0, 0, 0};
GstVideoRectangle src = { 0, 0, 0, 0};
GstVideoRectangle dst = { 0, 0, 0, 0};
+ gint res_rotate_angle = 0;
int rotate = 0;
+ int orientation = 0;
int ret = 0;
+ int idx = 0;
+ int (*handler) (Display *, XErrorEvent *) = NULL;
+ gboolean res = FALSE;
+ XV_DATA_PTR img_data = NULL;
+
+ if (xvimagesink->is_subpicture_format)
+ return TRUE;
#endif /* GST_EXT_XV_ENHANCEMENT */
/* We take the flow_lock. If expose is in there we don't want to run
concurrently from the data flow thread */
g_mutex_lock (xvimagesink->flow_lock);
- if (G_UNLIKELY (xvimagesink->xwindow == NULL)) {
#ifdef GST_EXT_XV_ENHANCEMENT
- GST_INFO_OBJECT( xvimagesink, "xwindow is NULL. Skip xvimage_put." );
+ if (xvimagesink->xid_updated) {
+ if (xvimage && xvimagesink->xvimage == NULL) {
+ GST_WARNING_OBJECT (xvimagesink, "set xvimage to NULL, new xid was set right after creation of new xvimage");
+ xvimage = NULL;
+ }
+ xvimagesink->xid_updated = FALSE;
+ }
#endif /* GST_EXT_XV_ENHANCEMENT */
+
+ if (G_UNLIKELY (xvimagesink->xwindow == NULL)) {
+#ifdef GST_EXT_XV_ENHANCEMENT
+ if (xvimagesink->get_pixmap_cb) {
+ GST_INFO_OBJECT( xvimagesink, "xwindow is NULL, but it has get_pixmap_cb(0x%x), keep going..",xvimagesink->get_pixmap_cb );
+ } else {
+ GST_INFO_OBJECT( xvimagesink, "xwindow is NULL. Skip xvimage_put." );
+ g_mutex_unlock(xvimagesink->flow_lock);
+ return FALSE;
+ }
+#else /* GST_EXT_XV_ENHANCEMENT */
g_mutex_unlock (xvimagesink->flow_lock);
return FALSE;
+#endif /* GST_EXT_XV_ENHANCEMENT */
}
#ifdef GST_EXT_XV_ENHANCEMENT
- if (xvimagesink->visible == FALSE) {
- GST_INFO_OBJECT(xvimagesink, "visible is FALSE. Skip xvimage_put.");
- g_mutex_unlock(xvimagesink->flow_lock);
- return TRUE;
+ /* check map status of window */
+ if(!xvimagesink->is_pixmap) {
+ if (xvimagesink->xcontext && xvimagesink->xwindow) {
+ if (XGetWindowAttributes(xvimagesink->xcontext->disp, xvimagesink->xwindow->win, &map_attr)) {
+ if (map_attr.map_state != IsViewable) {
+ GST_WARNING_OBJECT(xvimagesink, "window is unmapped, skip putimage");
+ g_mutex_unlock(xvimagesink->flow_lock);
+ return TRUE;
+ }
+ } else {
+ GST_WARNING_OBJECT(xvimagesink, "XGetWindowAttributes failed");
+ }
+ }
}
#endif /* GST_EXT_XV_ENHANCEMENT */
/* Expose sends a NULL image, we take the latest frame */
if (!xvimage) {
+#ifdef GST_EXT_XV_ENHANCEMENT
+ g_mutex_lock(xvimagesink->display_buffer_lock);
+ if (xvimagesink->is_zero_copy_format &&
+ xvimagesink->displaying_buffer_count < 1) {
+ g_mutex_unlock(xvimagesink->display_buffer_lock);
+ g_mutex_unlock (xvimagesink->flow_lock);
+ GST_WARNING_OBJECT(xvimagesink, "no buffer to display. skip putimage");
+ return TRUE;
+ }
+ g_mutex_unlock(xvimagesink->display_buffer_lock);
+#endif /* GST_EXT_XV_ENHANCEMENT */
if (xvimagesink->cur_image) {
draw_border = TRUE;
xvimage = xvimagesink->cur_image;
} else {
#ifdef GST_EXT_XV_ENHANCEMENT
- GST_INFO_OBJECT(xvimagesink, "cur_image is NULL. Skip xvimage_put.");
+ GST_WARNING_OBJECT(xvimagesink, "cur_image is NULL. Skip xvimage_put.");
+ /* no need to release gem handle */
#endif /* GST_EXT_XV_ENHANCEMENT */
g_mutex_unlock (xvimagesink->flow_lock);
return TRUE;
}
#ifdef GST_EXT_XV_ENHANCEMENT
- gst_xvimagesink_xwindow_update_geometry( xvimagesink );
+ gboolean enable_last_buffer;
+ g_object_get(G_OBJECT(xvimagesink), "enable-last-buffer", &enable_last_buffer, NULL);
+ if(enable_last_buffer) {
+ if (xvimagesink->cur_image && xvimagesink->is_zero_copy_format) {
+ GstBuffer *last_buffer= NULL;
+ g_object_get(G_OBJECT(xvimagesink), "last-buffer", &last_buffer, NULL);
+ if (last_buffer) {
+ if(last_buffer != xvimagesink->cur_image)
+ {
+ GST_LOG("curimage : %p , last_buffer : %p", xvimagesink->cur_image, last_buffer);
+ }
+ } else {
+ GST_WARNING_OBJECT(xvimagesink, "zero copy format and last buffer is NULL, so skip this putimage");
+ g_mutex_unlock (xvimagesink->flow_lock);
+ return TRUE;
+ }
+ gst_buffer_unref(last_buffer);
+ last_buffer = NULL;
+ }
+ }
+
+ if (xvimagesink->visible == FALSE ||
+ (xvimagesink->is_hided && GST_STATE(xvimagesink) != GST_STATE_PLAYING)) {
+ GST_INFO("visible[%d] or is_hided[%d]. Skip xvimage_put.",
+ xvimagesink->visible, xvimagesink->is_hided);
+ g_mutex_unlock(xvimagesink->flow_lock);
+ return TRUE;
+ }
+
+ if (!xvimagesink->get_pixmap_cb) {
+ gst_xvimagesink_xwindow_update_geometry( xvimagesink );
+ if (!xvimagesink->subpicture && !xvimagesink->is_during_seek) {
+ if(xvimagesink->is_multi_window && (GST_STATE(xvimagesink) != GST_STATE_PLAYING)) {
+ set_display_mode(xvimagesink->xcontext, DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_CLONE);
+ } else {
+ set_display_mode(xvimagesink->xcontext, xvimagesink->display_mode);
+ }
+ }
+ } else {
+ /* for multi-pixmap usage for the video texture */
+ gst_xvimagesink_set_pixmap_handle ((GstXOverlay *)xvimagesink, xvimagesink->get_pixmap_cb(xvimagesink->get_pixmap_cb_user_data));
+ idx = xvimagesink->current_pixmap_idx;
+ if (idx == -1) {
+ g_mutex_unlock (xvimagesink->flow_lock);
+ return FALSE;
+ } else if (idx == -2) {
+ GST_WARNING_OBJECT(xvimagesink, "Skip putImage()");
+ g_mutex_unlock (xvimagesink->flow_lock);
+ return TRUE;
+ }
+ }
+
+ res_rotate_angle = xvimagesink->rotate_angle;
src.x = src.y = 0;
src_origin.x = src_origin.y = src_input.x = src_input.y = 0;
src_input.w = src_origin.w = xvimagesink->video_width;
src_input.h = src_origin.h = xvimagesink->video_height;
+ if ((xvimagesink->display_geometry_method == DISP_GEO_METHOD_LETTER_BOX ||
+ xvimagesink->display_geometry_method == DISP_GEO_METHOD_FULL_SCREEN ||
+ xvimagesink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_DST_ROI) &&
+ xvimagesink->src_crop.w && xvimagesink->src_crop.h) {
+ GST_LOG_OBJECT(xvimagesink, "set src crop %d,%d,%dx%d -> %d,%d,%dx%d",
+ src_input.x, src_input.y, src_input.w, src_input.h,
+ xvimagesink->src_crop.x, xvimagesink->src_crop.y, xvimagesink->src_crop.w, xvimagesink->src_crop.h);
+ src_input.x = src_origin.w = xvimagesink->src_crop.x;
+ src_input.y = src_origin.y = xvimagesink->src_crop.y;
+ src_input.w = src_origin.w = xvimagesink->src_crop.w;
+ src_input.h = src_origin.h = xvimagesink->src_crop.h;
+ }
+
if (xvimagesink->rotate_angle == DEGREE_0 ||
xvimagesink->rotate_angle == DEGREE_180) {
src.w = src_origin.w;
case DISP_GEO_METHOD_FULL_SCREEN:
result.x = result.y = 0;
- result.w = xvimagesink->xwindow->width;
- result.h = xvimagesink->xwindow->height;
+ if (!xvimagesink->get_pixmap_cb) {
+ result.w = xvimagesink->xwindow->width;
+ result.h = xvimagesink->xwindow->height;
+ } else {
+ result.w = xvimagesink->xpixmap[idx]->width;
+ result.h = xvimagesink->xpixmap[idx]->height;
+ }
break;
case DISP_GEO_METHOD_CROPPED_FULL_SCREEN:
}
break;
- case DISP_GEO_METHOD_CUSTOM_ROI:
-#ifdef GST_EXT_XV_ENHANCEMENT_ROI_MODE
+ case DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX:
+ if (src.w > dst.w || src.h > dst.h) {
+ /* LETTER BOX */
+ gst_video_sink_center_rect (src, dst, &result, TRUE);
+ result.x += xvimagesink->render_rect.x;
+ result.y += xvimagesink->render_rect.y;
+ } else {
+ /* ORIGIN SIZE */
+ gst_video_sink_center_rect (src, dst, &result, FALSE);
+ gst_video_sink_center_rect (dst, src, &src_input, FALSE);
+
+ if (xvimagesink->rotate_angle == DEGREE_90 ||
+ xvimagesink->rotate_angle == DEGREE_270) {
+ src_input.x = src_input.x ^ src_input.y;
+ src_input.y = src_input.x ^ src_input.y;
+ src_input.x = src_input.x ^ src_input.y;
+
+ src_input.w = src_input.w ^ src_input.h;
+ src_input.h = src_input.w ^ src_input.h;
+ src_input.w = src_input.w ^ src_input.h;
+ }
+ }
+ break;
+
+ case DISP_GEO_METHOD_CUSTOM_DST_ROI:
+ {
+ GstVideoRectangle dst_roi_cmpns;
+ dst_roi_cmpns.w = xvimagesink->dst_roi.w;
+ dst_roi_cmpns.h = xvimagesink->dst_roi.h;
+ dst_roi_cmpns.x = xvimagesink->dst_roi.x;
+ dst_roi_cmpns.y = xvimagesink->dst_roi.y;
+
+ /* setting for DST ROI mode */
+ switch (xvimagesink->dst_roi_mode) {
+ case ROI_DISP_GEO_METHOD_FULL_SCREEN:
+ break;
+ case ROI_DISP_GEO_METHOD_LETTER_BOX:
+ {
+ GstVideoRectangle roi_result;
+ if (xvimagesink->orientation == DEGREE_0 ||
+ xvimagesink->orientation == DEGREE_180) {
+ src.w = src_origin.w;
+ src.h = src_origin.h;
+ } else {
+ src.w = src_origin.h;
+ src.h = src_origin.w;
+ }
+ dst.w = xvimagesink->dst_roi.w;
+ dst.h = xvimagesink->dst_roi.h;
+
+ gst_video_sink_center_rect (src, dst, &roi_result, TRUE);
+ dst_roi_cmpns.w = roi_result.w;
+ dst_roi_cmpns.h = roi_result.h;
+ dst_roi_cmpns.x = xvimagesink->dst_roi.x + roi_result.x;
+ dst_roi_cmpns.y = xvimagesink->dst_roi.y + roi_result.y;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* calculating coordinates according to rotation angle for DST ROI */
switch (xvimagesink->rotate_angle) {
case DEGREE_90:
- result.w = xvimagesink->dst_roi.h;
- result.h = xvimagesink->dst_roi.w;
+ result.w = dst_roi_cmpns.h;
+ result.h = dst_roi_cmpns.w;
- result.x = xvimagesink->dst_roi.y;
- result.y = xvimagesink->xwindow->height - xvimagesink->dst_roi.x - xvimagesink->dst_roi.w;
+ result.x = dst_roi_cmpns.y;
+ if (!xvimagesink->get_pixmap_cb) {
+ result.y = xvimagesink->xwindow->height - dst_roi_cmpns.x - dst_roi_cmpns.w;
+ } else {
+ result.y = xvimagesink->xpixmap[idx]->height - dst_roi_cmpns.x - dst_roi_cmpns.w;
+ }
break;
case DEGREE_180:
- result.w = xvimagesink->dst_roi.w;
- result.h = xvimagesink->dst_roi.h;
+ result.w = dst_roi_cmpns.w;
+ result.h = dst_roi_cmpns.h;
- result.x = xvimagesink->xwindow->width - result.w - xvimagesink->dst_roi.x;
- result.y = xvimagesink->xwindow->height - result.h - xvimagesink->dst_roi.y;
+ if (!xvimagesink->get_pixmap_cb) {
+ result.x = xvimagesink->xwindow->width - result.w - dst_roi_cmpns.x;
+ result.y = xvimagesink->xwindow->height - result.h - dst_roi_cmpns.y;
+ } else {
+ result.x = xvimagesink->xpixmap[idx]->width - result.w - dst_roi_cmpns.x;
+ result.y = xvimagesink->xpixmap[idx]->height - result.h - dst_roi_cmpns.y;
+ }
break;
case DEGREE_270:
- result.w = xvimagesink->dst_roi.h;
- result.h = xvimagesink->dst_roi.w;
+ result.w = dst_roi_cmpns.h;
+ result.h = dst_roi_cmpns.w;
- result.x = xvimagesink->xwindow->width - xvimagesink->dst_roi.y - xvimagesink->dst_roi.h;
- result.y = xvimagesink->dst_roi.x;
+ if (!xvimagesink->get_pixmap_cb) {
+ result.x = xvimagesink->xwindow->width - dst_roi_cmpns.y - dst_roi_cmpns.h;
+ } else {
+ result.x = xvimagesink->xpixmap[idx]->width - dst_roi_cmpns.y - dst_roi_cmpns.h;
+ }
+ result.y = dst_roi_cmpns.x;
break;
default:
- result.x = xvimagesink->dst_roi.x;
- result.y = xvimagesink->dst_roi.y;
- result.w = xvimagesink->dst_roi.w;
- result.h = xvimagesink->dst_roi.h;
+ result.x = dst_roi_cmpns.x;
+ result.y = dst_roi_cmpns.y;
+ result.w = dst_roi_cmpns.w;
+ result.h = dst_roi_cmpns.h;
break;
}
- GST_LOG_OBJECT(xvimagesink, "rotate[%d], ROI input[%d,%d,%dx%d] > result[%d,%d,%dx%d]",
- xvimagesink->rotate_angle,
+ /* orientation setting for auto rotation in DST ROI */
+ if (xvimagesink->orientation) {
+ res_rotate_angle = (xvimagesink->rotate_angle - xvimagesink->orientation);
+ if (res_rotate_angle < 0) {
+ res_rotate_angle += DEGREE_NUM;
+ }
+ GST_LOG_OBJECT(xvimagesink, "changing rotation value internally by ROI orientation[%d] : rotate[%d->%d]",
+ xvimagesink->orientation, xvimagesink->rotate_angle, res_rotate_angle);
+ }
+
+ GST_LOG_OBJECT(xvimagesink, "rotate[%d], dst ROI: orientation[%d], mode[%d], input[%d,%d,%dx%d]->result[%d,%d,%dx%d]",
+ xvimagesink->rotate_angle, xvimagesink->orientation, xvimagesink->dst_roi_mode,
xvimagesink->dst_roi.x, xvimagesink->dst_roi.y, xvimagesink->dst_roi.w, xvimagesink->dst_roi.h,
result.x, result.y, result.w, result.h);
-#else /* GST_EXT_XV_ENHANCEMENT_ROI_MODE */
- result.x = xvimagesink->dst_roi.x;
- result.y = xvimagesink->dst_roi.y;
- result.w = xvimagesink->dst_roi.w;
- result.h = xvimagesink->dst_roi.h;
-
- if (xvimagesink->rotate_angle == DEGREE_90 ||
- xvimagesink->rotate_angle == DEGREE_270) {
- result.w = xvimagesink->dst_roi.h;
- result.h = xvimagesink->dst_roi.w;
- }
-#endif /* GST_EXT_XV_ENHANCEMENT_ROI_MODE */
break;
-
+ }
default:
break;
}
- if (xvimagesink->zoom > 1 && xvimagesink->zoom < 10) {
- src_input.x += (src_input.w-(src_input.w/xvimagesink->zoom))>>1;
- src_input.y += (src_input.h-(src_input.h/xvimagesink->zoom))>>1;
- src_input.w /= xvimagesink->zoom;
- src_input.h /= xvimagesink->zoom;
+ if (xvimagesink->zoom > 1.0 && xvimagesink->zoom <= 9.0) {
+ GST_LOG_OBJECT(xvimagesink, "before zoom[%lf], src_input[x:%d,y:%d,w:%d,h:%d]",
+ xvimagesink->zoom, src_input.x, src_input.y, src_input.w, src_input.h);
+ gint default_offset_x = 0;
+ gint default_offset_y = 0;
+ gfloat w = (gfloat)src_input.w;
+ gfloat h = (gfloat)src_input.h;
+ if (xvimagesink->orientation == DEGREE_0 ||
+ xvimagesink->orientation == DEGREE_180) {
+ default_offset_x = ((gint)(w - (w/xvimagesink->zoom)))>>1;
+ default_offset_y = ((gint)(h - (h/xvimagesink->zoom)))>>1;
+ } else {
+ default_offset_y = ((gint)(w - (w/xvimagesink->zoom)))>>1;
+ default_offset_x = ((gint)(h - (h/xvimagesink->zoom)))>>1;
+ }
+ GST_LOG_OBJECT(xvimagesink, "default offset x[%d] y[%d], orientation[%d]", default_offset_x, default_offset_y, xvimagesink->orientation);
+ if (xvimagesink->zoom_pos_x == -1) {
+ src_input.x += default_offset_x;
+ } else {
+ if (xvimagesink->orientation == DEGREE_0 ||
+ xvimagesink->orientation == DEGREE_180) {
+ if ((w/xvimagesink->zoom) > w - xvimagesink->zoom_pos_x) {
+ xvimagesink->zoom_pos_x = w - (w/xvimagesink->zoom);
+ }
+ src_input.x += xvimagesink->zoom_pos_x;
+ } else {
+ if ((h/xvimagesink->zoom) > h - xvimagesink->zoom_pos_x) {
+ xvimagesink->zoom_pos_x = h - (h/xvimagesink->zoom);
+ }
+ src_input.y += (h - h/xvimagesink->zoom) - xvimagesink->zoom_pos_x;
+ }
+ }
+ if (xvimagesink->zoom_pos_y == -1) {
+ src_input.y += default_offset_y;
+ } else {
+ if (xvimagesink->orientation == DEGREE_0 ||
+ xvimagesink->orientation == DEGREE_180) {
+ if ((h/xvimagesink->zoom) > h - xvimagesink->zoom_pos_y) {
+ xvimagesink->zoom_pos_y = h - (h/xvimagesink->zoom);
+ }
+ src_input.y += xvimagesink->zoom_pos_y;
+ } else {
+ if ((w/xvimagesink->zoom) > w - xvimagesink->zoom_pos_y) {
+ xvimagesink->zoom_pos_y = w - (w/xvimagesink->zoom);
+ }
+ src_input.x += (xvimagesink->zoom_pos_y);
+ }
+ }
+ src_input.w = (gint)(w/xvimagesink->zoom);
+ src_input.h = (gint)(h/xvimagesink->zoom);
+ GST_LOG_OBJECT(xvimagesink, "after zoom[%lf], src_input[x:%d,y:%d,w:%d,h%d], zoom_pos[x:%d,y:%d]",
+ xvimagesink->zoom, src_input.x, src_input.y, src_input.w, src_input.h, xvimagesink->zoom_pos_x, xvimagesink->zoom_pos_y);
}
+
#else /* GST_EXT_XV_ENHANCEMENT */
if (xvimagesink->keep_aspect) {
GstVideoRectangle src, dst;
g_mutex_lock (xvimagesink->x_lock);
+#ifdef GST_EXT_XV_ENHANCEMENT
+ if (draw_border && xvimagesink->draw_borders && !xvimagesink->get_pixmap_cb) {
+#else
if (draw_border && xvimagesink->draw_borders) {
+#endif /* GST_EXT_XV_ENHANCEMENT */
gst_xvimagesink_xwindow_draw_borders (xvimagesink, xvimagesink->xwindow,
result);
xvimagesink->redraw_border = FALSE;
xvimagesink->render_rect.w, xvimagesink->render_rect.h, xvimage);
#ifdef GST_EXT_XV_ENHANCEMENT
- switch( xvimagesink->rotate_angle )
+ switch( res_rotate_angle )
{
/* There's slightly weired code (CCW? CW?) */
case DEGREE_0:
break;
default:
GST_WARNING_OBJECT( xvimagesink, "Unsupported rotation [%d]... set DEGREE 0.",
- xvimagesink->rotate_angle );
+ res_rotate_angle );
break;
}
src_input.h += 1;
}
- GST_LOG_OBJECT( xvimagesink, "screen[%dx%d],window[%d,%d,%dx%d],method[%d],rotate[%d],zoom[%d],dp_mode[%d],src[%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]",
- xvimagesink->scr_w, xvimagesink->scr_h,
- xvimagesink->xwindow->x, xvimagesink->xwindow->y, xvimagesink->xwindow->width, xvimagesink->xwindow->height,
+ if (!xvimagesink->get_pixmap_cb) {
+ GST_LOG_OBJECT( xvimagesink, "screen[%dx%d],window[%d,%d,%dx%d],method[%d],rotate[%d],zoom[%f],dp_mode[%d],src[%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]",
+ xvimagesink->scr_w, xvimagesink->scr_h,
+ xvimagesink->xwindow->x, xvimagesink->xwindow->y, xvimagesink->xwindow->width, xvimagesink->xwindow->height,
+ xvimagesink->display_geometry_method, rotate, xvimagesink->zoom, xvimagesink->display_mode,
+ src_origin.w, src_origin.h,
+ dst.x, dst.y, dst.w, dst.h,
+ src_input.x, src_input.y, src_input.w, src_input.h,
+ result.x, result.y, result.w, result.h );
+ } else {
+ GST_LOG_OBJECT( xvimagesink, "pixmap[%d,%d,%dx%d],method[%d],rotate[%d],zoom[%f],dp_mode[%d],src[%dx%d],dst[%d,%d,%dx%d],input[%d,%d,%dx%d],result[%d,%d,%dx%d]",
+ xvimagesink->xpixmap[idx]->x, xvimagesink->xpixmap[idx]->y, xvimagesink->xpixmap[idx]->width, xvimagesink->xpixmap[idx]->height,
xvimagesink->display_geometry_method, rotate, xvimagesink->zoom, xvimagesink->display_mode,
src_origin.w, src_origin.h,
dst.x, dst.y, dst.w, dst.h,
src_input.x, src_input.y, src_input.w, src_input.h,
result.x, result.y, result.w, result.h );
+ }
+ /* skip request to render if dst rect is 0 */
+ if (xvimagesink->is_zero_copy_format && (!result.w || !result.h)) {
+ GST_WARNING_OBJECT(xvimagesink, "result.w[%d] or result.h[%d] is 0. Skip xvimage_put.", result.w, result.h);
+ g_mutex_unlock(xvimagesink->x_lock);
+ g_mutex_unlock(xvimagesink->flow_lock);
+ return TRUE;
+ }
+
+ static gboolean is_exist = FALSE;
+ gchar *attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_ROTATION");
+ is_exist = check_supportable_port_attr(xvimagesink, attr_name);
+ g_free(attr_name);
- if (atom_rotation == None) {
- atom_rotation = XInternAtom(xvimagesink->xcontext->disp,
+ if (is_exist) {
+ /* set display rotation */
+ if (atom_rotation == None) {
+ atom_rotation = XInternAtom(xvimagesink->xcontext->disp,
"_USER_WM_PORT_ATTRIBUTE_ROTATION", False);
+ }
+ ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
+ atom_rotation, rotate);
+ if (ret != Success) {
+ GST_ERROR_OBJECT( xvimagesink, "XvSetPortAttribute failed[%d]. disp[%x],xv_port_id[%d],atom[%x],rotate[%d]",
+ ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_rotation, rotate );
+
+ g_mutex_unlock(xvimagesink->x_lock);
+ g_mutex_unlock(xvimagesink->flow_lock);
+ return FALSE;
+ }
+ } else {
+ GST_WARNING("_USER_WM_PORT_ATTRIBUTE_ROTATION is not existed");
}
- ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_rotation, rotate);
- if (ret != Success) {
- GST_ERROR_OBJECT( xvimagesink, "XvSetPortAttribute failed[%d]. disp[%x],xv_port_id[%d],atom[%x],rotate[%d]",
- ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_rotation, rotate );
- return FALSE;
+ switch( xvimagesink->orientation )
+ {
+ case DEGREE_0:
+ orientation = 0;
+ break;
+ case DEGREE_90:
+ orientation = 90;
+ break;
+ case DEGREE_180:
+ orientation = 180;
+ break;
+ case DEGREE_270:
+ orientation = 270;
+ break;
+ default:
+ GST_WARNING_OBJECT( xvimagesink, "Unsupported orientation [%d]...",
+ xvimagesink->orientation );
+ break;
+ }
+
+ is_exist = FALSE;
+ attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_CONTENTS_ROTATION");
+ is_exist = check_supportable_port_attr(xvimagesink, attr_name);
+ g_free(attr_name);
+
+ if (is_exist) {
+ /* set contents rotation for connecting with external display */
+ if (atom_contents_rotation == None) {
+ atom_contents_rotation = XInternAtom(xvimagesink->xcontext->disp,
+ "_USER_WM_PORT_ATTRIBUTE_CONTENTS_ROTATION", False);
+ }
+ ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
+ atom_contents_rotation, orientation);
+ if (ret != Success) {
+ GST_ERROR_OBJECT( xvimagesink, "XvSetPortAttribute failed[%d]. disp[%x],xv_port_id[%d],atom[%x],orientation[%d]",
+ ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_contents_rotation, orientation );
+
+ g_mutex_unlock(xvimagesink->x_lock);
+ g_mutex_unlock(xvimagesink->flow_lock);
+ return FALSE;
+ }
+ }else {
+ GST_WARNING("_USER_WM_PORT_ATTRIBUTE_CONTENTS_ROTATION is not existed");
+ }
+
+ switch (xvimagesink->flip) {
+ case FLIP_HORIZONTAL:
+ set_hflip = TRUE;
+ set_vflip = FALSE;
+ break;
+ case FLIP_VERTICAL:
+ set_hflip = FALSE;
+ set_vflip = TRUE;
+ break;
+ case FLIP_BOTH:
+ set_hflip = TRUE;
+ set_vflip = TRUE;
+ break;
+ case FLIP_NONE:
+ default:
+ set_hflip = FALSE;
+ set_vflip = FALSE;
+ break;
+ }
+
+ GST_LOG("set HFLIP %d, VFLIP %d", set_hflip, set_vflip);
+
+ is_exist = FALSE;
+ attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_HFLIP");
+ is_exist = check_supportable_port_attr(xvimagesink, attr_name);
+ g_free(attr_name);
+
+ if (is_exist) {
+ if (atom_hflip == None) {
+ /* set display flip */
+ atom_hflip = XInternAtom(xvimagesink->xcontext->disp,
+ "_USER_WM_PORT_ATTRIBUTE_HFLIP", False);
+ }
+ ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_hflip, set_hflip);
+ if (ret != Success) {
+ GST_WARNING("set HFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],hflip[%d]",
+ ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_hflip, set_hflip);
+ }
+ }
+
+ is_exist = FALSE;
+ attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_VFLIP");
+ is_exist = check_supportable_port_attr(xvimagesink, attr_name);
+ g_free(attr_name);
+
+ if (is_exist) {
+ if (atom_vflip == None) {
+ /* set display flip */
+ atom_vflip = XInternAtom(xvimagesink->xcontext->disp,
+ "_USER_WM_PORT_ATTRIBUTE_VFLIP", False);
+ }
+ ret = XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_vflip, set_vflip);
+ if (ret != Success) {
+ GST_WARNING("set VFLIP failed[%d]. disp[%x],xv_port_id[%d],atom[%x],vflip[%d]",
+ ret, xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_vflip, set_vflip);
+ }
}
+ /* set error handler */
+ error_caught = FALSE;
+ handler = XSetErrorHandler(gst_xvimagesink_handle_xerror);
+
/* src input indicates the status when degree is 0 */
/* dst input indicates the area that src will be shown regardless of rotate */
-
- if (xvimagesink->visible && !xvimagesink->is_hided) {
+ if (xvimagesink->visible &&
+ ((!xvimagesink->is_hided) || (xvimagesink->is_hided && (GST_STATE(xvimagesink) == GST_STATE_PLAYING)))) {
if (xvimagesink->xim_transparenter) {
GST_LOG_OBJECT( xvimagesink, "Transparent related issue." );
XPutImage(xvimagesink->xcontext->disp,
result.x, result.y, result.w, result.h);
}
- ret = XvShmPutImage (xvimagesink->xcontext->disp,
- xvimagesink->xcontext->xv_port_id,
- xvimagesink->xwindow->win,
- xvimagesink->xwindow->gc, xvimage->xvimage,
- src_input.x, src_input.y, src_input.w, src_input.h,
- result.x, result.y, result.w, result.h, FALSE);
- GST_LOG_OBJECT( xvimagesink, "XvShmPutImage return value [%d]", ret );
+ /* store buffer */
+ if (xvimagesink->is_zero_copy_format && xvimage->xvimage->data) {
+ img_data = (XV_DATA_PTR)xvimage->xvimage->data;
+ if (img_data->BufType == XV_BUF_TYPE_DMABUF) {
+ _add_displaying_buffer(xvimagesink, img_data, xvimage->current_buffer);
+ xvimage->current_buffer = NULL;
+ }
+ }
+
+ g_mutex_lock(xvimagesink->display_buffer_lock);
+ if (xvimagesink->displaying_buffer_count > 3) {
+ GST_WARNING("too many buffers are not released. [displaying_buffer_count %d]", xvimagesink->displaying_buffer_count);
+ }
+ g_mutex_unlock(xvimagesink->display_buffer_lock);
+
+ if (xvimagesink->get_pixmap_cb) {
+ gint idx = xvimagesink->current_pixmap_idx;
+ ret = XvShmPutImage (xvimagesink->xcontext->disp,
+ xvimagesink->xcontext->xv_port_id,
+ xvimagesink->xpixmap[idx]->pixmap,
+ xvimagesink->xpixmap[idx]->gc, xvimage->xvimage,
+ src_input.x, src_input.y, src_input.w, src_input.h,
+ result.x, result.y, result.w, result.h, FALSE);
+ GST_LOG_OBJECT( xvimagesink, "XvShmPutImage return value [%d], disp[0x%x], gc[0x%x], pixmap id[%d], idx[%d]", ret, xvimagesink->xcontext->disp, xvimagesink->xpixmap[idx]->gc, xvimagesink->xpixmap[idx]->pixmap, idx);
+ } else {
+ ret = XvShmPutImage (xvimagesink->xcontext->disp,
+ xvimagesink->xcontext->xv_port_id,
+ xvimagesink->xwindow->win,
+ xvimagesink->xwindow->gc, xvimage->xvimage,
+ src_input.x, src_input.y, src_input.w, src_input.h,
+ result.x, result.y, result.w, result.h, FALSE);
+ GST_LOG_OBJECT( xvimagesink, "XvShmPutImage return value [%d], disp[0x%x], gc[0x%x], xid[%d]", ret, xvimagesink->xcontext->disp, xvimagesink->xwindow->gc, xvimagesink->xwindow->win);
+ }
} else {
GST_LOG_OBJECT( xvimagesink, "visible is FALSE. skip this image..." );
}
XSync (xvimagesink->xcontext->disp, FALSE);
+#ifdef HAVE_XSHM
+#ifdef GST_EXT_XV_ENHANCEMENT
+ if (ret || error_caught || xvimagesink->get_pixmap_cb) {
+ GST_DEBUG("error or pixmap_cb");
+
+ if (ret || error_caught) {
+ GST_WARNING("putimage error : ret %d, error_caught %d, pixmap cb %p, displaying buffer count %d",
+ ret, error_caught, xvimagesink->get_pixmap_cb, xvimagesink->displaying_buffer_count);
+
+ if (xvimagesink->get_pixmap_cb) {
+ g_signal_emit (G_OBJECT (xvimagesink),
+ gst_xvimagesink_signals[SIGNAL_FRAME_RENDER_ERROR],
+ 0,
+ &xvimagesink->xpixmap[idx]->pixmap,
+ &res);
+ }
+ }
+
+ /* release gem handle */
+ if (img_data && img_data->BufType == XV_BUF_TYPE_DMABUF) {
+ unsigned int gem_name[XV_BUF_PLANE_NUM] = { 0, };
+ gem_name[0] = img_data->YBuf;
+ gem_name[1] = img_data->CbBuf;
+ gem_name[2] = img_data->CrBuf;
+ _remove_displaying_buffer(xvimagesink, gem_name);
+ }
+ }
+
+ /* Reset error handler */
+ if (handler) {
+ error_caught = FALSE;
+ XSetErrorHandler (handler);
+ }
+#endif /* GST_EXT_XV_ENHANCEMENT */
+#endif /* HAVE_XSHM */
+
g_mutex_unlock (xvimagesink->x_lock);
g_mutex_unlock (xvimagesink->flow_lock);
#ifdef GST_EXT_XV_ENHANCEMENT
static XImage *make_transparent_image(Display *d, Window win, int w, int h)
{
- XImage *xim;
+ XImage *xim;
/* create a normal ximage */
xim = XCreateImage(d, DefaultVisualOfScreen(DefaultScreenOfDisplay(d)), 24, ZPixmap, 0, NULL, w, h, 32, 0);
+ GST_INFO("ximage %p", xim);
+
/* allocate data for it */
if (xim) {
xim->data = (char *)malloc(xim->bytes_per_line * xim->height);
- }
-
- memset(xim->data, 0x00, xim->bytes_per_line * xim->height);
- if (!xim || !xim->data) {
- /* failed to create XImage or allocate data memory */
- if (xim) {
- XDestroyImage(xim);
+ if (xim->data) {
+ memset(xim->data, 0x00, xim->bytes_per_line * xim->height);
+ return xim;
+ } else {
+ GST_ERROR("failed to alloc data - size %d", xim->bytes_per_line * xim->height);
}
- return NULL;
+ XDestroyImage(xim);
}
- return xim;
+ GST_ERROR("failed to create Ximage");
+
+ return NULL;
}
int count = 0;
XvAttribute *const attr = XvQueryPortAttributes(xcontext->disp,
xcontext->xv_port_id, &count);
- is_exist = FALSE;
- current_port_id = xcontext->xv_port_id;
- for (i = 0 ; i < count ; i++) {
- if (!strcmp(attr[i].name, "_USER_WM_PORT_ATTRIBUTE_OUTPUT")) {
- is_exist = TRUE;
- GST_INFO("_USER_WM_PORT_ATTRIBUTE_OUTPUT[index %d] found", i);
- break;
+ if (attr) {
+ current_port_id = xcontext->xv_port_id;
+ for (i = 0 ; i < count ; i++) {
+ if (!strcmp(attr[i].name, "_USER_WM_PORT_ATTRIBUTE_OUTPUT")) {
+ is_exist = TRUE;
+ GST_INFO("_USER_WM_PORT_ATTRIBUTE_OUTPUT[index %d] found", i);
+ break;
+ }
}
+ XFree(attr);
+ } else {
+ GST_WARNING("XvQueryPortAttributes disp:%d, port_id:%d failed",
+ xcontext->disp, xcontext->xv_port_id);
}
}
if (is_exist) {
- GST_INFO("set display mode %d", set_mode);
+ GST_DEBUG("set display mode %d", set_mode);
atom_output = XInternAtom(xcontext->disp,
"_USER_WM_PORT_ATTRIBUTE_OUTPUT", False);
ret = XvSetPortAttribute(xcontext->disp, xcontext->xv_port_id,
return FALSE;
}
+
+
+static gboolean set_csc_range(GstXContext *xcontext, int set_range)
+{
+ int ret = 0;
+ static gboolean is_exist = FALSE;
+ static XvPortID current_port_id = -1;
+ Atom atom_csc_range = None;
+
+ if (xcontext == NULL) {
+ GST_WARNING("xcontext is NULL");
+ return FALSE;
+ }
+
+ /* check once per one xv_port_id */
+ if (current_port_id != xcontext->xv_port_id) {
+ /* check whether _USER_WM_PORT_ATTRIBUTE_OUTPUT attribute is existed */
+ int i = 0;
+ int count = 0;
+ XvAttribute *const attr = XvQueryPortAttributes(xcontext->disp,
+ xcontext->xv_port_id, &count);
+ if (attr) {
+ current_port_id = xcontext->xv_port_id;
+ for (i = 0 ; i < count ; i++) {
+ if (!strcmp(attr[i].name, "_USER_WM_PORT_ATTRIBUTE_CSC_RANGE")) {
+ is_exist = TRUE;
+ GST_INFO("_USER_WM_PORT_ATTRIBUTE_OUTPUT[index %d] found", i);
+ break;
+ }
+ }
+ XFree(attr);
+ } else {
+ GST_WARNING("XvQueryPortAttributes disp:%d, port_id:%d failed",
+ xcontext->disp, xcontext->xv_port_id);
+ }
+ }
+
+ if (is_exist) {
+ GST_WARNING("set csc range %d", set_range);
+ atom_csc_range = XInternAtom(xcontext->disp,
+ "_USER_WM_PORT_ATTRIBUTE_CSC_RANGE", False);
+ ret = XvSetPortAttribute(xcontext->disp, xcontext->xv_port_id,
+ atom_csc_range, set_range);
+ if (ret == Success) {
+ return TRUE;
+ } else {
+ GST_WARNING("csc range[%d] set failed.", set_range);
+ }
+ } else {
+ GST_WARNING("_USER_WM_PORT_ATTRIBUTE_CSC_RANGE is not existed");
+ }
+
+ return FALSE;
+}
+
+
+static void drm_init(GstXvImageSink *xvimagesink)
+{
+ Display *dpy;
+ int eventBase = 0;
+ int errorBase = 0;
+ int dri2Major = 0;
+ int dri2Minor = 0;
+ char *driverName = NULL;
+ char *deviceName = NULL;
+ struct drm_auth auth_arg = {0};
+
+ xvimagesink->drm_fd = -1;
+
+ dpy = XOpenDisplay(0);
+ if (!dpy) {
+ GST_ERROR("XOpenDisplay failed errno:%d", errno);
+ return;
+ }
+
+ GST_INFO("START");
+
+ /* DRI2 */
+ if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) {
+ GST_ERROR("DRI2QueryExtension !!");
+ goto DRM_INIT_ERROR;
+ }
+
+ if (!DRI2QueryVersion(dpy, &dri2Major, &dri2Minor)) {
+ GST_ERROR("DRI2QueryVersion !!");
+ goto DRM_INIT_ERROR;
+ }
+
+ if (!DRI2Connect(dpy, RootWindow(dpy, DefaultScreen(dpy)), &driverName, &deviceName)) {
+ GST_ERROR("DRI2Connect !!");
+ goto DRM_INIT_ERROR;
+ }
+
+ if (!driverName || !deviceName) {
+ GST_ERROR("driverName or deviceName is not valid");
+ goto DRM_INIT_ERROR;
+ }
+
+ GST_INFO("Open drm device : %s", deviceName);
+
+ /* get the drm_fd though opening the deviceName */
+ xvimagesink->drm_fd = open(deviceName, O_RDWR);
+ if (xvimagesink->drm_fd < 0) {
+ GST_ERROR("cannot open drm device (%s)", deviceName);
+ goto DRM_INIT_ERROR;
+ }
+
+ /* get magic from drm to authentication */
+ if (ioctl(xvimagesink->drm_fd, DRM_IOCTL_GET_MAGIC, &auth_arg)) {
+ GST_ERROR("cannot get drm auth magic [drm fd %d]", xvimagesink->drm_fd);
+ goto DRM_INIT_ERROR;
+ }
+
+ if (!DRI2Authenticate(dpy, RootWindow(dpy, DefaultScreen(dpy)), auth_arg.magic)) {
+ GST_ERROR("cannot get drm authentication from X");
+ goto DRM_INIT_ERROR;
+ }
+
+ XCloseDisplay(dpy);
+ free(driverName);
+ free(deviceName);
+
+ xvimagesink->bufmgr = tbm_bufmgr_init(xvimagesink->drm_fd);
+ if (xvimagesink->bufmgr == NULL) {
+ GST_ERROR_OBJECT(xvimagesink, "tbm_bufmgr_init failed");
+ goto DRM_INIT_ERROR;
+ }
+
+ GST_INFO("DONE");
+
+ return;
+
+DRM_INIT_ERROR:
+ if (xvimagesink->drm_fd >= 0) {
+ close(xvimagesink->drm_fd);
+ xvimagesink->drm_fd = -1;
+ }
+ if (dpy) {
+ XCloseDisplay(dpy);
+ }
+ if (driverName) {
+ free(driverName);
+ }
+ if (deviceName) {
+ free(deviceName);
+ }
+
+ return;
+}
+
+static void drm_fini(GstXvImageSink *xvimagesink)
+{
+ GST_WARNING_OBJECT(xvimagesink, "START");
+
+ if (xvimagesink->drm_fd >= 0) {
+ int i = 0;
+ int j = 0;
+
+ /* close remained gem handle */
+ g_mutex_lock(xvimagesink->display_buffer_lock);
+ for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
+ if (xvimagesink->displaying_buffers[i].gem_name[0] > 0) {
+ GST_WARNING_OBJECT(xvimagesink, "remained buffer %p, name %u %u %u, handle %u %u %u",
+ xvimagesink->displaying_buffers[i].buffer,
+ xvimagesink->displaying_buffers[i].gem_name[0],
+ xvimagesink->displaying_buffers[i].gem_name[1],
+ xvimagesink->displaying_buffers[i].gem_name[2],
+ xvimagesink->displaying_buffers[i].gem_handle[0],
+ xvimagesink->displaying_buffers[i].gem_handle[1],
+ xvimagesink->displaying_buffers[i].gem_handle[2]);
+
+ /* release flush buffer */
+ if (xvimagesink->flush_buffer) {
+ if (xvimagesink->flush_buffer->gem_name[0] == xvimagesink->displaying_buffers[i].gem_name[0] &&
+ xvimagesink->flush_buffer->gem_name[1] == xvimagesink->displaying_buffers[i].gem_name[1] &&
+ xvimagesink->flush_buffer->gem_name[2] == xvimagesink->displaying_buffers[i].gem_name[2]) {
+ _release_flush_buffer(xvimagesink);
+ }
+ } else {
+ GST_WARNING_OBJECT(xvimagesink, "Force Unref buffer");
+ }
+
+ for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
+ if (xvimagesink->displaying_buffers[i].gem_handle[j] > 0) {
+ drm_close_gem(xvimagesink, &(xvimagesink->displaying_buffers[i].gem_handle[j]));
+ }
+ xvimagesink->displaying_buffers[i].gem_name[j] = 0;
+ xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0;
+ xvimagesink->displaying_buffers[i].bo[j] = NULL;
+ }
+
+ if (xvimagesink->displaying_buffers[i].buffer) {
+ gst_buffer_unref(xvimagesink->displaying_buffers[i].buffer);
+ xvimagesink->displaying_buffers[i].buffer = NULL;
+ }
+ }
+ }
+ g_mutex_unlock(xvimagesink->display_buffer_lock);
+
+ GST_WARNING_OBJECT(xvimagesink, "destroy tbm buffer manager");
+ tbm_bufmgr_deinit(xvimagesink->bufmgr);
+ xvimagesink->bufmgr = NULL;
+
+ GST_WARNING_OBJECT(xvimagesink, "close drm_fd %d", xvimagesink->drm_fd);
+ close(xvimagesink->drm_fd);
+ xvimagesink->drm_fd = -1;
+ } else {
+ GST_WARNING_OBJECT(xvimagesink, "DRM device is NOT opened");
+ }
+
+ GST_WARNING_OBJECT(xvimagesink, "DONE");
+}
+
+static unsigned int drm_convert_dmabuf_gemname(GstXvImageSink *xvimagesink, unsigned int dmabuf_fd, unsigned int *gem_handle)
+{
+ int ret = 0;
+
+ struct drm_prime_handle prime_arg = {0,};
+ struct drm_gem_flink flink_arg = {0,};
+
+ if (!xvimagesink || !gem_handle) {
+ GST_ERROR("handle[%p,%p] is NULL", xvimagesink, gem_handle);
+ return 0;
+ }
+
+ if (xvimagesink->drm_fd < 0) {
+ GST_ERROR("DRM is not opened");
+ return 0;
+ }
+
+ if (dmabuf_fd <= 0) {
+ GST_LOG("Ignore wrong dmabuf fd [%u]", dmabuf_fd);
+ return 0;
+ }
+
+ prime_arg.fd = dmabuf_fd;
+ ret = ioctl(xvimagesink->drm_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &prime_arg);
+ if (ret) {
+ GST_ERROR("DRM_IOCTL_PRIME_FD_TO_HANDLE failed. ret %d, dmabuf fd : %u [drm fd %d]",
+ ret, dmabuf_fd, xvimagesink->drm_fd);
+ return 0;
+ }
+
+ *gem_handle = prime_arg.handle;
+ flink_arg.handle = prime_arg.handle;
+ ret = ioctl(xvimagesink->drm_fd, DRM_IOCTL_GEM_FLINK, &flink_arg);
+ if (ret) {
+ GST_ERROR("DRM_IOCTL_GEM_FLINK failed. ret %d, gem_handle %u, gem_name %u [drm fd %d]",
+ ret, *gem_handle, flink_arg.name, xvimagesink->drm_fd);
+ return 0;
+ }
+
+ return flink_arg.name;
+}
+
+static void drm_close_gem(GstXvImageSink *xvimagesink, unsigned int *gem_handle)
+{
+ struct drm_gem_close close_arg = {0,};
+
+ if (xvimagesink->drm_fd < 0 || !gem_handle) {
+ GST_ERROR("DRM is not opened");
+ return;
+ }
+
+ if (*gem_handle <= 0) {
+ GST_DEBUG("invalid gem handle %u", *gem_handle);
+ return;
+ }
+
+ GST_LOG("Call DRM_IOCTL_GEM_CLOSE - handle %u", *gem_handle);
+
+ close_arg.handle = *gem_handle;
+ if (ioctl(xvimagesink->drm_fd, DRM_IOCTL_GEM_CLOSE, &close_arg)) {
+ GST_ERROR("cannot close drm gem handle %u [drm fd %d]", *gem_handle, xvimagesink->drm_fd);
+ return;
+ }
+
+ *gem_handle = 0;
+
+ return;
+}
+
+
+static void _remove_last_buffer(GstXvImageSink *xvimagesink)
+{
+ gboolean enable_last_buffer = FALSE;
+
+ if (xvimagesink == NULL) {
+ GST_ERROR("handle is NULL");
+ return;
+ }
+
+ /* get enable-last-buffer */
+ g_object_get(G_OBJECT(xvimagesink), "enable-last-buffer", &enable_last_buffer, NULL);
+
+ GST_WARNING_OBJECT(xvimagesink, "current enable-last-buffer : %d", enable_last_buffer);
+
+ /* flush if enable-last-buffer is TRUE */
+ if (enable_last_buffer) {
+ g_object_set(G_OBJECT(xvimagesink), "enable-last-buffer", FALSE, NULL);
+ g_object_set(G_OBJECT(xvimagesink), "enable-last-buffer", TRUE, NULL);
+ }
+
+ return;
+}
+
+
+static void _release_flush_buffer(GstXvImageSink *xvimagesink)
+{
+ int i = 0;
+
+ if (xvimagesink == NULL ||
+ xvimagesink->flush_buffer == NULL) {
+ GST_WARNING("handle is NULL");
+ return;
+ }
+
+ GST_WARNING_OBJECT(xvimagesink, "release FLUSH BUFFER");
+
+ for (i = 0 ; i < XV_BUF_PLANE_NUM ; i++) {
+ if (xvimagesink->flush_buffer->bo[i]) {
+ tbm_bo_unref(xvimagesink->flush_buffer->bo[i]);
+ xvimagesink->flush_buffer->bo[i] = NULL;
+ }
+ }
+
+ GST_WARNING_OBJECT(xvimagesink, "release FLUSH BUFFER done");
+
+ free(xvimagesink->flush_buffer);
+ xvimagesink->flush_buffer = NULL;
+
+ return;
+}
+
+
+static void _add_displaying_buffer(GstXvImageSink *xvimagesink, XV_DATA_PTR img_data, GstBuffer *buffer)
+{
+ int i = 0;
+ int j = 0;
+
+ if (!xvimagesink || !img_data) {
+ GST_ERROR("handle is NULL %p, %p", xvimagesink, img_data);
+ return;
+ }
+
+ /* lock display buffer mutex */
+ g_mutex_lock(xvimagesink->display_buffer_lock);
+
+ /* increase displaying buffer count */
+ xvimagesink->displaying_buffer_count++;
+
+ /* check duplicated */
+ for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
+ if (xvimagesink->displaying_buffers[i].gem_name[0] > 0) {
+ if ((img_data->dmabuf_fd[0] > 0 &&
+ xvimagesink->displaying_buffers[i].dmabuf_fd[0] == img_data->dmabuf_fd[0] &&
+ xvimagesink->displaying_buffers[i].dmabuf_fd[1] == img_data->dmabuf_fd[1] &&
+ xvimagesink->displaying_buffers[i].dmabuf_fd[2] == img_data->dmabuf_fd[2]) ||
+ (img_data->bo[0] &&
+ xvimagesink->displaying_buffers[i].bo[0] == img_data->bo[0] &&
+ xvimagesink->displaying_buffers[i].bo[1] == img_data->bo[1] &&
+ xvimagesink->displaying_buffers[i].bo[2] == img_data->bo[2])) {
+ /* increase ref count */
+ xvimagesink->displaying_buffers[i].ref_count++;
+
+ /* set buffer info */
+ img_data->YBuf = xvimagesink->displaying_buffers[i].gem_name[0];
+ img_data->CbBuf = xvimagesink->displaying_buffers[i].gem_name[1];
+ img_data->CrBuf = xvimagesink->displaying_buffers[i].gem_name[2];
+
+ if (img_data->dmabuf_fd[0] > 0) {
+ GST_WARNING("already converted fd [%u %u %u] name [%u %u %u]",
+ img_data->dmabuf_fd[0], img_data->dmabuf_fd[1], img_data->dmabuf_fd[2],
+ img_data->YBuf, img_data->CbBuf, img_data->CrBuf);
+ } else {
+ GST_WARNING("already exported bo [%p %p %p] gem name [%u %u %u]",
+ img_data->bo[0], img_data->bo[1], img_data->bo[2],
+ img_data->YBuf, img_data->CbBuf, img_data->CrBuf);
+ }
+
+ /* unlock display buffer mutex */
+ g_mutex_unlock(xvimagesink->display_buffer_lock);
+ return;
+ }
+ }
+ }
+
+ /* store buffer temporarily */
+ for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
+ if (xvimagesink->displaying_buffers[i].gem_name[0] == 0) {
+ if (buffer) {
+ /* increase ref count of buffer */
+ gst_buffer_ref(buffer);
+ xvimagesink->displaying_buffers[i].buffer = buffer;
+ }
+
+ if (img_data->dmabuf_fd[0] > 0) {
+ /* convert fd to name */
+ img_data->YBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[0], &img_data->gem_handle[0]);
+ img_data->CbBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[1], &img_data->gem_handle[1]);
+ img_data->CrBuf = drm_convert_dmabuf_gemname(xvimagesink, img_data->dmabuf_fd[2], &img_data->gem_handle[2]);
+ } else {
+ /* export bo */
+ if (img_data->bo[0]) {
+ img_data->YBuf = tbm_bo_export(img_data->bo[0]);
+ }
+ if (img_data->bo[1]) {
+ img_data->CbBuf = tbm_bo_export(img_data->bo[1]);
+ }
+ if (img_data->bo[2]) {
+ img_data->CrBuf = tbm_bo_export(img_data->bo[2]);
+ }
+ }
+
+ for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
+ xvimagesink->displaying_buffers[i].dmabuf_fd[j] = img_data->dmabuf_fd[j];
+ xvimagesink->displaying_buffers[i].gem_handle[j] = img_data->gem_handle[j];
+ xvimagesink->displaying_buffers[i].bo[j] = img_data->bo[j];
+ }
+
+ /* set buffer info */
+ xvimagesink->displaying_buffers[i].gem_name[0] = img_data->YBuf;
+ xvimagesink->displaying_buffers[i].gem_name[1] = img_data->CbBuf;
+ xvimagesink->displaying_buffers[i].gem_name[2] = img_data->CrBuf;
+
+ /* set ref count */
+ xvimagesink->displaying_buffers[i].ref_count = 1;
+
+ if (xvimagesink->displayed_buffer_count < _CHECK_DISPLAYED_BUFFER_COUNT) {
+ GST_WARNING_OBJECT(xvimagesink, "cnt %d - add idx %d, buf %p, fd [%u %u %u], handle [%u %u %u], name [%u %u %u]",
+ xvimagesink->displayed_buffer_count,
+ i, xvimagesink->displaying_buffers[i].buffer,
+ xvimagesink->displaying_buffers[i].dmabuf_fd[0],
+ xvimagesink->displaying_buffers[i].dmabuf_fd[1],
+ xvimagesink->displaying_buffers[i].dmabuf_fd[2],
+ xvimagesink->displaying_buffers[i].gem_handle[0],
+ xvimagesink->displaying_buffers[i].gem_handle[1],
+ xvimagesink->displaying_buffers[i].gem_handle[2],
+ xvimagesink->displaying_buffers[i].gem_name[0],
+ xvimagesink->displaying_buffers[i].gem_name[1],
+ xvimagesink->displaying_buffers[i].gem_name[2]);
+ } else {
+ GST_DEBUG_OBJECT(xvimagesink, "add idx %d, buf %p, fd [%u %u %u], handle [%u %u %u], name [%u %u %u]",
+ i, xvimagesink->displaying_buffers[i].buffer,
+ xvimagesink->displaying_buffers[i].dmabuf_fd[0],
+ xvimagesink->displaying_buffers[i].dmabuf_fd[1],
+ xvimagesink->displaying_buffers[i].dmabuf_fd[2],
+ xvimagesink->displaying_buffers[i].gem_handle[0],
+ xvimagesink->displaying_buffers[i].gem_handle[1],
+ xvimagesink->displaying_buffers[i].gem_handle[2],
+ xvimagesink->displaying_buffers[i].gem_name[0],
+ xvimagesink->displaying_buffers[i].gem_name[1],
+ xvimagesink->displaying_buffers[i].gem_name[2]);
+ }
+
+ /* set last added buffer index */
+ xvimagesink->last_added_buffer_index = i;
+ GST_LOG_OBJECT(xvimagesink, "xvimagesink->last_added_buffer_index %d", i);
+
+ /* unlock display buffer mutex */
+ g_mutex_unlock(xvimagesink->display_buffer_lock);
+
+ /* get current time */
+ gettimeofday(&xvimagesink->request_time[i], NULL);
+ return;
+ }
+ }
+
+ /* decrease displaying buffer count */
+ xvimagesink->displaying_buffer_count--;
+
+ /* unlock display buffer mutex */
+ g_mutex_unlock(xvimagesink->display_buffer_lock);
+
+ GST_ERROR("should not be reached here. buffer slot is FULL...");
+
+ return;
+}
+
+
+static void _remove_displaying_buffer(GstXvImageSink *xvimagesink, unsigned int *gem_name)
+{
+ int i = 0;
+ int j = 0;
+
+ if (!xvimagesink || !gem_name) {
+ GST_ERROR_OBJECT(xvimagesink, "handle is NULL %p, %p", xvimagesink, gem_name);
+ return;
+ }
+
+ /* lock display buffer mutex */
+ g_mutex_lock(xvimagesink->display_buffer_lock);
+
+ if (xvimagesink->displaying_buffer_count == 0) {
+ GST_WARNING_OBJECT(xvimagesink, "there is no displaying buffer");
+ /* unlock display buffer mutex */
+ g_mutex_unlock(xvimagesink->display_buffer_lock);
+ return;
+ }
+
+ GST_DEBUG_OBJECT(xvimagesink, "gem name [%u %u %u], displaying buffer count %d",
+ gem_name[0], gem_name[1], gem_name[2],
+ xvimagesink->displaying_buffer_count);
+
+ for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
+ if (xvimagesink->displaying_buffers[i].gem_name[0] == gem_name[0] &&
+ xvimagesink->displaying_buffers[i].gem_name[1] == gem_name[1] &&
+ xvimagesink->displaying_buffers[i].gem_name[2] == gem_name[2]) {
+ struct timeval current_time;
+
+ /* get current time to calculate displaying time */
+ gettimeofday(¤t_time, NULL);
+
+ GST_DEBUG_OBJECT(xvimagesink, "buffer return time %8d us",
+ (current_time.tv_sec - xvimagesink->request_time[i].tv_sec)*1000000 + \
+ (current_time.tv_usec - xvimagesink->request_time[i].tv_usec));
+
+ if (xvimagesink->displayed_buffer_count < _CHECK_DISPLAYED_BUFFER_COUNT) {
+ xvimagesink->displayed_buffer_count++;
+ GST_WARNING_OBJECT(xvimagesink, "cnt %d - remove idx %d, buf %p, handle [%u %u %u], name [%u %u %u]",
+ xvimagesink->displayed_buffer_count,
+ i, xvimagesink->displaying_buffers[i].buffer,
+ xvimagesink->displaying_buffers[i].gem_handle[0],
+ xvimagesink->displaying_buffers[i].gem_handle[1],
+ xvimagesink->displaying_buffers[i].gem_handle[2],
+ xvimagesink->displaying_buffers[i].gem_name[0],
+ xvimagesink->displaying_buffers[i].gem_name[1],
+ xvimagesink->displaying_buffers[i].gem_name[2]);
+ } else {
+ GST_DEBUG_OBJECT(xvimagesink, "remove idx %d, buf %p, handle [%u %u %u], name [%u %u %u]",
+ i, xvimagesink->displaying_buffers[i].buffer,
+ xvimagesink->displaying_buffers[i].gem_handle[0],
+ xvimagesink->displaying_buffers[i].gem_handle[1],
+ xvimagesink->displaying_buffers[i].gem_handle[2],
+ xvimagesink->displaying_buffers[i].gem_name[0],
+ xvimagesink->displaying_buffers[i].gem_name[1],
+ xvimagesink->displaying_buffers[i].gem_name[2]);
+ }
+
+ /* decrease displaying buffer count */
+ xvimagesink->displaying_buffer_count--;
+
+ /* decrease ref count */
+ xvimagesink->displaying_buffers[i].ref_count--;
+
+ if (xvimagesink->displaying_buffers[i].ref_count > 0) {
+ GST_WARNING("ref count not zero[%d], skip close gem handle",
+ xvimagesink->displaying_buffers[i].ref_count);
+ break;
+ }
+
+ /* release flush buffer */
+ if (xvimagesink->flush_buffer) {
+ if (xvimagesink->flush_buffer->gem_name[0] == gem_name[0] &&
+ xvimagesink->flush_buffer->gem_name[1] == gem_name[1] &&
+ xvimagesink->flush_buffer->gem_name[2] == gem_name[2]) {
+ _release_flush_buffer(xvimagesink);
+ }
+ }
+
+ for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
+ if (xvimagesink->displaying_buffers[i].gem_handle[j] > 0) {
+ drm_close_gem(xvimagesink, &(xvimagesink->displaying_buffers[i].gem_handle[j]));
+ }
+ xvimagesink->displaying_buffers[i].gem_name[j] = 0;
+ xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0;
+ xvimagesink->displaying_buffers[i].bo[j] = NULL;
+ }
+
+ /* reset last_added_buffer_index */
+ if (xvimagesink->displaying_buffer_count < 1) {
+ xvimagesink->last_added_buffer_index = -1;
+ GST_DEBUG_OBJECT(xvimagesink, "displaying_buffer_count %d",
+ xvimagesink->displaying_buffer_count);
+ }
+
+ if (xvimagesink->displaying_buffers[i].buffer) {
+ gst_buffer_unref(xvimagesink->displaying_buffers[i].buffer);
+ xvimagesink->displaying_buffers[i].buffer = NULL;
+ } else {
+ GST_WARNING("no buffer to unref");
+ }
+ break;
+ }
+ }
+
+ /* unlock display buffer mutex */
+ g_mutex_unlock(xvimagesink->display_buffer_lock);
+
+ return;
+}
+
+
+static int _is_connected_to_external_display(GstXvImageSink *xvimagesink)
+{
+ Atom type_ret = 0;
+ int i = 0;
+ int ret = 0;
+ int size_ret = 0;
+ unsigned long num_ret = 0;
+ unsigned long bytes = 0;
+ unsigned char *prop_ret = NULL;
+ unsigned int data = 0;
+ int (*handler) (Display *, XErrorEvent *) = NULL;
+ Atom atom_output_external;
+
+ atom_output_external = XInternAtom(xvimagesink->xcontext->disp,
+ "XV_OUTPUT_EXTERNAL", False);
+ if (atom_output_external != None) {
+ /* set error handler */
+ error_caught = FALSE;
+ handler = XSetErrorHandler(gst_xvimagesink_handle_xerror);
+
+ ret = XGetWindowProperty(xvimagesink->xcontext->disp,
+ xvimagesink->xwindow->win,
+ atom_output_external, 0, 0x7fffffff,
+ False, XA_CARDINAL, &type_ret, &size_ret,
+ &num_ret, &bytes, &prop_ret);
+ XSync(xvimagesink->xcontext->disp, FALSE);
+ if (ret != Success || error_caught) {
+ GST_WARNING_OBJECT(xvimagesink, "XGetWindowProperty failed");
+ if (prop_ret) {
+ XFree(prop_ret);
+ }
+ if (error_caught) {
+ GST_WARNING_OBJECT(xvimagesink, "error caught in XGetWindowProperty()");
+ }
+ if (handler) {
+ error_caught = FALSE;
+ XSetErrorHandler (handler);
+ }
+ return False;
+ }
+
+ if (handler) {
+ error_caught = FALSE;
+ XSetErrorHandler (handler);
+ }
+
+ if (!num_ret) {
+ GST_WARNING_OBJECT(xvimagesink, "XGetWindowProperty num_ret failed");
+ if (prop_ret) {
+ XFree(prop_ret);
+ }
+ return False;
+ }
+
+ if (prop_ret) {
+ switch (size_ret) {
+ case 8:
+ for (i = 0 ; i < num_ret ; i++) {
+ (&data)[i] = prop_ret[i];
+ }
+ break;
+ case 16:
+ for (i = 0 ; i < num_ret ; i++) {
+ ((unsigned short *)&data)[i] = ((unsigned short *)prop_ret)[i];
+ }
+ break;
+ case 32:
+ for (i = 0 ; i < num_ret ; i++) {
+ ((unsigned int *)&data)[i] = ((unsigned long *)prop_ret)[i];
+ }
+ break;
+ }
+ XFree(prop_ret);
+ prop_ret = NULL;
+
+ GST_WARNING_OBJECT(xvimagesink, "external display %d", data);
+
+ return (int)data;
+ } else {
+ GST_WARNING_OBJECT(xvimagesink, "prop_ret is NULL");
+ return False;
+ }
+ } else {
+ GST_WARNING_OBJECT(xvimagesink, "get XV_OUTPUT_EXTERNAL atom failed");
+ }
+
+ return False;
+}
#endif /* GST_EXT_XV_ENHANCEMENT */
/* This function handles a GstXWindow creation
XGCValues values;
#ifdef GST_EXT_XV_ENHANCEMENT
XSetWindowAttributes win_attr;
- XWindowAttributes root_attr;
+ XWindowAttributes root_attr = {0 , };
#endif /* GST_EXT_XV_ENHANCEMENT */
g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
xvimagesink->render_rect.h = xwindow->height = width;
}
- XGetWindowAttributes(xvimagesink->xcontext->disp, xvimagesink->xcontext->root, &root_attr);
+ if(!xvimagesink->is_pixmap)
+ XGetWindowAttributes(xvimagesink->xcontext->disp, xvimagesink->xcontext->root, &root_attr);
if (xwindow->width > root_attr.width) {
GST_INFO_OBJECT(xvimagesink, "Width[%d] is bigger than Max width. Set Max[%d].",
/* Make window manager not to change window size as Full screen */
win_attr.override_redirect = True;
- XChangeWindowAttributes(xvimagesink->xcontext->disp, xwindow->win, CWOverrideRedirect, &win_attr);
+ if(!xvimagesink->is_pixmap)
+ XChangeWindowAttributes(xvimagesink->xcontext->disp, xwindow->win, CWOverrideRedirect, &win_attr);
#else /* GST_EXT_XV_ENHANCEMENT */
xvimagesink->render_rect.w = width;
xvimagesink->render_rect.h = height;
if (xvimagesink->handle_events) {
Atom wm_delete;
-
+#ifdef GST_EXT_XV_ENHANCEMENT
+ XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xcontext->root, StructureNotifyMask | SubstructureNotifyMask);
+ XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
+ StructureNotifyMask | PointerMotionMask | KeyPressMask |
+ KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PropertyChangeMask);
+#else
XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
StructureNotifyMask | PointerMotionMask | KeyPressMask |
KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
+#endif
+
/* Tell the window manager we'd like delete client messages instead of
* being killed */
g_free (xwindow);
}
+#ifdef GST_EXT_XV_ENHANCEMENT
+/* This function destroys a GstXWindow */
+static void
+gst_xvimagesink_xpixmap_destroy (GstXvImageSink * xvimagesink,
+ GstXPixmap * xpixmap)
+{
+ g_return_if_fail (xpixmap != NULL);
+ g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
+
+ g_mutex_lock (xvimagesink->x_lock);
+
+ XSelectInput (xvimagesink->xcontext->disp, xpixmap->pixmap, 0);
+
+ XFreeGC (xvimagesink->xcontext->disp, xpixmap->gc);
+
+ XSync (xvimagesink->xcontext->disp, FALSE);
+
+ g_mutex_unlock (xvimagesink->x_lock);
+
+ g_free (xpixmap);
+}
+#endif /* GST_EXT_XV_ENHANCEMENT */
+
static void
gst_xvimagesink_xwindow_update_geometry (GstXvImageSink * xvimagesink)
{
#ifdef GST_EXT_XV_ENHANCEMENT
Window root_window, child_window;
- XWindowAttributes root_attr;
+ XWindowAttributes root_attr = {0 , };
int cur_win_x = 0;
int cur_win_y = 0;
xvimagesink->xwindow->height = cur_win_height;
/* Get absolute coordinates of current window */
- XTranslateCoordinates( xvimagesink->xcontext->disp,
- xvimagesink->xwindow->win,
- root_window,
- 0, 0,
- &cur_win_x, &cur_win_y, // relative x, y to root window == absolute x, y
- &child_window );
+ if(!xvimagesink->is_pixmap) {
+ XTranslateCoordinates( xvimagesink->xcontext->disp,
+ xvimagesink->xwindow->win,
+ root_window,
+ 0, 0,
+ &cur_win_x, &cur_win_y, // relative x, y to root window == absolute x, y
+ &child_window );
+ }
xvimagesink->xwindow->x = cur_win_x;
xvimagesink->xwindow->y = cur_win_y;
/* Get size of root window == size of screen */
- XGetWindowAttributes(xvimagesink->xcontext->disp, root_window, &root_attr);
+ if(!xvimagesink->is_pixmap)
+ XGetWindowAttributes(xvimagesink->xcontext->disp, root_window, &root_attr);
xvimagesink->scr_w = root_attr.width;
xvimagesink->scr_h = root_attr.height;
xvimagesink->render_rect.w = cur_win_width;
xvimagesink->render_rect.h = cur_win_height;
}
+ if (xvimagesink->scr_w != xvimagesink->xwindow->width ||
+ xvimagesink->scr_h != xvimagesink->xwindow->height) {
+ xvimagesink->is_multi_window = TRUE;
+ g_signal_emit_by_name(G_OBJECT (xvimagesink), "multiwindow-active", xvimagesink->is_multi_window);
+ GST_INFO_OBJECT(xvimagesink, "It may be multi-window scenario");
+ } else {
+ xvimagesink->is_multi_window = FALSE;
+ g_signal_emit_by_name(G_OBJECT (xvimagesink), "multiwindow-active", xvimagesink->is_multi_window);
+ GST_INFO_OBJECT(xvimagesink, "It may be full-window scenario");
+ }
GST_LOG_OBJECT(xvimagesink, "screen size %dx%d, current window geometry %d,%d,%dx%d, render_rect %d,%d,%dx%d",
xvimagesink->scr_w, xvimagesink->scr_h,
gst_xvimagesink_xwindow_clear (GstXvImageSink * xvimagesink,
GstXWindow * xwindow)
{
+#ifdef GST_EXT_XV_ENHANCEMENT
+ if (xvimagesink->is_subpicture_format)
+ return;
+#endif
g_return_if_fail (xwindow != NULL);
g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
g_mutex_lock (xvimagesink->x_lock);
+#ifdef GST_EXT_XV_ENHANCEMENT
+ GST_WARNING_OBJECT(xvimagesink, "CALL XvStopVideo");
+#endif /* GST_EXT_XV_ENHANCEMENT */
XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
xwindow->win);
-#ifndef GST_EXT_XV_ENHANCEMENT
+#ifdef GST_EXT_XV_ENHANCEMENT
+#if 0
+ /* NOTE : it should be enabled in pixmap buffer case,
+ if we can check whether if it is a pixmap or a window by X API */
/* Preview area is not updated before other UI is updated in the screen. */
XSetForeground (xvimagesink->xcontext->disp, xwindow->gc,
xvimagesink->xcontext->black);
XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc,
xvimagesink->render_rect.x, xvimagesink->render_rect.y,
xvimagesink->render_rect.w, xvimagesink->render_rect.h);
+#endif
#endif /* GST_EXT_XV_ENHANCEMENT */
XSync (xvimagesink->xcontext->disp, FALSE);
g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
+#ifdef GST_EXT_XV_ENHANCEMENT
+ GST_LOG("check x event");
+ Atom sc_status_atom = XInternAtom (xvimagesink->xcontext->disp, STR_ATOM_SCRNCONF_STATUS, FALSE);
+ Atom external_atom = XInternAtom (xvimagesink->xcontext->disp, "XV_OUTPUT_EXTERNAL", FALSE);
+#endif /* GST_EXT_XV_ENHANCEMENT */
+
/* Handle Interaction, produces navigation events */
/* We get all pointer motion events, only the last position is
interesting. */
g_mutex_lock (xvimagesink->flow_lock);
g_mutex_lock (xvimagesink->x_lock);
+#ifdef GST_EXT_XV_ENHANCEMENT
+ if (xvimagesink->xcontext->disp) {
+#endif //GST_EXT_XV_ENHANCEMENT
while (XCheckWindowEvent (xvimagesink->xcontext->disp,
xvimagesink->xwindow->win, PointerMotionMask, &e)) {
g_mutex_unlock (xvimagesink->x_lock);
g_mutex_lock (xvimagesink->flow_lock);
g_mutex_lock (xvimagesink->x_lock);
}
+#ifdef GST_EXT_XV_ENHANCEMENT
+ }
+#endif //GST_EXT_XV_ENHANCEMENT
if (pointer_moved) {
g_mutex_unlock (xvimagesink->x_lock);
g_mutex_unlock (xvimagesink->flow_lock);
g_mutex_lock (xvimagesink->flow_lock);
g_mutex_lock (xvimagesink->x_lock);
}
-
/* Handle Expose */
while (XCheckWindowEvent (xvimagesink->xcontext->disp,
xvimagesink->xwindow->win, ExposureMask | StructureNotifyMask, &e)) {
case ConfigureNotify:
g_mutex_unlock (xvimagesink->x_lock);
#ifdef GST_EXT_XV_ENHANCEMENT
- GST_INFO_OBJECT (xvimagesink, "Call gst_xvimagesink_xwindow_update_geometry!");
+ GST_WARNING("Call gst_xvimagesink_xwindow_update_geometry!");
#endif /* GST_EXT_XV_ENHANCEMENT */
gst_xvimagesink_xwindow_update_geometry (xvimagesink);
+#ifdef GST_EXT_XV_ENHANCEMENT
+ GST_WARNING("Return gst_xvimagesink_xwindow_update_geometry!");
+#endif /* GST_EXT_XV_ENHANCEMENT */
g_mutex_lock (xvimagesink->x_lock);
configured = TRUE;
break;
g_mutex_unlock (xvimagesink->x_lock);
g_mutex_unlock (xvimagesink->flow_lock);
- gst_xvimagesink_expose (GST_X_OVERLAY (xvimagesink));
+ gst_xvimagesink_expose (GST_X_OVERLAY (xvimagesink));
+
+ g_mutex_lock (xvimagesink->flow_lock);
+ g_mutex_lock (xvimagesink->x_lock);
+ }
+
+ /* Handle Display events */
+ while (XPending (xvimagesink->xcontext->disp)) {
+ XNextEvent (xvimagesink->xcontext->disp, &e);
+ switch (e.type) {
+ case ClientMessage:{
+#ifdef GST_EXT_XV_ENHANCEMENT
+ XClientMessageEvent *cme = (XClientMessageEvent *)&e;
+ Atom buffer_atom = XInternAtom(xvimagesink->xcontext->disp, "XV_RETURN_BUFFER", False);
+ Atom qp_state_atom = XInternAtom(xvimagesink->xcontext->disp, "_E_ILLUME_QUICKPANEL_STATE", False);
+ Atom qp_on_atom = XInternAtom(xvimagesink->xcontext->disp, "_E_ILLUME_QUICKPANEL_ON", False);
+ Atom qp_off_atom = XInternAtom(xvimagesink->xcontext->disp, "_E_ILLUME_QUICKPANEL_OFF", False);
+#endif /* GST_EXT_XV_ENHANCEMENT */
+ Atom wm_delete;
+
+#ifdef GST_EXT_XV_ENHANCEMENT
+ GST_LOG_OBJECT(xvimagesink, "message type %d, buffer atom %d", cme->message_type, buffer_atom);
+ if (cme->message_type == buffer_atom) {
+ unsigned int gem_name[XV_BUF_PLANE_NUM] = { 0, };
+
+ GST_DEBUG("data.l[0] -> %d, data.l[1] -> %d",
+ cme->data.l[0], cme->data.l[1]);
+
+ gem_name[0] = cme->data.l[0];
+ gem_name[1] = cme->data.l[1];
+
+ _remove_displaying_buffer(xvimagesink, gem_name);
+ break;
+ } else if (cme->message_type == sc_status_atom) {
+ int stat = cme->data.s[0];
+ if (stat == UTILX_SCRNCONF_STATUS_NULL) {
+ GST_WARNING ("get UTILX_SCRNCONF_STATUS_NULL event\n");
+ check_hdmi_connected(xvimagesink);
+ } else if (stat == UTILX_SCRNCONF_STATUS_CONNECT) {
+ GST_WARNING ("get UTILX_SCRNCONF_STATUS_CONNECT event\n");
+ check_hdmi_connected(xvimagesink);
+ } else if (stat == UTILX_SCRNCONF_STATUS_ACTIVE) {
+ GST_WARNING ("get UTILX_SCRNCONF_STATUS_ACTIVE event\n");
+ g_signal_emit_by_name(G_OBJECT (xvimagesink), "display-status", DISPLAY_STATUS_HDMI_ACTIVE);
+ check_hdmi_connected(xvimagesink);
+ } else {
+ GST_INFO ("Wrong status\n");
+ }
+ break;
+ } else if (cme->message_type == qp_state_atom) {
+ if ((Atom) cme->data.l[0] == qp_on_atom) {
+ /* quick panel on */
+ GST_WARNING_OBJECT(xvimagesink, "quick panel is ON");
+ xvimagesink->is_quick_panel_on = TRUE;
+ g_signal_emit_by_name(G_OBJECT (xvimagesink), "quick-panel-on", TRUE);
+ } else if ((Atom) cme->data.l[0] == qp_off_atom) {
+ /* quick panel off */
+ GST_WARNING_OBJECT(xvimagesink, "quick panel is OFF");
+ xvimagesink->is_quick_panel_on = FALSE;
+ g_signal_emit_by_name(G_OBJECT (xvimagesink), "quick-panel-on", FALSE);
+ }
+ break;
+ }
+#endif /* GST_EXT_XV_ENHANCEMENT */
+
+ wm_delete = XInternAtom (xvimagesink->xcontext->disp,
+ "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 (xvimagesink, RESOURCE, NOT_FOUND,
+ ("Output window was closed"), (NULL));
+
+ g_mutex_unlock (xvimagesink->x_lock);
+ gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
+ xvimagesink->xwindow = NULL;
+ g_mutex_lock (xvimagesink->x_lock);
+ }
+ break;
+ }
+#ifdef GST_EXT_XV_ENHANCEMENT
+ case VisibilityNotify:
+ if (xvimagesink->xwindow &&
+ (e.xvisibility.window == xvimagesink->xwindow->win)) {
+ if (e.xvisibility.state == VisibilityFullyObscured) {
+ Atom atom_stream;
+
+ GST_WARNING_OBJECT(xvimagesink, "current window is FULLY HIDED");
+
+ xvimagesink->is_hided = TRUE;
+ g_signal_emit_by_name(G_OBJECT (xvimagesink), "hided-window", TRUE);
+ if (!_is_connected_to_external_display(xvimagesink)) {
+ GST_WARNING_OBJECT(xvimagesink, "no external display, calling XvStopVideo()");
+ XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xwindow->win);
+ XSync(xvimagesink->xcontext->disp, FALSE);
+ } else {
+ if (GST_STATE(xvimagesink) == GST_STATE_PLAYING || xvimagesink->keep_external_fullscreen_prev) {
+ GST_WARNING_OBJECT(xvimagesink, "external display is enabled. skip XvStopVideo()");
+ } else {
+ GST_WARNING_OBJECT(xvimagesink, "external display is enabled, but not in the middle of playing, calling XvStopVideo()");
+ XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xwindow->win);
+ XSync(xvimagesink->xcontext->disp, FALSE);
+ }
+ }
+ } else {
+ GST_INFO_OBJECT(xvimagesink, "current window is SHOWN");
+
+ if (xvimagesink->is_hided) {
+ g_mutex_unlock(xvimagesink->x_lock);
+ g_mutex_unlock(xvimagesink->flow_lock);
+
+ xvimagesink->is_hided = FALSE;
+ g_signal_emit_by_name(G_OBJECT (xvimagesink), "hided-window", FALSE);
+ gst_xvimagesink_expose(GST_X_OVERLAY(xvimagesink));
+
+ g_mutex_lock(xvimagesink->flow_lock);
+ g_mutex_lock(xvimagesink->x_lock);
+ } else {
+ GST_INFO_OBJECT(xvimagesink, "current window is not HIDED, skip this event");
+ }
+ }
+ }
+ break;
+
+ case PropertyNotify:
+ {
+ XPropertyEvent *noti = (XPropertyEvent *)&e;
+ if(xvimagesink->xwindow) {
+ if (noti->window == xvimagesink->xwindow->win && noti->atom == external_atom) {
+ int value = 0;
+ get_window_prop_card32_property (xvimagesink->xcontext->disp,
+ xvimagesink->xwindow->win,
+ external_atom, XA_CARDINAL,
+ (unsigned int*)&value, 1);
+ if (value) {
+ // If value is 1, video will be displayed only on external display.
+ // video won't be displayed on LCD.
+ g_signal_emit_by_name(G_OBJECT (xvimagesink), "display-status", DISPLAY_STATUS_UNKNOWN_ACTIVE);
+ if(xvimagesink->external_width==0 && xvimagesink->external_height==0) {
+ xvimagesink->external_width = 1920;
+ xvimagesink->external_height = 1080;
+ GST_WARNING("connected unknown external display");
+ }
+ } else {
+ g_signal_emit_by_name(G_OBJECT (xvimagesink), "display-status", DISPLAY_STATUS_NULL); //NULL
+ if(xvimagesink->external_width!=0 || xvimagesink->external_height!=0) {
+ xvimagesink->external_width = 0;
+ xvimagesink->external_height = 0;
+ GST_WARNING("disconnected external display");
+ }
+ }
+
+ g_signal_emit_by_name(G_OBJECT (xvimagesink), "external-resolution", xvimagesink->external_width, xvimagesink->external_height);
+ GST_INFO ("external device : %s\n", (value)?"on":"off");
+ }
+ }
+ break;
+ }
+
+#endif /* GST_EXT_XV_ENHANCEMENT */
+ default:
+ break;
+ }
+ }
+ g_mutex_unlock (xvimagesink->x_lock);
+ g_mutex_unlock (xvimagesink->flow_lock);
+}
+#ifdef GST_EXT_XV_ENHANCEMENT
+static int
+get_window_prop_card32_property (Display* dpy, Window win, Atom atom, Atom type,
+ unsigned int *val, unsigned int len)
+{
+ unsigned char* prop_ret;
+ Atom type_ret;
+ unsigned long bytes_after, num_ret;
+ int format_ret;
+ unsigned int i;
+ int num;
+ int ret;
+ int (*handler) (Display *, XErrorEvent *) = NULL;
+
+ prop_ret = NULL;
+
+ /* set error handler */
+ error_caught = FALSE;
+ handler = XSetErrorHandler(gst_xvimagesink_handle_xerror);
+
+ ret = XGetWindowProperty(dpy, win, atom, 0, 0x7fffffff, False,
+ type, &type_ret, &format_ret, &num_ret,
+ &bytes_after, &prop_ret);
+ XSync(dpy, FALSE);
+ if (ret != Success || error_caught) {
+ GST_WARNING("XGetWindowProperty failed [%d, %d]", ret, error_caught);
+ if (handler) {
+ error_caught = FALSE;
+ XSetErrorHandler (handler);
+ }
+ return -1;
+ }
+
+ if (handler) {
+ error_caught = FALSE;
+ XSetErrorHandler(handler);
+ }
+
+ if (type_ret != type || format_ret != 32)
+ num = -1;
+ else if (num_ret == 0 || !prop_ret)
+ num = 0;
+ else
+ {
+ if (num_ret < len)
+ len = num_ret;
+ for (i = 0; i < len; i++)
+ val[i] = ((unsigned long *)prop_ret)[i];
+ num = len;
+ }
+
+ if (prop_ret)
+ XFree(prop_ret);
- g_mutex_lock (xvimagesink->flow_lock);
- g_mutex_lock (xvimagesink->x_lock);
+ return num;
+}
+
+static void check_hdmi_connected(GstXvImageSink *xvimagesink)
+{
+ char *str_output = NULL;
+ char *str_resolution = NULL;
+ int external[2];
+ int cnt = 0;
+ char** list = NULL;
+ char** walk = NULL;
+
+ UtilxScrnConf *scrnconf = utilx_scrnconf_allocate();
+ if (!scrnconf)
+ {
+ GST_WARNING ("fail to allocate scrnconf");
+ return;
}
+ utilx_scrnconf_get_info (xvimagesink->xcontext->disp, scrnconf);
- /* Handle Display events */
- while (XPending (xvimagesink->xcontext->disp)) {
- XNextEvent (xvimagesink->xcontext->disp, &e);
+ str_output = scrnconf->str_output;
- switch (e.type) {
- case ClientMessage:{
-#ifdef GST_EXT_XV_ENHANCEMENT
- int active_pid, deactive_pid;
- Atom active_win_atom;
- Atom deactive_win_atom;
- Atom atom_stream;
-#endif /* GST_EXT_XV_ENHANCEMENT */
- Atom wm_delete;
+ if (scrnconf->status == UTILX_SCRNCONF_STATUS_CONNECT)
+ {
+ GST_INFO("CONNECT");
+ }
+ else if (scrnconf->status == UTILX_SCRNCONF_STATUS_ACTIVE)
+ {
+ GST_INFO("ACTIVE");
- wm_delete = XInternAtom (xvimagesink->xcontext->disp,
- "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 (xvimagesink, RESOURCE, NOT_FOUND,
- ("Output window was closed"), (NULL));
+ list = g_strsplit(scrnconf->str_resolution, "x", 2);
- g_mutex_unlock (xvimagesink->x_lock);
- gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
- xvimagesink->xwindow = NULL;
- g_mutex_lock (xvimagesink->x_lock);
- }
-#ifdef GST_EXT_XV_ENHANCEMENT
- GST_INFO_OBJECT( xvimagesink, "message type : %d", e.xclient.message_type );
+ if (!list)
+ {
+ if (scrnconf)
+ utilx_scrnconf_free (scrnconf);
+ return;
+ }
+ for(walk = list; *walk; walk++)
+ {
+ external[cnt++] = atoi(*walk);
+ }
+ if (cnt!=2) {
+ GST_WARNING("data error");
+ if(scrnconf)
+ utilx_scrnconf_free (scrnconf);
+ g_strfreev(list);
+ return;
+ } else {
+ xvimagesink->external_width = external[0];
+ xvimagesink->external_height = external[1];
+ g_strfreev(list);
+ }
+ GST_INFO("external display : %d * %d", xvimagesink->external_width, xvimagesink->external_height);
+ g_signal_emit_by_name(G_OBJECT (xvimagesink), "external-resolution", xvimagesink->external_width, xvimagesink->external_height);
+ }
+ else
+ {
+ GST_INFO("NULL");
+ }
- active_win_atom = XInternAtom (xvimagesink->xcontext->disp, "_X_ILLUME_ACTIVATE_WINDOW", False);
- deactive_win_atom = XInternAtom (xvimagesink->xcontext->disp, "_X_ILLUME_DEACTIVATE_WINDOW", False);
+ str_resolution = scrnconf->str_resolution;
- if (!active_win_atom || !deactive_win_atom) {
- GST_WARNING_OBJECT( xvimagesink, "Can NOT get active[%d] or deactive[%d] win atom",
- active_win_atom, deactive_win_atom );
- } else {
- if (e.xclient.message_type == deactive_win_atom) {
- /* Window is DEACTIVATED */
- /* Get pid of activated/deactivated window */
- active_pid = e.xclient.data.l[1];
- deactive_pid = e.xclient.data.l[3];
-
- if (active_pid != deactive_pid) {
- GST_INFO_OBJECT( xvimagesink, "XClientMessage : Window DEACTIVATED" );
-
- xvimagesink->is_hided = TRUE;
- atom_stream = XInternAtom( xvimagesink->xcontext->disp,
- "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False );
- if (atom_stream != None) {
- if (XvSetPortAttribute(xvimagesink->xcontext->disp,
- xvimagesink->xcontext->xv_port_id,
- atom_stream, 0 ) != Success) {
- GST_WARNING_OBJECT( xvimagesink, "STREAM OFF failed" );
- }
- XSync( xvimagesink->xcontext->disp, FALSE );
- }
- } else {
- GST_INFO_OBJECT( xvimagesink, "Window is DEACTIVATED, but same process. so Do not clear screen." );
- }
- } else if (e.xclient.message_type == active_win_atom) {
- /* Window is ACTIVATED */
- /* Get pid of activated/deactivated window */
- active_pid = e.xclient.data.l[1];
- deactive_pid = e.xclient.data.l[3];
+ if (scrnconf->dispmode == UTILX_SCRNCONF_DISPMODE_CLONE)
+ {
+ GST_INFO("CLONE mode");
+ }
+ else if (scrnconf->dispmode == UTILX_SCRNCONF_DISPMODE_EXTENDED)
+ {
+ GST_INFO("EXTENDED mode");
+ }
+ else
+ {
+ GST_INFO("NULL mode");
+ }
- if (active_pid != deactive_pid) {
- GST_INFO_OBJECT( xvimagesink, "XClientMessage : Window ACTIVATED" );
+ GST_INFO ("[Display status] : %s, %s\n", str_output, str_resolution);
- g_mutex_unlock (xvimagesink->x_lock);
- g_mutex_unlock (xvimagesink->flow_lock);
+ if(scrnconf)
+ utilx_scrnconf_free (scrnconf);
- xvimagesink->is_hided = FALSE;
- gst_xvimagesink_expose (GST_X_OVERLAY (xvimagesink));
+}
- g_mutex_lock (xvimagesink->flow_lock);
- g_mutex_lock (xvimagesink->x_lock);
- } else {
- GST_INFO_OBJECT( xvimagesink, "Window is ACTIVATED, but same process. so Do not redraw screen." );
- }
- }
- }
-#endif /* GST_EXT_XV_ENHANCEMENT */
- break;
+static gboolean
+check_supportable_port_attr(GstXvImageSink * xvimagesink, gchar* attr_name)
+{
+ int i = 0;
+ int count = 0;
+
+ XvAttribute *attr = XvQueryPortAttributes(xvimagesink->xcontext->disp,
+ xvimagesink->xcontext->xv_port_id, &count);
+ if (attr) {
+ for (i = 0 ; i < count ; i++) {
+ if (!strcmp(attr[i].name, attr_name)) {
+ GST_INFO("%s[index %d] found", attr_name, i);
+ XFree(attr);
+ return TRUE;
}
- default:
- break;
}
+ XFree(attr);
+ } else {
+ GST_WARNING("XvQueryPortAttributes disp:%d, port_id:%d failed",
+ xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id);
}
-
- g_mutex_unlock (xvimagesink->x_lock);
- g_mutex_unlock (xvimagesink->flow_lock);
+ return FALSE;
}
+#endif //GST_EXT_XV_ENHANCEMENT
static void
gst_lookup_xv_port_from_adaptor (GstXContext * xcontext,
}
}
+#ifdef GST_EXT_XV_ENHANCEMENT
+static void
+gst_lookup_xv_port_for_subtitle (GstXContext * xcontext,
+ XvAdaptorInfo * adaptors, guint adaptor_no, guint nb_adaptors)
+{
+ int i;
+ if (!adaptors)
+ return;
+ for (i = 0; i < nb_adaptors; i++)
+ {
+ int min, max;
+ if (!(adaptors[i].type & XvOutputMask) ||
+ !(adaptors[i].type & XvStillMask))
+ continue;
+ min = adaptors[i].base_id;
+ max = adaptors[i].base_id + adaptors[i].num_ports;
+ for (adaptors[adaptor_no].num_ports = min; adaptors[adaptor_no].num_ports < max ; adaptors[adaptor_no].num_ports++)
+ {
+ if (XvGrabPort (xcontext->disp, adaptors[adaptor_no].num_ports, 0) == Success)
+ {
+ GST_INFO ("========================================");
+ GST_INFO ("XvGrabPort success : %ld", adaptors[adaptor_no].num_ports);
+ GST_INFO ("========================================");
+ xcontext->xv_port_id = adaptors[adaptor_no].num_ports;
+ return;
+ }
+ GST_WARNING ("fail : grab port(%ld)\n", adaptors[adaptor_no].num_ports);
+ usleep(10000);
+ }
+ }
+}
+#endif
+
+
/* This function generates a caps with all supported format by the first
Xv grabable port we find. We store each one of the supported formats in a
format list and append the format to a newly created caps that we return
xcontext->xv_port_id = 0;
- GST_DEBUG ("Found %u XV adaptor(s)", xcontext->nb_adaptors);
+ GST_DEBUG_OBJECT(xvimagesink, "Found %u XV adaptor(s)", xcontext->nb_adaptors);
xcontext->adaptors =
(gchar **) g_malloc0 (xcontext->nb_adaptors * sizeof (gchar *));
if (xvimagesink->adaptor_no >= 0 &&
xvimagesink->adaptor_no < xcontext->nb_adaptors) {
/* Find xv port from user defined adaptor */
- gst_lookup_xv_port_from_adaptor (xcontext, adaptors,
- xvimagesink->adaptor_no);
+#ifdef GST_EXT_XV_ENHANCEMENT
+ if(!xvimagesink->subpicture)
+#endif
+ gst_lookup_xv_port_from_adaptor (xcontext, adaptors, xvimagesink->adaptor_no);
+#ifdef GST_EXT_XV_ENHANCEMENT
+ else
+ gst_lookup_xv_port_for_subtitle (xcontext, adaptors, xvimagesink->adaptor_no, xcontext->nb_adaptors);
+#endif
}
if (!xcontext->xv_port_id) {
/* Now search for an adaptor that supports XvImageMask */
for (i = 0; i < xcontext->nb_adaptors && !xcontext->xv_port_id; i++) {
- gst_lookup_xv_port_from_adaptor (xcontext, adaptors, i);
+#ifdef GST_EXT_XV_ENHANCEMENT
+ if(!xvimagesink->subpicture)
+#endif
+ gst_lookup_xv_port_from_adaptor (xcontext, adaptors, i);
+#ifdef GST_EXT_XV_ENHANCEMENT
+ else
+ gst_lookup_xv_port_for_subtitle (xcontext, adaptors, i, xcontext->nb_adaptors);
+#endif
xvimagesink->adaptor_no = i;
}
}
}
XvFreeEncodingInfo (encodings);
-
+#ifdef GST_EXT_XV_ENHANCEMENT
+if (!xvimagesink->subpicture) {
+#endif
/* We get all image formats supported by our port */
formats = XvListImageFormats (xcontext->disp,
xcontext->xv_port_id, &nb_formats);
}
format_caps = gst_caps_new_simple ("video/x-raw-rgb",
+#ifdef GST_EXT_XV_ENHANCEMENT
+ "format", GST_TYPE_FOURCC, formats[i].id,
+#endif /* GST_EXT_XV_ENHANCEMENT */
"endianness", G_TYPE_INT, endianness,
"depth", G_TYPE_INT, fmt->depth,
"bpp", G_TYPE_INT, fmt->bits_per_pixel,
("No supported format found"));
return NULL;
}
+#ifdef GST_EXT_XV_ENHANCEMENT
+} //subpicture
+#endif
return caps;
}
if (xvimagesink->xwindow) {
gst_xvimagesink_handle_xevents (xvimagesink);
}
+
+#ifdef GST_EXT_XV_ENHANCEMENT
+ g_usleep (_EVENT_THREAD_CHECK_INTERVAL);
+#else /* GST_EXT_XV_ENHANCEMENT */
/* FIXME: do we want to align this with the framerate or anything else? */
g_usleep (G_USEC_PER_SEC / 20);
+#endif /* GST_EXT_XV_ENHANCEMENT */
GST_OBJECT_LOCK (xvimagesink);
}
}
+#ifdef GST_EXT_XV_ENHANCEMENT
+/**
+ * gst_xvimagesink_prepare_xid:
+ * @overlay: a #GstXOverlay which does not yet have an XWindow or XPixmap.
+ *
+ * This will post a "prepare-xid" element message with video size and display size on the bus
+ * to give applications an opportunity to call
+ * gst_x_overlay_set_xwindow_id() before a plugin creates its own
+ * window or pixmap.
+ *
+ * This function should only be used by video overlay plugin developers.
+ */
+static void
+gst_xvimagesink_prepare_xid (GstXOverlay * overlay)
+{
+ GstStructure *s;
+ GstMessage *msg;
+
+ g_return_if_fail (overlay != NULL);
+ g_return_if_fail (GST_IS_X_OVERLAY (overlay));
+
+ GstXvImageSink *xvimagesink;
+ xvimagesink = GST_XVIMAGESINK (GST_OBJECT (overlay));
+
+ GST_DEBUG ("post \"prepare-xid\" element message with video-width(%d), video-height(%d), display-width(%d), display-height(%d)",
+ GST_VIDEO_SINK_WIDTH (xvimagesink), GST_VIDEO_SINK_HEIGHT (xvimagesink), xvimagesink->xcontext->width, xvimagesink->xcontext->height);
+
+ GST_LOG_OBJECT (GST_OBJECT (overlay), "prepare xid");
+ s = gst_structure_new ("prepare-xid",
+ "video-width", G_TYPE_INT, GST_VIDEO_SINK_WIDTH (xvimagesink),
+ "video-height", G_TYPE_INT, GST_VIDEO_SINK_HEIGHT (xvimagesink),
+ "display-width", G_TYPE_INT, xvimagesink->xcontext->width,
+ "display-height", G_TYPE_INT, xvimagesink->xcontext->height,
+ NULL);
+ msg = gst_message_new_element (GST_OBJECT (overlay), s);
+ gst_element_post_message (GST_ELEMENT (overlay), msg);
+}
+#endif /* GST_EXT_XV_ENHANCEMENT */
+
+
/* This function calculates the pixel aspect ratio based on the properties
* in the xcontext structure and stores it there. */
static void
{1, 1}, /* regular screen */
{16, 15}, /* PAL TV */
{11, 10}, /* 525 line Rec.601 video */
+#ifdef GST_EXT_XV_ENHANCEMENT
+ {44, 46}, /* Gear S Curved Display */
+#endif
{54, 59}, /* 625 line Rec.601 video */
{64, 45}, /* 1280x1024 on 16:9 display */
{5, 3}, /* 1280x1024 on 4:3 display */
GstXContext *xcontext = NULL;
XPixmapFormatValues *px_formats = NULL;
gint nb_formats = 0, i, j, N_attr;
- XvAttribute *xv_attr;
+ XvAttribute *xv_attr = NULL;
Atom prop_atom;
const char *channels[4] = { "XV_HUE", "XV_SATURATION",
"XV_BRIGHTNESS", "XV_CONTRAST"
g_mutex_lock (xvimagesink->x_lock);
xcontext->disp = XOpenDisplay (xvimagesink->display_name);
-
if (!xcontext->disp) {
g_mutex_unlock (xvimagesink->x_lock);
g_free (xcontext);
return NULL;
}
+#ifdef GST_EXT_XV_ENHANCEMENT
+ {
+ int i = 0;
+ for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
+ if (g_display_id[i] == NULL) {
+ g_display_id[i] = xcontext->disp;
+ GST_INFO_OBJECT(xvimagesink, "x display array[%d] = display(0x%x)", i, xcontext->disp);
+ break;
+ }
+ }
+ if (i == MAX_DISPLAY_IN_XVIMAGESINK) {
+ GST_WARNING_OBJECT(xvimagesink, "out of index(%d) for x display array", i);
+ }
+ }
+#endif
+
xcontext->screen = DefaultScreenOfDisplay (xcontext->disp);
xcontext->screen_num = DefaultScreen (xcontext->disp);
xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num);
px_formats = XListPixmapFormats (xcontext->disp, &nb_formats);
if (!px_formats) {
+#ifdef GST_EXT_XV_ENHANCEMENT
+ {
+ int i = 0;
+ for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
+ if (g_display_id[i] == xcontext->disp) {
+ g_display_id[i] = NULL;
+ }
+ }
+ }
+#endif
XCloseDisplay (xcontext->disp);
g_mutex_unlock (xvimagesink->x_lock);
g_free (xcontext->par);
xcontext->caps = gst_xvimagesink_get_xv_support (xvimagesink, xcontext);
- if (!xcontext->caps) {
+ if (!xcontext->caps
+#ifdef GST_EXT_XV_ENHANCEMENT
+ && !xvimagesink->subpicture
+#endif
+ ) {
+#ifdef GST_EXT_XV_ENHANCEMENT
+ {
+ int i = 0;
+ for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
+ if (g_display_id[i] == xcontext->disp) {
+ g_display_id[i] = NULL;
+ }
+ }
+ }
+#endif
XCloseDisplay (xcontext->disp);
g_mutex_unlock (xvimagesink->x_lock);
g_free (xcontext->par);
return NULL;
}
#ifdef HAVE_XSHM
- /* Search for XShm extension support */
- if (XShmQueryExtension (xcontext->disp) &&
- gst_xvimagesink_check_xshm_calls (xcontext)) {
- xcontext->use_xshm = TRUE;
- GST_DEBUG ("xvimagesink is using XShm extension");
- } else
+#ifdef GST_EXT_XV_ENHANCEMENT
+ if (!xvimagesink->subpicture) {
+#endif //GST_EXT_XV_ENHANCEMENT
+ /* Search for XShm extension support */
+ if (XShmQueryExtension (xcontext->disp) &&
+ gst_xvimagesink_check_xshm_calls (xcontext)) {
+ xcontext->use_xshm = TRUE;
+ GST_DEBUG ("xvimagesink is using XShm extension");
+ } else
#endif /* HAVE_XSHM */
- {
- xcontext->use_xshm = FALSE;
- GST_DEBUG ("xvimagesink is not using XShm extension");
- }
-
- xv_attr = XvQueryPortAttributes (xcontext->disp,
- xcontext->xv_port_id, &N_attr);
+ {
+ xcontext->use_xshm = FALSE;
+ GST_DEBUG ("xvimagesink is not using XShm extension");
+ }
+ xv_attr = XvQueryPortAttributes (xcontext->disp,
+ xcontext->xv_port_id, &N_attr);
+#ifdef GST_EXT_XV_ENHANCEMENT
+ }
+#endif //GST_EXT_XV_ENHANCEMENT
/* Generate the channels list */
for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++) {
}
}
}
-
+#ifdef GST_EXT_XV_ENHANCEMENT
+ if (!xvimagesink->subpicture) {
+#endif
if (xv_attr)
XFree (xv_attr);
-
#ifdef GST_EXT_XV_ENHANCEMENT
- set_display_mode(xcontext, xvimagesink->display_mode);
+ }
+ if(!xvimagesink->subpicture) {
+ set_display_mode(xvimagesink->xcontext, xvimagesink->display_mode);
+ set_csc_range(xcontext, xvimagesink->csc_range);
+ }
#endif /* GST_EXT_XV_ENHANCEMENT */
g_mutex_unlock (xvimagesink->x_lock);
static void
gst_xvimagesink_xcontext_clear (GstXvImageSink * xvimagesink)
{
- GList *formats_list, *channels_list;
+ GList *formats_list, *channels_list = NULL;
GstXContext *xcontext;
gint i = 0;
GST_OBJECT_UNLOCK (xvimagesink);
-
+#ifdef GST_EXT_XV_ENHANCEMENT
+ if (!xvimagesink->subpicture) {
+#endif
formats_list = xcontext->formats_list;
while (formats_list) {
g_list_free (xcontext->formats_list);
channels_list = xcontext->channels_list;
-
+#ifdef GST_EXT_XV_ENHANCEMENT
+ }
+#endif
while (channels_list) {
GstColorBalanceChannel *channel = channels_list->data;
XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
+#ifdef GST_EXT_XV_ENHANCEMENT
+ {
+ int i = 0;
+ for (i = 0; i < MAX_DISPLAY_IN_XVIMAGESINK; i++) {
+ if (g_display_id[i] == xcontext->disp) {
+ g_display_id[i] = NULL;
+ }
+ }
+ }
+#endif
XCloseDisplay (xcontext->disp);
-
g_mutex_unlock (xvimagesink->x_lock);
g_free (xcontext);
GstXvImageSink *xvimagesink;
xvimagesink = GST_XVIMAGESINK (bsink);
-
- if (xvimagesink->xcontext)
+ if (xvimagesink->xcontext
+#ifdef GST_EXT_XV_ENHANCEMENT
+ && !xvimagesink->subpicture
+#endif
+) {
return gst_caps_ref (xvimagesink->xcontext->caps);
-
+ }
return
gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD
(xvimagesink)));
const GValue *fps;
guint num, den;
#ifdef GST_EXT_XV_ENHANCEMENT
- gboolean enable_last_buffer;
+ gboolean subtitle;
+ gchar *str_in = gst_caps_to_string(caps);
+ if(str_in == NULL) {
+ GST_ERROR("gst_caps_to_string() returns NULL...");
+ }else{
+ GST_INFO("In setcaps. incaps:%s", str_in);
+ g_free (str_in);
+ str_in = NULL;
+ }
#endif /* #ifdef GST_EXT_XV_ENHANCEMENT */
xvimagesink = GST_XVIMAGESINK (bsink);
"In setcaps. Possible caps %" GST_PTR_FORMAT ", setting caps %"
GST_PTR_FORMAT, xvimagesink->xcontext->caps, caps);
- if (!gst_caps_can_intersect (xvimagesink->xcontext->caps, caps))
+ if (!gst_caps_can_intersect (xvimagesink->xcontext->caps, caps)
+#ifdef GST_EXT_XV_ENHANCEMENT
+ && !xvimagesink->subpicture
+#endif
+ )
goto incompatible_caps;
structure = gst_caps_get_structure (caps, 0);
ret &= gst_structure_get_int (structure, "height", &video_height);
fps = gst_structure_get_value (structure, "framerate");
ret &= (fps != NULL);
-
+#ifdef GST_EXT_XV_ENHANCEMENT
+ if(gst_structure_get_boolean (structure, "subtitle", &subtitle) && xvimagesink->subpicture)
+ {
+ xvimagesink->is_subpicture_format = TRUE;
+ GST_LOG("It is type of subpicture and subtitle.");
+ }
+#endif
if (!ret)
goto incomplete_caps;
xvimagesink->aligned_width = video_width;
xvimagesink->aligned_height = video_height;
- /* get enable-last-buffer */
- g_object_get(G_OBJECT(xvimagesink), "enable-last-buffer", &enable_last_buffer, NULL);
- GST_INFO_OBJECT(xvimagesink, "current enable-last-buffer : %d", enable_last_buffer);
-
- /* flush if enable-last-buffer is TRUE */
- if (enable_last_buffer) {
- GST_INFO_OBJECT(xvimagesink, "flush last-buffer");
- g_object_set(G_OBJECT(xvimagesink), "enable-last-buffer", FALSE, NULL);
- g_object_set(G_OBJECT(xvimagesink), "enable-last-buffer", TRUE, NULL);
+#ifdef GST_EXT_ENABLE_HEVC
+ /*get combine prop of hevc*/
+ if(gst_structure_get_int (structure, "yuvcombine", &(xvimagesink->need_combine_data)))
+ {
+ GST_INFO_OBJECT(xvimagesink, "need combine data : %d", xvimagesink->need_combine_data);
+ }
+ else
+ {
+ /*Not need to combine data, just directly copy*/
+ xvimagesink->need_combine_data = 0;
}
+#endif
+ _remove_last_buffer(xvimagesink);
#endif /* GST_EXT_XV_ENHANCEMENT */
xvimagesink->fps_n = gst_value_get_fraction_numerator (fps);
xvimagesink->video_width = video_width;
xvimagesink->video_height = video_height;
-
+#ifdef GST_EXT_XV_ENHANCEMENT
+ if (!xvimagesink->subpicture) {
+#endif
im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
if (im_format == -1)
goto invalid_format;
-
+#ifdef GST_EXT_XV_ENHANCEMENT
+ }
+#endif
/* get aspect ratio from caps if it's present, and
* convert video width and height to a display width and height
* using wd / hd = wv / hv * PARv / PARd */
/* Notify application to set xwindow id now */
g_mutex_lock (xvimagesink->flow_lock);
+#ifdef GST_EXT_XV_ENHANCEMENT
+ if (!xvimagesink->xwindow && !xvimagesink->get_pixmap_cb) {
+ g_mutex_unlock (xvimagesink->flow_lock);
+ gst_xvimagesink_prepare_xid (GST_X_OVERLAY (xvimagesink));
+#else
if (!xvimagesink->xwindow) {
g_mutex_unlock (xvimagesink->flow_lock);
gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (xvimagesink));
+#endif
} else {
g_mutex_unlock (xvimagesink->flow_lock);
}
+#ifdef GST_EXT_XV_ENHANCEMENT
+if (!xvimagesink->is_subpicture_format) {
+#endif
+ /* Creating our window and our image with the display size in pixels */
+ if (GST_VIDEO_SINK_WIDTH (xvimagesink) <= 0 ||
+ GST_VIDEO_SINK_HEIGHT (xvimagesink) <= 0)
+ goto no_display_size;
- /* Creating our window and our image with the display size in pixels */
- if (GST_VIDEO_SINK_WIDTH (xvimagesink) <= 0 ||
- GST_VIDEO_SINK_HEIGHT (xvimagesink) <= 0)
- goto no_display_size;
-
- g_mutex_lock (xvimagesink->flow_lock);
- if (!xvimagesink->xwindow) {
- xvimagesink->xwindow = gst_xvimagesink_xwindow_new (xvimagesink,
- GST_VIDEO_SINK_WIDTH (xvimagesink),
- GST_VIDEO_SINK_HEIGHT (xvimagesink));
+ g_mutex_lock (xvimagesink->flow_lock);
+#ifdef GST_EXT_XV_ENHANCEMENT
+ if (!xvimagesink->xwindow && !xvimagesink->get_pixmap_cb) {
+ GST_DEBUG_OBJECT (xvimagesink, "xwindow is null and not multi-pixmaps usage case");
+#else
+ if (!xvimagesink->xwindow) {
+#endif
+ xvimagesink->xwindow = gst_xvimagesink_xwindow_new (xvimagesink,
+ GST_VIDEO_SINK_WIDTH (xvimagesink),
+ GST_VIDEO_SINK_HEIGHT (xvimagesink));
+ }
}
/* After a resize, we want to redraw the borders in case the new frame size
if ((xvimagesink->xvimage) &&
((im_format != xvimagesink->xvimage->im_format) ||
(video_width != xvimagesink->xvimage->width) ||
- (video_height != xvimagesink->xvimage->height))) {
+ (video_height != xvimagesink->xvimage->height)) &&
+ (!xvimagesink->subpicture)) {
GST_DEBUG_OBJECT (xvimagesink,
"old format %" GST_FOURCC_FORMAT ", new format %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (xvimagesink->xvimage->im_format),
xvimagesink->xvimage = NULL;
}
+#ifdef GST_EXT_XV_ENHANCEMENT
+ /* In case of starting player with connecting external display, we have to check status.
+ * It will be unconditionally executed. */
+ if(!xvimagesink->is_subpicture_format)
+ check_hdmi_connected(xvimagesink);
+#endif
g_mutex_unlock (xvimagesink->flow_lock);
return TRUE;
("Error calculating the output display ratio of the video."));
return FALSE;
}
+#ifdef GST_EXT_XV_ENHANCEMENT
}
+#endif
static GstStateChangeReturn
gst_xvimagesink_change_state (GstElement * element, GstStateChange transition)
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
+#ifdef GST_EXT_XV_ENHANCEMENT
+ GST_WARNING("NULL_TO_READY start");
+#endif /* GST_EXT_XV_ENHANCEMENT */
/* Initializing the XContext */
if (xvimagesink->xcontext == NULL) {
xcontext = gst_xvimagesink_xcontext_get (xvimagesink);
XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous);
gst_xvimagesink_update_colorbalance (xvimagesink);
gst_xvimagesink_manage_event_thread (xvimagesink);
+#ifdef GST_EXT_XV_ENHANCEMENT
+ GST_WARNING("NULL_TO_READY done");
+#endif /* GST_EXT_XV_ENHANCEMENT */
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
+#ifdef GST_EXT_XV_ENHANCEMENT
+ GST_WARNING("READY_TO_PAUSED start");
+#endif /* GST_EXT_XV_ENHANCEMENT */
g_mutex_lock (xvimagesink->pool_lock);
xvimagesink->pool_invalid = FALSE;
g_mutex_unlock (xvimagesink->pool_lock);
- break;
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
#ifdef GST_EXT_XV_ENHANCEMENT
- g_mutex_lock (xvimagesink->x_lock);
- atom_preemption = XInternAtom( xvimagesink->xcontext->disp,
- "_USER_WM_PORT_ATTRIBUTE_PREEMPTION", False );
- if (atom_preemption != None) {
- if (XvSetPortAttribute(xvimagesink->xcontext->disp,
- xvimagesink->xcontext->xv_port_id,
- atom_preemption, 1 ) != Success) {
- GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: preemption failed.\n", atom_preemption);
- }
- XSync (xvimagesink->xcontext->disp, FALSE);
- }
- g_mutex_unlock (xvimagesink->x_lock);
+ GST_WARNING("READY_TO_PAUSED done");
+#endif /* GST_EXT_XV_ENHANCEMENT */
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+#ifdef GST_EXT_XV_ENHANCEMENT
+ if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_PLAYING))
+ GST_WARNING("vconf set fail");
+ GST_WARNING("PAUSED_TO_PLAYING done");
+ xvimagesink->is_during_seek = FALSE;
+ xvimagesink->keep_external_fullscreen_prev = FALSE;
#endif /* GST_EXT_XV_ENHANCEMENT */
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
+#ifdef GST_EXT_XV_ENHANCEMENT
+ GST_WARNING("PAUSED_TO_READY start");
+#endif /* GST_EXT_XV_ENHANCEMENT */
g_mutex_lock (xvimagesink->pool_lock);
xvimagesink->pool_invalid = TRUE;
g_mutex_unlock (xvimagesink->pool_lock);
+#ifdef GST_EXT_XV_ENHANCEMENT
+#endif /* GST_EXT_XV_ENHANCEMENT */
break;
default:
break;
switch (transition) {
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
#ifdef GST_EXT_XV_ENHANCEMENT
- xvimagesink->rotate_changed = TRUE;
+ GST_WARNING("PLAYING_TO_PAUSED start");
+ g_mutex_lock (xvimagesink->flow_lock);
+ /* init displayed buffer count */
+ xvimagesink->displayed_buffer_count = 0;
+
g_mutex_lock (xvimagesink->x_lock);
- atom_preemption = XInternAtom( xvimagesink->xcontext->disp,
- "_USER_WM_PORT_ATTRIBUTE_PREEMPTION", False );
- if (atom_preemption != None) {
- if (XvSetPortAttribute(xvimagesink->xcontext->disp,
- xvimagesink->xcontext->xv_port_id,
- atom_preemption, 0 ) != Success) {
- GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: preemption failed.\n", atom_preemption);
- }
- XSync (xvimagesink->xcontext->disp, FALSE);
+ if ((xvimagesink->is_hided || xvimagesink->is_quick_panel_on || xvimagesink->is_multi_window) && _is_connected_to_external_display(xvimagesink) && !xvimagesink->keep_external_fullscreen_prev) {
+ GST_WARNING_OBJECT(xvimagesink, "release external display mode");
+ XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
+ xvimagesink->xwindow->win);
+ XSync(xvimagesink->xcontext->disp, FALSE);
+ xvimagesink->skip_frame_due_to_external_dev = TRUE;
+ }
+ if((xvimagesink->is_hided_subpicture || xvimagesink->is_quick_panel_on_subpicture || xvimagesink->is_multi_window_subpicture)
+ && xvimagesink->is_subpicture_format && xvimagesink->pixmap_for_subpicture) {
+ GST_WARNING_OBJECT(xvimagesink, "calling XvStopVideo() for %d port [pixmap : %p]", xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture);
+ XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture);
+ XSync(xvimagesink->xcontext->disp, FALSE);
}
g_mutex_unlock (xvimagesink->x_lock);
+ g_mutex_unlock (xvimagesink->flow_lock);
+ if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_PAUSED))
+ GST_WARNING("vconf set fail");
+ GST_WARNING("PLAYING_TO_PAUSED done");
#endif /* GST_EXT_XV_ENHANCEMENT */
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
+#ifdef GST_EXT_XV_ENHANCEMENT
+ GST_WARNING_OBJECT(xvimagesink, "PAUSED_TO_READY start - %d %d %d %p",
+ xvimagesink->is_zero_copy_format,
+ xvimagesink->enable_flush_buffer,
+ xvimagesink->secure_path,
+ xvimagesink->get_pixmap_cb);
+
+ if ((xvimagesink->enable_flush_buffer == FALSE ||
+ xvimagesink->secure_path == SECURE_PATH_ON) &&
+ xvimagesink->xcontext && xvimagesink->xwindow) {
+ GST_WARNING_OBJECT(xvimagesink, "Call XvStopVideo and remove last buffer");
+ g_mutex_lock(xvimagesink->x_lock);
+ XvStopVideo(xvimagesink->xcontext->disp,
+ xvimagesink->xcontext->xv_port_id,
+ xvimagesink->xwindow->win);
+ XSync(xvimagesink->xcontext->disp, FALSE);
+ g_mutex_unlock(xvimagesink->x_lock);
+ _remove_last_buffer(xvimagesink);
+ } else if (xvimagesink->is_zero_copy_format &&
+ xvimagesink->xvimage &&
+ xvimagesink->xvimage->xvimage &&
+ !xvimagesink->get_pixmap_cb) {
+ if (gst_xvimagesink_make_flush_buffer(xvimagesink)) {
+ int i = 0;
+ XV_DATA_PTR img_data = (XV_DATA_PTR) xvimagesink->xvimage->xvimage->data;
+ memset(img_data, 0x0, sizeof(XV_DATA));
+ XV_INIT_DATA(img_data);
+
+ img_data->bo[0] = xvimagesink->flush_buffer->bo[0];
+ img_data->bo[1] = xvimagesink->flush_buffer->bo[1];
+ img_data->bo[2] = xvimagesink->flush_buffer->bo[2];
+
+ gst_xvimagesink_xvimage_put(xvimagesink, xvimagesink->xvimage);
+
+ GST_WARNING_OBJECT(xvimagesink, "gst_xvimagesink_xvimage_put done");
+
+ /* check whether putimage is succeeded or not */
+ g_mutex_lock(xvimagesink->display_buffer_lock);
+
+ for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
+ if (xvimagesink->displaying_buffers[i].gem_name[0] > 0) {
+ if ((img_data->dmabuf_fd[0] > 0 &&
+ xvimagesink->displaying_buffers[i].dmabuf_fd[0] == img_data->dmabuf_fd[0] &&
+ xvimagesink->displaying_buffers[i].dmabuf_fd[1] == img_data->dmabuf_fd[1] &&
+ xvimagesink->displaying_buffers[i].dmabuf_fd[2] == img_data->dmabuf_fd[2]) ||
+ (img_data->bo[0] &&
+ xvimagesink->displaying_buffers[i].bo[0] == img_data->bo[0] &&
+ xvimagesink->displaying_buffers[i].bo[1] == img_data->bo[1] &&
+ xvimagesink->displaying_buffers[i].bo[2] == img_data->bo[2])) {
+ GST_WARNING_OBJECT(xvimagesink, "found flush buffer in displaying_buffers");
+ break;
+ }
+ }
+ }
+
+ if (i >= DISPLAYING_BUFFERS_MAX_NUM) {
+ GST_WARNING_OBJECT(xvimagesink, "flush buffer is not existed in displaying_buffers");
+ _release_flush_buffer(xvimagesink);
+ } else {
+ _remove_last_buffer(xvimagesink);
+ }
+
+ g_mutex_unlock(xvimagesink->display_buffer_lock);
+ }
+ }
+#endif /* GST_EXT_XV_ENHANCEMENT */
xvimagesink->fps_n = 0;
xvimagesink->fps_d = 1;
GST_VIDEO_SINK_WIDTH (xvimagesink) = 0;
GST_VIDEO_SINK_HEIGHT (xvimagesink) = 0;
+#ifdef GST_EXT_XV_ENHANCEMENT
+ GST_WARNING("PAUSED_TO_READY done");
+#endif /* GST_EXT_XV_ENHANCEMENT */
break;
case GST_STATE_CHANGE_READY_TO_NULL:
+#ifdef GST_EXT_XV_ENHANCEMENT
+ GST_WARNING("READY_TO_NULL start");
+#endif /* GST_EXT_XV_ENHANCEMENT */
gst_xvimagesink_reset (xvimagesink);
+#ifdef GST_EXT_XV_ENHANCEMENT
+ /* close drm */
+ drm_fini(xvimagesink);
+ /* init displaying_buffer_count */
+ xvimagesink->displaying_buffer_count = 0;
+ GST_WARNING("READY_TO_NULL done");
+#endif /* GST_EXT_XV_ENHANCEMENT */
break;
default:
break;
}
}
+#ifdef GST_EXT_ENABLE_HEVC
+static void
+gst_xvimagesink_combine_i420_scmn_data(GstXvImageSink *xvimagesink, GstBuffer *buf)
+{
+ unsigned int outsize = 0;
+ unsigned char *temp_outbuf = xvimagesink->xvimage->xvimage->data;
+ int cnt = 0, j = 0;
+ unsigned char *temp_imgb;
+ SCMN_IMGB *imgb = NULL;
+ int stride, w, h, i;
+
+ GST_DEBUG("Begin");
+ imgb = (SCMN_IMGB *)GST_BUFFER_DATA(buf);
+ if(imgb == NULL || imgb->a[0] == NULL)
+ {
+ return;
+ }
+
+ stride = GST_ROUND_UP_4 (imgb->w[0]);
+ h = imgb->h[0];
+ w = imgb->w[0];
+ /*Y plane copy */
+ for (i = 0; i < h; i++)
+ {
+ memcpy (temp_outbuf + i * stride, imgb->a[0] + i * imgb->s[0], w);
+ }
+
+ temp_outbuf += GST_ROUND_UP_4 (imgb->w[0]) * GST_ROUND_UP_2 (imgb->h[0]);
+
+ stride = GST_ROUND_UP_4 (GST_ROUND_UP_2 (imgb->w[0]) / 2);
+ h = GST_ROUND_UP_2 (imgb->h[0]) / 2;
+ w = GST_ROUND_UP_2 (imgb->w[0]) / 2;
+ /* Cb plane copy */
+ for (i = 0; i < h; i++)
+ {
+ memcpy (temp_outbuf + i * stride, imgb->a[1] + i * imgb->s[1], w);
+ }
+
+ temp_outbuf += GST_ROUND_UP_4 (GST_ROUND_UP_2 (imgb->w[0]) / 2) * (GST_ROUND_UP_2 (imgb->h[0]) / 2);
+ /* Same stride, height, width as above */
+ /* Cr plane copy */
+ for (i = 0; i < h; i++)
+ {
+ memcpy (temp_outbuf + i * stride, imgb->a[2] + i * imgb->s[2], w);
+ }
+
+ outsize = imgb->w[0] * imgb->h[0]* 3 >> 1;
+ xvimagesink->xvimage->size = MIN(outsize, xvimagesink->xvimage->size);
+
+ GST_DEBUG("End");
+}
+#endif
+
+#ifdef GST_EXT_XV_ENHANCEMENT
+static gboolean gst_xvimagesink_make_flush_buffer(GstXvImageSink *xvimagesink)
+{
+ GstXvImageFlushBuffer *flush_buffer = NULL;
+ GstXvImageDisplayingBuffer *display_buffer = NULL;
+ tbm_bo bo = NULL;
+ int size = 0;
+ int i = 0;
+ int ret = 0;
+
+ if (xvimagesink == NULL) {
+ GST_ERROR("handle is NULL");
+ return FALSE;
+ }
+
+ if (xvimagesink->last_added_buffer_index == -1) {
+ GST_WARNING_OBJECT(xvimagesink, "there is no remained buffer");
+ return FALSE;
+ }
+
+ if (xvimagesink->drm_fd < 0 || xvimagesink->bufmgr == NULL) {
+ GST_ERROR_OBJECT(xvimagesink, "drm fd[%d] or bufmgr[%p] is invalid",
+ xvimagesink->drm_fd, xvimagesink->bufmgr);
+ return FALSE;
+ }
+
+ flush_buffer = (GstXvImageFlushBuffer *)malloc(sizeof(GstXvImageFlushBuffer));
+ if (flush_buffer == NULL) {
+ GST_ERROR_OBJECT(xvimagesink, "GstXvImageFlushBuffer alloc failed");
+ return FALSE;
+ }
+
+ memset(flush_buffer, 0x0, sizeof(GstXvImageFlushBuffer));
+
+ display_buffer = &(xvimagesink->displaying_buffers[xvimagesink->last_added_buffer_index]);
+ GST_WARNING_OBJECT(xvimagesink, "last_added_buffer_index [%d]",
+ xvimagesink->last_added_buffer_index);
+
+ for (i = 0 ; i < XV_BUF_PLANE_NUM ; i++) {
+ if (display_buffer->bo[i]) {
+ tbm_bo_handle vaddr_src;
+ tbm_bo_handle vaddr_dst;
+
+ /* get bo size */
+ size = tbm_bo_size(display_buffer->bo[i]);
+
+ /* alloc bo */
+ bo = tbm_bo_alloc(xvimagesink->bufmgr, size, TBM_BO_DEFAULT);
+ if (bo == NULL) {
+ GST_ERROR_OBJECT(xvimagesink, "bo alloc[%d] failed", size);
+ goto FLUSH_BUFFER_FAILED;
+ }
+
+ GST_WARNING_OBJECT(xvimagesink, "[%d] bo %p, size %d alloc done", i, bo, size);
+
+ flush_buffer->gem_name[i] = tbm_bo_export(bo);
+ flush_buffer->bo[i] = bo;
+
+ /* get virtual address */
+ vaddr_src = tbm_bo_map(display_buffer->bo[i], TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE);
+ vaddr_dst = tbm_bo_map(bo, TBM_DEVICE_CPU, TBM_OPTION_READ|TBM_OPTION_WRITE);
+ if (vaddr_src.ptr == NULL || vaddr_dst.ptr == NULL) {
+ GST_WARNING_OBJECT(xvimagesink, "get vaddr failed src %p, dst %p",
+ vaddr_src.ptr, vaddr_dst.ptr);
+ if (vaddr_src.ptr) {
+ tbm_bo_unmap(display_buffer->bo[i]);
+ }
+ if (vaddr_dst.ptr) {
+ tbm_bo_unmap(bo);
+ }
+ goto FLUSH_BUFFER_FAILED;
+ }
+
+ /* copy buffer */
+ memcpy(vaddr_dst.ptr, vaddr_src.ptr, size);
+
+ tbm_bo_unmap(display_buffer->bo[i]);
+ tbm_bo_unmap(bo);
+
+ GST_WARNING_OBJECT(xvimagesink, "[%d] copy done", i);
+
+ xvimagesink->flush_buffer = flush_buffer;
+
+ ret = TRUE;
+ }
+ }
+
+ return ret;
+
+FLUSH_BUFFER_FAILED:
+ if (flush_buffer) {
+ for (i = 0 ; i < XV_BUF_PLANE_NUM ; i++) {
+ if (flush_buffer->bo[i]) {
+ tbm_bo_unref(flush_buffer->bo[i]);
+ flush_buffer->bo[i] = NULL;
+ }
+ }
+ free(flush_buffer);
+ flush_buffer = NULL;
+ }
+
+ return FALSE;
+}
+#endif /* GST_EXT_XV_ENHANCEMENT */
+
+
static GstFlowReturn
gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
{
GstXvImageSink *xvimagesink;
#ifdef GST_EXT_XV_ENHANCEMENT
- XV_PUTIMAGE_DATA_PTR img_data = NULL;
+ XV_DATA_PTR img_data = NULL;
SCMN_IMGB *scmn_imgb = NULL;
gint format = 0;
+ gboolean ret = FALSE;
+ int res = -1;
+ int (*handler) (Display *, XErrorEvent *) = NULL;
+ Atom atom_overlay;
#endif /* GST_EXT_XV_ENHANCEMENT */
xvimagesink = GST_XVIMAGESINK (vsink);
put the ximage which is in the PRIVATE pointer */
if (GST_IS_XVIMAGE_BUFFER (buf)) {
GST_LOG_OBJECT (xvimagesink, "fast put of bufferpool buffer %p", buf);
+#ifdef GST_EXT_XV_ENHANCEMENT
+ xvimagesink->xid_updated = FALSE;
+#endif /* GST_EXT_XV_ENHANCEMENT */
if (!gst_xvimagesink_xvimage_put (xvimagesink,
GST_XVIMAGE_BUFFER_CAST (buf)))
goto no_window;
"slow copy into bufferpool buffer %p", buf);
/* Else we have to copy the data into our private image, */
/* if we have one... */
- if (!xvimagesink->xvimage) {
- GST_DEBUG_OBJECT (xvimagesink, "creating our xvimage");
+#ifdef GST_EXT_XV_ENHANCEMENT
+ g_mutex_lock (xvimagesink->flow_lock);
+ if (xvimagesink->skip_frame_due_to_external_dev) {
+ GST_WARNING_OBJECT( xvimagesink, "skip_frame_due_to_external_dev is TRUE. so skip show frame..." );
+ xvimagesink->skip_frame_due_to_external_dev = FALSE;
+ g_mutex_unlock (xvimagesink->flow_lock);
+ return GST_FLOW_OK;
+ }
+
+#endif /* GST_EXT_XV_ENHANCEMENT */
+ if (!xvimagesink->xvimage
+#ifdef GST_EXT_XV_ENHANCEMENT
+ && !xvimagesink->is_subpicture_format
+#endif
+ ) {
+ GST_DEBUG_OBJECT (xvimagesink, "creating our xvimage");
#ifdef GST_EXT_XV_ENHANCEMENT
format = gst_xvimagesink_get_format_from_caps(xvimagesink, GST_BUFFER_CAPS(buf));
switch (format) {
case GST_MAKE_FOURCC('S', 'T', '1', '2'):
case GST_MAKE_FOURCC('S', 'N', '1', '2'):
+ case GST_MAKE_FOURCC('S', 'N', '2', '1'):
case GST_MAKE_FOURCC('S', '4', '2', '0'):
case GST_MAKE_FOURCC('S', 'U', 'Y', '2'):
case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'):
case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'):
+ case GST_MAKE_FOURCC('I', 'T', 'L', 'V'):
+ case GST_MAKE_FOURCC('S', 'R', '3', '2'):
+ case GST_MAKE_FOURCC('S', 'V', '1', '2'):
+ xvimagesink->is_zero_copy_format = TRUE;
scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
if(scmn_imgb == NULL) {
GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." );
+ g_mutex_unlock (xvimagesink->flow_lock);
return GST_FLOW_OK;
}
GST_WARNING_OBJECT(xvimagesink, "invalid size[caps:%dx%d,aligned:%dx%d]. Skip this buffer...",
xvimagesink->video_width, xvimagesink->video_height,
scmn_imgb->s[0], scmn_imgb->e[0]);
+ g_mutex_unlock (xvimagesink->flow_lock);
return GST_FLOW_OK;
}
xvimagesink->aligned_width, xvimagesink->aligned_height);
break;
default:
+ xvimagesink->is_zero_copy_format = FALSE;
GST_INFO_OBJECT(xvimagesink, "Use original width,height of caps");
break;
}
+
+ GST_INFO("zero copy format - %d", xvimagesink->is_zero_copy_format);
#endif /* GST_EXT_XV_ENHANCEMENT */
xvimagesink->xvimage = gst_xvimagesink_xvimage_new (xvimagesink,
/* The create method should have posted an informative error */
goto no_image;
+#ifdef GST_EXT_XV_ENHANCEMENT
+ if ((xvimagesink->is_zero_copy_format == FALSE &&
+ xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf)) ||
+ (xvimagesink->is_zero_copy_format &&
+ xvimagesink->xvimage->size < sizeof(SCMN_IMGB))) {
+#else /* GST_EXT_XV_ENHANCEMENT */
if (xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf)) {
+#endif /* GST_EXT_XV_ENHANCEMENT */
GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
("Failed to create output image buffer of %dx%d pixels",
xvimagesink->xvimage->width, xvimagesink->xvimage->height),
}
#ifdef GST_EXT_XV_ENHANCEMENT
- switch (xvimagesink->xvimage->im_format) {
+ if (xvimagesink->is_zero_copy_format) {
/* Cases for specified formats of Samsung extension */
- case GST_MAKE_FOURCC('S', 'T', '1', '2'):
- case GST_MAKE_FOURCC('S', 'N', '1', '2'):
- case GST_MAKE_FOURCC('S', '4', '2', '0'):
- case GST_MAKE_FOURCC('S', 'U', 'Y', '2'):
- case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'):
- case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'):
- case GST_MAKE_FOURCC('I', 'T', 'L', 'V'):
- {
- GST_DEBUG("Samsung extension display format activated. fourcc:%d,display mode:%d,Rotate angle:%d",
- xvimagesink->xvimage->im_format, xvimagesink->display_mode, xvimagesink->rotate_angle);
+ GST_LOG("Samsung EXT format - fourcc:%c%c%c%c, display mode:%d, Rotate angle:%d",
+ xvimagesink->xvimage->im_format, xvimagesink->xvimage->im_format>>8,
+ xvimagesink->xvimage->im_format>>16, xvimagesink->xvimage->im_format>>24,
+ xvimagesink->display_mode, xvimagesink->rotate_angle);
if (xvimagesink->xvimage->xvimage->data) {
- img_data = (XV_PUTIMAGE_DATA_PTR) xvimagesink->xvimage->xvimage->data;
- XV_PUTIMAGE_INIT_DATA(img_data);
+ int i = 0;
+ img_data = (XV_DATA_PTR) xvimagesink->xvimage->xvimage->data;
+ memset(img_data, 0x0, sizeof(XV_DATA));
+ XV_INIT_DATA(img_data);
scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buf);
if (scmn_imgb == NULL) {
GST_DEBUG_OBJECT( xvimagesink, "scmn_imgb is NULL. Skip xvimage put..." );
+ g_mutex_unlock (xvimagesink->flow_lock);
return GST_FLOW_OK;
}
- img_data->YPhyAddr = (unsigned int)scmn_imgb->p[0];
- img_data->CbPhyAddr = (unsigned int)scmn_imgb->p[1];
- img_data->CrPhyAddr = (unsigned int)scmn_imgb->p[2];
+ /* Keep the vaddr of current image for copying last image */
+ if (scmn_imgb->buf_share_method != BUF_SHARE_METHOD_FLUSH_BUFFER) {
+ for(i = 0; i < SCMN_IMGB_MAX_PLANE; i++) {
+ xvimagesink->last_image_vaddr[i] = (unsigned int)scmn_imgb->a[i];
+ }
+ GST_LOG("Vaddr - YBuf[0x%x], CbBuf[0x%x], CrBuf[0x%x]",
+ xvimagesink->last_image_vaddr[0], xvimagesink->last_image_vaddr[1], xvimagesink->last_image_vaddr[2]);
+ }
+
+ if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_PADDR) {
+ img_data->YBuf = (unsigned int)scmn_imgb->p[0];
+ img_data->CbBuf = (unsigned int)scmn_imgb->p[1];
+ img_data->CrBuf = (unsigned int)scmn_imgb->p[2];
+ img_data->BufType = XV_BUF_TYPE_LEGACY;
+
+ GST_DEBUG("YBuf[0x%x], CbBuf[0x%x], CrBuf[0x%x]",
+ img_data->YBuf, img_data->CbBuf, img_data->CrBuf );
+ } else if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FD ||
+ scmn_imgb->buf_share_method == BUF_SHARE_METHOD_TIZEN_BUFFER) {
+ gboolean do_set_secure = FALSE;
+
+ /* open drm to use gem */
+ if (xvimagesink->drm_fd < 0) {
+ drm_init(xvimagesink);
+ }
+
+ if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FD) {
+ /* keep dma-buf fd. fd will be converted in gst_xvimagesink_xvimage_put */
+ img_data->dmabuf_fd[0] = scmn_imgb->dmabuf_fd[0];
+ img_data->dmabuf_fd[1] = scmn_imgb->dmabuf_fd[1];
+ img_data->dmabuf_fd[2] = scmn_imgb->dmabuf_fd[2];
+ img_data->BufType = XV_BUF_TYPE_DMABUF;
+ GST_DEBUG("DMABUF fd %u,%u,%u", img_data->dmabuf_fd[0], img_data->dmabuf_fd[1], img_data->dmabuf_fd[2]);
+ } else {
+ /* keep bo. bo will be converted in gst_xvimagesink_xvimage_put */
+ img_data->bo[0] = scmn_imgb->bo[0];
+ img_data->bo[1] = scmn_imgb->bo[1];
+ img_data->bo[2] = scmn_imgb->bo[2];
+ GST_DEBUG("TBM bo %p %p %p", img_data->bo[0], img_data->bo[1], img_data->bo[2]);
+ }
+
+ /* check secure contents path */
+ if (scmn_imgb->tz_enable) {
+ if (xvimagesink->secure_path != SECURE_PATH_ON) {
+ xvimagesink->secure_path = SECURE_PATH_ON;
+ do_set_secure = TRUE;
+ }
+ } else {
+ if (xvimagesink->secure_path != SECURE_PATH_OFF) {
+ xvimagesink->secure_path = SECURE_PATH_OFF;
+ do_set_secure = TRUE;
+ }
+ }
+ static gboolean is_exist = FALSE;
+ gchar *attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_SECURE");
+ is_exist = check_supportable_port_attr(xvimagesink, attr_name);
+ g_free(attr_name);
+
+ if (do_set_secure && is_exist) {
+ Atom atom_secure = None;
+ g_mutex_lock (xvimagesink->x_lock);
+ atom_secure = XInternAtom(xvimagesink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_SECURE", False);
+ if (atom_secure != None) {
+ if (XvSetPortAttribute(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_secure, xvimagesink->secure_path) != Success) {
+ GST_ERROR_OBJECT(xvimagesink, "%d: XvSetPortAttribute: secure setting failed.", atom_secure);
+ } else {
+ GST_WARNING_OBJECT(xvimagesink, "set contents path [%d] (0:NORMAL, 1:SECURE)", xvimagesink->secure_path);
+ }
+ XSync (xvimagesink->xcontext->disp, FALSE);
+ } else {
+ GST_ERROR_OBJECT(xvimagesink, "_USER_WM_PORT_ATTRIBUTE_SECURE is not existed");
+ }
+ g_mutex_unlock (xvimagesink->x_lock);
+ }
+
+ is_exist = FALSE;
+ attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL");
+ is_exist = check_supportable_port_attr(xvimagesink, attr_name);
+ g_free(attr_name);
+
- GST_LOG_OBJECT(xvimagesink, "Ypaddr[%p],CbPaddr[%p],CrPaddr[%p]",
- img_data->YPhyAddr, img_data->CbPhyAddr, img_data->CrPhyAddr );
+ if (xvimagesink->drm_level && is_exist) {
+ Atom atom_drm = None;
+ g_mutex_lock (xvimagesink->x_lock);
+ atom_drm = XInternAtom( xvimagesink->xcontext->disp,
+ "_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL", False);
+ if (atom_drm != None) {
+ GST_INFO_OBJECT(xvimagesink, "DRM LEVEL -> 1");
+ if (XvSetPortAttribute(xvimagesink->xcontext->disp,
+ xvimagesink->xcontext->xv_port_id,
+ atom_drm, xvimagesink->drm_level ) != Success) {
+ GST_WARNING_OBJECT( xvimagesink, "Set DRM LEVEL 1 failed" );
+ }
+ XSync (xvimagesink->xcontext->disp, FALSE);
+ g_mutex_unlock (xvimagesink->x_lock);
+ xvimagesink->drm_level = DRM_LEVEL_0;
+ }
+ }
- img_data->RotAngle = xvimagesink->rotate_angle;
- img_data->VideoMode = xvimagesink->display_mode;
+ /* set current buffer */
+ xvimagesink->xvimage->current_buffer = buf;
+ } else if (scmn_imgb->buf_share_method == BUF_SHARE_METHOD_FLUSH_BUFFER) {
+ /* Flush Buffer, we are going to push a new buffer for recieving return buffer event from X */
+ GST_WARNING_OBJECT(xvimagesink, "BUF_SHARE_METHOD_FLUSH_BUFFER case");
+ if (gst_xvimagesink_make_flush_buffer(xvimagesink)) {
+ img_data->bo[0] = xvimagesink->flush_buffer->bo[0];
+ img_data->bo[1] = xvimagesink->flush_buffer->bo[1];
+ img_data->bo[2] = xvimagesink->flush_buffer->bo[2];
+ } else {
+ g_mutex_unlock(xvimagesink->flow_lock);
+ return GST_FLOW_OK;
+ }
+ } else {
+ GST_WARNING("unknown buf_share_method type [%d]. skip xvimage put...",
+ scmn_imgb->buf_share_method);
+ g_mutex_unlock (xvimagesink->flow_lock);
+ return GST_FLOW_OK;
+ }
} else {
GST_WARNING_OBJECT( xvimagesink, "xvimage->data is NULL. skip xvimage put..." );
+ g_mutex_unlock (xvimagesink->flow_lock);
return GST_FLOW_OK;
}
- break;
+ } else if (xvimagesink->is_subpicture_format) {
+ GC gc;
+ xvimagesink->pixmap_for_subpicture = (Pixmap)GST_BUFFER_DATA(buf);
+ if(!xvimagesink->pixmap_for_subpicture) {
+ GST_ERROR("no pixmap");
+ g_mutex_unlock (xvimagesink->flow_lock);
+ return GST_FLOW_OK;
}
- default:
+ if(xvimagesink->video_width!=xvimagesink->external_width || xvimagesink->video_height!=xvimagesink->external_height) {
+ GST_ERROR("pixmap's size and current resolution are different");
+ g_mutex_unlock (xvimagesink->flow_lock);
+ return GST_FLOW_OK;
+ }
+ gc = XCreateGC (xvimagesink->xcontext->disp, xvimagesink->pixmap_for_subpicture, 0, 0);
+
+ GST_WARNING_OBJECT(xvimagesink, "xvimagesink pixmap ID : %p, port : %ld, GC : %p", xvimagesink->pixmap_for_subpicture,
+ xvimagesink->xcontext->xv_port_id, gc);
+
+ /* set error handler */
+ error_caught = FALSE;
+ handler = XSetErrorHandler(gst_xvimagesink_handle_xerror);
+
+ if(!xvimagesink->set_overlay_for_subpicture_just_once)
{
- GST_DEBUG("Normal format activated. fourcc = %d", xvimagesink->xvimage->im_format);
- memcpy (xvimagesink->xvimage->xvimage->data,
- GST_BUFFER_DATA (buf),
- MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size));
- break;
+ GST_LOG("setting attribute overlay");
+ atom_overlay = XInternAtom (xvimagesink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_OVERLAY", FALSE);
+ XvSetPortAttribute (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_overlay, 1);
+ XSync (xvimagesink->xcontext->disp, FALSE);
+ xvimagesink->set_overlay_for_subpicture_just_once = TRUE;
+ }
+ res = XvGetStill(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id,
+ xvimagesink->pixmap_for_subpicture, gc, 0, 0, xvimagesink->external_width, xvimagesink->external_height,
+ 0, 0, xvimagesink->external_width, xvimagesink->external_height);
+ XSync (xvimagesink->xcontext->disp, FALSE);
+
+ GST_WARNING_OBJECT(xvimagesink, "BUFFER TS=%" GST_TIME_FORMAT ", DUR=%" GST_TIME_FORMAT ", SIZE=%d\n",
+ GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buf)),
+ GST_TIME_ARGS(GST_BUFFER_DURATION(buf)),
+ GST_BUFFER_SIZE(buf));
+ if(gc) {
+ GST_DEBUG("FreeGC");
+ XFreeGC (xvimagesink->xcontext->disp, gc);
}
+ if (error_caught)
+ GST_WARNING_OBJECT(xvimagesink, "XvGetStill error");
+ else
+ GST_WARNING_OBJECT(xvimagesink, "XvGetStill %s ==> (width : %d, height : %d)", res == 0 ? "SUCCESS" : "FAIL", xvimagesink->external_width, xvimagesink->external_height);
+
+ /* Reset error handler */
+ if (handler) {
+ error_caught = FALSE;
+ XSetErrorHandler (handler);
+ }
+ } else {
+ GST_DEBUG("Normal format activated. fourcc = %d", xvimagesink->xvimage->im_format);
+
+#ifdef GST_EXT_ENABLE_HEVC
+ if(xvimagesink->need_combine_data == 1)
+ {
+ gst_xvimagesink_combine_i420_scmn_data(xvimagesink, buf);
+ }
+ else
+#endif
+ {
+ memcpy (xvimagesink->xvimage->xvimage->data,
+ GST_BUFFER_DATA (buf),
+ MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size));
+ }
+ }
+
+ g_mutex_unlock (xvimagesink->flow_lock);
+ ret = gst_xvimagesink_xvimage_put(xvimagesink, xvimagesink->xvimage);
+ if (!ret && !xvimagesink->is_subpicture_format) {
+ goto no_window;
}
#else /* GST_EXT_XV_ENHANCEMENT */
memcpy (xvimagesink->xvimage->xvimage->data,
GST_BUFFER_DATA (buf),
MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size));
-#endif /* GST_EXT_XV_ENHANCEMENT */
if (!gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage))
goto no_window;
+#endif /* GST_EXT_XV_ENHANCEMENT */
}
return GST_FLOW_OK;
{
/* No image available. That's very bad ! */
GST_WARNING_OBJECT (xvimagesink, "could not create image");
+#ifdef GST_EXT_XV_ENHANCEMENT
+ g_mutex_unlock (xvimagesink->flow_lock);
+#endif
return GST_FLOW_ERROR;
}
no_window:
gst_xvimagesink_event (GstBaseSink * sink, GstEvent * event)
{
GstXvImageSink *xvimagesink = GST_XVIMAGESINK (sink);
+ if(GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT)
+ {
+ if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_SEEK))
+ GST_WARNING("vconf set fail");
+ }
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_TAG:{
gst_tag_list_get_string (l, GST_TAG_TITLE, &title);
if (title) {
+#ifdef GST_EXT_XV_ENHANCEMENT
+ if (!xvimagesink->get_pixmap_cb) {
+#endif
GST_DEBUG_OBJECT (xvimagesink, "got tags, title='%s'", title);
gst_xvimagesink_xwindow_set_title (xvimagesink, xvimagesink->xwindow,
title);
g_free (title);
+#ifdef GST_EXT_XV_ENHANCEMENT
+ }
+#endif
+ }
+ break;
+ }
+#ifdef GST_EXT_XV_ENHANCEMENT
+ case GST_EVENT_FLUSH_START:
+ GST_DEBUG_OBJECT (xvimagesink, "flush start");
+ break;
+ case GST_EVENT_FLUSH_STOP:
+ GST_DEBUG_OBJECT (xvimagesink, "flush stop");
+ xvimagesink->is_during_seek = TRUE;
+ break;
+ case GST_EVENT_CUSTOM_DOWNSTREAM:
+ {
+ const GstStructure *st = NULL;
+ st = gst_event_get_structure (event);
+ if(!st) {
+ GST_WARNING_OBJECT (xvimagesink, "could not get structure for custom downstream event");
+ } else {
+ if (gst_structure_has_name (st, "Content_Is_DRM_Playready")) {
+ GST_INFO_OBJECT (xvimagesink, "got a event for DRM playready");
+ xvimagesink->drm_level = DRM_LEVEL_1;
+ if (xvimagesink->drm_level && xvimagesink->xcontext) {
+ static gboolean is_exist = FALSE;
+ gchar *attr_name = g_strdup("_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL");
+ is_exist = check_supportable_port_attr(xvimagesink, attr_name);
+ g_free(attr_name);
+
+ if(is_exist)
+ {
+ Atom atom_drm = None;
+ g_mutex_lock (xvimagesink->x_lock);
+ atom_drm = XInternAtom( xvimagesink->xcontext->disp,
+ "_USER_WM_PORT_ATTRIBUTE_DRM_LEVEL", False);
+ if (atom_drm != None) {
+ GST_INFO_OBJECT(xvimagesink, "DRM LEVEL -> 1");
+ if (XvSetPortAttribute(xvimagesink->xcontext->disp,
+ xvimagesink->xcontext->xv_port_id,
+ atom_drm, xvimagesink->drm_level ) != Success) {
+ GST_WARNING_OBJECT( xvimagesink, "Set DRM LEVEL 1 failed" );
+ }
+ XSync (xvimagesink->xcontext->disp, FALSE);
+ xvimagesink->drm_level = DRM_LEVEL_0;
+ }
+ g_mutex_unlock (xvimagesink->x_lock);
+ }
+ }
+ }
}
break;
}
+ case GST_EVENT_EOS:
+ xvimagesink->eos_received = TRUE;
+ GST_DEBUG_OBJECT(xvimagesink, "got eos");
+ break;
+ case GST_EVENT_NEWSEGMENT:
+ xvimagesink->eos_received = FALSE;
+ GST_DEBUG_OBJECT(xvimagesink, "got newsegment event");
+ break;
+#endif
default:
break;
}
}
if (!xvimage) {
+#ifdef GST_EXT_XV_ENHANCEMENT
+ /* init aligned size */
+ xvimagesink->aligned_width = 0;
+ xvimagesink->aligned_height = 0;
+#endif /* GST_EXT_XV_ENHANCEMENT */
+
/* We found no suitable image in the pool. Creating... */
GST_DEBUG_OBJECT (xvimagesink, "no usable image in pool, creating xvimage");
xvimage = gst_xvimagesink_xvimage_new (xvimagesink, intersection);
iface->send_event = gst_xvimagesink_navigation_send_event;
}
+#ifdef GST_EXT_XV_ENHANCEMENT
+static void
+gst_xvimagesink_set_pixmap_handle (GstXOverlay * overlay, guintptr id)
+{
+ XID pixmap_id = id;
+ int i = 0;
+ GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
+ GstXPixmap *xpixmap = NULL;
+ int (*handler) (Display *, XErrorEvent *);
+
+ g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
+
+ if (xvimagesink->subpicture)
+ return;
+
+ /* If the element has not initialized the X11 context try to do so */
+ if (!xvimagesink->xcontext && !(xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink))) {
+ /* we have thrown a GST_ELEMENT_ERROR now */
+ return;
+ }
+
+ gst_xvimagesink_update_colorbalance (xvimagesink);
+
+ GST_DEBUG_OBJECT( xvimagesink, "pixmap id : %d", pixmap_id );
+
+ /* if the returned pixmap_id is 0, set current pixmap index to -2 to skip putImage() */
+ if (pixmap_id == 0) {
+ xvimagesink->current_pixmap_idx = -2;
+ return;
+ }
+
+ g_mutex_lock (xvimagesink->x_lock);
+
+ for (i = 0; i < MAX_PIXMAP_NUM; i++) {
+ if (!xvimagesink->xpixmap[i]) {
+ Window root_window;
+ int cur_win_x = 0;
+ int cur_win_y = 0;
+ unsigned int cur_win_width = 0;
+ unsigned int cur_win_height = 0;
+ unsigned int cur_win_border_width = 0;
+ unsigned int cur_win_depth = 0;
+
+ GST_INFO_OBJECT( xvimagesink, "xpixmap[%d] is empty, create it with pixmap_id(%d)", i, pixmap_id );
+
+ xpixmap = g_new0 (GstXPixmap, 1);
+ if (xpixmap) {
+ xpixmap->pixmap = pixmap_id;
+
+ /* Get root window and size of current window */
+ XGetGeometry(xvimagesink->xcontext->disp, xpixmap->pixmap, &root_window,
+ &cur_win_x, &cur_win_y, /* relative x, y */
+ &cur_win_width, &cur_win_height,
+ &cur_win_border_width, &cur_win_depth);
+ if (!cur_win_width || !cur_win_height) {
+ GST_INFO_OBJECT( xvimagesink, "cur_win_width(%d) or cur_win_height(%d) is null..", cur_win_width, cur_win_height );
+ g_mutex_unlock (xvimagesink->x_lock);
+ return;
+ }
+ xpixmap->width = cur_win_width;
+ xpixmap->height = cur_win_height;
+
+ if (!xvimagesink->render_rect.w)
+ xvimagesink->render_rect.w = cur_win_width;
+ if (!xvimagesink->render_rect.h)
+ xvimagesink->render_rect.h = cur_win_height;
+
+ /* Setting an error handler to catch failure */
+ error_caught = FALSE;
+ handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
+
+ /* Create a GC */
+ xpixmap->gc = XCreateGC (xvimagesink->xcontext->disp, xpixmap->pixmap, 0, NULL);
+
+ XSync(xvimagesink->xcontext->disp, FALSE);
+ if (error_caught) {
+ GST_ERROR_OBJECT(xvimagesink, "XCreateGC failed [gc:0x%x, pixmap id:%d]", xpixmap->gc, xpixmap->pixmap);
+ }
+ if (handler) {
+ error_caught = FALSE;
+ XSetErrorHandler (handler);
+ }
+
+ xvimagesink->xpixmap[i] = xpixmap;
+ xvimagesink->current_pixmap_idx = i;
+ } else {
+ GST_ERROR("failed to create xpixmap errno: %d", errno);
+ }
+
+ g_mutex_unlock (xvimagesink->x_lock);
+ return;
+
+ } else if (xvimagesink->xpixmap[i]->pixmap == pixmap_id) {
+ GST_DEBUG_OBJECT( xvimagesink, "found xpixmap[%d]->pixmap : %d", i, pixmap_id );
+ xvimagesink->current_pixmap_idx = i;
+
+ g_mutex_unlock (xvimagesink->x_lock);
+ return;
+
+ } else {
+ continue;
+ }
+ }
+
+ GST_ERROR_OBJECT( xvimagesink, "could not find the pixmap id(%d) in xpixmap array", pixmap_id );
+ xvimagesink->current_pixmap_idx = -1;
+
+ g_mutex_unlock (xvimagesink->x_lock);
+ return;
+}
+#endif /* GST_EXT_XV_ENHANCEMENT */
+
static void
gst_xvimagesink_set_window_handle (GstXOverlay * overlay, guintptr id)
{
XID xwindow_id = id;
GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
GstXWindow *xwindow = NULL;
+#ifdef GST_EXT_XV_ENHANCEMENT
+ GstState current_state = GST_STATE_NULL;
+ int (*handler) (Display *, XErrorEvent *);
+#endif /* GST_EXT_XV_ENHANCEMENT */
g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
g_mutex_lock (xvimagesink->flow_lock);
#ifdef GST_EXT_XV_ENHANCEMENT
- GST_INFO_OBJECT( xvimagesink, "ENTER, id : %d", xwindow_id );
+ gst_element_get_state(GST_ELEMENT(xvimagesink), ¤t_state, NULL, 0);
+ GST_WARNING_OBJECT(xvimagesink, "ENTER, id : %d, current state : %d",
+ xwindow_id, current_state);
#endif /* GST_EXT_XV_ENHANCEMENT */
/* If we already use that window return */
/* Set the event we want to receive and create a GC */
g_mutex_lock (xvimagesink->x_lock);
- XGetWindowAttributes (xvimagesink->xcontext->disp, xwindow->win, &attr);
+ if(!xvimagesink->is_pixmap)
+ XGetWindowAttributes (xvimagesink->xcontext->disp, xwindow->win, &attr);
xwindow->width = attr.width;
xwindow->height = attr.height;
xvimagesink->render_rect.h = attr.height;
}
if (xvimagesink->handle_events) {
+#ifdef GST_EXT_XV_ENHANCEMENT
+ XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xcontext->root, StructureNotifyMask | SubstructureNotifyMask);
+ XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
+ StructureNotifyMask | PointerMotionMask | KeyPressMask |
+ KeyReleaseMask | PropertyChangeMask);
+#else
XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask |
StructureNotifyMask | PointerMotionMask | KeyPressMask |
KeyReleaseMask);
- }
+#endif
+ }
+#ifdef GST_EXT_XV_ENHANCEMENT
+ /* Setting an error handler to catch failure */
+ error_caught = FALSE;
+ handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
+#endif
xwindow->gc = XCreateGC (xvimagesink->xcontext->disp,
xwindow->win, 0, NULL);
+#ifdef GST_EXT_XV_ENHANCEMENT
+ XSync(xvimagesink->xcontext->disp, FALSE);
+ if (error_caught) {
+ GST_ERROR_OBJECT(xvimagesink, "XCreateGC failed [gc:0x%x, xid:%d]", xwindow->gc, xwindow->win);
+ }
+ if (handler) {
+ error_caught = FALSE;
+ XSetErrorHandler (handler);
+ }
+#endif
g_mutex_unlock (xvimagesink->x_lock);
}
if (xwindow)
xvimagesink->xwindow = xwindow;
+#ifdef GST_EXT_XV_ENHANCEMENT
+ xvimagesink->xid_updated = TRUE;
+#endif /* GST_EXT_XV_ENHANCEMENT */
+
g_mutex_unlock (xvimagesink->flow_lock);
+
+#ifdef GST_EXT_XV_ENHANCEMENT
+ if (current_state == GST_STATE_PAUSED) {
+ GstBuffer *last_buffer = NULL;
+ g_object_get(G_OBJECT(xvimagesink), "last-buffer", &last_buffer, NULL);
+ GST_WARNING_OBJECT(xvimagesink, "PASUED state: window handle is updated. last buffer %p", last_buffer);
+ if (last_buffer) {
+ gst_xvimagesink_show_frame((GstVideoSink *)xvimagesink, last_buffer);
+ gst_buffer_unref(last_buffer);
+ last_buffer = NULL;
+ }
+ }
+#endif /* GST_EXT_XV_ENHANCEMENT */
}
static void
gst_xvimagesink_xwindow_update_geometry (xvimagesink);
#ifdef GST_EXT_XV_ENHANCEMENT
- GST_INFO_OBJECT( xvimagesink, "Overlay window exposed. update it");
- gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
-#else /* GST_EXT_XV_ENHANCEMENT */
- gst_xvimagesink_xvimage_put (xvimagesink, NULL);
+ GST_INFO_OBJECT(xvimagesink, "Overlay window exposed. update it");
#endif /* GST_EXT_XV_ENHANCEMENT */
+ gst_xvimagesink_xvimage_put (xvimagesink, NULL);
}
static void
if (handle_events) {
if (xvimagesink->xwindow->internal) {
+#ifdef GST_EXT_XV_ENHANCEMENT
+ XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xcontext->root, StructureNotifyMask | SubstructureNotifyMask);
+#endif
XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win,
+#ifdef GST_EXT_XV_ENHANCEMENT
+ ExposureMask | StructureNotifyMask | PointerMotionMask | VisibilityChangeMask | PropertyChangeMask |
+#else /* GST_EXT_XV_ENHANCEMENT */
ExposureMask | StructureNotifyMask | PointerMotionMask |
+#endif /* GST_EXT_XV_ENHANCEMENT */
KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
} else {
+#ifdef GST_EXT_XV_ENHANCEMENT
+ XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xcontext->root, StructureNotifyMask | SubstructureNotifyMask);
+#endif
XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win,
+#ifdef GST_EXT_XV_ENHANCEMENT
+ ExposureMask | StructureNotifyMask | PointerMotionMask | VisibilityChangeMask | PropertyChangeMask |
+#else /* GST_EXT_XV_ENHANCEMENT */
ExposureMask | StructureNotifyMask | PointerMotionMask |
+#endif /* GST_EXT_XV_ENHANCEMENT */
KeyPressMask | KeyReleaseMask);
}
} else {
case PROP_DISPLAY_MODE:
{
int set_mode = g_value_get_enum (value);
+ g_mutex_lock(xvimagesink->flow_lock);
+ xvimagesink->display_mode = set_mode;
+ if(!xvimagesink->get_pixmap_cb && !xvimagesink->subpicture) {
+ if(xvimagesink->display_mode==DISPLAY_MODE_PRI_VIDEO_OFF_AND_SEC_VIDEO_FULL_SCREEN) {
+ if(!xvimagesink->is_multi_window || (GST_STATE(xvimagesink) == GST_STATE_PLAYING)) {
+ set_display_mode(xvimagesink->xcontext, xvimagesink->display_mode);
+ } else {
+ GST_WARNING_OBJECT(xvimagesink, "display-mode will be set later. just save value now(%d)", xvimagesink->display_mode);
+ }
+ } else if(xvimagesink->display_mode==DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_CLONE){
+ if(xvimagesink->is_multi_window && (GST_STATE(xvimagesink) != GST_STATE_PLAYING)) {
+ set_display_mode(xvimagesink->xcontext, xvimagesink->display_mode);
+ } else {
+ GST_WARNING_OBJECT(xvimagesink, "display-mode will be set later. just save value now(%d)", xvimagesink->display_mode);
+ }
+ } else {
+ GST_WARNING_OBJECT(xvimagesink, "unsupported format(%d)", xvimagesink->display_mode);
+ }
+ }
+ g_mutex_unlock(xvimagesink->flow_lock);
+ }
+ break;
+ case PROP_CSC_RANGE:
+ {
+ int set_range = g_value_get_enum (value);
g_mutex_lock(xvimagesink->flow_lock);
g_mutex_lock(xvimagesink->x_lock);
- if (xvimagesink->display_mode != set_mode) {
- if (xvimagesink->xcontext) {
- /* set display mode */
- if (set_display_mode(xvimagesink->xcontext, set_mode)) {
- xvimagesink->display_mode = set_mode;
+ if (xvimagesink->csc_range != set_range) {
+ if (xvimagesink->xcontext && !xvimagesink->subpicture) {
+ /* set color space range */
+ if (set_csc_range(xvimagesink->xcontext, set_range)) {
+ xvimagesink->csc_range = set_range;
} else {
- GST_WARNING_OBJECT(xvimagesink, "display mode[%d] set failed.", set_mode);
+ GST_WARNING_OBJECT(xvimagesink, "csc range[%d] set failed.", set_range);
}
} else {
/* "xcontext" is not created yet. It will be applied when xcontext is created. */
- GST_INFO_OBJECT(xvimagesink, "xcontext is NULL. display-mode will be set later.");
- xvimagesink->display_mode = set_mode;
+ GST_INFO_OBJECT(xvimagesink, "xcontext is NULL. color space range will be set later.");
+ xvimagesink->csc_range = set_range;
}
+ } else if (xvimagesink->subpicture) {
+ GST_WARNING("skip to set csc range, because it is subpicture format.");
} else {
- GST_INFO_OBJECT(xvimagesink, "skip display mode %d, because current mode is same", set_mode);
+ GST_INFO_OBJECT(xvimagesink, "skip to set csc range %d, because current is same", set_range);
}
g_mutex_unlock(xvimagesink->x_lock);
case PROP_DISPLAY_GEOMETRY_METHOD:
xvimagesink->display_geometry_method = g_value_get_enum (value);
GST_LOG("Overlay geometry changed. update it");
- gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
+ if (GST_STATE(xvimagesink) == GST_STATE_PAUSED || xvimagesink->eos_received) {
+ gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
+ }
+ break;
+ case PROP_FLIP:
+ xvimagesink->flip = g_value_get_enum(value);
break;
case PROP_ROTATE_ANGLE:
xvimagesink->rotate_angle = g_value_get_enum (value);
- xvimagesink->rotate_changed = TRUE;
+ if (GST_STATE(xvimagesink) == GST_STATE_PAUSED || xvimagesink->eos_received) {
+ gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
+ }
break;
case PROP_VISIBLE:
g_mutex_lock( xvimagesink->flow_lock );
g_mutex_lock( xvimagesink->x_lock );
+ GST_WARNING_OBJECT(xvimagesink, "set visible %d", g_value_get_boolean(value));
+
if (xvimagesink->visible && (g_value_get_boolean(value) == FALSE)) {
- Atom atom_stream = XInternAtom( xvimagesink->xcontext->disp,
- "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False );
- if (atom_stream != None) {
- if (XvSetPortAttribute(xvimagesink->xcontext->disp,
- xvimagesink->xcontext->xv_port_id,
- atom_stream, 0 ) != Success) {
- GST_WARNING_OBJECT( xvimagesink, "Set visible FALSE failed" );
+ if (xvimagesink->xcontext) {
+#if 0
+ Atom atom_stream = XInternAtom( xvimagesink->xcontext->disp,
+ "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", False );
+ if (atom_stream != None) {
+ GST_WARNING_OBJECT(xvimagesink, "Visible FALSE -> CALL STREAM_OFF");
+ if (XvSetPortAttribute(xvimagesink->xcontext->disp,
+ xvimagesink->xcontext->xv_port_id,
+ atom_stream, 0 ) != Success) {
+ GST_WARNING_OBJECT( xvimagesink, "Set visible FALSE failed" );
+ }
+ }
+#endif
+ xvimagesink->visible = g_value_get_boolean (value);
+ if ( xvimagesink->get_pixmap_cb ) {
+ if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
+ XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
+ }
+ } else {
+ if(xvimagesink->xwindow->win)
+ XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xwindow->win);
}
-
XSync( xvimagesink->xcontext->disp, FALSE );
+ } else {
+ GST_WARNING_OBJECT( xvimagesink, "xcontext is null");
+ xvimagesink->visible = g_value_get_boolean (value);
}
} else if (!xvimagesink->visible && (g_value_get_boolean(value) == TRUE)) {
+ xvimagesink->visible = g_value_get_boolean (value);
g_mutex_unlock( xvimagesink->x_lock );
g_mutex_unlock( xvimagesink->flow_lock );
- GST_INFO_OBJECT( xvimagesink, "Set visible as TRUE. Update it." );
gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
g_mutex_lock( xvimagesink->flow_lock );
g_mutex_lock( xvimagesink->x_lock );
}
- xvimagesink->visible = g_value_get_boolean (value);
+ GST_INFO("set visible(%d) done", xvimagesink->visible);
g_mutex_unlock( xvimagesink->x_lock );
g_mutex_unlock( xvimagesink->flow_lock );
break;
case PROP_ZOOM:
- xvimagesink->zoom = g_value_get_int (value);
+ xvimagesink->zoom = g_value_get_float (value);
+ break;
+ case PROP_ZOOM_POS_X:
+ xvimagesink->zoom_pos_x = g_value_get_int (value);
+ break;
+ case PROP_ZOOM_POS_Y:
+ xvimagesink->zoom_pos_y = g_value_get_int (value);
+ if (GST_STATE(xvimagesink) == GST_STATE_PAUSED || xvimagesink->eos_received) {
+ gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
+ }
+ break;
+ case PROP_ORIENTATION:
+ xvimagesink->orientation = g_value_get_enum (value);
+ GST_INFO("Orientation(%d) is changed", xvimagesink->orientation);
+ break;
+ case PROP_DST_ROI_MODE:
+ xvimagesink->dst_roi_mode = g_value_get_enum (value);
+ GST_INFO("Overlay geometry(%d) for ROI is changed", xvimagesink->dst_roi_mode);
break;
case PROP_DST_ROI_X:
xvimagesink->dst_roi.x = g_value_get_int (value);
case PROP_DST_ROI_H:
xvimagesink->dst_roi.h = g_value_get_int (value);
break;
+ case PROP_SRC_CROP_X:
+ xvimagesink->src_crop.x = g_value_get_int (value);
+ break;
+ case PROP_SRC_CROP_Y:
+ xvimagesink->src_crop.y = g_value_get_int (value);
+ break;
+ case PROP_SRC_CROP_W:
+ xvimagesink->src_crop.w = g_value_get_int (value);
+ break;
+ case PROP_SRC_CROP_H:
+ xvimagesink->src_crop.h = g_value_get_int (value);
+ break;
case PROP_STOP_VIDEO:
xvimagesink->stop_video = g_value_get_int (value);
g_mutex_lock( xvimagesink->flow_lock );
if( xvimagesink->stop_video )
{
- GST_INFO_OBJECT( xvimagesink, "Xwindow CLEAR when set video-stop property" );
- gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
+ if ( xvimagesink->get_pixmap_cb ) {
+ if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
+ g_mutex_lock (xvimagesink->x_lock);
+ GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
+ XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
+ g_mutex_unlock (xvimagesink->x_lock);
+ }
+ } else {
+ GST_INFO_OBJECT( xvimagesink, "Xwindow CLEAR when set video-stop property" );
+ gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
+ }
}
g_mutex_unlock( xvimagesink->flow_lock );
break;
+ case PROP_PIXMAP_CB:
+ {
+ void *cb_func;
+ cb_func = g_value_get_pointer(value);
+ if (cb_func) {
+ if (xvimagesink->get_pixmap_cb) {
+ int i = 0;
+ if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
+ g_mutex_lock (xvimagesink->x_lock);
+ GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
+ XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
+ g_mutex_unlock (xvimagesink->x_lock);
+ }
+ for (i = 0; i < MAX_PIXMAP_NUM; i++) {
+ if (xvimagesink->xpixmap[i]) {
+ gst_xvimagesink_xpixmap_destroy (xvimagesink, xvimagesink->xpixmap[i]);
+ xvimagesink->xpixmap[i] = NULL;
+ }
+ }
+ }
+ xvimagesink->get_pixmap_cb = cb_func;
+ GST_INFO_OBJECT (xvimagesink, "Set callback(0x%x) for getting pixmap id", xvimagesink->get_pixmap_cb);
+ }
+ break;
+ }
+ case PROP_PIXMAP_CB_USER_DATA:
+ {
+ void *user_data;
+ user_data = g_value_get_pointer(value);
+ if (user_data) {
+ xvimagesink->get_pixmap_cb_user_data = user_data;
+ GST_INFO_OBJECT (xvimagesink, "Set user data(0x%x) for getting pixmap id", xvimagesink->get_pixmap_cb_user_data);
+ }
+ break;
+ }
+ case PROP_SUBPICTURE:
+ xvimagesink->subpicture = g_value_get_boolean (value);
+ break;
+ case PROP_EXTERNAL_WIDTH:
+ {
+ xvimagesink->external_width = g_value_get_int (value);
+ GST_LOG("[set property] xvimagesink->external_width : %d", xvimagesink->external_width);
+ break;
+ }
+ case PROP_EXTERNAL_HEIGHT:
+ {
+ xvimagesink->external_height = g_value_get_int (value);
+ GST_LOG("[set property] xvimagesink->external_height : %d", xvimagesink->external_height);
+ break;
+ }
+ case PROP_ENABLE_FLUSH_BUFFER:
+ xvimagesink->enable_flush_buffer = g_value_get_boolean(value);
+ break;
+ case PROP_PIXMAP:
+ xvimagesink->is_pixmap = g_value_get_boolean(value);
+ break;
+ case PROP_HIDED_WINDOW:
+ {
+ xvimagesink->is_hided_subpicture = g_value_get_boolean(value);
+ GST_WARNING_OBJECT(xvimagesink, "update hided_window %d", xvimagesink->is_hided_subpicture);
+ break;
+ }
+ case PROP_QUICKPANEL_ON:
+ {
+ xvimagesink->is_quick_panel_on_subpicture = g_value_get_boolean(value);
+ GST_WARNING_OBJECT(xvimagesink, "update quick panel status %d", xvimagesink->is_quick_panel_on_subpicture);
+ break;
+ }
+ case PROP_MULTIWINDOW_ACTIVE:
+ {
+ xvimagesink->is_multi_window_subpicture = g_value_get_boolean(value);
+ GST_WARNING_OBJECT(xvimagesink, "update multi-window status %d", xvimagesink->is_multi_window_subpicture);
+ break;
+ }
+ case PROP_KEEP_EXTERNAL_FULLSCREEN_POST:
+ {
+ xvimagesink->keep_external_fullscreen_post = g_value_get_boolean(value);
+ GST_WARNING_OBJECT(xvimagesink, "set property %d for setting _USER_WM_PORT_ATTRIBUTE_KEEP_EXT", xvimagesink->keep_external_fullscreen_post);
+ if(xvimagesink->keep_external_fullscreen_post) {
+ Atom atom_keep_ext;
+ atom_keep_ext = XInternAtom (xvimagesink->xcontext->disp, "_USER_WM_PORT_ATTRIBUTE_KEEP_EXT", False);
+ if(XvSetPortAttribute (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, atom_keep_ext , 1) != Success)
+ {
+ GST_WARNING("set atom_keep_ext fail");
+ }
+ }
+ break;
+ }
+ case PROP_KEEP_EXTERNAL_FULLSCREEN_PREV:
+ {
+ xvimagesink->keep_external_fullscreen_prev = g_value_get_boolean(value);
+ GST_WARNING_OBJECT(xvimagesink, "set property %d for keeping external display to full screen", xvimagesink->keep_external_fullscreen_prev);
+ break;
+ }
+
#endif /* GST_EXT_XV_ENHANCEMENT */
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
case PROP_DISPLAY_MODE:
g_value_set_enum (value, xvimagesink->display_mode);
break;
+ case PROP_CSC_RANGE:
+ g_value_set_enum (value, xvimagesink->csc_range);
+ break;
case PROP_DISPLAY_GEOMETRY_METHOD:
g_value_set_enum (value, xvimagesink->display_geometry_method);
break;
+ case PROP_FLIP:
+ g_value_set_enum(value, xvimagesink->flip);
+ break;
case PROP_ROTATE_ANGLE:
g_value_set_enum (value, xvimagesink->rotate_angle);
break;
g_value_set_boolean (value, xvimagesink->visible);
break;
case PROP_ZOOM:
- g_value_set_int (value, xvimagesink->zoom);
+ g_value_set_float (value, xvimagesink->zoom);
+ break;
+ case PROP_ZOOM_POS_X:
+ g_value_set_int (value, xvimagesink->zoom_pos_x);
+ break;
+ case PROP_ZOOM_POS_Y:
+ g_value_set_int (value, xvimagesink->zoom_pos_y);
+ break;
+ case PROP_ORIENTATION:
+ g_value_set_enum (value, xvimagesink->orientation);
+ break;
+ case PROP_DST_ROI_MODE:
+ g_value_set_enum (value, xvimagesink->dst_roi_mode);
break;
case PROP_DST_ROI_X:
g_value_set_int (value, xvimagesink->dst_roi.x);
case PROP_DST_ROI_H:
g_value_set_int (value, xvimagesink->dst_roi.h);
break;
+ case PROP_SRC_CROP_X:
+ g_value_set_int (value, xvimagesink->src_crop.x);
+ break;
+ case PROP_SRC_CROP_Y:
+ g_value_set_int (value, xvimagesink->src_crop.y);
+ break;
+ case PROP_SRC_CROP_W:
+ g_value_set_int (value, xvimagesink->src_crop.w);
+ break;
+ case PROP_SRC_CROP_H:
+ g_value_set_int (value, xvimagesink->src_crop.h);
+ break;
case PROP_STOP_VIDEO:
g_value_set_int (value, xvimagesink->stop_video);
break;
+ case PROP_PIXMAP_CB:
+ g_value_set_pointer (value, xvimagesink->get_pixmap_cb);
+ break;
+ case PROP_PIXMAP_CB_USER_DATA:
+ g_value_set_pointer (value, xvimagesink->get_pixmap_cb_user_data);
+ break;
+ case PROP_SUBPICTURE:
+ g_value_set_boolean (value, xvimagesink->subpicture);
+ break;
+ case PROP_EXTERNAL_WIDTH:
+ g_value_set_int (value, xvimagesink->external_width);
+ break;
+ case PROP_EXTERNAL_HEIGHT:
+ g_value_set_int (value, xvimagesink->external_height);
+ break;
+ case PROP_ENABLE_FLUSH_BUFFER:
+ g_value_set_boolean(value, xvimagesink->enable_flush_buffer);
+ break;
+ case PROP_PIXMAP:
+ g_value_set_boolean(value, xvimagesink->is_pixmap);
+ break;
+ case PROP_HIDED_WINDOW:
+ g_value_set_boolean(value, xvimagesink->is_hided_subpicture);
+ break;
+ case PROP_QUICKPANEL_ON:
+ g_value_set_boolean(value, xvimagesink->is_quick_panel_on_subpicture);
+ break;
+ case PROP_MULTIWINDOW_ACTIVE:
+ g_value_set_boolean(value, xvimagesink->is_multi_window_subpicture);
+ break;
+ case PROP_KEEP_EXTERNAL_FULLSCREEN_POST:
+ g_value_set_boolean(value, xvimagesink->keep_external_fullscreen_post);
+ break;
+ case PROP_KEEP_EXTERNAL_FULLSCREEN_PREV:
+ g_value_set_boolean(value, xvimagesink->keep_external_fullscreen_prev);
+ break;
#endif /* GST_EXT_XV_ENHANCEMENT */
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
xvimagesink->xwindow = NULL;
}
+#ifdef GST_EXT_XV_ENHANCEMENT
+ if(xvimagesink->is_subpicture_format && xvimagesink->pixmap_for_subpicture) {
+ GST_INFO("calling XvStopVideo() for %d port [pixmap : %p]", xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture);
+ XvStopVideo(xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->pixmap_for_subpicture);
+ xvimagesink->pixmap_for_subpicture = 0;
+ }
+ if (xvimagesink->get_pixmap_cb) {
+ int i = 0;
+ if (xvimagesink->xpixmap[0] && xvimagesink->xpixmap[0]->pixmap) {
+ g_mutex_lock (xvimagesink->x_lock);
+ GST_WARNING_OBJECT( xvimagesink, "calling XvStopVideo()" );
+ XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, xvimagesink->xpixmap[0]->pixmap);
+ g_mutex_unlock (xvimagesink->x_lock);
+ }
+ for (i = 0; i < MAX_PIXMAP_NUM; i++) {
+ if (xvimagesink->xpixmap[i]) {
+ gst_xvimagesink_xpixmap_destroy (xvimagesink, xvimagesink->xpixmap[i]);
+ xvimagesink->xpixmap[i] = NULL;
+ }
+ }
+ xvimagesink->get_pixmap_cb = NULL;
+ xvimagesink->get_pixmap_cb_user_data = NULL;
+ }
+#endif /* GST_EXT_XV_ENHANCEMENT */
xvimagesink->render_rect.x = xvimagesink->render_rect.y =
xvimagesink->render_rect.w = xvimagesink->render_rect.h = 0;
xvimagesink->have_render_rect = FALSE;
g_mutex_free (xvimagesink->pool_lock);
xvimagesink->pool_lock = NULL;
}
+#ifdef GST_EXT_XV_ENHANCEMENT
+ if (xvimagesink->display_buffer_lock) {
+ g_mutex_free (xvimagesink->display_buffer_lock);
+ xvimagesink->display_buffer_lock = NULL;
+ }
+#endif /* GST_EXT_XV_ENHANCEMENT */
g_free (xvimagesink->media_title);
gst_xvimagesink_init (GstXvImageSink * xvimagesink,
GstXvImageSinkClass * xvimagesinkclass)
{
+#ifdef GST_EXT_XV_ENHANCEMENT
+ int i;
+ int j;
+#endif /* GST_EXT_XV_ENHANCEMENT */
+
xvimagesink->display_name = NULL;
xvimagesink->adaptor_no = 0;
xvimagesink->xcontext = NULL;
xvimagesink->draw_borders = TRUE;
#ifdef GST_EXT_XV_ENHANCEMENT
- xvimagesink->display_mode = DISPLAY_MODE_DEFAULT;
- xvimagesink->rotate_changed = TRUE;
+ xvimagesink->xid_updated = FALSE;
+ xvimagesink->display_mode = DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_CLONE;
+ xvimagesink->csc_range = CSC_RANGE_NARROW;
xvimagesink->display_geometry_method = DEF_DISPLAY_GEOMETRY_METHOD;
+ xvimagesink->flip = DEF_DISPLAY_FLIP;
xvimagesink->rotate_angle = DEGREE_270;
xvimagesink->visible = TRUE;
- xvimagesink->zoom = 1;
+ xvimagesink->zoom = 1.0;
+ xvimagesink->zoom_pos_x = -1;
+ xvimagesink->zoom_pos_y = -1;
xvimagesink->rotation = -1;
+ xvimagesink->dst_roi_mode = DEF_ROI_DISPLAY_GEOMETRY_METHOD;
+ xvimagesink->orientation = DEGREE_0;
xvimagesink->dst_roi.x = 0;
xvimagesink->dst_roi.y = 0;
xvimagesink->dst_roi.w = 0;
xvimagesink->dst_roi.h = 0;
+ xvimagesink->src_crop.x = 0;
+ xvimagesink->src_crop.y = 0;
+ xvimagesink->src_crop.w = 0;
+ xvimagesink->src_crop.h = 0;
xvimagesink->xim_transparenter = NULL;
xvimagesink->scr_w = 0;
xvimagesink->scr_h = 0;
xvimagesink->aligned_height = 0;
xvimagesink->stop_video = FALSE;
xvimagesink->is_hided = FALSE;
+ xvimagesink->is_quick_panel_on = FALSE;
+ xvimagesink->is_multi_window = FALSE;
+ xvimagesink->drm_fd = -1;
+ xvimagesink->current_pixmap_idx = -1;
+ xvimagesink->get_pixmap_cb = NULL;
+ xvimagesink->get_pixmap_cb_user_data = NULL;
+
+ for (i = 0 ; i < DISPLAYING_BUFFERS_MAX_NUM ; i++) {
+ xvimagesink->displaying_buffers[i].buffer = NULL;
+ for (j = 0 ; j < XV_BUF_PLANE_NUM ; j++) {
+ xvimagesink->displaying_buffers[i].gem_name[j] = 0;
+ xvimagesink->displaying_buffers[i].gem_handle[j] = 0;
+ xvimagesink->displaying_buffers[i].dmabuf_fd[j] = 0;
+ xvimagesink->displaying_buffers[i].ref_count = 0;
+ }
+ }
+
+ xvimagesink->display_buffer_lock = g_mutex_new ();
+
+ xvimagesink->displayed_buffer_count = 0;
+ xvimagesink->displaying_buffer_count = 0;
+ xvimagesink->is_zero_copy_format = FALSE;
+ xvimagesink->secure_path = SECURE_PATH_INIT;
+ xvimagesink->drm_level = DRM_LEVEL_0;
+ xvimagesink->last_added_buffer_index = -1;
+ xvimagesink->bufmgr = NULL;
+ xvimagesink->flush_buffer = NULL;
+ xvimagesink->enable_flush_buffer = TRUE;
+ xvimagesink->pixmap_for_subpicture = 0;
+ xvimagesink->is_subpicture_format = FALSE;
+ xvimagesink->set_overlay_for_subpicture_just_once = FALSE;
+ xvimagesink->subpicture = FALSE;
+ xvimagesink->external_width = 0;
+ xvimagesink->external_height = 0;
+ xvimagesink->skip_frame_due_to_external_dev = FALSE;
+ xvimagesink->is_hided_subpicture = FALSE;
+ xvimagesink->is_quick_panel_on_subpicture = FALSE;
+ xvimagesink->is_multi_window_subpicture = FALSE;
+ xvimagesink->keep_external_fullscreen_post = FALSE;
+ xvimagesink->keep_external_fullscreen_prev = FALSE;
+ if(!XInitThreads())
+ GST_WARNING("FAIL to call XInitThreads()");
+ if(vconf_set_int(VCONFKEY_XV_STATE, (xvimagesink->eos_received << 2) | XV_STATUS_NULL))
+ GST_WARNING("vconf set fail");
#endif /* GST_EXT_XV_ENHANCEMENT */
}
g_param_spec_string ("device-name", "Adaptor name",
"The name of the video adaptor", NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_EXTERNAL_WIDTH,
+ g_param_spec_int ("external-width", "external width",
+ "width of external display", 0, G_MAXINT,
+ 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_EXTERNAL_HEIGHT,
+ g_param_spec_int ("external-height", "external height",
+ "height of external display", 0, G_MAXINT,
+ 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstXvImageSink:handle-expose
*
g_object_class_install_property(gobject_class, PROP_DISPLAY_MODE,
g_param_spec_enum("display-mode", "Display Mode",
"Display device setting",
- GST_TYPE_XVIMAGESINK_DISPLAY_MODE, DISPLAY_MODE_DEFAULT,
+ GST_TYPE_XVIMAGESINK_DISPLAY_MODE, DISPLAY_MODE_PRI_VIDEO_ON_AND_SEC_VIDEO_CLONE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstXvImageSink:csc-range
+ *
+ * select color space range
+ */
+ g_object_class_install_property(gobject_class, PROP_CSC_RANGE,
+ g_param_spec_enum("csc-range", "Color Space Range",
+ "Color space range setting",
+ GST_TYPE_XVIMAGESINK_CSC_RANGE, CSC_RANGE_NARROW,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
+ * GstXvImageSink:display-flip
+ *
+ * Display flip setting
+ */
+ g_object_class_install_property(gobject_class, PROP_FLIP,
+ g_param_spec_enum("flip", "Display flip",
+ "Flip for display",
+ GST_TYPE_XVIMAGESINK_FLIP, DEF_DISPLAY_FLIP,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
* GstXvImageSink:rotate
*
* Draw rotation angle setting
/**
* GstXvImageSink:zoom
*
- * Scale small area of screen to 2X, 3X, ... , 9X
+ * Scale small area of screen to 1X~ 9X
*/
g_object_class_install_property (gobject_class, PROP_ZOOM,
- g_param_spec_int ("zoom", "Zoom",
- "Zooms screen as nX", 1, 9, 1,
+ g_param_spec_float ("zoom", "Zoom",
+ "Zooms screen as nX", 1.0, 9.0, 1.0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstXvImageSink:zoom-pos-x
+ *
+ * Standard x-position of zoom
+ */
+ g_object_class_install_property (gobject_class, PROP_ZOOM_POS_X,
+ g_param_spec_int ("zoom-pos-x", "Zoom Position X",
+ "Standard x-position of zoom", -1, 3840, -1,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
+ * GstXvImageSink:zoom-pos-y
+ *
+ * Standard y-position of zoom
+ */
+ g_object_class_install_property (gobject_class, PROP_ZOOM_POS_Y,
+ g_param_spec_int ("zoom-pos-y", "Zoom Position Y",
+ "Standard y-position of zoom", -1, 3840, -1,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstXvImageSink:dst-roi-mode
+ *
+ * Display geometrical method of ROI setting
+ */
+ g_object_class_install_property(gobject_class, PROP_DST_ROI_MODE,
+ g_param_spec_enum("dst-roi-mode", "Display geometry method of ROI",
+ "Geometrical method of ROI for display",
+ GST_TYPE_XVIMAGESINK_ROI_DISPLAY_GEOMETRY_METHOD, DEF_ROI_DISPLAY_GEOMETRY_METHOD,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstXvImageSink:orientation
+ *
+ * Orientation information which will be used for ROI/ZOOM
+ */
+ g_object_class_install_property(gobject_class, PROP_ORIENTATION,
+ g_param_spec_enum("orientation", "Orientation information used for ROI/ZOOM",
+ "Orientation information for display",
+ GST_TYPE_XVIMAGESINK_ROTATE_ANGLE, DEGREE_0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
* GstXvImageSink:dst-roi-x
*
* X value of Destination ROI
g_param_spec_int ("stop-video", "Stop-Video",
"Stop video for releasing video source buffer", 0, 1, 0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class, PROP_PIXMAP_CB,
+ g_param_spec_pointer("pixmap-id-callback", "Pixmap-Id-Callback",
+ "pointer of callback function for getting pixmap id", G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_PIXMAP_CB_USER_DATA,
+ g_param_spec_pointer("pixmap-id-callback-userdata", "Pixmap-Id-Callback-Userdata",
+ "pointer of user data of callback function for getting pixmap id", G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_SUBPICTURE,
+ g_param_spec_boolean ("subpicture", "Subpicture",
+ "identifier of player for supporting subpicture", FALSE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstXvImageSink:src-crop-x
+ *
+ * X value of video source crop
+ */
+ g_object_class_install_property (gobject_class, PROP_SRC_CROP_X,
+ g_param_spec_int ("src-crop-x", "Source Crop X",
+ "X value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstXvImageSink:src-crop-y
+ *
+ * Y value of video source crop
+ */
+ g_object_class_install_property (gobject_class, PROP_SRC_CROP_Y,
+ g_param_spec_int ("src-crop-y", "Source Crop X",
+ "Y value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstXvImageSink:src-crop-w
+ *
+ * Width value of video source crop
+ */
+ g_object_class_install_property (gobject_class, PROP_SRC_CROP_W,
+ g_param_spec_int ("src-crop-w", "Source Crop Width",
+ "Width value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstXvImageSink:src-crop-h
+ *
+ * Height value of video source crop
+ */
+ g_object_class_install_property (gobject_class, PROP_SRC_CROP_H,
+ g_param_spec_int ("src-crop-h", "Source Crop Height",
+ "Height value of Video source crop(only available if LETTER_BOX or FULL_SCREEN mode)", 0, XV_SCREEN_SIZE_WIDTH, 0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstXvImageSink:enable-flush-buffer
+ *
+ * Enable flush buffer mechanism when state change(PAUSED_TO_READY)
+ */
+ g_object_class_install_property (gobject_class, PROP_ENABLE_FLUSH_BUFFER,
+ g_param_spec_boolean("enable-flush-buffer", "Enable flush buffer mechanism",
+ "Enable flush buffer mechanism when state change(PAUSED_TO_READY)",
+ TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstXvImageSink:is-pixmap
+ *
+ * Check using pixmap id for blocking X api
+ */
+ g_object_class_install_property (gobject_class, PROP_PIXMAP,
+ g_param_spec_boolean("is-pixmap", "Check if use pixmap",
+ "Check using pixmap id for blocking X api",
+ FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstXvImageSink:hided-window
+ *
+ * check window status for hiding subtitle
+ */
+ g_object_class_install_property (gobject_class, PROP_HIDED_WINDOW,
+ g_param_spec_boolean("hided-window", "Hided window",
+ "check window status for hiding subtitle",
+ FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstXvImageSink:quick-panel-on
+ *
+ * check quick-panel status for hiding subtitle
+ */
+ g_object_class_install_property (gobject_class, PROP_QUICKPANEL_ON,
+ g_param_spec_boolean("quick-panel-on", "Quick panel On",
+ "check quick-panel status for hiding subtitle",
+ FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstXvImageSink:multiwindow-activated
+ *
+ * check multiwindow-activated status for hiding subtitle
+ */
+ g_object_class_install_property (gobject_class, PROP_MULTIWINDOW_ACTIVE,
+ g_param_spec_boolean("multiwindow-active", "Multiwindow Activate",
+ "check multiwindow status for hiding subtitle",
+ FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstXvImageSink:keep-external-fullscreen-post
+ *
+ * keep video-only mode for special case, it is set immediately.
+ */
+ g_object_class_install_property (gobject_class, PROP_KEEP_EXTERNAL_FULLSCREEN_POST,
+ g_param_spec_boolean("keep-external-fullscreen-post", "Keep external display to full screen",
+ "set video-only mode forcedly for special case",
+ FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstXvImageSink:keep-external-fullscreen-prev
+ *
+ * keep video-only mode for special case, it is set in advance.
+ */
+ g_object_class_install_property (gobject_class, PROP_KEEP_EXTERNAL_FULLSCREEN_PREV,
+ g_param_spec_boolean("keep-external-fullscreen-prev", "Keep external display to full screen",
+ "set video-only mode forcedly for special case",
+ FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstXvImageSink::frame-render-error
+ */
+ gst_xvimagesink_signals[SIGNAL_FRAME_RENDER_ERROR] = g_signal_new (
+ "frame-render-error",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL,
+ NULL,
+ gst_xvimagesink_BOOLEAN__POINTER,
+ G_TYPE_BOOLEAN,
+ 1,
+ G_TYPE_POINTER);
+ /**
+ * GstXvImageSink::display-status
+ */
+ gst_xvimagesink_signals[SIGNAL_DISPLAY_STATUS] = g_signal_new (
+ "display-status",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__INT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_INT);
+
+ /**
+ * GstXvImageSink::external-resolution
+ */
+ gst_xvimagesink_signals[SIGNAL_EXTERNAL_RESOLUTION] = g_signal_new (
+ "external-resolution",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ 0,
+ NULL,
+ NULL,
+ gst_marshal_VOID__INT_INT,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_INT,
+ G_TYPE_INT);
+
+ /**
+ * GstXvImageSink::hided-window
+ */
+ gst_xvimagesink_signals[SIGNAL_WINDOW_STATUS] = g_signal_new (
+ "hided-window",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_BOOLEAN);
+
+ /**
+ * GstXvImageSink::quick-panel-on
+ */
+ gst_xvimagesink_signals[SIGNAL_QUICKPANEL_STATUS] = g_signal_new (
+ "quick-panel-on",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_BOOLEAN);
+
+ /**
+ * GstXvImageSink::multiwindow-active
+ */
+ gst_xvimagesink_signals[SIGNAL_MULTIWINDOW_STATUS] = g_signal_new (
+ "multiwindow-active",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_BOOLEAN);
+
#endif /* GST_EXT_XV_ENHANCEMENT */
gobject_class->finalize = gst_xvimagesink_finalize;
"xvimagesink",
"XFree86 video output plugin using Xv extension",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
+
+