mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +00:00
Plugin port to 0.9, ogg/theora playback should work in the seek example now.
Original commit message from CVS: Plugin port to 0.9, ogg/theora playback should work in the seek example now. Removed old examples. Removed old oggvorbisenc, renamed rawvorbisenc to vorbisenc as explained in 0.9 TODO doc.
This commit is contained in:
parent
66cd4c1006
commit
1dae961cbf
63 changed files with 4510 additions and 7584 deletions
159
ChangeLog
159
ChangeLog
|
@ -1,3 +1,162 @@
|
|||
2005-03-31 Wim Taymans <wim@fluendo.com>
|
||||
|
||||
* examples/seeking/Makefile.am:
|
||||
* examples/seeking/cdparanoia.c: (main):
|
||||
* examples/seeking/cdplayer.c: (update_scale), (stop_seek),
|
||||
(play_cb), (pause_cb), (stop_cb), (main):
|
||||
* examples/seeking/playbin.c:
|
||||
* examples/seeking/seek.c: (dynamic_link), (make_mod_pipeline),
|
||||
(make_dv_pipeline), (make_wav_pipeline), (make_flac_pipeline),
|
||||
(make_sid_pipeline), (make_vorbis_pipeline),
|
||||
(make_theora_pipeline), (make_vorbis_theora_pipeline),
|
||||
(make_avi_msmpeg4v3_mp3_pipeline), (make_mp3_pipeline),
|
||||
(make_avi_pipeline), (make_mpeg_pipeline), (make_mpegnt_pipeline),
|
||||
(make_playerbin_pipeline), (update_scale), (end_scrub), (do_seek),
|
||||
(seek_cb), (start_seek), (stop_seek), (play_cb), (pause_cb),
|
||||
(stop_cb), (main):
|
||||
* examples/seeking/spider_seek.c:
|
||||
* examples/seeking/vorbisfile.c:
|
||||
* ext/gnomevfs/Makefile.am:
|
||||
* ext/gnomevfs/gstgnomevfs.c: (plugin_init):
|
||||
* ext/gnomevfs/gstgnomevfssrc.c: (gst_gnomevfssrc_base_init),
|
||||
(gst_gnomevfssrc_class_init), (gst_gnomevfssrc_init),
|
||||
(gst_gnomevfssrc_get_property), (gst_gnomevfssrc_get),
|
||||
(gst_gnomevfssrc_open_file), (gst_gnomevfssrc_close_file),
|
||||
(gst_gnomevfssrc_getrange), (gst_gnomevfssrc_loop),
|
||||
(gst_gnomevfssrc_activate), (gst_gnomevfssrc_change_state),
|
||||
(gst_gnomevfssrc_srcpad_query), (gst_gnomevfssrc_srcpad_event):
|
||||
* ext/ogg/README:
|
||||
* ext/ogg/gstoggdemux.c: (gst_ogg_pad_get_type),
|
||||
(gst_ogg_pad_class_init), (gst_ogg_pad_init),
|
||||
(gst_ogg_pad_dispose), (gst_ogg_pad_finalize),
|
||||
(gst_ogg_pad_formats), (gst_ogg_pad_event_masks),
|
||||
(gst_ogg_pad_query_types), (gst_ogg_pad_getcaps),
|
||||
(gst_ogg_pad_src_convert), (gst_ogg_pad_src_query),
|
||||
(gst_ogg_pad_event), (gst_ogg_pad_reset),
|
||||
(gst_ogg_demux_factory_filter), (compare_ranks),
|
||||
(gst_ogg_pad_internal_chain), (gst_ogg_pad_typefind),
|
||||
(gst_ogg_pad_submit_packet), (gst_ogg_pad_submit_page),
|
||||
(gst_ogg_chain_new), (gst_ogg_chain_free),
|
||||
(gst_ogg_chain_new_stream), (gst_ogg_chain_get_stream),
|
||||
(gst_ogg_chain_has_stream), (gst_ogg_demux_base_init),
|
||||
(gst_ogg_demux_class_init), (gst_ogg_demux_init),
|
||||
(gst_ogg_demux_finalize), (gst_ogg_demux_handle_event),
|
||||
(gst_ogg_demux_submit_buffer), (gst_ogg_demux_seek),
|
||||
(gst_ogg_demux_get_data), (gst_ogg_demux_get_next_page),
|
||||
(gst_ogg_demux_get_prev_page),
|
||||
(gst_ogg_demux_deactivate_current_chain),
|
||||
(gst_ogg_demux_activate_chain), (gst_ogg_demux_perform_seek),
|
||||
(gst_ogg_demux_bisect_forward_serialno),
|
||||
(gst_ogg_demux_read_chain), (gst_ogg_demux_read_end_chain),
|
||||
(gst_ogg_demux_find_pad), (gst_ogg_demux_find_chain),
|
||||
(gst_ogg_demux_find_chains), (gst_ogg_demux_chain_unlocked),
|
||||
(gst_ogg_demux_chain), (gst_ogg_demux_send_eos),
|
||||
(gst_ogg_demux_loop), (gst_ogg_demux_sink_activate),
|
||||
(gst_ogg_demux_change_state), (gst_ogg_print):
|
||||
* ext/ogg/gstoggmux.c: (gst_ogg_mux_class_init),
|
||||
(gst_ogg_mux_init), (gst_ogg_mux_sinkconnect),
|
||||
(gst_ogg_mux_next_buffer), (gst_ogg_mux_buffer_from_page),
|
||||
(gst_ogg_mux_push_page), (gst_ogg_mux_send_headers),
|
||||
(gst_ogg_mux_loop):
|
||||
* ext/ogg/gstogmparse.c: (gst_ogm_parse_chain):
|
||||
* ext/theora/theoradec.c: (gst_theora_dec_init), (_inc_granulepos),
|
||||
(theora_dec_src_convert), (theora_dec_sink_convert),
|
||||
(theora_dec_src_query), (theora_dec_src_event),
|
||||
(theora_dec_sink_event), (theora_dec_chain),
|
||||
(theora_dec_change_state):
|
||||
* ext/theora/theoraenc.c: (gst_theora_enc_init),
|
||||
(theora_enc_sink_setcaps), (theora_buffer_from_packet),
|
||||
(theora_push_buffer), (theora_enc_sink_event), (theora_enc_chain),
|
||||
(theora_enc_change_state):
|
||||
* ext/vorbis/Makefile.am:
|
||||
* ext/vorbis/oggvorbisenc.c:
|
||||
* ext/vorbis/oggvorbisenc.h:
|
||||
* ext/vorbis/vorbis.c: (plugin_init):
|
||||
* ext/vorbis/vorbisdec.c: (gst_vorbis_dec_init),
|
||||
(vorbis_dec_src_query), (vorbis_dec_src_event),
|
||||
(vorbis_dec_sink_event), (vorbis_dec_chain),
|
||||
(vorbis_dec_change_state):
|
||||
* ext/vorbis/vorbisenc.c: (gst_vorbisenc_class_init),
|
||||
(gst_vorbisenc_sink_setcaps), (gst_vorbisenc_init),
|
||||
(gst_vorbisenc_buffer_from_packet), (gst_vorbisenc_push_buffer),
|
||||
(gst_vorbisenc_sink_event), (gst_vorbisenc_chain),
|
||||
(gst_vorbisenc_change_state):
|
||||
* ext/vorbis/vorbisenc.h:
|
||||
* ext/vorbis/vorbisparse.c: (vorbis_parse_chain):
|
||||
* gst-libs/gst/audio/audioclock.c:
|
||||
* gst-libs/gst/audio/gstaudiofilter.c: (gst_audiofilter_link),
|
||||
(gst_audiofilter_init), (gst_audiofilter_chain):
|
||||
* gst-libs/gst/audio/testchannels.c: (main):
|
||||
* gst-libs/gst/gconf/gconf.c: (gst_bin_find_unconnected_pad):
|
||||
* gst-libs/gst/media-info/media-info-priv.c: (gmip_reset),
|
||||
(gmip_find_type), (gmip_find_stream), (gmip_find_track_metadata),
|
||||
(gmip_find_track_streaminfo), (gmip_find_track_format):
|
||||
* gst-libs/gst/media-info/media-info.c:
|
||||
(gst_media_info_read_idler):
|
||||
* gst-libs/gst/play/play.c: (gst_play_get_sink_element),
|
||||
(gst_play_get_all_by_interface):
|
||||
* gst-libs/gst/riff/riff-read.c: (gst_riff_read_chunk),
|
||||
(gst_riff_parse_chunk), (gst_riff_parse_file_header),
|
||||
(gst_riff_parse_strh), (gst_riff_parse_strf_vids),
|
||||
(gst_riff_parse_strf_auds), (gst_riff_parse_strf_iavs),
|
||||
(gst_riff_parse_info):
|
||||
* gst-libs/gst/riff/riff-read.h:
|
||||
* gst-libs/gst/riff/riff.c: (plugin_init):
|
||||
* gst-libs/gst/video/Makefile.am:
|
||||
* gst-libs/gst/video/gstvideosink.c: (gst_videosink_init),
|
||||
(gst_videosink_class_init), (gst_videosink_get_type):
|
||||
* gst-libs/gst/video/videosink.h:
|
||||
* gst/audioconvert/bufferframesconvert.c:
|
||||
(buffer_frames_convert_init), (buffer_frames_convert_fixate),
|
||||
(buffer_frames_convert_setcaps), (buffer_frames_convert_chain):
|
||||
* gst/audioconvert/channelmixtest.c: (main):
|
||||
* gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_init),
|
||||
(gst_audio_convert_chain),
|
||||
(gst_audio_convert_caps_remove_format_info),
|
||||
(gst_audio_convert_getcaps), (gst_audio_convert_parse_caps),
|
||||
(gst_audio_convert_setcaps), (_fixate_caps_to_int),
|
||||
(gst_audio_convert_fixate), (gst_audio_convert_get_buffer),
|
||||
(gst_audio_convert_buffer_to_default_format),
|
||||
(gst_audio_convert_buffer_from_default_format),
|
||||
(gst_audio_convert_channels):
|
||||
* gst/audioconvert/gstchannelmix.h:
|
||||
* gst/ffmpegcolorspace/avcodec.h:
|
||||
* gst/ffmpegcolorspace/gstffmpegcolorspace.c:
|
||||
(gst_ffmpegcsp_caps_remove_format_info), (gst_ffmpegcsp_getcaps),
|
||||
(gst_ffmpegcsp_configure_context), (gst_ffmpegcsp_setcaps),
|
||||
(gst_ffmpegcsp_init), (gst_ffmpegcsp_chain):
|
||||
* gst/tags/gstid3tag.c: (gst_tag_extract_id3v1_string):
|
||||
* gst/tags/gstvorbistag.c: (gst_vorbis_tag_chain):
|
||||
* gst/typefind/gsttypefindfunctions.c: (aac_type_find),
|
||||
(mp3_type_find), (mpeg2_sys_type_find), (mpeg1_sys_type_find),
|
||||
(mpeg_video_type_find), (mpeg_video_stream_type_find),
|
||||
(dv_type_find):
|
||||
* gst/videotestsrc/gstvideotestsrc.c:
|
||||
(gst_videotestsrc_class_init), (gst_videotestsrc_src_negotiate),
|
||||
(gst_videotestsrc_src_link), (gst_videotestsrc_parse_caps),
|
||||
(gst_videotestsrc_src_accept_caps), (gst_videotestsrc_setcaps),
|
||||
(gst_videotestsrc_src_unlink), (gst_videotestsrc_activate),
|
||||
(gst_videotestsrc_change_state), (gst_videotestsrc_getcaps),
|
||||
(gst_videotestsrc_init), (gst_videotestsrc_src_query),
|
||||
(gst_videotestsrc_handle_src_event), (gst_videotestsrc_loop):
|
||||
* sys/xvimage/xvimagesink.c: (gst_xvimagesink_get_xv_support),
|
||||
(gst_xvimagesink_xcontext_clear), (gst_xvimagesink_fixate),
|
||||
(gst_xvimagesink_getcaps), (gst_xvimagesink_setcaps),
|
||||
(gst_xvimagesink_change_state), (gst_xvimagesink_get_times),
|
||||
(gst_xvimagesink_show_frame), (gst_xvimagesink_chain),
|
||||
(gst_xvimagesink_buffer_free), (gst_xvimagesink_buffer_alloc),
|
||||
(gst_xvimagesink_navigation_send_event),
|
||||
(gst_xvimagesink_set_xwindow_id), (gst_xvimagesink_expose),
|
||||
(gst_xvimagesink_set_property), (gst_xvimagesink_finalize),
|
||||
(gst_xvimagesink_init), (gst_xvimagesink_class_init):
|
||||
* sys/xvimage/xvimagesink.h:
|
||||
Plugin port to 0.9, ogg/theora playback should work in the seek
|
||||
example now.
|
||||
Removed old examples.
|
||||
Removed old oggvorbisenc, renamed rawvorbisenc to vorbisenc as
|
||||
explained in 0.9 TODO doc.
|
||||
|
||||
|
||||
2005-02-23 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||
|
||||
* autogen.sh:
|
||||
|
|
2
common
2
common
|
@ -1 +1 @@
|
|||
Subproject commit b2638c100721f67b280c3b43b21f1ce1c9b5e316
|
||||
Subproject commit 131c2632127e6f061b5270d8f80651782a4fdd13
|
|
@ -1,4 +1,4 @@
|
|||
examples = seek spider_seek cdplayer cdparanoia vorbisfile playbin chained
|
||||
examples = seek cdplayer cdparanoia
|
||||
|
||||
noinst_PROGRAMS = $(examples)
|
||||
|
||||
|
|
|
@ -159,7 +159,7 @@ main (int argc, char **argv)
|
|||
gst_element_link_pads (cdparanoia, "src", audiosink, "sink");
|
||||
|
||||
g_signal_connect (G_OBJECT (pipeline), "deep_notify",
|
||||
G_CALLBACK (gst_element_default_deep_notify), NULL);
|
||||
G_CALLBACK (gst_object_default_deep_notify), NULL);
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
|
||||
|
@ -184,10 +184,9 @@ main (int argc, char **argv)
|
|||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
||||
count = 0;
|
||||
while (gst_bin_iterate (GST_BIN (pipeline))) {
|
||||
while (count++ < 500) {
|
||||
get_position_info (cdparanoia);
|
||||
if (count++ > 500)
|
||||
break;
|
||||
g_usleep (G_USEC_PER_SEC / 2);
|
||||
}
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
|
||||
|
@ -202,8 +201,10 @@ main (int argc, char **argv)
|
|||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
||||
while (gst_bin_iterate (GST_BIN (pipeline))) {
|
||||
count = 0;
|
||||
while (count++ < 500) {
|
||||
get_position_info (cdparanoia);
|
||||
g_usleep (G_USEC_PER_SEC / 2);
|
||||
}
|
||||
g_print ("\n");
|
||||
|
||||
|
|
|
@ -125,7 +125,7 @@ update_scale (gpointer data)
|
|||
GstFormat format = GST_FORMAT_TIME;
|
||||
|
||||
duration = 0;
|
||||
clock = gst_bin_get_clock (GST_BIN (pipeline));
|
||||
clock = gst_pipeline_get_clock (GST_PIPELINE (pipeline));
|
||||
|
||||
if (seekable_elements) {
|
||||
GstElement *element = GST_ELEMENT (seekable_elements->data);
|
||||
|
@ -148,20 +148,6 @@ update_scale (gpointer data)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
iterate (gpointer data)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
|
||||
g_print ("iterate\n");
|
||||
res = gst_bin_iterate (GST_BIN (data));
|
||||
if (!res) {
|
||||
gtk_timeout_remove (update_id);
|
||||
g_print ("stopping iterations\n");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
start_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
||||
{
|
||||
|
@ -194,8 +180,6 @@ stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
|||
}
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
if (!GST_FLAG_IS_SET (pipeline, GST_BIN_SELF_SCHEDULABLE))
|
||||
gtk_idle_add ((GtkFunction) iterate, pipeline);
|
||||
update_id =
|
||||
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
|
||||
|
||||
|
@ -205,10 +189,11 @@ stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
|||
static void
|
||||
play_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_PLAYING) {
|
||||
GstElementState state;
|
||||
|
||||
gst_element_get_state (pipeline, &state, NULL, NULL);
|
||||
if (state != GST_STATE_PLAYING) {
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
if (!GST_FLAG_IS_SET (pipeline, GST_BIN_SELF_SCHEDULABLE))
|
||||
gtk_idle_add ((GtkFunction) iterate, pipeline);
|
||||
update_id =
|
||||
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
|
||||
}
|
||||
|
@ -217,7 +202,10 @@ play_cb (GtkButton * button, gpointer data)
|
|||
static void
|
||||
pause_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_PAUSED) {
|
||||
GstElementState state;
|
||||
|
||||
gst_element_get_state (pipeline, &state, NULL, NULL);
|
||||
if (state != GST_STATE_PAUSED) {
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
gtk_timeout_remove (update_id);
|
||||
}
|
||||
|
@ -226,7 +214,10 @@ pause_cb (GtkButton * button, gpointer data)
|
|||
static void
|
||||
stop_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_READY) {
|
||||
GstElementState state;
|
||||
|
||||
gst_element_get_state (pipeline, &state, NULL, NULL);
|
||||
if (state != GST_STATE_READY) {
|
||||
gst_element_set_state (pipeline, GST_STATE_READY);
|
||||
gtk_timeout_remove (update_id);
|
||||
}
|
||||
|
@ -249,9 +240,7 @@ main (int argc, char **argv)
|
|||
pipeline = make_cdaudio_pipeline ();
|
||||
|
||||
g_signal_connect (pipeline, "deep_notify",
|
||||
G_CALLBACK (gst_element_default_deep_notify), NULL);
|
||||
g_signal_connect (pipeline, "error", G_CALLBACK (gst_element_default_error),
|
||||
NULL);
|
||||
G_CALLBACK (gst_object_default_deep_notify), NULL);
|
||||
|
||||
/* initialize gui elements ... */
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
|
|
|
@ -1,270 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gst/gst.h>
|
||||
#include <string.h>
|
||||
|
||||
static GstElement *playbin = NULL;
|
||||
static GstElement *pipeline;
|
||||
static guint64 duration;
|
||||
static GtkAdjustment *adjustment;
|
||||
static GtkWidget *hscale;
|
||||
static gboolean verbose = FALSE;
|
||||
|
||||
static guint update_id;
|
||||
|
||||
#define UPDATE_INTERVAL 500
|
||||
|
||||
static GstElement *
|
||||
make_playerbin_pipeline (const gchar * location)
|
||||
{
|
||||
playbin = gst_element_factory_make ("playbin", "player");
|
||||
g_assert (playbin);
|
||||
|
||||
g_object_set (G_OBJECT (playbin), "uri", location, NULL);
|
||||
|
||||
return playbin;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
format_value (GtkScale * scale, gdouble value)
|
||||
{
|
||||
gint64 real;
|
||||
gint64 seconds;
|
||||
gint64 subseconds;
|
||||
|
||||
real = value * duration / 100;
|
||||
seconds = (gint64) real / GST_SECOND;
|
||||
subseconds = (gint64) real / (GST_SECOND / 100);
|
||||
|
||||
return g_strdup_printf ("%02" G_GINT64_FORMAT ":%02" G_GINT64_FORMAT ":%02"
|
||||
G_GINT64_FORMAT, seconds / 60, seconds % 60, subseconds % 100);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
update_scale (gpointer data)
|
||||
{
|
||||
GstClock *clock;
|
||||
guint64 position;
|
||||
GstFormat format = GST_FORMAT_TIME;
|
||||
gboolean res;
|
||||
|
||||
duration = 0;
|
||||
clock = gst_bin_get_clock (GST_BIN (pipeline));
|
||||
|
||||
res = gst_element_query (playbin, GST_QUERY_TOTAL, &format, &duration);
|
||||
if (!res)
|
||||
duration = 0;
|
||||
res = gst_element_query (playbin, GST_QUERY_POSITION, &format, &position);
|
||||
if (!res)
|
||||
position = 0;
|
||||
|
||||
if (position >= duration)
|
||||
duration = position;
|
||||
|
||||
if (duration > 0) {
|
||||
gtk_adjustment_set_value (adjustment, position * 100.0 / duration);
|
||||
gtk_widget_queue_draw (hscale);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
iterate (gpointer data)
|
||||
{
|
||||
gboolean res;
|
||||
|
||||
if (!GST_FLAG_IS_SET (GST_OBJECT (data), GST_BIN_SELF_SCHEDULABLE)) {
|
||||
res = gst_bin_iterate (GST_BIN (data));
|
||||
} else {
|
||||
g_usleep (UPDATE_INTERVAL);
|
||||
res = gst_element_get_state (GST_ELEMENT (data)) == GST_STATE_PLAYING;
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
gtk_timeout_remove (update_id);
|
||||
g_print ("stopping iterations\n");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
start_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
||||
{
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
gtk_timeout_remove (update_id);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
||||
{
|
||||
gint64 real = gtk_range_get_value (GTK_RANGE (widget)) * duration / 100;
|
||||
gboolean res;
|
||||
GstEvent *s_event;
|
||||
|
||||
g_print ("seek to %" G_GINT64_FORMAT " on element %s\n", real,
|
||||
gst_element_get_name (playbin));
|
||||
s_event =
|
||||
gst_event_new_seek (GST_FORMAT_TIME | GST_SEEK_METHOD_SET |
|
||||
GST_SEEK_FLAG_FLUSH, real);
|
||||
|
||||
res = gst_element_send_event (playbin, s_event);
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
gtk_idle_add ((GtkFunction) iterate, pipeline);
|
||||
update_id =
|
||||
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
print_media_info (GstElement * playbin)
|
||||
{
|
||||
GList *streaminfo;
|
||||
GList *s;
|
||||
|
||||
g_print ("have media info now\n");
|
||||
|
||||
/* get info about the stream */
|
||||
g_object_get (G_OBJECT (playbin), "stream-info", &streaminfo, NULL);
|
||||
|
||||
for (s = streaminfo; s; s = g_list_next (s)) {
|
||||
GObject *obj = G_OBJECT (s->data);
|
||||
gint type;
|
||||
gboolean mute;
|
||||
|
||||
g_object_get (obj, "type", &type, NULL);
|
||||
g_object_get (obj, "mute", &mute, NULL);
|
||||
|
||||
g_print ("%d %d\n", type, mute);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
play_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_PLAYING) {
|
||||
GstElementStateReturn res;
|
||||
|
||||
res = gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
if (res == GST_STATE_SUCCESS) {
|
||||
print_media_info (playbin);
|
||||
|
||||
res = gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
gtk_idle_add ((GtkFunction) iterate, pipeline);
|
||||
update_id =
|
||||
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale,
|
||||
pipeline);
|
||||
} else {
|
||||
g_print ("failed playing\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pause_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_PAUSED) {
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
gtk_timeout_remove (update_id);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
stop_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_READY) {
|
||||
gst_element_set_state (pipeline, GST_STATE_READY);
|
||||
gtk_adjustment_set_value (adjustment, 0.0);
|
||||
gtk_timeout_remove (update_id);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_usage (int argc, char **argv)
|
||||
{
|
||||
g_print ("usage: %s <uri>\n", argv[0]);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
GtkWidget *window, *hbox, *vbox, *play_button, *pause_button, *stop_button;
|
||||
struct poptOption options[] = {
|
||||
{"verbose", 'v', POPT_ARG_NONE | POPT_ARGFLAG_STRIP, &verbose, 0,
|
||||
"Verbose properties", NULL},
|
||||
POPT_TABLEEND
|
||||
};
|
||||
|
||||
gst_init_with_popt_table (&argc, &argv, options);
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
if (argc != 2) {
|
||||
print_usage (argc, argv);
|
||||
exit (-1);
|
||||
}
|
||||
|
||||
pipeline = make_playerbin_pipeline (argv[1]);
|
||||
g_assert (pipeline);
|
||||
|
||||
/* initialize gui elements ... */
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
hbox = gtk_hbox_new (FALSE, 0);
|
||||
vbox = gtk_vbox_new (FALSE, 0);
|
||||
play_button = gtk_button_new_with_label ("play");
|
||||
pause_button = gtk_button_new_with_label ("pause");
|
||||
stop_button = gtk_button_new_with_label ("stop");
|
||||
|
||||
adjustment =
|
||||
GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.00, 100.0, 0.1, 1.0, 1.0));
|
||||
hscale = gtk_hscale_new (adjustment);
|
||||
gtk_scale_set_digits (GTK_SCALE (hscale), 2);
|
||||
gtk_range_set_update_policy (GTK_RANGE (hscale), GTK_UPDATE_CONTINUOUS);
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (hscale),
|
||||
"button_press_event", G_CALLBACK (start_seek), pipeline);
|
||||
gtk_signal_connect (GTK_OBJECT (hscale),
|
||||
"button_release_event", G_CALLBACK (stop_seek), pipeline);
|
||||
gtk_signal_connect (GTK_OBJECT (hscale),
|
||||
"format_value", G_CALLBACK (format_value), pipeline);
|
||||
|
||||
/* do the packing stuff ... */
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 96, 96);
|
||||
gtk_container_add (GTK_CONTAINER (window), vbox);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), hbox);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), play_button, FALSE, FALSE, 2);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), pause_button, FALSE, FALSE, 2);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), stop_button, FALSE, FALSE, 2);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), hscale, TRUE, TRUE, 2);
|
||||
|
||||
/* connect things ... */
|
||||
g_signal_connect (G_OBJECT (play_button), "clicked", G_CALLBACK (play_cb),
|
||||
pipeline);
|
||||
g_signal_connect (G_OBJECT (pause_button), "clicked", G_CALLBACK (pause_cb),
|
||||
pipeline);
|
||||
g_signal_connect (G_OBJECT (stop_button), "clicked", G_CALLBACK (stop_cb),
|
||||
pipeline);
|
||||
g_signal_connect (G_OBJECT (window), "delete_event", gtk_main_quit, NULL);
|
||||
|
||||
/* show the gui. */
|
||||
gtk_widget_show_all (window);
|
||||
|
||||
if (verbose) {
|
||||
g_signal_connect (pipeline, "deep_notify",
|
||||
G_CALLBACK (gst_element_default_deep_notify), NULL);
|
||||
}
|
||||
g_signal_connect (pipeline, "error", G_CALLBACK (gst_element_default_error),
|
||||
NULL);
|
||||
|
||||
gtk_main ();
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
|
||||
gst_object_unref (GST_OBJECT (pipeline));
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,6 +1,3 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
@ -20,12 +17,18 @@ static gboolean elem_seek = FALSE;
|
|||
static gboolean verbose = FALSE;
|
||||
|
||||
static guint update_id;
|
||||
static guint seek_timeout_id = 0;
|
||||
static gulong changed_id;
|
||||
|
||||
//#define SOURCE "gnomevfssrc"
|
||||
#define SOURCE "filesrc"
|
||||
#define SOURCE "gnomevfssrc"
|
||||
|
||||
#define UPDATE_INTERVAL 500
|
||||
|
||||
/* number of milliseconds to play for after a seek */
|
||||
#define SCRUB_TIME 250
|
||||
#define SCRUB
|
||||
|
||||
#define THREAD
|
||||
#define PAD_SEEK
|
||||
|
||||
|
@ -54,13 +57,13 @@ dynamic_link (GstPadTemplate * templ, GstPad * newpad, gpointer data)
|
|||
{
|
||||
dyn_link *connect = (dyn_link *) data;
|
||||
|
||||
if (!strcmp (gst_pad_get_name (newpad), connect->padname)) {
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
gst_bin_add (GST_BIN (pipeline), connect->bin);
|
||||
if (connect->padname == NULL ||
|
||||
!strcmp (gst_pad_get_name (newpad), connect->padname)) {
|
||||
if (connect->bin)
|
||||
gst_bin_add (GST_BIN (pipeline), connect->bin);
|
||||
gst_pad_link (newpad, connect->target);
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
||||
seekable_pads = g_list_prepend (seekable_pads, newpad);
|
||||
//seekable_pads = g_list_prepend (seekable_pads, newpad);
|
||||
rate_pads = g_list_prepend (rate_pads, newpad);
|
||||
}
|
||||
}
|
||||
|
@ -91,7 +94,7 @@ make_mod_pipeline (const gchar * location)
|
|||
|
||||
src = gst_element_factory_make_or_warn (SOURCE, "src");
|
||||
decoder = gst_element_factory_make_or_warn ("modplug", "decoder");
|
||||
audiosink = gst_element_factory_make_or_warn (DEFAULT_AUDIOSINK, "sink");
|
||||
audiosink = gst_element_factory_make_or_warn ("osssink", "sink");
|
||||
//g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
|
||||
|
||||
g_object_set (G_OBJECT (src), "location", location, NULL);
|
||||
|
@ -122,8 +125,8 @@ make_dv_pipeline (const gchar * location)
|
|||
|
||||
src = gst_element_factory_make_or_warn (SOURCE, "src");
|
||||
decoder = gst_element_factory_make_or_warn ("dvdec", "decoder");
|
||||
videosink = gst_element_factory_make_or_warn (DEFAULT_VIDEOSINK, "v_sink");
|
||||
audiosink = gst_element_factory_make_or_warn (DEFAULT_AUDIOSINK, "a_sink");
|
||||
videosink = gst_element_factory_make_or_warn ("ximagesink", "v_sink");
|
||||
audiosink = gst_element_factory_make_or_warn ("osssink", "a_sink");
|
||||
//g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
|
||||
|
||||
g_object_set (G_OBJECT (src), "location", location, NULL);
|
||||
|
@ -159,7 +162,7 @@ make_wav_pipeline (const gchar * location)
|
|||
|
||||
src = gst_element_factory_make_or_warn (SOURCE, "src");
|
||||
decoder = gst_element_factory_make_or_warn ("wavparse", "decoder");
|
||||
audiosink = gst_element_factory_make_or_warn (DEFAULT_AUDIOSINK, "sink");
|
||||
audiosink = gst_element_factory_make_or_warn ("osssink", "sink");
|
||||
//g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
|
||||
|
||||
g_object_set (G_OBJECT (src), "location", location, NULL);
|
||||
|
@ -190,7 +193,7 @@ make_flac_pipeline (const gchar * location)
|
|||
|
||||
src = gst_element_factory_make_or_warn (SOURCE, "src");
|
||||
decoder = gst_element_factory_make_or_warn ("flacdec", "decoder");
|
||||
audiosink = gst_element_factory_make_or_warn (DEFAULT_AUDIOSINK, "sink");
|
||||
audiosink = gst_element_factory_make_or_warn ("osssink", "sink");
|
||||
g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
|
||||
|
||||
g_object_set (G_OBJECT (src), "location", location, NULL);
|
||||
|
@ -221,7 +224,7 @@ make_sid_pipeline (const gchar * location)
|
|||
|
||||
src = gst_element_factory_make_or_warn (SOURCE, "src");
|
||||
decoder = gst_element_factory_make_or_warn ("siddec", "decoder");
|
||||
audiosink = gst_element_factory_make_or_warn (DEFAULT_AUDIOSINK, "sink");
|
||||
audiosink = gst_element_factory_make_or_warn ("osssink", "sink");
|
||||
//g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
|
||||
|
||||
g_object_set (G_OBJECT (src), "location", location, NULL);
|
||||
|
@ -276,25 +279,35 @@ make_parse_pipeline (const gchar * location)
|
|||
static GstElement *
|
||||
make_vorbis_pipeline (const gchar * location)
|
||||
{
|
||||
GstElement *pipeline;
|
||||
GstElement *src, *decoder, *audiosink;
|
||||
GstElement *pipeline, *audio_bin;
|
||||
GstElement *src, *demux, *decoder, *convert, *audiosink;
|
||||
GstPad *seekable;
|
||||
|
||||
pipeline = gst_pipeline_new ("app");
|
||||
|
||||
src = gst_element_factory_make_or_warn (SOURCE, "src");
|
||||
decoder = gst_element_factory_make_or_warn ("vorbisfile", "decoder");
|
||||
audiosink = gst_element_factory_make_or_warn (DEFAULT_AUDIOSINK, "sink");
|
||||
demux = gst_element_factory_make_or_warn ("oggdemux", "demux");
|
||||
decoder = gst_element_factory_make_or_warn ("vorbisdec", "decoder");
|
||||
convert = gst_element_factory_make_or_warn ("audioconvert", "convert");
|
||||
audiosink = gst_element_factory_make_or_warn ("osssink", "sink");
|
||||
g_object_set (G_OBJECT (audiosink), "sync", TRUE, NULL);
|
||||
|
||||
g_object_set (G_OBJECT (src), "location", location, NULL);
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), src);
|
||||
gst_bin_add (GST_BIN (pipeline), decoder);
|
||||
gst_bin_add (GST_BIN (pipeline), audiosink);
|
||||
audio_bin = gst_bin_new ("a_decoder_bin");
|
||||
|
||||
gst_element_link (src, decoder);
|
||||
gst_element_link (decoder, audiosink);
|
||||
gst_bin_add (GST_BIN (pipeline), src);
|
||||
gst_bin_add (GST_BIN (pipeline), demux);
|
||||
gst_bin_add (GST_BIN (audio_bin), decoder);
|
||||
gst_bin_add (GST_BIN (audio_bin), convert);
|
||||
gst_bin_add (GST_BIN (audio_bin), audiosink);
|
||||
gst_bin_add (GST_BIN (pipeline), audio_bin);
|
||||
|
||||
gst_element_link (src, demux);
|
||||
gst_element_link (decoder, convert);
|
||||
gst_element_link (convert, audiosink);
|
||||
|
||||
setup_dynamic_link (demux, NULL, gst_element_get_pad (decoder, "sink"), NULL);
|
||||
|
||||
seekable = gst_element_get_pad (decoder, "src");
|
||||
seekable_pads = g_list_prepend (seekable_pads, seekable);
|
||||
|
@ -304,11 +317,185 @@ make_vorbis_pipeline (const gchar * location)
|
|||
return pipeline;
|
||||
}
|
||||
|
||||
static GstElement *
|
||||
make_theora_pipeline (const gchar * location)
|
||||
{
|
||||
GstElement *pipeline, *video_bin;
|
||||
GstElement *src, *demux, *decoder, *convert, *videosink;
|
||||
GstElement *queue;
|
||||
GstPad *seekable;
|
||||
|
||||
pipeline = gst_pipeline_new ("app");
|
||||
|
||||
src = gst_element_factory_make_or_warn (SOURCE, "src");
|
||||
demux = gst_element_factory_make_or_warn ("oggdemux", "demux");
|
||||
queue = gst_element_factory_make_or_warn ("queue", "queue");
|
||||
decoder = gst_element_factory_make_or_warn ("theoradec", "decoder");
|
||||
convert = gst_element_factory_make_or_warn ("ffmpegcolorspace", "convert");
|
||||
videosink = gst_element_factory_make_or_warn ("xvimagesink", "sink");
|
||||
|
||||
g_object_set (G_OBJECT (src), "location", location, NULL);
|
||||
|
||||
video_bin = gst_bin_new ("v_decoder_bin");
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), src);
|
||||
gst_bin_add (GST_BIN (pipeline), demux);
|
||||
gst_bin_add (GST_BIN (pipeline), queue);
|
||||
gst_bin_add (GST_BIN (video_bin), decoder);
|
||||
gst_bin_add (GST_BIN (video_bin), convert);
|
||||
gst_bin_add (GST_BIN (video_bin), videosink);
|
||||
gst_bin_add (GST_BIN (pipeline), video_bin);
|
||||
|
||||
gst_element_link (src, demux);
|
||||
gst_element_link (queue, decoder);
|
||||
gst_element_link (decoder, convert);
|
||||
gst_element_link (convert, videosink);
|
||||
|
||||
setup_dynamic_link (demux, NULL, gst_element_get_pad (queue, "sink"), NULL);
|
||||
|
||||
seekable = gst_element_get_pad (decoder, "src");
|
||||
seekable_pads = g_list_prepend (seekable_pads, seekable);
|
||||
rate_pads = g_list_prepend (rate_pads, seekable);
|
||||
rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
static GstElement *
|
||||
make_vorbis_theora_pipeline (const gchar * location)
|
||||
{
|
||||
GstElement *pipeline, *audio_bin, *video_bin;
|
||||
GstElement *src, *demux, *a_decoder, *a_convert, *v_decoder, *v_convert;
|
||||
GstElement *audiosink, *videosink;
|
||||
GstElement *a_queue, *v_queue;
|
||||
GstPad *seekable;
|
||||
|
||||
pipeline = gst_pipeline_new ("app");
|
||||
|
||||
src = gst_element_factory_make_or_warn (SOURCE, "src");
|
||||
g_object_set (G_OBJECT (src), "location", location, NULL);
|
||||
|
||||
demux = gst_element_factory_make_or_warn ("oggdemux", "demux");
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), src);
|
||||
gst_bin_add (GST_BIN (pipeline), demux);
|
||||
gst_element_link (src, demux);
|
||||
|
||||
audio_bin = gst_bin_new ("a_decoder_bin");
|
||||
a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
|
||||
a_decoder = gst_element_factory_make_or_warn ("vorbisdec", "a_dec");
|
||||
a_convert = gst_element_factory_make_or_warn ("audioconvert", "a_convert");
|
||||
audiosink = gst_element_factory_make_or_warn ("osssink", "a_sink");
|
||||
|
||||
gst_element_link (a_queue, a_decoder);
|
||||
gst_element_link (a_decoder, a_convert);
|
||||
gst_element_link (a_convert, audiosink);
|
||||
|
||||
gst_bin_add (GST_BIN (audio_bin), a_queue);
|
||||
gst_bin_add (GST_BIN (audio_bin), a_decoder);
|
||||
gst_bin_add (GST_BIN (audio_bin), a_convert);
|
||||
gst_bin_add (GST_BIN (audio_bin), audiosink);
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), audio_bin);
|
||||
|
||||
setup_dynamic_link (demux, NULL, gst_element_get_pad (a_queue, "sink"), NULL);
|
||||
|
||||
video_bin = gst_bin_new ("v_decoder_bin");
|
||||
v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
|
||||
v_decoder = gst_element_factory_make_or_warn ("theoradec", "v_dec");
|
||||
v_convert =
|
||||
gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_convert");
|
||||
videosink = gst_element_factory_make_or_warn ("xvimagesink", "v_sink");
|
||||
gst_element_link_many (v_queue, v_decoder, v_convert, videosink, NULL);
|
||||
|
||||
gst_bin_add (GST_BIN (video_bin), v_queue);
|
||||
gst_bin_add (GST_BIN (video_bin), v_decoder);
|
||||
gst_bin_add (GST_BIN (video_bin), v_convert);
|
||||
gst_bin_add (GST_BIN (video_bin), videosink);
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), video_bin);
|
||||
|
||||
setup_dynamic_link (demux, NULL, gst_element_get_pad (v_queue, "sink"), NULL);
|
||||
|
||||
seekable = gst_element_get_pad (a_decoder, "src");
|
||||
seekable_pads = g_list_prepend (seekable_pads, seekable);
|
||||
rate_pads = g_list_prepend (rate_pads, seekable);
|
||||
rate_pads =
|
||||
g_list_prepend (rate_pads, gst_element_get_pad (a_decoder, "sink"));
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
static GstElement *
|
||||
make_avi_msmpeg4v3_mp3_pipeline (const gchar * location)
|
||||
{
|
||||
GstElement *pipeline, *audio_bin, *video_bin;
|
||||
GstElement *src, *demux, *a_decoder, *a_convert, *v_decoder, *v_convert;
|
||||
GstElement *audiosink, *videosink;
|
||||
GstElement *a_queue, *v_queue;
|
||||
GstPad *seekable;
|
||||
|
||||
pipeline = gst_pipeline_new ("app");
|
||||
|
||||
src = gst_element_factory_make_or_warn (SOURCE, "src");
|
||||
g_object_set (G_OBJECT (src), "location", location, NULL);
|
||||
|
||||
demux = gst_element_factory_make_or_warn ("avidemux", "demux");
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), src);
|
||||
gst_bin_add (GST_BIN (pipeline), demux);
|
||||
gst_element_link (src, demux);
|
||||
|
||||
audio_bin = gst_bin_new ("a_decoder_bin");
|
||||
a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
|
||||
a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
|
||||
a_convert = gst_element_factory_make_or_warn ("audioconvert", "a_convert");
|
||||
audiosink = gst_element_factory_make_or_warn ("osssink", "a_sink");
|
||||
|
||||
gst_element_link (a_queue, a_decoder);
|
||||
gst_element_link (a_decoder, a_convert);
|
||||
gst_element_link (a_convert, audiosink);
|
||||
|
||||
gst_bin_add (GST_BIN (audio_bin), a_queue);
|
||||
gst_bin_add (GST_BIN (audio_bin), a_decoder);
|
||||
gst_bin_add (GST_BIN (audio_bin), a_convert);
|
||||
gst_bin_add (GST_BIN (audio_bin), audiosink);
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), audio_bin);
|
||||
|
||||
setup_dynamic_link (demux, NULL, gst_element_get_pad (a_queue, "sink"), NULL);
|
||||
|
||||
video_bin = gst_bin_new ("v_decoder_bin");
|
||||
v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
|
||||
v_decoder = gst_element_factory_make_or_warn ("ffdec_msmpeg4", "v_dec");
|
||||
v_convert =
|
||||
gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_convert");
|
||||
videosink = gst_element_factory_make_or_warn ("xvimagesink", "v_sink");
|
||||
gst_element_link_many (v_queue, v_decoder, v_convert, videosink, NULL);
|
||||
|
||||
gst_bin_add (GST_BIN (video_bin), v_queue);
|
||||
gst_bin_add (GST_BIN (video_bin), v_decoder);
|
||||
gst_bin_add (GST_BIN (video_bin), v_convert);
|
||||
gst_bin_add (GST_BIN (video_bin), videosink);
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), video_bin);
|
||||
|
||||
setup_dynamic_link (demux, NULL, gst_element_get_pad (v_queue, "sink"), NULL);
|
||||
|
||||
seekable = gst_element_get_pad (a_decoder, "src");
|
||||
seekable_pads = g_list_prepend (seekable_pads, seekable);
|
||||
rate_pads = g_list_prepend (rate_pads, seekable);
|
||||
rate_pads =
|
||||
g_list_prepend (rate_pads, gst_element_get_pad (a_decoder, "sink"));
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
static GstElement *
|
||||
make_mp3_pipeline (const gchar * location)
|
||||
{
|
||||
GstElement *pipeline;
|
||||
GstElement *src, *decoder, *audiosink, *queue, *audio_thread;
|
||||
GstElement *src, *decoder, *osssink, *queue;
|
||||
GstPad *seekable;
|
||||
|
||||
pipeline = gst_pipeline_new ("app");
|
||||
|
@ -316,24 +503,21 @@ make_mp3_pipeline (const gchar * location)
|
|||
src = gst_element_factory_make_or_warn (SOURCE, "src");
|
||||
decoder = gst_element_factory_make_or_warn ("mad", "dec");
|
||||
queue = gst_element_factory_make_or_warn ("queue", "queue");
|
||||
audiosink = gst_element_factory_make_or_warn (DEFAULT_AUDIOSINK, "sink");
|
||||
osssink = gst_element_factory_make_or_warn ("osssink", "sink");
|
||||
|
||||
audio_thread = gst_thread_new ("a_decoder_thread");
|
||||
|
||||
seekable_elements = g_list_prepend (seekable_elements, audiosink);
|
||||
seekable_elements = g_list_prepend (seekable_elements, osssink);
|
||||
|
||||
g_object_set (G_OBJECT (src), "location", location, NULL);
|
||||
g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
|
||||
g_object_set (G_OBJECT (osssink), "fragment", 0x00180008, NULL);
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), src);
|
||||
gst_bin_add (GST_BIN (pipeline), decoder);
|
||||
gst_bin_add (GST_BIN (audio_thread), queue);
|
||||
gst_bin_add (GST_BIN (audio_thread), audiosink);
|
||||
gst_bin_add (GST_BIN (pipeline), audio_thread);
|
||||
gst_bin_add (GST_BIN (pipeline), queue);
|
||||
gst_bin_add (GST_BIN (pipeline), osssink);
|
||||
|
||||
gst_element_link (src, decoder);
|
||||
gst_element_link (decoder, queue);
|
||||
gst_element_link (queue, audiosink);
|
||||
gst_element_link (queue, osssink);
|
||||
|
||||
seekable = gst_element_get_pad (queue, "src");
|
||||
seekable_pads = g_list_prepend (seekable_pads, seekable);
|
||||
|
@ -348,8 +532,7 @@ make_avi_pipeline (const gchar * location)
|
|||
{
|
||||
GstElement *pipeline, *audio_bin, *video_bin;
|
||||
GstElement *src, *demux, *a_decoder, *v_decoder, *audiosink, *videosink;
|
||||
GstElement *a_queue = NULL, *audio_thread = NULL, *v_queue =
|
||||
NULL, *video_thread = NULL;
|
||||
GstElement *a_queue = NULL, *v_queue = NULL;
|
||||
GstPad *seekable;
|
||||
|
||||
pipeline = gst_pipeline_new ("app");
|
||||
|
@ -366,16 +549,14 @@ make_avi_pipeline (const gchar * location)
|
|||
|
||||
audio_bin = gst_bin_new ("a_decoder_bin");
|
||||
a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
|
||||
audio_thread = gst_thread_new ("a_decoder_thread");
|
||||
audiosink = gst_element_factory_make_or_warn (DEFAULT_AUDIOSINK, "a_sink");
|
||||
audiosink = gst_element_factory_make_or_warn ("osssink", "a_sink");
|
||||
//g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
|
||||
a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
|
||||
gst_element_link (a_decoder, a_queue);
|
||||
gst_element_link (a_queue, audiosink);
|
||||
gst_bin_add (GST_BIN (audio_bin), a_decoder);
|
||||
gst_bin_add (GST_BIN (audio_bin), audio_thread);
|
||||
gst_bin_add (GST_BIN (audio_thread), a_queue);
|
||||
gst_bin_add (GST_BIN (audio_thread), audiosink);
|
||||
gst_bin_add (GST_BIN (audio_bin), a_queue);
|
||||
gst_bin_add (GST_BIN (audio_bin), audiosink);
|
||||
gst_element_set_state (audio_bin, GST_STATE_PAUSED);
|
||||
|
||||
setup_dynamic_link (demux, "audio_00", gst_element_get_pad (a_decoder,
|
||||
|
@ -391,8 +572,7 @@ make_avi_pipeline (const gchar * location)
|
|||
//v_decoder = gst_element_factory_make_or_warn ("identity", "v_dec");
|
||||
//v_decoder = gst_element_factory_make_or_warn ("windec", "v_dec");
|
||||
v_decoder = gst_element_factory_make_or_warn ("ffmpegdecall", "v_dec");
|
||||
video_thread = gst_thread_new ("v_decoder_thread");
|
||||
videosink = gst_element_factory_make_or_warn (DEFAULT_VIDEOSINK, "v_sink");
|
||||
videosink = gst_element_factory_make_or_warn ("ximagesink", "v_sink");
|
||||
//videosink = gst_element_factory_make_or_warn ("fakesink", "v_sink");
|
||||
//g_object_set (G_OBJECT (videosink), "sync", TRUE, NULL);
|
||||
v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
|
||||
|
@ -400,9 +580,8 @@ make_avi_pipeline (const gchar * location)
|
|||
gst_element_link (v_decoder, v_queue);
|
||||
gst_element_link (v_queue, videosink);
|
||||
gst_bin_add (GST_BIN (video_bin), v_decoder);
|
||||
gst_bin_add (GST_BIN (video_bin), video_thread);
|
||||
gst_bin_add (GST_BIN (video_thread), v_queue);
|
||||
gst_bin_add (GST_BIN (video_thread), videosink);
|
||||
gst_bin_add (GST_BIN (video_bin), v_queue);
|
||||
gst_bin_add (GST_BIN (video_bin), videosink);
|
||||
|
||||
gst_element_set_state (video_bin, GST_STATE_PAUSED);
|
||||
|
||||
|
@ -424,7 +603,7 @@ make_mpeg_pipeline (const gchar * location)
|
|||
GstElement *pipeline, *audio_bin, *video_bin;
|
||||
GstElement *src, *demux, *a_decoder, *v_decoder, *v_filter;
|
||||
GstElement *audiosink, *videosink;
|
||||
GstElement *a_queue, *audio_thread, *v_queue, *video_thread;
|
||||
GstElement *a_queue, *v_queue;
|
||||
GstPad *seekable;
|
||||
|
||||
pipeline = gst_pipeline_new ("app");
|
||||
|
@ -443,16 +622,14 @@ make_mpeg_pipeline (const gchar * location)
|
|||
|
||||
audio_bin = gst_bin_new ("a_decoder_bin");
|
||||
a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
|
||||
audio_thread = gst_thread_new ("a_decoder_thread");
|
||||
a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
|
||||
audiosink = gst_element_factory_make_or_warn (DEFAULT_AUDIOSINK, "a_sink");
|
||||
audiosink = gst_element_factory_make_or_warn ("osssink", "a_sink");
|
||||
g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
|
||||
gst_element_link (a_decoder, a_queue);
|
||||
gst_element_link (a_queue, audiosink);
|
||||
gst_bin_add (GST_BIN (audio_bin), a_decoder);
|
||||
gst_bin_add (GST_BIN (audio_bin), audio_thread);
|
||||
gst_bin_add (GST_BIN (audio_thread), a_queue);
|
||||
gst_bin_add (GST_BIN (audio_thread), audiosink);
|
||||
gst_bin_add (GST_BIN (audio_bin), a_queue);
|
||||
gst_bin_add (GST_BIN (audio_bin), audiosink);
|
||||
|
||||
setup_dynamic_link (demux, "audio_00", gst_element_get_pad (a_decoder,
|
||||
"sink"), audio_bin);
|
||||
|
@ -465,16 +642,15 @@ make_mpeg_pipeline (const gchar * location)
|
|||
|
||||
video_bin = gst_bin_new ("v_decoder_bin");
|
||||
v_decoder = gst_element_factory_make_or_warn ("mpeg2dec", "v_dec");
|
||||
video_thread = gst_thread_new ("v_decoder_thread");
|
||||
//g_object_set (G_OBJECT (video_thread), "priority", 2, NULL);
|
||||
v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
|
||||
v_filter = gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_filter");
|
||||
videosink = gst_element_factory_make_or_warn (DEFAULT_VIDEOSINK, "v_sink");
|
||||
videosink = gst_element_factory_make_or_warn ("ximagesink", "v_sink");
|
||||
gst_element_link_many (v_decoder, v_queue, v_filter, NULL);
|
||||
|
||||
gst_element_link (v_filter, videosink);
|
||||
gst_bin_add_many (GST_BIN (video_bin), v_decoder, video_thread, NULL);
|
||||
gst_bin_add_many (GST_BIN (video_thread), v_queue, v_filter, videosink, NULL);
|
||||
gst_bin_add_many (GST_BIN (video_bin), v_decoder, NULL);
|
||||
gst_bin_add_many (GST_BIN (video_bin), v_queue, v_filter, videosink, NULL);
|
||||
|
||||
setup_dynamic_link (demux, "video_00", gst_element_get_pad (v_decoder,
|
||||
"sink"), video_bin);
|
||||
|
@ -494,7 +670,7 @@ make_mpegnt_pipeline (const gchar * location)
|
|||
GstElement *pipeline, *audio_bin, *video_bin;
|
||||
GstElement *src, *demux, *a_decoder, *v_decoder, *v_filter;
|
||||
GstElement *audiosink, *videosink;
|
||||
GstElement *a_queue, *audio_thread;
|
||||
GstElement *a_queue;
|
||||
GstPad *seekable;
|
||||
|
||||
pipeline = gst_pipeline_new ("app");
|
||||
|
@ -513,17 +689,15 @@ make_mpegnt_pipeline (const gchar * location)
|
|||
|
||||
audio_bin = gst_bin_new ("a_decoder_bin");
|
||||
a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
|
||||
audio_thread = gst_thread_new ("a_decoder_thread");
|
||||
a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
|
||||
audiosink = gst_element_factory_make_or_warn (DEFAULT_AUDIOSINK, "a_sink");
|
||||
audiosink = gst_element_factory_make_or_warn ("osssink", "a_sink");
|
||||
//g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
|
||||
g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
|
||||
gst_element_link (a_decoder, a_queue);
|
||||
gst_element_link (a_queue, audiosink);
|
||||
gst_bin_add (GST_BIN (audio_bin), a_decoder);
|
||||
gst_bin_add (GST_BIN (audio_bin), audio_thread);
|
||||
gst_bin_add (GST_BIN (audio_thread), a_queue);
|
||||
gst_bin_add (GST_BIN (audio_thread), audiosink);
|
||||
gst_bin_add (GST_BIN (audio_bin), a_queue);
|
||||
gst_bin_add (GST_BIN (audio_bin), audiosink);
|
||||
|
||||
setup_dynamic_link (demux, "audio_00", gst_element_get_pad (a_decoder,
|
||||
"sink"), audio_bin);
|
||||
|
@ -537,7 +711,7 @@ make_mpegnt_pipeline (const gchar * location)
|
|||
video_bin = gst_bin_new ("v_decoder_bin");
|
||||
v_decoder = gst_element_factory_make_or_warn ("mpeg2dec", "v_dec");
|
||||
v_filter = gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_filter");
|
||||
videosink = gst_element_factory_make_or_warn (DEFAULT_VIDEOSINK, "v_sink");
|
||||
videosink = gst_element_factory_make_or_warn ("ximagesink", "v_sink");
|
||||
gst_element_link_many (v_decoder, v_filter, videosink, NULL);
|
||||
|
||||
gst_bin_add_many (GST_BIN (video_bin), v_decoder, v_filter, videosink, NULL);
|
||||
|
@ -554,45 +728,15 @@ make_mpegnt_pipeline (const gchar * location)
|
|||
return pipeline;
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
fixate (GstPad * pad, const GstCaps * in_caps, gpointer data)
|
||||
{
|
||||
GstCaps *caps;
|
||||
GstStructure *s;
|
||||
|
||||
if (gst_caps_get_size (in_caps) > 1)
|
||||
return NULL;
|
||||
|
||||
/* nothing if fixed already */
|
||||
s = gst_caps_get_structure (in_caps, 0);
|
||||
if (gst_structure_has_field_typed (s, "width", G_TYPE_INT) &&
|
||||
gst_structure_has_field_typed (s, "height", G_TYPE_INT) &&
|
||||
gst_structure_has_field_typed (s, "framerate", G_TYPE_DOUBLE))
|
||||
return NULL;
|
||||
|
||||
/* fixate */
|
||||
caps = gst_caps_copy (in_caps);
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
gst_caps_structure_fixate_field_nearest_int (s, "width", 200);
|
||||
gst_caps_structure_fixate_field_nearest_int (s, "height", 150);
|
||||
gst_caps_structure_fixate_field_nearest_double (s, "framerate", 10.0);
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
static GstElement *
|
||||
make_playerbin_pipeline (const gchar * location)
|
||||
{
|
||||
GstElement *player, *vis;
|
||||
GstElement *player;
|
||||
|
||||
player = gst_element_factory_make ("playbin", "player");
|
||||
vis = gst_element_factory_make ("synaesthesia", "vis");
|
||||
g_assert (player);
|
||||
g_assert (vis);
|
||||
|
||||
g_signal_connect (gst_element_get_pad (vis, "src"), "fixate",
|
||||
G_CALLBACK (fixate), NULL);
|
||||
g_object_set (G_OBJECT (player), "uri", location, "vis-plugin", vis, NULL);
|
||||
g_object_set (G_OBJECT (player), "uri", location, NULL);
|
||||
|
||||
seekable_elements = g_list_prepend (seekable_elements, player);
|
||||
|
||||
|
@ -791,7 +935,7 @@ update_scale (gpointer data)
|
|||
gboolean res;
|
||||
|
||||
duration = 0;
|
||||
clock = gst_bin_get_clock (GST_BIN (pipeline));
|
||||
clock = gst_pipeline_get_clock (GST_PIPELINE (pipeline));
|
||||
|
||||
if (elem_seek) {
|
||||
if (seekable_elements) {
|
||||
|
@ -843,36 +987,21 @@ update_scale (gpointer data)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void do_seek (GtkWidget * widget);
|
||||
|
||||
#ifdef SCRUB
|
||||
static gboolean
|
||||
iterate (gpointer data)
|
||||
{
|
||||
gboolean res;
|
||||
|
||||
if (!GST_FLAG_IS_SET (GST_OBJECT (data), GST_BIN_SELF_SCHEDULABLE)) {
|
||||
res = gst_bin_iterate (GST_BIN (data));
|
||||
} else {
|
||||
g_usleep (500);
|
||||
res = gst_element_get_state (GST_ELEMENT (data)) == GST_STATE_PLAYING;
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
gtk_timeout_remove (update_id);
|
||||
g_print ("stopping iterations\n");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
start_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
||||
end_scrub (GtkWidget * widget)
|
||||
{
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
gtk_timeout_remove (update_id);
|
||||
seek_timeout_id = 0;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
||||
static void
|
||||
do_seek (GtkWidget * widget)
|
||||
{
|
||||
gint64 real = gtk_range_get_value (GTK_RANGE (widget)) * duration / 100;
|
||||
gboolean res;
|
||||
|
@ -884,8 +1013,8 @@ stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
|||
while (walk) {
|
||||
GstPad *seekable = GST_PAD (walk->data);
|
||||
|
||||
g_print ("seek to %" G_GINT64_FORMAT " on pad %s:%s\n", real,
|
||||
GST_DEBUG_PAD_NAME (seekable));
|
||||
g_print ("seek to %" GST_TIME_FORMAT " on pad %s:%s\n",
|
||||
GST_TIME_ARGS (real), GST_DEBUG_PAD_NAME (seekable));
|
||||
s_event =
|
||||
gst_event_new_seek (GST_FORMAT_TIME | GST_SEEK_METHOD_SET |
|
||||
GST_SEEK_FLAG_FLUSH, real);
|
||||
|
@ -912,8 +1041,57 @@ stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
|||
}
|
||||
}
|
||||
|
||||
GST_PIPELINE (pipeline)->stream_time = real;
|
||||
}
|
||||
|
||||
static void
|
||||
seek_cb (GtkWidget * widget)
|
||||
{
|
||||
#ifdef SCRUB
|
||||
/* If the timer hasn't expired yet, then the pipeline is running */
|
||||
if (seek_timeout_id != 0) {
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
}
|
||||
#endif
|
||||
|
||||
do_seek (widget);
|
||||
|
||||
#ifdef SCRUB
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
gtk_idle_add ((GtkFunction) iterate, pipeline);
|
||||
|
||||
if (seek_timeout_id == 0) {
|
||||
seek_timeout_id =
|
||||
gtk_timeout_add (SCRUB_TIME, (GSourceFunc) end_scrub, widget);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static gboolean
|
||||
start_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
||||
{
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
gtk_timeout_remove (update_id);
|
||||
|
||||
if (changed_id == 0) {
|
||||
changed_id = gtk_signal_connect (GTK_OBJECT (hscale),
|
||||
"value_changed", G_CALLBACK (seek_cb), pipeline);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
stop_seek (GtkWidget * widget, gpointer user_data)
|
||||
{
|
||||
g_signal_handler_disconnect (GTK_OBJECT (hscale), changed_id);
|
||||
changed_id = 0;
|
||||
if (seek_timeout_id != 0) {
|
||||
gtk_timeout_remove (seek_timeout_id);
|
||||
seek_timeout_id = 0;
|
||||
/* Still scrubbing, so the pipeline is already playing */
|
||||
} else
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
||||
update_id =
|
||||
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
|
||||
|
||||
|
@ -923,9 +1101,11 @@ stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
|||
static void
|
||||
play_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_PLAYING) {
|
||||
GstElementState state;
|
||||
|
||||
gst_element_get_state (pipeline, &state, NULL, NULL);
|
||||
if (state != GST_STATE_PLAYING) {
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
gtk_idle_add ((GtkFunction) iterate, pipeline);
|
||||
update_id =
|
||||
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
|
||||
}
|
||||
|
@ -934,7 +1114,10 @@ play_cb (GtkButton * button, gpointer data)
|
|||
static void
|
||||
pause_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_PAUSED) {
|
||||
GstElementState state;
|
||||
|
||||
gst_element_get_state (pipeline, &state, NULL, NULL);
|
||||
if (state != GST_STATE_PAUSED) {
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
gtk_timeout_remove (update_id);
|
||||
}
|
||||
|
@ -943,7 +1126,10 @@ pause_cb (GtkButton * button, gpointer data)
|
|||
static void
|
||||
stop_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_READY) {
|
||||
GstElementState state;
|
||||
|
||||
gst_element_get_state (pipeline, &state, NULL, NULL);
|
||||
if (state != GST_STATE_READY) {
|
||||
gst_element_set_state (pipeline, GST_STATE_READY);
|
||||
gtk_adjustment_set_value (adjustment, 0.0);
|
||||
gtk_timeout_remove (update_id);
|
||||
|
@ -963,6 +1149,9 @@ static Pipeline pipelines[] = {
|
|||
{"mpeg1", make_mpeg_pipeline},
|
||||
{"mpegparse", make_parse_pipeline},
|
||||
{"vorbis", make_vorbis_pipeline},
|
||||
{"theora", make_theora_pipeline},
|
||||
{"ogg/v/t", make_vorbis_theora_pipeline},
|
||||
{"avi/msmpeg4v3/mp3", make_avi_msmpeg4v3_mp3_pipeline},
|
||||
{"sid", make_sid_pipeline},
|
||||
{"flac", make_flac_pipeline},
|
||||
{"wav", make_wav_pipeline},
|
||||
|
@ -1065,18 +1254,13 @@ main (int argc, char **argv)
|
|||
|
||||
if (verbose) {
|
||||
g_signal_connect (pipeline, "deep_notify",
|
||||
G_CALLBACK (gst_element_default_deep_notify), NULL);
|
||||
G_CALLBACK (gst_object_default_deep_notify), NULL);
|
||||
}
|
||||
g_signal_connect (pipeline, "error", G_CALLBACK (gst_element_default_error),
|
||||
NULL);
|
||||
|
||||
gtk_main ();
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
|
||||
//gst_object_unref (GST_OBJECT (pipeline));
|
||||
|
||||
//g_mem_chunk_info();
|
||||
gst_object_unref (GST_OBJECT (pipeline));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,379 +0,0 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gst/gst.h>
|
||||
#include <string.h>
|
||||
|
||||
static GList *rate_pads = NULL;
|
||||
static GList *seekable_elements = NULL;
|
||||
|
||||
static GstElement *pipeline;
|
||||
static GtkAdjustment *adjustment;
|
||||
static gboolean stats = FALSE;
|
||||
static guint64 duration;
|
||||
|
||||
static guint update_id;
|
||||
|
||||
//#define SOURCE "gnomevfssrc"
|
||||
#define SOURCE "filesrc"
|
||||
|
||||
#define UPDATE_INTERVAL 500
|
||||
|
||||
static GstElement *
|
||||
make_spider_pipeline (const gchar * location, gboolean thread)
|
||||
{
|
||||
GstElement *pipeline;
|
||||
GstElement *src, *decoder, *audiosink, *videosink, *a_thread, *v_thread,
|
||||
*a_queue, *v_queue;
|
||||
|
||||
if (thread) {
|
||||
pipeline = gst_thread_new ("app");
|
||||
} else {
|
||||
pipeline = gst_pipeline_new ("app");
|
||||
}
|
||||
|
||||
|
||||
src = gst_element_factory_make (SOURCE, "src");
|
||||
decoder = gst_element_factory_make ("spider", "decoder");
|
||||
a_thread = gst_thread_new ("a_thread");
|
||||
a_queue = gst_element_factory_make ("queue", "a_queue");
|
||||
audiosink = gst_element_factory_make (DEFAULT_AUDIOSINK, "a_sink");
|
||||
//g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
|
||||
|
||||
v_thread = gst_thread_new ("v_thread");
|
||||
v_queue = gst_element_factory_make ("queue", "v_queue");
|
||||
videosink = gst_element_factory_make (DEFAULT_VIDEOSINK, "v_sink");
|
||||
//g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
|
||||
|
||||
g_object_set (G_OBJECT (src), "location", location, NULL);
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), src);
|
||||
gst_bin_add (GST_BIN (pipeline), decoder);
|
||||
gst_bin_add (GST_BIN (a_thread), a_queue);
|
||||
gst_bin_add (GST_BIN (a_thread), audiosink);
|
||||
gst_bin_add (GST_BIN (v_thread), v_queue);
|
||||
gst_bin_add (GST_BIN (v_thread), videosink);
|
||||
gst_bin_add (GST_BIN (pipeline), a_thread);
|
||||
gst_bin_add (GST_BIN (pipeline), v_thread);
|
||||
|
||||
gst_element_link (src, decoder);
|
||||
gst_element_link (v_queue, videosink);
|
||||
gst_element_link (decoder, v_queue);
|
||||
gst_element_link (a_queue, audiosink);
|
||||
gst_element_link (decoder, a_queue);
|
||||
|
||||
seekable_elements = g_list_prepend (seekable_elements, videosink);
|
||||
seekable_elements = g_list_prepend (seekable_elements, audiosink);
|
||||
rate_pads =
|
||||
g_list_prepend (rate_pads, gst_element_get_pad (audiosink, "sink"));
|
||||
rate_pads =
|
||||
g_list_prepend (rate_pads, gst_element_get_pad (videosink, "sink"));
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
format_value (GtkScale * scale, gdouble value)
|
||||
{
|
||||
gint64 real;
|
||||
gint64 seconds;
|
||||
gint64 subseconds;
|
||||
|
||||
real = value * duration / 100;
|
||||
seconds = (gint64) real / GST_SECOND;
|
||||
subseconds = (gint64) real / (GST_SECOND / 100);
|
||||
|
||||
return g_strdup_printf ("%02" G_GINT64_FORMAT ":%02" G_GINT64_FORMAT ":%02"
|
||||
G_GINT64_FORMAT, seconds / 60, seconds % 60, subseconds % 100);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const gchar *name;
|
||||
const GstFormat format;
|
||||
}
|
||||
seek_format;
|
||||
|
||||
static seek_format seek_formats[] = {
|
||||
{"tim", GST_FORMAT_TIME},
|
||||
{"byt", GST_FORMAT_BYTES},
|
||||
{"buf", GST_FORMAT_BUFFERS},
|
||||
{"def", GST_FORMAT_DEFAULT},
|
||||
{NULL, 0},
|
||||
};
|
||||
|
||||
G_GNUC_UNUSED static void
|
||||
query_rates (void)
|
||||
{
|
||||
GList *walk = rate_pads;
|
||||
|
||||
while (walk) {
|
||||
GstPad *pad = GST_PAD (walk->data);
|
||||
gint i = 0;
|
||||
|
||||
g_print ("rate/sec %8.8s: ", GST_PAD_NAME (pad));
|
||||
while (seek_formats[i].name) {
|
||||
gint64 value;
|
||||
GstFormat format;
|
||||
|
||||
format = seek_formats[i].format;
|
||||
|
||||
if (gst_pad_convert (pad, GST_FORMAT_TIME, GST_SECOND, &format, &value)) {
|
||||
g_print ("%s %13" G_GINT64_FORMAT " | ", seek_formats[i].name, value);
|
||||
} else {
|
||||
g_print ("%s %13.13s | ", seek_formats[i].name, "*NA*");
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
g_print (" %s:%s\n", GST_DEBUG_PAD_NAME (pad));
|
||||
|
||||
walk = g_list_next (walk);
|
||||
}
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static void
|
||||
query_durations ()
|
||||
{
|
||||
GList *walk = seekable_elements;
|
||||
|
||||
while (walk) {
|
||||
GstElement *element = GST_ELEMENT (walk->data);
|
||||
gint i = 0;
|
||||
|
||||
g_print ("durations %8.8s: ", GST_ELEMENT_NAME (element));
|
||||
while (seek_formats[i].name) {
|
||||
gboolean res;
|
||||
gint64 value;
|
||||
GstFormat format;
|
||||
|
||||
format = seek_formats[i].format;
|
||||
res = gst_element_query (element, GST_QUERY_TOTAL, &format, &value);
|
||||
if (res) {
|
||||
g_print ("%s %13" G_GINT64_FORMAT " | ", seek_formats[i].name, value);
|
||||
} else {
|
||||
g_print ("%s %13.13s | ", seek_formats[i].name, "*NA*");
|
||||
}
|
||||
i++;
|
||||
}
|
||||
g_print (" %s\n", GST_ELEMENT_NAME (element));
|
||||
walk = g_list_next (walk);
|
||||
}
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static void
|
||||
query_positions ()
|
||||
{
|
||||
GList *walk = seekable_elements;
|
||||
|
||||
while (walk) {
|
||||
GstElement *element = GST_ELEMENT (walk->data);
|
||||
gint i = 0;
|
||||
|
||||
g_print ("positions %8.8s: ", GST_ELEMENT_NAME (element));
|
||||
while (seek_formats[i].name) {
|
||||
gboolean res;
|
||||
gint64 value;
|
||||
GstFormat format;
|
||||
|
||||
format = seek_formats[i].format;
|
||||
res = gst_element_query (element, GST_QUERY_POSITION, &format, &value);
|
||||
if (res) {
|
||||
g_print ("%s %13" G_GINT64_FORMAT " | ", seek_formats[i].name, value);
|
||||
} else {
|
||||
g_print ("%s %13.13s | ", seek_formats[i].name, "*NA*");
|
||||
}
|
||||
i++;
|
||||
}
|
||||
g_print (" %s\n", GST_ELEMENT_NAME (element));
|
||||
walk = g_list_next (walk);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
update_scale (gpointer data)
|
||||
{
|
||||
GstClock *clock;
|
||||
guint64 position;
|
||||
GstFormat format = GST_FORMAT_TIME;
|
||||
|
||||
duration = 0;
|
||||
clock = gst_bin_get_clock (GST_BIN (pipeline));
|
||||
|
||||
if (seekable_elements) {
|
||||
GstElement *element = GST_ELEMENT (seekable_elements->data);
|
||||
|
||||
gst_element_query (element, GST_QUERY_TOTAL, &format, &duration);
|
||||
}
|
||||
position = gst_clock_get_time (clock);
|
||||
|
||||
if (stats) {
|
||||
g_print ("clock: %13" G_GUINT64_FORMAT " (%s)\n",
|
||||
position, gst_object_get_name (GST_OBJECT (clock)));
|
||||
query_durations ();
|
||||
query_positions ();
|
||||
query_rates ();
|
||||
}
|
||||
if (duration > 0) {
|
||||
gtk_adjustment_set_value (adjustment, position * 100.0 / duration);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
iterate (gpointer data)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
|
||||
res = gst_bin_iterate (GST_BIN (data));
|
||||
if (!res) {
|
||||
gtk_timeout_remove (update_id);
|
||||
g_print ("stopping iterations\n");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
start_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
||||
{
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
gtk_timeout_remove (update_id);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
||||
{
|
||||
gint64 real = gtk_range_get_value (GTK_RANGE (widget)) * duration / 100;
|
||||
gboolean res;
|
||||
GstEvent *s_event;
|
||||
GList *walk = seekable_elements;
|
||||
|
||||
while (walk) {
|
||||
GstElement *seekable = GST_ELEMENT (walk->data);
|
||||
|
||||
g_print ("seek to %" G_GINT64_FORMAT " on element %s\n", real,
|
||||
GST_ELEMENT_NAME (seekable));
|
||||
s_event =
|
||||
gst_event_new_seek (GST_FORMAT_TIME | GST_SEEK_METHOD_SET |
|
||||
GST_SEEK_FLAG_FLUSH, real);
|
||||
|
||||
res = gst_element_send_event (seekable, s_event);
|
||||
|
||||
walk = g_list_next (walk);
|
||||
}
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
if (!GST_FLAG_IS_SET (pipeline, GST_BIN_SELF_SCHEDULABLE))
|
||||
gtk_idle_add ((GtkFunction) iterate, pipeline);
|
||||
update_id =
|
||||
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
play_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_PLAYING) {
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
if (!GST_FLAG_IS_SET (pipeline, GST_BIN_SELF_SCHEDULABLE))
|
||||
gtk_idle_add ((GtkFunction) iterate, pipeline);
|
||||
update_id =
|
||||
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pause_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_PAUSED) {
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
gtk_timeout_remove (update_id);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
stop_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_READY) {
|
||||
gst_element_set_state (pipeline, GST_STATE_READY);
|
||||
gtk_timeout_remove (update_id);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
GtkWidget *window, *hbox, *vbox,
|
||||
*play_button, *pause_button, *stop_button, *hscale;
|
||||
gboolean threaded = FALSE;
|
||||
struct poptOption options[] = {
|
||||
{"threaded", 't', POPT_ARG_NONE | POPT_ARGFLAG_STRIP, &threaded, 0,
|
||||
"Run the pipeline in a toplevel thread", NULL},
|
||||
{"stats", 's', POPT_ARG_NONE | POPT_ARGFLAG_STRIP, &stats, 0,
|
||||
"Show element stats", NULL},
|
||||
POPT_TABLEEND
|
||||
};
|
||||
|
||||
gst_init_with_popt_table (&argc, &argv, options);
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
if (argc != 2) {
|
||||
g_print ("usage: %s <filename>\n", argv[0]);
|
||||
exit (-1);
|
||||
}
|
||||
|
||||
pipeline = make_spider_pipeline (argv[1], threaded);
|
||||
|
||||
/* initialize gui elements ... */
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
hbox = gtk_hbox_new (FALSE, 0);
|
||||
vbox = gtk_vbox_new (FALSE, 0);
|
||||
play_button = gtk_button_new_with_label ("play");
|
||||
pause_button = gtk_button_new_with_label ("pause");
|
||||
stop_button = gtk_button_new_with_label ("stop");
|
||||
|
||||
adjustment =
|
||||
GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.00, 100.0, 0.1, 1.0, 1.0));
|
||||
hscale = gtk_hscale_new (adjustment);
|
||||
gtk_scale_set_digits (GTK_SCALE (hscale), 2);
|
||||
gtk_range_set_update_policy (GTK_RANGE (hscale), GTK_UPDATE_CONTINUOUS);
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (hscale),
|
||||
"button_press_event", G_CALLBACK (start_seek), pipeline);
|
||||
gtk_signal_connect (GTK_OBJECT (hscale),
|
||||
"button_release_event", G_CALLBACK (stop_seek), pipeline);
|
||||
gtk_signal_connect (GTK_OBJECT (hscale),
|
||||
"format_value", G_CALLBACK (format_value), pipeline);
|
||||
|
||||
/* do the packing stuff ... */
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 96, 96);
|
||||
gtk_container_add (GTK_CONTAINER (window), vbox);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), hbox);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), play_button, FALSE, FALSE, 2);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), pause_button, FALSE, FALSE, 2);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), stop_button, FALSE, FALSE, 2);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), hscale, TRUE, TRUE, 2);
|
||||
|
||||
/* connect things ... */
|
||||
g_signal_connect (G_OBJECT (play_button), "clicked", G_CALLBACK (play_cb),
|
||||
pipeline);
|
||||
g_signal_connect (G_OBJECT (pause_button), "clicked", G_CALLBACK (pause_cb),
|
||||
pipeline);
|
||||
g_signal_connect (G_OBJECT (stop_button), "clicked", G_CALLBACK (stop_cb),
|
||||
pipeline);
|
||||
g_signal_connect (G_OBJECT (window), "delete_event", gtk_main_quit, NULL);
|
||||
|
||||
/* show the gui. */
|
||||
gtk_widget_show_all (window);
|
||||
|
||||
gtk_main ();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,266 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <gst/gst.h>
|
||||
#include <string.h>
|
||||
|
||||
static gboolean ready = FALSE;
|
||||
|
||||
struct probe_context
|
||||
{
|
||||
GstElement *pipeline;
|
||||
GstElement *element;
|
||||
GstPad *pad;
|
||||
GstFormat ls_format;
|
||||
|
||||
gint total_ls;
|
||||
|
||||
GstCaps *metadata;
|
||||
GstCaps *streaminfo;
|
||||
GstCaps *caps;
|
||||
};
|
||||
|
||||
static void
|
||||
print_caps (GstCaps * caps)
|
||||
{
|
||||
char *s;
|
||||
|
||||
s = gst_caps_to_string (caps);
|
||||
g_print (" %s\n", s);
|
||||
g_free (s);
|
||||
}
|
||||
|
||||
static void
|
||||
print_format (GstCaps * caps)
|
||||
{
|
||||
char *s;
|
||||
|
||||
s = gst_caps_to_string (caps);
|
||||
g_print (" format: %s\n", s);
|
||||
g_free (s);
|
||||
}
|
||||
|
||||
static void
|
||||
print_lbs_info (struct probe_context *context, gint stream)
|
||||
{
|
||||
const GstFormat *formats;
|
||||
|
||||
/* FIXME: need a better name here */
|
||||
g_print (" stream info:\n");
|
||||
|
||||
/* report info in all supported formats */
|
||||
formats = gst_pad_get_formats (context->pad);
|
||||
while (*formats) {
|
||||
const GstFormatDefinition *definition;
|
||||
gint64 value_start, value_end;
|
||||
gboolean res;
|
||||
GstFormat format;
|
||||
|
||||
format = *formats;
|
||||
formats++;
|
||||
|
||||
if (format == context->ls_format) {
|
||||
continue;
|
||||
}
|
||||
|
||||
definition = gst_format_get_details (format);
|
||||
|
||||
/* get start and end position of this stream */
|
||||
res = gst_pad_convert (context->pad,
|
||||
context->ls_format, stream, &format, &value_start);
|
||||
res &= gst_pad_convert (context->pad,
|
||||
context->ls_format, stream + 1, &format, &value_end);
|
||||
|
||||
if (res) {
|
||||
/* substract to get the length */
|
||||
value_end -= value_start;
|
||||
|
||||
if (format == GST_FORMAT_TIME) {
|
||||
value_end /= (GST_SECOND / 100);
|
||||
g_print (" %s: %" G_GINT64_FORMAT ":%02" G_GINT64_FORMAT ".%02"
|
||||
G_GINT64_FORMAT "\n", definition->nick, value_end / 6000,
|
||||
(value_end / 100) % 60, (value_end % 100));
|
||||
} else {
|
||||
g_print (" %s: %" G_GINT64_FORMAT "\n", definition->nick, value_end);
|
||||
}
|
||||
} else
|
||||
g_print (" could not get logical stream %s\n", definition->nick);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
deep_notify (GObject * object, GstObject * origin,
|
||||
GParamSpec * pspec, gpointer data)
|
||||
{
|
||||
struct probe_context *context = (struct probe_context *) data;
|
||||
GValue value = { 0, };
|
||||
|
||||
if (!strcmp (pspec->name, "metadata")) {
|
||||
|
||||
g_value_init (&value, pspec->value_type);
|
||||
g_object_get_property (G_OBJECT (origin), pspec->name, &value);
|
||||
context->metadata = g_value_peek_pointer (&value);
|
||||
} else if (!strcmp (pspec->name, "streaminfo")) {
|
||||
|
||||
g_value_init (&value, pspec->value_type);
|
||||
g_object_get_property (G_OBJECT (origin), pspec->name, &value);
|
||||
context->streaminfo = g_value_peek_pointer (&value);
|
||||
} else if (!strcmp (pspec->name, "caps")) {
|
||||
if (GST_IS_PAD (origin) && GST_PAD (origin) == context->pad) {
|
||||
g_value_init (&value, pspec->value_type);
|
||||
g_object_get_property (G_OBJECT (origin), pspec->name, &value);
|
||||
context->caps = g_value_peek_pointer (&value);
|
||||
|
||||
ready = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
collect_logical_stream_properties (struct probe_context *context, gint stream)
|
||||
{
|
||||
GstEvent *event;
|
||||
gboolean res;
|
||||
gint count;
|
||||
|
||||
g_print ("info for logical stream %d:\n", stream);
|
||||
|
||||
/* seek to stream */
|
||||
event = gst_event_new_seek (context->ls_format |
|
||||
GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH, stream);
|
||||
res = gst_pad_send_event (context->pad, event);
|
||||
if (!res) {
|
||||
g_warning ("seek to logical track failed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* run the pipeline to get the info */
|
||||
count = 0;
|
||||
ready = FALSE;
|
||||
while (gst_bin_iterate (GST_BIN (context->pipeline)) && !ready) {
|
||||
count++;
|
||||
if (count > 10)
|
||||
break;
|
||||
}
|
||||
|
||||
print_caps (context->metadata);
|
||||
print_caps (context->streaminfo);
|
||||
print_format (context->caps);
|
||||
print_lbs_info (context, stream);
|
||||
|
||||
g_print ("\n");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
collect_stream_properties (struct probe_context *context)
|
||||
{
|
||||
const GstFormat *formats;
|
||||
|
||||
ready = FALSE;
|
||||
while (gst_bin_iterate (GST_BIN (context->pipeline)) && !ready);
|
||||
|
||||
g_print ("stream info:\n");
|
||||
|
||||
context->total_ls = -1;
|
||||
|
||||
/* report info in all supported formats */
|
||||
formats = gst_pad_get_formats (context->pad);
|
||||
while (*formats) {
|
||||
const GstFormatDefinition *definition;
|
||||
gint64 value;
|
||||
gboolean res;
|
||||
GstFormat format;
|
||||
|
||||
format = *formats;
|
||||
formats++;
|
||||
|
||||
res = gst_pad_query (context->pad, GST_QUERY_TOTAL, &format, &value);
|
||||
|
||||
definition = gst_format_get_details (format);
|
||||
|
||||
if (res) {
|
||||
if (format == GST_FORMAT_TIME) {
|
||||
value /= (GST_SECOND / 100);
|
||||
g_print (" total %s: %" G_GINT64_FORMAT ":%02" G_GINT64_FORMAT ".%02"
|
||||
G_GINT64_FORMAT "\n", definition->nick, value / 6000,
|
||||
(value / 100) % 60, (value % 100));
|
||||
} else {
|
||||
if (format == context->ls_format)
|
||||
context->total_ls = value;
|
||||
g_print (" total %s: %" G_GINT64_FORMAT "\n", definition->nick, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (context->total_ls == -1) {
|
||||
g_warning (" could not get number of logical streams");
|
||||
}
|
||||
g_print ("\n");
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
GstElement *pipeline;
|
||||
GstElement *filesrc;
|
||||
GstElement *vorbisfile;
|
||||
GstPad *pad;
|
||||
GstFormat logical_stream_format;
|
||||
struct probe_context *context;
|
||||
gint stream;
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
if (argc < 2) {
|
||||
g_print ("usage: %s <oggfile>\n", argv[0]);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
pipeline = gst_pipeline_new ("pipeline");
|
||||
|
||||
filesrc = gst_element_factory_make ("filesrc", "filesrc");
|
||||
g_assert (filesrc);
|
||||
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
|
||||
|
||||
vorbisfile = gst_element_factory_make ("vorbisfile", "vorbisfile");
|
||||
//vorbisfile = gst_element_factory_make ("mad", "vorbisfile");
|
||||
g_assert (vorbisfile);
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), filesrc);
|
||||
gst_bin_add (GST_BIN (pipeline), vorbisfile);
|
||||
|
||||
gst_element_link_pads (filesrc, "src", vorbisfile, "sink");
|
||||
|
||||
pad = gst_element_get_pad (vorbisfile, "src");
|
||||
g_assert (pad);
|
||||
|
||||
logical_stream_format = gst_format_get_by_nick ("logical_stream");
|
||||
g_assert (logical_stream_format != 0);
|
||||
|
||||
context = g_new0 (struct probe_context, 1);
|
||||
context->pipeline = pipeline;
|
||||
context->element = vorbisfile;
|
||||
context->pad = pad;
|
||||
context->ls_format = logical_stream_format;
|
||||
|
||||
g_signal_connect (G_OBJECT (pipeline), "deep_notify",
|
||||
G_CALLBACK (deep_notify), context);
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
||||
/* at this point we can inspect the stream */
|
||||
collect_stream_properties (context);
|
||||
|
||||
/* loop over all logical streams to get info */
|
||||
stream = 0;
|
||||
while (stream < context->total_ls) {
|
||||
collect_logical_stream_properties (context, stream);
|
||||
stream++;
|
||||
}
|
||||
|
||||
/* stop probe */
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -3,8 +3,11 @@ plugin_LTLIBRARIES = libgstgnomevfs.la
|
|||
libgstgnomevfs_la_SOURCES = \
|
||||
gstgnomevfs.c \
|
||||
gstgnomevfssrc.c \
|
||||
gstgnomevfssink.c \
|
||||
gstgnomevfsuri.c
|
||||
|
||||
EXTRA_DIST = \
|
||||
gstgnomevfssink.c
|
||||
|
||||
libgstgnomevfs_la_CFLAGS = $(GST_CFLAGS) $(GNOME_VFS_CFLAGS)
|
||||
libgstgnomevfs_la_LIBADD = $(GNOME_VFS_LIBS)
|
||||
libgstgnomevfs_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
|
|
|
@ -34,10 +34,9 @@ plugin_init (GstPlugin * plugin)
|
|||
{
|
||||
gnome_vfs_init ();
|
||||
|
||||
if (!gst_element_register (plugin, "gnomevfssrc",
|
||||
GST_RANK_SECONDARY, gst_gnomevfssrc_get_type ()) ||
|
||||
!gst_element_register (plugin, "gnomevfssink",
|
||||
GST_RANK_SECONDARY, gst_gnomevfssink_get_type ())) {
|
||||
if (!gst_element_register (plugin, "gnomevfssrc", GST_RANK_SECONDARY, gst_gnomevfssrc_get_type ()) /*||
|
||||
!gst_element_register (plugin, "gnomevfssink",
|
||||
GST_RANK_SECONDARY, gst_gnomevfssink_get_type ()) */ ) {
|
||||
return FALSE;
|
||||
}
|
||||
#ifdef ENABLE_NLS
|
||||
|
|
|
@ -54,7 +54,6 @@
|
|||
/* gnome-vfs.h doesn't include the following header, which we need: */
|
||||
#include <libgnomevfs/gnome-vfs-standard-callbacks.h>
|
||||
|
||||
|
||||
#define GST_TYPE_GNOMEVFSSRC \
|
||||
(gst_gnomevfssrc_get_type())
|
||||
#define GST_GNOMEVFSSRC(obj) \
|
||||
|
@ -78,37 +77,30 @@ typedef enum
|
|||
}
|
||||
GstGnomeVFSSrcFlags;
|
||||
|
||||
typedef struct _GstGnomeVFSSrc GstGnomeVFSSrc;
|
||||
typedef struct _GstGnomeVFSSrcClass GstGnomeVFSSrcClass;
|
||||
|
||||
struct _GstGnomeVFSSrc
|
||||
typedef struct _GstGnomeVFSSrc
|
||||
{
|
||||
GstElement element;
|
||||
|
||||
/* pads */
|
||||
GstPad *srcpad;
|
||||
|
||||
/* uri */
|
||||
/* uri, file, ... */
|
||||
GnomeVFSURI *uri;
|
||||
gchar *uri_name;
|
||||
|
||||
/* handle */
|
||||
GnomeVFSHandle *handle;
|
||||
gboolean own_handle;
|
||||
GnomeVFSFileSize size; /* -1 = unknown */
|
||||
GnomeVFSFileOffset curoffset; /* current offset in file */
|
||||
gboolean seekable;
|
||||
gulong bytes_per_read; /* bytes per read */
|
||||
|
||||
/* Seek stuff */
|
||||
gboolean need_flush;
|
||||
|
||||
/* details for fallback synchronous read */
|
||||
GnomeVFSFileSize size;
|
||||
GnomeVFSFileOffset curoffset; /* current offset in file */
|
||||
gulong bytes_per_read; /* bytes per read */
|
||||
gboolean new_seek;
|
||||
gboolean need_flush, need_discont;
|
||||
GnomeVFSFileOffset reqoffset; /* wanted offset for next buf */
|
||||
|
||||
/* icecast/audiocast metadata extraction handling */
|
||||
gboolean iradio_mode;
|
||||
gboolean http_callbacks_pushed;
|
||||
gboolean seekable;
|
||||
|
||||
gint icy_metaint;
|
||||
GnomeVFSFileSize icy_count;
|
||||
|
@ -126,19 +118,17 @@ struct _GstGnomeVFSSrc
|
|||
gint audiocast_thread_die_outfd;
|
||||
gint audiocast_port;
|
||||
gint audiocast_fd;
|
||||
};
|
||||
} GstGnomeVFSSrc;
|
||||
|
||||
struct _GstGnomeVFSSrcClass
|
||||
typedef struct _GstGnomeVFSSrcClass
|
||||
{
|
||||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
static GstElementDetails gst_gnomevfssrc_details =
|
||||
GST_ELEMENT_DETAILS ("GnomeVFS Source",
|
||||
"Source/File",
|
||||
"Read from any GnomeVFS file",
|
||||
"Bastien Nocera <hadess@hadess.net>");
|
||||
} GstGnomeVFSSrcClass;
|
||||
|
||||
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
static const GstFormat *
|
||||
gst_gnomevfssrc_get_formats (GstPad * pad)
|
||||
|
@ -177,12 +167,6 @@ gst_gnomevfssrc_get_event_mask (GstPad * pad)
|
|||
return masks;
|
||||
}
|
||||
|
||||
/* GnomeVFSSrc signals and args */
|
||||
enum
|
||||
{
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0,
|
||||
|
@ -193,15 +177,13 @@ enum
|
|||
ARG_IRADIO_NAME,
|
||||
ARG_IRADIO_GENRE,
|
||||
ARG_IRADIO_URL,
|
||||
ARG_IRADIO_TITLE,
|
||||
ARG_SEEKABLE
|
||||
ARG_IRADIO_TITLE
|
||||
};
|
||||
|
||||
static void gst_gnomevfssrc_base_init (gpointer g_class);
|
||||
static void gst_gnomevfssrc_class_init (GstGnomeVFSSrcClass * klass);
|
||||
static void gst_gnomevfssrc_init (GstGnomeVFSSrc * gnomevfssrc);
|
||||
static void gst_gnomevfssrc_finalize (GObject * object);
|
||||
|
||||
static void gst_gnomevfssrc_uri_handler_init (gpointer g_iface,
|
||||
gpointer iface_data);
|
||||
|
||||
|
@ -210,7 +192,9 @@ static void gst_gnomevfssrc_set_property (GObject * object, guint prop_id,
|
|||
static void gst_gnomevfssrc_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static GstData *gst_gnomevfssrc_get (GstPad * pad);
|
||||
static GstFlowReturn gst_gnomevfssrc_getrange (GstPad * pad,
|
||||
guint64 offset, guint size, GstBuffer ** buffer);
|
||||
static gboolean gst_gnomevfssrc_activate (GstPad * pad, GstActivateMode mode);
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_gnomevfssrc_change_state (GstElement * element);
|
||||
|
@ -265,27 +249,36 @@ static void
|
|||
gst_gnomevfssrc_base_init (gpointer g_class)
|
||||
{
|
||||
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
||||
static GstElementDetails gst_gnomevfssrc_details =
|
||||
GST_ELEMENT_DETAILS ("GnomeVFS Source",
|
||||
"Source/File",
|
||||
"Read from any GnomeVFS-supported file",
|
||||
"Bastien Nocera <hadess@hadess.net>\n"
|
||||
"Ronald S. Bultje <rbultje@ronald.bitfreak.net>");
|
||||
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&srctemplate));
|
||||
gst_element_class_set_details (element_class, &gst_gnomevfssrc_details);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_gnomevfssrc_class_init (GstGnomeVFSSrcClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
|
||||
|
||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
||||
|
||||
gobject_class->finalize = gst_gnomevfssrc_finalize;
|
||||
gobject_class->set_property = gst_gnomevfssrc_set_property;
|
||||
gobject_class->get_property = gst_gnomevfssrc_get_property;
|
||||
|
||||
gstelement_class->change_state = gst_gnomevfssrc_change_state;
|
||||
|
||||
/* properties */
|
||||
gst_element_class_install_std_props (GST_ELEMENT_CLASS (klass),
|
||||
"bytesperread", ARG_BYTESPERREAD, G_PARAM_READWRITE,
|
||||
"location", ARG_LOCATION, G_PARAM_READWRITE, NULL);
|
||||
|
||||
gobject_class->finalize = gst_gnomevfssrc_finalize;
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
ARG_HANDLE,
|
||||
g_param_spec_pointer ("handle",
|
||||
|
@ -316,22 +309,16 @@ gst_gnomevfssrc_class_init (GstGnomeVFSSrcClass * klass)
|
|||
g_param_spec_string ("iradio-title",
|
||||
"iradio-title",
|
||||
"Name of currently playing song", NULL, G_PARAM_READABLE));
|
||||
g_object_class_install_property (gobject_class,
|
||||
ARG_SEEKABLE,
|
||||
g_param_spec_boolean ("seekable",
|
||||
"seekable", "TRUE is stream is seekable", FALSE, G_PARAM_READABLE));
|
||||
|
||||
gstelement_class->set_property = gst_gnomevfssrc_set_property;
|
||||
gstelement_class->get_property = gst_gnomevfssrc_get_property;
|
||||
|
||||
gstelement_class->change_state = gst_gnomevfssrc_change_state;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_gnomevfssrc_init (GstGnomeVFSSrc * gnomevfssrc)
|
||||
{
|
||||
gnomevfssrc->srcpad = gst_pad_new ("src", GST_PAD_SRC);
|
||||
gst_pad_set_get_function (gnomevfssrc->srcpad, gst_gnomevfssrc_get);
|
||||
gnomevfssrc->srcpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
|
||||
"src");
|
||||
gst_pad_set_getrange_function (gnomevfssrc->srcpad, gst_gnomevfssrc_getrange);
|
||||
gst_pad_set_activate_function (gnomevfssrc->srcpad, gst_gnomevfssrc_activate);
|
||||
gst_pad_set_event_mask_function (gnomevfssrc->srcpad,
|
||||
gst_gnomevfssrc_get_event_mask);
|
||||
gst_pad_set_event_function (gnomevfssrc->srcpad,
|
||||
|
@ -347,14 +334,13 @@ gst_gnomevfssrc_init (GstGnomeVFSSrc * gnomevfssrc)
|
|||
gnomevfssrc->uri = NULL;
|
||||
gnomevfssrc->uri_name = NULL;
|
||||
gnomevfssrc->handle = NULL;
|
||||
gnomevfssrc->curoffset = 0;
|
||||
gnomevfssrc->curoffset = gnomevfssrc->reqoffset = 0;
|
||||
gnomevfssrc->bytes_per_read = 4096;
|
||||
gnomevfssrc->new_seek = FALSE;
|
||||
gnomevfssrc->need_discont = gnomevfssrc->need_flush = FALSE;
|
||||
gnomevfssrc->seekable = FALSE;
|
||||
gnomevfssrc->size = (GnomeVFSFileSize) - 1;
|
||||
|
||||
gnomevfssrc->icy_metaint = 0;
|
||||
|
||||
gnomevfssrc->seekable = FALSE;
|
||||
|
||||
gnomevfssrc->iradio_mode = FALSE;
|
||||
gnomevfssrc->http_callbacks_pushed = FALSE;
|
||||
gnomevfssrc->icy_count = 0;
|
||||
|
@ -410,6 +396,10 @@ gst_gnomevfssrc_finalize (GObject * object)
|
|||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
/*
|
||||
* URI interface support.
|
||||
*/
|
||||
|
||||
static guint
|
||||
gst_gnomevfssrc_uri_get_type (void)
|
||||
{
|
||||
|
@ -571,9 +561,6 @@ gst_gnomevfssrc_get_property (GObject * object, guint prop_id, GValue * value,
|
|||
g_value_set_string (value, src->iradio_title);
|
||||
g_mutex_unlock (src->audiocast_udpdata_mutex);
|
||||
break;
|
||||
case ARG_SEEKABLE:
|
||||
g_value_set_boolean (value, src->seekable);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -1018,123 +1005,129 @@ gst_gnomevfssrc_get_icy_metadata (GstGnomeVFSSrc * src)
|
|||
|
||||
/* end of icecast/audiocast metadata extraction support code */
|
||||
|
||||
/**
|
||||
* gst_gnomevfssrc_get:
|
||||
* @pad: #GstPad to push a buffer from
|
||||
*
|
||||
* Push a new buffer from the gnomevfssrc at the current offset.
|
||||
/*
|
||||
* Read a new buffer from src->reqoffset, takes care of events
|
||||
* and seeking and such.
|
||||
*/
|
||||
static GstData *
|
||||
gst_gnomevfssrc_get (GstPad * pad)
|
||||
static GstFlowReturn
|
||||
gst_gnomevfssrc_get (GstGnomeVFSSrc * src, GstBuffer ** buffer)
|
||||
{
|
||||
GstGnomeVFSSrc *src;
|
||||
GnomeVFSResult result = 0;
|
||||
GnomeVFSResult res;
|
||||
GstBuffer *buf;
|
||||
GnomeVFSFileSize readbytes;
|
||||
guint8 *data;
|
||||
|
||||
g_return_val_if_fail (pad != NULL, NULL);
|
||||
src = GST_GNOMEVFSSRC (gst_pad_get_parent (pad));
|
||||
g_return_val_if_fail (GST_FLAG_IS_SET (src, GST_GNOMEVFSSRC_OPEN), NULL);
|
||||
g_return_val_if_fail (GST_FLAG_IS_SET (src, GST_GNOMEVFSSRC_OPEN),
|
||||
GST_FLOW_ERROR);
|
||||
|
||||
/* deal with EOF state */
|
||||
if ((src->curoffset >= src->size) && (src->size != 0)) {
|
||||
gst_element_set_eos (GST_ELEMENT (src));
|
||||
GST_DEBUG ("Returning EOS");
|
||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
||||
/* if the requested offset is outside the file boundary, we´re EOF */
|
||||
if (src->size != (GnomeVFSFileSize) - 1 && src->reqoffset >= src->size) {
|
||||
GST_LOG_OBJECT (src, "Requested offset %lld is outside filesize %llu",
|
||||
src->reqoffset, src->size);
|
||||
gst_pad_push_event (src->srcpad, gst_event_new (GST_EVENT_EOS));
|
||||
return GST_FLOW_WRONG_STATE;
|
||||
}
|
||||
|
||||
/* seek if required */
|
||||
if (src->curoffset != src->reqoffset) {
|
||||
if (src->seekable) {
|
||||
if ((res = gnome_vfs_seek (src->handle,
|
||||
GNOME_VFS_SEEK_START, src->reqoffset)) != GNOME_VFS_OK) {
|
||||
GST_ERROR_OBJECT (src,
|
||||
"Failed to seek to requested position %lld: %s",
|
||||
src->reqoffset, gnome_vfs_result_to_string (res));
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
src->curoffset = src->reqoffset;
|
||||
} else {
|
||||
GST_ERROR_OBJECT (src,
|
||||
"Requested seek from %lld to %lld on non-seekable stream",
|
||||
src->curoffset, src->reqoffset);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* create the buffer */
|
||||
/* FIXME: should eventually use a bufferpool for this */
|
||||
buf = gst_buffer_new ();
|
||||
g_return_val_if_fail (buf, NULL);
|
||||
|
||||
audiocast_do_notifications (src);
|
||||
|
||||
if (src->iradio_mode && src->icy_metaint > 0) {
|
||||
GST_BUFFER_DATA (buf) = g_malloc0 (src->icy_metaint);
|
||||
data = GST_BUFFER_DATA (buf);
|
||||
g_return_val_if_fail (GST_BUFFER_DATA (buf) != NULL, NULL);
|
||||
data = g_malloc (src->icy_metaint);
|
||||
|
||||
GST_BUFFER_SIZE (buf) = 0;
|
||||
/* try to read */
|
||||
GST_DEBUG ("doing read: icy_count: %" G_GINT64_FORMAT, src->icy_count);
|
||||
result = gnome_vfs_read (src->handle, data,
|
||||
src->icy_metaint - src->icy_count, &readbytes);
|
||||
|
||||
/* EOS? */
|
||||
if (readbytes == 0) {
|
||||
if ((res = gnome_vfs_read (src->handle, data,
|
||||
src->icy_metaint - src->icy_count,
|
||||
&readbytes)) != GNOME_VFS_OK) {
|
||||
GST_ERROR_OBJECT (src, "Failed to read iradio data: %s",
|
||||
gnome_vfs_result_to_string (res));
|
||||
return GST_FLOW_ERROR;
|
||||
} else if (readbytes == 0) {
|
||||
gst_buffer_unref (buf);
|
||||
GST_DEBUG ("Returning EOS");
|
||||
gst_element_set_eos (GST_ELEMENT (src));
|
||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
||||
GST_LOG_OBJECT (src, "Reading iradio data gave EOS");
|
||||
gst_pad_push_event (src->srcpad, gst_event_new (GST_EVENT_EOS));
|
||||
return GST_FLOW_WRONG_STATE;
|
||||
}
|
||||
|
||||
src->icy_count += readbytes;
|
||||
GST_BUFFER_OFFSET (buf) = src->curoffset;
|
||||
GST_BUFFER_SIZE (buf) += readbytes;
|
||||
data += readbytes;
|
||||
GST_BUFFER_DATA (buf) = data;
|
||||
src->curoffset += readbytes;
|
||||
src->reqoffset += readbytes;
|
||||
|
||||
if (src->icy_count == src->icy_metaint) {
|
||||
gst_gnomevfssrc_get_icy_metadata (src);
|
||||
src->icy_count = 0;
|
||||
}
|
||||
} else {
|
||||
/* allocate the space for the buffer data */
|
||||
GST_BUFFER_DATA (buf) = g_malloc (src->bytes_per_read);
|
||||
g_return_val_if_fail (GST_BUFFER_DATA (buf) != NULL, NULL);
|
||||
data = g_malloc (src->bytes_per_read);
|
||||
|
||||
if (src->need_flush) {
|
||||
GstEvent *event = gst_event_new_flush ();
|
||||
|
||||
src->need_flush = FALSE;
|
||||
gst_buffer_unref (buf);
|
||||
GST_DEBUG ("gnomevfssrc sending flush");
|
||||
return GST_DATA (event);
|
||||
GST_LOG_OBJECT (src, "sending flush");
|
||||
gst_pad_push_event (src->srcpad, gst_event_new (GST_EVENT_FLUSH));
|
||||
}
|
||||
|
||||
if (src->new_seek) {
|
||||
GstEvent *event;
|
||||
|
||||
gst_buffer_unref (buf);
|
||||
GST_DEBUG ("new seek %" G_GINT64_FORMAT, src->curoffset);
|
||||
src->new_seek = FALSE;
|
||||
GST_DEBUG ("gnomevfssrc sending discont");
|
||||
event =
|
||||
gst_event_new_discontinuous (FALSE, GST_FORMAT_BYTES, src->curoffset,
|
||||
NULL);
|
||||
return GST_DATA (event);
|
||||
if (src->need_discont) {
|
||||
src->need_discont = FALSE;
|
||||
GST_LOG_OBJECT (src, "sending discont");
|
||||
gst_pad_push_event (src->srcpad, gst_event_new_discontinuous (FALSE,
|
||||
GST_FORMAT_BYTES, src->reqoffset, GST_FORMAT_UNDEFINED));
|
||||
}
|
||||
|
||||
result = gnome_vfs_read (src->handle, GST_BUFFER_DATA (buf),
|
||||
src->bytes_per_read, &readbytes);
|
||||
|
||||
GST_DEBUG ("read: %s, readbytes: %" G_GINT64_FORMAT " @ %" G_GINT64_FORMAT,
|
||||
gnome_vfs_result_to_string (result), readbytes, src->curoffset);
|
||||
/* deal with EOS */
|
||||
if (readbytes == 0) {
|
||||
if ((res = gnome_vfs_read (src->handle, data,
|
||||
src->bytes_per_read, &readbytes)) != GNOME_VFS_OK) {
|
||||
GST_ERROR_OBJECT (src, "Failed to read data: %s",
|
||||
gnome_vfs_result_to_string (res));
|
||||
return GST_FLOW_ERROR;
|
||||
} else if (readbytes == 0) {
|
||||
gst_buffer_unref (buf);
|
||||
GST_DEBUG ("Returning EOS");
|
||||
gst_element_set_eos (GST_ELEMENT (src));
|
||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
||||
GST_LOG_OBJECT (src, "Reading data gave EOS");
|
||||
gst_pad_push_event (src->srcpad, gst_event_new (GST_EVENT_EOS));
|
||||
return GST_FLOW_WRONG_STATE;
|
||||
}
|
||||
|
||||
GST_BUFFER_OFFSET (buf) = src->curoffset;
|
||||
GST_BUFFER_SIZE (buf) = readbytes;
|
||||
GST_BUFFER_DATA (buf) = data;
|
||||
src->curoffset += readbytes;
|
||||
src->reqoffset += readbytes;
|
||||
}
|
||||
|
||||
GST_BUFFER_TIMESTAMP (buf) = -1;
|
||||
|
||||
/* we're done, return the buffer */
|
||||
return GST_DATA (buf);
|
||||
*buffer = buf;
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
/* open the file, do stuff necessary to go to READY state */
|
||||
static gboolean
|
||||
gst_gnomevfssrc_open_file (GstGnomeVFSSrc * src)
|
||||
{
|
||||
GnomeVFSResult result;
|
||||
GnomeVFSResult res;
|
||||
GnomeVFSFileInfo *info;
|
||||
|
||||
g_return_val_if_fail (!GST_FLAG_IS_SET (src, GST_GNOMEVFSSRC_OPEN), FALSE);
|
||||
|
@ -1145,42 +1138,43 @@ gst_gnomevfssrc_open_file (GstGnomeVFSSrc * src)
|
|||
gst_gnomevfssrc_push_callbacks (src);
|
||||
|
||||
if (src->uri != NULL) {
|
||||
result = gnome_vfs_open_uri (&(src->handle), src->uri, GNOME_VFS_OPEN_READ);
|
||||
if (result != GNOME_VFS_OK) {
|
||||
if ((res = gnome_vfs_open_uri (&src->handle, src->uri,
|
||||
GNOME_VFS_OPEN_READ)) != GNOME_VFS_OK) {
|
||||
gchar *filename = gnome_vfs_uri_to_string (src->uri,
|
||||
GNOME_VFS_URI_HIDE_PASSWORD);
|
||||
|
||||
gst_gnomevfssrc_pop_callbacks (src);
|
||||
audiocast_thread_kill (src);
|
||||
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
|
||||
(_("Could not open vfs file \"%s\" for reading."), filename),
|
||||
(gnome_vfs_result_to_string (result)));
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
|
||||
("Could not open vfs file \"%s\" for reading: %s",
|
||||
filename, gnome_vfs_result_to_string (res)));
|
||||
g_free (filename);
|
||||
return FALSE;
|
||||
}
|
||||
src->own_handle = TRUE;
|
||||
} else if (!src->handle) {
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
|
||||
(_("No filename given.")), (NULL));
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("No filename given"));
|
||||
return FALSE;
|
||||
} else {
|
||||
src->own_handle = FALSE;
|
||||
}
|
||||
|
||||
src->size = (GnomeVFSFileSize) - 1;
|
||||
info = gnome_vfs_file_info_new ();
|
||||
if ((result = gnome_vfs_get_file_info_from_handle (src->handle,
|
||||
info, GNOME_VFS_FILE_INFO_DEFAULT))
|
||||
== GNOME_VFS_OK) {
|
||||
if (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE)
|
||||
if ((res = gnome_vfs_get_file_info_from_handle (src->handle,
|
||||
info, GNOME_VFS_FILE_INFO_DEFAULT)) == GNOME_VFS_OK) {
|
||||
if (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
|
||||
src->size = info->size;
|
||||
} else
|
||||
GST_DEBUG ("getting info failed: %s", gnome_vfs_result_to_string (result));
|
||||
|
||||
GST_DEBUG_OBJECT (src, "size: %llu bytes", src->size);
|
||||
} else
|
||||
GST_LOG_OBJECT (src, "filesize not known");
|
||||
} else {
|
||||
GST_WARNING_OBJECT (src, "getting info failed: %s",
|
||||
gnome_vfs_result_to_string (res));
|
||||
}
|
||||
gnome_vfs_file_info_unref (info);
|
||||
|
||||
GST_DEBUG ("size %" G_GINT64_FORMAT, src->size);
|
||||
|
||||
audiocast_do_notifications (src);
|
||||
|
||||
if (gnome_vfs_seek (src->handle, GNOME_VFS_SEEK_CURRENT, 0)
|
||||
|
@ -1207,13 +1201,117 @@ gst_gnomevfssrc_close_file (GstGnomeVFSSrc * src)
|
|||
gnome_vfs_close (src->handle);
|
||||
src->handle = NULL;
|
||||
}
|
||||
src->size = 0;
|
||||
src->curoffset = 0;
|
||||
src->new_seek = FALSE;
|
||||
src->size = (GnomeVFSFileSize) - 1;
|
||||
src->curoffset = src->reqoffset = 0;
|
||||
src->need_flush = src->need_discont = FALSE;
|
||||
|
||||
GST_FLAG_UNSET (src, GST_GNOMEVFSSRC_OPEN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to get random access data.
|
||||
*/
|
||||
|
||||
static GstFlowReturn
|
||||
gst_gnomevfssrc_getrange (GstPad * pad,
|
||||
guint64 offset, guint size, GstBuffer ** buffer)
|
||||
{
|
||||
GstGnomeVFSSrc *src = GST_GNOMEVFSSRC (gst_pad_get_parent (pad));
|
||||
|
||||
/* get ready */
|
||||
src->reqoffset = offset;
|
||||
src->bytes_per_read = size;
|
||||
|
||||
/* get data */
|
||||
return gst_gnomevfssrc_get (src, buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Used if we´re loopbased.
|
||||
*/
|
||||
|
||||
static void
|
||||
gst_gnomevfssrc_loop (GstPad * pad)
|
||||
{
|
||||
GstGnomeVFSSrc *src = GST_GNOMEVFSSRC (gst_pad_get_parent (pad));
|
||||
GstFlowReturn res;
|
||||
GstBuffer *buffer;
|
||||
|
||||
if ((res = gst_gnomevfssrc_get (src, &buffer)) != GST_FLOW_OK ||
|
||||
(res = gst_pad_push (pad, buffer)) != GST_FLOW_OK) {
|
||||
gst_task_pause (GST_RPAD_TASK (pad));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to notify us of scheduling mode.
|
||||
*/
|
||||
|
||||
static gboolean
|
||||
gst_gnomevfssrc_activate (GstPad * pad, GstActivateMode mode)
|
||||
{
|
||||
gboolean res = FALSE;
|
||||
GstGnomeVFSSrc *src = GST_GNOMEVFSSRC (gst_pad_get_parent (pad));
|
||||
|
||||
switch (mode) {
|
||||
/* we're the loop function */
|
||||
case GST_ACTIVATE_PUSH:
|
||||
/* if we have a scheduler we can start the task */
|
||||
if (GST_ELEMENT_SCHEDULER (src)) {
|
||||
GST_STREAM_LOCK (pad);
|
||||
if (!GST_FLAG_IS_SET (src, GST_GNOMEVFSSRC_OPEN)) {
|
||||
if (!gst_gnomevfssrc_open_file (src)) {
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
goto fail_open;
|
||||
}
|
||||
}
|
||||
GST_RPAD_TASK (pad) =
|
||||
gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (src),
|
||||
(GstTaskFunction) gst_gnomevfssrc_loop, pad);
|
||||
|
||||
gst_task_start (GST_RPAD_TASK (pad));
|
||||
res = TRUE;
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
}
|
||||
break;
|
||||
|
||||
/* random access mode */
|
||||
case GST_ACTIVATE_PULL:
|
||||
if (!GST_FLAG_IS_SET (src, GST_GNOMEVFSSRC_OPEN)) {
|
||||
if (!gst_gnomevfssrc_open_file (src)) {
|
||||
goto fail_open;
|
||||
}
|
||||
}
|
||||
res = TRUE;
|
||||
break;
|
||||
|
||||
case GST_ACTIVATE_NONE:
|
||||
/* step 1, unblock clock sync (if any) */
|
||||
|
||||
/* step 2, make sure streaming finishes */
|
||||
GST_STREAM_LOCK (pad);
|
||||
/* step 3, stop the task */
|
||||
if (GST_RPAD_TASK (pad)) {
|
||||
gst_task_stop (GST_RPAD_TASK (pad));
|
||||
}
|
||||
if (GST_FLAG_IS_SET (src, GST_GNOMEVFSSRC_OPEN))
|
||||
gst_gnomevfssrc_close_file (src);
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
|
||||
res = TRUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
fail_open:
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_gnomevfssrc_change_state (GstElement * element)
|
||||
{
|
||||
|
@ -1221,17 +1319,8 @@ gst_gnomevfssrc_change_state (GstElement * element)
|
|||
|
||||
switch (GST_STATE_TRANSITION (element)) {
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
if (!GST_FLAG_IS_SET (element, GST_GNOMEVFSSRC_OPEN)) {
|
||||
if (!gst_gnomevfssrc_open_file (GST_GNOMEVFSSRC (element)))
|
||||
return GST_STATE_FAILURE;
|
||||
}
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
if (GST_FLAG_IS_SET (element, GST_GNOMEVFSSRC_OPEN))
|
||||
gst_gnomevfssrc_close_file (GST_GNOMEVFSSRC (element));
|
||||
break;
|
||||
case GST_STATE_NULL_TO_READY:
|
||||
case GST_STATE_READY_TO_NULL:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1247,100 +1336,102 @@ gst_gnomevfssrc_srcpad_query (GstPad * pad, GstQueryType type,
|
|||
GstFormat * format, gint64 * value)
|
||||
{
|
||||
GstGnomeVFSSrc *src = GST_GNOMEVFSSRC (gst_pad_get_parent (pad));
|
||||
gboolean res = FALSE;
|
||||
|
||||
switch (type) {
|
||||
case GST_QUERY_TOTAL:
|
||||
if (*format != GST_FORMAT_BYTES || src->size == 0) {
|
||||
return FALSE;
|
||||
if (*format == GST_FORMAT_BYTES || src->size != (GnomeVFSFileSize) - 1) {
|
||||
res = TRUE;
|
||||
*value = src->size;
|
||||
}
|
||||
*value = src->size;
|
||||
break;
|
||||
case GST_QUERY_POSITION:
|
||||
switch (*format) {
|
||||
case GST_FORMAT_BYTES:
|
||||
*value = src->curoffset;
|
||||
res = TRUE;
|
||||
break;
|
||||
case GST_FORMAT_PERCENT:
|
||||
if (src->size == 0)
|
||||
return FALSE;
|
||||
*value = src->curoffset * GST_FORMAT_PERCENT_MAX / src->size;
|
||||
if (src->size != (GnomeVFSFileSize) - 1) {
|
||||
res = TRUE;
|
||||
*value = src->curoffset * GST_FORMAT_PERCENT_MAX / src->size;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_gnomevfssrc_srcpad_event (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
GstGnomeVFSSrc *src = GST_GNOMEVFSSRC (GST_PAD_PARENT (pad));
|
||||
gboolean res = FALSE;
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_SEEK:
|
||||
{
|
||||
gint64 desired_offset;
|
||||
GnomeVFSResult result;
|
||||
GnomeVFSResult res;
|
||||
|
||||
if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES) {
|
||||
gst_event_unref (event);
|
||||
return FALSE;
|
||||
break;
|
||||
} else if (!src->seekable) {
|
||||
GST_WARNING_OBJECT (src, "Seek on non-seekable stream");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (GST_EVENT_SEEK_METHOD (event)) {
|
||||
case GST_SEEK_METHOD_SET:
|
||||
desired_offset = (guint64) GST_EVENT_SEEK_OFFSET (event);
|
||||
desired_offset = GST_EVENT_SEEK_OFFSET (event);
|
||||
break;
|
||||
case GST_SEEK_METHOD_CUR:
|
||||
desired_offset = src->curoffset + GST_EVENT_SEEK_OFFSET (event);
|
||||
break;
|
||||
case GST_SEEK_METHOD_END:
|
||||
if (src->size == 0)
|
||||
return FALSE;
|
||||
if (src->size == (GnomeVFSFileSize) - 1) {
|
||||
goto done;
|
||||
}
|
||||
desired_offset = src->size - ABS (GST_EVENT_SEEK_OFFSET (event));
|
||||
break;
|
||||
default:
|
||||
gst_event_unref (event);
|
||||
return FALSE;
|
||||
break;
|
||||
goto done;
|
||||
}
|
||||
|
||||
result = gnome_vfs_seek (src->handle,
|
||||
GNOME_VFS_SEEK_START, desired_offset);
|
||||
GST_DEBUG ("new_seek to %" G_GINT64_FORMAT ": %s",
|
||||
desired_offset, gnome_vfs_result_to_string (result));
|
||||
|
||||
if (result != GNOME_VFS_OK) {
|
||||
gst_event_unref (event);
|
||||
return FALSE;
|
||||
/* check boundaries */
|
||||
if (desired_offset < 0 || desired_offset >= src->size) {
|
||||
GST_WARNING_OBJECT (src, "Seek to %lld is outside filebounds 0-%llu",
|
||||
desired_offset, src->size);
|
||||
break;
|
||||
}
|
||||
src->curoffset = desired_offset;
|
||||
src->new_seek = TRUE;
|
||||
|
||||
/* prepare for seek */
|
||||
src->reqoffset = desired_offset;
|
||||
GST_DEBUG_OBJECT (src, "new_seek to %lld: %s", desired_offset);
|
||||
src->need_discont = TRUE;
|
||||
src->need_flush = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH;
|
||||
res = TRUE;
|
||||
break;
|
||||
}
|
||||
case GST_EVENT_SIZE:
|
||||
if (GST_EVENT_SIZE_FORMAT (event) != GST_FORMAT_BYTES) {
|
||||
gst_event_unref (event);
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
src->bytes_per_read = GST_EVENT_SIZE_VALUE (event);
|
||||
g_object_notify (G_OBJECT (src), "bytesperread");
|
||||
break;
|
||||
|
||||
case GST_EVENT_FLUSH:
|
||||
src->need_flush = TRUE;
|
||||
break;
|
||||
default:
|
||||
gst_event_unref (event);
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
gst_event_unref (event);
|
||||
|
||||
return TRUE;
|
||||
return res;
|
||||
}
|
||||
|
|
105
ext/ogg/README
105
ext/ogg/README
|
@ -1,9 +1,110 @@
|
|||
ogg demuxer
|
||||
-----------
|
||||
|
||||
This ogg demuxer has two modes of operation, which both share a significant
|
||||
amount of code. The first mode is the streaming mode which is automatically
|
||||
selected when the demuxer is connected to a non-getrange based element. When
|
||||
connected to a getrange based element the ogg demuxer can do full seeking
|
||||
with great efficiency.
|
||||
|
||||
1) the streaming mode.
|
||||
|
||||
In this mode, the ogg demuxer receives buffers in the _chain() function which
|
||||
are then simply submited to the ogg sync layer. Pages are then processed when the
|
||||
sync layer detects them, pads are created for new chains and packets are sent to
|
||||
the peer elements of the pads.
|
||||
|
||||
In this mode, no seeking is possible. This is the typical case when the stream is
|
||||
read from a network source.
|
||||
|
||||
In this mode, no setup is done at startup, the pages are just read and decoded.
|
||||
A new logical chain is detected when one of the pages has the BOS flag set. At this
|
||||
point the existing pads are removed and new pads are created for all the logical
|
||||
streams in this new chain.
|
||||
|
||||
|
||||
2) the random access mode.
|
||||
|
||||
In this mode, the ogg file is first scanned to detect the position and length of
|
||||
all chains. This scanning is performed using a recursive binary search algorithm
|
||||
that is explained below.
|
||||
|
||||
find_chains(start, end)
|
||||
{
|
||||
ret1 = read_next_pages (start);
|
||||
ret2 = read_prev_page (end);
|
||||
|
||||
if (WAS_HEADER (ret1)) {
|
||||
}
|
||||
else {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
a) read first and last pages
|
||||
|
||||
start end
|
||||
V V
|
||||
+-----------------------+-------------+--------------------+
|
||||
| 111 | 222 | 333 |
|
||||
BOS BOS BOS EOS
|
||||
|
||||
|
||||
after reading start, serial 111, BOS, chain[0] = 111
|
||||
after reading end, serial 333, EOS
|
||||
|
||||
start serialno != end serialno, binary search start, (end-start)/2
|
||||
|
||||
start bisect end
|
||||
V V V
|
||||
+-----------------------+-------------+--------------------+
|
||||
| 111 | 222 | 333 |
|
||||
|
||||
|
||||
after reading start, serial 111, BOS, chain[0] = 111
|
||||
after reading end, serial 222, EOS
|
||||
|
||||
while (
|
||||
|
||||
|
||||
|
||||
testcases
|
||||
---------
|
||||
|
||||
a) stream without BOS
|
||||
|
||||
+----------------------------------------------------------+
|
||||
111 |
|
||||
EOS
|
||||
|
||||
b) chained stream, first chain without BOS
|
||||
|
||||
+-------------------+--------------------------------------+
|
||||
111 | 222 |
|
||||
BOS EOS
|
||||
|
||||
|
||||
c) chained stream
|
||||
|
||||
+-------------------+--------------------------------------+
|
||||
| 111 | 222 |
|
||||
BOS BOS EOS
|
||||
|
||||
|
||||
d) chained stream, second without BOS
|
||||
|
||||
+-------------------+--------------------------------------+
|
||||
| 111 | 222 |
|
||||
BOS EOS
|
||||
|
||||
|
||||
|
||||
ogg and the granulepos
|
||||
----------------------
|
||||
|
||||
an ogg streams contains pages with a serial number and a granule pos. The granulepos
|
||||
is a number that is codec specific and denotes the 'position' of the last packet
|
||||
in that page.
|
||||
is a number that is codec specific and denotes the 'position' of the last sample in
|
||||
the last packet in that page.
|
||||
|
||||
ogg has therefore no notion about time, it only knows about bytes and granule positions.
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -219,6 +219,9 @@ gst_ogg_mux_class_init (GstOggMuxClass * klass)
|
|||
|
||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
||||
|
||||
gobject_class->get_property = gst_ogg_mux_get_property;
|
||||
gobject_class->set_property = gst_ogg_mux_set_property;
|
||||
|
||||
gstelement_class->request_new_pad = gst_ogg_mux_request_new_pad;
|
||||
|
||||
g_object_class_install_property (gobject_class, ARG_MAX_DELAY,
|
||||
|
@ -232,8 +235,6 @@ gst_ogg_mux_class_init (GstOggMuxClass * klass)
|
|||
|
||||
gstelement_class->change_state = gst_ogg_mux_change_state;
|
||||
|
||||
gstelement_class->get_property = gst_ogg_mux_get_property;
|
||||
gstelement_class->set_property = gst_ogg_mux_set_property;
|
||||
}
|
||||
|
||||
static const GstEventMask *
|
||||
|
@ -259,7 +260,6 @@ gst_ogg_mux_init (GstOggMux * ogg_mux)
|
|||
gst_pad_set_event_function (ogg_mux->srcpad, gst_ogg_mux_handle_src_event);
|
||||
gst_element_add_pad (GST_ELEMENT (ogg_mux), ogg_mux->srcpad);
|
||||
|
||||
GST_FLAG_SET (GST_ELEMENT (ogg_mux), GST_ELEMENT_EVENT_AWARE);
|
||||
GST_FLAG_SET (GST_ELEMENT (ogg_mux), GST_OGG_FLAG_BOS);
|
||||
|
||||
/* seed random number generator for creation of serial numbers */
|
||||
|
@ -273,24 +273,20 @@ gst_ogg_mux_init (GstOggMux * ogg_mux)
|
|||
|
||||
ogg_mux->delta_pad = NULL;
|
||||
|
||||
gst_element_set_loop_function (GST_ELEMENT (ogg_mux), gst_ogg_mux_loop);
|
||||
//gst_element_set_loop_function (GST_ELEMENT (ogg_mux), gst_ogg_mux_loop);
|
||||
gst_ogg_mux_loop (GST_ELEMENT (ogg_mux));
|
||||
}
|
||||
|
||||
static GstPadLinkReturn
|
||||
gst_ogg_mux_sinkconnect (GstPad * pad, const GstCaps * vscaps)
|
||||
gst_ogg_mux_sinkconnect (GstPad * pad, GstPad * peer)
|
||||
{
|
||||
GstOggMux *ogg_mux;
|
||||
GstStructure *structure;
|
||||
const gchar *mimetype;
|
||||
|
||||
ogg_mux = GST_OGG_MUX (gst_pad_get_parent (pad));
|
||||
|
||||
GST_DEBUG_OBJECT (ogg_mux, "sinkconnect triggered on %s",
|
||||
gst_pad_get_name (pad));
|
||||
|
||||
structure = gst_caps_get_structure (vscaps, 0);
|
||||
mimetype = gst_structure_get_name (structure);
|
||||
|
||||
return GST_PAD_LINK_OK;
|
||||
}
|
||||
|
||||
|
@ -412,9 +408,10 @@ static GstBuffer *
|
|||
gst_ogg_mux_next_buffer (GstOggPad * pad, gboolean * interrupt)
|
||||
{
|
||||
GstData *data = NULL;
|
||||
GstBuffer *buffer = NULL;
|
||||
|
||||
while (data == NULL) {
|
||||
data = gst_pad_pull (pad->pad);
|
||||
while (buffer == NULL) {
|
||||
//gst_pad_pull (pad->pad, &buffer);
|
||||
GST_DEBUG ("muxer: pulled %s:%s %p", GST_DEBUG_PAD_NAME (pad->pad), data);
|
||||
/* if it's an event, handle it */
|
||||
if (GST_IS_EVENT (data)) {
|
||||
|
@ -430,23 +427,18 @@ gst_ogg_mux_next_buffer (GstOggPad * pad, gboolean * interrupt)
|
|||
pad->eos = TRUE;
|
||||
gst_event_unref (event);
|
||||
return NULL;
|
||||
case GST_EVENT_INTERRUPT:
|
||||
*interrupt = TRUE;
|
||||
return NULL;
|
||||
case GST_EVENT_DISCONTINUOUS:
|
||||
{
|
||||
guint64 value;
|
||||
guint64 start_value, end_value;
|
||||
|
||||
if (GST_EVENT_DISCONT_NEW_MEDIA (event)) {
|
||||
gst_pad_event_default (pad->pad, event);
|
||||
break;
|
||||
}
|
||||
if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &value)) {
|
||||
if (gst_event_discont_get_value (event, GST_FORMAT_TIME,
|
||||
&start_value, &end_value)) {
|
||||
GST_DEBUG_OBJECT (ogg_mux,
|
||||
"got discont of %" G_GUINT64_FORMAT " on pad %s:%s",
|
||||
value, GST_DEBUG_PAD_NAME (pad->pad));
|
||||
"got discont of %" G_GUINT64_FORMAT " and %" G_GUINT64_FORMAT
|
||||
" on pad %s:%s", start_value, end_value,
|
||||
GST_DEBUG_PAD_NAME (pad->pad));
|
||||
}
|
||||
pad->offset = value;
|
||||
pad->offset = start_value;
|
||||
gst_event_unref (event);
|
||||
|
||||
}
|
||||
|
@ -489,7 +481,7 @@ gst_ogg_mux_buffer_from_page (GstOggMux * mux, ogg_page * page, gboolean delta)
|
|||
|
||||
/* allocate space for header and body */
|
||||
buffer = gst_pad_alloc_buffer (mux->srcpad, GST_BUFFER_OFFSET_NONE,
|
||||
page->header_len + page->body_len);
|
||||
page->header_len + page->body_len, NULL);
|
||||
memcpy (GST_BUFFER_DATA (buffer), page->header, page->header_len);
|
||||
memcpy (GST_BUFFER_DATA (buffer) + page->header_len,
|
||||
page->body, page->body_len);
|
||||
|
@ -511,7 +503,7 @@ gst_ogg_mux_push_page (GstOggMux * mux, ogg_page * page, gboolean delta)
|
|||
if (GST_PAD_IS_USABLE (mux->srcpad)) {
|
||||
GstBuffer *buffer = gst_ogg_mux_buffer_from_page (mux, page, delta);
|
||||
|
||||
gst_pad_push (mux->srcpad, GST_DATA (buffer));
|
||||
gst_pad_push (mux->srcpad, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -817,7 +809,7 @@ gst_ogg_mux_send_headers (GstOggMux * mux)
|
|||
caps = gst_pad_get_caps (mux->srcpad);
|
||||
if (caps) {
|
||||
gst_ogg_mux_set_header_on_caps (caps, hbufs);
|
||||
gst_pad_try_set_caps (mux->srcpad, caps);
|
||||
//gst_pad_try_set_caps (mux->srcpad, caps);
|
||||
}
|
||||
/* and send the buffers */
|
||||
hwalk = hbufs;
|
||||
|
@ -827,7 +819,7 @@ gst_ogg_mux_send_headers (GstOggMux * mux)
|
|||
hwalk = hwalk->next;
|
||||
|
||||
if (GST_PAD_IS_USABLE (mux->srcpad)) {
|
||||
gst_pad_push (mux->srcpad, GST_DATA (buf));
|
||||
gst_pad_push (mux->srcpad, buf);
|
||||
} else {
|
||||
gst_buffer_unref (buf);
|
||||
}
|
||||
|
@ -897,9 +889,8 @@ gst_ogg_mux_loop (GstElement * element)
|
|||
} else {
|
||||
/* no pad to pull on, send EOS */
|
||||
if (GST_PAD_IS_USABLE (ogg_mux->srcpad))
|
||||
gst_pad_push (ogg_mux->srcpad,
|
||||
GST_DATA (gst_event_new (GST_EVENT_EOS)));
|
||||
gst_element_set_eos (element);
|
||||
gst_pad_push_event (ogg_mux->srcpad, gst_event_new (GST_EVENT_EOS));
|
||||
//gst_element_set_eos (element);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1013,11 +1004,6 @@ gst_ogg_mux_loop (GstElement * element)
|
|||
pad->prev_delta = delta_unit;
|
||||
|
||||
/* swap the packet in */
|
||||
if (packet.e_o_s == 1)
|
||||
GST_DEBUG_OBJECT (pad, "swapping in EOS packet");
|
||||
if (packet.b_o_s == 1)
|
||||
GST_DEBUG_OBJECT (pad, "swapping in BOS packet");
|
||||
|
||||
ogg_stream_packetin (&pad->stream, &packet);
|
||||
|
||||
/* don't need the old buffer anymore */
|
||||
|
|
|
@ -147,7 +147,7 @@ static gboolean gst_ogm_parse_sink_convert (GstPad * pad, GstFormat src_format,
|
|||
static gboolean gst_ogm_parse_sink_query (GstPad * pad, GstQueryType type,
|
||||
GstFormat * fmt, gint64 * val);
|
||||
|
||||
static void gst_ogm_parse_chain (GstPad * pad, GstData * data);
|
||||
static GstFlowReturn gst_ogm_parse_chain (GstPad * pad, GstBuffer * buffer);
|
||||
|
||||
static GstElementStateReturn gst_ogm_parse_change_state (GstElement * element);
|
||||
|
||||
|
@ -499,11 +499,11 @@ gst_ogm_parse_sink_query (GstPad * pad,
|
|||
GST_FORMAT_DEFAULT, ogm->next_granulepos, fmt, val);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_ogm_parse_chain (GstPad * pad, GstData * dat)
|
||||
static GstFlowReturn
|
||||
gst_ogm_parse_chain (GstPad * pad, GstBuffer * buffer)
|
||||
{
|
||||
GstOgmParse *ogm = GST_OGM_PARSE (gst_pad_get_parent (pad));
|
||||
GstBuffer *buf = GST_BUFFER (dat);
|
||||
GstBuffer *buf = GST_BUFFER (buffer);
|
||||
guint8 *data = GST_BUFFER_DATA (buf);
|
||||
guint size = GST_BUFFER_SIZE (buf);
|
||||
|
||||
|
@ -567,7 +567,7 @@ gst_ogm_parse_chain (GstPad * pad, GstData * dat)
|
|||
|
||||
fcc = GST_MAKE_FOURCC (ogm->hdr.subtype[0],
|
||||
ogm->hdr.subtype[1], ogm->hdr.subtype[2], ogm->hdr.subtype[3]);
|
||||
GST_LOG_OBJECT (ogm, "Type: %s, subtype: " GST_FOURCC_FORMAT
|
||||
GST_LOG_OBJECT (ogm, "Type: %s, subtype: %" GST_FOURCC_FORMAT
|
||||
", size: %dx%d, timeunit: %" G_GINT64_FORMAT
|
||||
" (fps: %lf), s/u: %" G_GINT64_FORMAT ", "
|
||||
"def.len: %d, bufsize: %d, bps: %d",
|
||||
|
@ -595,13 +595,13 @@ gst_ogm_parse_chain (GstPad * pad, GstData * dat)
|
|||
}
|
||||
|
||||
ogm->srcpad = gst_pad_new_from_template (ogm->srcpadtempl, "src");
|
||||
gst_pad_use_explicit_caps (ogm->srcpad);
|
||||
if (!gst_pad_set_explicit_caps (ogm->srcpad, caps)) {
|
||||
GST_ELEMENT_ERROR (ogm, CORE, NEGOTIATION, (NULL), (NULL));
|
||||
//gst_object_unref (GST_OBJECT (ogm->srcpad));
|
||||
ogm->srcpad = NULL;
|
||||
break;
|
||||
}
|
||||
//gst_pad_use_explicit_caps (ogm->srcpad);
|
||||
//if (!gst_pad_set_explicit_caps (ogm->srcpad, caps)) {
|
||||
// GST_ELEMENT_ERROR (ogm, CORE, NEGOTIATION, (NULL), (NULL));
|
||||
//gst_object_unref (GST_OBJECT (ogm->srcpad));
|
||||
// ogm->srcpad = NULL;
|
||||
// break;
|
||||
//}
|
||||
gst_element_add_pad (GST_ELEMENT (ogm), ogm->srcpad);
|
||||
break;
|
||||
}
|
||||
|
@ -637,8 +637,9 @@ gst_ogm_parse_chain (GstPad * pad, GstData * dat)
|
|||
case 'v':{
|
||||
gint samples = (ogm->hdr.streamtype[0] == 'v') ? 1 : xsize;
|
||||
|
||||
if (keyframe)
|
||||
GST_BUFFER_FLAG_SET (sbuf, GST_BUFFER_KEY_UNIT);
|
||||
if (!keyframe)
|
||||
GST_BUFFER_FLAG_SET (sbuf, GST_BUFFER_DELTA_UNIT);
|
||||
|
||||
GST_BUFFER_TIMESTAMP (sbuf) = (GST_SECOND / 10000000) *
|
||||
ogm->next_granulepos * ogm->hdr.time_unit;
|
||||
GST_BUFFER_DURATION (sbuf) = (GST_SECOND / 10000000) *
|
||||
|
@ -659,8 +660,7 @@ gst_ogm_parse_chain (GstPad * pad, GstData * dat)
|
|||
GST_ELEMENT_ERROR (ogm, RESOURCE, SYNC, (NULL), (NULL));
|
||||
break;
|
||||
}
|
||||
if (sbuf)
|
||||
gst_pad_push (ogm->srcpad, GST_DATA (sbuf));
|
||||
gst_pad_push (ogm->srcpad, sbuf);
|
||||
} else {
|
||||
GST_ELEMENT_ERROR (ogm, STREAM, WRONG_TYPE,
|
||||
("Wrong packet startcode 0x%02x", data[0]), (NULL));
|
||||
|
@ -669,6 +669,8 @@ gst_ogm_parse_chain (GstPad * pad, GstData * dat)
|
|||
}
|
||||
|
||||
gst_buffer_unref (buf);
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
|
|
|
@ -63,6 +63,8 @@ struct _GstTheoraDec
|
|||
gint offset_x, offset_y;
|
||||
|
||||
gboolean crop;
|
||||
|
||||
GList *queued;
|
||||
};
|
||||
|
||||
struct _GstTheoraDecClass
|
||||
|
@ -109,7 +111,8 @@ static void theora_dec_get_property (GObject * object, guint prop_id,
|
|||
static void theora_dec_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
|
||||
static void theora_dec_chain (GstPad * pad, GstData * data);
|
||||
static gboolean theora_dec_sink_event (GstPad * pad, GstEvent * event);
|
||||
static GstFlowReturn theora_dec_chain (GstPad * pad, GstBuffer * buffer);
|
||||
static GstElementStateReturn theora_dec_change_state (GstElement * element);
|
||||
static gboolean theora_dec_src_event (GstPad * pad, GstEvent * event);
|
||||
static gboolean theora_dec_src_query (GstPad * pad,
|
||||
|
@ -164,13 +167,13 @@ gst_theora_dec_init (GstTheoraDec * dec)
|
|||
(&theora_dec_sink_factory), "sink");
|
||||
gst_pad_set_formats_function (dec->sinkpad, theora_get_formats);
|
||||
gst_pad_set_convert_function (dec->sinkpad, theora_dec_sink_convert);
|
||||
gst_pad_set_event_function (dec->sinkpad, theora_dec_sink_event);
|
||||
gst_pad_set_chain_function (dec->sinkpad, theora_dec_chain);
|
||||
gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
|
||||
|
||||
dec->srcpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get
|
||||
(&theora_dec_src_factory), "src");
|
||||
gst_pad_use_explicit_caps (dec->srcpad);
|
||||
gst_pad_set_event_mask_function (dec->srcpad, theora_get_event_masks);
|
||||
gst_pad_set_event_function (dec->srcpad, theora_dec_src_event);
|
||||
gst_pad_set_query_type_function (dec->srcpad, theora_get_query_types);
|
||||
|
@ -180,9 +183,8 @@ gst_theora_dec_init (GstTheoraDec * dec)
|
|||
|
||||
gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
|
||||
|
||||
GST_FLAG_SET (dec, GST_ELEMENT_EVENT_AWARE);
|
||||
|
||||
dec->crop = THEORA_DEF_CROP;
|
||||
dec->queued = NULL;
|
||||
}
|
||||
|
||||
/* FIXME: copy from libtheora, theora should somehow make this available for seeking */
|
||||
|
@ -198,6 +200,27 @@ _theora_ilog (unsigned int v)
|
|||
return (ret);
|
||||
}
|
||||
|
||||
static void
|
||||
_inc_granulepos (GstTheoraDec * dec)
|
||||
{
|
||||
guint ilog;
|
||||
gint framecount;
|
||||
|
||||
if (dec->granulepos == -1)
|
||||
return;
|
||||
|
||||
ilog = _theora_ilog (dec->info.keyframe_frequency_force - 1);
|
||||
|
||||
framecount = dec->granulepos >> ilog;
|
||||
framecount += dec->granulepos - (framecount << ilog);
|
||||
|
||||
GST_DEBUG_OBJECT (dec, "framecount=%d, ilog=%u", framecount, ilog);
|
||||
|
||||
framecount++;
|
||||
|
||||
dec->granulepos = (framecount << ilog);
|
||||
}
|
||||
|
||||
static const GstFormat *
|
||||
theora_get_formats (GstPad * pad)
|
||||
{
|
||||
|
@ -249,7 +272,7 @@ theora_dec_src_convert (GstPad * pad,
|
|||
GstTheoraDec *dec;
|
||||
guint64 scale = 1;
|
||||
|
||||
dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
|
||||
dec = GST_THEORA_DEC (GST_PAD_PARENT (pad));
|
||||
|
||||
/* we need the info part before we can done something */
|
||||
if (dec->packetno < 1)
|
||||
|
@ -310,7 +333,7 @@ theora_dec_sink_convert (GstPad * pad,
|
|||
gboolean res = TRUE;
|
||||
GstTheoraDec *dec;
|
||||
|
||||
dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
|
||||
dec = GST_THEORA_DEC (GST_PAD_PARENT (pad));
|
||||
|
||||
/* we need the info part before we can done something */
|
||||
if (dec->packetno < 1)
|
||||
|
@ -376,7 +399,7 @@ theora_dec_src_query (GstPad * pad, GstQueryType query, GstFormat * format,
|
|||
gint64 * value)
|
||||
{
|
||||
gint64 granulepos;
|
||||
GstTheoraDec *dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
|
||||
GstTheoraDec *dec = GST_THEORA_DEC (GST_PAD_PARENT (pad));
|
||||
GstFormat my_format = GST_FORMAT_DEFAULT;
|
||||
guint64 time;
|
||||
|
||||
|
@ -385,9 +408,7 @@ theora_dec_src_query (GstPad * pad, GstQueryType query, GstFormat * format,
|
|||
granulepos = dec->granulepos;
|
||||
} else {
|
||||
/* for the total, we just forward the query to the peer */
|
||||
if (!gst_pad_query (GST_PAD_PEER (dec->sinkpad), query, &my_format,
|
||||
&granulepos))
|
||||
return FALSE;
|
||||
return gst_pad_query (GST_PAD_PEER (dec->sinkpad), query, format, value);
|
||||
}
|
||||
|
||||
/* and convert to the final format in two steps with time as the
|
||||
|
@ -402,6 +423,7 @@ theora_dec_src_query (GstPad * pad, GstQueryType query, GstFormat * format,
|
|||
GST_LOG_OBJECT (dec,
|
||||
"query %u: peer returned granulepos: %llu - we return %llu (format %u)",
|
||||
query, granulepos, *value, *format);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -412,7 +434,7 @@ theora_dec_src_event (GstPad * pad, GstEvent * event)
|
|||
GstTheoraDec *dec;
|
||||
GstFormat format;
|
||||
|
||||
dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
|
||||
dec = GST_THEORA_DEC (GST_PAD_PARENT (pad));
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_SEEK:{
|
||||
|
@ -455,31 +477,36 @@ theora_dec_src_event (GstPad * pad, GstEvent * event)
|
|||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
theora_dec_event (GstTheoraDec * dec, GstEvent * event)
|
||||
static gboolean
|
||||
theora_dec_sink_event (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
guint64 value, time, bytes;
|
||||
guint64 start_value, end_value, time, bytes;
|
||||
GstTheoraDec *dec;
|
||||
|
||||
dec = GST_THEORA_DEC (GST_PAD_PARENT (pad));
|
||||
|
||||
GST_LOG_OBJECT (dec, "handling event");
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_DISCONTINUOUS:
|
||||
if (gst_event_discont_get_value (event, GST_FORMAT_DEFAULT, &value)) {
|
||||
dec->granulepos = value;
|
||||
if (gst_event_discont_get_value (event, GST_FORMAT_DEFAULT,
|
||||
&start_value, &end_value)) {
|
||||
dec->granulepos = start_value;
|
||||
GST_DEBUG_OBJECT (dec,
|
||||
"setting granuleposition to %" G_GUINT64_FORMAT " after discont",
|
||||
value);
|
||||
start_value);
|
||||
} else {
|
||||
GST_WARNING_OBJECT (dec,
|
||||
"discont event didn't include offset, we might set it wrong now");
|
||||
dec->granulepos = -1;
|
||||
}
|
||||
if (dec->packetno < 3) {
|
||||
if (dec->granulepos != 0)
|
||||
GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL),
|
||||
("can't handle discont before parsing first 3 packets"));
|
||||
dec->packetno = 0;
|
||||
gst_pad_push (dec->srcpad, GST_DATA (gst_event_new_discontinuous (FALSE,
|
||||
GST_FORMAT_TIME, (guint64) 0, GST_FORMAT_DEFAULT,
|
||||
(guint64) 0, GST_FORMAT_BYTES, (guint64) 0, 0)));
|
||||
gst_pad_push_event (dec->srcpad, gst_event_new_discontinuous (FALSE,
|
||||
GST_FORMAT_TIME, (guint64) 0, GST_FORMAT_DEFAULT,
|
||||
(guint64) 0, GST_FORMAT_BYTES, (guint64) 0, 0));
|
||||
} else {
|
||||
GstFormat time_format, default_format, bytes_format;
|
||||
|
||||
|
@ -491,15 +518,15 @@ theora_dec_event (GstTheoraDec * dec, GstEvent * event)
|
|||
if (theora_dec_sink_convert (dec->sinkpad, GST_FORMAT_DEFAULT,
|
||||
dec->granulepos, &time_format, &time)
|
||||
&& theora_dec_src_convert (dec->srcpad, GST_FORMAT_TIME, time,
|
||||
&default_format, &value)
|
||||
&default_format, &start_value)
|
||||
&& theora_dec_src_convert (dec->srcpad, GST_FORMAT_TIME, time,
|
||||
&bytes_format, &bytes)) {
|
||||
gst_pad_push (dec->srcpad,
|
||||
GST_DATA (gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
|
||||
time, GST_FORMAT_DEFAULT, value, GST_FORMAT_BYTES, bytes,
|
||||
0)));
|
||||
gst_pad_push_event (dec->srcpad,
|
||||
gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
|
||||
time, GST_FORMAT_DEFAULT, start_value, GST_FORMAT_BYTES,
|
||||
bytes, 0));
|
||||
/* store new framenumber */
|
||||
dec->packetno = value + 3;
|
||||
dec->packetno = start_value + 3;
|
||||
} else {
|
||||
GST_ERROR_OBJECT (dec,
|
||||
"failed to parse data for DISCONT event, not sending any");
|
||||
|
@ -511,38 +538,94 @@ theora_dec_event (GstTheoraDec * dec, GstEvent * event)
|
|||
default:
|
||||
break;
|
||||
}
|
||||
gst_pad_event_default (dec->sinkpad, event);
|
||||
return gst_pad_event_default (dec->sinkpad, event);
|
||||
}
|
||||
|
||||
#define ROUND_UP_2(x) (((x) + 1) & ~1)
|
||||
#define ROUND_UP_4(x) (((x) + 3) & ~3)
|
||||
#define ROUND_UP_8(x) (((x) + 7) & ~7)
|
||||
|
||||
static void
|
||||
theora_dec_chain (GstPad * pad, GstData * data)
|
||||
static GstFlowReturn
|
||||
theora_dec_chain (GstPad * pad, GstBuffer * buffer)
|
||||
{
|
||||
GstBuffer *buf;
|
||||
GstTheoraDec *dec;
|
||||
ogg_packet packet;
|
||||
guint64 offset_end;
|
||||
GstClockTime outtime;
|
||||
GstFlowReturn result = GST_FLOW_OK;
|
||||
|
||||
dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
|
||||
if (GST_IS_EVENT (data)) {
|
||||
theora_dec_event (dec, GST_EVENT (data));
|
||||
return;
|
||||
}
|
||||
dec = GST_THEORA_DEC (GST_PAD_PARENT (pad));
|
||||
|
||||
buf = GST_BUFFER (data);
|
||||
buf = GST_BUFFER (buffer);
|
||||
|
||||
if (dec->packetno >= 3) {
|
||||
offset_end = GST_BUFFER_OFFSET_END (buf);
|
||||
if (offset_end != -1) {
|
||||
dec->granulepos = offset_end;
|
||||
}
|
||||
/* try timestamp first */
|
||||
outtime = GST_BUFFER_TIMESTAMP (buf);
|
||||
|
||||
/* granulepos to time */
|
||||
outtime = GST_SECOND * theora_granule_time (&dec->state, dec->granulepos);
|
||||
if (outtime == -1) {
|
||||
gboolean need_flush = FALSE;
|
||||
|
||||
/* the offset end field in theora is actually the time of
|
||||
* this frame, not the end time */
|
||||
offset_end = GST_BUFFER_OFFSET_END (buf);
|
||||
GST_DEBUG_OBJECT (dec, "got buffer with granule %lld", offset_end);
|
||||
|
||||
if (offset_end != -1) {
|
||||
if (dec->granulepos == -1) {
|
||||
GST_DEBUG_OBJECT (dec, "first buffer with granule");
|
||||
need_flush = TRUE;
|
||||
}
|
||||
dec->granulepos = offset_end;
|
||||
}
|
||||
if (dec->granulepos == -1) {
|
||||
/* we need to wait for a buffer with at least a timestamp or an
|
||||
* offset before we can generate valid timestamps */
|
||||
dec->queued = g_list_append (dec->queued, buf);
|
||||
GST_DEBUG_OBJECT (dec, "queued buffer");
|
||||
return GST_FLOW_OK;
|
||||
} else {
|
||||
/* granulepos to time */
|
||||
outtime =
|
||||
GST_SECOND * theora_granule_time (&dec->state, dec->granulepos);
|
||||
|
||||
GST_DEBUG_OBJECT (dec, "granulepos=%lld outtime=%" GST_TIME_FORMAT,
|
||||
dec->granulepos, GST_TIME_ARGS (outtime));
|
||||
|
||||
if (need_flush) {
|
||||
GList *walk;
|
||||
GstClockTime patch;
|
||||
gint64 len;
|
||||
gint64 old_granule = dec->granulepos;
|
||||
|
||||
dec->granulepos = -1;
|
||||
|
||||
len = g_list_length (dec->queued);
|
||||
|
||||
GST_DEBUG_OBJECT (dec, "first buffer with granule, flushing");
|
||||
|
||||
/* now resubmit all queued buffers with corrected timestamps */
|
||||
for (walk = dec->queued; walk; walk = g_list_next (walk)) {
|
||||
GstBuffer *qbuffer = GST_BUFFER (walk->data);
|
||||
|
||||
patch = outtime - (GST_SECOND * len * dec->info.fps_denominator) /
|
||||
dec->info.fps_numerator,
|
||||
GST_DEBUG_OBJECT (dec, "patch buffer %lld %lld", len, patch);
|
||||
GST_BUFFER_TIMESTAMP (qbuffer) = patch;
|
||||
|
||||
/* buffers are unreffed in chain function */
|
||||
theora_dec_chain (pad, qbuffer);
|
||||
len--;
|
||||
}
|
||||
g_list_free (dec->queued);
|
||||
dec->queued = NULL;
|
||||
|
||||
dec->granulepos = old_granule;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (dec, "got buffer with timestamp %lld", outtime);
|
||||
}
|
||||
} else {
|
||||
/* we don't know yet */
|
||||
outtime = -1;
|
||||
|
@ -556,10 +639,8 @@ theora_dec_chain (GstPad * pad, GstData * data)
|
|||
packet.b_o_s = (packet.packetno == 0) ? 1 : 0;
|
||||
packet.e_o_s = 0;
|
||||
|
||||
GST_DEBUG_OBJECT (dec, "outtime=%" GST_TIME_FORMAT " (%"
|
||||
G_GUINT64_FORMAT ") header=0x%02x packetno=%d",
|
||||
GST_TIME_ARGS (outtime), outtime,
|
||||
(gint) packet.packet[0], packet.packetno);
|
||||
GST_DEBUG_OBJECT (dec, "header=%d packetno=%lld, outtime=%" GST_TIME_FORMAT,
|
||||
packet.packet[0], packet.packetno, GST_TIME_ARGS (outtime));
|
||||
|
||||
/* switch depending on packet type */
|
||||
if (packet.packet[0] & 0x80) {
|
||||
|
@ -571,6 +652,7 @@ theora_dec_chain (GstPad * pad, GstData * data)
|
|||
if (theora_decode_header (&dec->info, &dec->comment, &packet)) {
|
||||
GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
|
||||
(NULL), ("couldn't read header packet"));
|
||||
result = GST_FLOW_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -595,7 +677,7 @@ theora_dec_chain (GstPad * pad, GstData * data)
|
|||
GST_TAG_ENCODER_VERSION, dec->info.version_major,
|
||||
GST_TAG_NOMINAL_BITRATE, dec->info.target_bitrate,
|
||||
GST_TAG_VIDEO_CODEC, "Theora", NULL);
|
||||
gst_element_found_tags_for_pad (GST_ELEMENT (dec), dec->srcpad, 0, list);
|
||||
//gst_element_found_tags_for_pad (GST_ELEMENT (dec), dec->srcpad, 0, list);
|
||||
|
||||
dec->packetno++;
|
||||
} else if (packet.packetno == 2) {
|
||||
|
@ -657,8 +739,8 @@ theora_dec_chain (GstPad * pad, GstData * data)
|
|||
"pixel-aspect-ratio", GST_TYPE_FRACTION, par_num, par_den,
|
||||
"width", G_TYPE_INT, dec->width, "height", G_TYPE_INT,
|
||||
dec->height, NULL);
|
||||
gst_pad_set_explicit_caps (dec->srcpad, caps);
|
||||
gst_caps_free (caps);
|
||||
gst_pad_set_caps (dec->srcpad, caps);
|
||||
gst_caps_unref (caps);
|
||||
|
||||
dec->initialized = TRUE;
|
||||
dec->packetno++;
|
||||
|
@ -677,6 +759,7 @@ theora_dec_chain (GstPad * pad, GstData * data)
|
|||
dec->packetno++;
|
||||
|
||||
if (!dec->initialized) {
|
||||
result = GST_FLOW_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -684,30 +767,7 @@ theora_dec_chain (GstPad * pad, GstData * data)
|
|||
* for keyframes */
|
||||
keyframe = (packet.packet[0] & 0x40) == 0;
|
||||
if (keyframe) {
|
||||
guint ilog;
|
||||
guint64 framecount;
|
||||
gboolean add_one = FALSE;
|
||||
|
||||
dec->need_keyframe = FALSE;
|
||||
ilog = _theora_ilog (dec->info.keyframe_frequency_force - 1);
|
||||
if (dec->granulepos % (1 << ilog) == 0 &&
|
||||
dec->granulepos > 0 && GST_BUFFER_OFFSET_END (buf) == -1) {
|
||||
dec->granulepos--;
|
||||
add_one = TRUE;
|
||||
}
|
||||
framecount = dec->granulepos >> ilog;
|
||||
framecount += dec->granulepos - (framecount << ilog);
|
||||
if (add_one) {
|
||||
framecount++;
|
||||
}
|
||||
dec->granulepos = framecount << ilog;
|
||||
if (add_one) {
|
||||
outtime = GST_SECOND * theora_granule_time (&dec->state,
|
||||
dec->granulepos);
|
||||
GST_DEBUG_OBJECT (dec,
|
||||
"Correcting output time to %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (outtime));
|
||||
}
|
||||
} else if (dec->need_keyframe) {
|
||||
GST_WARNING_OBJECT (dec, "dropping frame because we need a keyframe");
|
||||
/* drop frames if we're looking for a keyframe */
|
||||
|
@ -716,16 +776,18 @@ theora_dec_chain (GstPad * pad, GstData * data)
|
|||
if (theora_decode_packetin (&dec->state, &packet)) {
|
||||
GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
|
||||
(NULL), ("theora decoder did not read data packet"));
|
||||
result = GST_FLOW_ERROR;
|
||||
goto done;
|
||||
}
|
||||
if (theora_decode_YUVout (&dec->state, &yuv) < 0) {
|
||||
GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
|
||||
(NULL), ("couldn't read out YUV image"));
|
||||
result = GST_FLOW_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
g_return_if_fail (yuv.y_width == dec->info.width);
|
||||
g_return_if_fail (yuv.y_height == dec->info.height);
|
||||
g_return_val_if_fail (yuv.y_width == dec->info.width, GST_FLOW_ERROR);
|
||||
g_return_val_if_fail (yuv.y_height == dec->info.height, GST_FLOW_ERROR);
|
||||
|
||||
width = dec->width;
|
||||
height = dec->height;
|
||||
|
@ -742,7 +804,10 @@ theora_dec_chain (GstPad * pad, GstData * data)
|
|||
|
||||
/* now copy over the area contained in offset_x,offset_y,
|
||||
* frame_width, frame_height */
|
||||
out = gst_pad_alloc_buffer (dec->srcpad, GST_BUFFER_OFFSET_NONE, out_size);
|
||||
out = gst_pad_alloc_buffer (dec->srcpad, GST_BUFFER_OFFSET_NONE, out_size,
|
||||
GST_PAD_CAPS (dec->srcpad));
|
||||
if (out == NULL)
|
||||
goto done;
|
||||
|
||||
/* copy the visible region to the destination. This is actually pretty
|
||||
* complicated and gstreamer doesn't support all the needed caps to do this
|
||||
|
@ -790,11 +855,13 @@ theora_dec_chain (GstPad * pad, GstData * data)
|
|||
dec->info.fps_numerator;
|
||||
GST_BUFFER_TIMESTAMP (out) = outtime;
|
||||
|
||||
gst_pad_push (dec->srcpad, GST_DATA (out));
|
||||
result = gst_pad_push (dec->srcpad, out);
|
||||
}
|
||||
done:
|
||||
gst_data_unref (data);
|
||||
dec->granulepos++;
|
||||
gst_buffer_unref (buffer);
|
||||
_inc_granulepos (dec);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
|
@ -810,6 +877,7 @@ theora_dec_change_state (GstElement * element)
|
|||
theora_comment_init (&dec->comment);
|
||||
dec->need_keyframe = TRUE;
|
||||
dec->initialized = FALSE;
|
||||
dec->granulepos = -1;
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
break;
|
||||
|
@ -820,7 +888,7 @@ theora_dec_change_state (GstElement * element)
|
|||
theora_comment_clear (&dec->comment);
|
||||
theora_info_clear (&dec->info);
|
||||
dec->packetno = 0;
|
||||
dec->granulepos = 0;
|
||||
dec->granulepos = -1;
|
||||
break;
|
||||
case GST_STATE_READY_TO_NULL:
|
||||
break;
|
||||
|
|
|
@ -103,7 +103,7 @@ struct _GstTheoraEnc
|
|||
|
||||
guint packetno;
|
||||
guint64 bytes_out;
|
||||
guint64 initial_delay;
|
||||
guint64 next_ts;
|
||||
};
|
||||
|
||||
struct _GstTheoraEncClass
|
||||
|
@ -170,10 +170,10 @@ GST_STATIC_PAD_TEMPLATE ("src",
|
|||
|
||||
GST_BOILERPLATE (GstTheoraEnc, gst_theora_enc, GstElement, GST_TYPE_ELEMENT);
|
||||
|
||||
static void theora_enc_chain (GstPad * pad, GstData * data);
|
||||
static gboolean theora_enc_sink_event (GstPad * pad, GstEvent * event);
|
||||
static GstFlowReturn theora_enc_chain (GstPad * pad, GstBuffer * buffer);
|
||||
static GstElementStateReturn theora_enc_change_state (GstElement * element);
|
||||
static GstPadLinkReturn theora_enc_sink_link (GstPad * pad,
|
||||
const GstCaps * caps);
|
||||
static gboolean theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps);
|
||||
static void theora_enc_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
static void theora_enc_set_property (GObject * object, guint prop_id,
|
||||
|
@ -255,13 +255,13 @@ gst_theora_enc_init (GstTheoraEnc * enc)
|
|||
gst_pad_new_from_template (gst_static_pad_template_get
|
||||
(&theora_enc_sink_factory), "sink");
|
||||
gst_pad_set_chain_function (enc->sinkpad, theora_enc_chain);
|
||||
gst_pad_set_link_function (enc->sinkpad, theora_enc_sink_link);
|
||||
gst_pad_set_event_function (enc->sinkpad, theora_enc_sink_event);
|
||||
gst_pad_set_setcaps_function (enc->sinkpad, theora_enc_sink_setcaps);
|
||||
gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
|
||||
|
||||
enc->srcpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get
|
||||
(&theora_enc_src_factory), "src");
|
||||
gst_pad_use_explicit_caps (enc->srcpad);
|
||||
gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
|
||||
|
||||
enc->center = THEORA_DEF_CENTER;
|
||||
|
@ -276,12 +276,10 @@ gst_theora_enc_init (GstTheoraEnc * enc)
|
|||
enc->keyframe_threshold = THEORA_DEF_KEYFRAME_THRESHOLD;
|
||||
enc->keyframe_mindistance = THEORA_DEF_KEYFRAME_MINDISTANCE;
|
||||
enc->noise_sensitivity = THEORA_DEF_NOISE_SENSITIVITY;
|
||||
|
||||
GST_FLAG_SET (enc, GST_ELEMENT_EVENT_AWARE);
|
||||
}
|
||||
|
||||
static GstPadLinkReturn
|
||||
theora_enc_sink_link (GstPad * pad, const GstCaps * caps)
|
||||
static gboolean
|
||||
theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
|
||||
{
|
||||
GstStructure *structure = gst_caps_get_structure (caps, 0);
|
||||
GstTheoraEnc *enc = GST_THEORA_ENC (gst_pad_get_parent (pad));
|
||||
|
@ -289,9 +287,6 @@ theora_enc_sink_link (GstPad * pad, const GstCaps * caps)
|
|||
GValue fps = { 0 };
|
||||
GValue framerate = { 0 };
|
||||
|
||||
if (!gst_caps_is_fixed (caps))
|
||||
return GST_PAD_LINK_DELAYED;
|
||||
|
||||
gst_structure_get_int (structure, "width", &enc->width);
|
||||
gst_structure_get_int (structure, "height", &enc->height);
|
||||
gst_structure_get_double (structure, "framerate", &enc->fps);
|
||||
|
@ -352,7 +347,7 @@ theora_enc_sink_link (GstPad * pad, const GstCaps * caps)
|
|||
|
||||
theora_encode_init (&enc->state, &enc->info);
|
||||
|
||||
return GST_PAD_LINK_OK;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* prepare a buffer for transmission by passing data through libtheora */
|
||||
|
@ -361,43 +356,25 @@ theora_buffer_from_packet (GstTheoraEnc * enc, ogg_packet * packet,
|
|||
GstClockTime timestamp, GstClockTime duration)
|
||||
{
|
||||
GstBuffer *buf;
|
||||
guint64 granulepos_delta, timestamp_delta;
|
||||
|
||||
/* if duration is 0, it's a header packet and should
|
||||
* have granulepos 0 (so no delta regardless of delay) */
|
||||
if (duration == 0) {
|
||||
granulepos_delta = 0;
|
||||
timestamp_delta = 0;
|
||||
} else {
|
||||
granulepos_delta = enc->initial_delay * enc->fps / GST_SECOND;
|
||||
timestamp_delta = enc->initial_delay;
|
||||
}
|
||||
|
||||
buf = gst_pad_alloc_buffer (enc->srcpad,
|
||||
GST_BUFFER_OFFSET_NONE, packet->bytes);
|
||||
GST_BUFFER_OFFSET_NONE, packet->bytes, GST_PAD_CAPS (enc->srcpad));
|
||||
memcpy (GST_BUFFER_DATA (buf), packet->packet, packet->bytes);
|
||||
GST_BUFFER_OFFSET (buf) = enc->bytes_out;
|
||||
GST_BUFFER_OFFSET_END (buf) = packet->granulepos + granulepos_delta;
|
||||
GST_BUFFER_TIMESTAMP (buf) = timestamp + timestamp_delta;
|
||||
GST_BUFFER_OFFSET_END (buf) = packet->granulepos;
|
||||
GST_BUFFER_TIMESTAMP (buf) = timestamp;
|
||||
GST_BUFFER_DURATION (buf) = duration;
|
||||
|
||||
/* the second most significant bit of the first data byte is cleared
|
||||
* for keyframes */
|
||||
if ((packet->packet[0] & 0x40) == 0) {
|
||||
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_KEY_UNIT);
|
||||
GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_DELTA_UNIT);
|
||||
} else {
|
||||
GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_KEY_UNIT);
|
||||
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_DELTA_UNIT);
|
||||
}
|
||||
|
||||
enc->packetno++;
|
||||
|
||||
GST_DEBUG ("encoded buffer of %d bytes. granulepos = %" G_GINT64_FORMAT
|
||||
" + %" G_GINT64_FORMAT " = %" G_GINT64_FORMAT, GST_BUFFER_SIZE (buf),
|
||||
packet->granulepos, granulepos_delta,
|
||||
packet->granulepos + granulepos_delta);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
@ -408,7 +385,7 @@ theora_push_buffer (GstTheoraEnc * enc, GstBuffer * buffer)
|
|||
enc->bytes_out += GST_BUFFER_SIZE (buffer);
|
||||
|
||||
if (GST_PAD_IS_USABLE (enc->srcpad)) {
|
||||
gst_pad_push (enc->srcpad, GST_DATA (buffer));
|
||||
gst_pad_push (enc->srcpad, buffer);
|
||||
} else {
|
||||
gst_buffer_unref (buffer);
|
||||
}
|
||||
|
@ -455,51 +432,38 @@ theora_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
|
|||
g_value_unset (&list);
|
||||
}
|
||||
|
||||
static void
|
||||
theora_enc_chain (GstPad * pad, GstData * data)
|
||||
static gboolean
|
||||
theora_enc_sink_event (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
GstTheoraEnc *enc;
|
||||
ogg_packet op;
|
||||
|
||||
enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_EOS:
|
||||
/* push last packet with eos flag */
|
||||
while (theora_encode_packetout (&enc->state, 1, &op)) {
|
||||
GstClockTime out_time =
|
||||
theora_granule_time (&enc->state, op.granulepos) * GST_SECOND;
|
||||
theora_push_packet (enc, &op, out_time, GST_SECOND / enc->fps);
|
||||
}
|
||||
default:
|
||||
return gst_pad_event_default (pad, event);
|
||||
}
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
theora_enc_chain (GstPad * pad, GstBuffer * buffer)
|
||||
{
|
||||
GstTheoraEnc *enc;
|
||||
ogg_packet op;
|
||||
GstBuffer *buf;
|
||||
GstClockTime in_time;
|
||||
|
||||
enc = GST_THEORA_ENC (gst_pad_get_parent (pad));
|
||||
if (GST_IS_EVENT (data)) {
|
||||
switch (GST_EVENT_TYPE (data)) {
|
||||
case GST_EVENT_DISCONTINUOUS:
|
||||
{
|
||||
guint64 val;
|
||||
enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
|
||||
|
||||
if (gst_event_discont_get_value (GST_EVENT (data), GST_FORMAT_TIME,
|
||||
&val)) {
|
||||
/* theora does not support discontinuities in the middle of
|
||||
* a stream so we can't just increase the granulepos to reflect
|
||||
* the new position, or can we? would that still be according
|
||||
* to spec? */
|
||||
if (enc->bytes_out == 0) {
|
||||
enc->initial_delay = val;
|
||||
GST_DEBUG ("initial delay = %" G_GUINT64_FORMAT, val);
|
||||
} else {
|
||||
GST_DEBUG ("mid stream discont: val = %" G_GUINT64_FORMAT, val);
|
||||
}
|
||||
}
|
||||
gst_pad_event_default (pad, GST_EVENT (data));
|
||||
return;
|
||||
}
|
||||
case GST_EVENT_EOS:
|
||||
/* push last packet with eos flag */
|
||||
while (theora_encode_packetout (&enc->state, 1, &op)) {
|
||||
GstClockTime out_time =
|
||||
theora_granule_time (&enc->state, op.granulepos) * GST_SECOND;
|
||||
theora_push_packet (enc, &op, out_time, GST_SECOND / enc->fps);
|
||||
}
|
||||
default:
|
||||
gst_pad_event_default (pad, GST_EVENT (data));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
buf = GST_BUFFER (data);
|
||||
buf = GST_BUFFER (buffer);
|
||||
in_time = GST_BUFFER_TIMESTAMP (buf);
|
||||
|
||||
/* no packets written yet, setup headers */
|
||||
|
@ -531,7 +495,7 @@ theora_enc_chain (GstPad * pad, GstData * data)
|
|||
|
||||
/* negotiate with these caps */
|
||||
GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
|
||||
gst_pad_try_set_caps (enc->srcpad, caps);
|
||||
gst_pad_set_caps (enc->srcpad, caps);
|
||||
|
||||
/* push out the header buffers */
|
||||
theora_push_buffer (enc, buf1);
|
||||
|
@ -590,7 +554,7 @@ theora_enc_chain (GstPad * pad, GstData * data)
|
|||
dst_uv_stride = enc->info_width / 2;
|
||||
|
||||
newbuf = gst_pad_alloc_buffer (enc->srcpad,
|
||||
GST_BUFFER_OFFSET_NONE, y_size * 3 / 2);
|
||||
GST_BUFFER_OFFSET_NONE, y_size * 3 / 2, GST_PAD_CAPS (enc->srcpad));
|
||||
|
||||
dest_y = yuv.y = GST_BUFFER_DATA (newbuf);
|
||||
dest_u = yuv.u = yuv.y + y_size;
|
||||
|
@ -691,6 +655,8 @@ theora_enc_chain (GstPad * pad, GstData * data)
|
|||
|
||||
gst_buffer_unref (buf);
|
||||
}
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
|
@ -705,7 +671,6 @@ theora_enc_change_state (GstElement * element)
|
|||
theora_info_init (&enc->info);
|
||||
theora_comment_init (&enc->comment);
|
||||
enc->packetno = 0;
|
||||
enc->initial_delay = 0;
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
break;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
plugin_LTLIBRARIES = libgstvorbis.la
|
||||
|
||||
libgstvorbis_la_SOURCES = vorbis.c \
|
||||
vorbisdec.c vorbisenc.c oggvorbisenc.c vorbisparse.c
|
||||
vorbisdec.c vorbisenc.c vorbisparse.c
|
||||
libgstvorbis_la_CFLAGS = $(GST_CFLAGS) $(VORBIS_CFLAGS)
|
||||
## AM_PATH_VORBIS also sets VORBISENC_LIBS
|
||||
libgstvorbis_la_LIBADD = $(VORBIS_LIBS) $(VORBISENC_LIBS) $(VORBISFILE_LIBS)
|
||||
libgstvorbis_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
|
||||
noinst_HEADERS = vorbisenc.h vorbisdec.h oggvorbisenc.h vorbisparse.h
|
||||
noinst_HEADERS = vorbisenc.h vorbisdec.h vorbisparse.h
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,100 +0,0 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __OGGVORBISENC_H__
|
||||
#define __OGGVORBISENC_H__
|
||||
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include <vorbis/codec.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define GST_TYPE_OGGVORBISENC \
|
||||
(oggvorbisenc_get_type())
|
||||
#define GST_OGGVORBISENC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OGGVORBISENC,OggVorbisEnc))
|
||||
#define GST_OGGVORBISENC_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OGGVORBISENC,OggVorbisEncClass))
|
||||
#define GST_IS_OGGVORBISENC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OGGVORBISENC))
|
||||
#define GST_IS_OGGVORBISENC_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OGGVORBISENC))
|
||||
|
||||
typedef struct _OggVorbisEnc OggVorbisEnc;
|
||||
typedef struct _OggVorbisEncClass OggVorbisEncClass;
|
||||
|
||||
struct _OggVorbisEnc {
|
||||
GstElement element;
|
||||
|
||||
GstPad *sinkpad,
|
||||
*srcpad;
|
||||
|
||||
ogg_stream_state os; /* take physical pages, weld into a logical
|
||||
stream of packets */
|
||||
ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */
|
||||
ogg_packet op; /* one raw packet of data for decode */
|
||||
|
||||
vorbis_info vi; /* struct that stores all the static vorbis bitstream
|
||||
settings */
|
||||
vorbis_comment vc; /* struct that stores all the user comments */
|
||||
|
||||
vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
|
||||
vorbis_block vb; /* local working space for packet->PCM decode */
|
||||
|
||||
gboolean eos;
|
||||
|
||||
gboolean managed;
|
||||
gint bitrate;
|
||||
gint min_bitrate;
|
||||
gint max_bitrate;
|
||||
gfloat quality;
|
||||
gboolean quality_set;
|
||||
gint serial;
|
||||
|
||||
gint channels;
|
||||
gint frequency;
|
||||
|
||||
guint64 samples_in;
|
||||
guint64 bytes_out;
|
||||
|
||||
GstTagList * tags;
|
||||
|
||||
gboolean setup;
|
||||
gboolean header_sent;
|
||||
gchar *last_message;
|
||||
};
|
||||
|
||||
struct _OggVorbisEncClass {
|
||||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
GType oggvorbisenc_get_type(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
#endif /* __OGGVORBISENC_H__ */
|
|
@ -22,7 +22,6 @@
|
|||
#endif
|
||||
|
||||
#include "vorbisenc.h"
|
||||
#include "oggvorbisenc.h"
|
||||
#include "vorbisdec.h"
|
||||
#include "vorbisparse.h"
|
||||
|
||||
|
@ -33,15 +32,10 @@ GST_DEBUG_CATEGORY (vorbisparse_debug);
|
|||
static gboolean
|
||||
plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
if (!gst_library_load ("gstbytestream") ||
|
||||
!gst_library_load ("gstaudio") || !gst_library_load ("gsttags"))
|
||||
if (!gst_library_load ("gstaudio") || !gst_library_load ("gsttags"))
|
||||
return FALSE;
|
||||
|
||||
if (!gst_element_register (plugin, "vorbisenc", GST_RANK_NONE,
|
||||
GST_TYPE_OGGVORBISENC))
|
||||
return FALSE;
|
||||
|
||||
if (!gst_element_register (plugin, "rawvorbisenc", GST_RANK_NONE,
|
||||
GST_TYPE_VORBISENC))
|
||||
return FALSE;
|
||||
|
||||
|
|
|
@ -72,7 +72,8 @@ GST_STATIC_PAD_TEMPLATE ("sink",
|
|||
|
||||
GST_BOILERPLATE (GstVorbisDec, gst_vorbis_dec, GstElement, GST_TYPE_ELEMENT);
|
||||
|
||||
static void vorbis_dec_chain (GstPad * pad, GstData * data);
|
||||
static gboolean vorbis_dec_sink_event (GstPad * pad, GstEvent * event);
|
||||
static GstFlowReturn vorbis_dec_chain (GstPad * pad, GstBuffer * buffer);
|
||||
static GstElementStateReturn vorbis_dec_change_state (GstElement * element);
|
||||
static const GstFormat *vorbis_dec_get_formats (GstPad * pad);
|
||||
|
||||
|
@ -152,6 +153,7 @@ gst_vorbis_dec_init (GstVorbisDec * dec)
|
|||
dec->sinkpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get
|
||||
(&vorbis_dec_sink_factory), "sink");
|
||||
gst_pad_set_event_function (dec->sinkpad, vorbis_dec_sink_event);
|
||||
gst_pad_set_chain_function (dec->sinkpad, vorbis_dec_chain);
|
||||
gst_pad_set_formats_function (dec->sinkpad, vorbis_dec_get_formats);
|
||||
gst_pad_set_convert_function (dec->sinkpad, vorbis_dec_convert);
|
||||
|
@ -160,7 +162,6 @@ gst_vorbis_dec_init (GstVorbisDec * dec)
|
|||
dec->srcpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get
|
||||
(&vorbis_dec_src_factory), "src");
|
||||
gst_pad_use_explicit_caps (dec->srcpad);
|
||||
gst_pad_set_event_mask_function (dec->srcpad, vorbis_get_event_masks);
|
||||
gst_pad_set_event_function (dec->srcpad, vorbis_dec_src_event);
|
||||
gst_pad_set_query_type_function (dec->srcpad, vorbis_get_query_types);
|
||||
|
@ -168,8 +169,6 @@ gst_vorbis_dec_init (GstVorbisDec * dec)
|
|||
gst_pad_set_formats_function (dec->srcpad, vorbis_dec_get_formats);
|
||||
gst_pad_set_convert_function (dec->srcpad, vorbis_dec_convert);
|
||||
gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
|
||||
|
||||
GST_FLAG_SET (dec, GST_ELEMENT_EVENT_AWARE);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -240,16 +239,12 @@ vorbis_dec_src_query (GstPad * pad, GstQueryType query, GstFormat * format,
|
|||
{
|
||||
gint64 granulepos = 0;
|
||||
GstVorbisDec *dec = GST_VORBIS_DEC (gst_pad_get_parent (pad));
|
||||
GstFormat my_format = GST_FORMAT_DEFAULT;
|
||||
|
||||
if (query == GST_QUERY_POSITION) {
|
||||
granulepos = dec->granulepos;
|
||||
} else {
|
||||
/* query peer in default format */
|
||||
if (!dec->sinkpad || !GST_PAD_PEER (dec->sinkpad) ||
|
||||
!gst_pad_query (GST_PAD_PEER (dec->sinkpad), query, &my_format,
|
||||
&granulepos))
|
||||
return FALSE;
|
||||
return gst_pad_query (GST_PAD_PEER (dec->sinkpad), query, format, value);
|
||||
}
|
||||
|
||||
/* and convert to the final format */
|
||||
|
@ -257,7 +252,7 @@ vorbis_dec_src_query (GstPad * pad, GstQueryType query, GstFormat * format,
|
|||
return FALSE;
|
||||
|
||||
GST_LOG_OBJECT (dec,
|
||||
"query %u: peer returned granulepos: %llu - we return %llu (format %u)",
|
||||
"query %u: peer returned granulepos: %llu - we return %llu (format %u)\n",
|
||||
query, granulepos, *value, *format);
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -271,16 +266,15 @@ vorbis_dec_src_event (GstPad * pad, GstEvent * event)
|
|||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_SEEK:{
|
||||
guint64 value;
|
||||
GstFormat my_format = GST_FORMAT_DEFAULT;
|
||||
GstFormat my_format = GST_FORMAT_TIME;
|
||||
|
||||
/* convert to granulepos */
|
||||
res = vorbis_dec_convert (pad, GST_EVENT_SEEK_FORMAT (event),
|
||||
/* convert to time */
|
||||
res = gst_pad_convert (pad, GST_EVENT_SEEK_FORMAT (event),
|
||||
GST_EVENT_SEEK_OFFSET (event), &my_format, &value);
|
||||
if (res) {
|
||||
GstEvent *real_seek = gst_event_new_seek (
|
||||
(GST_EVENT_SEEK_TYPE (event) & ~GST_SEEK_FORMAT_MASK) |
|
||||
GST_FORMAT_DEFAULT,
|
||||
value);
|
||||
GST_FORMAT_TIME, value);
|
||||
|
||||
res = gst_pad_send_event (GST_PAD_PEER (dec->sinkpad), real_seek);
|
||||
}
|
||||
|
@ -295,20 +289,24 @@ vorbis_dec_src_event (GstPad * pad, GstEvent * event)
|
|||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
vorbis_dec_event (GstVorbisDec * dec, GstEvent * event)
|
||||
static gboolean
|
||||
vorbis_dec_sink_event (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
guint64 value, time, bytes;
|
||||
guint64 start_value, end_value, time, bytes;
|
||||
gboolean ret = TRUE;
|
||||
GstVorbisDec *dec;
|
||||
|
||||
dec = GST_VORBIS_DEC (GST_PAD_PARENT (pad));
|
||||
|
||||
GST_LOG_OBJECT (dec, "handling event");
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_DISCONTINUOUS:
|
||||
if (gst_event_discont_get_value (event, GST_FORMAT_DEFAULT,
|
||||
(gint64 *) & value)) {
|
||||
dec->granulepos = value;
|
||||
(gint64 *) & start_value, &end_value)) {
|
||||
dec->granulepos = start_value;
|
||||
GST_DEBUG_OBJECT (dec,
|
||||
"setting granuleposition to %" G_GUINT64_FORMAT " after discont",
|
||||
value);
|
||||
start_value);
|
||||
} else {
|
||||
GST_WARNING_OBJECT (dec,
|
||||
"discont event didn't include offset, we might set it wrong now");
|
||||
|
@ -318,9 +316,9 @@ vorbis_dec_event (GstVorbisDec * dec, GstEvent * event)
|
|||
GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL),
|
||||
("can't handle discont before parsing first 3 packets"));
|
||||
dec->packetno = 0;
|
||||
gst_pad_push (dec->srcpad, GST_DATA (gst_event_new_discontinuous (FALSE,
|
||||
GST_FORMAT_TIME, (guint64) 0, GST_FORMAT_DEFAULT,
|
||||
(guint64) 0, GST_FORMAT_BYTES, (guint64) 0, 0)));
|
||||
gst_pad_push_event (dec->srcpad, gst_event_new_discontinuous (FALSE,
|
||||
GST_FORMAT_TIME, (guint64) 0, GST_FORMAT_DEFAULT,
|
||||
(guint64) 0, GST_FORMAT_BYTES, (guint64) 0, 0));
|
||||
} else {
|
||||
GstFormat time_format, default_format, bytes_format;
|
||||
|
||||
|
@ -334,10 +332,10 @@ vorbis_dec_event (GstVorbisDec * dec, GstEvent * event)
|
|||
dec->granulepos, &time_format, &time)
|
||||
&& vorbis_dec_convert (dec->srcpad, GST_FORMAT_DEFAULT,
|
||||
dec->granulepos, &bytes_format, &bytes)) {
|
||||
gst_pad_push (dec->srcpad,
|
||||
GST_DATA (gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
|
||||
time, GST_FORMAT_DEFAULT, dec->granulepos,
|
||||
GST_FORMAT_BYTES, bytes, 0)));
|
||||
gst_pad_push_event (dec->srcpad,
|
||||
gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
|
||||
time, GST_FORMAT_DEFAULT, dec->granulepos,
|
||||
GST_FORMAT_BYTES, bytes, 0));
|
||||
} else {
|
||||
GST_ERROR_OBJECT (dec,
|
||||
"failed to parse data for DISCONT event, not sending any");
|
||||
|
@ -349,25 +347,22 @@ vorbis_dec_event (GstVorbisDec * dec, GstEvent * event)
|
|||
gst_data_unref (GST_DATA (event));
|
||||
break;
|
||||
default:
|
||||
gst_pad_event_default (dec->sinkpad, event);
|
||||
ret = gst_pad_event_default (dec->sinkpad, event);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
vorbis_dec_chain (GstPad * pad, GstData * data)
|
||||
static GstFlowReturn
|
||||
vorbis_dec_chain (GstPad * pad, GstBuffer * buffer)
|
||||
{
|
||||
GstBuffer *buf;
|
||||
GstBuffer *buf = GST_BUFFER (buffer);
|
||||
GstVorbisDec *vd;
|
||||
ogg_packet packet; /* lol */
|
||||
ogg_packet packet;
|
||||
GstFlowReturn result = GST_FLOW_OK;
|
||||
|
||||
vd = GST_VORBIS_DEC (gst_pad_get_parent (pad));
|
||||
if (GST_IS_EVENT (data)) {
|
||||
vorbis_dec_event (vd, GST_EVENT (data));
|
||||
return;
|
||||
}
|
||||
vd = GST_VORBIS_DEC (GST_PAD_PARENT (pad));
|
||||
|
||||
buf = GST_BUFFER (data);
|
||||
/* make ogg_packet out of the buffer */
|
||||
packet.packet = GST_BUFFER_DATA (buf);
|
||||
packet.bytes = GST_BUFFER_SIZE (buf);
|
||||
|
@ -391,16 +386,16 @@ vorbis_dec_chain (GstPad * pad, GstData * data)
|
|||
GST_WARNING_OBJECT (GST_ELEMENT (vd),
|
||||
"unexpected packet type %d, expected %d",
|
||||
(gint) packet.packet[0], (gint) packet.packetno);
|
||||
gst_data_unref (data);
|
||||
return;
|
||||
gst_buffer_unref (buffer);
|
||||
return GST_FLOW_UNEXPECTED;
|
||||
}
|
||||
/* Packetno = 0 if the first byte is exactly 0x01 */
|
||||
packet.b_o_s = (packet.packet[0] == 0x1) ? 1 : 0;
|
||||
if (vorbis_synthesis_headerin (&vd->vi, &vd->vc, &packet)) {
|
||||
GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE,
|
||||
(NULL), ("couldn't read header packet"));
|
||||
gst_data_unref (data);
|
||||
return;
|
||||
gst_buffer_unref (buffer);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
if (packet.packetno == 1) {
|
||||
gchar *encoder = NULL;
|
||||
|
@ -429,7 +424,7 @@ vorbis_dec_chain (GstPad * pad, GstData * data)
|
|||
if (vd->vi.bitrate_lower > 0)
|
||||
gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
|
||||
GST_TAG_MINIMUM_BITRATE, (guint) vd->vi.bitrate_lower, NULL);
|
||||
gst_element_found_tags_for_pad (GST_ELEMENT (vd), vd->srcpad, 0, list);
|
||||
//gst_element_found_tags_for_pad (GST_ELEMENT (vd), vd->srcpad, 0, list);
|
||||
} else if (packet.packetno == 2) {
|
||||
GstCaps *caps;
|
||||
const GstAudioChannelPosition *pos = NULL;
|
||||
|
@ -490,20 +485,17 @@ vorbis_dec_chain (GstPad * pad, GstData * data)
|
|||
break;
|
||||
}
|
||||
default:
|
||||
gst_data_unref (data);
|
||||
gst_caps_free (caps);
|
||||
gst_buffer_unref (buffer);
|
||||
gst_caps_unref (caps);
|
||||
GST_ELEMENT_ERROR (vd, STREAM, NOT_IMPLEMENTED, (NULL),
|
||||
("Unsupported channel count %d", vd->vi.channels));
|
||||
return;
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
if (pos) {
|
||||
gst_audio_set_channel_positions (gst_caps_get_structure (caps, 0), pos);
|
||||
}
|
||||
if (!gst_pad_set_explicit_caps (vd->srcpad, caps)) {
|
||||
gst_caps_free (caps);
|
||||
return;
|
||||
}
|
||||
gst_caps_free (caps);
|
||||
gst_pad_set_caps (vd->srcpad, caps);
|
||||
gst_caps_unref (caps);
|
||||
}
|
||||
} else {
|
||||
float **pcm;
|
||||
|
@ -512,62 +504,71 @@ vorbis_dec_chain (GstPad * pad, GstData * data)
|
|||
if (packet.packetno < 3) {
|
||||
GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE,
|
||||
(NULL), ("no header sent yet (packet no is %d)", packet.packetno));
|
||||
gst_data_unref (data);
|
||||
return;
|
||||
gst_buffer_unref (buffer);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
/* normal data packet */
|
||||
if (vorbis_synthesis (&vd->vb, &packet)) {
|
||||
GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE,
|
||||
(NULL), ("couldn't read data packet"));
|
||||
gst_data_unref (data);
|
||||
return;
|
||||
gst_buffer_unref (buffer);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
if (vorbis_synthesis_blockin (&vd->vd, &vd->vb) < 0) {
|
||||
GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE,
|
||||
(NULL), ("vorbis decoder did not accept data packet"));
|
||||
gst_data_unref (data);
|
||||
return;
|
||||
gst_buffer_unref (buffer);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
sample_count = vorbis_synthesis_pcmout (&vd->vd, &pcm);
|
||||
if (sample_count > 0) {
|
||||
int i, j;
|
||||
GstBuffer *out = gst_pad_alloc_buffer (vd->srcpad, GST_BUFFER_OFFSET_NONE,
|
||||
sample_count * vd->vi.channels * sizeof (float));
|
||||
float *out_data = (float *) GST_BUFFER_DATA (out);
|
||||
sample_count * vd->vi.channels * sizeof (float),
|
||||
GST_PAD_CAPS (vd->srcpad));
|
||||
float *out_data;
|
||||
|
||||
if (out != NULL) {
|
||||
out_data = (float *) GST_BUFFER_DATA (out);
|
||||
|
||||
#ifdef GST_VORBIS_DEC_SEQUENTIAL
|
||||
for (i = 0; i < vd->vi.channels; i++) {
|
||||
memcpy (out_data, pcm[i], sample_count * sizeof (float));
|
||||
out_data += sample_count;
|
||||
}
|
||||
#else
|
||||
for (j = 0; j < sample_count; j++) {
|
||||
for (i = 0; i < vd->vi.channels; i++) {
|
||||
*out_data = pcm[i][j];
|
||||
out_data++;
|
||||
memcpy (out_data, pcm[i], sample_count * sizeof (float));
|
||||
out_data += sample_count;
|
||||
}
|
||||
#else
|
||||
for (j = 0; j < sample_count; j++) {
|
||||
for (i = 0; i < vd->vi.channels; i++) {
|
||||
*out_data = pcm[i][j];
|
||||
out_data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
GST_BUFFER_OFFSET (out) = vd->granulepos;
|
||||
GST_BUFFER_OFFSET_END (out) = vd->granulepos + sample_count;
|
||||
GST_BUFFER_TIMESTAMP (out) = vd->granulepos * GST_SECOND / vd->vi.rate;
|
||||
GST_BUFFER_DURATION (out) = sample_count * GST_SECOND / vd->vi.rate;
|
||||
GST_DEBUG ("Pushing data of time %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out)));
|
||||
gst_pad_push (vd->srcpad, GST_DATA (out));
|
||||
GST_BUFFER_OFFSET (out) = vd->granulepos;
|
||||
GST_BUFFER_OFFSET_END (out) = vd->granulepos + sample_count;
|
||||
GST_BUFFER_TIMESTAMP (out) = vd->granulepos * GST_SECOND / vd->vi.rate;
|
||||
GST_BUFFER_DURATION (out) = sample_count * GST_SECOND / vd->vi.rate;
|
||||
result = gst_pad_push (vd->srcpad, out);
|
||||
vd->granulepos += sample_count;
|
||||
}
|
||||
vorbis_synthesis_read (&vd->vd, sample_count);
|
||||
vd->granulepos += sample_count;
|
||||
}
|
||||
}
|
||||
gst_data_unref (data);
|
||||
gst_buffer_unref (buffer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
vorbis_dec_change_state (GstElement * element)
|
||||
{
|
||||
GstVorbisDec *vd = GST_VORBIS_DEC (element);
|
||||
GstElementState transition;
|
||||
GstElementStateReturn res;
|
||||
|
||||
switch (GST_STATE_TRANSITION (element)) {
|
||||
transition = GST_STATE_TRANSITION (element);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_NULL_TO_READY:
|
||||
break;
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
|
@ -576,6 +577,13 @@ vorbis_dec_change_state (GstElement * element)
|
|||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
res = parent_class->change_state (element);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_PLAYING_TO_PAUSED:
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
|
@ -592,5 +600,5 @@ vorbis_dec_change_state (GstElement * element)
|
|||
break;
|
||||
}
|
||||
|
||||
return parent_class->change_state (element);
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -103,7 +103,8 @@ static void gst_vorbisenc_base_init (gpointer g_class);
|
|||
static void gst_vorbisenc_class_init (VorbisEncClass * klass);
|
||||
static void gst_vorbisenc_init (VorbisEnc * vorbisenc);
|
||||
|
||||
static void gst_vorbisenc_chain (GstPad * pad, GstData * _data);
|
||||
static gboolean gst_vorbisenc_sink_event (GstPad * pad, GstEvent * event);
|
||||
static GstFlowReturn gst_vorbisenc_chain (GstPad * pad, GstBuffer * buffer);
|
||||
static gboolean gst_vorbisenc_setup (VorbisEnc * vorbisenc);
|
||||
|
||||
static void gst_vorbisenc_get_property (GObject * object, guint prop_id,
|
||||
|
@ -197,6 +198,9 @@ gst_vorbisenc_class_init (VorbisEncClass * klass)
|
|||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
|
||||
gobject_class->set_property = gst_vorbisenc_set_property;
|
||||
gobject_class->get_property = gst_vorbisenc_get_property;
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAX_BITRATE,
|
||||
g_param_spec_int ("max-bitrate", "Maximum Bitrate",
|
||||
"Specify a maximum bitrate (in bps). Useful for streaming "
|
||||
|
@ -226,14 +230,11 @@ gst_vorbisenc_class_init (VorbisEncClass * klass)
|
|||
|
||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
||||
|
||||
gobject_class->set_property = gst_vorbisenc_set_property;
|
||||
gobject_class->get_property = gst_vorbisenc_get_property;
|
||||
|
||||
gstelement_class->change_state = gst_vorbisenc_change_state;
|
||||
}
|
||||
|
||||
static GstPadLinkReturn
|
||||
gst_vorbisenc_sinkconnect (GstPad * pad, const GstCaps * caps)
|
||||
static gboolean
|
||||
gst_vorbisenc_sink_setcaps (GstPad * pad, GstCaps * caps)
|
||||
{
|
||||
VorbisEnc *vorbisenc;
|
||||
GstStructure *structure;
|
||||
|
@ -248,9 +249,9 @@ gst_vorbisenc_sinkconnect (GstPad * pad, const GstCaps * caps)
|
|||
gst_vorbisenc_setup (vorbisenc);
|
||||
|
||||
if (vorbisenc->setup)
|
||||
return GST_PAD_LINK_OK;
|
||||
return TRUE;
|
||||
|
||||
return GST_PAD_LINK_REFUSED;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -447,8 +448,9 @@ gst_vorbisenc_init (VorbisEnc * vorbisenc)
|
|||
vorbisenc->sinkpad =
|
||||
gst_pad_new_from_template (gst_vorbisenc_sink_template, "sink");
|
||||
gst_element_add_pad (GST_ELEMENT (vorbisenc), vorbisenc->sinkpad);
|
||||
gst_pad_set_event_function (vorbisenc->sinkpad, gst_vorbisenc_sink_event);
|
||||
gst_pad_set_chain_function (vorbisenc->sinkpad, gst_vorbisenc_chain);
|
||||
gst_pad_set_link_function (vorbisenc->sinkpad, gst_vorbisenc_sinkconnect);
|
||||
gst_pad_set_setcaps_function (vorbisenc->sinkpad, gst_vorbisenc_sink_setcaps);
|
||||
gst_pad_set_convert_function (vorbisenc->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_vorbisenc_convert_sink));
|
||||
gst_pad_set_formats_function (vorbisenc->sinkpad,
|
||||
|
@ -482,11 +484,6 @@ gst_vorbisenc_init (VorbisEnc * vorbisenc)
|
|||
vorbisenc->header_sent = FALSE;
|
||||
|
||||
vorbisenc->tags = gst_tag_list_new ();
|
||||
|
||||
vorbisenc->initial_delay = 0;
|
||||
|
||||
/* we're chained and we can deal with events */
|
||||
GST_FLAG_SET (vorbisenc, GST_ELEMENT_EVENT_AWARE);
|
||||
}
|
||||
|
||||
|
||||
|
@ -718,32 +715,16 @@ static GstBuffer *
|
|||
gst_vorbisenc_buffer_from_packet (VorbisEnc * vorbisenc, ogg_packet * packet)
|
||||
{
|
||||
GstBuffer *outbuf;
|
||||
guint64 granulepos_delta, timestamp_delta;
|
||||
|
||||
/* header packets always need to have granulepos 0,
|
||||
* regardless of the initial delay */
|
||||
if (packet->granulepos == 0) {
|
||||
granulepos_delta = 0;
|
||||
timestamp_delta = 0;
|
||||
} else {
|
||||
granulepos_delta =
|
||||
vorbisenc->initial_delay * vorbisenc->frequency / GST_SECOND;
|
||||
timestamp_delta = vorbisenc->initial_delay;
|
||||
}
|
||||
|
||||
outbuf = gst_buffer_new_and_alloc (packet->bytes);
|
||||
memcpy (GST_BUFFER_DATA (outbuf), packet->packet, packet->bytes);
|
||||
GST_BUFFER_OFFSET (outbuf) = vorbisenc->bytes_out;
|
||||
GST_BUFFER_OFFSET_END (outbuf) = packet->granulepos + granulepos_delta;
|
||||
GST_BUFFER_OFFSET_END (outbuf) = packet->granulepos;
|
||||
GST_BUFFER_TIMESTAMP (outbuf) =
|
||||
vorbis_granule_time_copy (&vorbisenc->vd,
|
||||
packet->granulepos) * GST_SECOND + timestamp_delta;
|
||||
|
||||
GST_DEBUG ("encoded buffer of %d bytes. granulepos = %" G_GINT64_FORMAT
|
||||
" + %" G_GINT64_FORMAT " = %" G_GINT64_FORMAT, GST_BUFFER_SIZE (outbuf),
|
||||
packet->granulepos, granulepos_delta,
|
||||
packet->granulepos + granulepos_delta);
|
||||
packet->granulepos) * GST_SECOND;
|
||||
|
||||
GST_DEBUG ("encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
|
||||
return outbuf;
|
||||
}
|
||||
|
||||
|
@ -754,7 +735,7 @@ gst_vorbisenc_push_buffer (VorbisEnc * vorbisenc, GstBuffer * buffer)
|
|||
vorbisenc->bytes_out += GST_BUFFER_SIZE (buffer);
|
||||
|
||||
if (GST_PAD_IS_USABLE (vorbisenc->srcpad)) {
|
||||
gst_pad_push (vorbisenc->srcpad, GST_DATA (buffer));
|
||||
gst_pad_push (vorbisenc->srcpad, buffer);
|
||||
} else {
|
||||
gst_buffer_unref (buffer);
|
||||
}
|
||||
|
@ -800,63 +781,49 @@ gst_vorbisenc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
|
|||
g_value_unset (&list);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_vorbisenc_chain (GstPad * pad, GstData * _data)
|
||||
static gboolean
|
||||
gst_vorbisenc_sink_event (GstPad * pad, GstEvent * event)
|
||||
{
|
||||
GstBuffer *buf = GST_BUFFER (_data);
|
||||
gboolean res = TRUE;
|
||||
VorbisEnc *vorbisenc;
|
||||
|
||||
g_return_if_fail (pad != NULL);
|
||||
g_return_if_fail (GST_IS_PAD (pad));
|
||||
g_return_if_fail (buf != NULL);
|
||||
vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));
|
||||
|
||||
vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad));
|
||||
|
||||
if (GST_IS_EVENT (buf)) {
|
||||
GstEvent *event = GST_EVENT (buf);
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_EOS:
|
||||
/* end of file. this can be done implicitly in the mainline,
|
||||
but it's easier to see here in non-clever fashion.
|
||||
Tell the library we're at end of stream so that it can handle
|
||||
the last frame and mark end of stream in the output properly */
|
||||
vorbis_analysis_wrote (&vorbisenc->vd, 0);
|
||||
vorbisenc->eos = TRUE;
|
||||
gst_event_unref (event);
|
||||
break;
|
||||
case GST_EVENT_TAG:
|
||||
if (vorbisenc->tags) {
|
||||
gst_tag_list_insert (vorbisenc->tags, gst_event_tag_get_list (event),
|
||||
gst_tag_setter_get_merge_mode (GST_TAG_SETTER (vorbisenc)));
|
||||
} else {
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
gst_pad_event_default (pad, event);
|
||||
return;
|
||||
case GST_EVENT_DISCONTINUOUS:
|
||||
{
|
||||
guint64 val;
|
||||
|
||||
if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &val)) {
|
||||
/* vorbis does not support discontinuities in the middle of
|
||||
* a stream so we can't just increase the granulepos to reflect
|
||||
* the new position, or can we? would that still be according
|
||||
* to spec? */
|
||||
if (vorbisenc->samples_in == 0) {
|
||||
vorbisenc->initial_delay = val;
|
||||
GST_DEBUG ("initial delay = %" G_GUINT64_FORMAT, val);
|
||||
} else {
|
||||
GST_DEBUG ("mid stream discont: val = %" G_GUINT64_FORMAT, val);
|
||||
}
|
||||
}
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_EOS:
|
||||
/* end of file. this can be done implicitly in the mainline,
|
||||
but it's easier to see here in non-clever fashion.
|
||||
Tell the library we're at end of stream so that it can handle
|
||||
the last frame and mark end of stream in the output properly */
|
||||
vorbis_analysis_wrote (&vorbisenc->vd, 0);
|
||||
vorbisenc->eos = TRUE;
|
||||
gst_event_unref (event);
|
||||
break;
|
||||
case GST_EVENT_TAG:
|
||||
if (vorbisenc->tags) {
|
||||
gst_tag_list_insert (vorbisenc->tags, gst_event_tag_get_list (event),
|
||||
gst_tag_setter_get_merge_mode (GST_TAG_SETTER (vorbisenc)));
|
||||
} else {
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
gst_pad_event_default (pad, event);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
res = gst_pad_event_default (pad, event);
|
||||
break;
|
||||
default:
|
||||
res = gst_pad_event_default (pad, event);
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_vorbisenc_chain (GstPad * pad, GstBuffer * buffer)
|
||||
{
|
||||
GstBuffer *buf = GST_BUFFER (buffer);
|
||||
VorbisEnc *vorbisenc;
|
||||
|
||||
vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));
|
||||
|
||||
{
|
||||
gfloat *data;
|
||||
gulong size;
|
||||
gulong i, j;
|
||||
|
@ -866,7 +833,7 @@ gst_vorbisenc_chain (GstPad * pad, GstData * _data)
|
|||
gst_buffer_unref (buf);
|
||||
GST_ELEMENT_ERROR (vorbisenc, CORE, NEGOTIATION, (NULL),
|
||||
("encoder not initialized (input is not audio?)"));
|
||||
return;
|
||||
return GST_FLOW_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (!vorbisenc->header_sent) {
|
||||
|
@ -899,7 +866,7 @@ gst_vorbisenc_chain (GstPad * pad, GstData * _data)
|
|||
|
||||
/* negotiate with these caps */
|
||||
GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
|
||||
gst_pad_try_set_caps (vorbisenc->srcpad, caps);
|
||||
gst_pad_set_caps (vorbisenc->srcpad, caps);
|
||||
|
||||
/* push out buffers */
|
||||
gst_vorbisenc_push_buffer (vorbisenc, buf1);
|
||||
|
@ -951,9 +918,10 @@ gst_vorbisenc_chain (GstPad * pad, GstData * _data)
|
|||
vorbis_block_clear (&vorbisenc->vb);
|
||||
vorbis_dsp_clear (&vorbisenc->vd);
|
||||
vorbis_info_clear (&vorbisenc->vi);
|
||||
gst_pad_push (vorbisenc->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS)));
|
||||
gst_element_set_eos (GST_ELEMENT (vorbisenc));
|
||||
gst_pad_push_event (vorbisenc->srcpad, gst_event_new (GST_EVENT_EOS));
|
||||
//gst_element_set_eos (GST_ELEMENT (vorbisenc));
|
||||
}
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1069,23 +1037,29 @@ static GstElementStateReturn
|
|||
gst_vorbisenc_change_state (GstElement * element)
|
||||
{
|
||||
VorbisEnc *vorbisenc = GST_VORBISENC (element);
|
||||
GstElementState transition;
|
||||
GstElementStateReturn res;
|
||||
|
||||
switch (GST_STATE_TRANSITION (element)) {
|
||||
transition = GST_STATE_TRANSITION (element);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_NULL_TO_READY:
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
vorbisenc->eos = FALSE;
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
res = GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_PLAYING_TO_PAUSED:
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
vorbisenc->setup = FALSE;
|
||||
vorbisenc->header_sent = FALSE;
|
||||
vorbisenc->initial_delay = 0;
|
||||
vorbisenc->samples_in = 0;
|
||||
vorbisenc->bytes_out = 0;
|
||||
vorbisenc->channels = -1;
|
||||
vorbisenc->frequency = -1;
|
||||
gst_tag_list_free (vorbisenc->tags);
|
||||
vorbisenc->tags = gst_tag_list_new ();
|
||||
break;
|
||||
|
@ -1094,8 +1068,5 @@ gst_vorbisenc_change_state (GstElement * element)
|
|||
break;
|
||||
}
|
||||
|
||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
|
||||
return GST_STATE_SUCCESS;
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -77,8 +77,6 @@ struct _VorbisEnc {
|
|||
gboolean setup;
|
||||
gboolean header_sent;
|
||||
gchar *last_message;
|
||||
|
||||
guint64 initial_delay; /* for streams not starting at timestamp/sample 0 */
|
||||
};
|
||||
|
||||
struct _VorbisEncClass {
|
||||
|
|
|
@ -62,7 +62,7 @@ GST_STATIC_PAD_TEMPLATE ("src",
|
|||
GST_BOILERPLATE (GstVorbisParse, gst_vorbis_parse, GstElement,
|
||||
GST_TYPE_ELEMENT);
|
||||
|
||||
static void vorbis_parse_chain (GstPad * pad, GstData * data);
|
||||
static GstFlowReturn vorbis_parse_chain (GstPad * pad, GstBuffer * buffer);
|
||||
static GstElementStateReturn vorbis_parse_change_state (GstElement * element);
|
||||
|
||||
static void
|
||||
|
@ -143,23 +143,22 @@ vorbis_parse_set_header_on_caps (GstVorbisParse * parse, GstCaps * caps)
|
|||
g_value_unset (&list);
|
||||
}
|
||||
|
||||
static void
|
||||
vorbis_parse_chain (GstPad * pad, GstData * data)
|
||||
static GstFlowReturn
|
||||
vorbis_parse_chain (GstPad * pad, GstBuffer * buffer)
|
||||
{
|
||||
GstBuffer *buf;
|
||||
GstVorbisParse *parse;
|
||||
|
||||
parse = GST_VORBIS_PARSE (gst_pad_get_parent (pad));
|
||||
g_assert (parse);
|
||||
parse = GST_VORBIS_PARSE (GST_PAD_PARENT (pad));
|
||||
|
||||
buf = GST_BUFFER (data);
|
||||
buf = GST_BUFFER (buffer);
|
||||
parse->packetno++;
|
||||
|
||||
/* if 1 <= packetno <= 3, it's streamheader,
|
||||
* so put it on the streamheader list and return */
|
||||
if (parse->packetno <= 3) {
|
||||
parse->streamheader = g_list_append (parse->streamheader, buf);
|
||||
return;
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
/* else, if we haven't sent streamheader buffers yet,
|
||||
|
@ -172,7 +171,7 @@ vorbis_parse_chain (GstPad * pad, GstData * data)
|
|||
|
||||
/* negotiate with these caps */
|
||||
GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
|
||||
gst_pad_try_set_caps (parse->srcpad, caps);
|
||||
gst_pad_set_caps (parse->srcpad, caps);
|
||||
|
||||
/* push out buffers */
|
||||
gst_pad_push (parse->srcpad, parse->streamheader->data);
|
||||
|
@ -182,7 +181,9 @@ vorbis_parse_chain (GstPad * pad, GstData * data)
|
|||
parse->streamheader_sent = TRUE;
|
||||
}
|
||||
/* just send on buffer by default */
|
||||
gst_pad_push (parse->srcpad, data);
|
||||
gst_pad_push (parse->srcpad, buf);
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
|
|
|
@ -30,7 +30,7 @@ static void gst_audio_clock_class_init (GstAudioClockClass * klass);
|
|||
static void gst_audio_clock_init (GstAudioClock * clock);
|
||||
|
||||
static GstClockTime gst_audio_clock_get_internal_time (GstClock * clock);
|
||||
static GstClockEntryStatus gst_audio_clock_id_wait_async (GstClock * clock,
|
||||
static GstClockReturn gst_audio_clock_id_wait_async (GstClock * clock,
|
||||
GstClockEntry * entry);
|
||||
static void gst_audio_clock_id_unschedule (GstClock * clock,
|
||||
GstClockEntry * entry);
|
||||
|
@ -184,7 +184,7 @@ compare_clock_entries (GstClockEntry * entry1, GstClockEntry * entry2)
|
|||
return entry1->time - entry2->time;
|
||||
}
|
||||
|
||||
static GstClockEntryStatus
|
||||
static GstClockReturn
|
||||
gst_audio_clock_id_wait_async (GstClock * clock, GstClockEntry * entry)
|
||||
{
|
||||
GstAudioClock *aclock = (GstAudioClock *) clock;
|
||||
|
|
|
@ -51,7 +51,7 @@ static void gst_audiofilter_set_property (GObject * object, guint prop_id,
|
|||
static void gst_audiofilter_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static void gst_audiofilter_chain (GstPad * pad, GstData * _data);
|
||||
static GstFlowReturn gst_audiofilter_chain (GstPad * pad, GstBuffer * buffer);
|
||||
GstCaps *gst_audiofilter_class_get_capslist (GstAudiofilterClass * klass);
|
||||
|
||||
static GstElementClass *parent_class = NULL;
|
||||
|
@ -113,18 +113,20 @@ gst_audiofilter_class_init (gpointer g_class, gpointer class_data)
|
|||
}
|
||||
|
||||
static GstPadLinkReturn
|
||||
gst_audiofilter_link (GstPad * pad, const GstCaps * caps)
|
||||
gst_audiofilter_link (GstPad * pad, GstPad * peer)
|
||||
{
|
||||
GstAudiofilter *audiofilter;
|
||||
GstPadLinkReturn ret;
|
||||
GstPadLinkReturn link_ret;
|
||||
GstStructure *structure;
|
||||
|
||||
//GstPadLinkReturn ret;
|
||||
//GstPadLinkReturn link_ret;
|
||||
//GstStructure *structure;
|
||||
GstAudiofilterClass *audiofilter_class;
|
||||
|
||||
GST_DEBUG ("gst_audiofilter_link");
|
||||
audiofilter = GST_AUDIOFILTER (gst_pad_get_parent (pad));
|
||||
audiofilter_class = GST_AUDIOFILTER_CLASS (G_OBJECT_GET_CLASS (audiofilter));
|
||||
|
||||
#if 0
|
||||
ret = GST_PAD_LINK_DELAYED; /* intialise with dummy value */
|
||||
if (pad == audiofilter->srcpad) {
|
||||
link_ret = gst_pad_try_set_caps (audiofilter->sinkpad, caps);
|
||||
|
@ -158,6 +160,7 @@ gst_audiofilter_link (GstPad * pad, const GstCaps * caps)
|
|||
|
||||
if (audiofilter_class->setup)
|
||||
(audiofilter_class->setup) (audiofilter);
|
||||
#endif
|
||||
|
||||
return GST_PAD_LINK_OK;
|
||||
}
|
||||
|
@ -177,7 +180,7 @@ gst_audiofilter_init (GTypeInstance * instance, gpointer g_class)
|
|||
gst_element_add_pad (GST_ELEMENT (audiofilter), audiofilter->sinkpad);
|
||||
gst_pad_set_chain_function (audiofilter->sinkpad, gst_audiofilter_chain);
|
||||
gst_pad_set_link_function (audiofilter->sinkpad, gst_audiofilter_link);
|
||||
gst_pad_set_getcaps_function (audiofilter->sinkpad, gst_pad_proxy_getcaps);
|
||||
//gst_pad_set_getcaps_function (audiofilter->sinkpad, gst_pad_proxy_getcaps);
|
||||
|
||||
pad_template =
|
||||
gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
|
||||
|
@ -185,24 +188,24 @@ gst_audiofilter_init (GTypeInstance * instance, gpointer g_class)
|
|||
audiofilter->srcpad = gst_pad_new_from_template (pad_template, "src");
|
||||
gst_element_add_pad (GST_ELEMENT (audiofilter), audiofilter->srcpad);
|
||||
gst_pad_set_link_function (audiofilter->srcpad, gst_audiofilter_link);
|
||||
gst_pad_set_getcaps_function (audiofilter->srcpad, gst_pad_proxy_getcaps);
|
||||
//gst_pad_set_getcaps_function (audiofilter->srcpad, gst_pad_proxy_getcaps);
|
||||
|
||||
audiofilter->inited = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_audiofilter_chain (GstPad * pad, GstData * data)
|
||||
static GstFlowReturn
|
||||
gst_audiofilter_chain (GstPad * pad, GstBuffer * buffer)
|
||||
{
|
||||
GstBuffer *inbuf = GST_BUFFER (data);
|
||||
GstBuffer *inbuf = GST_BUFFER (buffer);
|
||||
GstAudiofilter *audiofilter;
|
||||
GstBuffer *outbuf;
|
||||
GstAudiofilterClass *audiofilter_class;
|
||||
|
||||
GST_DEBUG ("gst_audiofilter_chain");
|
||||
|
||||
g_return_if_fail (pad != NULL);
|
||||
g_return_if_fail (GST_IS_PAD (pad));
|
||||
g_return_if_fail (inbuf != NULL);
|
||||
g_return_val_if_fail (pad != NULL, GST_FLOW_ERROR);
|
||||
g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
|
||||
g_return_val_if_fail (inbuf != NULL, GST_FLOW_ERROR);
|
||||
|
||||
audiofilter = GST_AUDIOFILTER (gst_pad_get_parent (pad));
|
||||
//g_return_if_fail (audiofilter->inited);
|
||||
|
@ -212,14 +215,14 @@ gst_audiofilter_chain (GstPad * pad, GstData * data)
|
|||
GST_BUFFER_SIZE (inbuf), GST_OBJECT_NAME (audiofilter));
|
||||
|
||||
if (audiofilter->passthru) {
|
||||
gst_pad_push (audiofilter->srcpad, data);
|
||||
return;
|
||||
gst_pad_push (audiofilter->srcpad, buffer);
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
audiofilter->size = GST_BUFFER_SIZE (inbuf);
|
||||
audiofilter->n_samples = audiofilter->size / audiofilter->bytes_per_sample;
|
||||
|
||||
if (gst_data_is_writable (data)) {
|
||||
if (gst_data_is_writable (GST_DATA (buffer))) {
|
||||
if (audiofilter_class->filter_inplace) {
|
||||
(audiofilter_class->filter_inplace) (audiofilter, inbuf);
|
||||
outbuf = inbuf;
|
||||
|
@ -246,7 +249,9 @@ gst_audiofilter_chain (GstPad * pad, GstData * data)
|
|||
gst_buffer_unref (inbuf);
|
||||
}
|
||||
|
||||
gst_pad_push (audiofilter->srcpad, GST_DATA (outbuf));
|
||||
gst_pad_push (audiofilter->srcpad, outbuf);
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -49,7 +49,7 @@ main (gint argc, gchar * argv[])
|
|||
str = gst_caps_to_string (caps);
|
||||
g_print ("Test caps #2: %s\n", str);
|
||||
g_free (str);
|
||||
gst_caps_free (caps);
|
||||
gst_caps_unref (caps);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -55,25 +55,34 @@ gst_bin_find_unconnected_pad (GstBin * bin, GstPadDirection direction)
|
|||
const GList *pads = NULL;
|
||||
GstElement *element = NULL;
|
||||
|
||||
elements = (GList *) gst_bin_get_list (bin);
|
||||
GST_LOCK (bin);
|
||||
elements = bin->children;
|
||||
/* traverse all elements looking for unconnected pads */
|
||||
while (elements && pad == NULL) {
|
||||
element = GST_ELEMENT (elements->data);
|
||||
pads = gst_element_get_pad_list (element);
|
||||
GST_LOCK (element);
|
||||
pads = element->pads;
|
||||
while (pads) {
|
||||
GstPad *testpad = GST_PAD (pads->data);
|
||||
|
||||
/* check if the direction matches */
|
||||
if (GST_PAD_DIRECTION (GST_PAD (pads->data)) == direction) {
|
||||
if (GST_PAD_PEER (GST_PAD (pads->data)) == NULL) {
|
||||
if (GST_PAD_DIRECTION (testpad) == direction) {
|
||||
GST_LOCK (pad);
|
||||
if (GST_PAD_PEER (testpad) == NULL) {
|
||||
GST_UNLOCK (pad);
|
||||
/* found it ! */
|
||||
pad = GST_PAD (pads->data);
|
||||
pad = testpad;
|
||||
break;
|
||||
}
|
||||
GST_UNLOCK (pad);
|
||||
}
|
||||
if (pad)
|
||||
break; /* found one already */
|
||||
pads = g_list_next (pads);
|
||||
}
|
||||
GST_UNLOCK (element);
|
||||
elements = g_list_next (elements);
|
||||
}
|
||||
GST_UNLOCK (bin);
|
||||
|
||||
return pad;
|
||||
}
|
||||
|
||||
|
|
|
@ -273,7 +273,7 @@ G_STMT_START { \
|
|||
|
||||
#define CAPS_RESET(target) \
|
||||
G_STMT_START { \
|
||||
if (target) gst_caps_free (target); \
|
||||
if (target) gst_caps_unref (target); \
|
||||
target = NULL; \
|
||||
} G_STMT_END
|
||||
CAPS_RESET (priv->type);
|
||||
|
@ -509,7 +509,9 @@ gmip_find_type (GstMediaInfoPriv * priv, GError ** error)
|
|||
if (!gmip_find_type_pre (priv, error))
|
||||
return FALSE;
|
||||
GST_DEBUG ("gmip_find_type: iterating");
|
||||
while ((priv->type == NULL) && gst_bin_iterate (GST_BIN (priv->pipeline)))
|
||||
while ((priv->type == NULL)
|
||||
// && gst_bin_iterate (GST_BIN (priv->pipeline))
|
||||
)
|
||||
GMI_DEBUG ("+");
|
||||
GMI_DEBUG ("\n");
|
||||
return gmip_find_type_post (priv);
|
||||
|
@ -616,7 +618,7 @@ gmip_find_stream (GstMediaInfoPriv * priv)
|
|||
/* iterate until caps are found */
|
||||
/* FIXME: this should be done through the plugin sending some signal
|
||||
* that it is ready for queries */
|
||||
while (gst_bin_iterate (GST_BIN (priv->pipeline)) && priv->format == NULL);
|
||||
//while (gst_bin_iterate (GST_BIN (priv->pipeline)) && priv->format == NULL);
|
||||
if (gst_element_set_state (priv->pipeline, GST_STATE_PAUSED)
|
||||
== GST_STATE_FAILURE)
|
||||
g_warning ("Couldn't set to paused");
|
||||
|
@ -659,7 +661,9 @@ gmip_find_track_metadata (GstMediaInfoPriv * priv)
|
|||
{
|
||||
gmip_find_track_metadata_pre (priv);
|
||||
GST_DEBUG ("gmip_find_metadata: iterating");
|
||||
while ((priv->metadata == NULL) && gst_bin_iterate (GST_BIN (priv->pipeline)))
|
||||
while ((priv->metadata == NULL)
|
||||
//&& gst_bin_iterate (GST_BIN (priv->pipeline))
|
||||
)
|
||||
GMI_DEBUG ("+");
|
||||
GMI_DEBUG ("\n");
|
||||
gmip_find_track_metadata_post (priv);
|
||||
|
@ -729,8 +733,9 @@ gmip_find_track_streaminfo (GstMediaInfoPriv * priv)
|
|||
{
|
||||
gmip_find_track_streaminfo_pre (priv);
|
||||
GST_DEBUG ("DEBUG: gmip_find_streaminfo: iterating");
|
||||
while ((priv->streaminfo == NULL) &&
|
||||
gst_bin_iterate (GST_BIN (priv->pipeline)))
|
||||
while ((priv->streaminfo == NULL)
|
||||
// && gst_bin_iterate (GST_BIN (priv->pipeline))
|
||||
)
|
||||
GMI_DEBUG ("+");
|
||||
GMI_DEBUG ("\n");
|
||||
gmip_find_track_streaminfo_post (priv);
|
||||
|
@ -766,7 +771,9 @@ gmip_find_track_format (GstMediaInfoPriv * priv)
|
|||
{
|
||||
gmip_find_track_format_pre (priv);
|
||||
GST_DEBUG ("DEBUG: gmip_find_format: iterating");
|
||||
while ((priv->format == NULL) && gst_bin_iterate (GST_BIN (priv->pipeline)))
|
||||
while ((priv->format == NULL)
|
||||
//&& gst_bin_iterate (GST_BIN (priv->pipeline))
|
||||
)
|
||||
GMI_DEBUG ("+");
|
||||
GMI_DEBUG ("\n");
|
||||
gmip_find_track_format_post (priv);
|
||||
|
|
|
@ -266,7 +266,8 @@ gst_media_info_read_idler (GstMediaInfo * info, GstMediaInfoStream ** streamp,
|
|||
gchar *mime;
|
||||
|
||||
GST_LOG ("STATE_TYPEFIND");
|
||||
if ((priv->type == NULL) && gst_bin_iterate (GST_BIN (priv->pipeline))) {
|
||||
//if ((priv->type == NULL) && gst_bin_iterate (GST_BIN (priv->pipeline))) {
|
||||
if ((priv->type == NULL)) {
|
||||
GST_DEBUG ("iterating while in STATE_TYPEFIND");
|
||||
GMI_DEBUG ("?");
|
||||
return TRUE;
|
||||
|
@ -298,7 +299,8 @@ gst_media_info_read_idler (GstMediaInfo * info, GstMediaInfoStream ** streamp,
|
|||
case GST_MEDIA_INFO_STATE_STREAM:
|
||||
{
|
||||
GST_LOG ("STATE_STREAM");
|
||||
if ((priv->format == NULL) && gst_bin_iterate (GST_BIN (priv->pipeline))) {
|
||||
//if ((priv->format == NULL) && gst_bin_iterate (GST_BIN (priv->pipeline))) {
|
||||
if ((priv->format == NULL)) {
|
||||
GMI_DEBUG ("?");
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -317,7 +319,7 @@ gst_media_info_read_idler (GstMediaInfo * info, GstMediaInfoStream ** streamp,
|
|||
case GST_MEDIA_INFO_STATE_METADATA:
|
||||
{
|
||||
if ((priv->metadata == NULL) &&
|
||||
gst_bin_iterate (GST_BIN (priv->pipeline)) &&
|
||||
//gst_bin_iterate (GST_BIN (priv->pipeline)) &&
|
||||
priv->metadata_iters < MAX_METADATA_ITERS) {
|
||||
GMI_DEBUG ("?");
|
||||
priv->metadata_iters++;
|
||||
|
@ -338,8 +340,9 @@ gst_media_info_read_idler (GstMediaInfo * info, GstMediaInfoStream ** streamp,
|
|||
}
|
||||
case GST_MEDIA_INFO_STATE_STREAMINFO:
|
||||
{
|
||||
if ((priv->streaminfo == NULL) &&
|
||||
gst_bin_iterate (GST_BIN (priv->pipeline))) {
|
||||
if ((priv->streaminfo == NULL)
|
||||
//&& gst_bin_iterate (GST_BIN (priv->pipeline))
|
||||
) {
|
||||
GMI_DEBUG ("?");
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -355,7 +358,9 @@ gst_media_info_read_idler (GstMediaInfo * info, GstMediaInfoStream ** streamp,
|
|||
}
|
||||
case GST_MEDIA_INFO_STATE_FORMAT:
|
||||
{
|
||||
if ((priv->format == NULL) && gst_bin_iterate (GST_BIN (priv->pipeline))) {
|
||||
if ((priv->format == NULL)
|
||||
// && gst_bin_iterate (GST_BIN (priv->pipeline))
|
||||
) {
|
||||
GMI_DEBUG ("?");
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
@ -572,7 +572,8 @@ gst_play_get_sink_element (GstPlay * play,
|
|||
return element;
|
||||
}
|
||||
|
||||
elements = (GList *) gst_bin_get_list (GST_BIN (element));
|
||||
/* FIXME, not MT safe */
|
||||
elements = (GList *) GST_BIN (element)->children;
|
||||
|
||||
/* traverse all elements looking for one without src pad */
|
||||
|
||||
|
@ -588,7 +589,8 @@ gst_play_get_sink_element (GstPlay * play,
|
|||
if (GST_IS_ELEMENT (element))
|
||||
return element;
|
||||
} else {
|
||||
pads = gst_element_get_pad_list (element);
|
||||
/* FIXME, not MT safe */
|
||||
pads = element->pads;
|
||||
has_src = FALSE;
|
||||
has_correct_type = FALSE;
|
||||
while (pads) {
|
||||
|
@ -631,7 +633,7 @@ gst_play_get_sink_element (GstPlay * play,
|
|||
}
|
||||
}
|
||||
|
||||
gst_caps_free (caps);
|
||||
gst_caps_unref (caps);
|
||||
|
||||
switch (sink_type) {
|
||||
case GST_PLAY_SINK_TYPE_AUDIO:
|
||||
|
@ -678,6 +680,8 @@ gst_play_get_sink_element (GstPlay * play,
|
|||
* Returns all elements that are used by @play implementing the given interface.
|
||||
*
|
||||
* Returns: a #GList of #GstElement implementing the interface.
|
||||
*
|
||||
* Not MT safe.
|
||||
*/
|
||||
|
||||
GList *
|
||||
|
@ -685,16 +689,24 @@ gst_play_get_all_by_interface (GstPlay * play, GType interface_type)
|
|||
{
|
||||
GstElement *videosink = NULL, *audiosink = NULL;
|
||||
GList *res = NULL;
|
||||
GstIterator *it = NULL;
|
||||
|
||||
g_object_get (G_OBJECT (play->priv->playbin),
|
||||
"video-sink", &videosink, "audio-sink", &audiosink, NULL);
|
||||
|
||||
/* ehw... */
|
||||
if (videosink && GST_IS_BIN (videosink)) {
|
||||
res = gst_bin_get_all_by_interface (GST_BIN (videosink), interface_type);
|
||||
it = gst_bin_iterate_all_by_interface (GST_BIN (videosink), interface_type);
|
||||
}
|
||||
if (!res && audiosink && GST_IS_BIN (audiosink)) {
|
||||
res = gst_bin_get_all_by_interface (GST_BIN (audiosink), interface_type);
|
||||
it = gst_bin_iterate_all_by_interface (GST_BIN (audiosink), interface_type);
|
||||
}
|
||||
if (it != NULL) {
|
||||
gpointer data;
|
||||
|
||||
while (gst_iterator_next (it, &data) == GST_ITERATOR_OK) {
|
||||
res = g_list_prepend (res, data);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -24,90 +24,58 @@
|
|||
|
||||
#include <glib.h>
|
||||
#include <gst/gst.h>
|
||||
#include <gst/bytestream/bytestream.h>
|
||||
|
||||
#include "riff-ids.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_RIFF_READ \
|
||||
(gst_riff_read_get_type ())
|
||||
#define GST_RIFF_READ(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RIFF_READ, GstRiffRead))
|
||||
#define GST_RIFF_READ_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RIFF_READ, GstRiffReadClass))
|
||||
#define GST_IS_RIFF_READ(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RIFF_READ))
|
||||
#define GST_IS_RIFF_READ_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RIFF_READ))
|
||||
#define GST_RIFF_READ_GET_CLASS(obj) \
|
||||
(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RIFF_READ, GstRiffReadClass))
|
||||
|
||||
typedef struct _GstRiffLevel {
|
||||
guint64 start,
|
||||
length;
|
||||
} GstRiffLevel;
|
||||
|
||||
typedef struct _GstRiffRead {
|
||||
GstElement parent;
|
||||
|
||||
GstPad *sinkpad;
|
||||
GstByteStream *bs;
|
||||
|
||||
GList *level;
|
||||
} GstRiffRead;
|
||||
|
||||
typedef struct _GstRiffReadClass {
|
||||
GstElementClass parent;
|
||||
} GstRiffReadClass;
|
||||
|
||||
GType gst_riff_read_get_type (void);
|
||||
|
||||
guint32 gst_riff_peek_tag (GstRiffRead *riff,
|
||||
guint *level_up);
|
||||
guint32 gst_riff_peek_list (GstRiffRead *riff);
|
||||
gboolean gst_riff_peek_head (GstRiffRead *riff,
|
||||
guint32 *tag,
|
||||
guint32 *length,
|
||||
guint *level_up);
|
||||
|
||||
GstEvent *gst_riff_read_seek (GstRiffRead *riff,
|
||||
guint64 offset);
|
||||
gboolean gst_riff_read_skip (GstRiffRead *riff);
|
||||
gboolean gst_riff_read_data (GstRiffRead *riff,
|
||||
guint32 *tag,
|
||||
GstBuffer **buf);
|
||||
gboolean gst_riff_read_ascii (GstRiffRead *riff,
|
||||
guint32 *tag,
|
||||
gchar **str);
|
||||
gboolean gst_riff_read_list (GstRiffRead *riff,
|
||||
guint32 *tag);
|
||||
gboolean gst_riff_read_header (GstRiffRead *read,
|
||||
guint32 *doctype);
|
||||
GstBuffer *gst_riff_read_element_data (GstRiffRead *riff,
|
||||
guint length,
|
||||
guint *got_bytes);
|
||||
GstBuffer *gst_riff_peek_element_data (GstRiffRead *riff,
|
||||
guint length,
|
||||
guint *got_bytes);
|
||||
/*
|
||||
* Utility functions (including byteswapping).
|
||||
* Operate using pull_range().
|
||||
*/
|
||||
gboolean gst_riff_read_strh (GstRiffRead *riff,
|
||||
gst_riff_strh **header);
|
||||
gboolean gst_riff_read_strf_vids (GstRiffRead *riff,
|
||||
gst_riff_strf_vids **header);
|
||||
gboolean gst_riff_read_strf_vids_with_data
|
||||
(GstRiffRead *riff,
|
||||
gst_riff_strf_vids **header,
|
||||
GstBuffer **extradata);
|
||||
gboolean gst_riff_read_strf_auds (GstRiffRead *riff,
|
||||
gst_riff_strf_auds **header);
|
||||
gboolean gst_riff_read_strf_auds_with_data
|
||||
(GstRiffRead *riff,
|
||||
gst_riff_strf_auds **header,
|
||||
GstBuffer **extradata);
|
||||
gboolean gst_riff_read_strf_iavs (GstRiffRead *riff,
|
||||
gst_riff_strf_iavs **header);
|
||||
gboolean gst_riff_read_info (GstRiffRead *riff);
|
||||
|
||||
GstFlowReturn gst_riff_read_chunk (GstElement * element,
|
||||
GstPad * pad,
|
||||
guint64 * offset,
|
||||
guint32 * fourcc,
|
||||
GstBuffer ** chunk_data);
|
||||
|
||||
/*
|
||||
* These functions operate on provided data (the caller is
|
||||
* supposed to strip the chunk headers). The buffer is
|
||||
* provided by the caller, the strf/strh/data are filled in
|
||||
* by the function.
|
||||
*/
|
||||
|
||||
gboolean gst_riff_parse_chunk (GstElement * element,
|
||||
GstBuffer * buf,
|
||||
guint * offset,
|
||||
guint32 * fourcc,
|
||||
GstBuffer ** chunk_data);
|
||||
|
||||
gboolean gst_riff_parse_file_header (GstElement * element,
|
||||
GstBuffer * buf,
|
||||
guint32 * doctype);
|
||||
|
||||
gboolean gst_riff_parse_strh (GstElement * element,
|
||||
GstBuffer * buf,
|
||||
gst_riff_strh ** strh);
|
||||
|
||||
gboolean gst_riff_parse_strf_vids (GstElement * element,
|
||||
GstBuffer * buf,
|
||||
gst_riff_strf_vids ** strf,
|
||||
GstBuffer ** data);
|
||||
gboolean gst_riff_parse_strf_auds (GstElement * element,
|
||||
GstBuffer * buf,
|
||||
gst_riff_strf_auds ** strf,
|
||||
GstBuffer ** data);
|
||||
gboolean gst_riff_parse_strf_iavs (GstElement * element,
|
||||
GstBuffer * buf,
|
||||
gst_riff_strf_iavs ** strf,
|
||||
GstBuffer ** data);
|
||||
|
||||
void gst_riff_parse_info (GstElement * element,
|
||||
GstBuffer * buf,
|
||||
GstTagList ** taglist);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
|
|
@ -25,10 +25,14 @@
|
|||
|
||||
#include <gst/gst.h>
|
||||
|
||||
GST_DEBUG_CATEGORY (riff_debug);
|
||||
|
||||
static gboolean
|
||||
plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
return gst_library_load ("gstbytestream");
|
||||
GST_DEBUG_CATEGORY_INIT (riff_debug, "riff", 0, "RIFF I/O");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
||||
|
|
|
@ -9,4 +9,4 @@ libgstvideoinclude_HEADERS = video.h videosink.h
|
|||
|
||||
libgstvideo_la_LIBADD =
|
||||
libgstvideo_la_CFLAGS = $(GST_CFLAGS)
|
||||
libgstvideo_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
libgstvideo_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) ../../../../gstreamer-NEWHEAD/gst/base/libgstbase.la
|
||||
|
|
|
@ -27,17 +27,6 @@
|
|||
|
||||
static GstElementClass *parent_class = NULL;
|
||||
|
||||
/* Private methods */
|
||||
|
||||
static void
|
||||
gst_videosink_set_clock (GstElement * element, GstClock * clock)
|
||||
{
|
||||
GstVideoSink *videosink;
|
||||
|
||||
videosink = GST_VIDEOSINK (element);
|
||||
|
||||
videosink->clock = clock;
|
||||
}
|
||||
|
||||
/* Initing stuff */
|
||||
|
||||
|
@ -46,7 +35,6 @@ gst_videosink_init (GstVideoSink * videosink)
|
|||
{
|
||||
videosink->width = 0;
|
||||
videosink->height = 0;
|
||||
videosink->clock = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -59,8 +47,6 @@ gst_videosink_class_init (GstVideoSinkClass * klass)
|
|||
gstelement_class = (GstElementClass *) klass;
|
||||
|
||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
||||
|
||||
gstelement_class->set_clock = gst_videosink_set_clock;
|
||||
}
|
||||
|
||||
/* Public methods */
|
||||
|
@ -83,7 +69,7 @@ gst_videosink_get_type (void)
|
|||
(GInstanceInitFunc) gst_videosink_init,
|
||||
};
|
||||
|
||||
videosink_type = g_type_register_static (GST_TYPE_ELEMENT,
|
||||
videosink_type = g_type_register_static (GST_TYPE_BASESINK,
|
||||
"GstVideoSink", &videosink_info, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#define __GST_VIDEOSINK_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstbasesink.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
@ -38,28 +39,24 @@ G_BEGIN_DECLS
|
|||
#define GST_VIDEOSINK_GET_CLASS(obj) \
|
||||
(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VIDEOSINK, GstVideoSinkClass))
|
||||
|
||||
#define GST_VIDEOSINK_PAD(obj) (GST_VIDEOSINK (obj)->sinkpad)
|
||||
#define GST_VIDEOSINK_PAD GST_BASESINK_PAD
|
||||
#define GST_VIDEOSINK_CLOCK GST_BASESINK_CLOCK
|
||||
#define GST_VIDEOSINK_WIDTH(obj) (GST_VIDEOSINK (obj)->width)
|
||||
#define GST_VIDEOSINK_HEIGHT(obj) (GST_VIDEOSINK (obj)->height)
|
||||
#define GST_VIDEOSINK_CLOCK(obj) (GST_VIDEOSINK (obj)->clock)
|
||||
|
||||
typedef struct _GstVideoSink GstVideoSink;
|
||||
typedef struct _GstVideoSinkClass GstVideoSinkClass;
|
||||
|
||||
struct _GstVideoSink {
|
||||
GstElement element;
|
||||
|
||||
GstPad *sinkpad;
|
||||
GstBaseSink element;
|
||||
|
||||
gint width, height;
|
||||
|
||||
GstClock *clock;
|
||||
|
||||
gpointer _gst_reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
struct _GstVideoSinkClass {
|
||||
GstElementClass parent_class;
|
||||
GstBaseSinkClass parent_class;
|
||||
|
||||
gpointer _gst_reserved[GST_PADDING];
|
||||
};
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#define __GST_VIDEOSINK_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstbasesink.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
@ -38,28 +39,24 @@ G_BEGIN_DECLS
|
|||
#define GST_VIDEOSINK_GET_CLASS(obj) \
|
||||
(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VIDEOSINK, GstVideoSinkClass))
|
||||
|
||||
#define GST_VIDEOSINK_PAD(obj) (GST_VIDEOSINK (obj)->sinkpad)
|
||||
#define GST_VIDEOSINK_PAD GST_BASESINK_PAD
|
||||
#define GST_VIDEOSINK_CLOCK GST_BASESINK_CLOCK
|
||||
#define GST_VIDEOSINK_WIDTH(obj) (GST_VIDEOSINK (obj)->width)
|
||||
#define GST_VIDEOSINK_HEIGHT(obj) (GST_VIDEOSINK (obj)->height)
|
||||
#define GST_VIDEOSINK_CLOCK(obj) (GST_VIDEOSINK (obj)->clock)
|
||||
|
||||
typedef struct _GstVideoSink GstVideoSink;
|
||||
typedef struct _GstVideoSinkClass GstVideoSinkClass;
|
||||
|
||||
struct _GstVideoSink {
|
||||
GstElement element;
|
||||
|
||||
GstPad *sinkpad;
|
||||
GstBaseSink element;
|
||||
|
||||
gint width, height;
|
||||
|
||||
GstClock *clock;
|
||||
|
||||
gpointer _gst_reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
struct _GstVideoSinkClass {
|
||||
GstElementClass parent_class;
|
||||
GstBaseSinkClass parent_class;
|
||||
|
||||
gpointer _gst_reserved[GST_PADDING];
|
||||
};
|
||||
|
|
|
@ -91,12 +91,11 @@ static GstElementStateReturn buffer_frames_convert_change_state (GstElement *
|
|||
element);
|
||||
|
||||
static GstCaps *buffer_frames_convert_getcaps (GstPad * pad);
|
||||
static GstPadLinkReturn buffer_frames_convert_link (GstPad * pad,
|
||||
const GstCaps * caps);
|
||||
static GstCaps *buffer_frames_convert_fixate (GstPad * pad,
|
||||
const GstCaps * caps);
|
||||
static gboolean buffer_frames_convert_setcaps (GstPad * pad, GstCaps * caps);
|
||||
static GstCaps *buffer_frames_convert_fixate (GstPad * pad, GstCaps * caps);
|
||||
|
||||
static void buffer_frames_convert_chain (GstPad * sinkpad, GstData * _data);
|
||||
static GstFlowReturn buffer_frames_convert_chain (GstPad * sinkpad,
|
||||
GstBuffer * buffer);
|
||||
|
||||
static GstElementClass *parent_class = NULL;
|
||||
|
||||
|
@ -153,17 +152,17 @@ buffer_frames_convert_init (BufferFramesConvert * this)
|
|||
this->sinkpad = gst_pad_new_from_template
|
||||
(gst_static_pad_template_get (&sink_static_template), "sink");
|
||||
gst_element_add_pad (GST_ELEMENT (this), this->sinkpad);
|
||||
gst_pad_set_link_function (this->sinkpad, buffer_frames_convert_link);
|
||||
gst_pad_set_setcaps_function (this->sinkpad, buffer_frames_convert_setcaps);
|
||||
gst_pad_set_getcaps_function (this->sinkpad, buffer_frames_convert_getcaps);
|
||||
gst_pad_set_chain_function (this->sinkpad, buffer_frames_convert_chain);
|
||||
gst_pad_set_fixate_function (this->sinkpad, buffer_frames_convert_fixate);
|
||||
gst_pad_set_fixatecaps_function (this->sinkpad, buffer_frames_convert_fixate);
|
||||
|
||||
this->srcpad = gst_pad_new_from_template
|
||||
(gst_static_pad_template_get (&src_static_template), "src");
|
||||
gst_element_add_pad (GST_ELEMENT (this), this->srcpad);
|
||||
gst_pad_set_link_function (this->srcpad, buffer_frames_convert_link);
|
||||
gst_pad_set_setcaps_function (this->srcpad, buffer_frames_convert_setcaps);
|
||||
gst_pad_set_getcaps_function (this->srcpad, buffer_frames_convert_getcaps);
|
||||
gst_pad_set_fixate_function (this->sinkpad, buffer_frames_convert_fixate);
|
||||
gst_pad_set_fixatecaps_function (this->sinkpad, buffer_frames_convert_fixate);
|
||||
|
||||
this->in_buffer_samples = -1;
|
||||
this->out_buffer_samples = -1;
|
||||
|
@ -221,7 +220,7 @@ buffer_frames_convert_getcaps (GstPad * pad)
|
|||
}
|
||||
|
||||
static GstCaps *
|
||||
buffer_frames_convert_fixate (GstPad * pad, const GstCaps * caps)
|
||||
buffer_frames_convert_fixate (GstPad * pad, GstCaps * caps)
|
||||
{
|
||||
GstCaps *newcaps;
|
||||
GstStructure *structure;
|
||||
|
@ -235,14 +234,15 @@ buffer_frames_convert_fixate (GstPad * pad, const GstCaps * caps)
|
|||
return newcaps;
|
||||
}
|
||||
|
||||
gst_caps_free (newcaps);
|
||||
gst_caps_unref (newcaps);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GstPadLinkReturn
|
||||
buffer_frames_convert_link (GstPad * pad, const GstCaps * caps)
|
||||
static gboolean
|
||||
buffer_frames_convert_setcaps (GstPad * pad, GstCaps * caps)
|
||||
{
|
||||
#if 0
|
||||
BufferFramesConvert *this;
|
||||
GstCaps *othercaps;
|
||||
GstPad *otherpad;
|
||||
|
@ -255,7 +255,7 @@ buffer_frames_convert_link (GstPad * pad, const GstCaps * caps)
|
|||
otherpad = pad == this->srcpad ? this->sinkpad : this->srcpad;
|
||||
|
||||
/* first try to act as a passthrough */
|
||||
ret = gst_pad_try_set_caps (otherpad, caps);
|
||||
ret = gst_pad_set_caps (otherpad, caps);
|
||||
if (GST_PAD_LINK_SUCCESSFUL (ret)) {
|
||||
this->passthrough = TRUE;
|
||||
return ret;
|
||||
|
@ -266,10 +266,8 @@ buffer_frames_convert_link (GstPad * pad, const GstCaps * caps)
|
|||
gst_caps_set_simple (othercaps, "buffer-frames", GST_TYPE_INT_RANGE, 0,
|
||||
G_MAXINT, NULL);
|
||||
ret = gst_pad_try_set_caps_nonfixed (otherpad, othercaps);
|
||||
gst_caps_free (othercaps);
|
||||
if (GST_PAD_LINK_FAILED (ret))
|
||||
return ret;
|
||||
othercaps = gst_caps_copy (gst_pad_get_negotiated_caps (otherpad));
|
||||
|
||||
/* it's ok, let's record our data */
|
||||
sinkstructure =
|
||||
|
@ -284,16 +282,16 @@ buffer_frames_convert_link (GstPad * pad, const GstCaps * caps)
|
|||
gst_structure_get_int (sinkstructure, "channels", &numchannels);
|
||||
this->in_buffer_samples *= numchannels;
|
||||
this->out_buffer_samples *= numchannels;
|
||||
gst_caps_free (othercaps);
|
||||
|
||||
if (this->out_buffer_samples == 0)
|
||||
this->passthrough = TRUE;
|
||||
#endif
|
||||
|
||||
return GST_PAD_LINK_OK;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
buffer_frames_convert_chain (GstPad * pad, GstData * _data)
|
||||
static GstFlowReturn
|
||||
buffer_frames_convert_chain (GstPad * pad, GstBuffer * buf)
|
||||
{
|
||||
BufferFramesConvert *this;
|
||||
GstBuffer *buf_in, *buf_out;
|
||||
|
@ -305,11 +303,10 @@ buffer_frames_convert_chain (GstPad * pad, GstData * _data)
|
|||
this = (BufferFramesConvert *) GST_OBJECT_PARENT (pad);
|
||||
|
||||
if (this->passthrough) {
|
||||
gst_pad_push (this->srcpad, _data);
|
||||
return;
|
||||
return gst_pad_push (this->srcpad, buf);
|
||||
}
|
||||
|
||||
buf_in = (GstBuffer *) _data;
|
||||
buf_in = buf;
|
||||
data_in = (gfloat *) GST_BUFFER_DATA (buf_in);
|
||||
samples_in = samples_in_remaining =
|
||||
GST_BUFFER_SIZE (buf_in) / sizeof (gfloat);
|
||||
|
@ -331,12 +328,12 @@ buffer_frames_convert_chain (GstPad * pad, GstData * _data)
|
|||
if (!samples_out_remaining) {
|
||||
this->buf_out = NULL;
|
||||
this->samples_out_remaining = 0;
|
||||
gst_pad_push (this->srcpad, (GstData *) buf_out);
|
||||
gst_pad_push (this->srcpad, buf_out);
|
||||
} else {
|
||||
/* we used up the incoming samples, but didn't fill our buffer */
|
||||
this->samples_out_remaining = samples_out_remaining;
|
||||
gst_buffer_unref (buf_in);
|
||||
return;
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -347,7 +344,7 @@ buffer_frames_convert_chain (GstPad * pad, GstData * _data)
|
|||
out_buffer_samples * sizeof (gfloat));
|
||||
data_in += out_buffer_samples;
|
||||
samples_in_remaining -= out_buffer_samples;
|
||||
gst_pad_push (this->srcpad, (GstData *) buf_out);
|
||||
gst_pad_push (this->srcpad, buf_out);
|
||||
}
|
||||
|
||||
/* if there's an event coming next, just push what we have */
|
||||
|
@ -357,13 +354,13 @@ buffer_frames_convert_chain (GstPad * pad, GstData * _data)
|
|||
gst_buffer_create_sub (buf_in,
|
||||
(samples_in - samples_in_remaining) * sizeof (gfloat),
|
||||
samples_in_remaining * sizeof (gfloat));
|
||||
gst_pad_push (this->srcpad, (GstData *) buf_out);
|
||||
gst_pad_push (this->srcpad, buf_out);
|
||||
} else {
|
||||
/* otherwise make a leftover buffer if it's necessary */
|
||||
if (samples_in_remaining) {
|
||||
buf_out =
|
||||
gst_pad_alloc_buffer (this->srcpad, 0,
|
||||
out_buffer_samples * sizeof (gfloat));
|
||||
out_buffer_samples * sizeof (gfloat), GST_PAD_CAPS (this->srcpad));
|
||||
data_out = (gfloat *) GST_BUFFER_DATA (buf_out);
|
||||
this->buf_out = buf_out;
|
||||
this->samples_out_remaining = out_buffer_samples - samples_in_remaining;
|
||||
|
@ -373,4 +370,6 @@ buffer_frames_convert_chain (GstPad * pad, GstData * _data)
|
|||
}
|
||||
|
||||
gst_buffer_unref (buf_in);
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
|
|
@ -65,12 +65,12 @@ main (gint argc, gchar ** argv)
|
|||
g_assert (caps);
|
||||
if (!gst_element_link_filtered (src, GST_ELEMENT (c), caps))
|
||||
g_assert_not_reached ();
|
||||
gst_caps_free (caps);
|
||||
gst_caps_unref (caps);
|
||||
caps = gst_caps_from_string (tests[i].srccaps);
|
||||
g_assert (caps);
|
||||
if (!gst_element_link_filtered (GST_ELEMENT (c), sink, caps))
|
||||
g_assert_not_reached ();
|
||||
gst_caps_free (caps);
|
||||
gst_caps_unref (caps);
|
||||
if (!gst_element_set_state (bin, GST_STATE_PLAYING))
|
||||
g_assert_not_reached ();
|
||||
g_assert (c->srccaps.channels <= 6);
|
||||
|
|
|
@ -60,10 +60,9 @@ static void gst_audio_convert_init (GstAudioConvert * audio_convert);
|
|||
static void gst_audio_convert_dispose (GObject * obj);
|
||||
|
||||
/* gstreamer functions */
|
||||
static void gst_audio_convert_chain (GstPad * pad, GstData * _data);
|
||||
static GstPadLinkReturn gst_audio_convert_link (GstPad * pad,
|
||||
const GstCaps * caps);
|
||||
static GstCaps *gst_audio_convert_fixate (GstPad * pad, const GstCaps * caps);
|
||||
static GstFlowReturn gst_audio_convert_chain (GstPad * pad, GstBuffer * buffer);
|
||||
static gboolean gst_audio_convert_setcaps (GstPad * pad, GstCaps * caps);
|
||||
static GstCaps *gst_audio_convert_fixate (GstPad * pad, GstCaps * caps);
|
||||
static GstCaps *gst_audio_convert_getcaps (GstPad * pad);
|
||||
static GstElementStateReturn gst_audio_convert_change_state (GstElement *
|
||||
element);
|
||||
|
@ -187,8 +186,8 @@ gst_audio_convert_init (GstAudioConvert * this)
|
|||
gst_pad_new_from_template (gst_static_pad_template_get
|
||||
(&gst_audio_convert_sink_template), "sink");
|
||||
gst_pad_set_getcaps_function (this->sink, gst_audio_convert_getcaps);
|
||||
gst_pad_set_link_function (this->sink, gst_audio_convert_link);
|
||||
gst_pad_set_fixate_function (this->sink, gst_audio_convert_fixate);
|
||||
gst_pad_set_setcaps_function (this->sink, gst_audio_convert_setcaps);
|
||||
gst_pad_set_fixatecaps_function (this->sink, gst_audio_convert_fixate);
|
||||
gst_element_add_pad (GST_ELEMENT (this), this->sink);
|
||||
|
||||
/* srcpad */
|
||||
|
@ -196,8 +195,8 @@ gst_audio_convert_init (GstAudioConvert * this)
|
|||
gst_pad_new_from_template (gst_static_pad_template_get
|
||||
(&gst_audio_convert_src_template), "src");
|
||||
gst_pad_set_getcaps_function (this->src, gst_audio_convert_getcaps);
|
||||
gst_pad_set_link_function (this->src, gst_audio_convert_link);
|
||||
gst_pad_set_fixate_function (this->src, gst_audio_convert_fixate);
|
||||
gst_pad_set_setcaps_function (this->src, gst_audio_convert_setcaps);
|
||||
gst_pad_set_fixatecaps_function (this->src, gst_audio_convert_fixate);
|
||||
gst_element_add_pad (GST_ELEMENT (this), this->src);
|
||||
|
||||
gst_pad_set_chain_function (this->sink, gst_audio_convert_chain);
|
||||
|
@ -228,34 +227,28 @@ gst_audio_convert_dispose (GObject * obj)
|
|||
|
||||
/*** GSTREAMER FUNCTIONS ******************************************************/
|
||||
|
||||
static void
|
||||
gst_audio_convert_chain (GstPad * pad, GstData * data)
|
||||
static GstFlowReturn
|
||||
gst_audio_convert_chain (GstPad * pad, GstBuffer * buf)
|
||||
{
|
||||
GstBuffer *buf = GST_BUFFER (data);
|
||||
GstAudioConvert *this;
|
||||
|
||||
g_return_if_fail (GST_IS_PAD (pad));
|
||||
g_return_if_fail (buf != NULL);
|
||||
g_return_if_fail (GST_IS_AUDIO_CONVERT (GST_OBJECT_PARENT (pad)));
|
||||
this = GST_AUDIO_CONVERT (GST_OBJECT_PARENT (pad));
|
||||
|
||||
/* FIXME */
|
||||
if (GST_IS_EVENT (buf)) {
|
||||
gst_pad_event_default (pad, GST_EVENT (buf));
|
||||
return;
|
||||
}
|
||||
g_return_if_fail (GST_IS_BUFFER (buf));
|
||||
|
||||
if (!gst_pad_is_negotiated (this->sink)) {
|
||||
#if 0
|
||||
if (!GST_PAD_CAPS (this->sink)) {
|
||||
GST_ELEMENT_ERROR (this, CORE, NEGOTIATION, (NULL),
|
||||
("Sink pad (connected to %s:%s) not negotiated before chain function",
|
||||
GST_DEBUG_PAD_NAME (gst_pad_get_peer (this->sink))));
|
||||
return;
|
||||
gst_buffer_unref (buf);
|
||||
return GST_FLOW_NOT_NEGOTIATED;
|
||||
}
|
||||
if (!gst_pad_is_negotiated (this->src)) {
|
||||
gst_data_unref (data);
|
||||
return;
|
||||
if (!GST_PAD_CAPS (this->src)) {
|
||||
gst_buffer_unref (buf);
|
||||
return GST_FLOW_NOT_NEGOTIATED;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Theory of operation:
|
||||
|
@ -271,35 +264,25 @@ gst_audio_convert_chain (GstPad * pad, GstData * data)
|
|||
|
||||
buf = gst_audio_convert_buffer_from_default_format (this, buf);
|
||||
|
||||
gst_pad_push (this->src, GST_DATA (buf));
|
||||
return gst_pad_push (this->src, buf);
|
||||
}
|
||||
|
||||
/* this function is complicated now, but it will be unnecessary when we convert
|
||||
* rate. */
|
||||
static GstCaps *
|
||||
gst_audio_convert_getcaps (GstPad * pad)
|
||||
gst_audio_convert_caps_remove_format_info (GstPad * pad, GstCaps * caps)
|
||||
{
|
||||
GstAudioConvert *this;
|
||||
GstPad *otherpad;
|
||||
GstStructure *structure;
|
||||
GstCaps *othercaps, *caps;
|
||||
const GstCaps *templcaps;
|
||||
int i, size;
|
||||
GstAudioConvert *this;
|
||||
|
||||
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
|
||||
g_return_val_if_fail (GST_IS_AUDIO_CONVERT (GST_OBJECT_PARENT (pad)), NULL);
|
||||
this = GST_AUDIO_CONVERT (GST_OBJECT_PARENT (pad));
|
||||
|
||||
otherpad = (pad == this->src) ? this->sink : this->src;
|
||||
size = gst_caps_get_size (caps);
|
||||
|
||||
/* all we want to find out is the rate */
|
||||
templcaps = gst_pad_get_pad_template_caps (pad);
|
||||
othercaps = gst_pad_get_allowed_caps (otherpad);
|
||||
|
||||
size = gst_caps_get_size (othercaps);
|
||||
caps = gst_caps_make_writable (caps);
|
||||
|
||||
for (i = size - 1; i >= 0; i--) {
|
||||
structure = gst_caps_get_structure (othercaps, i);
|
||||
GstStructure *structure;
|
||||
|
||||
structure = gst_caps_get_structure (caps, i);
|
||||
gst_structure_remove_field (structure, "channels");
|
||||
gst_structure_remove_field (structure, "channel-positions");
|
||||
gst_structure_remove_field (structure, "endianness");
|
||||
|
@ -319,10 +302,34 @@ gst_audio_convert_getcaps (GstPad * pad)
|
|||
gst_structure_set_name (structure, "audio/x-raw-int");
|
||||
gst_structure_remove_field (structure, "buffer-frames");
|
||||
}
|
||||
gst_caps_append_structure (othercaps, structure);
|
||||
gst_caps_append_structure (caps, structure);
|
||||
}
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
/* this function is complicated now, but it will be unnecessary when we convert
|
||||
* rate. */
|
||||
static GstCaps *
|
||||
gst_audio_convert_getcaps (GstPad * pad)
|
||||
{
|
||||
GstAudioConvert *this;
|
||||
GstPad *otherpad;
|
||||
GstCaps *othercaps, *caps;
|
||||
const GstCaps *templcaps;
|
||||
|
||||
this = GST_AUDIO_CONVERT (GST_OBJECT_PARENT (pad));
|
||||
|
||||
otherpad = (pad == this->src) ? this->sink : this->src;
|
||||
|
||||
/* we can do all our peer can */
|
||||
othercaps = gst_pad_peer_get_caps (otherpad);
|
||||
/* without the format info even */
|
||||
othercaps = gst_audio_convert_caps_remove_format_info (pad, othercaps);
|
||||
/* but filtered against our template */
|
||||
templcaps = gst_pad_get_pad_template_caps (pad);
|
||||
caps = gst_caps_intersect (othercaps, templcaps);
|
||||
gst_caps_free (othercaps);
|
||||
gst_caps_unref (othercaps);
|
||||
|
||||
/* Get the channel positions in as well. */
|
||||
gst_audio_set_caps_channel_positions_list (caps, supported_positions,
|
||||
|
@ -337,6 +344,8 @@ gst_audio_convert_parse_caps (const GstCaps * gst_caps,
|
|||
{
|
||||
GstStructure *structure = gst_caps_get_structure (gst_caps, 0);
|
||||
|
||||
GST_DEBUG ("parse caps %p and %" GST_PTR_FORMAT, gst_caps, gst_caps);
|
||||
|
||||
g_return_val_if_fail (gst_caps_is_fixed (gst_caps), FALSE);
|
||||
g_return_val_if_fail (caps != NULL, FALSE);
|
||||
|
||||
|
@ -375,76 +384,72 @@ gst_audio_convert_parse_caps (const GstCaps * gst_caps,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static GstPadLinkReturn
|
||||
gst_audio_convert_link (GstPad * pad, const GstCaps * caps)
|
||||
static gboolean
|
||||
gst_audio_convert_setcaps (GstPad * pad, GstCaps * caps)
|
||||
{
|
||||
GstAudioConvert *this;
|
||||
GstPad *otherpad;
|
||||
GstAudioConvertCaps ac_caps = { 0 }, other_ac_caps = {
|
||||
0};
|
||||
GstCaps *othercaps;
|
||||
guint i;
|
||||
GstPadLinkReturn ret;
|
||||
GstAudioConvertCaps ac_caps = { 0 };
|
||||
GstAudioConvertCaps other_ac_caps = { 0 };
|
||||
GstCaps **other_prefered, **prefered;
|
||||
|
||||
g_return_val_if_fail (GST_IS_PAD (pad), GST_PAD_LINK_REFUSED);
|
||||
g_return_val_if_fail (GST_IS_AUDIO_CONVERT (GST_OBJECT_PARENT (pad)),
|
||||
GST_PAD_LINK_REFUSED);
|
||||
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
|
||||
g_return_val_if_fail (GST_IS_AUDIO_CONVERT (GST_OBJECT_PARENT (pad)), FALSE);
|
||||
g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
|
||||
|
||||
this = GST_AUDIO_CONVERT (GST_OBJECT_PARENT (pad));
|
||||
otherpad = (pad == this->src ? this->sink : this->src);
|
||||
|
||||
/* we'll need a new matrix after every new negotiation */
|
||||
gst_audio_convert_unset_matrix (this);
|
||||
|
||||
ac_caps.pos = NULL;
|
||||
if (!gst_audio_convert_parse_caps (caps, &ac_caps))
|
||||
return GST_PAD_LINK_REFUSED;
|
||||
return FALSE;
|
||||
|
||||
/* ok, not those - try setting "any" caps */
|
||||
othercaps = gst_pad_get_allowed_caps (otherpad);
|
||||
for (i = 0; i < gst_caps_get_size (othercaps); i++) {
|
||||
GstStructure *structure = gst_caps_get_structure (othercaps, i);
|
||||
otherpad = (pad == this->src ? this->sink : this->src);
|
||||
prefered = (pad == this->src) ? &this->src_prefered : &this->sink_prefered;
|
||||
other_prefered =
|
||||
(pad == this->src) ? &this->sink_prefered : &this->src_prefered;
|
||||
|
||||
gst_structure_set (structure, "rate", G_TYPE_INT, ac_caps.rate, NULL);
|
||||
if (strcmp (gst_structure_get_name (structure), "audio/x-raw-float") == 0) {
|
||||
if (!ac_caps.is_int) {
|
||||
gst_structure_set (structure, "buffer-frames", G_TYPE_INT,
|
||||
ac_caps.buffer_frames, NULL);
|
||||
} else {
|
||||
gst_structure_set (structure, "buffer-frames", GST_TYPE_INT_RANGE, 0,
|
||||
G_MAXINT, NULL);
|
||||
*prefered = caps;
|
||||
|
||||
/* check passthrough */
|
||||
if (gst_pad_peer_accept_caps (otherpad, caps)) {
|
||||
/* great, so that will be our suggestion then */
|
||||
*other_prefered = gst_caps_ref (caps);
|
||||
} else {
|
||||
/* nope, find something we can convert to and the peer can
|
||||
* accept. */
|
||||
GstCaps *othercaps = gst_pad_peer_get_caps (otherpad);
|
||||
|
||||
if (othercaps) {
|
||||
/* peel off first one */
|
||||
GstCaps *targetcaps = gst_caps_copy_nth (othercaps, 0);
|
||||
GstStructure *structure = gst_caps_get_structure (targetcaps, 0);
|
||||
|
||||
gst_caps_unref (othercaps);
|
||||
|
||||
/* set the rate on the caps */
|
||||
gst_structure_set (structure, "rate", G_TYPE_INT, ac_caps.rate, NULL);
|
||||
gst_structure_set (structure, "channels", G_TYPE_INT, ac_caps.channels,
|
||||
NULL);
|
||||
if (strcmp (gst_structure_get_name (structure), "audio/x-raw-float") == 0) {
|
||||
if (!ac_caps.is_int) {
|
||||
gst_structure_set (structure, "buffer-frames", G_TYPE_INT,
|
||||
ac_caps.buffer_frames, NULL);
|
||||
} else {
|
||||
gst_structure_set (structure, "buffer-frames", GST_TYPE_INT_RANGE, 0,
|
||||
G_MAXINT, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* this will be our suggestion */
|
||||
*other_prefered = targetcaps;
|
||||
if (!gst_audio_convert_parse_caps (targetcaps, &other_ac_caps))
|
||||
return FALSE;
|
||||
GST_RPAD_CAPS (otherpad) = targetcaps;
|
||||
}
|
||||
}
|
||||
if (this->sink == pad) {
|
||||
g_free (this->sinkcaps.pos);
|
||||
this->sinkcaps = ac_caps;
|
||||
} else {
|
||||
g_free (this->srccaps.pos);
|
||||
this->srccaps = ac_caps;
|
||||
}
|
||||
GST_LOG_OBJECT (this, "trying to set caps to %" GST_PTR_FORMAT, othercaps);
|
||||
|
||||
ret = gst_pad_try_set_caps_nonfixed (otherpad, othercaps);
|
||||
gst_caps_free (othercaps);
|
||||
if (ret < GST_PAD_LINK_OK)
|
||||
return ret;
|
||||
|
||||
/* woohoo, got it */
|
||||
othercaps = (GstCaps *) gst_pad_get_negotiated_caps (otherpad);
|
||||
if (othercaps) {
|
||||
other_ac_caps.pos = NULL;
|
||||
|
||||
if (!gst_audio_convert_parse_caps (othercaps, &other_ac_caps)) {
|
||||
g_critical ("internal negotiation error");
|
||||
return GST_PAD_LINK_REFUSED;
|
||||
}
|
||||
} else {
|
||||
other_ac_caps = ac_caps;
|
||||
other_ac_caps.pos = g_memdup (ac_caps.pos,
|
||||
ac_caps.channels * sizeof (GstAudioChannelPosition));
|
||||
}
|
||||
|
||||
if (this->sink == pad) {
|
||||
g_free (this->srccaps.pos);
|
||||
this->srccaps = other_ac_caps;
|
||||
|
@ -457,7 +462,7 @@ gst_audio_convert_link (GstPad * pad, const GstCaps * caps)
|
|||
|
||||
GST_DEBUG_OBJECT (this, "negotiated pad to %" GST_PTR_FORMAT, caps);
|
||||
gst_audio_convert_setup_matrix (this);
|
||||
return GST_PAD_LINK_OK;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* tries to fixate the given field of the given caps to the given int value */
|
||||
|
@ -475,7 +480,7 @@ _fixate_caps_to_int (GstCaps ** caps, const gchar * field, gint value)
|
|||
gst_caps_append (try, gst_caps_new_simple ("audio/x-raw-float", field,
|
||||
GST_TYPE_INT_RANGE, G_MININT, value - 1, NULL));
|
||||
isect_lower = gst_caps_intersect (*caps, try);
|
||||
gst_caps_free (try);
|
||||
gst_caps_unref (try);
|
||||
|
||||
if (!gst_caps_is_empty (isect_lower)) {
|
||||
try = gst_caps_new_simple ("audio/x-raw-int", field, GST_TYPE_INT_RANGE,
|
||||
|
@ -483,18 +488,18 @@ _fixate_caps_to_int (GstCaps ** caps, const gchar * field, gint value)
|
|||
gst_caps_append (try, gst_caps_new_simple ("audio/x-raw-float", field,
|
||||
GST_TYPE_INT_RANGE, value, G_MAXINT, NULL));
|
||||
isect_higher = gst_caps_intersect (*caps, try);
|
||||
gst_caps_free (try);
|
||||
gst_caps_unref (try);
|
||||
/* FIXME: why choose to end up with the higher range, and not the fixed
|
||||
* value ? */
|
||||
if (!gst_caps_is_empty (isect_higher)) {
|
||||
gst_caps_free (*caps);
|
||||
gst_caps_unref (*caps);
|
||||
*caps = isect_higher;
|
||||
ret = TRUE;
|
||||
} else {
|
||||
gst_caps_free (isect_higher);
|
||||
gst_caps_unref (isect_higher);
|
||||
}
|
||||
}
|
||||
gst_caps_free (isect_lower);
|
||||
gst_caps_unref (isect_lower);
|
||||
|
||||
/* FIXME: why don't we already return here when ret == TRUE ? */
|
||||
for (i = 0; i < gst_caps_get_size (*caps); i++) {
|
||||
|
@ -508,27 +513,29 @@ _fixate_caps_to_int (GstCaps ** caps, const gchar * field, gint value)
|
|||
}
|
||||
|
||||
static GstCaps *
|
||||
gst_audio_convert_fixate (GstPad * pad, const GstCaps * caps)
|
||||
gst_audio_convert_fixate (GstPad * pad, GstCaps * caps)
|
||||
{
|
||||
const GValue *pos_val;
|
||||
GstAudioConvert *this =
|
||||
GST_AUDIO_CONVERT (gst_object_get_parent (GST_OBJECT (pad)));
|
||||
GstPad *otherpad = (pad == this->sink ? this->src : this->sink);
|
||||
//GstPad *otherpad = (pad == this->sink ? this->src : this->sink);
|
||||
GstAudioConvertCaps try, ac_caps =
|
||||
(pad == this->sink ? this->srccaps : this->sinkcaps);
|
||||
GstCaps *copy = gst_caps_copy (caps);
|
||||
|
||||
if (!GST_PAD_IS_NEGOTIATING (otherpad)) {
|
||||
try.channels = 2;
|
||||
try.width = 16;
|
||||
try.depth = 16;
|
||||
try.endianness = G_BYTE_ORDER;
|
||||
} else {
|
||||
try.channels = ac_caps.channels;
|
||||
try.width = ac_caps.is_int ? ac_caps.width : 16;
|
||||
try.depth = ac_caps.is_int ? ac_caps.depth : 16;
|
||||
try.endianness = ac_caps.is_int ? ac_caps.endianness : G_BYTE_ORDER;
|
||||
}
|
||||
//if (!GST_PAD_IS_NEGOTIATING (otherpad)) {
|
||||
try.channels = 2;
|
||||
try.width = 16;
|
||||
try.depth = 16;
|
||||
try.endianness = G_BYTE_ORDER;
|
||||
/*
|
||||
} else {
|
||||
try.channels = ac_caps.channels;
|
||||
try.width = ac_caps.is_int ? ac_caps.width : 16;
|
||||
try.depth = ac_caps.is_int ? ac_caps.depth : 16;
|
||||
try.endianness = ac_caps.is_int ? ac_caps.endianness : G_BYTE_ORDER;
|
||||
}
|
||||
*/
|
||||
|
||||
if (_fixate_caps_to_int (©, "channels", try.channels)) {
|
||||
int n, c;
|
||||
|
@ -591,7 +598,7 @@ gst_audio_convert_fixate (GstPad * pad, const GstCaps * caps)
|
|||
}
|
||||
}
|
||||
|
||||
gst_caps_free (copy);
|
||||
gst_caps_unref (copy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -639,7 +646,7 @@ gst_audio_convert_get_buffer (GstBuffer * buf, guint size)
|
|||
} else {
|
||||
ret = gst_buffer_new_and_alloc (size);
|
||||
g_assert (ret);
|
||||
gst_buffer_stamp (ret, buf);
|
||||
//gst_buffer_stamp (ret, buf);
|
||||
GST_LOG ("returning new buffer. data: %p - size: %u - maxsize: %u",
|
||||
ret->data, ret->size, ret->maxsize);
|
||||
return ret;
|
||||
|
@ -690,6 +697,7 @@ gst_audio_convert_buffer_to_default_format (GstAudioConvert * this,
|
|||
ret =
|
||||
gst_audio_convert_get_buffer (buf,
|
||||
buf->size * 32 / this->sinkcaps.width);
|
||||
gst_buffer_set_caps (ret, GST_RPAD_CAPS (this->src));
|
||||
|
||||
count = ret->size / 4;
|
||||
src = buf->data + (count - 1) * (this->sinkcaps.width / 8);
|
||||
|
@ -757,6 +765,7 @@ gst_audio_convert_buffer_to_default_format (GstAudioConvert * this,
|
|||
/* should just give the same buffer, unless it's not writable -- float is
|
||||
* already 32 bits */
|
||||
ret = gst_audio_convert_get_buffer (buf, buf->size);
|
||||
gst_buffer_set_caps (ret, GST_RPAD_CAPS (this->src));
|
||||
|
||||
in = (gfloat *) GST_BUFFER_DATA (buf);
|
||||
out = (gint32 *) GST_BUFFER_DATA (ret);
|
||||
|
@ -816,6 +825,7 @@ gst_audio_convert_buffer_from_default_format (GstAudioConvert * this,
|
|||
ret =
|
||||
gst_audio_convert_get_buffer (buf,
|
||||
buf->size * this->srccaps.width / 32);
|
||||
gst_buffer_set_caps (ret, GST_RPAD_CAPS (this->src));
|
||||
|
||||
dest = ret->data;
|
||||
src = (gint32 *) buf->data;
|
||||
|
@ -881,6 +891,7 @@ gst_audio_convert_buffer_from_default_format (GstAudioConvert * this,
|
|||
ret =
|
||||
gst_audio_convert_get_buffer (buf,
|
||||
buf->size * this->srccaps.width / 32);
|
||||
gst_buffer_set_caps (ret, GST_RPAD_CAPS (this->src));
|
||||
|
||||
dest = (gfloat *) ret->data;
|
||||
src = (gint32 *) buf->data;
|
||||
|
@ -902,6 +913,7 @@ gst_audio_convert_channels (GstAudioConvert * this, GstBuffer * buf)
|
|||
gint count;
|
||||
|
||||
g_assert (this->matrix != NULL);
|
||||
|
||||
/* check for passthrough */
|
||||
if (gst_audio_convert_passthrough (this))
|
||||
return buf;
|
||||
|
@ -909,6 +921,7 @@ gst_audio_convert_channels (GstAudioConvert * this, GstBuffer * buf)
|
|||
/* convert */
|
||||
count = GST_BUFFER_SIZE (buf) / 4 / this->sinkcaps.channels;
|
||||
ret = gst_audio_convert_get_buffer (buf, count * 4 * this->srccaps.channels);
|
||||
gst_buffer_set_caps (ret, GST_RPAD_CAPS (this->src));
|
||||
gst_audio_convert_mix (this, (gint32 *) GST_BUFFER_DATA (buf),
|
||||
(gint32 *) GST_BUFFER_DATA (ret), count);
|
||||
gst_buffer_unref (buf);
|
||||
|
|
|
@ -68,6 +68,9 @@ struct _GstAudioConvert
|
|||
GstAudioConvertCaps srccaps;
|
||||
GstAudioConvertCaps sinkcaps;
|
||||
|
||||
GstCaps *src_prefered;
|
||||
GstCaps *sink_prefered;
|
||||
|
||||
/* channel conversion matrix, m[in_channels][out_channels].
|
||||
* If identity matrix, passthrough applies. */
|
||||
gfloat **matrix;
|
||||
|
|
|
@ -90,7 +90,6 @@ enum SampleFormat {
|
|||
|
||||
#define DEFAULT_FRAME_RATE_BASE 1001000
|
||||
|
||||
|
||||
/* thomas: extracted from imgconvert.c since it's also used in
|
||||
* gstffmpegcodecmap.c */
|
||||
|
||||
|
|
|
@ -56,7 +56,9 @@ struct _GstFFMpegCsp
|
|||
enum PixelFormat from_pixfmt, to_pixfmt;
|
||||
AVPicture from_frame, to_frame;
|
||||
AVPaletteControl *palette;
|
||||
GstCaps *sinkcaps;
|
||||
|
||||
GstCaps *src_prefered;
|
||||
GstCaps *sink_prefered;
|
||||
};
|
||||
|
||||
struct _GstFFMpegCspClass
|
||||
|
@ -96,10 +98,7 @@ static void gst_ffmpegcsp_set_property (GObject * object,
|
|||
static void gst_ffmpegcsp_get_property (GObject * object,
|
||||
guint prop_id, GValue * value, GParamSpec * pspec);
|
||||
|
||||
static GstPadLinkReturn
|
||||
gst_ffmpegcsp_pad_link (GstPad * pad, const GstCaps * caps);
|
||||
|
||||
static void gst_ffmpegcsp_chain (GstPad * pad, GstData * data);
|
||||
static GstFlowReturn gst_ffmpegcsp_chain (GstPad * pad, GstBuffer * buffer);
|
||||
static GstElementStateReturn gst_ffmpegcsp_change_state (GstElement * element);
|
||||
|
||||
static GstPadTemplate *srctempl, *sinktempl;
|
||||
|
@ -115,6 +114,8 @@ gst_ffmpegcsp_caps_remove_format_info (GstCaps * caps)
|
|||
GstStructure *structure;
|
||||
GstCaps *rgbcaps;
|
||||
|
||||
caps = gst_caps_make_writable (caps);
|
||||
|
||||
for (i = 0; i < gst_caps_get_size (caps); i++) {
|
||||
structure = gst_caps_get_structure (caps, i);
|
||||
|
||||
|
@ -151,47 +152,28 @@ gst_ffmpegcsp_getcaps (GstPad * pad)
|
|||
GstCaps *caps;
|
||||
GstPad *otherpad;
|
||||
|
||||
space = GST_FFMPEGCSP (gst_pad_get_parent (pad));
|
||||
space = GST_FFMPEGCSP (GST_PAD_PARENT (pad));
|
||||
|
||||
otherpad = (pad == space->srcpad) ? space->sinkpad : space->srcpad;
|
||||
|
||||
othercaps = gst_pad_get_allowed_caps (otherpad);
|
||||
|
||||
/* we can do whatever the peer can */
|
||||
othercaps = gst_pad_peer_get_caps (otherpad);
|
||||
/* without the format info */
|
||||
othercaps = gst_ffmpegcsp_caps_remove_format_info (othercaps);
|
||||
|
||||
/* and filtered against our padtemplate */
|
||||
caps = gst_caps_intersect (othercaps, gst_pad_get_pad_template_caps (pad));
|
||||
gst_caps_free (othercaps);
|
||||
gst_caps_unref (othercaps);
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
static GstPadLinkReturn
|
||||
gst_ffmpegcsp_pad_link (GstPad * pad, const GstCaps * caps)
|
||||
static gboolean
|
||||
gst_ffmpegcsp_configure_context (GstPad * pad, const GstCaps * caps, gint width,
|
||||
gint height)
|
||||
{
|
||||
GstStructure *structure;
|
||||
AVCodecContext *ctx;
|
||||
GstFFMpegCsp *space;
|
||||
const GstCaps *othercaps;
|
||||
GstPad *otherpad;
|
||||
GstPadLinkReturn ret;
|
||||
int height, width;
|
||||
double framerate;
|
||||
const GValue *par = NULL;
|
||||
|
||||
space = GST_FFMPEGCSP (gst_pad_get_parent (pad));
|
||||
|
||||
GST_DEBUG_OBJECT (space, "pad_link on %s:%s with caps %" GST_PTR_FORMAT,
|
||||
GST_DEBUG_PAD_NAME (pad), caps);
|
||||
|
||||
otherpad = (pad == space->srcpad) ? space->sinkpad : space->srcpad;
|
||||
|
||||
structure = gst_caps_get_structure (caps, 0);
|
||||
gst_structure_get_int (structure, "width", &width);
|
||||
gst_structure_get_int (structure, "height", &height);
|
||||
gst_structure_get_double (structure, "framerate", &framerate);
|
||||
par = gst_structure_get_value (structure, "pixel-aspect-ratio");
|
||||
|
||||
/* FIXME attempt and/or check for passthru */
|
||||
space = GST_FFMPEGCSP (GST_PAD_PARENT (pad));
|
||||
|
||||
/* loop over all possibilities and select the first one we can convert and
|
||||
* is accepted by the peer */
|
||||
|
@ -211,47 +193,97 @@ gst_ffmpegcsp_pad_link (GstPad * pad, const GstCaps * caps)
|
|||
space->from_pixfmt = PIX_FMT_NB;
|
||||
}
|
||||
|
||||
return GST_PAD_LINK_REFUSED;
|
||||
}
|
||||
|
||||
/* set the size on the otherpad */
|
||||
othercaps = gst_pad_get_negotiated_caps (otherpad);
|
||||
if (othercaps) {
|
||||
GstCaps *caps = gst_caps_copy (othercaps);
|
||||
|
||||
gst_caps_set_simple (caps,
|
||||
"width", G_TYPE_INT, width,
|
||||
"height", G_TYPE_INT, height,
|
||||
"framerate", G_TYPE_DOUBLE, framerate, NULL);
|
||||
if (par) {
|
||||
gst_caps_set_simple (caps,
|
||||
"pixel-aspect-ratio", GST_TYPE_FRACTION,
|
||||
gst_value_get_fraction_numerator (par),
|
||||
gst_value_get_fraction_denominator (par), NULL);
|
||||
}
|
||||
ret = gst_pad_try_set_caps (otherpad, caps);
|
||||
gst_caps_free (caps);
|
||||
if (GST_PAD_LINK_FAILED (ret)) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (pad == space->srcpad) {
|
||||
space->to_pixfmt = ctx->pix_fmt;
|
||||
return FALSE;
|
||||
} else {
|
||||
space->from_pixfmt = ctx->pix_fmt;
|
||||
if (pad == space->srcpad) {
|
||||
space->to_pixfmt = ctx->pix_fmt;
|
||||
} else {
|
||||
space->from_pixfmt = ctx->pix_fmt;
|
||||
|
||||
/* palette */
|
||||
if (space->palette)
|
||||
av_free (space->palette);
|
||||
space->palette = ctx->palctrl;
|
||||
/* palette */
|
||||
if (space->palette)
|
||||
av_free (space->palette);
|
||||
space->palette = ctx->palctrl;
|
||||
}
|
||||
av_free (ctx);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* configureing the caps on a pad means that we should check if we
|
||||
* can get a fic format for that caps. Then we need to figure out
|
||||
* how we can convert that to the peer format */
|
||||
static gboolean
|
||||
gst_ffmpegcsp_setcaps (GstPad * pad, GstCaps * caps)
|
||||
{
|
||||
GstStructure *structure;
|
||||
GstFFMpegCsp *space;
|
||||
GstPad *otherpeer;
|
||||
GstPad *otherpad;
|
||||
int height, width;
|
||||
double framerate;
|
||||
const GValue *par = NULL;
|
||||
GstCaps **other_prefered, **prefered;
|
||||
|
||||
space = GST_FFMPEGCSP (GST_PAD_PARENT (pad));
|
||||
|
||||
GST_DEBUG_OBJECT (space, "setcaps on %s:%s with caps %" GST_PTR_FORMAT,
|
||||
GST_DEBUG_PAD_NAME (pad), caps);
|
||||
|
||||
otherpad = (pad == space->srcpad) ? space->sinkpad : space->srcpad;
|
||||
prefered =
|
||||
(pad == space->srcpad) ? &space->src_prefered : &space->sink_prefered;
|
||||
other_prefered =
|
||||
(pad == space->srcpad) ? &space->sink_prefered : &space->src_prefered;
|
||||
|
||||
structure = gst_caps_get_structure (caps, 0);
|
||||
gst_structure_get_int (structure, "width", &width);
|
||||
gst_structure_get_int (structure, "height", &height);
|
||||
gst_structure_get_double (structure, "framerate", &framerate);
|
||||
par = gst_structure_get_value (structure, "pixel-aspect-ratio");
|
||||
|
||||
if (!gst_ffmpegcsp_configure_context (pad, caps, width, height))
|
||||
return FALSE;
|
||||
|
||||
*prefered = caps;
|
||||
|
||||
otherpeer = gst_pad_get_peer (otherpad);
|
||||
if (otherpeer) {
|
||||
/* check passthrough */
|
||||
//if (gst_pad_accept_caps (otherpeer, caps)) {
|
||||
if (FALSE) {
|
||||
*other_prefered = gst_caps_ref (caps);
|
||||
} else {
|
||||
GstCaps *othercaps;
|
||||
|
||||
/* set the size on the otherpad */
|
||||
othercaps = gst_pad_get_caps (otherpeer);
|
||||
if (othercaps) {
|
||||
GstCaps *targetcaps = gst_caps_copy_nth (othercaps, 0);
|
||||
|
||||
gst_caps_unref (othercaps);
|
||||
|
||||
gst_caps_set_simple (targetcaps,
|
||||
"width", G_TYPE_INT, width,
|
||||
"height", G_TYPE_INT, height,
|
||||
"framerate", G_TYPE_DOUBLE, framerate, NULL);
|
||||
|
||||
if (par) {
|
||||
gst_caps_set_simple (targetcaps,
|
||||
"pixel-aspect-ratio", GST_TYPE_FRACTION,
|
||||
gst_value_get_fraction_numerator (par),
|
||||
gst_value_get_fraction_denominator (par), NULL);
|
||||
}
|
||||
*other_prefered = targetcaps;
|
||||
}
|
||||
}
|
||||
gst_object_unref (GST_OBJECT (otherpeer));
|
||||
}
|
||||
av_free (ctx);
|
||||
|
||||
space->width = width;
|
||||
space->height = height;
|
||||
|
||||
return GST_PAD_LINK_OK;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GType
|
||||
|
@ -313,62 +345,63 @@ static void
|
|||
gst_ffmpegcsp_init (GstFFMpegCsp * space)
|
||||
{
|
||||
space->sinkpad = gst_pad_new_from_template (sinktempl, "sink");
|
||||
gst_pad_set_link_function (space->sinkpad, gst_ffmpegcsp_pad_link);
|
||||
gst_pad_set_getcaps_function (space->sinkpad, gst_ffmpegcsp_getcaps);
|
||||
gst_pad_set_setcaps_function (space->sinkpad, gst_ffmpegcsp_setcaps);
|
||||
gst_pad_set_chain_function (space->sinkpad, gst_ffmpegcsp_chain);
|
||||
gst_element_add_pad (GST_ELEMENT (space), space->sinkpad);
|
||||
|
||||
space->srcpad = gst_pad_new_from_template (srctempl, "src");
|
||||
gst_element_add_pad (GST_ELEMENT (space), space->srcpad);
|
||||
gst_pad_set_link_function (space->srcpad, gst_ffmpegcsp_pad_link);
|
||||
gst_pad_set_getcaps_function (space->srcpad, gst_ffmpegcsp_getcaps);
|
||||
gst_pad_set_setcaps_function (space->srcpad, gst_ffmpegcsp_setcaps);
|
||||
|
||||
space->from_pixfmt = space->to_pixfmt = PIX_FMT_NB;
|
||||
space->palette = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_ffmpegcsp_chain (GstPad * pad, GstData * data)
|
||||
static GstFlowReturn
|
||||
gst_ffmpegcsp_chain (GstPad * pad, GstBuffer * buffer)
|
||||
{
|
||||
GstBuffer *inbuf = GST_BUFFER (data);
|
||||
GstBuffer *inbuf = GST_BUFFER (buffer);
|
||||
GstFFMpegCsp *space;
|
||||
GstBuffer *outbuf = NULL;
|
||||
|
||||
g_return_if_fail (pad != NULL);
|
||||
g_return_if_fail (GST_IS_PAD (pad));
|
||||
g_return_if_fail (inbuf != NULL);
|
||||
//GstCaps *outcaps;
|
||||
|
||||
space = GST_FFMPEGCSP (gst_pad_get_parent (pad));
|
||||
|
||||
g_return_if_fail (space != NULL);
|
||||
g_return_if_fail (GST_IS_FFMPEGCSP (space));
|
||||
space = GST_FFMPEGCSP (GST_PAD_PARENT (pad));
|
||||
|
||||
if (!GST_PAD_IS_USABLE (space->srcpad)) {
|
||||
gst_buffer_unref (inbuf);
|
||||
return;
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
/* asume passthrough */
|
||||
guint size =
|
||||
avpicture_get_size (space->from_pixfmt, space->width, space->height);
|
||||
|
||||
outbuf = gst_pad_alloc_buffer (space->srcpad, GST_BUFFER_OFFSET_NONE, size,
|
||||
space->src_prefered);
|
||||
if (outbuf == NULL) {
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
if (space->from_pixfmt == PIX_FMT_NB || space->to_pixfmt == PIX_FMT_NB) {
|
||||
GST_ELEMENT_ERROR (space, CORE, NOT_IMPLEMENTED, (NULL),
|
||||
("attempting to convert colorspaces between unknown formats"));
|
||||
gst_buffer_unref (inbuf);
|
||||
return;
|
||||
return GST_FLOW_NOT_NEGOTIATED;
|
||||
}
|
||||
|
||||
if (space->from_pixfmt == space->to_pixfmt) {
|
||||
outbuf = inbuf;
|
||||
gst_buffer_unref (outbuf);
|
||||
} else {
|
||||
guint size = avpicture_get_size (space->to_pixfmt,
|
||||
space->width, space->height);
|
||||
|
||||
outbuf = gst_pad_alloc_buffer (space->srcpad, GST_BUFFER_OFFSET_NONE, size);
|
||||
|
||||
/* convert */
|
||||
gst_ffmpegcsp_avpicture_fill (&space->from_frame,
|
||||
GST_BUFFER_DATA (inbuf),
|
||||
space->from_pixfmt, space->width, space->height);
|
||||
if (space->palette)
|
||||
space->from_frame.data[1] = (uint8_t *) space->palette->palette;
|
||||
space->from_frame.data[1] = (uint8_t *) space->palette;
|
||||
gst_ffmpegcsp_avpicture_fill (&space->to_frame,
|
||||
GST_BUFFER_DATA (outbuf),
|
||||
space->to_pixfmt, space->width, space->height);
|
||||
|
@ -377,16 +410,10 @@ gst_ffmpegcsp_chain (GstPad * pad, GstData * data)
|
|||
|
||||
GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (inbuf);
|
||||
GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (inbuf);
|
||||
|
||||
gst_buffer_unref (inbuf);
|
||||
}
|
||||
|
||||
/* try negotiating here if it isn't yet */
|
||||
if (!gst_pad_is_negotiated (space->srcpad)) {
|
||||
gst_pad_renegotiate (space->srcpad);
|
||||
}
|
||||
|
||||
gst_pad_push (space->srcpad, GST_DATA (outbuf));
|
||||
return gst_pad_push (space->srcpad, outbuf);
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
|
|
|
@ -279,7 +279,6 @@ gst_tag_extract_id3v1_string (GstTagList * list, const gchar * tag,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Try current locale (if not UTF-8) */
|
||||
if (!g_get_charset (&env)) {
|
||||
if ((utf8 = g_locale_to_utf8 (start, size, &bytes_read, NULL, NULL))) {
|
||||
|
|
|
@ -96,7 +96,7 @@ static void gst_vorbis_tag_base_init (gpointer g_class);
|
|||
static void gst_vorbis_tag_class_init (gpointer g_class, gpointer class_data);
|
||||
static void gst_vorbis_tag_init (GTypeInstance * instance, gpointer g_class);
|
||||
|
||||
static void gst_vorbis_tag_chain (GstPad * pad, GstData * data);
|
||||
static GstFlowReturn gst_vorbis_tag_chain (GstPad * pad, GstBuffer * buffer);
|
||||
|
||||
static GstElementStateReturn gst_vorbis_tag_change_state (GstElement * element);
|
||||
|
||||
|
@ -571,13 +571,13 @@ gst_tag_list_to_vorbiscomment_buffer (const GstTagList * list,
|
|||
|
||||
return buffer;
|
||||
}
|
||||
static void
|
||||
gst_vorbis_tag_chain (GstPad * pad, GstData * data)
|
||||
|
||||
static GstFlowReturn
|
||||
gst_vorbis_tag_chain (GstPad * pad, GstBuffer * buffer)
|
||||
{
|
||||
GstVorbisTag *tag;
|
||||
GstBuffer *buffer;
|
||||
GstBuffer *out = NULL;
|
||||
|
||||
buffer = GST_BUFFER (data);
|
||||
tag = GST_VORBIS_TAG (gst_pad_get_parent (pad));
|
||||
|
||||
if (tag->output == OUTPUT_UNKNOWN) {
|
||||
|
@ -586,6 +586,7 @@ gst_vorbis_tag_chain (GstPad * pad, GstData * data)
|
|||
|
||||
/* caps nego */
|
||||
do {
|
||||
#if 0
|
||||
if (gst_pad_try_set_caps (tag->srcpad, vorbis_caps) >= 0) {
|
||||
tag->output = OUTPUT_DATA;
|
||||
} else if (gst_pad_try_set_caps (tag->srcpad, tags_caps) >= 0) {
|
||||
|
@ -595,14 +596,15 @@ gst_vorbis_tag_chain (GstPad * pad, GstData * data)
|
|||
gst_static_caps_get (&gst_vorbis_tag_src_template.static_caps);
|
||||
if (gst_pad_recover_caps_error (tag->srcpad, caps))
|
||||
continue;
|
||||
gst_caps_free (vorbis_caps);
|
||||
gst_caps_free (tags_caps);
|
||||
return;
|
||||
gst_caps_unref (vorbis_caps);
|
||||
gst_caps_unref (tags_caps);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
#endif
|
||||
} while (FALSE);
|
||||
|
||||
gst_caps_free (vorbis_caps);
|
||||
gst_caps_free (tags_caps);
|
||||
gst_caps_unref (vorbis_caps);
|
||||
gst_caps_unref (tags_caps);
|
||||
}
|
||||
|
||||
if (GST_BUFFER_SIZE (buffer) == 0)
|
||||
|
@ -616,31 +618,32 @@ gst_vorbis_tag_chain (GstPad * pad, GstData * data)
|
|||
&vendor);
|
||||
const GstTagList *found_tags;
|
||||
|
||||
gst_data_unref (data);
|
||||
gst_data_unref (GST_DATA (buffer));
|
||||
if (list == NULL) {
|
||||
GST_ELEMENT_ERROR (tag, CORE, TAG, (NULL),
|
||||
("invalid data in vorbis comments"));
|
||||
return;
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
gst_element_found_tags_for_pad (GST_ELEMENT (tag), tag->srcpad, 0,
|
||||
gst_tag_list_copy (list));
|
||||
//gst_element_found_tags_for_pad (GST_ELEMENT (tag), tag->srcpad, 0,
|
||||
// gst_tag_list_copy (list));
|
||||
|
||||
found_tags = gst_tag_setter_get_list (GST_TAG_SETTER (tag));
|
||||
if (found_tags)
|
||||
gst_tag_list_insert (list, found_tags,
|
||||
gst_tag_setter_get_merge_mode (GST_TAG_SETTER (tag)));
|
||||
data =
|
||||
GST_DATA (gst_tag_list_to_vorbiscomment_buffer (list, "\003vorbis", 7,
|
||||
vendor));
|
||||
out = gst_tag_list_to_vorbiscomment_buffer (list, "\003vorbis", 7, vendor);
|
||||
gst_tag_list_free (list);
|
||||
g_free (vendor);
|
||||
}
|
||||
|
||||
if (tag->output == OUTPUT_DATA) {
|
||||
gst_pad_push (tag->srcpad, data);
|
||||
gst_pad_push (tag->srcpad, out);
|
||||
} else {
|
||||
gst_data_unref (data);
|
||||
gst_data_unref (GST_DATA (out));
|
||||
}
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_vorbis_tag_change_state (GstElement * element)
|
||||
{
|
||||
|
|
|
@ -256,7 +256,7 @@ aac_type_find (GstTypeFind * tf, gpointer unused)
|
|||
NULL);
|
||||
|
||||
gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, caps);
|
||||
gst_caps_free (caps);
|
||||
gst_caps_unref (caps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -496,7 +496,7 @@ mp3_type_find (GstTypeFind * tf, gpointer unused)
|
|||
gst_structure_set (gst_caps_get_structure (caps, 0), "layer",
|
||||
G_TYPE_INT, layer, 0);
|
||||
gst_type_find_suggest (tf, probability, caps);
|
||||
gst_caps_free (caps);
|
||||
gst_caps_unref (caps);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -570,7 +570,7 @@ mpeg2_sys_type_find (GstTypeFind * tf, gpointer unused)
|
|||
gst_structure_set (gst_caps_get_structure (caps, 0), "mpegversion",
|
||||
G_TYPE_INT, 1, 0);
|
||||
gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, caps);
|
||||
gst_caps_free (caps);
|
||||
gst_caps_unref (caps);
|
||||
}
|
||||
} else if (data && IS_MPEG_PES_HEADER (data)) {
|
||||
/* PES stream */
|
||||
|
@ -712,7 +712,7 @@ mpeg1_sys_type_find (GstTypeFind * tf, gpointer unused)
|
|||
gst_structure_set (gst_caps_get_structure (caps, 0), "mpegversion",
|
||||
G_TYPE_INT, 1, 0);
|
||||
gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM - 1, caps);
|
||||
gst_caps_free (caps);
|
||||
gst_caps_unref (caps);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -741,7 +741,7 @@ mpeg_video_type_find (GstTypeFind * tf, gpointer unused)
|
|||
gst_structure_set (gst_caps_get_structure (caps, 0), "mpegversion",
|
||||
G_TYPE_INT, 1, 0);
|
||||
gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM - 1, caps);
|
||||
gst_caps_free (caps);
|
||||
gst_caps_unref (caps);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -772,7 +772,7 @@ mpeg_video_stream_type_find (GstTypeFind * tf, gpointer unused)
|
|||
gst_structure_set (gst_caps_get_structure (caps, 0), "mpegversion",
|
||||
G_TYPE_INT, 1, 0);
|
||||
gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM - 2, caps);
|
||||
gst_caps_free (caps);
|
||||
gst_caps_unref (caps);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -989,7 +989,6 @@ q3gp_type_find (GstTypeFind * tf, gpointer unused)
|
|||
|
||||
static GstStaticCaps mod_caps = GST_STATIC_CAPS ("audio/x-mod");
|
||||
|
||||
|
||||
#define MOD_CAPS gst_static_caps_get(&mod_caps)
|
||||
/* FIXME: M15 CheckType to do */
|
||||
static void
|
||||
|
@ -1319,7 +1318,7 @@ dv_type_find (GstTypeFind * tf, gpointer private)
|
|||
G_TYPE_STRING, format, NULL);
|
||||
|
||||
gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, caps);
|
||||
gst_caps_free (caps);
|
||||
gst_caps_unref (caps);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ static void gst_videotestsrc_set_property (GObject * object, guint prop_id,
|
|||
static void gst_videotestsrc_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static GstData *gst_videotestsrc_get (GstPad * pad);
|
||||
static void gst_videotestsrc_loop (GstPad * pad);
|
||||
|
||||
static const GstQueryType *gst_videotestsrc_get_query_types (GstPad * pad);
|
||||
static gboolean gst_videotestsrc_src_query (GstPad * pad,
|
||||
|
@ -160,6 +160,9 @@ gst_videotestsrc_class_init (GstVideotestsrcClass * klass)
|
|||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
|
||||
gobject_class->set_property = gst_videotestsrc_set_property;
|
||||
gobject_class->get_property = gst_videotestsrc_get_property;
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TYPE,
|
||||
g_param_spec_enum ("pattern", "Pattern",
|
||||
"Type of test pattern to generate", GST_TYPE_VIDEOTESTSRC_PATTERN, 1,
|
||||
|
@ -174,9 +177,6 @@ gst_videotestsrc_class_init (GstVideotestsrcClass * klass)
|
|||
|
||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
||||
|
||||
gobject_class->set_property = gst_videotestsrc_set_property;
|
||||
gobject_class->get_property = gst_videotestsrc_get_property;
|
||||
|
||||
gstelement_class->change_state = gst_videotestsrc_change_state;
|
||||
gstelement_class->set_clock = gst_videotestsrc_set_clock;
|
||||
|
||||
|
@ -195,66 +195,107 @@ gst_videotestsrc_set_clock (GstElement * element, GstClock * clock)
|
|||
}
|
||||
|
||||
static GstCaps *
|
||||
gst_videotestsrc_src_fixate (GstPad * pad, const GstCaps * caps)
|
||||
gst_videotestsrc_src_negotiate (GstPad * pad)
|
||||
{
|
||||
GstStructure *structure;
|
||||
GstCaps *newcaps;
|
||||
GstCaps *caps;
|
||||
GstCaps *temp;
|
||||
|
||||
/* FIXME this function isn't very intelligent in choosing "good" caps */
|
||||
/* get all possible caps on this link */
|
||||
caps = gst_pad_get_allowed_caps (pad);
|
||||
temp = gst_caps_normalize (caps);
|
||||
gst_caps_unref (caps);
|
||||
caps = temp;
|
||||
|
||||
if (gst_caps_get_size (caps) > 1)
|
||||
return NULL;
|
||||
if (gst_caps_get_size (caps) > 0) {
|
||||
GstStructure *structure;
|
||||
|
||||
newcaps = gst_caps_copy (caps);
|
||||
structure = gst_caps_get_structure (newcaps, 0);
|
||||
/* pick the first one */
|
||||
temp = gst_caps_copy_nth (caps, 0);
|
||||
gst_caps_unref (caps);
|
||||
caps = temp;
|
||||
|
||||
if (gst_caps_structure_fixate_field_nearest_int (structure, "width", 320)) {
|
||||
return newcaps;
|
||||
}
|
||||
if (gst_caps_structure_fixate_field_nearest_int (structure, "height", 240)) {
|
||||
return newcaps;
|
||||
}
|
||||
if (gst_caps_structure_fixate_field_nearest_double (structure, "framerate",
|
||||
30.0)) {
|
||||
return newcaps;
|
||||
structure = gst_caps_get_structure (caps, 0);
|
||||
|
||||
gst_caps_structure_fixate_field_nearest_int (structure, "width", 320);
|
||||
gst_caps_structure_fixate_field_nearest_int (structure, "height", 240);
|
||||
gst_caps_structure_fixate_field_nearest_double (structure, "framerate",
|
||||
30.0);
|
||||
}
|
||||
|
||||
/* failed to fixate */
|
||||
gst_caps_free (newcaps);
|
||||
return NULL;
|
||||
return caps;
|
||||
}
|
||||
|
||||
static GstPadLinkReturn
|
||||
gst_videotestsrc_src_link (GstPad * pad, const GstCaps * caps)
|
||||
gst_videotestsrc_src_link (GstPad * pad, GstPad * peer)
|
||||
{
|
||||
return GST_PAD_LINK_OK;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_videotestsrc_parse_caps (const GstCaps * caps,
|
||||
gint * width, gint * height, gdouble * rate,
|
||||
struct fourcc_list_struct **fourcc)
|
||||
{
|
||||
GstVideotestsrc *videotestsrc;
|
||||
const GstStructure *structure;
|
||||
GstPadLinkReturn ret;
|
||||
|
||||
videotestsrc = GST_VIDEOTESTSRC (gst_pad_get_parent (pad));
|
||||
GST_DEBUG_OBJECT (videotestsrc, "linking");
|
||||
GST_DEBUG ("parsing caps");
|
||||
|
||||
if (gst_caps_get_size (caps) < 1)
|
||||
return FALSE;
|
||||
|
||||
structure = gst_caps_get_structure (caps, 0);
|
||||
|
||||
videotestsrc->fourcc = paintinfo_find_by_structure (structure);
|
||||
if (!videotestsrc->fourcc) {
|
||||
*fourcc = paintinfo_find_by_structure (structure);
|
||||
if (!*fourcc) {
|
||||
g_critical ("videotestsrc format not found");
|
||||
return GST_PAD_LINK_REFUSED;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ret = gst_structure_get_int (structure, "width", &videotestsrc->width);
|
||||
ret &= gst_structure_get_int (structure, "height", &videotestsrc->height);
|
||||
ret &= gst_structure_get_double (structure, "framerate", &videotestsrc->rate);
|
||||
ret = gst_structure_get_int (structure, "width", width);
|
||||
ret &= gst_structure_get_int (structure, "height", height);
|
||||
ret &= gst_structure_get_double (structure, "framerate", rate);
|
||||
|
||||
if (!ret)
|
||||
return GST_PAD_LINK_REFUSED;
|
||||
return ret;
|
||||
}
|
||||
|
||||
videotestsrc->bpp = videotestsrc->fourcc->bitspp;
|
||||
#if 0
|
||||
static gboolean
|
||||
gst_videotestsrc_src_accept_caps (GstPad * pad, const GstCaps * caps)
|
||||
{
|
||||
gint width, height;
|
||||
gdouble rate;
|
||||
struct fourcc_list_struct *fourcc;
|
||||
|
||||
GST_DEBUG_OBJECT (videotestsrc, "size %dx%d, %f fps", videotestsrc->width,
|
||||
videotestsrc->height, videotestsrc->rate);
|
||||
return gst_videotestsrc_parse_caps (caps, &width, &height, &rate, &fourcc);
|
||||
}
|
||||
#endif
|
||||
|
||||
return GST_PAD_LINK_OK;
|
||||
static gboolean
|
||||
gst_videotestsrc_setcaps (GstPad * pad, GstCaps * caps)
|
||||
{
|
||||
gboolean res;
|
||||
gint width, height;
|
||||
gdouble rate;
|
||||
struct fourcc_list_struct *fourcc;
|
||||
GstVideotestsrc *videotestsrc;
|
||||
|
||||
videotestsrc = GST_VIDEOTESTSRC (GST_PAD_PARENT (pad));
|
||||
|
||||
res = gst_videotestsrc_parse_caps (caps, &width, &height, &rate, &fourcc);
|
||||
if (res) {
|
||||
/* looks ok here */
|
||||
videotestsrc->fourcc = fourcc;
|
||||
videotestsrc->width = width;
|
||||
videotestsrc->height = height;
|
||||
videotestsrc->rate = rate;
|
||||
videotestsrc->bpp = videotestsrc->fourcc->bitspp;
|
||||
|
||||
GST_DEBUG_OBJECT (videotestsrc, "size %dx%d, %f fps", videotestsrc->width,
|
||||
videotestsrc->height, videotestsrc->rate);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -262,13 +303,55 @@ gst_videotestsrc_src_unlink (GstPad * pad)
|
|||
{
|
||||
GstVideotestsrc *videotestsrc;
|
||||
|
||||
videotestsrc = GST_VIDEOTESTSRC (gst_pad_get_parent (pad));
|
||||
videotestsrc = GST_VIDEOTESTSRC (GST_PAD_PARENT (pad));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_videotestsrc_activate (GstPad * pad, GstActivateMode mode)
|
||||
{
|
||||
gboolean result = FALSE;
|
||||
GstVideotestsrc *videotestsrc;
|
||||
|
||||
videotestsrc = GST_VIDEOTESTSRC (GST_OBJECT_PARENT (pad));
|
||||
|
||||
switch (mode) {
|
||||
case GST_ACTIVATE_PULL:
|
||||
break;
|
||||
case GST_ACTIVATE_PUSH:
|
||||
/* if we have a scheduler we can start the task */
|
||||
if (GST_ELEMENT_SCHEDULER (videotestsrc)) {
|
||||
GST_STREAM_LOCK (pad);
|
||||
GST_RPAD_TASK (pad) =
|
||||
gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (videotestsrc),
|
||||
(GstTaskFunction) gst_videotestsrc_loop, pad);
|
||||
|
||||
gst_task_start (GST_RPAD_TASK (pad));
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
result = TRUE;
|
||||
}
|
||||
break;
|
||||
case GST_ACTIVATE_NONE:
|
||||
/* step 1, unblock clock sync (if any) */
|
||||
|
||||
/* step 2, make sure streaming finishes */
|
||||
GST_STREAM_LOCK (pad);
|
||||
/* step 3, stop the task */
|
||||
gst_task_stop (GST_RPAD_TASK (pad));
|
||||
gst_object_unref (GST_OBJECT (GST_RPAD_TASK (pad)));
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
|
||||
result = TRUE;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_videotestsrc_change_state (GstElement * element)
|
||||
{
|
||||
GstVideotestsrc *videotestsrc;
|
||||
GstElementStateReturn result;
|
||||
|
||||
videotestsrc = GST_VIDEOTESTSRC (element);
|
||||
|
||||
|
@ -280,6 +363,11 @@ gst_videotestsrc_change_state (GstElement * element)
|
|||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
break;
|
||||
}
|
||||
|
||||
result = parent_class->change_state (element);
|
||||
|
||||
switch (GST_STATE_TRANSITION (element)) {
|
||||
case GST_STATE_PLAYING_TO_PAUSED:
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
|
@ -291,7 +379,7 @@ gst_videotestsrc_change_state (GstElement * element)
|
|||
break;
|
||||
}
|
||||
|
||||
return parent_class->change_state (element);
|
||||
return result;
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
|
@ -348,7 +436,7 @@ gst_videotestsrc_getcaps (GstPad * pad)
|
|||
{
|
||||
GstVideotestsrc *vts;
|
||||
|
||||
vts = GST_VIDEOTESTSRC (gst_pad_get_parent (pad));
|
||||
vts = GST_VIDEOTESTSRC (GST_PAD_PARENT (pad));
|
||||
|
||||
return gst_videotestsrc_get_capslist ();
|
||||
}
|
||||
|
@ -360,10 +448,11 @@ gst_videotestsrc_init (GstVideotestsrc * videotestsrc)
|
|||
gst_pad_new_from_template (gst_videotestsrc_src_template_factory (),
|
||||
"src");
|
||||
gst_pad_set_getcaps_function (videotestsrc->srcpad, gst_videotestsrc_getcaps);
|
||||
gst_pad_set_fixate_function (videotestsrc->srcpad,
|
||||
gst_videotestsrc_src_fixate);
|
||||
gst_pad_set_setcaps_function (videotestsrc->srcpad, gst_videotestsrc_setcaps);
|
||||
gst_element_add_pad (GST_ELEMENT (videotestsrc), videotestsrc->srcpad);
|
||||
gst_pad_set_get_function (videotestsrc->srcpad, gst_videotestsrc_get);
|
||||
gst_pad_set_activate_function (videotestsrc->srcpad,
|
||||
gst_videotestsrc_activate);
|
||||
gst_pad_set_loop_function (videotestsrc->srcpad, gst_videotestsrc_loop);
|
||||
gst_pad_set_link_function (videotestsrc->srcpad, gst_videotestsrc_src_link);
|
||||
gst_pad_set_unlink_function (videotestsrc->srcpad,
|
||||
gst_videotestsrc_src_unlink);
|
||||
|
@ -405,7 +494,7 @@ gst_videotestsrc_src_query (GstPad * pad,
|
|||
GstQueryType type, GstFormat * format, gint64 * value)
|
||||
{
|
||||
gboolean res = FALSE;
|
||||
GstVideotestsrc *videotestsrc = GST_VIDEOTESTSRC (gst_pad_get_parent (pad));
|
||||
GstVideotestsrc *videotestsrc = GST_VIDEOTESTSRC (GST_PAD_PARENT (pad));
|
||||
|
||||
switch (type) {
|
||||
case GST_QUERY_POSITION:
|
||||
|
@ -446,42 +535,15 @@ gst_videotestsrc_handle_src_event (GstPad * pad, GstEvent * event)
|
|||
gboolean res = TRUE;
|
||||
GstVideotestsrc *videotestsrc;
|
||||
gint64 new_n_frames;
|
||||
GstClockTime new_running_time;
|
||||
|
||||
g_return_val_if_fail (pad != NULL, FALSE);
|
||||
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
|
||||
|
||||
videotestsrc = GST_VIDEOTESTSRC (gst_pad_get_parent (pad));
|
||||
videotestsrc = GST_VIDEOTESTSRC (GST_PAD_PARENT (pad));
|
||||
new_n_frames = videotestsrc->n_frames;
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_SEEK:
|
||||
{
|
||||
/* since we don't do bookkeeping, we just assign a useful meaning
|
||||
* to the time/frame relation after seeking based on current fps */
|
||||
switch (GST_EVENT_SEEK_FORMAT (event)) {
|
||||
case GST_FORMAT_TIME:
|
||||
new_running_time = GST_EVENT_SEEK_OFFSET (event);
|
||||
new_n_frames =
|
||||
GST_EVENT_SEEK_OFFSET (event) * (double) videotestsrc->rate /
|
||||
GST_SECOND;
|
||||
videotestsrc->segment_start_frame = -1;
|
||||
videotestsrc->segment_end_frame = -1;
|
||||
break;
|
||||
case GST_FORMAT_DEFAULT:
|
||||
new_n_frames = GST_EVENT_SEEK_OFFSET (event);
|
||||
new_running_time = GST_EVENT_SEEK_OFFSET (event) /
|
||||
(double) videotestsrc->rate * GST_SECOND;
|
||||
videotestsrc->segment_start_frame = -1;
|
||||
videotestsrc->segment_end_frame = -1;
|
||||
break;
|
||||
default:
|
||||
res = FALSE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GST_EVENT_SEEK_SEGMENT:
|
||||
{
|
||||
switch (GST_EVENT_SEEK_FORMAT (event)) {
|
||||
case GST_FORMAT_TIME:
|
||||
|
@ -517,27 +579,39 @@ gst_videotestsrc_handle_src_event (GstPad * pad, GstEvent * event)
|
|||
videotestsrc->n_frames = new_n_frames;
|
||||
videotestsrc->need_discont = TRUE;
|
||||
}
|
||||
gst_event_unref (event);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static GstData *
|
||||
gst_videotestsrc_get (GstPad * pad)
|
||||
static void
|
||||
gst_videotestsrc_loop (GstPad * pad)
|
||||
{
|
||||
GstVideotestsrc *videotestsrc;
|
||||
gulong newsize;
|
||||
GstBuffer *buf;
|
||||
GstBuffer *outbuf;
|
||||
|
||||
g_return_val_if_fail (pad != NULL, NULL);
|
||||
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
|
||||
|
||||
videotestsrc = GST_VIDEOTESTSRC (gst_pad_get_parent (pad));
|
||||
videotestsrc = GST_VIDEOTESTSRC (GST_PAD_PARENT (pad));
|
||||
GST_LOG_OBJECT (videotestsrc, "get");
|
||||
|
||||
/* no format on this pad, find a format */
|
||||
if (GST_PAD_CAPS (pad) == NULL) {
|
||||
GstCaps *caps;
|
||||
|
||||
caps = gst_videotestsrc_src_negotiate (pad);
|
||||
if (!gst_pad_set_caps (videotestsrc->srcpad, caps)) {
|
||||
GST_ELEMENT_ERROR (videotestsrc, CORE, NEGOTIATION, (NULL),
|
||||
("format could not be negotiated"));
|
||||
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||
goto need_pause;
|
||||
}
|
||||
}
|
||||
|
||||
if (videotestsrc->fourcc == NULL) {
|
||||
GST_ELEMENT_ERROR (videotestsrc, CORE, NEGOTIATION, (NULL),
|
||||
("format wasn't negotiated before get function"));
|
||||
return NULL;
|
||||
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||
goto need_pause;
|
||||
}
|
||||
|
||||
if (videotestsrc->need_discont) {
|
||||
|
@ -545,23 +619,23 @@ gst_videotestsrc_get (GstPad * pad)
|
|||
(videotestsrc->n_frames * GST_SECOND) / (double) videotestsrc->rate;
|
||||
|
||||
videotestsrc->need_discont = FALSE;
|
||||
return GST_DATA (gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, ts,
|
||||
NULL));
|
||||
gst_pad_push_event (pad, gst_event_new_discontinuous (FALSE,
|
||||
GST_FORMAT_TIME, ts, NULL));
|
||||
}
|
||||
|
||||
if ((videotestsrc->segment_end_frame != -1) &&
|
||||
(videotestsrc->n_frames > videotestsrc->segment_end_frame)) {
|
||||
if (videotestsrc->loop) {
|
||||
return GST_DATA (gst_event_new (GST_EVENT_SEGMENT_DONE));
|
||||
//gst_pad_push_event (pad, gst_event_new (GST_EVENT_SEGMENT_DONE));
|
||||
} else {
|
||||
gst_element_set_eos (GST_ELEMENT (videotestsrc));
|
||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
||||
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||
goto need_pause;
|
||||
}
|
||||
}
|
||||
|
||||
if (videotestsrc->num_buffers_left == 0) {
|
||||
gst_element_set_eos (GST_ELEMENT (videotestsrc));
|
||||
return GST_DATA (gst_event_new (GST_EVENT_EOS));
|
||||
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||
goto need_pause;
|
||||
} else {
|
||||
if (videotestsrc->num_buffers_left > 0)
|
||||
videotestsrc->num_buffers_left--;
|
||||
|
@ -569,29 +643,46 @@ gst_videotestsrc_get (GstPad * pad)
|
|||
|
||||
newsize = gst_videotestsrc_get_size (videotestsrc, videotestsrc->width,
|
||||
videotestsrc->height);
|
||||
g_return_val_if_fail (newsize > 0, NULL);
|
||||
g_return_if_fail (newsize > 0);
|
||||
|
||||
GST_LOG_OBJECT (videotestsrc, "creating buffer of %ld bytes for %dx%d image",
|
||||
newsize, videotestsrc->width, videotestsrc->height);
|
||||
|
||||
buf = gst_pad_alloc_buffer (pad, GST_BUFFER_OFFSET_NONE, newsize);
|
||||
g_return_val_if_fail (GST_BUFFER_DATA (buf) != NULL, NULL);
|
||||
outbuf =
|
||||
gst_pad_alloc_buffer (pad, GST_BUFFER_OFFSET_NONE, newsize,
|
||||
GST_RPAD_CAPS (pad));
|
||||
|
||||
videotestsrc->make_image (videotestsrc, (void *) GST_BUFFER_DATA (buf),
|
||||
if (GST_BUFFER_CAPS (outbuf) != GST_PAD_CAPS (pad)) {
|
||||
if (!gst_pad_set_caps (pad, GST_BUFFER_CAPS (outbuf))) {
|
||||
GST_ELEMENT_ERROR (videotestsrc, CORE, NEGOTIATION, (NULL),
|
||||
("format wasn't accepted"));
|
||||
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
|
||||
goto need_pause;
|
||||
}
|
||||
}
|
||||
|
||||
videotestsrc->make_image (videotestsrc, (void *) GST_BUFFER_DATA (outbuf),
|
||||
videotestsrc->width, videotestsrc->height);
|
||||
|
||||
GST_BUFFER_TIMESTAMP (buf) = videotestsrc->timestamp_offset +
|
||||
GST_BUFFER_TIMESTAMP (outbuf) = videotestsrc->timestamp_offset +
|
||||
videotestsrc->running_time;
|
||||
GST_BUFFER_DURATION (buf) = GST_SECOND / (double) videotestsrc->rate;
|
||||
GST_BUFFER_DURATION (outbuf) = GST_SECOND / (double) videotestsrc->rate;
|
||||
if (videotestsrc->sync) {
|
||||
/* FIXME this is not correct if we do QoS */
|
||||
if (videotestsrc->clock) {
|
||||
gst_element_wait (GST_ELEMENT (videotestsrc), GST_BUFFER_TIMESTAMP (buf));
|
||||
//gst_element_wait (GST_ELEMENT (videotestsrc), GST_BUFFER_TIMESTAMP (outbuf));
|
||||
}
|
||||
}
|
||||
videotestsrc->n_frames++;
|
||||
videotestsrc->running_time += GST_BUFFER_DURATION (buf);
|
||||
return GST_DATA (buf);
|
||||
videotestsrc->running_time += GST_BUFFER_DURATION (outbuf);
|
||||
|
||||
gst_pad_push (pad, outbuf);
|
||||
return;
|
||||
|
||||
need_pause:
|
||||
{
|
||||
gst_task_pause (GST_RPAD_TASK (pad));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -49,8 +49,7 @@ MotifWmHints, MwmHints;
|
|||
static void gst_xvimagesink_buffer_free (GstBuffer * buffer);
|
||||
static void gst_xvimagesink_xvimage_destroy (GstXvImageSink * xvimagesink,
|
||||
GstXvImage * xvimage);
|
||||
static void
|
||||
gst_xvimagesink_send_pending_navigation (GstXvImageSink * xvimagesink);
|
||||
//static void gst_xvimagesink_send_pending_navigation (GstXvImageSink * xvimagesink);
|
||||
|
||||
/* ElementFactory information */
|
||||
static GstElementDetails gst_xvimagesink_details =
|
||||
|
@ -821,7 +820,7 @@ gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink,
|
|||
GST_DEBUG ("Generated the following caps: %" GST_PTR_FORMAT, caps);
|
||||
|
||||
if (gst_caps_is_empty (caps)) {
|
||||
gst_caps_free (caps);
|
||||
gst_caps_unref (caps);
|
||||
XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0);
|
||||
GST_ELEMENT_ERROR (xvimagesink, STREAM, WRONG_TYPE, (NULL),
|
||||
("No supported format found"));
|
||||
|
@ -1066,7 +1065,7 @@ gst_xvimagesink_xcontext_clear (GstXvImageSink * xvimagesink)
|
|||
while (formats_list) {
|
||||
GstXvImageFormat *format = formats_list->data;
|
||||
|
||||
gst_caps_free (format->caps);
|
||||
gst_caps_unref (format->caps);
|
||||
g_free (format);
|
||||
formats_list = g_list_next (formats_list);
|
||||
}
|
||||
|
@ -1086,7 +1085,7 @@ gst_xvimagesink_xcontext_clear (GstXvImageSink * xvimagesink)
|
|||
if (xvimagesink->xcontext->channels_list)
|
||||
g_list_free (xvimagesink->xcontext->channels_list);
|
||||
|
||||
gst_caps_free (xvimagesink->xcontext->caps);
|
||||
gst_caps_unref (xvimagesink->xcontext->caps);
|
||||
g_free (xvimagesink->xcontext->par);
|
||||
|
||||
g_mutex_lock (xvimagesink->x_lock);
|
||||
|
@ -1120,6 +1119,7 @@ gst_xvimagesink_imagepool_clear (GstXvImageSink * xvimagesink)
|
|||
|
||||
/* Element stuff */
|
||||
|
||||
#if 0
|
||||
static GstCaps *
|
||||
gst_xvimagesink_fixate (GstPad * pad, const GstCaps * caps)
|
||||
{
|
||||
|
@ -1143,9 +1143,10 @@ gst_xvimagesink_fixate (GstPad * pad, const GstCaps * caps)
|
|||
return newcaps;
|
||||
}
|
||||
|
||||
gst_caps_free (newcaps);
|
||||
gst_caps_unref (newcaps);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This function tries to get a format matching with a given caps in the
|
||||
supported list of formats we generated in gst_xvimagesink_get_xv_support */
|
||||
|
@ -1176,20 +1177,24 @@ gst_xvimagesink_get_fourcc_from_caps (GstXvImageSink * xvimagesink,
|
|||
}
|
||||
|
||||
static GstCaps *
|
||||
gst_xvimagesink_getcaps (GstPad * pad)
|
||||
gst_xvimagesink_getcaps (GstBaseSink * bsink)
|
||||
{
|
||||
GstXvImageSink *xvimagesink;
|
||||
|
||||
xvimagesink = GST_XVIMAGESINK (gst_pad_get_parent (pad));
|
||||
xvimagesink = GST_XVIMAGESINK (bsink);
|
||||
|
||||
g_print ("getcaps\n");
|
||||
|
||||
if (xvimagesink->xcontext)
|
||||
return gst_caps_copy (xvimagesink->xcontext->caps);
|
||||
return gst_caps_ref (xvimagesink->xcontext->caps);
|
||||
|
||||
return gst_caps_copy (gst_pad_get_pad_template_caps (pad));
|
||||
return
|
||||
gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEOSINK_PAD
|
||||
(xvimagesink)));
|
||||
}
|
||||
|
||||
static GstPadLinkReturn
|
||||
gst_xvimagesink_sink_link (GstPad * pad, const GstCaps * caps)
|
||||
static gboolean
|
||||
gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
|
||||
{
|
||||
GstXvImageSink *xvimagesink;
|
||||
GstStructure *structure;
|
||||
|
@ -1202,10 +1207,7 @@ gst_xvimagesink_sink_link (GstPad * pad, const GstCaps * caps)
|
|||
const GValue *caps_par;
|
||||
gint num, den;
|
||||
|
||||
xvimagesink = GST_XVIMAGESINK (gst_pad_get_parent (pad));
|
||||
|
||||
if (!xvimagesink->xcontext)
|
||||
return GST_PAD_LINK_DELAYED;
|
||||
xvimagesink = GST_XVIMAGESINK (bsink);
|
||||
|
||||
GST_DEBUG_OBJECT (xvimagesink,
|
||||
"sinkconnect possible caps %" GST_PTR_FORMAT " with given caps %"
|
||||
|
@ -1217,9 +1219,7 @@ gst_xvimagesink_sink_link (GstPad * pad, const GstCaps * caps)
|
|||
ret &= gst_structure_get_double (structure, "framerate",
|
||||
&xvimagesink->framerate);
|
||||
if (!ret)
|
||||
return GST_PAD_LINK_REFUSED;
|
||||
|
||||
g_mutex_lock (xvimagesink->stream_lock);
|
||||
return FALSE;
|
||||
|
||||
xvimagesink->video_width = video_width;
|
||||
xvimagesink->video_height = video_height;
|
||||
|
@ -1229,8 +1229,7 @@ gst_xvimagesink_sink_link (GstPad * pad, const GstCaps * caps)
|
|||
gst_caps_copy (caps));
|
||||
}
|
||||
if (im_format == 0) {
|
||||
g_mutex_unlock (xvimagesink->stream_lock);
|
||||
return GST_PAD_LINK_REFUSED;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* get aspect ratio from caps if it's present, and
|
||||
|
@ -1319,12 +1318,10 @@ gst_xvimagesink_sink_link (GstPad * pad, const GstCaps * caps)
|
|||
|
||||
xvimagesink->xcontext->im_format = im_format;
|
||||
|
||||
g_mutex_unlock (xvimagesink->stream_lock);
|
||||
|
||||
gst_x_overlay_got_desired_size (GST_X_OVERLAY (xvimagesink),
|
||||
GST_VIDEOSINK_WIDTH (xvimagesink), GST_VIDEOSINK_HEIGHT (xvimagesink));
|
||||
|
||||
return GST_PAD_LINK_OK;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
|
@ -1349,32 +1346,23 @@ gst_xvimagesink_change_state (GstElement * element)
|
|||
/* call XSynchronize with the current value of synchronous */
|
||||
GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s",
|
||||
xvimagesink->synchronous ? "TRUE" : "FALSE");
|
||||
g_mutex_lock (xvimagesink->x_lock);
|
||||
XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous);
|
||||
g_mutex_unlock (xvimagesink->x_lock);
|
||||
gst_xvimagesink_update_colorbalance (xvimagesink);
|
||||
break;
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
xvimagesink->time = 0;
|
||||
if (xvimagesink->xwindow)
|
||||
gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
break;
|
||||
case GST_STATE_PLAYING_TO_PAUSED:
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
g_mutex_lock (xvimagesink->stream_lock);
|
||||
if (xvimagesink->xwindow)
|
||||
gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
|
||||
xvimagesink->framerate = 0;
|
||||
GST_VIDEOSINK_WIDTH (xvimagesink) = 0;
|
||||
GST_VIDEOSINK_HEIGHT (xvimagesink) = 0;
|
||||
g_mutex_unlock (xvimagesink->stream_lock);
|
||||
break;
|
||||
case GST_STATE_READY_TO_NULL:
|
||||
/* We are cleaning our resources here, yes i know chain is not running
|
||||
but the interface can be called to set a window from a different thread
|
||||
and that would crash */
|
||||
g_mutex_lock (xvimagesink->stream_lock);
|
||||
if (xvimagesink->xvimage) {
|
||||
gst_xvimagesink_xvimage_destroy (xvimagesink, xvimagesink->xvimage);
|
||||
xvimagesink->xvimage = NULL;
|
||||
|
@ -1392,45 +1380,38 @@ gst_xvimagesink_change_state (GstElement * element)
|
|||
gst_xvimagesink_xcontext_clear (xvimagesink);
|
||||
xvimagesink->xcontext = NULL;
|
||||
}
|
||||
g_mutex_unlock (xvimagesink->stream_lock);
|
||||
break;
|
||||
}
|
||||
|
||||
if (GST_ELEMENT_CLASS (parent_class)->change_state)
|
||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
|
||||
return GST_STATE_SUCCESS;
|
||||
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_xvimagesink_chain (GstPad * pad, GstData * data)
|
||||
gst_xvimagesink_get_times (GstBaseSink * bsink, GstBuffer * buf,
|
||||
GstClockTime * start, GstClockTime * end)
|
||||
{
|
||||
GstBuffer *buf = NULL;
|
||||
GstXvImageSink *xvimagesink;
|
||||
|
||||
g_return_if_fail (GST_IS_PAD (pad));
|
||||
g_return_if_fail (data != NULL);
|
||||
xvimagesink = GST_XVIMAGESINK (bsink);
|
||||
|
||||
xvimagesink = GST_XVIMAGESINK (gst_pad_get_parent (pad));
|
||||
|
||||
if (GST_IS_EVENT (data)) {
|
||||
gst_pad_event_default (pad, GST_EVENT (data));
|
||||
return;
|
||||
}
|
||||
|
||||
g_mutex_lock (xvimagesink->stream_lock);
|
||||
|
||||
buf = GST_BUFFER (data);
|
||||
/* update time */
|
||||
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
|
||||
xvimagesink->time = GST_BUFFER_TIMESTAMP (buf);
|
||||
*start = GST_BUFFER_TIMESTAMP (buf);
|
||||
if (GST_BUFFER_DURATION_IS_VALID (buf)) {
|
||||
*end = *start + GST_BUFFER_DURATION (buf);
|
||||
} else {
|
||||
if (xvimagesink->framerate > 0) {
|
||||
*end = *start + GST_SECOND / xvimagesink->framerate;
|
||||
}
|
||||
}
|
||||
}
|
||||
GST_LOG_OBJECT (xvimagesink, "clock wait: %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (xvimagesink->time));
|
||||
}
|
||||
|
||||
if (GST_VIDEOSINK_CLOCK (xvimagesink)) {
|
||||
gst_element_wait (GST_ELEMENT (xvimagesink), xvimagesink->time);
|
||||
}
|
||||
static GstFlowReturn
|
||||
gst_xvimagesink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
|
||||
{
|
||||
GstXvImageSink *xvimagesink;
|
||||
|
||||
xvimagesink = GST_XVIMAGESINK (bsink);
|
||||
|
||||
/* If this buffer has been allocated using our buffer management we simply
|
||||
put the ximage which is in the PRIVATE pointer */
|
||||
|
@ -1448,8 +1429,7 @@ gst_xvimagesink_chain (GstPad * pad, GstData * data)
|
|||
gst_buffer_unref (buf);
|
||||
GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
|
||||
("Failed creating an XvImage in xvimagesink chain function."));
|
||||
g_mutex_unlock (xvimagesink->stream_lock);
|
||||
return;
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1459,18 +1439,49 @@ gst_xvimagesink_chain (GstPad * pad, GstData * data)
|
|||
gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage);
|
||||
}
|
||||
|
||||
/* set correct time for next buffer */
|
||||
if (!GST_BUFFER_TIMESTAMP_IS_VALID (buf) && xvimagesink->framerate > 0) {
|
||||
xvimagesink->time += GST_SECOND / xvimagesink->framerate;
|
||||
gst_xvimagesink_handle_xevents (xvimagesink, GST_VIDEOSINK_PAD (xvimagesink));
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static GstFlowReturn
|
||||
gst_xvimagesink_chain (GstPad * pad, GstBuffer * buffer)
|
||||
{
|
||||
GstBuffer *buf = NULL;
|
||||
GstXvImageSink *xvimagesink;
|
||||
GstCaps *caps;
|
||||
GstFlowReturn result;
|
||||
|
||||
xvimagesink = GST_XVIMAGESINK (GST_PAD_PARENT (pad));
|
||||
|
||||
buf = GST_BUFFER (buffer);
|
||||
|
||||
caps = gst_buffer_get_caps (buffer);
|
||||
if (caps && caps != GST_PAD_CAPS (pad)) {
|
||||
if (gst_xvimagesink_parse_caps (pad, caps)) {
|
||||
gst_pad_set_caps (pad, caps);
|
||||
} else {
|
||||
GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
|
||||
("received unkown format"));
|
||||
gst_element_abort_preroll (GST_ELEMENT (xvimagesink));
|
||||
gst_buffer_unref (buffer);
|
||||
return GST_FLOW_NOT_NEGOTIATED;
|
||||
}
|
||||
}
|
||||
if (!GST_PAD_CAPS (pad)) {
|
||||
gst_buffer_unref (buffer);
|
||||
return GST_FLOW_NOT_NEGOTIATED;
|
||||
}
|
||||
|
||||
gst_buffer_unref (buf);
|
||||
gst_xvimagesink_show_frame (xvimagesink, buf);
|
||||
|
||||
|
||||
gst_xvimagesink_handle_xevents (xvimagesink, pad);
|
||||
gst_xvimagesink_send_pending_navigation (xvimagesink);
|
||||
|
||||
g_mutex_unlock (xvimagesink->stream_lock);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Buffer management */
|
||||
|
||||
|
@ -1486,8 +1497,8 @@ gst_xvimagesink_buffer_free (GstBuffer * buffer)
|
|||
xvimagesink = xvimage->xvimagesink;
|
||||
|
||||
/* If our geometry changed we can't reuse that image. */
|
||||
if ((xvimage->width != xvimagesink->video_width) ||
|
||||
(xvimage->height != xvimagesink->video_height))
|
||||
if ((xvimage->width != GST_VIDEOSINK_WIDTH (xvimagesink)) ||
|
||||
(xvimage->height != GST_VIDEOSINK_HEIGHT (xvimagesink)))
|
||||
gst_xvimagesink_xvimage_destroy (xvimagesink, xvimage);
|
||||
else {
|
||||
/* In that case we can reuse the image and add it to our image pool. */
|
||||
|
@ -1499,20 +1510,28 @@ gst_xvimagesink_buffer_free (GstBuffer * buffer)
|
|||
}
|
||||
|
||||
static GstBuffer *
|
||||
gst_xvimagesink_buffer_alloc (GstPad * pad, guint64 offset, guint size)
|
||||
gst_xvimagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
|
||||
GstCaps * caps)
|
||||
{
|
||||
GstXvImageSink *xvimagesink;
|
||||
GstBuffer *buffer;
|
||||
GstXvImage *xvimage = NULL;
|
||||
gboolean not_found = TRUE;
|
||||
|
||||
xvimagesink = GST_XVIMAGESINK (gst_pad_get_parent (pad));
|
||||
xvimagesink = GST_XVIMAGESINK (bsink);
|
||||
|
||||
/* FIXME, we should just parse the caps, and provide a buffer in this format,
|
||||
* we should not just reconfigure ourselves yet */
|
||||
if (caps && caps != GST_PAD_CAPS (GST_VIDEOSINK_PAD (xvimagesink))) {
|
||||
if (!gst_xvimagesink_setcaps (bsink, caps)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
g_mutex_lock (xvimagesink->pool_lock);
|
||||
|
||||
/* Walking through the pool cleaning unusable images and searching for a
|
||||
suitable one */
|
||||
while (not_found && xvimagesink->image_pool) {
|
||||
while (xvimagesink->image_pool) {
|
||||
xvimage = xvimagesink->image_pool->data;
|
||||
|
||||
if (xvimage) {
|
||||
|
@ -1521,8 +1540,8 @@ gst_xvimagesink_buffer_alloc (GstPad * pad, guint64 offset, guint size)
|
|||
xvimagesink->image_pool);
|
||||
|
||||
/* We check for geometry or image format changes */
|
||||
if ((xvimage->width != xvimagesink->video_width) ||
|
||||
(xvimage->height != xvimagesink->video_height) ||
|
||||
if ((xvimage->width != GST_VIDEOSINK_WIDTH (xvimagesink)) ||
|
||||
(xvimage->height != GST_VIDEOSINK_HEIGHT (xvimagesink)) ||
|
||||
(xvimage->im_format != xvimagesink->xcontext->im_format)) {
|
||||
/* This image is unusable. Destroying... */
|
||||
gst_xvimagesink_xvimage_destroy (xvimagesink, xvimage);
|
||||
|
@ -1538,7 +1557,7 @@ gst_xvimagesink_buffer_alloc (GstPad * pad, guint64 offset, guint size)
|
|||
|
||||
if (!xvimage) {
|
||||
/* We found no suitable image in the pool. Creating... */
|
||||
GST_LOG_OBJECT (xvimagesink, "no usable image in pool, creating xvimage");
|
||||
GST_DEBUG_OBJECT (xvimagesink, "no usable image in pool, creating xvimage");
|
||||
xvimage = gst_xvimagesink_xvimage_new (xvimagesink,
|
||||
xvimagesink->video_width, xvimagesink->video_height);
|
||||
}
|
||||
|
@ -1552,6 +1571,7 @@ gst_xvimagesink_buffer_alloc (GstPad * pad, guint64 offset, guint size)
|
|||
GST_BUFFER_DATA (buffer) = xvimage->xvimage->data;
|
||||
GST_BUFFER_FREE_DATA_FUNC (buffer) = gst_xvimagesink_buffer_free;
|
||||
GST_BUFFER_SIZE (buffer) = xvimage->size;
|
||||
gst_buffer_set_caps (buffer, caps);
|
||||
return buffer;
|
||||
} else
|
||||
return NULL;
|
||||
|
@ -1573,6 +1593,7 @@ gst_xvimagesink_interface_init (GstImplementsInterfaceClass * klass)
|
|||
klass->supported = gst_xvimagesink_interface_supported;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* This function is called with the stream-lock held
|
||||
*/
|
||||
|
@ -1622,6 +1643,7 @@ gst_xvimagesink_send_pending_navigation (GstXvImageSink * xvimagesink)
|
|||
|
||||
g_slist_free (pend_events);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
gst_xvimagesink_navigation_send_event (GstNavigation * navigation,
|
||||
|
@ -1629,14 +1651,25 @@ gst_xvimagesink_navigation_send_event (GstNavigation * navigation,
|
|||
{
|
||||
GstXvImageSink *xvimagesink = GST_XVIMAGESINK (navigation);
|
||||
GstEvent *event;
|
||||
double x, y;
|
||||
|
||||
event = gst_event_new (GST_EVENT_NAVIGATION);
|
||||
event->event_data.structure.structure = structure;
|
||||
|
||||
g_mutex_lock (xvimagesink->nav_lock);
|
||||
xvimagesink->pend_nav_events =
|
||||
g_slist_prepend (xvimagesink->pend_nav_events, event);
|
||||
g_mutex_unlock (xvimagesink->nav_lock);
|
||||
/* Converting pointer coordinates to the non scaled geometry */
|
||||
if (gst_structure_get_double (structure, "pointer_x", &x)) {
|
||||
x *= GST_VIDEOSINK_WIDTH (xvimagesink);
|
||||
x /= xvimagesink->xwindow->width;
|
||||
gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, x, NULL);
|
||||
}
|
||||
if (gst_structure_get_double (structure, "pointer_y", &y)) {
|
||||
y *= GST_VIDEOSINK_HEIGHT (xvimagesink);
|
||||
y /= xvimagesink->xwindow->height;
|
||||
gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, y, NULL);
|
||||
}
|
||||
|
||||
gst_pad_send_event (gst_pad_get_peer (GST_VIDEOSINK_PAD (xvimagesink)),
|
||||
event);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1666,11 +1699,6 @@ gst_xvimagesink_set_xwindow_id (GstXOverlay * overlay, XID xwindow_id)
|
|||
|
||||
gst_xvimagesink_update_colorbalance (xvimagesink);
|
||||
|
||||
/* We acquire the stream lock while setting this window in the element.
|
||||
We are basically cleaning tons of stuff replacing the old window, putting
|
||||
images while we do that would surely crash */
|
||||
g_mutex_lock (xvimagesink->stream_lock);
|
||||
|
||||
/* Clear image pool as the images are unusable anyway */
|
||||
gst_xvimagesink_imagepool_clear (xvimagesink);
|
||||
|
||||
|
@ -1718,8 +1746,6 @@ gst_xvimagesink_set_xwindow_id (GstXOverlay * overlay, XID xwindow_id)
|
|||
|
||||
if (xwindow)
|
||||
xvimagesink->xwindow = xwindow;
|
||||
|
||||
g_mutex_unlock (xvimagesink->stream_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1741,10 +1767,6 @@ gst_xvimagesink_expose (GstXOverlay * overlay)
|
|||
if (!xvimagesink->xwindow)
|
||||
return;
|
||||
|
||||
/* We don't want chain to iterate while we do that. We might act on random
|
||||
cur_image and different geometry */
|
||||
g_mutex_lock (xvimagesink->stream_lock);
|
||||
|
||||
/* Update the window geometry */
|
||||
g_mutex_lock (xvimagesink->x_lock);
|
||||
XGetWindowAttributes (xvimagesink->xcontext->disp,
|
||||
|
@ -1757,8 +1779,6 @@ gst_xvimagesink_expose (GstXOverlay * overlay)
|
|||
if (xvimagesink->cur_image) {
|
||||
gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->cur_image);
|
||||
}
|
||||
|
||||
g_mutex_unlock (xvimagesink->stream_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1894,11 +1914,9 @@ gst_xvimagesink_set_property (GObject * object, guint prop_id,
|
|||
case ARG_SYNCHRONOUS:
|
||||
xvimagesink->synchronous = g_value_get_boolean (value);
|
||||
if (xvimagesink->xcontext) {
|
||||
g_mutex_lock (xvimagesink->x_lock);
|
||||
XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous);
|
||||
GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s",
|
||||
xvimagesink->synchronous ? "TRUE" : "FALSE");
|
||||
g_mutex_unlock (xvimagesink->x_lock);
|
||||
}
|
||||
break;
|
||||
case ARG_PIXEL_ASPECT_RATIO:
|
||||
|
@ -1981,27 +1999,10 @@ gst_xvimagesink_finalize (GObject * object)
|
|||
g_mutex_free (xvimagesink->x_lock);
|
||||
xvimagesink->x_lock = NULL;
|
||||
}
|
||||
if (xvimagesink->stream_lock) {
|
||||
g_mutex_free (xvimagesink->stream_lock);
|
||||
xvimagesink->stream_lock = NULL;
|
||||
}
|
||||
if (xvimagesink->pool_lock) {
|
||||
g_mutex_free (xvimagesink->pool_lock);
|
||||
xvimagesink->pool_lock = NULL;
|
||||
}
|
||||
if (xvimagesink->nav_lock) {
|
||||
g_mutex_free (xvimagesink->nav_lock);
|
||||
xvimagesink->nav_lock = NULL;
|
||||
}
|
||||
|
||||
while (xvimagesink->pend_nav_events) {
|
||||
GstEvent *event = xvimagesink->pend_nav_events->data;
|
||||
|
||||
xvimagesink->pend_nav_events =
|
||||
g_slist_delete_link (xvimagesink->pend_nav_events,
|
||||
xvimagesink->pend_nav_events);
|
||||
gst_event_unref (event);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
@ -2009,24 +2010,6 @@ gst_xvimagesink_finalize (GObject * object)
|
|||
static void
|
||||
gst_xvimagesink_init (GstXvImageSink * xvimagesink)
|
||||
{
|
||||
GST_VIDEOSINK_PAD (xvimagesink) =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get
|
||||
(&gst_xvimagesink_sink_template_factory), "sink");
|
||||
|
||||
gst_element_add_pad (GST_ELEMENT (xvimagesink),
|
||||
GST_VIDEOSINK_PAD (xvimagesink));
|
||||
|
||||
gst_pad_set_chain_function (GST_VIDEOSINK_PAD (xvimagesink),
|
||||
gst_xvimagesink_chain);
|
||||
gst_pad_set_link_function (GST_VIDEOSINK_PAD (xvimagesink),
|
||||
gst_xvimagesink_sink_link);
|
||||
gst_pad_set_getcaps_function (GST_VIDEOSINK_PAD (xvimagesink),
|
||||
gst_xvimagesink_getcaps);
|
||||
gst_pad_set_fixate_function (GST_VIDEOSINK_PAD (xvimagesink),
|
||||
gst_xvimagesink_fixate);
|
||||
gst_pad_set_bufferalloc_function (GST_VIDEOSINK_PAD (xvimagesink),
|
||||
gst_xvimagesink_buffer_alloc);
|
||||
|
||||
xvimagesink->display_name = NULL;
|
||||
xvimagesink->xcontext = NULL;
|
||||
xvimagesink->xwindow = NULL;
|
||||
|
@ -2042,19 +2025,12 @@ gst_xvimagesink_init (GstXvImageSink * xvimagesink)
|
|||
xvimagesink->video_height = 0;
|
||||
|
||||
xvimagesink->x_lock = g_mutex_new ();
|
||||
xvimagesink->stream_lock = g_mutex_new ();
|
||||
|
||||
xvimagesink->image_pool = NULL;
|
||||
xvimagesink->pool_lock = g_mutex_new ();
|
||||
|
||||
xvimagesink->synchronous = FALSE;
|
||||
xvimagesink->par = NULL;
|
||||
|
||||
GST_FLAG_SET (xvimagesink, GST_ELEMENT_THREAD_SUGGESTED);
|
||||
GST_FLAG_SET (xvimagesink, GST_ELEMENT_EVENT_AWARE);
|
||||
|
||||
xvimagesink->nav_lock = g_mutex_new ();
|
||||
xvimagesink->pend_nav_events = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2073,12 +2049,17 @@ gst_xvimagesink_class_init (GstXvImageSinkClass * klass)
|
|||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
GstBaseSinkClass *gstbasesink_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
gstbasesink_class = (GstBaseSinkClass *) klass;
|
||||
|
||||
parent_class = g_type_class_ref (GST_TYPE_VIDEOSINK);
|
||||
|
||||
gobject_class->set_property = gst_xvimagesink_set_property;
|
||||
gobject_class->get_property = gst_xvimagesink_get_property;
|
||||
|
||||
g_object_class_install_property (gobject_class, ARG_CONTRAST,
|
||||
g_param_spec_int ("contrast", "Contrast", "The contrast of the video",
|
||||
-1000, 1000, 0, G_PARAM_READWRITE));
|
||||
|
@ -2104,10 +2085,18 @@ gst_xvimagesink_class_init (GstXvImageSinkClass * klass)
|
|||
"The pixel aspect ratio of the device", "1/1", G_PARAM_READWRITE));
|
||||
|
||||
gobject_class->finalize = gst_xvimagesink_finalize;
|
||||
gobject_class->set_property = gst_xvimagesink_set_property;
|
||||
gobject_class->get_property = gst_xvimagesink_get_property;
|
||||
|
||||
gstelement_class->change_state = gst_xvimagesink_change_state;
|
||||
gstelement_class->change_state =
|
||||
GST_DEBUG_FUNCPTR (gst_xvimagesink_change_state);
|
||||
|
||||
//gstbasesink_class->get_template = GST_DEBUG_FUNCPTR (gst_xvimagesink_get_template);
|
||||
gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_getcaps);
|
||||
gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_setcaps);
|
||||
gstbasesink_class->buffer_alloc =
|
||||
GST_DEBUG_FUNCPTR (gst_xvimagesink_buffer_alloc);
|
||||
gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_xvimagesink_get_times);
|
||||
gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_xvimagesink_show_frame);
|
||||
gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_xvimagesink_show_frame);
|
||||
}
|
||||
|
||||
/* ============================================================= */
|
||||
|
|
|
@ -142,21 +142,15 @@ struct _GstXvImageSink {
|
|||
gboolean cb_changed;
|
||||
|
||||
GMutex *x_lock;
|
||||
GMutex *stream_lock;
|
||||
|
||||
guint video_width, video_height; /* size of incoming video;
|
||||
* used as the size for XvImage */
|
||||
GValue *par; /* object-set pixel aspect ratio */
|
||||
|
||||
GstClockTime time;
|
||||
|
||||
GMutex *pool_lock;
|
||||
GSList *image_pool;
|
||||
|
||||
gboolean synchronous;
|
||||
|
||||
GMutex *nav_lock;
|
||||
GSList *pend_nav_events;
|
||||
};
|
||||
|
||||
struct _GstXvImageSinkClass {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
examples = seek spider_seek cdplayer cdparanoia vorbisfile playbin chained
|
||||
examples = seek cdplayer cdparanoia
|
||||
|
||||
noinst_PROGRAMS = $(examples)
|
||||
|
||||
|
|
|
@ -1,270 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gst/gst.h>
|
||||
#include <string.h>
|
||||
|
||||
static GstElement *playbin = NULL;
|
||||
static GstElement *pipeline;
|
||||
static guint64 duration;
|
||||
static GtkAdjustment *adjustment;
|
||||
static GtkWidget *hscale;
|
||||
static gboolean verbose = FALSE;
|
||||
|
||||
static guint update_id;
|
||||
|
||||
#define UPDATE_INTERVAL 500
|
||||
|
||||
static GstElement *
|
||||
make_playerbin_pipeline (const gchar * location)
|
||||
{
|
||||
playbin = gst_element_factory_make ("playbin", "player");
|
||||
g_assert (playbin);
|
||||
|
||||
g_object_set (G_OBJECT (playbin), "uri", location, NULL);
|
||||
|
||||
return playbin;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
format_value (GtkScale * scale, gdouble value)
|
||||
{
|
||||
gint64 real;
|
||||
gint64 seconds;
|
||||
gint64 subseconds;
|
||||
|
||||
real = value * duration / 100;
|
||||
seconds = (gint64) real / GST_SECOND;
|
||||
subseconds = (gint64) real / (GST_SECOND / 100);
|
||||
|
||||
return g_strdup_printf ("%02" G_GINT64_FORMAT ":%02" G_GINT64_FORMAT ":%02"
|
||||
G_GINT64_FORMAT, seconds / 60, seconds % 60, subseconds % 100);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
update_scale (gpointer data)
|
||||
{
|
||||
GstClock *clock;
|
||||
guint64 position;
|
||||
GstFormat format = GST_FORMAT_TIME;
|
||||
gboolean res;
|
||||
|
||||
duration = 0;
|
||||
clock = gst_bin_get_clock (GST_BIN (pipeline));
|
||||
|
||||
res = gst_element_query (playbin, GST_QUERY_TOTAL, &format, &duration);
|
||||
if (!res)
|
||||
duration = 0;
|
||||
res = gst_element_query (playbin, GST_QUERY_POSITION, &format, &position);
|
||||
if (!res)
|
||||
position = 0;
|
||||
|
||||
if (position >= duration)
|
||||
duration = position;
|
||||
|
||||
if (duration > 0) {
|
||||
gtk_adjustment_set_value (adjustment, position * 100.0 / duration);
|
||||
gtk_widget_queue_draw (hscale);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
iterate (gpointer data)
|
||||
{
|
||||
gboolean res;
|
||||
|
||||
if (!GST_FLAG_IS_SET (GST_OBJECT (data), GST_BIN_SELF_SCHEDULABLE)) {
|
||||
res = gst_bin_iterate (GST_BIN (data));
|
||||
} else {
|
||||
g_usleep (UPDATE_INTERVAL);
|
||||
res = gst_element_get_state (GST_ELEMENT (data)) == GST_STATE_PLAYING;
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
gtk_timeout_remove (update_id);
|
||||
g_print ("stopping iterations\n");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
start_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
||||
{
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
gtk_timeout_remove (update_id);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
||||
{
|
||||
gint64 real = gtk_range_get_value (GTK_RANGE (widget)) * duration / 100;
|
||||
gboolean res;
|
||||
GstEvent *s_event;
|
||||
|
||||
g_print ("seek to %" G_GINT64_FORMAT " on element %s\n", real,
|
||||
gst_element_get_name (playbin));
|
||||
s_event =
|
||||
gst_event_new_seek (GST_FORMAT_TIME | GST_SEEK_METHOD_SET |
|
||||
GST_SEEK_FLAG_FLUSH, real);
|
||||
|
||||
res = gst_element_send_event (playbin, s_event);
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
gtk_idle_add ((GtkFunction) iterate, pipeline);
|
||||
update_id =
|
||||
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
print_media_info (GstElement * playbin)
|
||||
{
|
||||
GList *streaminfo;
|
||||
GList *s;
|
||||
|
||||
g_print ("have media info now\n");
|
||||
|
||||
/* get info about the stream */
|
||||
g_object_get (G_OBJECT (playbin), "stream-info", &streaminfo, NULL);
|
||||
|
||||
for (s = streaminfo; s; s = g_list_next (s)) {
|
||||
GObject *obj = G_OBJECT (s->data);
|
||||
gint type;
|
||||
gboolean mute;
|
||||
|
||||
g_object_get (obj, "type", &type, NULL);
|
||||
g_object_get (obj, "mute", &mute, NULL);
|
||||
|
||||
g_print ("%d %d\n", type, mute);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
play_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_PLAYING) {
|
||||
GstElementStateReturn res;
|
||||
|
||||
res = gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
if (res == GST_STATE_SUCCESS) {
|
||||
print_media_info (playbin);
|
||||
|
||||
res = gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
gtk_idle_add ((GtkFunction) iterate, pipeline);
|
||||
update_id =
|
||||
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale,
|
||||
pipeline);
|
||||
} else {
|
||||
g_print ("failed playing\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pause_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_PAUSED) {
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
gtk_timeout_remove (update_id);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
stop_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_READY) {
|
||||
gst_element_set_state (pipeline, GST_STATE_READY);
|
||||
gtk_adjustment_set_value (adjustment, 0.0);
|
||||
gtk_timeout_remove (update_id);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_usage (int argc, char **argv)
|
||||
{
|
||||
g_print ("usage: %s <uri>\n", argv[0]);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
GtkWidget *window, *hbox, *vbox, *play_button, *pause_button, *stop_button;
|
||||
struct poptOption options[] = {
|
||||
{"verbose", 'v', POPT_ARG_NONE | POPT_ARGFLAG_STRIP, &verbose, 0,
|
||||
"Verbose properties", NULL},
|
||||
POPT_TABLEEND
|
||||
};
|
||||
|
||||
gst_init_with_popt_table (&argc, &argv, options);
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
if (argc != 2) {
|
||||
print_usage (argc, argv);
|
||||
exit (-1);
|
||||
}
|
||||
|
||||
pipeline = make_playerbin_pipeline (argv[1]);
|
||||
g_assert (pipeline);
|
||||
|
||||
/* initialize gui elements ... */
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
hbox = gtk_hbox_new (FALSE, 0);
|
||||
vbox = gtk_vbox_new (FALSE, 0);
|
||||
play_button = gtk_button_new_with_label ("play");
|
||||
pause_button = gtk_button_new_with_label ("pause");
|
||||
stop_button = gtk_button_new_with_label ("stop");
|
||||
|
||||
adjustment =
|
||||
GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.00, 100.0, 0.1, 1.0, 1.0));
|
||||
hscale = gtk_hscale_new (adjustment);
|
||||
gtk_scale_set_digits (GTK_SCALE (hscale), 2);
|
||||
gtk_range_set_update_policy (GTK_RANGE (hscale), GTK_UPDATE_CONTINUOUS);
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (hscale),
|
||||
"button_press_event", G_CALLBACK (start_seek), pipeline);
|
||||
gtk_signal_connect (GTK_OBJECT (hscale),
|
||||
"button_release_event", G_CALLBACK (stop_seek), pipeline);
|
||||
gtk_signal_connect (GTK_OBJECT (hscale),
|
||||
"format_value", G_CALLBACK (format_value), pipeline);
|
||||
|
||||
/* do the packing stuff ... */
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 96, 96);
|
||||
gtk_container_add (GTK_CONTAINER (window), vbox);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), hbox);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), play_button, FALSE, FALSE, 2);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), pause_button, FALSE, FALSE, 2);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), stop_button, FALSE, FALSE, 2);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), hscale, TRUE, TRUE, 2);
|
||||
|
||||
/* connect things ... */
|
||||
g_signal_connect (G_OBJECT (play_button), "clicked", G_CALLBACK (play_cb),
|
||||
pipeline);
|
||||
g_signal_connect (G_OBJECT (pause_button), "clicked", G_CALLBACK (pause_cb),
|
||||
pipeline);
|
||||
g_signal_connect (G_OBJECT (stop_button), "clicked", G_CALLBACK (stop_cb),
|
||||
pipeline);
|
||||
g_signal_connect (G_OBJECT (window), "delete_event", gtk_main_quit, NULL);
|
||||
|
||||
/* show the gui. */
|
||||
gtk_widget_show_all (window);
|
||||
|
||||
if (verbose) {
|
||||
g_signal_connect (pipeline, "deep_notify",
|
||||
G_CALLBACK (gst_element_default_deep_notify), NULL);
|
||||
}
|
||||
g_signal_connect (pipeline, "error", G_CALLBACK (gst_element_default_error),
|
||||
NULL);
|
||||
|
||||
gtk_main ();
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
|
||||
gst_object_unref (GST_OBJECT (pipeline));
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,6 +1,3 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
@ -20,12 +17,18 @@ static gboolean elem_seek = FALSE;
|
|||
static gboolean verbose = FALSE;
|
||||
|
||||
static guint update_id;
|
||||
static guint seek_timeout_id = 0;
|
||||
static gulong changed_id;
|
||||
|
||||
//#define SOURCE "gnomevfssrc"
|
||||
#define SOURCE "filesrc"
|
||||
#define SOURCE "gnomevfssrc"
|
||||
|
||||
#define UPDATE_INTERVAL 500
|
||||
|
||||
/* number of milliseconds to play for after a seek */
|
||||
#define SCRUB_TIME 250
|
||||
#define SCRUB
|
||||
|
||||
#define THREAD
|
||||
#define PAD_SEEK
|
||||
|
||||
|
@ -54,13 +57,13 @@ dynamic_link (GstPadTemplate * templ, GstPad * newpad, gpointer data)
|
|||
{
|
||||
dyn_link *connect = (dyn_link *) data;
|
||||
|
||||
if (!strcmp (gst_pad_get_name (newpad), connect->padname)) {
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
gst_bin_add (GST_BIN (pipeline), connect->bin);
|
||||
if (connect->padname == NULL ||
|
||||
!strcmp (gst_pad_get_name (newpad), connect->padname)) {
|
||||
if (connect->bin)
|
||||
gst_bin_add (GST_BIN (pipeline), connect->bin);
|
||||
gst_pad_link (newpad, connect->target);
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
||||
seekable_pads = g_list_prepend (seekable_pads, newpad);
|
||||
//seekable_pads = g_list_prepend (seekable_pads, newpad);
|
||||
rate_pads = g_list_prepend (rate_pads, newpad);
|
||||
}
|
||||
}
|
||||
|
@ -91,7 +94,7 @@ make_mod_pipeline (const gchar * location)
|
|||
|
||||
src = gst_element_factory_make_or_warn (SOURCE, "src");
|
||||
decoder = gst_element_factory_make_or_warn ("modplug", "decoder");
|
||||
audiosink = gst_element_factory_make_or_warn (DEFAULT_AUDIOSINK, "sink");
|
||||
audiosink = gst_element_factory_make_or_warn ("osssink", "sink");
|
||||
//g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
|
||||
|
||||
g_object_set (G_OBJECT (src), "location", location, NULL);
|
||||
|
@ -122,8 +125,8 @@ make_dv_pipeline (const gchar * location)
|
|||
|
||||
src = gst_element_factory_make_or_warn (SOURCE, "src");
|
||||
decoder = gst_element_factory_make_or_warn ("dvdec", "decoder");
|
||||
videosink = gst_element_factory_make_or_warn (DEFAULT_VIDEOSINK, "v_sink");
|
||||
audiosink = gst_element_factory_make_or_warn (DEFAULT_AUDIOSINK, "a_sink");
|
||||
videosink = gst_element_factory_make_or_warn ("ximagesink", "v_sink");
|
||||
audiosink = gst_element_factory_make_or_warn ("osssink", "a_sink");
|
||||
//g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
|
||||
|
||||
g_object_set (G_OBJECT (src), "location", location, NULL);
|
||||
|
@ -159,7 +162,7 @@ make_wav_pipeline (const gchar * location)
|
|||
|
||||
src = gst_element_factory_make_or_warn (SOURCE, "src");
|
||||
decoder = gst_element_factory_make_or_warn ("wavparse", "decoder");
|
||||
audiosink = gst_element_factory_make_or_warn (DEFAULT_AUDIOSINK, "sink");
|
||||
audiosink = gst_element_factory_make_or_warn ("osssink", "sink");
|
||||
//g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
|
||||
|
||||
g_object_set (G_OBJECT (src), "location", location, NULL);
|
||||
|
@ -190,7 +193,7 @@ make_flac_pipeline (const gchar * location)
|
|||
|
||||
src = gst_element_factory_make_or_warn (SOURCE, "src");
|
||||
decoder = gst_element_factory_make_or_warn ("flacdec", "decoder");
|
||||
audiosink = gst_element_factory_make_or_warn (DEFAULT_AUDIOSINK, "sink");
|
||||
audiosink = gst_element_factory_make_or_warn ("osssink", "sink");
|
||||
g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
|
||||
|
||||
g_object_set (G_OBJECT (src), "location", location, NULL);
|
||||
|
@ -221,7 +224,7 @@ make_sid_pipeline (const gchar * location)
|
|||
|
||||
src = gst_element_factory_make_or_warn (SOURCE, "src");
|
||||
decoder = gst_element_factory_make_or_warn ("siddec", "decoder");
|
||||
audiosink = gst_element_factory_make_or_warn (DEFAULT_AUDIOSINK, "sink");
|
||||
audiosink = gst_element_factory_make_or_warn ("osssink", "sink");
|
||||
//g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
|
||||
|
||||
g_object_set (G_OBJECT (src), "location", location, NULL);
|
||||
|
@ -276,25 +279,35 @@ make_parse_pipeline (const gchar * location)
|
|||
static GstElement *
|
||||
make_vorbis_pipeline (const gchar * location)
|
||||
{
|
||||
GstElement *pipeline;
|
||||
GstElement *src, *decoder, *audiosink;
|
||||
GstElement *pipeline, *audio_bin;
|
||||
GstElement *src, *demux, *decoder, *convert, *audiosink;
|
||||
GstPad *seekable;
|
||||
|
||||
pipeline = gst_pipeline_new ("app");
|
||||
|
||||
src = gst_element_factory_make_or_warn (SOURCE, "src");
|
||||
decoder = gst_element_factory_make_or_warn ("vorbisfile", "decoder");
|
||||
audiosink = gst_element_factory_make_or_warn (DEFAULT_AUDIOSINK, "sink");
|
||||
demux = gst_element_factory_make_or_warn ("oggdemux", "demux");
|
||||
decoder = gst_element_factory_make_or_warn ("vorbisdec", "decoder");
|
||||
convert = gst_element_factory_make_or_warn ("audioconvert", "convert");
|
||||
audiosink = gst_element_factory_make_or_warn ("osssink", "sink");
|
||||
g_object_set (G_OBJECT (audiosink), "sync", TRUE, NULL);
|
||||
|
||||
g_object_set (G_OBJECT (src), "location", location, NULL);
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), src);
|
||||
gst_bin_add (GST_BIN (pipeline), decoder);
|
||||
gst_bin_add (GST_BIN (pipeline), audiosink);
|
||||
audio_bin = gst_bin_new ("a_decoder_bin");
|
||||
|
||||
gst_element_link (src, decoder);
|
||||
gst_element_link (decoder, audiosink);
|
||||
gst_bin_add (GST_BIN (pipeline), src);
|
||||
gst_bin_add (GST_BIN (pipeline), demux);
|
||||
gst_bin_add (GST_BIN (audio_bin), decoder);
|
||||
gst_bin_add (GST_BIN (audio_bin), convert);
|
||||
gst_bin_add (GST_BIN (audio_bin), audiosink);
|
||||
gst_bin_add (GST_BIN (pipeline), audio_bin);
|
||||
|
||||
gst_element_link (src, demux);
|
||||
gst_element_link (decoder, convert);
|
||||
gst_element_link (convert, audiosink);
|
||||
|
||||
setup_dynamic_link (demux, NULL, gst_element_get_pad (decoder, "sink"), NULL);
|
||||
|
||||
seekable = gst_element_get_pad (decoder, "src");
|
||||
seekable_pads = g_list_prepend (seekable_pads, seekable);
|
||||
|
@ -304,11 +317,185 @@ make_vorbis_pipeline (const gchar * location)
|
|||
return pipeline;
|
||||
}
|
||||
|
||||
static GstElement *
|
||||
make_theora_pipeline (const gchar * location)
|
||||
{
|
||||
GstElement *pipeline, *video_bin;
|
||||
GstElement *src, *demux, *decoder, *convert, *videosink;
|
||||
GstElement *queue;
|
||||
GstPad *seekable;
|
||||
|
||||
pipeline = gst_pipeline_new ("app");
|
||||
|
||||
src = gst_element_factory_make_or_warn (SOURCE, "src");
|
||||
demux = gst_element_factory_make_or_warn ("oggdemux", "demux");
|
||||
queue = gst_element_factory_make_or_warn ("queue", "queue");
|
||||
decoder = gst_element_factory_make_or_warn ("theoradec", "decoder");
|
||||
convert = gst_element_factory_make_or_warn ("ffmpegcolorspace", "convert");
|
||||
videosink = gst_element_factory_make_or_warn ("xvimagesink", "sink");
|
||||
|
||||
g_object_set (G_OBJECT (src), "location", location, NULL);
|
||||
|
||||
video_bin = gst_bin_new ("v_decoder_bin");
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), src);
|
||||
gst_bin_add (GST_BIN (pipeline), demux);
|
||||
gst_bin_add (GST_BIN (pipeline), queue);
|
||||
gst_bin_add (GST_BIN (video_bin), decoder);
|
||||
gst_bin_add (GST_BIN (video_bin), convert);
|
||||
gst_bin_add (GST_BIN (video_bin), videosink);
|
||||
gst_bin_add (GST_BIN (pipeline), video_bin);
|
||||
|
||||
gst_element_link (src, demux);
|
||||
gst_element_link (queue, decoder);
|
||||
gst_element_link (decoder, convert);
|
||||
gst_element_link (convert, videosink);
|
||||
|
||||
setup_dynamic_link (demux, NULL, gst_element_get_pad (queue, "sink"), NULL);
|
||||
|
||||
seekable = gst_element_get_pad (decoder, "src");
|
||||
seekable_pads = g_list_prepend (seekable_pads, seekable);
|
||||
rate_pads = g_list_prepend (rate_pads, seekable);
|
||||
rate_pads = g_list_prepend (rate_pads, gst_element_get_pad (decoder, "sink"));
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
static GstElement *
|
||||
make_vorbis_theora_pipeline (const gchar * location)
|
||||
{
|
||||
GstElement *pipeline, *audio_bin, *video_bin;
|
||||
GstElement *src, *demux, *a_decoder, *a_convert, *v_decoder, *v_convert;
|
||||
GstElement *audiosink, *videosink;
|
||||
GstElement *a_queue, *v_queue;
|
||||
GstPad *seekable;
|
||||
|
||||
pipeline = gst_pipeline_new ("app");
|
||||
|
||||
src = gst_element_factory_make_or_warn (SOURCE, "src");
|
||||
g_object_set (G_OBJECT (src), "location", location, NULL);
|
||||
|
||||
demux = gst_element_factory_make_or_warn ("oggdemux", "demux");
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), src);
|
||||
gst_bin_add (GST_BIN (pipeline), demux);
|
||||
gst_element_link (src, demux);
|
||||
|
||||
audio_bin = gst_bin_new ("a_decoder_bin");
|
||||
a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
|
||||
a_decoder = gst_element_factory_make_or_warn ("vorbisdec", "a_dec");
|
||||
a_convert = gst_element_factory_make_or_warn ("audioconvert", "a_convert");
|
||||
audiosink = gst_element_factory_make_or_warn ("osssink", "a_sink");
|
||||
|
||||
gst_element_link (a_queue, a_decoder);
|
||||
gst_element_link (a_decoder, a_convert);
|
||||
gst_element_link (a_convert, audiosink);
|
||||
|
||||
gst_bin_add (GST_BIN (audio_bin), a_queue);
|
||||
gst_bin_add (GST_BIN (audio_bin), a_decoder);
|
||||
gst_bin_add (GST_BIN (audio_bin), a_convert);
|
||||
gst_bin_add (GST_BIN (audio_bin), audiosink);
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), audio_bin);
|
||||
|
||||
setup_dynamic_link (demux, NULL, gst_element_get_pad (a_queue, "sink"), NULL);
|
||||
|
||||
video_bin = gst_bin_new ("v_decoder_bin");
|
||||
v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
|
||||
v_decoder = gst_element_factory_make_or_warn ("theoradec", "v_dec");
|
||||
v_convert =
|
||||
gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_convert");
|
||||
videosink = gst_element_factory_make_or_warn ("xvimagesink", "v_sink");
|
||||
gst_element_link_many (v_queue, v_decoder, v_convert, videosink, NULL);
|
||||
|
||||
gst_bin_add (GST_BIN (video_bin), v_queue);
|
||||
gst_bin_add (GST_BIN (video_bin), v_decoder);
|
||||
gst_bin_add (GST_BIN (video_bin), v_convert);
|
||||
gst_bin_add (GST_BIN (video_bin), videosink);
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), video_bin);
|
||||
|
||||
setup_dynamic_link (demux, NULL, gst_element_get_pad (v_queue, "sink"), NULL);
|
||||
|
||||
seekable = gst_element_get_pad (a_decoder, "src");
|
||||
seekable_pads = g_list_prepend (seekable_pads, seekable);
|
||||
rate_pads = g_list_prepend (rate_pads, seekable);
|
||||
rate_pads =
|
||||
g_list_prepend (rate_pads, gst_element_get_pad (a_decoder, "sink"));
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
static GstElement *
|
||||
make_avi_msmpeg4v3_mp3_pipeline (const gchar * location)
|
||||
{
|
||||
GstElement *pipeline, *audio_bin, *video_bin;
|
||||
GstElement *src, *demux, *a_decoder, *a_convert, *v_decoder, *v_convert;
|
||||
GstElement *audiosink, *videosink;
|
||||
GstElement *a_queue, *v_queue;
|
||||
GstPad *seekable;
|
||||
|
||||
pipeline = gst_pipeline_new ("app");
|
||||
|
||||
src = gst_element_factory_make_or_warn (SOURCE, "src");
|
||||
g_object_set (G_OBJECT (src), "location", location, NULL);
|
||||
|
||||
demux = gst_element_factory_make_or_warn ("avidemux", "demux");
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), src);
|
||||
gst_bin_add (GST_BIN (pipeline), demux);
|
||||
gst_element_link (src, demux);
|
||||
|
||||
audio_bin = gst_bin_new ("a_decoder_bin");
|
||||
a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
|
||||
a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
|
||||
a_convert = gst_element_factory_make_or_warn ("audioconvert", "a_convert");
|
||||
audiosink = gst_element_factory_make_or_warn ("osssink", "a_sink");
|
||||
|
||||
gst_element_link (a_queue, a_decoder);
|
||||
gst_element_link (a_decoder, a_convert);
|
||||
gst_element_link (a_convert, audiosink);
|
||||
|
||||
gst_bin_add (GST_BIN (audio_bin), a_queue);
|
||||
gst_bin_add (GST_BIN (audio_bin), a_decoder);
|
||||
gst_bin_add (GST_BIN (audio_bin), a_convert);
|
||||
gst_bin_add (GST_BIN (audio_bin), audiosink);
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), audio_bin);
|
||||
|
||||
setup_dynamic_link (demux, NULL, gst_element_get_pad (a_queue, "sink"), NULL);
|
||||
|
||||
video_bin = gst_bin_new ("v_decoder_bin");
|
||||
v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
|
||||
v_decoder = gst_element_factory_make_or_warn ("ffdec_msmpeg4", "v_dec");
|
||||
v_convert =
|
||||
gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_convert");
|
||||
videosink = gst_element_factory_make_or_warn ("xvimagesink", "v_sink");
|
||||
gst_element_link_many (v_queue, v_decoder, v_convert, videosink, NULL);
|
||||
|
||||
gst_bin_add (GST_BIN (video_bin), v_queue);
|
||||
gst_bin_add (GST_BIN (video_bin), v_decoder);
|
||||
gst_bin_add (GST_BIN (video_bin), v_convert);
|
||||
gst_bin_add (GST_BIN (video_bin), videosink);
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), video_bin);
|
||||
|
||||
setup_dynamic_link (demux, NULL, gst_element_get_pad (v_queue, "sink"), NULL);
|
||||
|
||||
seekable = gst_element_get_pad (a_decoder, "src");
|
||||
seekable_pads = g_list_prepend (seekable_pads, seekable);
|
||||
rate_pads = g_list_prepend (rate_pads, seekable);
|
||||
rate_pads =
|
||||
g_list_prepend (rate_pads, gst_element_get_pad (a_decoder, "sink"));
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
static GstElement *
|
||||
make_mp3_pipeline (const gchar * location)
|
||||
{
|
||||
GstElement *pipeline;
|
||||
GstElement *src, *decoder, *audiosink, *queue, *audio_thread;
|
||||
GstElement *src, *decoder, *osssink, *queue;
|
||||
GstPad *seekable;
|
||||
|
||||
pipeline = gst_pipeline_new ("app");
|
||||
|
@ -316,24 +503,21 @@ make_mp3_pipeline (const gchar * location)
|
|||
src = gst_element_factory_make_or_warn (SOURCE, "src");
|
||||
decoder = gst_element_factory_make_or_warn ("mad", "dec");
|
||||
queue = gst_element_factory_make_or_warn ("queue", "queue");
|
||||
audiosink = gst_element_factory_make_or_warn (DEFAULT_AUDIOSINK, "sink");
|
||||
osssink = gst_element_factory_make_or_warn ("osssink", "sink");
|
||||
|
||||
audio_thread = gst_thread_new ("a_decoder_thread");
|
||||
|
||||
seekable_elements = g_list_prepend (seekable_elements, audiosink);
|
||||
seekable_elements = g_list_prepend (seekable_elements, osssink);
|
||||
|
||||
g_object_set (G_OBJECT (src), "location", location, NULL);
|
||||
g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
|
||||
g_object_set (G_OBJECT (osssink), "fragment", 0x00180008, NULL);
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), src);
|
||||
gst_bin_add (GST_BIN (pipeline), decoder);
|
||||
gst_bin_add (GST_BIN (audio_thread), queue);
|
||||
gst_bin_add (GST_BIN (audio_thread), audiosink);
|
||||
gst_bin_add (GST_BIN (pipeline), audio_thread);
|
||||
gst_bin_add (GST_BIN (pipeline), queue);
|
||||
gst_bin_add (GST_BIN (pipeline), osssink);
|
||||
|
||||
gst_element_link (src, decoder);
|
||||
gst_element_link (decoder, queue);
|
||||
gst_element_link (queue, audiosink);
|
||||
gst_element_link (queue, osssink);
|
||||
|
||||
seekable = gst_element_get_pad (queue, "src");
|
||||
seekable_pads = g_list_prepend (seekable_pads, seekable);
|
||||
|
@ -348,8 +532,7 @@ make_avi_pipeline (const gchar * location)
|
|||
{
|
||||
GstElement *pipeline, *audio_bin, *video_bin;
|
||||
GstElement *src, *demux, *a_decoder, *v_decoder, *audiosink, *videosink;
|
||||
GstElement *a_queue = NULL, *audio_thread = NULL, *v_queue =
|
||||
NULL, *video_thread = NULL;
|
||||
GstElement *a_queue = NULL, *v_queue = NULL;
|
||||
GstPad *seekable;
|
||||
|
||||
pipeline = gst_pipeline_new ("app");
|
||||
|
@ -366,16 +549,14 @@ make_avi_pipeline (const gchar * location)
|
|||
|
||||
audio_bin = gst_bin_new ("a_decoder_bin");
|
||||
a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
|
||||
audio_thread = gst_thread_new ("a_decoder_thread");
|
||||
audiosink = gst_element_factory_make_or_warn (DEFAULT_AUDIOSINK, "a_sink");
|
||||
audiosink = gst_element_factory_make_or_warn ("osssink", "a_sink");
|
||||
//g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
|
||||
a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
|
||||
gst_element_link (a_decoder, a_queue);
|
||||
gst_element_link (a_queue, audiosink);
|
||||
gst_bin_add (GST_BIN (audio_bin), a_decoder);
|
||||
gst_bin_add (GST_BIN (audio_bin), audio_thread);
|
||||
gst_bin_add (GST_BIN (audio_thread), a_queue);
|
||||
gst_bin_add (GST_BIN (audio_thread), audiosink);
|
||||
gst_bin_add (GST_BIN (audio_bin), a_queue);
|
||||
gst_bin_add (GST_BIN (audio_bin), audiosink);
|
||||
gst_element_set_state (audio_bin, GST_STATE_PAUSED);
|
||||
|
||||
setup_dynamic_link (demux, "audio_00", gst_element_get_pad (a_decoder,
|
||||
|
@ -391,8 +572,7 @@ make_avi_pipeline (const gchar * location)
|
|||
//v_decoder = gst_element_factory_make_or_warn ("identity", "v_dec");
|
||||
//v_decoder = gst_element_factory_make_or_warn ("windec", "v_dec");
|
||||
v_decoder = gst_element_factory_make_or_warn ("ffmpegdecall", "v_dec");
|
||||
video_thread = gst_thread_new ("v_decoder_thread");
|
||||
videosink = gst_element_factory_make_or_warn (DEFAULT_VIDEOSINK, "v_sink");
|
||||
videosink = gst_element_factory_make_or_warn ("ximagesink", "v_sink");
|
||||
//videosink = gst_element_factory_make_or_warn ("fakesink", "v_sink");
|
||||
//g_object_set (G_OBJECT (videosink), "sync", TRUE, NULL);
|
||||
v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
|
||||
|
@ -400,9 +580,8 @@ make_avi_pipeline (const gchar * location)
|
|||
gst_element_link (v_decoder, v_queue);
|
||||
gst_element_link (v_queue, videosink);
|
||||
gst_bin_add (GST_BIN (video_bin), v_decoder);
|
||||
gst_bin_add (GST_BIN (video_bin), video_thread);
|
||||
gst_bin_add (GST_BIN (video_thread), v_queue);
|
||||
gst_bin_add (GST_BIN (video_thread), videosink);
|
||||
gst_bin_add (GST_BIN (video_bin), v_queue);
|
||||
gst_bin_add (GST_BIN (video_bin), videosink);
|
||||
|
||||
gst_element_set_state (video_bin, GST_STATE_PAUSED);
|
||||
|
||||
|
@ -424,7 +603,7 @@ make_mpeg_pipeline (const gchar * location)
|
|||
GstElement *pipeline, *audio_bin, *video_bin;
|
||||
GstElement *src, *demux, *a_decoder, *v_decoder, *v_filter;
|
||||
GstElement *audiosink, *videosink;
|
||||
GstElement *a_queue, *audio_thread, *v_queue, *video_thread;
|
||||
GstElement *a_queue, *v_queue;
|
||||
GstPad *seekable;
|
||||
|
||||
pipeline = gst_pipeline_new ("app");
|
||||
|
@ -443,16 +622,14 @@ make_mpeg_pipeline (const gchar * location)
|
|||
|
||||
audio_bin = gst_bin_new ("a_decoder_bin");
|
||||
a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
|
||||
audio_thread = gst_thread_new ("a_decoder_thread");
|
||||
a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
|
||||
audiosink = gst_element_factory_make_or_warn (DEFAULT_AUDIOSINK, "a_sink");
|
||||
audiosink = gst_element_factory_make_or_warn ("osssink", "a_sink");
|
||||
g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
|
||||
gst_element_link (a_decoder, a_queue);
|
||||
gst_element_link (a_queue, audiosink);
|
||||
gst_bin_add (GST_BIN (audio_bin), a_decoder);
|
||||
gst_bin_add (GST_BIN (audio_bin), audio_thread);
|
||||
gst_bin_add (GST_BIN (audio_thread), a_queue);
|
||||
gst_bin_add (GST_BIN (audio_thread), audiosink);
|
||||
gst_bin_add (GST_BIN (audio_bin), a_queue);
|
||||
gst_bin_add (GST_BIN (audio_bin), audiosink);
|
||||
|
||||
setup_dynamic_link (demux, "audio_00", gst_element_get_pad (a_decoder,
|
||||
"sink"), audio_bin);
|
||||
|
@ -465,16 +642,15 @@ make_mpeg_pipeline (const gchar * location)
|
|||
|
||||
video_bin = gst_bin_new ("v_decoder_bin");
|
||||
v_decoder = gst_element_factory_make_or_warn ("mpeg2dec", "v_dec");
|
||||
video_thread = gst_thread_new ("v_decoder_thread");
|
||||
//g_object_set (G_OBJECT (video_thread), "priority", 2, NULL);
|
||||
v_queue = gst_element_factory_make_or_warn ("queue", "v_queue");
|
||||
v_filter = gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_filter");
|
||||
videosink = gst_element_factory_make_or_warn (DEFAULT_VIDEOSINK, "v_sink");
|
||||
videosink = gst_element_factory_make_or_warn ("ximagesink", "v_sink");
|
||||
gst_element_link_many (v_decoder, v_queue, v_filter, NULL);
|
||||
|
||||
gst_element_link (v_filter, videosink);
|
||||
gst_bin_add_many (GST_BIN (video_bin), v_decoder, video_thread, NULL);
|
||||
gst_bin_add_many (GST_BIN (video_thread), v_queue, v_filter, videosink, NULL);
|
||||
gst_bin_add_many (GST_BIN (video_bin), v_decoder, NULL);
|
||||
gst_bin_add_many (GST_BIN (video_bin), v_queue, v_filter, videosink, NULL);
|
||||
|
||||
setup_dynamic_link (demux, "video_00", gst_element_get_pad (v_decoder,
|
||||
"sink"), video_bin);
|
||||
|
@ -494,7 +670,7 @@ make_mpegnt_pipeline (const gchar * location)
|
|||
GstElement *pipeline, *audio_bin, *video_bin;
|
||||
GstElement *src, *demux, *a_decoder, *v_decoder, *v_filter;
|
||||
GstElement *audiosink, *videosink;
|
||||
GstElement *a_queue, *audio_thread;
|
||||
GstElement *a_queue;
|
||||
GstPad *seekable;
|
||||
|
||||
pipeline = gst_pipeline_new ("app");
|
||||
|
@ -513,17 +689,15 @@ make_mpegnt_pipeline (const gchar * location)
|
|||
|
||||
audio_bin = gst_bin_new ("a_decoder_bin");
|
||||
a_decoder = gst_element_factory_make_or_warn ("mad", "a_dec");
|
||||
audio_thread = gst_thread_new ("a_decoder_thread");
|
||||
a_queue = gst_element_factory_make_or_warn ("queue", "a_queue");
|
||||
audiosink = gst_element_factory_make_or_warn (DEFAULT_AUDIOSINK, "a_sink");
|
||||
audiosink = gst_element_factory_make_or_warn ("osssink", "a_sink");
|
||||
//g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
|
||||
g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
|
||||
gst_element_link (a_decoder, a_queue);
|
||||
gst_element_link (a_queue, audiosink);
|
||||
gst_bin_add (GST_BIN (audio_bin), a_decoder);
|
||||
gst_bin_add (GST_BIN (audio_bin), audio_thread);
|
||||
gst_bin_add (GST_BIN (audio_thread), a_queue);
|
||||
gst_bin_add (GST_BIN (audio_thread), audiosink);
|
||||
gst_bin_add (GST_BIN (audio_bin), a_queue);
|
||||
gst_bin_add (GST_BIN (audio_bin), audiosink);
|
||||
|
||||
setup_dynamic_link (demux, "audio_00", gst_element_get_pad (a_decoder,
|
||||
"sink"), audio_bin);
|
||||
|
@ -537,7 +711,7 @@ make_mpegnt_pipeline (const gchar * location)
|
|||
video_bin = gst_bin_new ("v_decoder_bin");
|
||||
v_decoder = gst_element_factory_make_or_warn ("mpeg2dec", "v_dec");
|
||||
v_filter = gst_element_factory_make_or_warn ("ffmpegcolorspace", "v_filter");
|
||||
videosink = gst_element_factory_make_or_warn (DEFAULT_VIDEOSINK, "v_sink");
|
||||
videosink = gst_element_factory_make_or_warn ("ximagesink", "v_sink");
|
||||
gst_element_link_many (v_decoder, v_filter, videosink, NULL);
|
||||
|
||||
gst_bin_add_many (GST_BIN (video_bin), v_decoder, v_filter, videosink, NULL);
|
||||
|
@ -554,45 +728,15 @@ make_mpegnt_pipeline (const gchar * location)
|
|||
return pipeline;
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
fixate (GstPad * pad, const GstCaps * in_caps, gpointer data)
|
||||
{
|
||||
GstCaps *caps;
|
||||
GstStructure *s;
|
||||
|
||||
if (gst_caps_get_size (in_caps) > 1)
|
||||
return NULL;
|
||||
|
||||
/* nothing if fixed already */
|
||||
s = gst_caps_get_structure (in_caps, 0);
|
||||
if (gst_structure_has_field_typed (s, "width", G_TYPE_INT) &&
|
||||
gst_structure_has_field_typed (s, "height", G_TYPE_INT) &&
|
||||
gst_structure_has_field_typed (s, "framerate", G_TYPE_DOUBLE))
|
||||
return NULL;
|
||||
|
||||
/* fixate */
|
||||
caps = gst_caps_copy (in_caps);
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
gst_caps_structure_fixate_field_nearest_int (s, "width", 200);
|
||||
gst_caps_structure_fixate_field_nearest_int (s, "height", 150);
|
||||
gst_caps_structure_fixate_field_nearest_double (s, "framerate", 10.0);
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
static GstElement *
|
||||
make_playerbin_pipeline (const gchar * location)
|
||||
{
|
||||
GstElement *player, *vis;
|
||||
GstElement *player;
|
||||
|
||||
player = gst_element_factory_make ("playbin", "player");
|
||||
vis = gst_element_factory_make ("synaesthesia", "vis");
|
||||
g_assert (player);
|
||||
g_assert (vis);
|
||||
|
||||
g_signal_connect (gst_element_get_pad (vis, "src"), "fixate",
|
||||
G_CALLBACK (fixate), NULL);
|
||||
g_object_set (G_OBJECT (player), "uri", location, "vis-plugin", vis, NULL);
|
||||
g_object_set (G_OBJECT (player), "uri", location, NULL);
|
||||
|
||||
seekable_elements = g_list_prepend (seekable_elements, player);
|
||||
|
||||
|
@ -791,7 +935,7 @@ update_scale (gpointer data)
|
|||
gboolean res;
|
||||
|
||||
duration = 0;
|
||||
clock = gst_bin_get_clock (GST_BIN (pipeline));
|
||||
clock = gst_pipeline_get_clock (GST_PIPELINE (pipeline));
|
||||
|
||||
if (elem_seek) {
|
||||
if (seekable_elements) {
|
||||
|
@ -843,36 +987,21 @@ update_scale (gpointer data)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void do_seek (GtkWidget * widget);
|
||||
|
||||
#ifdef SCRUB
|
||||
static gboolean
|
||||
iterate (gpointer data)
|
||||
{
|
||||
gboolean res;
|
||||
|
||||
if (!GST_FLAG_IS_SET (GST_OBJECT (data), GST_BIN_SELF_SCHEDULABLE)) {
|
||||
res = gst_bin_iterate (GST_BIN (data));
|
||||
} else {
|
||||
g_usleep (500);
|
||||
res = gst_element_get_state (GST_ELEMENT (data)) == GST_STATE_PLAYING;
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
gtk_timeout_remove (update_id);
|
||||
g_print ("stopping iterations\n");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
start_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
||||
end_scrub (GtkWidget * widget)
|
||||
{
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
gtk_timeout_remove (update_id);
|
||||
seek_timeout_id = 0;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
||||
static void
|
||||
do_seek (GtkWidget * widget)
|
||||
{
|
||||
gint64 real = gtk_range_get_value (GTK_RANGE (widget)) * duration / 100;
|
||||
gboolean res;
|
||||
|
@ -884,8 +1013,8 @@ stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
|||
while (walk) {
|
||||
GstPad *seekable = GST_PAD (walk->data);
|
||||
|
||||
g_print ("seek to %" G_GINT64_FORMAT " on pad %s:%s\n", real,
|
||||
GST_DEBUG_PAD_NAME (seekable));
|
||||
g_print ("seek to %" GST_TIME_FORMAT " on pad %s:%s\n",
|
||||
GST_TIME_ARGS (real), GST_DEBUG_PAD_NAME (seekable));
|
||||
s_event =
|
||||
gst_event_new_seek (GST_FORMAT_TIME | GST_SEEK_METHOD_SET |
|
||||
GST_SEEK_FLAG_FLUSH, real);
|
||||
|
@ -912,8 +1041,57 @@ stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
|||
}
|
||||
}
|
||||
|
||||
GST_PIPELINE (pipeline)->stream_time = real;
|
||||
}
|
||||
|
||||
static void
|
||||
seek_cb (GtkWidget * widget)
|
||||
{
|
||||
#ifdef SCRUB
|
||||
/* If the timer hasn't expired yet, then the pipeline is running */
|
||||
if (seek_timeout_id != 0) {
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
}
|
||||
#endif
|
||||
|
||||
do_seek (widget);
|
||||
|
||||
#ifdef SCRUB
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
gtk_idle_add ((GtkFunction) iterate, pipeline);
|
||||
|
||||
if (seek_timeout_id == 0) {
|
||||
seek_timeout_id =
|
||||
gtk_timeout_add (SCRUB_TIME, (GSourceFunc) end_scrub, widget);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static gboolean
|
||||
start_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
||||
{
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
gtk_timeout_remove (update_id);
|
||||
|
||||
if (changed_id == 0) {
|
||||
changed_id = gtk_signal_connect (GTK_OBJECT (hscale),
|
||||
"value_changed", G_CALLBACK (seek_cb), pipeline);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
stop_seek (GtkWidget * widget, gpointer user_data)
|
||||
{
|
||||
g_signal_handler_disconnect (GTK_OBJECT (hscale), changed_id);
|
||||
changed_id = 0;
|
||||
if (seek_timeout_id != 0) {
|
||||
gtk_timeout_remove (seek_timeout_id);
|
||||
seek_timeout_id = 0;
|
||||
/* Still scrubbing, so the pipeline is already playing */
|
||||
} else
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
||||
update_id =
|
||||
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
|
||||
|
||||
|
@ -923,9 +1101,11 @@ stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
|||
static void
|
||||
play_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_PLAYING) {
|
||||
GstElementState state;
|
||||
|
||||
gst_element_get_state (pipeline, &state, NULL, NULL);
|
||||
if (state != GST_STATE_PLAYING) {
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
gtk_idle_add ((GtkFunction) iterate, pipeline);
|
||||
update_id =
|
||||
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
|
||||
}
|
||||
|
@ -934,7 +1114,10 @@ play_cb (GtkButton * button, gpointer data)
|
|||
static void
|
||||
pause_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_PAUSED) {
|
||||
GstElementState state;
|
||||
|
||||
gst_element_get_state (pipeline, &state, NULL, NULL);
|
||||
if (state != GST_STATE_PAUSED) {
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
gtk_timeout_remove (update_id);
|
||||
}
|
||||
|
@ -943,7 +1126,10 @@ pause_cb (GtkButton * button, gpointer data)
|
|||
static void
|
||||
stop_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_READY) {
|
||||
GstElementState state;
|
||||
|
||||
gst_element_get_state (pipeline, &state, NULL, NULL);
|
||||
if (state != GST_STATE_READY) {
|
||||
gst_element_set_state (pipeline, GST_STATE_READY);
|
||||
gtk_adjustment_set_value (adjustment, 0.0);
|
||||
gtk_timeout_remove (update_id);
|
||||
|
@ -963,6 +1149,9 @@ static Pipeline pipelines[] = {
|
|||
{"mpeg1", make_mpeg_pipeline},
|
||||
{"mpegparse", make_parse_pipeline},
|
||||
{"vorbis", make_vorbis_pipeline},
|
||||
{"theora", make_theora_pipeline},
|
||||
{"ogg/v/t", make_vorbis_theora_pipeline},
|
||||
{"avi/msmpeg4v3/mp3", make_avi_msmpeg4v3_mp3_pipeline},
|
||||
{"sid", make_sid_pipeline},
|
||||
{"flac", make_flac_pipeline},
|
||||
{"wav", make_wav_pipeline},
|
||||
|
@ -1065,18 +1254,13 @@ main (int argc, char **argv)
|
|||
|
||||
if (verbose) {
|
||||
g_signal_connect (pipeline, "deep_notify",
|
||||
G_CALLBACK (gst_element_default_deep_notify), NULL);
|
||||
G_CALLBACK (gst_object_default_deep_notify), NULL);
|
||||
}
|
||||
g_signal_connect (pipeline, "error", G_CALLBACK (gst_element_default_error),
|
||||
NULL);
|
||||
|
||||
gtk_main ();
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
|
||||
//gst_object_unref (GST_OBJECT (pipeline));
|
||||
|
||||
//g_mem_chunk_info();
|
||||
gst_object_unref (GST_OBJECT (pipeline));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,379 +0,0 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gst/gst.h>
|
||||
#include <string.h>
|
||||
|
||||
static GList *rate_pads = NULL;
|
||||
static GList *seekable_elements = NULL;
|
||||
|
||||
static GstElement *pipeline;
|
||||
static GtkAdjustment *adjustment;
|
||||
static gboolean stats = FALSE;
|
||||
static guint64 duration;
|
||||
|
||||
static guint update_id;
|
||||
|
||||
//#define SOURCE "gnomevfssrc"
|
||||
#define SOURCE "filesrc"
|
||||
|
||||
#define UPDATE_INTERVAL 500
|
||||
|
||||
static GstElement *
|
||||
make_spider_pipeline (const gchar * location, gboolean thread)
|
||||
{
|
||||
GstElement *pipeline;
|
||||
GstElement *src, *decoder, *audiosink, *videosink, *a_thread, *v_thread,
|
||||
*a_queue, *v_queue;
|
||||
|
||||
if (thread) {
|
||||
pipeline = gst_thread_new ("app");
|
||||
} else {
|
||||
pipeline = gst_pipeline_new ("app");
|
||||
}
|
||||
|
||||
|
||||
src = gst_element_factory_make (SOURCE, "src");
|
||||
decoder = gst_element_factory_make ("spider", "decoder");
|
||||
a_thread = gst_thread_new ("a_thread");
|
||||
a_queue = gst_element_factory_make ("queue", "a_queue");
|
||||
audiosink = gst_element_factory_make (DEFAULT_AUDIOSINK, "a_sink");
|
||||
//g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
|
||||
|
||||
v_thread = gst_thread_new ("v_thread");
|
||||
v_queue = gst_element_factory_make ("queue", "v_queue");
|
||||
videosink = gst_element_factory_make (DEFAULT_VIDEOSINK, "v_sink");
|
||||
//g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
|
||||
|
||||
g_object_set (G_OBJECT (src), "location", location, NULL);
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), src);
|
||||
gst_bin_add (GST_BIN (pipeline), decoder);
|
||||
gst_bin_add (GST_BIN (a_thread), a_queue);
|
||||
gst_bin_add (GST_BIN (a_thread), audiosink);
|
||||
gst_bin_add (GST_BIN (v_thread), v_queue);
|
||||
gst_bin_add (GST_BIN (v_thread), videosink);
|
||||
gst_bin_add (GST_BIN (pipeline), a_thread);
|
||||
gst_bin_add (GST_BIN (pipeline), v_thread);
|
||||
|
||||
gst_element_link (src, decoder);
|
||||
gst_element_link (v_queue, videosink);
|
||||
gst_element_link (decoder, v_queue);
|
||||
gst_element_link (a_queue, audiosink);
|
||||
gst_element_link (decoder, a_queue);
|
||||
|
||||
seekable_elements = g_list_prepend (seekable_elements, videosink);
|
||||
seekable_elements = g_list_prepend (seekable_elements, audiosink);
|
||||
rate_pads =
|
||||
g_list_prepend (rate_pads, gst_element_get_pad (audiosink, "sink"));
|
||||
rate_pads =
|
||||
g_list_prepend (rate_pads, gst_element_get_pad (videosink, "sink"));
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
format_value (GtkScale * scale, gdouble value)
|
||||
{
|
||||
gint64 real;
|
||||
gint64 seconds;
|
||||
gint64 subseconds;
|
||||
|
||||
real = value * duration / 100;
|
||||
seconds = (gint64) real / GST_SECOND;
|
||||
subseconds = (gint64) real / (GST_SECOND / 100);
|
||||
|
||||
return g_strdup_printf ("%02" G_GINT64_FORMAT ":%02" G_GINT64_FORMAT ":%02"
|
||||
G_GINT64_FORMAT, seconds / 60, seconds % 60, subseconds % 100);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const gchar *name;
|
||||
const GstFormat format;
|
||||
}
|
||||
seek_format;
|
||||
|
||||
static seek_format seek_formats[] = {
|
||||
{"tim", GST_FORMAT_TIME},
|
||||
{"byt", GST_FORMAT_BYTES},
|
||||
{"buf", GST_FORMAT_BUFFERS},
|
||||
{"def", GST_FORMAT_DEFAULT},
|
||||
{NULL, 0},
|
||||
};
|
||||
|
||||
G_GNUC_UNUSED static void
|
||||
query_rates (void)
|
||||
{
|
||||
GList *walk = rate_pads;
|
||||
|
||||
while (walk) {
|
||||
GstPad *pad = GST_PAD (walk->data);
|
||||
gint i = 0;
|
||||
|
||||
g_print ("rate/sec %8.8s: ", GST_PAD_NAME (pad));
|
||||
while (seek_formats[i].name) {
|
||||
gint64 value;
|
||||
GstFormat format;
|
||||
|
||||
format = seek_formats[i].format;
|
||||
|
||||
if (gst_pad_convert (pad, GST_FORMAT_TIME, GST_SECOND, &format, &value)) {
|
||||
g_print ("%s %13" G_GINT64_FORMAT " | ", seek_formats[i].name, value);
|
||||
} else {
|
||||
g_print ("%s %13.13s | ", seek_formats[i].name, "*NA*");
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
g_print (" %s:%s\n", GST_DEBUG_PAD_NAME (pad));
|
||||
|
||||
walk = g_list_next (walk);
|
||||
}
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static void
|
||||
query_durations ()
|
||||
{
|
||||
GList *walk = seekable_elements;
|
||||
|
||||
while (walk) {
|
||||
GstElement *element = GST_ELEMENT (walk->data);
|
||||
gint i = 0;
|
||||
|
||||
g_print ("durations %8.8s: ", GST_ELEMENT_NAME (element));
|
||||
while (seek_formats[i].name) {
|
||||
gboolean res;
|
||||
gint64 value;
|
||||
GstFormat format;
|
||||
|
||||
format = seek_formats[i].format;
|
||||
res = gst_element_query (element, GST_QUERY_TOTAL, &format, &value);
|
||||
if (res) {
|
||||
g_print ("%s %13" G_GINT64_FORMAT " | ", seek_formats[i].name, value);
|
||||
} else {
|
||||
g_print ("%s %13.13s | ", seek_formats[i].name, "*NA*");
|
||||
}
|
||||
i++;
|
||||
}
|
||||
g_print (" %s\n", GST_ELEMENT_NAME (element));
|
||||
walk = g_list_next (walk);
|
||||
}
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static void
|
||||
query_positions ()
|
||||
{
|
||||
GList *walk = seekable_elements;
|
||||
|
||||
while (walk) {
|
||||
GstElement *element = GST_ELEMENT (walk->data);
|
||||
gint i = 0;
|
||||
|
||||
g_print ("positions %8.8s: ", GST_ELEMENT_NAME (element));
|
||||
while (seek_formats[i].name) {
|
||||
gboolean res;
|
||||
gint64 value;
|
||||
GstFormat format;
|
||||
|
||||
format = seek_formats[i].format;
|
||||
res = gst_element_query (element, GST_QUERY_POSITION, &format, &value);
|
||||
if (res) {
|
||||
g_print ("%s %13" G_GINT64_FORMAT " | ", seek_formats[i].name, value);
|
||||
} else {
|
||||
g_print ("%s %13.13s | ", seek_formats[i].name, "*NA*");
|
||||
}
|
||||
i++;
|
||||
}
|
||||
g_print (" %s\n", GST_ELEMENT_NAME (element));
|
||||
walk = g_list_next (walk);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
update_scale (gpointer data)
|
||||
{
|
||||
GstClock *clock;
|
||||
guint64 position;
|
||||
GstFormat format = GST_FORMAT_TIME;
|
||||
|
||||
duration = 0;
|
||||
clock = gst_bin_get_clock (GST_BIN (pipeline));
|
||||
|
||||
if (seekable_elements) {
|
||||
GstElement *element = GST_ELEMENT (seekable_elements->data);
|
||||
|
||||
gst_element_query (element, GST_QUERY_TOTAL, &format, &duration);
|
||||
}
|
||||
position = gst_clock_get_time (clock);
|
||||
|
||||
if (stats) {
|
||||
g_print ("clock: %13" G_GUINT64_FORMAT " (%s)\n",
|
||||
position, gst_object_get_name (GST_OBJECT (clock)));
|
||||
query_durations ();
|
||||
query_positions ();
|
||||
query_rates ();
|
||||
}
|
||||
if (duration > 0) {
|
||||
gtk_adjustment_set_value (adjustment, position * 100.0 / duration);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
iterate (gpointer data)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
|
||||
res = gst_bin_iterate (GST_BIN (data));
|
||||
if (!res) {
|
||||
gtk_timeout_remove (update_id);
|
||||
g_print ("stopping iterations\n");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
start_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
||||
{
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
gtk_timeout_remove (update_id);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
||||
{
|
||||
gint64 real = gtk_range_get_value (GTK_RANGE (widget)) * duration / 100;
|
||||
gboolean res;
|
||||
GstEvent *s_event;
|
||||
GList *walk = seekable_elements;
|
||||
|
||||
while (walk) {
|
||||
GstElement *seekable = GST_ELEMENT (walk->data);
|
||||
|
||||
g_print ("seek to %" G_GINT64_FORMAT " on element %s\n", real,
|
||||
GST_ELEMENT_NAME (seekable));
|
||||
s_event =
|
||||
gst_event_new_seek (GST_FORMAT_TIME | GST_SEEK_METHOD_SET |
|
||||
GST_SEEK_FLAG_FLUSH, real);
|
||||
|
||||
res = gst_element_send_event (seekable, s_event);
|
||||
|
||||
walk = g_list_next (walk);
|
||||
}
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
if (!GST_FLAG_IS_SET (pipeline, GST_BIN_SELF_SCHEDULABLE))
|
||||
gtk_idle_add ((GtkFunction) iterate, pipeline);
|
||||
update_id =
|
||||
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
play_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_PLAYING) {
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
if (!GST_FLAG_IS_SET (pipeline, GST_BIN_SELF_SCHEDULABLE))
|
||||
gtk_idle_add ((GtkFunction) iterate, pipeline);
|
||||
update_id =
|
||||
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pause_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_PAUSED) {
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
gtk_timeout_remove (update_id);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
stop_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_READY) {
|
||||
gst_element_set_state (pipeline, GST_STATE_READY);
|
||||
gtk_timeout_remove (update_id);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
GtkWidget *window, *hbox, *vbox,
|
||||
*play_button, *pause_button, *stop_button, *hscale;
|
||||
gboolean threaded = FALSE;
|
||||
struct poptOption options[] = {
|
||||
{"threaded", 't', POPT_ARG_NONE | POPT_ARGFLAG_STRIP, &threaded, 0,
|
||||
"Run the pipeline in a toplevel thread", NULL},
|
||||
{"stats", 's', POPT_ARG_NONE | POPT_ARGFLAG_STRIP, &stats, 0,
|
||||
"Show element stats", NULL},
|
||||
POPT_TABLEEND
|
||||
};
|
||||
|
||||
gst_init_with_popt_table (&argc, &argv, options);
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
if (argc != 2) {
|
||||
g_print ("usage: %s <filename>\n", argv[0]);
|
||||
exit (-1);
|
||||
}
|
||||
|
||||
pipeline = make_spider_pipeline (argv[1], threaded);
|
||||
|
||||
/* initialize gui elements ... */
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
hbox = gtk_hbox_new (FALSE, 0);
|
||||
vbox = gtk_vbox_new (FALSE, 0);
|
||||
play_button = gtk_button_new_with_label ("play");
|
||||
pause_button = gtk_button_new_with_label ("pause");
|
||||
stop_button = gtk_button_new_with_label ("stop");
|
||||
|
||||
adjustment =
|
||||
GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.00, 100.0, 0.1, 1.0, 1.0));
|
||||
hscale = gtk_hscale_new (adjustment);
|
||||
gtk_scale_set_digits (GTK_SCALE (hscale), 2);
|
||||
gtk_range_set_update_policy (GTK_RANGE (hscale), GTK_UPDATE_CONTINUOUS);
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (hscale),
|
||||
"button_press_event", G_CALLBACK (start_seek), pipeline);
|
||||
gtk_signal_connect (GTK_OBJECT (hscale),
|
||||
"button_release_event", G_CALLBACK (stop_seek), pipeline);
|
||||
gtk_signal_connect (GTK_OBJECT (hscale),
|
||||
"format_value", G_CALLBACK (format_value), pipeline);
|
||||
|
||||
/* do the packing stuff ... */
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 96, 96);
|
||||
gtk_container_add (GTK_CONTAINER (window), vbox);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), hbox);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), play_button, FALSE, FALSE, 2);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), pause_button, FALSE, FALSE, 2);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), stop_button, FALSE, FALSE, 2);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), hscale, TRUE, TRUE, 2);
|
||||
|
||||
/* connect things ... */
|
||||
g_signal_connect (G_OBJECT (play_button), "clicked", G_CALLBACK (play_cb),
|
||||
pipeline);
|
||||
g_signal_connect (G_OBJECT (pause_button), "clicked", G_CALLBACK (pause_cb),
|
||||
pipeline);
|
||||
g_signal_connect (G_OBJECT (stop_button), "clicked", G_CALLBACK (stop_cb),
|
||||
pipeline);
|
||||
g_signal_connect (G_OBJECT (window), "delete_event", gtk_main_quit, NULL);
|
||||
|
||||
/* show the gui. */
|
||||
gtk_widget_show_all (window);
|
||||
|
||||
gtk_main ();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,266 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <gst/gst.h>
|
||||
#include <string.h>
|
||||
|
||||
static gboolean ready = FALSE;
|
||||
|
||||
struct probe_context
|
||||
{
|
||||
GstElement *pipeline;
|
||||
GstElement *element;
|
||||
GstPad *pad;
|
||||
GstFormat ls_format;
|
||||
|
||||
gint total_ls;
|
||||
|
||||
GstCaps *metadata;
|
||||
GstCaps *streaminfo;
|
||||
GstCaps *caps;
|
||||
};
|
||||
|
||||
static void
|
||||
print_caps (GstCaps * caps)
|
||||
{
|
||||
char *s;
|
||||
|
||||
s = gst_caps_to_string (caps);
|
||||
g_print (" %s\n", s);
|
||||
g_free (s);
|
||||
}
|
||||
|
||||
static void
|
||||
print_format (GstCaps * caps)
|
||||
{
|
||||
char *s;
|
||||
|
||||
s = gst_caps_to_string (caps);
|
||||
g_print (" format: %s\n", s);
|
||||
g_free (s);
|
||||
}
|
||||
|
||||
static void
|
||||
print_lbs_info (struct probe_context *context, gint stream)
|
||||
{
|
||||
const GstFormat *formats;
|
||||
|
||||
/* FIXME: need a better name here */
|
||||
g_print (" stream info:\n");
|
||||
|
||||
/* report info in all supported formats */
|
||||
formats = gst_pad_get_formats (context->pad);
|
||||
while (*formats) {
|
||||
const GstFormatDefinition *definition;
|
||||
gint64 value_start, value_end;
|
||||
gboolean res;
|
||||
GstFormat format;
|
||||
|
||||
format = *formats;
|
||||
formats++;
|
||||
|
||||
if (format == context->ls_format) {
|
||||
continue;
|
||||
}
|
||||
|
||||
definition = gst_format_get_details (format);
|
||||
|
||||
/* get start and end position of this stream */
|
||||
res = gst_pad_convert (context->pad,
|
||||
context->ls_format, stream, &format, &value_start);
|
||||
res &= gst_pad_convert (context->pad,
|
||||
context->ls_format, stream + 1, &format, &value_end);
|
||||
|
||||
if (res) {
|
||||
/* substract to get the length */
|
||||
value_end -= value_start;
|
||||
|
||||
if (format == GST_FORMAT_TIME) {
|
||||
value_end /= (GST_SECOND / 100);
|
||||
g_print (" %s: %" G_GINT64_FORMAT ":%02" G_GINT64_FORMAT ".%02"
|
||||
G_GINT64_FORMAT "\n", definition->nick, value_end / 6000,
|
||||
(value_end / 100) % 60, (value_end % 100));
|
||||
} else {
|
||||
g_print (" %s: %" G_GINT64_FORMAT "\n", definition->nick, value_end);
|
||||
}
|
||||
} else
|
||||
g_print (" could not get logical stream %s\n", definition->nick);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
deep_notify (GObject * object, GstObject * origin,
|
||||
GParamSpec * pspec, gpointer data)
|
||||
{
|
||||
struct probe_context *context = (struct probe_context *) data;
|
||||
GValue value = { 0, };
|
||||
|
||||
if (!strcmp (pspec->name, "metadata")) {
|
||||
|
||||
g_value_init (&value, pspec->value_type);
|
||||
g_object_get_property (G_OBJECT (origin), pspec->name, &value);
|
||||
context->metadata = g_value_peek_pointer (&value);
|
||||
} else if (!strcmp (pspec->name, "streaminfo")) {
|
||||
|
||||
g_value_init (&value, pspec->value_type);
|
||||
g_object_get_property (G_OBJECT (origin), pspec->name, &value);
|
||||
context->streaminfo = g_value_peek_pointer (&value);
|
||||
} else if (!strcmp (pspec->name, "caps")) {
|
||||
if (GST_IS_PAD (origin) && GST_PAD (origin) == context->pad) {
|
||||
g_value_init (&value, pspec->value_type);
|
||||
g_object_get_property (G_OBJECT (origin), pspec->name, &value);
|
||||
context->caps = g_value_peek_pointer (&value);
|
||||
|
||||
ready = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
collect_logical_stream_properties (struct probe_context *context, gint stream)
|
||||
{
|
||||
GstEvent *event;
|
||||
gboolean res;
|
||||
gint count;
|
||||
|
||||
g_print ("info for logical stream %d:\n", stream);
|
||||
|
||||
/* seek to stream */
|
||||
event = gst_event_new_seek (context->ls_format |
|
||||
GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH, stream);
|
||||
res = gst_pad_send_event (context->pad, event);
|
||||
if (!res) {
|
||||
g_warning ("seek to logical track failed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* run the pipeline to get the info */
|
||||
count = 0;
|
||||
ready = FALSE;
|
||||
while (gst_bin_iterate (GST_BIN (context->pipeline)) && !ready) {
|
||||
count++;
|
||||
if (count > 10)
|
||||
break;
|
||||
}
|
||||
|
||||
print_caps (context->metadata);
|
||||
print_caps (context->streaminfo);
|
||||
print_format (context->caps);
|
||||
print_lbs_info (context, stream);
|
||||
|
||||
g_print ("\n");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
collect_stream_properties (struct probe_context *context)
|
||||
{
|
||||
const GstFormat *formats;
|
||||
|
||||
ready = FALSE;
|
||||
while (gst_bin_iterate (GST_BIN (context->pipeline)) && !ready);
|
||||
|
||||
g_print ("stream info:\n");
|
||||
|
||||
context->total_ls = -1;
|
||||
|
||||
/* report info in all supported formats */
|
||||
formats = gst_pad_get_formats (context->pad);
|
||||
while (*formats) {
|
||||
const GstFormatDefinition *definition;
|
||||
gint64 value;
|
||||
gboolean res;
|
||||
GstFormat format;
|
||||
|
||||
format = *formats;
|
||||
formats++;
|
||||
|
||||
res = gst_pad_query (context->pad, GST_QUERY_TOTAL, &format, &value);
|
||||
|
||||
definition = gst_format_get_details (format);
|
||||
|
||||
if (res) {
|
||||
if (format == GST_FORMAT_TIME) {
|
||||
value /= (GST_SECOND / 100);
|
||||
g_print (" total %s: %" G_GINT64_FORMAT ":%02" G_GINT64_FORMAT ".%02"
|
||||
G_GINT64_FORMAT "\n", definition->nick, value / 6000,
|
||||
(value / 100) % 60, (value % 100));
|
||||
} else {
|
||||
if (format == context->ls_format)
|
||||
context->total_ls = value;
|
||||
g_print (" total %s: %" G_GINT64_FORMAT "\n", definition->nick, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (context->total_ls == -1) {
|
||||
g_warning (" could not get number of logical streams");
|
||||
}
|
||||
g_print ("\n");
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
GstElement *pipeline;
|
||||
GstElement *filesrc;
|
||||
GstElement *vorbisfile;
|
||||
GstPad *pad;
|
||||
GstFormat logical_stream_format;
|
||||
struct probe_context *context;
|
||||
gint stream;
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
if (argc < 2) {
|
||||
g_print ("usage: %s <oggfile>\n", argv[0]);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
pipeline = gst_pipeline_new ("pipeline");
|
||||
|
||||
filesrc = gst_element_factory_make ("filesrc", "filesrc");
|
||||
g_assert (filesrc);
|
||||
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
|
||||
|
||||
vorbisfile = gst_element_factory_make ("vorbisfile", "vorbisfile");
|
||||
//vorbisfile = gst_element_factory_make ("mad", "vorbisfile");
|
||||
g_assert (vorbisfile);
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), filesrc);
|
||||
gst_bin_add (GST_BIN (pipeline), vorbisfile);
|
||||
|
||||
gst_element_link_pads (filesrc, "src", vorbisfile, "sink");
|
||||
|
||||
pad = gst_element_get_pad (vorbisfile, "src");
|
||||
g_assert (pad);
|
||||
|
||||
logical_stream_format = gst_format_get_by_nick ("logical_stream");
|
||||
g_assert (logical_stream_format != 0);
|
||||
|
||||
context = g_new0 (struct probe_context, 1);
|
||||
context->pipeline = pipeline;
|
||||
context->element = vorbisfile;
|
||||
context->pad = pad;
|
||||
context->ls_format = logical_stream_format;
|
||||
|
||||
g_signal_connect (G_OBJECT (pipeline), "deep_notify",
|
||||
G_CALLBACK (deep_notify), context);
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
||||
/* at this point we can inspect the stream */
|
||||
collect_stream_properties (context);
|
||||
|
||||
/* loop over all logical streams to get info */
|
||||
stream = 0;
|
||||
while (stream < context->total_ls) {
|
||||
collect_logical_stream_properties (context, stream);
|
||||
stream++;
|
||||
}
|
||||
|
||||
/* stop probe */
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
examples = seek spider_seek cdplayer cdparanoia vorbisfile playbin chained
|
||||
examples = seek cdplayer cdparanoia
|
||||
|
||||
noinst_PROGRAMS = $(examples)
|
||||
|
||||
|
|
|
@ -159,7 +159,7 @@ main (int argc, char **argv)
|
|||
gst_element_link_pads (cdparanoia, "src", audiosink, "sink");
|
||||
|
||||
g_signal_connect (G_OBJECT (pipeline), "deep_notify",
|
||||
G_CALLBACK (gst_element_default_deep_notify), NULL);
|
||||
G_CALLBACK (gst_object_default_deep_notify), NULL);
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
|
||||
|
@ -184,10 +184,9 @@ main (int argc, char **argv)
|
|||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
||||
count = 0;
|
||||
while (gst_bin_iterate (GST_BIN (pipeline))) {
|
||||
while (count++ < 500) {
|
||||
get_position_info (cdparanoia);
|
||||
if (count++ > 500)
|
||||
break;
|
||||
g_usleep (G_USEC_PER_SEC / 2);
|
||||
}
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
|
||||
|
@ -202,8 +201,10 @@ main (int argc, char **argv)
|
|||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
||||
while (gst_bin_iterate (GST_BIN (pipeline))) {
|
||||
count = 0;
|
||||
while (count++ < 500) {
|
||||
get_position_info (cdparanoia);
|
||||
g_usleep (G_USEC_PER_SEC / 2);
|
||||
}
|
||||
g_print ("\n");
|
||||
|
||||
|
|
|
@ -125,7 +125,7 @@ update_scale (gpointer data)
|
|||
GstFormat format = GST_FORMAT_TIME;
|
||||
|
||||
duration = 0;
|
||||
clock = gst_bin_get_clock (GST_BIN (pipeline));
|
||||
clock = gst_pipeline_get_clock (GST_PIPELINE (pipeline));
|
||||
|
||||
if (seekable_elements) {
|
||||
GstElement *element = GST_ELEMENT (seekable_elements->data);
|
||||
|
@ -148,20 +148,6 @@ update_scale (gpointer data)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
iterate (gpointer data)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
|
||||
g_print ("iterate\n");
|
||||
res = gst_bin_iterate (GST_BIN (data));
|
||||
if (!res) {
|
||||
gtk_timeout_remove (update_id);
|
||||
g_print ("stopping iterations\n");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
start_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
||||
{
|
||||
|
@ -194,8 +180,6 @@ stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
|||
}
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
if (!GST_FLAG_IS_SET (pipeline, GST_BIN_SELF_SCHEDULABLE))
|
||||
gtk_idle_add ((GtkFunction) iterate, pipeline);
|
||||
update_id =
|
||||
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
|
||||
|
||||
|
@ -205,10 +189,11 @@ stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
|||
static void
|
||||
play_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_PLAYING) {
|
||||
GstElementState state;
|
||||
|
||||
gst_element_get_state (pipeline, &state, NULL, NULL);
|
||||
if (state != GST_STATE_PLAYING) {
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
if (!GST_FLAG_IS_SET (pipeline, GST_BIN_SELF_SCHEDULABLE))
|
||||
gtk_idle_add ((GtkFunction) iterate, pipeline);
|
||||
update_id =
|
||||
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
|
||||
}
|
||||
|
@ -217,7 +202,10 @@ play_cb (GtkButton * button, gpointer data)
|
|||
static void
|
||||
pause_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_PAUSED) {
|
||||
GstElementState state;
|
||||
|
||||
gst_element_get_state (pipeline, &state, NULL, NULL);
|
||||
if (state != GST_STATE_PAUSED) {
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
gtk_timeout_remove (update_id);
|
||||
}
|
||||
|
@ -226,7 +214,10 @@ pause_cb (GtkButton * button, gpointer data)
|
|||
static void
|
||||
stop_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_READY) {
|
||||
GstElementState state;
|
||||
|
||||
gst_element_get_state (pipeline, &state, NULL, NULL);
|
||||
if (state != GST_STATE_READY) {
|
||||
gst_element_set_state (pipeline, GST_STATE_READY);
|
||||
gtk_timeout_remove (update_id);
|
||||
}
|
||||
|
@ -249,9 +240,7 @@ main (int argc, char **argv)
|
|||
pipeline = make_cdaudio_pipeline ();
|
||||
|
||||
g_signal_connect (pipeline, "deep_notify",
|
||||
G_CALLBACK (gst_element_default_deep_notify), NULL);
|
||||
g_signal_connect (pipeline, "error", G_CALLBACK (gst_element_default_error),
|
||||
NULL);
|
||||
G_CALLBACK (gst_object_default_deep_notify), NULL);
|
||||
|
||||
/* initialize gui elements ... */
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
|
|
|
@ -1,270 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gst/gst.h>
|
||||
#include <string.h>
|
||||
|
||||
static GstElement *playbin = NULL;
|
||||
static GstElement *pipeline;
|
||||
static guint64 duration;
|
||||
static GtkAdjustment *adjustment;
|
||||
static GtkWidget *hscale;
|
||||
static gboolean verbose = FALSE;
|
||||
|
||||
static guint update_id;
|
||||
|
||||
#define UPDATE_INTERVAL 500
|
||||
|
||||
static GstElement *
|
||||
make_playerbin_pipeline (const gchar * location)
|
||||
{
|
||||
playbin = gst_element_factory_make ("playbin", "player");
|
||||
g_assert (playbin);
|
||||
|
||||
g_object_set (G_OBJECT (playbin), "uri", location, NULL);
|
||||
|
||||
return playbin;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
format_value (GtkScale * scale, gdouble value)
|
||||
{
|
||||
gint64 real;
|
||||
gint64 seconds;
|
||||
gint64 subseconds;
|
||||
|
||||
real = value * duration / 100;
|
||||
seconds = (gint64) real / GST_SECOND;
|
||||
subseconds = (gint64) real / (GST_SECOND / 100);
|
||||
|
||||
return g_strdup_printf ("%02" G_GINT64_FORMAT ":%02" G_GINT64_FORMAT ":%02"
|
||||
G_GINT64_FORMAT, seconds / 60, seconds % 60, subseconds % 100);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
update_scale (gpointer data)
|
||||
{
|
||||
GstClock *clock;
|
||||
guint64 position;
|
||||
GstFormat format = GST_FORMAT_TIME;
|
||||
gboolean res;
|
||||
|
||||
duration = 0;
|
||||
clock = gst_bin_get_clock (GST_BIN (pipeline));
|
||||
|
||||
res = gst_element_query (playbin, GST_QUERY_TOTAL, &format, &duration);
|
||||
if (!res)
|
||||
duration = 0;
|
||||
res = gst_element_query (playbin, GST_QUERY_POSITION, &format, &position);
|
||||
if (!res)
|
||||
position = 0;
|
||||
|
||||
if (position >= duration)
|
||||
duration = position;
|
||||
|
||||
if (duration > 0) {
|
||||
gtk_adjustment_set_value (adjustment, position * 100.0 / duration);
|
||||
gtk_widget_queue_draw (hscale);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
iterate (gpointer data)
|
||||
{
|
||||
gboolean res;
|
||||
|
||||
if (!GST_FLAG_IS_SET (GST_OBJECT (data), GST_BIN_SELF_SCHEDULABLE)) {
|
||||
res = gst_bin_iterate (GST_BIN (data));
|
||||
} else {
|
||||
g_usleep (UPDATE_INTERVAL);
|
||||
res = gst_element_get_state (GST_ELEMENT (data)) == GST_STATE_PLAYING;
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
gtk_timeout_remove (update_id);
|
||||
g_print ("stopping iterations\n");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
start_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
||||
{
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
gtk_timeout_remove (update_id);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
||||
{
|
||||
gint64 real = gtk_range_get_value (GTK_RANGE (widget)) * duration / 100;
|
||||
gboolean res;
|
||||
GstEvent *s_event;
|
||||
|
||||
g_print ("seek to %" G_GINT64_FORMAT " on element %s\n", real,
|
||||
gst_element_get_name (playbin));
|
||||
s_event =
|
||||
gst_event_new_seek (GST_FORMAT_TIME | GST_SEEK_METHOD_SET |
|
||||
GST_SEEK_FLAG_FLUSH, real);
|
||||
|
||||
res = gst_element_send_event (playbin, s_event);
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
gtk_idle_add ((GtkFunction) iterate, pipeline);
|
||||
update_id =
|
||||
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
print_media_info (GstElement * playbin)
|
||||
{
|
||||
GList *streaminfo;
|
||||
GList *s;
|
||||
|
||||
g_print ("have media info now\n");
|
||||
|
||||
/* get info about the stream */
|
||||
g_object_get (G_OBJECT (playbin), "stream-info", &streaminfo, NULL);
|
||||
|
||||
for (s = streaminfo; s; s = g_list_next (s)) {
|
||||
GObject *obj = G_OBJECT (s->data);
|
||||
gint type;
|
||||
gboolean mute;
|
||||
|
||||
g_object_get (obj, "type", &type, NULL);
|
||||
g_object_get (obj, "mute", &mute, NULL);
|
||||
|
||||
g_print ("%d %d\n", type, mute);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
play_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_PLAYING) {
|
||||
GstElementStateReturn res;
|
||||
|
||||
res = gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
if (res == GST_STATE_SUCCESS) {
|
||||
print_media_info (playbin);
|
||||
|
||||
res = gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
gtk_idle_add ((GtkFunction) iterate, pipeline);
|
||||
update_id =
|
||||
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale,
|
||||
pipeline);
|
||||
} else {
|
||||
g_print ("failed playing\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pause_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_PAUSED) {
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
gtk_timeout_remove (update_id);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
stop_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_READY) {
|
||||
gst_element_set_state (pipeline, GST_STATE_READY);
|
||||
gtk_adjustment_set_value (adjustment, 0.0);
|
||||
gtk_timeout_remove (update_id);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_usage (int argc, char **argv)
|
||||
{
|
||||
g_print ("usage: %s <uri>\n", argv[0]);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
GtkWidget *window, *hbox, *vbox, *play_button, *pause_button, *stop_button;
|
||||
struct poptOption options[] = {
|
||||
{"verbose", 'v', POPT_ARG_NONE | POPT_ARGFLAG_STRIP, &verbose, 0,
|
||||
"Verbose properties", NULL},
|
||||
POPT_TABLEEND
|
||||
};
|
||||
|
||||
gst_init_with_popt_table (&argc, &argv, options);
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
if (argc != 2) {
|
||||
print_usage (argc, argv);
|
||||
exit (-1);
|
||||
}
|
||||
|
||||
pipeline = make_playerbin_pipeline (argv[1]);
|
||||
g_assert (pipeline);
|
||||
|
||||
/* initialize gui elements ... */
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
hbox = gtk_hbox_new (FALSE, 0);
|
||||
vbox = gtk_vbox_new (FALSE, 0);
|
||||
play_button = gtk_button_new_with_label ("play");
|
||||
pause_button = gtk_button_new_with_label ("pause");
|
||||
stop_button = gtk_button_new_with_label ("stop");
|
||||
|
||||
adjustment =
|
||||
GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.00, 100.0, 0.1, 1.0, 1.0));
|
||||
hscale = gtk_hscale_new (adjustment);
|
||||
gtk_scale_set_digits (GTK_SCALE (hscale), 2);
|
||||
gtk_range_set_update_policy (GTK_RANGE (hscale), GTK_UPDATE_CONTINUOUS);
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (hscale),
|
||||
"button_press_event", G_CALLBACK (start_seek), pipeline);
|
||||
gtk_signal_connect (GTK_OBJECT (hscale),
|
||||
"button_release_event", G_CALLBACK (stop_seek), pipeline);
|
||||
gtk_signal_connect (GTK_OBJECT (hscale),
|
||||
"format_value", G_CALLBACK (format_value), pipeline);
|
||||
|
||||
/* do the packing stuff ... */
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 96, 96);
|
||||
gtk_container_add (GTK_CONTAINER (window), vbox);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), hbox);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), play_button, FALSE, FALSE, 2);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), pause_button, FALSE, FALSE, 2);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), stop_button, FALSE, FALSE, 2);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), hscale, TRUE, TRUE, 2);
|
||||
|
||||
/* connect things ... */
|
||||
g_signal_connect (G_OBJECT (play_button), "clicked", G_CALLBACK (play_cb),
|
||||
pipeline);
|
||||
g_signal_connect (G_OBJECT (pause_button), "clicked", G_CALLBACK (pause_cb),
|
||||
pipeline);
|
||||
g_signal_connect (G_OBJECT (stop_button), "clicked", G_CALLBACK (stop_cb),
|
||||
pipeline);
|
||||
g_signal_connect (G_OBJECT (window), "delete_event", gtk_main_quit, NULL);
|
||||
|
||||
/* show the gui. */
|
||||
gtk_widget_show_all (window);
|
||||
|
||||
if (verbose) {
|
||||
g_signal_connect (pipeline, "deep_notify",
|
||||
G_CALLBACK (gst_element_default_deep_notify), NULL);
|
||||
}
|
||||
g_signal_connect (pipeline, "error", G_CALLBACK (gst_element_default_error),
|
||||
NULL);
|
||||
|
||||
gtk_main ();
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
|
||||
gst_object_unref (GST_OBJECT (pipeline));
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,379 +0,0 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gst/gst.h>
|
||||
#include <string.h>
|
||||
|
||||
static GList *rate_pads = NULL;
|
||||
static GList *seekable_elements = NULL;
|
||||
|
||||
static GstElement *pipeline;
|
||||
static GtkAdjustment *adjustment;
|
||||
static gboolean stats = FALSE;
|
||||
static guint64 duration;
|
||||
|
||||
static guint update_id;
|
||||
|
||||
//#define SOURCE "gnomevfssrc"
|
||||
#define SOURCE "filesrc"
|
||||
|
||||
#define UPDATE_INTERVAL 500
|
||||
|
||||
static GstElement *
|
||||
make_spider_pipeline (const gchar * location, gboolean thread)
|
||||
{
|
||||
GstElement *pipeline;
|
||||
GstElement *src, *decoder, *audiosink, *videosink, *a_thread, *v_thread,
|
||||
*a_queue, *v_queue;
|
||||
|
||||
if (thread) {
|
||||
pipeline = gst_thread_new ("app");
|
||||
} else {
|
||||
pipeline = gst_pipeline_new ("app");
|
||||
}
|
||||
|
||||
|
||||
src = gst_element_factory_make (SOURCE, "src");
|
||||
decoder = gst_element_factory_make ("spider", "decoder");
|
||||
a_thread = gst_thread_new ("a_thread");
|
||||
a_queue = gst_element_factory_make ("queue", "a_queue");
|
||||
audiosink = gst_element_factory_make (DEFAULT_AUDIOSINK, "a_sink");
|
||||
//g_object_set (G_OBJECT (audiosink), "fragment", 0x00180008, NULL);
|
||||
|
||||
v_thread = gst_thread_new ("v_thread");
|
||||
v_queue = gst_element_factory_make ("queue", "v_queue");
|
||||
videosink = gst_element_factory_make (DEFAULT_VIDEOSINK, "v_sink");
|
||||
//g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
|
||||
|
||||
g_object_set (G_OBJECT (src), "location", location, NULL);
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), src);
|
||||
gst_bin_add (GST_BIN (pipeline), decoder);
|
||||
gst_bin_add (GST_BIN (a_thread), a_queue);
|
||||
gst_bin_add (GST_BIN (a_thread), audiosink);
|
||||
gst_bin_add (GST_BIN (v_thread), v_queue);
|
||||
gst_bin_add (GST_BIN (v_thread), videosink);
|
||||
gst_bin_add (GST_BIN (pipeline), a_thread);
|
||||
gst_bin_add (GST_BIN (pipeline), v_thread);
|
||||
|
||||
gst_element_link (src, decoder);
|
||||
gst_element_link (v_queue, videosink);
|
||||
gst_element_link (decoder, v_queue);
|
||||
gst_element_link (a_queue, audiosink);
|
||||
gst_element_link (decoder, a_queue);
|
||||
|
||||
seekable_elements = g_list_prepend (seekable_elements, videosink);
|
||||
seekable_elements = g_list_prepend (seekable_elements, audiosink);
|
||||
rate_pads =
|
||||
g_list_prepend (rate_pads, gst_element_get_pad (audiosink, "sink"));
|
||||
rate_pads =
|
||||
g_list_prepend (rate_pads, gst_element_get_pad (videosink, "sink"));
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
format_value (GtkScale * scale, gdouble value)
|
||||
{
|
||||
gint64 real;
|
||||
gint64 seconds;
|
||||
gint64 subseconds;
|
||||
|
||||
real = value * duration / 100;
|
||||
seconds = (gint64) real / GST_SECOND;
|
||||
subseconds = (gint64) real / (GST_SECOND / 100);
|
||||
|
||||
return g_strdup_printf ("%02" G_GINT64_FORMAT ":%02" G_GINT64_FORMAT ":%02"
|
||||
G_GINT64_FORMAT, seconds / 60, seconds % 60, subseconds % 100);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const gchar *name;
|
||||
const GstFormat format;
|
||||
}
|
||||
seek_format;
|
||||
|
||||
static seek_format seek_formats[] = {
|
||||
{"tim", GST_FORMAT_TIME},
|
||||
{"byt", GST_FORMAT_BYTES},
|
||||
{"buf", GST_FORMAT_BUFFERS},
|
||||
{"def", GST_FORMAT_DEFAULT},
|
||||
{NULL, 0},
|
||||
};
|
||||
|
||||
G_GNUC_UNUSED static void
|
||||
query_rates (void)
|
||||
{
|
||||
GList *walk = rate_pads;
|
||||
|
||||
while (walk) {
|
||||
GstPad *pad = GST_PAD (walk->data);
|
||||
gint i = 0;
|
||||
|
||||
g_print ("rate/sec %8.8s: ", GST_PAD_NAME (pad));
|
||||
while (seek_formats[i].name) {
|
||||
gint64 value;
|
||||
GstFormat format;
|
||||
|
||||
format = seek_formats[i].format;
|
||||
|
||||
if (gst_pad_convert (pad, GST_FORMAT_TIME, GST_SECOND, &format, &value)) {
|
||||
g_print ("%s %13" G_GINT64_FORMAT " | ", seek_formats[i].name, value);
|
||||
} else {
|
||||
g_print ("%s %13.13s | ", seek_formats[i].name, "*NA*");
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
g_print (" %s:%s\n", GST_DEBUG_PAD_NAME (pad));
|
||||
|
||||
walk = g_list_next (walk);
|
||||
}
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static void
|
||||
query_durations ()
|
||||
{
|
||||
GList *walk = seekable_elements;
|
||||
|
||||
while (walk) {
|
||||
GstElement *element = GST_ELEMENT (walk->data);
|
||||
gint i = 0;
|
||||
|
||||
g_print ("durations %8.8s: ", GST_ELEMENT_NAME (element));
|
||||
while (seek_formats[i].name) {
|
||||
gboolean res;
|
||||
gint64 value;
|
||||
GstFormat format;
|
||||
|
||||
format = seek_formats[i].format;
|
||||
res = gst_element_query (element, GST_QUERY_TOTAL, &format, &value);
|
||||
if (res) {
|
||||
g_print ("%s %13" G_GINT64_FORMAT " | ", seek_formats[i].name, value);
|
||||
} else {
|
||||
g_print ("%s %13.13s | ", seek_formats[i].name, "*NA*");
|
||||
}
|
||||
i++;
|
||||
}
|
||||
g_print (" %s\n", GST_ELEMENT_NAME (element));
|
||||
walk = g_list_next (walk);
|
||||
}
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static void
|
||||
query_positions ()
|
||||
{
|
||||
GList *walk = seekable_elements;
|
||||
|
||||
while (walk) {
|
||||
GstElement *element = GST_ELEMENT (walk->data);
|
||||
gint i = 0;
|
||||
|
||||
g_print ("positions %8.8s: ", GST_ELEMENT_NAME (element));
|
||||
while (seek_formats[i].name) {
|
||||
gboolean res;
|
||||
gint64 value;
|
||||
GstFormat format;
|
||||
|
||||
format = seek_formats[i].format;
|
||||
res = gst_element_query (element, GST_QUERY_POSITION, &format, &value);
|
||||
if (res) {
|
||||
g_print ("%s %13" G_GINT64_FORMAT " | ", seek_formats[i].name, value);
|
||||
} else {
|
||||
g_print ("%s %13.13s | ", seek_formats[i].name, "*NA*");
|
||||
}
|
||||
i++;
|
||||
}
|
||||
g_print (" %s\n", GST_ELEMENT_NAME (element));
|
||||
walk = g_list_next (walk);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
update_scale (gpointer data)
|
||||
{
|
||||
GstClock *clock;
|
||||
guint64 position;
|
||||
GstFormat format = GST_FORMAT_TIME;
|
||||
|
||||
duration = 0;
|
||||
clock = gst_bin_get_clock (GST_BIN (pipeline));
|
||||
|
||||
if (seekable_elements) {
|
||||
GstElement *element = GST_ELEMENT (seekable_elements->data);
|
||||
|
||||
gst_element_query (element, GST_QUERY_TOTAL, &format, &duration);
|
||||
}
|
||||
position = gst_clock_get_time (clock);
|
||||
|
||||
if (stats) {
|
||||
g_print ("clock: %13" G_GUINT64_FORMAT " (%s)\n",
|
||||
position, gst_object_get_name (GST_OBJECT (clock)));
|
||||
query_durations ();
|
||||
query_positions ();
|
||||
query_rates ();
|
||||
}
|
||||
if (duration > 0) {
|
||||
gtk_adjustment_set_value (adjustment, position * 100.0 / duration);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
iterate (gpointer data)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
|
||||
res = gst_bin_iterate (GST_BIN (data));
|
||||
if (!res) {
|
||||
gtk_timeout_remove (update_id);
|
||||
g_print ("stopping iterations\n");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
start_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
||||
{
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
gtk_timeout_remove (update_id);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
stop_seek (GtkWidget * widget, GdkEventButton * event, gpointer user_data)
|
||||
{
|
||||
gint64 real = gtk_range_get_value (GTK_RANGE (widget)) * duration / 100;
|
||||
gboolean res;
|
||||
GstEvent *s_event;
|
||||
GList *walk = seekable_elements;
|
||||
|
||||
while (walk) {
|
||||
GstElement *seekable = GST_ELEMENT (walk->data);
|
||||
|
||||
g_print ("seek to %" G_GINT64_FORMAT " on element %s\n", real,
|
||||
GST_ELEMENT_NAME (seekable));
|
||||
s_event =
|
||||
gst_event_new_seek (GST_FORMAT_TIME | GST_SEEK_METHOD_SET |
|
||||
GST_SEEK_FLAG_FLUSH, real);
|
||||
|
||||
res = gst_element_send_event (seekable, s_event);
|
||||
|
||||
walk = g_list_next (walk);
|
||||
}
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
if (!GST_FLAG_IS_SET (pipeline, GST_BIN_SELF_SCHEDULABLE))
|
||||
gtk_idle_add ((GtkFunction) iterate, pipeline);
|
||||
update_id =
|
||||
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
play_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_PLAYING) {
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
if (!GST_FLAG_IS_SET (pipeline, GST_BIN_SELF_SCHEDULABLE))
|
||||
gtk_idle_add ((GtkFunction) iterate, pipeline);
|
||||
update_id =
|
||||
gtk_timeout_add (UPDATE_INTERVAL, (GtkFunction) update_scale, pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pause_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_PAUSED) {
|
||||
gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
gtk_timeout_remove (update_id);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
stop_cb (GtkButton * button, gpointer data)
|
||||
{
|
||||
if (gst_element_get_state (pipeline) != GST_STATE_READY) {
|
||||
gst_element_set_state (pipeline, GST_STATE_READY);
|
||||
gtk_timeout_remove (update_id);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
GtkWidget *window, *hbox, *vbox,
|
||||
*play_button, *pause_button, *stop_button, *hscale;
|
||||
gboolean threaded = FALSE;
|
||||
struct poptOption options[] = {
|
||||
{"threaded", 't', POPT_ARG_NONE | POPT_ARGFLAG_STRIP, &threaded, 0,
|
||||
"Run the pipeline in a toplevel thread", NULL},
|
||||
{"stats", 's', POPT_ARG_NONE | POPT_ARGFLAG_STRIP, &stats, 0,
|
||||
"Show element stats", NULL},
|
||||
POPT_TABLEEND
|
||||
};
|
||||
|
||||
gst_init_with_popt_table (&argc, &argv, options);
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
if (argc != 2) {
|
||||
g_print ("usage: %s <filename>\n", argv[0]);
|
||||
exit (-1);
|
||||
}
|
||||
|
||||
pipeline = make_spider_pipeline (argv[1], threaded);
|
||||
|
||||
/* initialize gui elements ... */
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
hbox = gtk_hbox_new (FALSE, 0);
|
||||
vbox = gtk_vbox_new (FALSE, 0);
|
||||
play_button = gtk_button_new_with_label ("play");
|
||||
pause_button = gtk_button_new_with_label ("pause");
|
||||
stop_button = gtk_button_new_with_label ("stop");
|
||||
|
||||
adjustment =
|
||||
GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.00, 100.0, 0.1, 1.0, 1.0));
|
||||
hscale = gtk_hscale_new (adjustment);
|
||||
gtk_scale_set_digits (GTK_SCALE (hscale), 2);
|
||||
gtk_range_set_update_policy (GTK_RANGE (hscale), GTK_UPDATE_CONTINUOUS);
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (hscale),
|
||||
"button_press_event", G_CALLBACK (start_seek), pipeline);
|
||||
gtk_signal_connect (GTK_OBJECT (hscale),
|
||||
"button_release_event", G_CALLBACK (stop_seek), pipeline);
|
||||
gtk_signal_connect (GTK_OBJECT (hscale),
|
||||
"format_value", G_CALLBACK (format_value), pipeline);
|
||||
|
||||
/* do the packing stuff ... */
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 96, 96);
|
||||
gtk_container_add (GTK_CONTAINER (window), vbox);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), hbox);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), play_button, FALSE, FALSE, 2);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), pause_button, FALSE, FALSE, 2);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), stop_button, FALSE, FALSE, 2);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), hscale, TRUE, TRUE, 2);
|
||||
|
||||
/* connect things ... */
|
||||
g_signal_connect (G_OBJECT (play_button), "clicked", G_CALLBACK (play_cb),
|
||||
pipeline);
|
||||
g_signal_connect (G_OBJECT (pause_button), "clicked", G_CALLBACK (pause_cb),
|
||||
pipeline);
|
||||
g_signal_connect (G_OBJECT (stop_button), "clicked", G_CALLBACK (stop_cb),
|
||||
pipeline);
|
||||
g_signal_connect (G_OBJECT (window), "delete_event", gtk_main_quit, NULL);
|
||||
|
||||
/* show the gui. */
|
||||
gtk_widget_show_all (window);
|
||||
|
||||
gtk_main ();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,266 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <gst/gst.h>
|
||||
#include <string.h>
|
||||
|
||||
static gboolean ready = FALSE;
|
||||
|
||||
struct probe_context
|
||||
{
|
||||
GstElement *pipeline;
|
||||
GstElement *element;
|
||||
GstPad *pad;
|
||||
GstFormat ls_format;
|
||||
|
||||
gint total_ls;
|
||||
|
||||
GstCaps *metadata;
|
||||
GstCaps *streaminfo;
|
||||
GstCaps *caps;
|
||||
};
|
||||
|
||||
static void
|
||||
print_caps (GstCaps * caps)
|
||||
{
|
||||
char *s;
|
||||
|
||||
s = gst_caps_to_string (caps);
|
||||
g_print (" %s\n", s);
|
||||
g_free (s);
|
||||
}
|
||||
|
||||
static void
|
||||
print_format (GstCaps * caps)
|
||||
{
|
||||
char *s;
|
||||
|
||||
s = gst_caps_to_string (caps);
|
||||
g_print (" format: %s\n", s);
|
||||
g_free (s);
|
||||
}
|
||||
|
||||
static void
|
||||
print_lbs_info (struct probe_context *context, gint stream)
|
||||
{
|
||||
const GstFormat *formats;
|
||||
|
||||
/* FIXME: need a better name here */
|
||||
g_print (" stream info:\n");
|
||||
|
||||
/* report info in all supported formats */
|
||||
formats = gst_pad_get_formats (context->pad);
|
||||
while (*formats) {
|
||||
const GstFormatDefinition *definition;
|
||||
gint64 value_start, value_end;
|
||||
gboolean res;
|
||||
GstFormat format;
|
||||
|
||||
format = *formats;
|
||||
formats++;
|
||||
|
||||
if (format == context->ls_format) {
|
||||
continue;
|
||||
}
|
||||
|
||||
definition = gst_format_get_details (format);
|
||||
|
||||
/* get start and end position of this stream */
|
||||
res = gst_pad_convert (context->pad,
|
||||
context->ls_format, stream, &format, &value_start);
|
||||
res &= gst_pad_convert (context->pad,
|
||||
context->ls_format, stream + 1, &format, &value_end);
|
||||
|
||||
if (res) {
|
||||
/* substract to get the length */
|
||||
value_end -= value_start;
|
||||
|
||||
if (format == GST_FORMAT_TIME) {
|
||||
value_end /= (GST_SECOND / 100);
|
||||
g_print (" %s: %" G_GINT64_FORMAT ":%02" G_GINT64_FORMAT ".%02"
|
||||
G_GINT64_FORMAT "\n", definition->nick, value_end / 6000,
|
||||
(value_end / 100) % 60, (value_end % 100));
|
||||
} else {
|
||||
g_print (" %s: %" G_GINT64_FORMAT "\n", definition->nick, value_end);
|
||||
}
|
||||
} else
|
||||
g_print (" could not get logical stream %s\n", definition->nick);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
deep_notify (GObject * object, GstObject * origin,
|
||||
GParamSpec * pspec, gpointer data)
|
||||
{
|
||||
struct probe_context *context = (struct probe_context *) data;
|
||||
GValue value = { 0, };
|
||||
|
||||
if (!strcmp (pspec->name, "metadata")) {
|
||||
|
||||
g_value_init (&value, pspec->value_type);
|
||||
g_object_get_property (G_OBJECT (origin), pspec->name, &value);
|
||||
context->metadata = g_value_peek_pointer (&value);
|
||||
} else if (!strcmp (pspec->name, "streaminfo")) {
|
||||
|
||||
g_value_init (&value, pspec->value_type);
|
||||
g_object_get_property (G_OBJECT (origin), pspec->name, &value);
|
||||
context->streaminfo = g_value_peek_pointer (&value);
|
||||
} else if (!strcmp (pspec->name, "caps")) {
|
||||
if (GST_IS_PAD (origin) && GST_PAD (origin) == context->pad) {
|
||||
g_value_init (&value, pspec->value_type);
|
||||
g_object_get_property (G_OBJECT (origin), pspec->name, &value);
|
||||
context->caps = g_value_peek_pointer (&value);
|
||||
|
||||
ready = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
collect_logical_stream_properties (struct probe_context *context, gint stream)
|
||||
{
|
||||
GstEvent *event;
|
||||
gboolean res;
|
||||
gint count;
|
||||
|
||||
g_print ("info for logical stream %d:\n", stream);
|
||||
|
||||
/* seek to stream */
|
||||
event = gst_event_new_seek (context->ls_format |
|
||||
GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH, stream);
|
||||
res = gst_pad_send_event (context->pad, event);
|
||||
if (!res) {
|
||||
g_warning ("seek to logical track failed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* run the pipeline to get the info */
|
||||
count = 0;
|
||||
ready = FALSE;
|
||||
while (gst_bin_iterate (GST_BIN (context->pipeline)) && !ready) {
|
||||
count++;
|
||||
if (count > 10)
|
||||
break;
|
||||
}
|
||||
|
||||
print_caps (context->metadata);
|
||||
print_caps (context->streaminfo);
|
||||
print_format (context->caps);
|
||||
print_lbs_info (context, stream);
|
||||
|
||||
g_print ("\n");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
collect_stream_properties (struct probe_context *context)
|
||||
{
|
||||
const GstFormat *formats;
|
||||
|
||||
ready = FALSE;
|
||||
while (gst_bin_iterate (GST_BIN (context->pipeline)) && !ready);
|
||||
|
||||
g_print ("stream info:\n");
|
||||
|
||||
context->total_ls = -1;
|
||||
|
||||
/* report info in all supported formats */
|
||||
formats = gst_pad_get_formats (context->pad);
|
||||
while (*formats) {
|
||||
const GstFormatDefinition *definition;
|
||||
gint64 value;
|
||||
gboolean res;
|
||||
GstFormat format;
|
||||
|
||||
format = *formats;
|
||||
formats++;
|
||||
|
||||
res = gst_pad_query (context->pad, GST_QUERY_TOTAL, &format, &value);
|
||||
|
||||
definition = gst_format_get_details (format);
|
||||
|
||||
if (res) {
|
||||
if (format == GST_FORMAT_TIME) {
|
||||
value /= (GST_SECOND / 100);
|
||||
g_print (" total %s: %" G_GINT64_FORMAT ":%02" G_GINT64_FORMAT ".%02"
|
||||
G_GINT64_FORMAT "\n", definition->nick, value / 6000,
|
||||
(value / 100) % 60, (value % 100));
|
||||
} else {
|
||||
if (format == context->ls_format)
|
||||
context->total_ls = value;
|
||||
g_print (" total %s: %" G_GINT64_FORMAT "\n", definition->nick, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (context->total_ls == -1) {
|
||||
g_warning (" could not get number of logical streams");
|
||||
}
|
||||
g_print ("\n");
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
GstElement *pipeline;
|
||||
GstElement *filesrc;
|
||||
GstElement *vorbisfile;
|
||||
GstPad *pad;
|
||||
GstFormat logical_stream_format;
|
||||
struct probe_context *context;
|
||||
gint stream;
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
if (argc < 2) {
|
||||
g_print ("usage: %s <oggfile>\n", argv[0]);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
pipeline = gst_pipeline_new ("pipeline");
|
||||
|
||||
filesrc = gst_element_factory_make ("filesrc", "filesrc");
|
||||
g_assert (filesrc);
|
||||
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
|
||||
|
||||
vorbisfile = gst_element_factory_make ("vorbisfile", "vorbisfile");
|
||||
//vorbisfile = gst_element_factory_make ("mad", "vorbisfile");
|
||||
g_assert (vorbisfile);
|
||||
|
||||
gst_bin_add (GST_BIN (pipeline), filesrc);
|
||||
gst_bin_add (GST_BIN (pipeline), vorbisfile);
|
||||
|
||||
gst_element_link_pads (filesrc, "src", vorbisfile, "sink");
|
||||
|
||||
pad = gst_element_get_pad (vorbisfile, "src");
|
||||
g_assert (pad);
|
||||
|
||||
logical_stream_format = gst_format_get_by_nick ("logical_stream");
|
||||
g_assert (logical_stream_format != 0);
|
||||
|
||||
context = g_new0 (struct probe_context, 1);
|
||||
context->pipeline = pipeline;
|
||||
context->element = vorbisfile;
|
||||
context->pad = pad;
|
||||
context->ls_format = logical_stream_format;
|
||||
|
||||
g_signal_connect (G_OBJECT (pipeline), "deep_notify",
|
||||
G_CALLBACK (deep_notify), context);
|
||||
|
||||
gst_element_set_state (pipeline, GST_STATE_PLAYING);
|
||||
|
||||
/* at this point we can inspect the stream */
|
||||
collect_stream_properties (context);
|
||||
|
||||
/* loop over all logical streams to get info */
|
||||
stream = 0;
|
||||
while (stream < context->total_ls) {
|
||||
collect_logical_stream_properties (context, stream);
|
||||
stream++;
|
||||
}
|
||||
|
||||
/* stop probe */
|
||||
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue