X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=libmafw-gst-renderer%2Fmafw-gst-renderer-worker.c;h=2404608a77a19faac16512bc9ac745527b3e397d;hb=96e51230b8e83c98c4aa787534374251ce5248c0;hp=8c81870f01c22c83825e09c9ab52b06fb54ab959;hpb=30e2d15a0a2b1c39900e50ec932655877d548723;p=mafwsubrenderer diff --git a/libmafw-gst-renderer/mafw-gst-renderer-worker.c b/libmafw-gst-renderer/mafw-gst-renderer-worker.c index 8c81870..2404608 100644 --- a/libmafw-gst-renderer/mafw-gst-renderer-worker.c +++ b/libmafw-gst-renderer/mafw-gst-renderer-worker.c @@ -45,6 +45,7 @@ #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" @@ -62,6 +63,16 @@ 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; @@ -74,10 +85,39 @@ static void _play_pl_next(MafwGstRendererWorker *worker); 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. @@ -211,7 +251,7 @@ static void _emit_gst_buffer_as_graphic_file_cb(GstBuffer *new_buffer, /* 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, @@ -342,6 +382,7 @@ static void _emit_gst_buffer_as_graphic_file(MafwGstRendererWorker *worker, NULL, sgd); } } + g_object_unref(loader); } } } @@ -386,8 +427,8 @@ static void _add_ready_timeout(MafwGstRendererWorker *worker) 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; } @@ -453,21 +494,19 @@ static gboolean _handle_video_info(MafwGstRendererWorker *worker, 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); @@ -579,6 +618,7 @@ static GstBusSyncReply _sync_bus_handler(GstBus *bus, GstMessage *msg, 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", @@ -592,8 +632,13 @@ static GstBusSyncReply _sync_bus_handler(GstBus *bus, GstMessage *msg, 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) { @@ -602,8 +647,10 @@ static GstBusSyncReply _sync_bus_handler(GstBus *bus, GstMessage *msg, 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; } @@ -649,26 +696,21 @@ static void _check_duration(MafwGstRendererWorker *worker, gint64 value) 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); @@ -710,19 +752,16 @@ static void _check_seekability(MafwGstRendererWorker *worker) } 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); @@ -944,6 +983,7 @@ static void _handle_state_changed(GstMessage *msg, MafwGstRendererWorker *worker 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 @@ -1015,20 +1055,6 @@ static void _emit_renderer_art(MafwGstRendererWorker *worker, } #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; @@ -1115,24 +1141,26 @@ static void _emit_tag(const GstTagList *list, const gchar *tag, 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); } } @@ -1216,7 +1244,7 @@ static void _handle_buffering(MafwGstRendererWorker *worker, GstMessage *msg) /* 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; @@ -1299,6 +1327,20 @@ static void _handle_buffering(MafwGstRendererWorker *worker, GstMessage *msg) 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( @@ -1461,6 +1503,20 @@ static gboolean _async_bus_handler(GstBus *bus, GstMessage *msg, } 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); } } @@ -1568,6 +1624,8 @@ static void _volume_cb(MafwGstRendererWorkerVolume *wvolume, gdouble volume, &value); } +#ifdef MAFW_GST_RENDERER_ENABLE_MUTE + static void _mute_cb(MafwGstRendererWorkerVolume *wvolume, gboolean mute, gpointer data) { @@ -1583,6 +1641,8 @@ static void _mute_cb(MafwGstRendererWorkerVolume *wvolume, gboolean mute, &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 @@ -1685,6 +1745,8 @@ static void _start_play(MafwGstRendererWorker *worker) gst_element_set_state(worker->pipeline, GST_STATE_READY); g_free(autoload_sub); } + } else { + g_object_set(G_OBJECT(worker->pipeline), "suburi", NULL, NULL); } g_debug("URI: %s", worker->media.location); @@ -1753,9 +1815,9 @@ static void _construct_pipeline(MafwGstRendererWorker *worker) /* 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); } } @@ -1784,7 +1846,7 @@ static void _construct_pipeline(MafwGstRendererWorker *worker) 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. */ @@ -1800,10 +1862,10 @@ static void _construct_pipeline(MafwGstRendererWorker *worker) 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 @@ -1820,12 +1882,15 @@ static void _construct_pipeline(MafwGstRendererWorker *worker) 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); @@ -2028,7 +2093,7 @@ void mafw_gst_renderer_worker_set_autopaint( 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( @@ -2037,6 +2102,15 @@ 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; @@ -2058,17 +2132,6 @@ static void _play_pl_next(MafwGstRendererWorker *worker) { _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); @@ -2102,46 +2165,33 @@ static void _do_play(MafwGstRendererWorker *worker) } 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; } @@ -2153,9 +2203,6 @@ void mafw_gst_renderer_worker_play(MafwGstRendererWorker *worker, 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; @@ -2257,6 +2304,7 @@ void mafw_gst_renderer_worker_stop(MafwGstRendererWorker *worker) /* 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); @@ -2288,6 +2336,7 @@ void mafw_gst_renderer_worker_pause(MafwGstRendererWorker *worker) 2 * GST_SECOND); } blanking_allow(); + keypadlocking_allow(); } } @@ -2342,7 +2391,9 @@ static void _volume_init_cb(MafwGstRendererWorkerVolume *wvolume, 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) @@ -2389,7 +2440,12 @@ 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);