summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/timidity/gstwildmidi.c268
-rw-r--r--ext/timidity/gstwildmidi.h15
2 files changed, 154 insertions, 129 deletions
diff --git a/ext/timidity/gstwildmidi.c b/ext/timidity/gstwildmidi.c
index 43359d8e3..5a37491fd 100644
--- a/ext/timidity/gstwildmidi.c
+++ b/ext/timidity/gstwildmidi.c
@@ -83,7 +83,9 @@ enum
83 83
84static void gst_wildmidi_base_init (gpointer g_class); 84static void gst_wildmidi_base_init (gpointer g_class);
85static void gst_wildmidi_class_init (GstWildmidiClass * klass); 85static void gst_wildmidi_class_init (GstWildmidiClass * klass);
86static void gst_wildmidi_finalize (GObject * object);
86 87
88static gboolean gst_wildmidi_sink_event (GstPad * pad, GstEvent * event);
87static gboolean gst_wildmidi_src_event (GstPad * pad, GstEvent * event); 89static gboolean gst_wildmidi_src_event (GstPad * pad, GstEvent * event);
88 90
89static GstStateChangeReturn gst_wildmidi_change_state (GstElement * element, 91static GstStateChangeReturn gst_wildmidi_change_state (GstElement * element,
@@ -92,6 +94,7 @@ static gboolean gst_wildmidi_activate (GstPad * pad);
92static gboolean gst_wildmidi_activatepull (GstPad * pad, gboolean active); 94static gboolean gst_wildmidi_activatepull (GstPad * pad, gboolean active);
93 95
94static void gst_wildmidi_loop (GstPad * sinkpad); 96static void gst_wildmidi_loop (GstPad * sinkpad);
97static GstFlowReturn gst_wildmidi_chain (GstPad * sinkpad, GstBuffer * buffer);
95 98
96static gboolean gst_wildmidi_src_query (GstPad * pad, GstQuery * query); 99static gboolean gst_wildmidi_src_query (GstPad * pad, GstQuery * query);
97 100
@@ -230,7 +233,7 @@ gst_wildmidi_class_init (GstWildmidiClass * klass)
230 gobject_class = (GObjectClass *) klass; 233 gobject_class = (GObjectClass *) klass;
231 gstelement_class = (GstElementClass *) klass; 234 gstelement_class = (GstElementClass *) klass;
232 235
233 gstelement_class->change_state = gst_wildmidi_change_state; 236 gobject_class->finalize = gst_wildmidi_finalize;
234 gobject_class->set_property = gst_wildmidi_set_property; 237 gobject_class->set_property = gst_wildmidi_set_property;
235 gobject_class->get_property = gst_wildmidi_get_property; 238 gobject_class->get_property = gst_wildmidi_get_property;
236 239
@@ -241,6 +244,8 @@ gst_wildmidi_class_init (GstWildmidiClass * klass)
241 g_object_class_install_property (gobject_class, ARG_HIGH_QUALITY, 244 g_object_class_install_property (gobject_class, ARG_HIGH_QUALITY,
242 g_param_spec_boolean ("high-quality", "High Quality", 245 g_param_spec_boolean ("high-quality", "High Quality",
243 "High Quality", TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); 246 "High Quality", TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
247
248 gstelement_class->change_state = gst_wildmidi_change_state;
244} 249}
245 250
246/* initialize the new element 251/* initialize the new element
@@ -260,6 +265,8 @@ gst_wildmidi_init (GstWildmidi * filter, GstWildmidiClass * g_class)
260 gst_pad_set_activatepull_function (filter->sinkpad, 265 gst_pad_set_activatepull_function (filter->sinkpad,
261 gst_wildmidi_activatepull); 266 gst_wildmidi_activatepull);
262 gst_pad_set_activate_function (filter->sinkpad, gst_wildmidi_activate); 267 gst_pad_set_activate_function (filter->sinkpad, gst_wildmidi_activate);
268 gst_pad_set_event_function (filter->sinkpad, gst_wildmidi_sink_event);
269 gst_pad_set_chain_function (filter->sinkpad, gst_wildmidi_chain);
263 gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad); 270 gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
264 271
265 filter->srcpad = 272 filter->srcpad =
@@ -274,10 +281,18 @@ gst_wildmidi_init (GstWildmidi * filter, GstWildmidiClass * g_class)
274 281
275 gst_segment_init (filter->o_segment, GST_FORMAT_DEFAULT); 282 gst_segment_init (filter->o_segment, GST_FORMAT_DEFAULT);
276 283
284 filter->adapter = gst_adapter_new ();
285
277 filter->bytes_per_frame = WILDMIDI_BPS; 286 filter->bytes_per_frame = WILDMIDI_BPS;
278 filter->time_per_frame = GST_SECOND / WILDMIDI_RATE; 287 filter->time_per_frame = GST_SECOND / WILDMIDI_RATE;
279} 288}
280 289
290static void
291gst_wildmidi_finalize (GObject * object)
292{
293 G_OBJECT_CLASS (parent_class)->finalize (object);
294}
295
281static gboolean 296static gboolean
282gst_wildmidi_src_convert (GstWildmidi * wildmidi, 297gst_wildmidi_src_convert (GstWildmidi * wildmidi,
283 GstFormat src_format, gint64 src_value, 298 GstFormat src_format, gint64 src_value,
@@ -381,20 +396,6 @@ gst_wildmidi_src_query (GstPad * pad, GstQuery * query)
381 return res; 396 return res;
382} 397}
383 398
384static gboolean
385gst_wildmidi_get_upstream_size (GstWildmidi * wildmidi, gint64 * size)
386{
387 GstFormat format = GST_FORMAT_BYTES;
388 gboolean res = FALSE;
389 GstPad *peer = gst_pad_get_peer (wildmidi->sinkpad);
390
391 if (peer != NULL)
392 res = gst_pad_query_duration (peer, &format, size) && *size >= 0;
393
394 gst_object_unref (peer);
395 return res;
396}
397
398static GstSegment * 399static GstSegment *
399gst_wildmidi_get_segment (GstWildmidi * wildmidi, GstFormat format, 400gst_wildmidi_get_segment (GstWildmidi * wildmidi, GstFormat format,
400 gboolean update) 401 gboolean update)
@@ -521,6 +522,7 @@ gst_wildmidi_src_event (GstPad * pad, GstEvent * event)
521 return res; 522 return res;
522} 523}
523 524
525
524static gboolean 526static gboolean
525gst_wildmidi_activate (GstPad * sinkpad) 527gst_wildmidi_activate (GstPad * sinkpad)
526{ 528{
@@ -643,123 +645,58 @@ gst_wildmidi_get_buffer (GstWildmidi * wildmidi)
643 return gst_wildmidi_clip_buffer (wildmidi, out); 645 return gst_wildmidi_clip_buffer (wildmidi, out);
644} 646}
645 647
646static void 648static gboolean
647gst_wildmidi_loop (GstPad * sinkpad) 649gst_wildmidi_parse_song (GstWildmidi * wildmidi)
648{ 650{
649 GstWildmidi *wildmidi = GST_WILDMIDI (GST_PAD_PARENT (sinkpad)); 651 struct _WM_Info *info;
650 GstBuffer *out;
651 GstFlowReturn ret;
652 GstCaps *outcaps; 652 GstCaps *outcaps;
653 guint8 *data;
654 guint size;
653 655
654 if (wildmidi->mididata_size == 0) { 656 GST_DEBUG_OBJECT (wildmidi, "Parsing song");
655 if (!gst_wildmidi_get_upstream_size (wildmidi, &wildmidi->mididata_size)) {
656 GST_ELEMENT_ERROR (wildmidi, STREAM, DECODE, (NULL),
657 ("Unable to get song length"));
658 goto paused;
659 }
660
661 if (wildmidi->mididata)
662 free (wildmidi->mididata);
663
664 wildmidi->mididata = malloc (wildmidi->mididata_size);
665 wildmidi->mididata_offset = 0;
666 return;
667 }
668
669 if (wildmidi->mididata_offset < wildmidi->mididata_size) {
670 GstBuffer *buffer;
671 gint64 size;
672 657
673 GST_DEBUG_OBJECT (wildmidi, "loading song"); 658 size = gst_adapter_available (wildmidi->adapter);
674 659 data = gst_adapter_take (wildmidi->adapter, size);
675 ret =
676 gst_pad_pull_range (wildmidi->sinkpad, wildmidi->mididata_offset,
677 -1, &buffer);
678 if (ret != GST_FLOW_OK) {
679 GST_ELEMENT_ERROR (wildmidi, STREAM, DECODE, (NULL),
680 ("Unable to load song"));
681 goto paused;
682 }
683
684 size = wildmidi->mididata_size - wildmidi->mididata_offset;
685 if (GST_BUFFER_SIZE (buffer) < size)
686 size = GST_BUFFER_SIZE (buffer);
687
688 memmove (wildmidi->mididata + wildmidi->mididata_offset,
689 GST_BUFFER_DATA (buffer), size);
690 gst_buffer_unref (buffer);
691 660
692 wildmidi->mididata_offset += size; 661 /* this method takes our memory block */
693 GST_DEBUG_OBJECT (wildmidi, "Song loaded"); 662 wildmidi->song = WildMidi_OpenBuffer (data, size);
694 return;
695 }
696 663
697 if (!wildmidi->song) { 664 if (!wildmidi->song) {
698 struct _WM_Info *info; 665 GST_ELEMENT_ERROR (wildmidi, STREAM, DECODE, (NULL),
699 666 ("Unable to parse midi"));
700 GST_DEBUG_OBJECT (wildmidi, "Parsing song"); 667 return FALSE;
701 668 }
702 /* this method takes our memory block */
703 wildmidi->song =
704 WildMidi_OpenBuffer ((unsigned char *) wildmidi->mididata,
705 wildmidi->mididata_size);
706 wildmidi->mididata_size = 0;
707 wildmidi->mididata = NULL;
708
709 if (!wildmidi->song) {
710 GST_ELEMENT_ERROR (wildmidi, STREAM, DECODE, (NULL),
711 ("Unable to parse midi"));
712 goto paused;
713 }
714
715 WildMidi_LoadSamples (wildmidi->song);
716
717 WildMidi_SetOption (wildmidi->song, WM_MO_LINEAR_VOLUME,
718 wildmidi->linear_volume);
719 WildMidi_SetOption (wildmidi->song, WM_MO_EXPENSIVE_INTERPOLATION,
720 wildmidi->high_quality);
721
722 info = WildMidi_GetInfo (wildmidi->song);
723 wildmidi->o_len = info->approx_total_samples;
724
725 outcaps = gst_caps_copy (gst_pad_get_pad_template_caps (wildmidi->srcpad));
726 gst_pad_set_caps (wildmidi->srcpad, outcaps);
727 gst_caps_unref (outcaps);
728 669
729 gst_segment_set_newsegment (wildmidi->o_segment, FALSE, 1.0, 670 WildMidi_LoadSamples (wildmidi->song);
730 GST_FORMAT_DEFAULT, 0, GST_CLOCK_TIME_NONE, 0);
731 671
732 gst_pad_push_event (wildmidi->srcpad, 672 WildMidi_SetOption (wildmidi->song, WM_MO_LINEAR_VOLUME,
733 gst_wildmidi_get_new_segment_event (wildmidi, GST_FORMAT_TIME, FALSE)); 673 wildmidi->linear_volume);
674 WildMidi_SetOption (wildmidi->song, WM_MO_EXPENSIVE_INTERPOLATION,
675 wildmidi->high_quality);
734 676
735 GST_DEBUG_OBJECT (wildmidi, "Parsing song done"); 677 info = WildMidi_GetInfo (wildmidi->song);
736 return; 678 wildmidi->o_len = info->approx_total_samples;
737 }
738 679
739 if (wildmidi->o_segment_changed) { 680 outcaps = gst_caps_copy (gst_pad_get_pad_template_caps (wildmidi->srcpad));
740 GstSegment *segment; 681 gst_pad_set_caps (wildmidi->srcpad, outcaps);
682 gst_caps_unref (outcaps);
741 683
742 GST_DEBUG_OBJECT (wildmidi, "segment changed"); 684 gst_segment_set_newsegment (wildmidi->o_segment, FALSE, 1.0,
685 GST_FORMAT_DEFAULT, 0, GST_CLOCK_TIME_NONE, 0);
743 686
744 segment = gst_wildmidi_get_segment (wildmidi, GST_FORMAT_TIME, 687 gst_pad_push_event (wildmidi->srcpad,
745 !wildmidi->o_new_segment); 688 gst_wildmidi_get_new_segment_event (wildmidi, GST_FORMAT_TIME, FALSE));
746 689
747 GST_LOG_OBJECT (wildmidi, 690 GST_DEBUG_OBJECT (wildmidi, "Parsing song done");
748 "sending newsegment from %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT
749 ", pos=%" GST_TIME_FORMAT, GST_TIME_ARGS ((guint64) segment->start),
750 GST_TIME_ARGS ((guint64) segment->stop),
751 GST_TIME_ARGS ((guint64) segment->time));
752 691
753 if (wildmidi->o_segment->flags & GST_SEEK_FLAG_SEGMENT) { 692 return TRUE;
754 gst_element_post_message (GST_ELEMENT (wildmidi), 693}
755 gst_message_new_segment_start (GST_OBJECT (wildmidi),
756 segment->format, segment->start));
757 }
758 694
759 gst_segment_free (segment); 695static GstFlowReturn
760 wildmidi->o_segment_changed = FALSE; 696gst_wildmidi_do_play (GstWildmidi * wildmidi)
761 return; 697{
762 } 698 GstBuffer *out;
699 GstFlowReturn ret;
763 700
764 if (wildmidi->o_seek) { 701 if (wildmidi->o_seek) {
765 unsigned long int sample; 702 unsigned long int sample;
@@ -781,7 +718,7 @@ gst_wildmidi_loop (GstPad * sinkpad)
781 GST_LOG_OBJECT (wildmidi, "Song ended, generating eos"); 718 GST_LOG_OBJECT (wildmidi, "Song ended, generating eos");
782 gst_pad_push_event (wildmidi->srcpad, gst_event_new_eos ()); 719 gst_pad_push_event (wildmidi->srcpad, gst_event_new_eos ());
783 wildmidi->o_seek = FALSE; 720 wildmidi->o_seek = FALSE;
784 goto paused; 721 return GST_FLOW_UNEXPECTED;
785 } 722 }
786 723
787 if (wildmidi->o_seek) { 724 if (wildmidi->o_seek) {
@@ -792,9 +729,94 @@ gst_wildmidi_loop (GstPad * sinkpad)
792 gst_buffer_set_caps (out, GST_PAD_CAPS (wildmidi->srcpad)); 729 gst_buffer_set_caps (out, GST_PAD_CAPS (wildmidi->srcpad));
793 ret = gst_pad_push (wildmidi->srcpad, out); 730 ret = gst_pad_push (wildmidi->srcpad, out);
794 731
795 if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) 732 return ret;
796 goto error; 733}
734
735static gboolean
736gst_wildmidi_sink_event (GstPad * pad, GstEvent * event)
737{
738 gboolean res = FALSE;
739 GstWildmidi *wildmidi = GST_WILDMIDI (gst_pad_get_parent (pad));
740
741 GST_DEBUG_OBJECT (pad, "%s event received", GST_EVENT_TYPE_NAME (event));
742
743 switch (GST_EVENT_TYPE (event)) {
744 case GST_EVENT_EOS:
745 wildmidi->state = GST_WILDMIDI_STATE_PARSE;
746 /* now start the parsing task */
747 gst_pad_start_task (wildmidi->sinkpad,
748 (GstTaskFunction) gst_wildmidi_loop, wildmidi->sinkpad);
749 gst_event_unref (event);
750 break;
751 default:
752 res = gst_pad_push_event (wildmidi->srcpad, event);
753 break;
754 }
755 return res;
756}
757
758static GstFlowReturn
759gst_wildmidi_chain (GstPad * sinkpad, GstBuffer * buffer)
760{
761 GstFlowReturn ret;
762 GstWildmidi *wildmidi;
763
764 wildmidi = GST_WILDMIDI (GST_PAD_PARENT (sinkpad));
765
766 gst_adapter_push (wildmidi->adapter, buffer);
797 767
768 ret = GST_FLOW_OK;
769
770 return ret;
771}
772
773static void
774gst_wildmidi_loop (GstPad * sinkpad)
775{
776 GstWildmidi *wildmidi = GST_WILDMIDI (GST_PAD_PARENT (sinkpad));
777 GstFlowReturn ret;
778
779 switch (wildmidi->state) {
780 case GST_WILDMIDI_STATE_LOAD:
781 {
782 GstBuffer *buffer;
783
784 GST_DEBUG_OBJECT (wildmidi, "loading song");
785
786 ret =
787 gst_pad_pull_range (wildmidi->sinkpad, wildmidi->offset, -1, &buffer);
788
789 if (ret == GST_FLOW_UNEXPECTED) {
790 GST_DEBUG_OBJECT (wildmidi, "Song loaded");
791 wildmidi->state = GST_WILDMIDI_STATE_PARSE;
792 } else if (ret != GST_FLOW_OK) {
793 GST_ELEMENT_ERROR (wildmidi, STREAM, DECODE, (NULL),
794 ("Unable to load song"));
795 goto paused;
796 } else {
797 GST_DEBUG_OBJECT (wildmidi, "pushing buffer");
798 gst_adapter_push (wildmidi->adapter, buffer);
799 wildmidi->offset += GST_BUFFER_SIZE (buffer);
800 }
801 break;
802 }
803 case GST_WILDMIDI_STATE_PARSE:
804 {
805 if (!wildmidi->song) {
806 if (!gst_wildmidi_parse_song (wildmidi))
807 goto paused;
808 }
809 wildmidi->state = GST_WILDMIDI_STATE_PLAY;
810 break;
811 }
812 case GST_WILDMIDI_STATE_PLAY:
813 ret = gst_wildmidi_do_play (wildmidi);
814 if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED)
815 goto error;
816 break;
817 default:
818 break;
819 }
798 return; 820 return;
799 821
800paused: 822paused:
@@ -821,10 +843,10 @@ gst_wildmidi_change_state (GstElement * element, GstStateChange transition)
821 843
822 switch (transition) { 844 switch (transition) {
823 case GST_STATE_CHANGE_NULL_TO_READY: 845 case GST_STATE_CHANGE_NULL_TO_READY:
824 wildmidi->mididata = NULL;
825 break; 846 break;
826 case GST_STATE_CHANGE_READY_TO_PAUSED: 847 case GST_STATE_CHANGE_READY_TO_PAUSED:
827 wildmidi->mididata_size = 0; 848 wildmidi->offset = 0;
849 wildmidi->state = GST_WILDMIDI_STATE_LOAD;
828 break; 850 break;
829 case GST_STATE_CHANGE_PAUSED_TO_PLAYING: 851 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
830 break; 852 break;
@@ -841,9 +863,7 @@ gst_wildmidi_change_state (GstElement * element, GstStateChange transition)
841 if (wildmidi->song) 863 if (wildmidi->song)
842 WildMidi_Close (wildmidi->song); 864 WildMidi_Close (wildmidi->song);
843 wildmidi->song = NULL; 865 wildmidi->song = NULL;
844 if (wildmidi->mididata) 866 gst_adapter_clear (wildmidi->adapter);
845 free (wildmidi->mididata);
846 wildmidi->mididata = NULL;
847 break; 867 break;
848 case GST_STATE_CHANGE_READY_TO_NULL: 868 case GST_STATE_CHANGE_READY_TO_NULL:
849 break; 869 break;
diff --git a/ext/timidity/gstwildmidi.h b/ext/timidity/gstwildmidi.h
index 84802f735..c33f5005e 100644
--- a/ext/timidity/gstwildmidi.h
+++ b/ext/timidity/gstwildmidi.h
@@ -47,6 +47,12 @@ G_BEGIN_DECLS
47typedef struct _GstWildmidi GstWildmidi; 47typedef struct _GstWildmidi GstWildmidi;
48typedef struct _GstWildmidiClass GstWildmidiClass; 48typedef struct _GstWildmidiClass GstWildmidiClass;
49 49
50typedef enum {
51 GST_WILDMIDI_STATE_LOAD,
52 GST_WILDMIDI_STATE_PARSE,
53 GST_WILDMIDI_STATE_PLAY
54} GstWildmidiState;
55
50struct _GstWildmidi 56struct _GstWildmidi
51{ 57{
52 GstElement element; 58 GstElement element;
@@ -54,14 +60,13 @@ struct _GstWildmidi
54 GstPad *sinkpad, *srcpad; 60 GstPad *sinkpad, *srcpad;
55 61
56 /* input stream properties */ 62 /* input stream properties */
57 gint64 mididata_size, mididata_offset; 63 GstWildmidiState state;
58 gchar *mididata; 64 GstAdapter *adapter;
59 gboolean mididata_filled;
60
61 midi *song; 65 midi *song;
66 guint64 offset;
62 67
63 /* output data */ 68 /* output data */
64 gboolean o_new_segment, o_segment_changed, o_seek; 69 gboolean o_new_segment, o_seek;
65 GstSegment o_segment[1]; 70 GstSegment o_segment[1];
66 gint64 o_len; 71 gint64 o_len;
67 72