mirror of
https://github.com/Rafostar/clapper.git
synced 2026-01-15 00:10:34 +01:00
Merge pull request #599 from Rafostar/framestepping
clapper: Implement frame advance function
This commit is contained in:
@@ -883,6 +883,18 @@ _handle_speed_key_press (ClapperAppWindow *self, gboolean forward)
|
||||
(forward) ? "av.speed-up" : "av.speed-down", NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
_handle_advance_frame_key_press (ClapperAppWindow *self)
|
||||
{
|
||||
ClapperPlayer *player = clapper_gtk_av_get_player (
|
||||
CLAPPER_GTK_AV_CAST (self->video));
|
||||
ClapperPlayerState state = clapper_player_get_state (player);
|
||||
|
||||
/* Do not try to advance frame when stopped or buffering */
|
||||
if (state >= CLAPPER_PLAYER_STATE_PAUSED)
|
||||
clapper_player_advance_frame (player);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_handle_progression_key_press (ClapperAppWindow *self)
|
||||
{
|
||||
@@ -939,6 +951,10 @@ key_pressed_cb (GtkEventControllerKey *controller, guint keyval,
|
||||
if ((state & GDK_MODIFIER_MASK) == 0)
|
||||
_handle_seek_key_press (self, TRUE);
|
||||
break;
|
||||
case GDK_KEY_e:
|
||||
if ((state & GDK_MODIFIER_MASK) == 0)
|
||||
_handle_advance_frame_key_press (self);
|
||||
break;
|
||||
case GDK_KEY_space:
|
||||
case GDK_KEY_k:
|
||||
if (!self->key_held && (state & GDK_MODIFIER_MASK) == 0)
|
||||
|
||||
@@ -190,6 +190,16 @@
|
||||
<property name="accelerator">less</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="title" translatable="yes">Advance frame</property>
|
||||
<property name="accelerator">e</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkShortcutsGroup">
|
||||
<child>
|
||||
<object class="GtkShortcutsShortcut">
|
||||
<property name="direction">ltr</property>
|
||||
|
||||
@@ -43,6 +43,8 @@ void clapper_playbin_bus_post_seek (GstBus *bus, gdouble position, ClapperPlayer
|
||||
|
||||
void clapper_playbin_bus_post_rate_change (GstBus *bus, gdouble rate);
|
||||
|
||||
void clapper_playbin_bus_post_advance_frame (GstBus *bus);
|
||||
|
||||
void clapper_playbin_bus_post_stream_change (GstBus *bus);
|
||||
|
||||
void clapper_playbin_bus_post_current_item_change (GstBus *bus, ClapperMediaItem *current_item, ClapperQueueItemChangeMode mode);
|
||||
|
||||
@@ -41,6 +41,7 @@ enum
|
||||
CLAPPER_PLAYBIN_BUS_STRUCTURE_SET_PLAY_FLAG,
|
||||
CLAPPER_PLAYBIN_BUS_STRUCTURE_SEEK,
|
||||
CLAPPER_PLAYBIN_BUS_STRUCTURE_RATE_CHANGE,
|
||||
CLAPPER_PLAYBIN_BUS_STRUCTURE_ADVANCE_FRAME,
|
||||
CLAPPER_PLAYBIN_BUS_STRUCTURE_STREAM_CHANGE,
|
||||
CLAPPER_PLAYBIN_BUS_STRUCTURE_CURRENT_ITEM_CHANGE,
|
||||
CLAPPER_PLAYBIN_BUS_STRUCTURE_ITEM_SUBURI_CHANGE,
|
||||
@@ -53,6 +54,7 @@ static ClapperBusQuark _structure_quarks[] = {
|
||||
{"set-play-flag", 0},
|
||||
{"seek", 0},
|
||||
{"rate-change", 0},
|
||||
{"advance-frame", 0},
|
||||
{"stream-change", 0},
|
||||
{"current-item-change", 0},
|
||||
{"item-suburi-change", 0},
|
||||
@@ -568,6 +570,42 @@ _handle_rate_change_msg (GstMessage *msg, const GstStructure *structure, Clapper
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
clapper_playbin_bus_post_advance_frame (GstBus *bus)
|
||||
{
|
||||
GstStructure *structure = gst_structure_new_id_empty (_STRUCTURE_QUARK (ADVANCE_FRAME));
|
||||
gst_bus_post (bus, gst_message_new_application (NULL, structure));
|
||||
}
|
||||
|
||||
static inline void
|
||||
_handle_advance_frame_msg (GstMessage *msg, const GstStructure *structure, ClapperPlayer *player)
|
||||
{
|
||||
GstEvent *step_event;
|
||||
|
||||
/* If we are starting playback or pipeline is going
|
||||
* to be stopped, ignore advance frame operation */
|
||||
if (player->current_state < GST_STATE_PAUSED
|
||||
|| player->target_state < GST_STATE_PAUSED)
|
||||
return;
|
||||
|
||||
/* Pause playback for frame stepping */
|
||||
if (player->target_state != GST_STATE_PAUSED) {
|
||||
player->target_state = GST_STATE_PAUSED;
|
||||
gst_element_set_state (player->playbin, player->target_state);
|
||||
}
|
||||
|
||||
step_event = gst_event_new_step (GST_FORMAT_BUFFERS, 1, 1.0, TRUE, FALSE);
|
||||
GST_DEBUG_OBJECT (player, "Advancing frame");
|
||||
|
||||
clapper_player_remove_tick_source (player);
|
||||
|
||||
if (!(player->stepping = gst_element_send_event (player->playbin, step_event))) {
|
||||
/* FIXME: Should we maybe call _handle_error_msg with
|
||||
* some error here? Or will playbin post such message for us? */
|
||||
GST_ERROR_OBJECT (player, "Could not advance frame");
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_handle_state_changed_msg (GstMessage *msg, ClapperPlayer *player)
|
||||
{
|
||||
@@ -904,6 +942,8 @@ _handle_app_msg (GstMessage *msg, ClapperPlayer *player)
|
||||
_handle_seek_msg (msg, structure, player);
|
||||
else if (quark == _STRUCTURE_QUARK (RATE_CHANGE))
|
||||
_handle_rate_change_msg (msg, structure, player);
|
||||
else if (quark == _STRUCTURE_QUARK (ADVANCE_FRAME))
|
||||
_handle_advance_frame_msg (msg, structure, player);
|
||||
else if (quark == _STRUCTURE_QUARK (STREAM_CHANGE))
|
||||
_handle_stream_change_msg (msg, structure, player);
|
||||
else if (quark == _STRUCTURE_QUARK (CURRENT_ITEM_CHANGE))
|
||||
@@ -1216,6 +1256,11 @@ _handle_async_done_msg (GstMessage *msg G_GNUC_UNUSED, ClapperPlayer *player)
|
||||
clapper_app_bus_post_simple_signal (player->app_bus,
|
||||
GST_OBJECT_CAST (player), signal_id);
|
||||
}
|
||||
if (player->stepping) {
|
||||
player->stepping = FALSE;
|
||||
GST_DEBUG_OBJECT (player, "Frame advanced");
|
||||
clapper_player_refresh_position (player);
|
||||
}
|
||||
if (player->speed_changing) {
|
||||
if (player->pending_speed != 0) {
|
||||
GST_DEBUG_OBJECT (player, "Changing rate to pending value: %.2lf -> %.2lf",
|
||||
|
||||
@@ -87,6 +87,7 @@ struct _ClapperPlayer
|
||||
gboolean use_playbin3; // when using playbin3
|
||||
gboolean had_error; // so we do not do stuff after error
|
||||
gboolean seeking; // during seek operation
|
||||
gboolean stepping; // during frame step operation
|
||||
gboolean speed_changing; // during rate change operation
|
||||
gboolean pending_eos; // when pausing due to EOS
|
||||
gboolean pending_flush; // after another stream selection
|
||||
|
||||
@@ -2195,6 +2195,24 @@ clapper_player_seek_custom (ClapperPlayer *self, gdouble position, ClapperPlayer
|
||||
clapper_playbin_bus_post_seek (self->bus, position, method);
|
||||
}
|
||||
|
||||
/**
|
||||
* clapper_player_advance_frame:
|
||||
* @player: a #ClapperPlayer
|
||||
*
|
||||
* Request the player to perform a frame step operation.
|
||||
*
|
||||
* Note that this will pause playback automatically.
|
||||
*
|
||||
* Since: 0.10
|
||||
*/
|
||||
void
|
||||
clapper_player_advance_frame (ClapperPlayer *self)
|
||||
{
|
||||
g_return_if_fail (CLAPPER_IS_PLAYER (self));
|
||||
|
||||
clapper_playbin_bus_post_advance_frame (self->bus);
|
||||
}
|
||||
|
||||
/**
|
||||
* clapper_player_add_feature:
|
||||
* @player: a #ClapperPlayer
|
||||
|
||||
@@ -204,6 +204,9 @@ void clapper_player_seek (ClapperPlayer *player, gdouble position);
|
||||
CLAPPER_API
|
||||
void clapper_player_seek_custom (ClapperPlayer *player, gdouble position, ClapperPlayerSeekMethod method);
|
||||
|
||||
CLAPPER_API
|
||||
void clapper_player_advance_frame (ClapperPlayer *player);
|
||||
|
||||
CLAPPER_API
|
||||
void clapper_player_add_feature (ClapperPlayer *player, ClapperFeature *feature);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user