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:
Wim Taymans 2005-03-31 09:43:49 +00:00
parent 66cd4c1006
commit 1dae961cbf
63 changed files with 4510 additions and 7584 deletions

159
ChangeLog
View file

@ -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

@ -1 +1 @@
Subproject commit b2638c100721f67b280c3b43b21f1ce1c9b5e316
Subproject commit 131c2632127e6f061b5270d8f80651782a4fdd13

View file

@ -1,4 +1,4 @@
examples = seek spider_seek cdplayer cdparanoia vorbisfile playbin chained
examples = seek cdplayer cdparanoia
noinst_PROGRAMS = $(examples)

View file

@ -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");

View file

@ -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);

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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)

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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 */

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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__ */

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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 {

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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

View file

@ -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);
}

View file

@ -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];
};

View file

@ -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];
};

View file

@ -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;
}

View file

@ -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);

View file

@ -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 (&copy, "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);

View file

@ -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;

View file

@ -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 */

View file

@ -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

View file

@ -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))) {

View file

@ -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)
{

View file

@ -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);
}
}

View file

@ -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

View file

@ -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);
}
/* ============================================================= */

View file

@ -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 {

View file

@ -1,4 +1,4 @@
examples = seek spider_seek cdplayer cdparanoia vorbisfile playbin chained
examples = seek cdplayer cdparanoia
noinst_PROGRAMS = $(examples)

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -1,4 +1,4 @@
examples = seek spider_seek cdplayer cdparanoia vorbisfile playbin chained
examples = seek cdplayer cdparanoia
noinst_PROGRAMS = $(examples)

View file

@ -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");

View file

@ -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);

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}