#include "mafw-gst-renderer-worker.h"
#include "mafw-gst-renderer-utils.h"
#include "blanking.h"
+#include "keypad.h"
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "mafw-gst-renderer-worker"
GST_TIME_AS_SECONDS((ns)):\
GST_TIME_AS_SECONDS((ns))+1)
+#define _current_metadata_add(worker, key, type, value) \
+ do { \
+ if (!worker->current_metadata) \
+ worker->current_metadata = mafw_metadata_new(); \
+ /* At first remove old value */ \
+ g_hash_table_remove(worker->current_metadata, key); \
+ mafw_metadata_add_something(worker->current_metadata, \
+ key, type, 1, value); \
+ } while (0)
+
/* Private variables. */
/* Global reference to worker instance, needed for Xerror handler */
static MafwGstRendererWorker *Global_worker = NULL;
static void _emit_metadatas(MafwGstRendererWorker *worker);
-static void _current_metadata_add(MafwGstRendererWorker *worker,
- const gchar *key, GType type,
- const gpointer value);
+/* Playlist parsing */
+static void _on_pl_entry_parsed(TotemPlParser *parser, gchar *uri,
+ gpointer metadata, GSList **plitems)
+{
+ if (uri != NULL) {
+ *plitems = g_slist_append(*plitems, g_strdup(uri));
+ }
+}
+static GSList *_parse_playlist(const gchar *uri)
+{
+ static TotemPlParser *pl_parser = NULL;
+ GSList *plitems = NULL;
+ gulong handler_id;
+ /* Initialize the playlist parser */
+ if (!pl_parser)
+ {
+ pl_parser = totem_pl_parser_new ();
+ g_object_set(pl_parser, "recurse", TRUE, "disable-unsafe",
+ TRUE, NULL);
+ }
+ handler_id = g_signal_connect(G_OBJECT(pl_parser), "entry-parsed",
+ G_CALLBACK(_on_pl_entry_parsed), &plitems);
+ /* Parsing */
+ if (totem_pl_parser_parse(pl_parser, uri, FALSE) !=
+ TOTEM_PL_PARSER_RESULT_SUCCESS) {
+ /* An error happens while parsing */
+
+ }
+ g_signal_handler_disconnect(pl_parser, handler_id);
+ return plitems;
+}
+
/*
* Sends @error to MafwGstRenderer. Only call this from the glib main thread, or
* face the consequences. @err is free'd.
/* Add the info to the current metadata. */
_current_metadata_add(sgd->worker, sgd->metadata_key,
G_TYPE_STRING,
- (const gpointer) filename);
+ (gchar*)filename);
/* Emit the metadata. */
mafw_renderer_emit_metadata_string(sgd->worker->owner,
NULL, sgd);
}
}
+ g_object_unref(loader);
}
}
}
static void _remove_ready_timeout(MafwGstRendererWorker *worker)
{
- g_debug("removing timeout for READY");
if (worker->ready_timeout != 0) {
+ g_debug("removing timeout for READY");
g_source_remove(worker->ready_timeout);
worker->ready_timeout = 0;
}
worker->media.fps = fps;
/* Add the info to the current metadata. */
- gint *p_width = g_new0(gint, 1);
- gint *p_height = g_new0(gint, 1);
- gdouble *p_fps = g_new0(gdouble, 1);
+ gint p_width, p_height, p_fps;
- *p_width = width;* p_height = height; *p_fps = fps;
+ p_width = width;
+ p_height = height;
+ p_fps = fps;
_current_metadata_add(worker, MAFW_METADATA_KEY_RES_X, G_TYPE_INT,
- (const gpointer) p_width);
+ p_width);
_current_metadata_add(worker, MAFW_METADATA_KEY_RES_Y, G_TYPE_INT,
- (const gpointer) p_height);
+ p_height);
_current_metadata_add(worker, MAFW_METADATA_KEY_VIDEO_FRAMERATE,
G_TYPE_DOUBLE,
- (const gpointer) p_fps);
-
- g_free(p_width); g_free(p_height); g_free(p_fps);
+ p_fps);
/* Emit the metadata.*/
g_idle_add((GSourceFunc)_emit_video_info, worker);
MAFW_RENDERER_ERROR,
MAFW_RENDERER_ERROR_PLAYBACK,
"No video window XID set"));
+ gst_message_unref (msg);
return GST_BUS_DROP;
} else {
g_debug ("Video window to use is: %x",
mafw_gst_renderer_worker_set_autopaint(
worker,
worker->autopaint);
- g_object_get(worker->vsink,
- "colorkey", &worker->colorkey, NULL);
+ if (worker->colorkey == -1)
+ g_object_get(worker->vsink,
+ "colorkey", &worker->colorkey, NULL);
+ else
+ mafw_gst_renderer_worker_set_colorkey(
+ worker,
+ worker->colorkey);
/* Defer the signal emission to the thread running the
* mainloop. */
if (worker->colorkey != -1) {
GST_OBJECT(worker->vsink),
gst_structure_empty_new("ckey")));
}
+ gst_message_unref (msg);
return GST_BUS_DROP;
}
+ /* do not unref message when returning PASS */
return GST_BUS_PASS;
}
gint duration_seconds = NSECONDS_TO_SECONDS(value);
if (!_seconds_duration_equal(worker->media.length_nanos,
- value)) {
- gint64 *duration = g_new0(gint64, 1);
- *duration = duration_seconds;
-
+ value)) {
/* Add the duration to the current metadata. */
- _current_metadata_add(worker,
- MAFW_METADATA_KEY_DURATION,
- G_TYPE_INT64,
- (const gpointer) duration);
-
+ _current_metadata_add(worker, MAFW_METADATA_KEY_DURATION,
+ G_TYPE_INT64,
+ (gint64)duration_seconds);
/* Emit the duration. */
mafw_renderer_emit_metadata_int64(
worker->owner, MAFW_METADATA_KEY_DURATION,
- *duration);
- g_free(duration);
+ (gint64)duration_seconds);
}
/* We compare this duration we just got with the
* source one and update it in the source if needed */
- if (duration_seconds != renderer->media->duration) {
+ if (duration_seconds > 0 &&
+ duration_seconds != renderer->media->duration) {
mafw_gst_renderer_update_source_duration(
renderer,
duration_seconds);
}
if (worker->media.seekable != seekable) {
- gboolean *is_seekable = g_new0(gboolean, 1);
- *is_seekable = (seekable == SEEKABILITY_SEEKABLE) ? TRUE : FALSE;
+ gboolean is_seekable = (seekable == SEEKABILITY_SEEKABLE);
/* Add the seekability to the current metadata. */
_current_metadata_add(worker, MAFW_METADATA_KEY_IS_SEEKABLE,
- G_TYPE_BOOLEAN, (const gpointer) is_seekable);
+ G_TYPE_BOOLEAN, is_seekable);
/* Emit. */
mafw_renderer_emit_metadata_boolean(
worker->owner, MAFW_METADATA_KEY_IS_SEEKABLE,
- *is_seekable);
-
- g_free(is_seekable);
+ is_seekable);
}
g_debug("media seekable: %d", seekable);
if (worker->media.has_visual_content) {
blanking_prohibit();
}
+ keypadlocking_prohibit();
/* Remove the ready timeout if we are playing [again] */
_remove_ready_timeout(worker);
/* If mode is redundant we are trying to play one of several
}
#endif
-
-
-static void _current_metadata_add(MafwGstRendererWorker *worker,
- const gchar *key, GType type,
- const gpointer value)
-{
- g_return_if_fail(value != NULL);
-
- if (!worker->current_metadata)
- worker->current_metadata = mafw_metadata_new();
-
- mafw_metadata_add_something(worker->current_metadata, key, type, 1, value);
-}
-
static GHashTable* _build_tagmap(void)
{
GHashTable *hash_table = NULL;
g_value_init(&utf8gval, G_TYPE_STRING);
g_value_take_string(&utf8gval, utf8);
- _current_metadata_add(worker, mafwtag, G_TYPE_VALUE,
- (const gpointer) &utf8gval);
+ _current_metadata_add(worker, mafwtag, G_TYPE_STRING,
+ utf8);
g_value_array_append(values, &utf8gval);
g_value_unset(&utf8gval);
}
g_free(orig);
} else if (type == G_TYPE_UINT) {
GValue intgval = {0};
+ gint intval;
g_value_init(&intgval, G_TYPE_INT);
g_value_transform(v, &intgval);
- _current_metadata_add(worker, mafwtag, G_TYPE_VALUE,
- (const gpointer) &intgval);
+ intval = g_value_get_int(&intgval);
+ _current_metadata_add(worker, mafwtag, G_TYPE_INT,
+ intval);
g_value_array_append(values, &intgval);
g_value_unset(&intgval);
} else {
_current_metadata_add(worker, mafwtag, G_TYPE_VALUE,
- (const gpointer) v);
+ v);
g_value_array_append(values, v);
}
}
/* No state management needed for live pipelines */
if (!worker->is_live) {
worker->buffering = TRUE;
- if (worker->state == GST_STATE_PLAYING) {
+ if (percent < 100 && worker->state == GST_STATE_PLAYING) {
g_debug("setting pipeline to PAUSED not to wolf the "
"buffer down");
worker->report_statechanges = FALSE;
the state change, since in
_handle_state_changed we do not do anything
if we are buffering */
+
+ /* Set the pipeline to playing. This is an async
+ handler, it could be, that the reported state
+ is not the real-current state */
+ if (gst_element_set_state(
+ worker->pipeline,
+ GST_STATE_PLAYING) ==
+ GST_STATE_CHANGE_ASYNC)
+ {
+ /* XXX this blocks at most 2 seconds. */
+ gst_element_get_state(
+ worker->pipeline, NULL, NULL,
+ 2 * GST_SECOND);
+ }
if (worker->report_statechanges &&
worker->notify_play_handler) {
worker->notify_play_handler(
}
if (worker->mode == WORKER_MODE_SINGLE_PLAY) {
+ if (err->domain == GST_STREAM_ERROR &&
+ err->code == GST_STREAM_ERROR_WRONG_TYPE)
+ {/* Maybe it is a playlist? */
+ GSList *plitems = _parse_playlist(worker->media.location);
+
+ if (plitems)
+ {/* Yes, it is a plitem */
+ g_error_free(err);
+ mafw_gst_renderer_worker_play(worker, NULL, plitems);
+ break;
+ }
+
+
+ }
_send_error(worker, err);
}
}
&value);
}
+#ifdef MAFW_GST_RENDERER_ENABLE_MUTE
+
static void _mute_cb(MafwGstRendererWorkerVolume *wvolume, gboolean mute,
gpointer data)
{
&value);
}
+#endif
+
/* TODO: I think it's not enought to act on error, we need to handle
* DestroyNotify on the given window ourselves, because for example helixbin
* does it and silently stops the decoder thread. But it doesn't notify
/* These need a modified version of playbin. */
g_object_set(G_OBJECT(worker->pipeline),
- "nw-queue", use_nw, NULL);
- g_object_set(G_OBJECT(worker->pipeline),
- "no-video-transform", TRUE, NULL);
+ "nw-queue", use_nw,
+ "no-video-transform", TRUE,
+ NULL);
}
}
G_CALLBACK(_stream_info_cb), worker);
#ifndef MAFW_GST_RENDERER_DISABLE_PULSE_VOLUME
- g_object_set(worker->pipeline, "flags", 103, NULL);
+
/* Set audio and video sinks ourselves. We create and configure
them only once. */
g_assert_not_reached();
}
gst_object_ref(worker->asink);
- g_object_set(worker->asink, "buffer-time",
- (gint64) MAFW_GST_BUFFER_TIME, NULL);
- g_object_set(worker->asink, "latency-time",
- (gint64) MAFW_GST_LATENCY_TIME, NULL);
+ g_object_set(worker->asink,
+ "buffer-time", (gint64) MAFW_GST_BUFFER_TIME,
+ "latency-time", (gint64) MAFW_GST_LATENCY_TIME,
+ NULL);
}
g_object_set(worker->pipeline, "audio-sink", worker->asink, NULL);
#endif
g_assert_not_reached();
}
gst_object_ref(worker->vsink);
- g_object_set(G_OBJECT(worker->vsink), "handle-events",
- TRUE, NULL);
- g_object_set(worker->vsink, "force-aspect-ratio",
- TRUE, NULL);
- }
- g_object_set(worker->pipeline, "video-sink", worker->vsink, NULL);
+ g_object_set(G_OBJECT(worker->vsink),
+ "handle-events", TRUE,
+ "force-aspect-ratio", TRUE,
+ NULL);
+ }
+ g_object_set(worker->pipeline,
+ "video-sink", worker->vsink,
+ "flags", 103,
+ NULL);
if (!worker->tsink) {
worker->tsink = gst_element_factory_make("textoverlay", NULL);
worker->autopaint = autopaint;
if (worker->vsink)
g_object_set(worker->vsink, "autopaint-colorkey",
- autopaint, NULL);
+ worker->autopaint, NULL);
}
gint mafw_gst_renderer_worker_get_colorkey(
return worker->colorkey;
}
+void mafw_gst_renderer_worker_set_colorkey(
+ MafwGstRendererWorker *worker, gint colorkey)
+{
+ worker->colorkey = colorkey;
+ if (worker->vsink)
+ g_object_set(worker->vsink, "colorkey",
+ worker->colorkey, NULL);
+}
+
gboolean mafw_gst_renderer_worker_get_seekable(MafwGstRendererWorker *worker)
{
return worker->media.seekable;
_start_play(worker);
}
-static void _on_pl_entry_parsed(TotemPlParser *parser, gchar *uri,
- gpointer metadata, gpointer user_data)
-{
- MafwGstRendererWorker *worker = user_data;
-
- if (uri != NULL) {
- worker->pl.items =
- g_slist_append(worker->pl.items, g_strdup(uri));
- }
-}
-
static void _do_play(MafwGstRendererWorker *worker)
{
g_assert(worker != NULL);
}
void mafw_gst_renderer_worker_play(MafwGstRendererWorker *worker,
- const gchar *uri)
+ const gchar *uri, GSList *plitems)
{
- g_assert(uri);
+ g_assert(uri || plitems);
mafw_gst_renderer_worker_stop(worker);
_reset_media_info(worker);
_reset_pl_info(worker);
/* Check if the item to play is a single item or a playlist. */
- if (uri_is_playlist(uri)){
+ if (plitems || uri_is_playlist(uri)){
+ gchar *item;
/* In case of a playlist we parse it and start playing the first
item of the playlist. */
- TotemPlParser *pl_parser;
- gchar *item;
-
- /* Initialize the playlist parser */
- pl_parser = totem_pl_parser_new ();
- g_object_set(pl_parser, "recurse", TRUE, "disable-unsafe",
- TRUE, NULL);
- g_signal_connect(G_OBJECT(pl_parser), "entry-parsed",
- G_CALLBACK(_on_pl_entry_parsed), worker);
-
- /* Parsing */
- if (totem_pl_parser_parse(pl_parser, uri, FALSE) !=
- TOTEM_PL_PARSER_RESULT_SUCCESS) {
- /* An error happens while parsing */
- _send_error(worker,
- g_error_new(MAFW_RENDERER_ERROR,
- MAFW_RENDERER_ERROR_PLAYLIST_PARSING,
- "Playlist parsing failed: %s",
- uri));
- return;
+ if (plitems)
+ {
+ worker->pl.items = plitems;
}
-
- if (!worker->pl.items) {
- /* The playlist is empty */
+ else
+ {
+ worker->pl.items = _parse_playlist(uri);
+ }
+ if (!worker->pl.items)
+ {
_send_error(worker,
- g_error_new(MAFW_RENDERER_ERROR,
- MAFW_RENDERER_ERROR_PLAYLIST_PARSING,
- "The playlist %s is empty.",
- uri));
+ g_error_new(MAFW_RENDERER_ERROR,
+ MAFW_RENDERER_ERROR_PLAYLIST_PARSING,
+ "Playlist parsing failed: %s",
+ uri));
return;
}
worker->pl.current = 0;
item = (gchar *) g_slist_nth_data(worker->pl.items, 0);
worker->media.location = g_strdup(item);
-
- /* Free the playlist parser */
- g_object_unref(pl_parser);
} else {
/* Single item. Set the playback mode according to that */
worker->mode = WORKER_MODE_SINGLE_PLAY;
/* We are not playing, so we can let the screen blank */
blanking_allow();
+ keypadlocking_allow();
/* And now get a fresh pipeline ready */
_construct_pipeline(worker);
2 * GST_SECOND);
}
blanking_allow();
+ keypadlocking_allow();
}
}
volume = mafw_gst_renderer_worker_volume_get(wvolume);
mute = mafw_gst_renderer_worker_volume_is_muted(wvolume);
_volume_cb(wvolume, volume, worker);
+#ifdef MAFW_GST_RENDERER_ENABLE_MUTE
_mute_cb(wvolume, mute, worker);
+#endif
}
MafwGstRendererWorker *mafw_gst_renderer_worker_new(gpointer owner)
mafw_gst_renderer_worker_volume_init(main_context,
_volume_init_cb, worker,
_volume_cb, worker,
- _mute_cb, worker);
+#ifdef MAFW_GST_RENDERER_ENABLE_MUTE
+ _mute_cb,
+#else
+ NULL,
+#endif
+ worker);
blanking_init();
_construct_pipeline(worker);