213 |
216 |
214 gobject_klass = (GObjectClass *) klass; |
217 gobject_klass = (GObjectClass *) klass; |
215 gstelement_klass = (GstElementClass *) klass; |
218 gstelement_klass = (GstElementClass *) klass; |
216 gstbin_klass = (GstBinClass *) klass; |
219 gstbin_klass = (GstBinClass *) klass; |
217 |
220 |
218 parent_class = g_type_class_peek_parent (klass); |
|
219 |
|
220 gobject_klass->set_property = gst_play_sink_set_property; |
|
221 gobject_klass->get_property = gst_play_sink_get_property; |
|
222 |
|
223 gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_play_sink_dispose); |
221 gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_play_sink_dispose); |
224 gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_play_sink_finalize); |
222 gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_play_sink_finalize); |
225 |
|
226 g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK, |
|
227 g_param_spec_object ("video-sink", "Video Sink", |
|
228 "the video output element to use (NULL = default sink)", |
|
229 GST_TYPE_ELEMENT, G_PARAM_READWRITE)); |
|
230 g_object_class_install_property (gobject_klass, PROP_AUDIO_SINK, |
|
231 g_param_spec_object ("audio-sink", "Audio Sink", |
|
232 "the audio output element to use (NULL = default sink)", |
|
233 GST_TYPE_ELEMENT, G_PARAM_READWRITE)); |
|
234 g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN, |
|
235 g_param_spec_object ("vis-plugin", "Vis plugin", |
|
236 "the visualization element to use (NULL = none)", |
|
237 GST_TYPE_ELEMENT, G_PARAM_READWRITE)); |
|
238 g_object_class_install_property (gobject_klass, PROP_VOLUME, |
|
239 g_param_spec_double ("volume", "volume", "volume", |
|
240 0.0, VOLUME_MAX_DOUBLE, 1.0, G_PARAM_READWRITE)); |
|
241 g_object_class_install_property (gobject_klass, PROP_FRAME, |
|
242 gst_param_spec_mini_object ("frame", "Frame", |
|
243 "The last video frame (NULL = no video available)", |
|
244 GST_TYPE_BUFFER, G_PARAM_READABLE)); |
|
245 g_object_class_install_property (gobject_klass, PROP_FONT_DESC, |
|
246 g_param_spec_string ("subtitle-font-desc", |
|
247 "Subtitle font description", |
|
248 "Pango font description of font " |
|
249 "to be used for subtitle rendering", NULL, G_PARAM_WRITABLE)); |
|
250 |
223 |
251 gst_element_class_set_details (gstelement_klass, &gst_play_sink_details); |
224 gst_element_class_set_details (gstelement_klass, &gst_play_sink_details); |
252 |
225 |
253 gstelement_klass->change_state = |
226 gstelement_klass->change_state = |
254 GST_DEBUG_FUNCPTR (gst_play_sink_change_state); |
227 GST_DEBUG_FUNCPTR (gst_play_sink_change_state); |
255 gstelement_klass->send_event = GST_DEBUG_FUNCPTR (gst_play_sink_send_event); |
228 gstelement_klass->send_event = GST_DEBUG_FUNCPTR (gst_play_sink_send_event); |
|
229 |
|
230 gstbin_klass->handle_message = |
|
231 GST_DEBUG_FUNCPTR (gst_play_sink_handle_message); |
256 |
232 |
257 GST_DEBUG_CATEGORY_INIT (gst_play_sink_debug, "playsink", 0, "play bin"); |
233 GST_DEBUG_CATEGORY_INIT (gst_play_sink_debug, "playsink", 0, "play bin"); |
258 } |
234 } |
259 |
235 |
260 static void |
236 static void |
311 |
329 |
312 playsink = GST_PLAY_SINK (object); |
330 playsink = GST_PLAY_SINK (object); |
313 |
331 |
314 g_mutex_free (playsink->lock); |
332 g_mutex_free (playsink->lock); |
315 |
333 |
316 G_OBJECT_CLASS (parent_class)->finalize (object); |
334 G_OBJECT_CLASS (gst_play_sink_parent_class)->finalize (object); |
317 } |
335 } |
318 #ifdef __SYMBIAN32__ |
336 #ifdef __SYMBIAN32__ |
319 EXPORT_C |
337 EXPORT_C |
320 #endif |
338 #endif |
321 |
339 |
322 |
|
323 void |
340 void |
324 gst_play_sink_set_video_sink (GstPlaySink * playsink, GstElement * sink) |
341 gst_play_sink_set_sink (GstPlaySink * playsink, GstPlaySinkType type, |
325 { |
342 GstElement * sink) |
326 GST_OBJECT_LOCK (playsink); |
343 { |
327 if (playsink->video_sink) |
344 GstElement **elem = NULL, *old = NULL; |
328 gst_object_unref (playsink->video_sink); |
345 |
329 |
346 GST_LOG ("Setting sink %" GST_PTR_FORMAT " as sink type %d", sink, type); |
330 if (sink) { |
347 |
331 gst_object_ref (sink); |
348 GST_PLAY_SINK_LOCK (playsink); |
332 gst_object_sink (sink); |
349 switch (type) { |
333 } |
350 case GST_PLAY_SINK_TYPE_AUDIO: |
334 playsink->video_sink = sink; |
351 case GST_PLAY_SINK_TYPE_AUDIO_RAW: |
335 GST_OBJECT_UNLOCK (playsink); |
352 elem = &playsink->audio_sink; |
336 } |
353 break; |
|
354 case GST_PLAY_SINK_TYPE_VIDEO: |
|
355 case GST_PLAY_SINK_TYPE_VIDEO_RAW: |
|
356 elem = &playsink->video_sink; |
|
357 break; |
|
358 case GST_PLAY_SINK_TYPE_TEXT: |
|
359 elem = &playsink->text_sink; |
|
360 break; |
|
361 case GST_PLAY_SINK_TYPE_SUBPIC: |
|
362 elem = &playsink->subp_sink; |
|
363 break; |
|
364 default: |
|
365 break; |
|
366 } |
|
367 if (elem) { |
|
368 old = *elem; |
|
369 if (sink) |
|
370 gst_object_ref (sink); |
|
371 *elem = sink; |
|
372 } |
|
373 GST_PLAY_SINK_UNLOCK (playsink); |
|
374 |
|
375 if (old) |
|
376 gst_object_unref (old); |
|
377 } |
|
378 |
337 #ifdef __SYMBIAN32__ |
379 #ifdef __SYMBIAN32__ |
338 EXPORT_C |
380 EXPORT_C |
339 #endif |
381 #endif |
340 |
382 |
341 |
383 GstElement * |
342 void |
384 gst_play_sink_get_sink (GstPlaySink * playsink, GstPlaySinkType type) |
343 gst_play_sink_set_audio_sink (GstPlaySink * playsink, GstElement * sink) |
385 { |
344 { |
386 GstElement *result = NULL; |
345 GST_OBJECT_LOCK (playsink); |
387 GstElement *elem = NULL, *chainp = NULL; |
346 if (playsink->audio_sink) |
388 |
347 gst_object_unref (playsink->audio_sink); |
389 GST_PLAY_SINK_LOCK (playsink); |
348 |
390 switch (type) { |
349 if (sink) { |
391 case GST_PLAY_SINK_TYPE_AUDIO: |
350 gst_object_ref (sink); |
392 { |
351 gst_object_sink (sink); |
393 GstPlayAudioChain *chain; |
352 } |
394 if ((chain = (GstPlayAudioChain *) playsink->audiochain)) |
353 playsink->audio_sink = sink; |
395 chainp = chain->sink; |
354 GST_OBJECT_UNLOCK (playsink); |
396 elem = playsink->audio_sink; |
|
397 break; |
|
398 } |
|
399 case GST_PLAY_SINK_TYPE_VIDEO: |
|
400 { |
|
401 GstPlayVideoChain *chain; |
|
402 if ((chain = (GstPlayVideoChain *) playsink->videochain)) |
|
403 chainp = chain->sink; |
|
404 elem = playsink->video_sink; |
|
405 break; |
|
406 } |
|
407 case GST_PLAY_SINK_TYPE_TEXT: |
|
408 { |
|
409 GstPlayTextChain *chain; |
|
410 if ((chain = (GstPlayTextChain *) playsink->textchain)) |
|
411 chainp = chain->sink; |
|
412 elem = playsink->text_sink; |
|
413 break; |
|
414 } |
|
415 case GST_PLAY_SINK_TYPE_SUBPIC: |
|
416 { |
|
417 GstPlaySubpChain *chain; |
|
418 if ((chain = (GstPlaySubpChain *) playsink->subpchain)) |
|
419 chainp = chain->sink; |
|
420 elem = playsink->subp_sink; |
|
421 break; |
|
422 } |
|
423 default: |
|
424 break; |
|
425 } |
|
426 if (chainp) { |
|
427 /* we have an active chain with a sink, get the sink */ |
|
428 result = gst_object_ref (chainp); |
|
429 } |
|
430 /* nothing found, return last configured sink */ |
|
431 if (result == NULL && elem) |
|
432 result = gst_object_ref (elem); |
|
433 GST_PLAY_SINK_UNLOCK (playsink); |
|
434 |
|
435 return result; |
355 } |
436 } |
356 |
437 |
357 static void |
438 static void |
358 gst_play_sink_vis_unblocked (GstPad * tee_pad, gboolean blocked, |
439 gst_play_sink_vis_unblocked (GstPad * tee_pad, gboolean blocked, |
359 gpointer user_data) |
440 gpointer user_data) |
698 * | | +-------+ +----------+ +----------+ +---------+ | |
859 * | | +-------+ +----------+ +----------+ +---------+ | |
699 * sink-+ | |
860 * sink-+ | |
700 * +------------------------------------------------------------+ |
861 * +------------------------------------------------------------+ |
701 * |
862 * |
702 */ |
863 */ |
703 static GstPlayChain * |
864 static GstPlayVideoChain * |
704 gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) |
865 gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async, |
|
866 gboolean queue) |
705 { |
867 { |
706 GstPlayVideoChain *chain; |
868 GstPlayVideoChain *chain; |
707 GstBin *bin; |
869 GstBin *bin; |
708 GstPad *pad; |
870 GstPad *pad; |
|
871 GstElement *head, *prev, *elem; |
709 |
872 |
710 chain = g_new0 (GstPlayVideoChain, 1); |
873 chain = g_new0 (GstPlayVideoChain, 1); |
711 chain->chain.playsink = gst_object_ref (playsink); |
874 chain->chain.playsink = playsink; |
|
875 chain->chain.raw = raw; |
|
876 |
|
877 GST_DEBUG_OBJECT (playsink, "making video chain %p", chain); |
712 |
878 |
713 if (playsink->video_sink) { |
879 if (playsink->video_sink) { |
714 chain->sink = playsink->video_sink; |
880 GST_DEBUG_OBJECT (playsink, "trying configured videosink"); |
|
881 chain->sink = try_element (playsink, playsink->video_sink, FALSE); |
|
882 } |
|
883 if (chain->sink == NULL) { |
|
884 GST_DEBUG_OBJECT (playsink, "trying autovideosink"); |
|
885 elem = gst_element_factory_make ("autovideosink", "videosink"); |
|
886 chain->sink = try_element (playsink, elem, TRUE); |
|
887 } |
|
888 /* FIXME: if DEFAULT_VIDEOSINK != "autovideosink" try this now */ |
|
889 if (chain->sink == NULL) { |
|
890 GST_DEBUG_OBJECT (playsink, "trying xvimagesink"); |
|
891 elem = gst_element_factory_make ("xvimagesink", "videosink"); |
|
892 chain->sink = try_element (playsink, elem, TRUE); |
|
893 } |
|
894 if (chain->sink == NULL) |
|
895 goto no_sinks; |
|
896 |
|
897 /* if we can disable async behaviour of the sink, we can avoid adding a |
|
898 * queue for the audio chain. */ |
|
899 elem = gst_play_sink_find_property_sinks (playsink, chain->sink, "async"); |
|
900 if (elem) { |
|
901 GST_DEBUG_OBJECT (playsink, "setting async property to %d on element %s", |
|
902 async, GST_ELEMENT_NAME (elem)); |
|
903 g_object_set (elem, "async", async, NULL); |
|
904 chain->async = async; |
715 } else { |
905 } else { |
716 chain->sink = gst_element_factory_make ("autovideosink", "videosink"); |
906 GST_DEBUG_OBJECT (playsink, "no async property on the sink"); |
717 if (chain->sink == NULL) { |
|
718 chain->sink = gst_element_factory_make ("xvimagesink", "videosink"); |
|
719 } |
|
720 if (chain->sink == NULL) |
|
721 goto no_sinks; |
|
722 } |
|
723 |
|
724 /* if we can disable async behaviour of the sink, we can avoid adding a |
|
725 * queue for the audio chain. We can't use the deep property here because the |
|
726 * sink might change it's internal sink element later. */ |
|
727 if (g_object_class_find_property (G_OBJECT_GET_CLASS (chain->sink), "async")) { |
|
728 GST_DEBUG_OBJECT (playsink, "setting async property to %d on video sink", |
|
729 async); |
|
730 g_object_set (chain->sink, "async", async, NULL); |
|
731 chain->async = async; |
|
732 } else |
|
733 chain->async = TRUE; |
907 chain->async = TRUE; |
|
908 } |
734 |
909 |
735 /* create a bin to hold objects, as we create them we add them to this bin so |
910 /* create a bin to hold objects, as we create them we add them to this bin so |
736 * that when something goes wrong we only need to unref the bin */ |
911 * that when something goes wrong we only need to unref the bin */ |
737 chain->chain.bin = gst_bin_new ("vbin"); |
912 chain->chain.bin = gst_bin_new ("vbin"); |
738 bin = GST_BIN_CAST (chain->chain.bin); |
913 bin = GST_BIN_CAST (chain->chain.bin); |
739 gst_object_ref (bin); |
914 gst_object_ref (bin); |
740 gst_object_sink (bin); |
915 gst_object_sink (bin); |
741 gst_bin_add (bin, chain->sink); |
916 gst_bin_add (bin, chain->sink); |
742 |
917 |
743 if (raw) { |
918 if (queue) { |
|
919 /* decouple decoder from sink, this improves playback quite a lot since the |
|
920 * decoder can continue while the sink blocks for synchronisation. We don't |
|
921 * need a lot of buffers as this consumes a lot of memory and we don't want |
|
922 * too little because else we would be context switching too quickly. */ |
|
923 chain->queue = gst_element_factory_make ("queue", "vqueue"); |
|
924 g_object_set (G_OBJECT (chain->queue), "max-size-buffers", 3, |
|
925 "max-size-bytes", 0, "max-size-time", (gint64) 0, NULL); |
|
926 gst_bin_add (bin, chain->queue); |
|
927 head = prev = chain->queue; |
|
928 } else { |
|
929 head = chain->sink; |
|
930 prev = NULL; |
|
931 } |
|
932 |
|
933 if (raw && !(playsink->flags & GST_PLAY_FLAG_NATIVE_VIDEO)) { |
|
934 GST_DEBUG_OBJECT (playsink, "creating ffmpegcolorspace"); |
744 chain->conv = gst_element_factory_make ("ffmpegcolorspace", "vconv"); |
935 chain->conv = gst_element_factory_make ("ffmpegcolorspace", "vconv"); |
745 if (chain->conv == NULL) |
936 if (chain->conv == NULL) { |
746 goto no_colorspace; |
937 post_missing_element_message (playsink, "ffmpegcolorspace"); |
747 gst_bin_add (bin, chain->conv); |
938 GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN, |
748 |
939 (_("Missing element '%s' - check your GStreamer installation."), |
|
940 "ffmpegcolorspace"), ("video rendering might fail")); |
|
941 } else { |
|
942 gst_bin_add (bin, chain->conv); |
|
943 if (prev) { |
|
944 if (!gst_element_link_pads (prev, "src", chain->conv, "sink")) |
|
945 goto link_failed; |
|
946 } else { |
|
947 head = chain->conv; |
|
948 } |
|
949 prev = chain->conv; |
|
950 } |
|
951 |
|
952 GST_DEBUG_OBJECT (playsink, "creating videoscale"); |
749 chain->scale = gst_element_factory_make ("videoscale", "vscale"); |
953 chain->scale = gst_element_factory_make ("videoscale", "vscale"); |
750 if (chain->scale == NULL) |
954 if (chain->scale == NULL) { |
751 goto no_videoscale; |
955 post_missing_element_message (playsink, "videoscale"); |
752 gst_bin_add (bin, chain->scale); |
956 GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN, |
753 } |
957 (_("Missing element '%s' - check your GStreamer installation."), |
754 |
958 "videoscale"), ("possibly a liboil version mismatch?")); |
755 /* decouple decoder from sink, this improves playback quite a lot since the |
959 } else { |
756 * decoder can continue while the sink blocks for synchronisation. We don't |
960 gst_bin_add (bin, chain->scale); |
757 * need a lot of buffers as this consumes a lot of memory and we don't want |
961 if (prev) { |
758 * too little because else we would be context switching too quickly. */ |
962 if (!gst_element_link_pads (prev, "src", chain->scale, "sink")) |
759 chain->queue = gst_element_factory_make ("queue", "vqueue"); |
963 goto link_failed; |
760 g_object_set (G_OBJECT (chain->queue), "max-size-buffers", 3, |
964 } else { |
761 "max-size-bytes", 0, "max-size-time", (gint64) 0, NULL); |
965 head = chain->scale; |
762 gst_bin_add (bin, chain->queue); |
966 } |
763 |
967 prev = chain->scale; |
764 if (raw) { |
968 } |
765 gst_element_link_pads (chain->queue, "src", chain->conv, "sink"); |
969 } |
766 gst_element_link_pads (chain->conv, "src", chain->scale, "sink"); |
970 |
767 /* be more careful with the pad from the custom sink element, it might not |
971 if (prev) { |
768 * be named 'sink' */ |
972 GST_DEBUG_OBJECT (playsink, "linking to sink"); |
769 if (!gst_element_link_pads (chain->scale, "src", chain->sink, NULL)) |
973 if (!gst_element_link_pads (prev, "src", chain->sink, NULL)) |
770 goto link_failed; |
974 goto link_failed; |
771 |
975 } |
772 pad = gst_element_get_pad (chain->queue, "sink"); |
976 |
773 } else { |
977 pad = gst_element_get_static_pad (head, "sink"); |
774 if (!gst_element_link_pads (chain->queue, "src", chain->sink, NULL)) |
978 chain->sinkpad = gst_ghost_pad_new ("sink", pad); |
775 goto link_failed; |
|
776 pad = gst_element_get_pad (chain->queue, "sink"); |
|
777 } |
|
778 |
|
779 chain->chain.sinkpad = gst_ghost_pad_new ("sink", pad); |
|
780 gst_object_unref (pad); |
979 gst_object_unref (pad); |
781 gst_element_add_pad (chain->chain.bin, chain->chain.sinkpad); |
980 |
782 |
981 gst_element_add_pad (chain->chain.bin, chain->sinkpad); |
783 return (GstPlayChain *) chain; |
982 |
|
983 return chain; |
784 |
984 |
785 /* ERRORS */ |
985 /* ERRORS */ |
786 no_sinks: |
986 no_sinks: |
787 { |
987 { |
788 post_missing_element_message (playsink, "autovideosink"); |
988 if (!elem) { |
789 GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN, |
989 post_missing_element_message (playsink, "autovideosink"); |
790 (_("Both autovideosink and xvimagesink elements are missing.")), |
990 GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN, |
791 (NULL)); |
991 (_("Both autovideosink and xvimagesink elements are missing.")), |
792 free_chain ((GstPlayChain *) chain); |
992 (NULL)); |
793 return NULL; |
993 } else { |
794 } |
994 GST_ELEMENT_ERROR (playsink, CORE, STATE_CHANGE, |
795 no_colorspace: |
995 (_("Both autovideosink and xvimagesink elements are not working.")), |
796 { |
996 (NULL)); |
797 post_missing_element_message (playsink, "ffmpegcolorspace"); |
997 } |
798 GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN, |
|
799 (_("Missing element '%s' - check your GStreamer installation."), |
|
800 "ffmpegcolorspace"), (NULL)); |
|
801 free_chain ((GstPlayChain *) chain); |
|
802 return NULL; |
|
803 } |
|
804 |
|
805 no_videoscale: |
|
806 { |
|
807 post_missing_element_message (playsink, "videoscale"); |
|
808 GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN, |
|
809 (_("Missing element '%s' - check your GStreamer installation."), |
|
810 "videoscale"), ("possibly a liboil version mismatch?")); |
|
811 free_chain ((GstPlayChain *) chain); |
998 free_chain ((GstPlayChain *) chain); |
812 return NULL; |
999 return NULL; |
813 } |
1000 } |
814 link_failed: |
1001 link_failed: |
815 { |
1002 { |
818 free_chain ((GstPlayChain *) chain); |
1005 free_chain ((GstPlayChain *) chain); |
819 return NULL; |
1006 return NULL; |
820 } |
1007 } |
821 } |
1008 } |
822 |
1009 |
823 #if 0 |
1010 static gboolean |
|
1011 setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async, |
|
1012 gboolean queue) |
|
1013 { |
|
1014 GstElement *elem; |
|
1015 GstPlayVideoChain *chain; |
|
1016 GstStateChangeReturn ret; |
|
1017 |
|
1018 chain = playsink->videochain; |
|
1019 |
|
1020 /* if the chain was active we don't do anything */ |
|
1021 if (GST_PLAY_CHAIN (chain)->activated == TRUE) |
|
1022 return TRUE; |
|
1023 |
|
1024 if (chain->chain.raw != raw) |
|
1025 return FALSE; |
|
1026 |
|
1027 /* try to set the sink element to READY again */ |
|
1028 ret = gst_element_set_state (chain->sink, GST_STATE_READY); |
|
1029 if (ret == GST_STATE_CHANGE_FAILURE) |
|
1030 return FALSE; |
|
1031 |
|
1032 /* if we can disable async behaviour of the sink, we can avoid adding a |
|
1033 * queue for the audio chain. */ |
|
1034 elem = gst_play_sink_find_property_sinks (playsink, chain->sink, "async"); |
|
1035 if (elem) { |
|
1036 GST_DEBUG_OBJECT (playsink, "setting async property to %d on element %s", |
|
1037 async, GST_ELEMENT_NAME (elem)); |
|
1038 g_object_set (elem, "async", async, NULL); |
|
1039 chain->async = async; |
|
1040 } else { |
|
1041 GST_DEBUG_OBJECT (playsink, "no async property on the sink"); |
|
1042 chain->async = TRUE; |
|
1043 } |
|
1044 return TRUE; |
|
1045 } |
|
1046 |
824 /* make an element for playback of video with subtitles embedded. |
1047 /* make an element for playback of video with subtitles embedded. |
825 * |
1048 * |
826 * +--------------------------------------------------+ |
1049 * +----------------------------------------------+ |
827 * | tbin +-------------+ | |
1050 * | tbin +-------------+ | |
828 * | +-----+ | textoverlay | +------+ | |
1051 * | +-----+ | textoverlay | | |
829 * | | csp | +--video_sink | | vbin | | |
1052 * | | csp | +--video_sink | | |
830 * video_sink-sink src+ +-text_sink src-sink | | |
1053 * sink-------sink src+ +-text_sink src--+ | |
831 * | +-----+ | +-------------+ +------+ | |
1054 * | +-----+ | +-------------+ +-- src |
832 * text_sink-------------+ | |
1055 * text_sink-------------+ | |
833 * +--------------------------------------------------+ |
1056 * +----------------------------------------------+ |
|
1057 */ |
|
1058 static GstPlayTextChain * |
|
1059 gen_text_chain (GstPlaySink * playsink) |
|
1060 { |
|
1061 GstPlayTextChain *chain; |
|
1062 GstBin *bin; |
|
1063 GstElement *elem; |
|
1064 GstPad *videosinkpad, *textsinkpad, *srcpad; |
|
1065 |
|
1066 chain = g_new0 (GstPlayTextChain, 1); |
|
1067 chain->chain.playsink = playsink; |
|
1068 |
|
1069 GST_DEBUG_OBJECT (playsink, "making text chain %p", chain); |
|
1070 |
|
1071 chain->chain.bin = gst_bin_new ("tbin"); |
|
1072 bin = GST_BIN_CAST (chain->chain.bin); |
|
1073 gst_object_ref (bin); |
|
1074 gst_object_sink (bin); |
|
1075 |
|
1076 videosinkpad = textsinkpad = srcpad = NULL; |
|
1077 |
|
1078 /* first try to hook the text pad to the custom sink */ |
|
1079 if (playsink->text_sink) { |
|
1080 GST_DEBUG_OBJECT (playsink, "trying configured textsink"); |
|
1081 chain->sink = try_element (playsink, playsink->text_sink, FALSE); |
|
1082 if (chain->sink) { |
|
1083 elem = gst_play_sink_find_property_sinks (playsink, chain->sink, "async"); |
|
1084 if (elem) { |
|
1085 /* make sure the sparse subtitles don't participate in the preroll */ |
|
1086 g_object_set (elem, "async", FALSE, NULL); |
|
1087 /* we have a custom sink, this will be our textsinkpad */ |
|
1088 textsinkpad = gst_element_get_static_pad (chain->sink, "sink"); |
|
1089 if (textsinkpad) { |
|
1090 /* we're all fine now and we can add the sink to the chain */ |
|
1091 GST_DEBUG_OBJECT (playsink, "adding custom text sink"); |
|
1092 gst_bin_add (bin, chain->sink); |
|
1093 } else { |
|
1094 GST_WARNING_OBJECT (playsink, |
|
1095 "can't find a sink pad on custom text sink"); |
|
1096 gst_object_unref (chain->sink); |
|
1097 chain->sink = NULL; |
|
1098 } |
|
1099 /* try to set sync to true but it's no biggie when we can't */ |
|
1100 if ((elem = |
|
1101 gst_play_sink_find_property_sinks (playsink, chain->sink, |
|
1102 "sync"))) |
|
1103 g_object_set (elem, "sync", TRUE, NULL); |
|
1104 } else { |
|
1105 GST_WARNING_OBJECT (playsink, |
|
1106 "can't find async property in custom text sink"); |
|
1107 } |
|
1108 } |
|
1109 if (textsinkpad == NULL) { |
|
1110 GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN, |
|
1111 (_("Custom text sink element is not usable.")), |
|
1112 ("fallback to default textoverlay")); |
|
1113 } |
|
1114 } |
|
1115 |
|
1116 if (textsinkpad == NULL) { |
|
1117 if (!(playsink->flags & GST_PLAY_FLAG_NATIVE_VIDEO)) { |
|
1118 /* no custom sink, try to setup the colorspace and textoverlay elements */ |
|
1119 chain->conv = gst_element_factory_make ("ffmpegcolorspace", "tconv"); |
|
1120 if (chain->conv == NULL) { |
|
1121 /* not really needed, it might work without colorspace */ |
|
1122 post_missing_element_message (playsink, "ffmpegcolorspace"); |
|
1123 GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN, |
|
1124 (_("Missing element '%s' - check your GStreamer installation."), |
|
1125 "ffmpegcolorspace"), ("subtitle rendering might fail")); |
|
1126 } else { |
|
1127 gst_bin_add (bin, chain->conv); |
|
1128 videosinkpad = gst_element_get_static_pad (chain->conv, "sink"); |
|
1129 } |
|
1130 } |
|
1131 |
|
1132 chain->overlay = gst_element_factory_make ("textoverlay", "overlay"); |
|
1133 if (chain->overlay == NULL) { |
|
1134 post_missing_element_message (playsink, "textoverlay"); |
|
1135 GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN, |
|
1136 (_("Missing element '%s' - check your GStreamer installation."), |
|
1137 "textoverlay"), ("subtitle rendering disabled")); |
|
1138 } else { |
|
1139 gst_bin_add (bin, chain->overlay); |
|
1140 |
|
1141 /* Set some parameters */ |
|
1142 g_object_set (G_OBJECT (chain->overlay), |
|
1143 "halign", "center", "valign", "bottom", NULL); |
|
1144 if (playsink->font_desc) { |
|
1145 g_object_set (G_OBJECT (chain->overlay), "font-desc", |
|
1146 playsink->font_desc, NULL); |
|
1147 } |
|
1148 g_object_set (G_OBJECT (chain->overlay), "wait-text", FALSE, NULL); |
|
1149 |
|
1150 textsinkpad = gst_element_get_static_pad (chain->overlay, "text_sink"); |
|
1151 |
|
1152 srcpad = gst_element_get_static_pad (chain->overlay, "src"); |
|
1153 |
|
1154 if (videosinkpad) { |
|
1155 /* if we had a videosinkpad, we had a converter and we can link it, we |
|
1156 * know that this will work */ |
|
1157 gst_element_link_pads (chain->conv, "src", chain->overlay, |
|
1158 "video_sink"); |
|
1159 } else { |
|
1160 /* no videopad, expose our own video pad then */ |
|
1161 videosinkpad = |
|
1162 gst_element_get_static_pad (chain->overlay, "video_sink"); |
|
1163 } |
|
1164 } |
|
1165 } |
|
1166 |
|
1167 if (videosinkpad == NULL) { |
|
1168 /* if we still don't have a videosink, we don't have a converter nor an |
|
1169 * overlay. the only thing we can do is insert an identity and ghost the src |
|
1170 * and sink pads. */ |
|
1171 chain->conv = gst_element_factory_make ("identity", "tidentity"); |
|
1172 g_object_set (chain->conv, "signal-handoffs", FALSE, NULL); |
|
1173 g_object_set (chain->conv, "silent", TRUE, NULL); |
|
1174 gst_bin_add (bin, chain->conv); |
|
1175 srcpad = gst_element_get_static_pad (chain->conv, "src"); |
|
1176 videosinkpad = gst_element_get_static_pad (chain->conv, "sink"); |
|
1177 } else { |
|
1178 /* we have a videosink but maybe not a srcpad because there was no |
|
1179 * overlay */ |
|
1180 if (srcpad == NULL) { |
|
1181 /* ghost the source pad of the converter then */ |
|
1182 srcpad = gst_element_get_static_pad (chain->conv, "src"); |
|
1183 } |
|
1184 } |
|
1185 |
|
1186 /* expose the ghostpads */ |
|
1187 if (videosinkpad) { |
|
1188 chain->videosinkpad = gst_ghost_pad_new ("sink", videosinkpad); |
|
1189 gst_object_unref (videosinkpad); |
|
1190 gst_element_add_pad (chain->chain.bin, chain->videosinkpad); |
|
1191 } |
|
1192 if (textsinkpad) { |
|
1193 chain->textsinkpad = gst_ghost_pad_new ("text_sink", textsinkpad); |
|
1194 gst_object_unref (textsinkpad); |
|
1195 gst_element_add_pad (chain->chain.bin, chain->textsinkpad); |
|
1196 } |
|
1197 if (srcpad) { |
|
1198 chain->srcpad = gst_ghost_pad_new ("src", srcpad); |
|
1199 gst_object_unref (srcpad); |
|
1200 gst_element_add_pad (chain->chain.bin, chain->srcpad); |
|
1201 } |
|
1202 |
|
1203 return chain; |
|
1204 } |
|
1205 |
|
1206 /* make an element for playback of video with subpictures embedded. |
834 * |
1207 * |
835 * If there is no subtitle renderer this function will simply return the |
1208 * +--------------------------------------------------------+ |
836 * videosink without the text_sink pad. |
1209 * | pbin +-------------+ | |
|
1210 * | +-------+ +-----+ | dvdspu | | |
|
1211 * | | queue | | csp | +---video | | |
|
1212 * sink----sink src--sink src+ +-subpicture src--+ | |
|
1213 * | +-------+ +-----+ | +-------------+ +-- src |
|
1214 * subpicture----------------------+ | |
|
1215 * +--------------------------------------------------------+ |
837 */ |
1216 */ |
838 static GstElement * |
1217 static GstPlaySubpChain * |
839 gen_text_element (GstPlaySink * playsink) |
1218 gen_subp_chain (GstPlaySink * playsink) |
840 { |
1219 { |
841 GstElement *element, *csp, *overlay, *vbin; |
1220 GstPlaySubpChain *chain; |
842 GstPad *pad; |
1221 GstBin *bin; |
843 |
1222 GstElement *elem, *head; |
844 /* Create the video rendering bin, error is posted when this fails. */ |
1223 GstPad *videosinkpad, *subpsinkpad, *srcpad; |
845 vbin = gen_video_element (playsink); |
1224 |
846 if (!vbin) |
1225 chain = g_new0 (GstPlaySubpChain, 1); |
847 return NULL; |
1226 chain->chain.playsink = playsink; |
848 |
1227 |
849 /* Text overlay */ |
1228 GST_DEBUG_OBJECT (playsink, "making subpicture chain %p", chain); |
850 overlay = gst_element_factory_make ("textoverlay", "overlay"); |
1229 |
851 |
1230 chain->chain.bin = gst_bin_new ("pbin"); |
852 /* If no overlay return the video bin without subtitle support. */ |
1231 bin = GST_BIN_CAST (chain->chain.bin); |
853 if (!overlay) |
1232 gst_object_ref (bin); |
854 goto no_overlay; |
1233 gst_object_sink (bin); |
855 |
1234 |
856 /* Create our bin */ |
1235 videosinkpad = subpsinkpad = srcpad = NULL; |
857 element = gst_bin_new ("textbin"); |
1236 |
858 |
1237 /* first try to hook the text pad to the custom sink */ |
859 /* Set some parameters */ |
1238 if (playsink->subp_sink) { |
860 g_object_set (G_OBJECT (overlay), |
1239 GST_DEBUG_OBJECT (playsink, "trying configured subpsink"); |
861 "halign", "center", "valign", "bottom", NULL); |
1240 chain->sink = try_element (playsink, playsink->text_sink, FALSE); |
862 if (playsink->font_desc) { |
1241 if (chain->sink) { |
863 g_object_set (G_OBJECT (overlay), "font-desc", playsink->font_desc, NULL); |
1242 elem = gst_play_sink_find_property_sinks (playsink, chain->sink, "async"); |
864 } |
1243 if (elem) { |
865 |
1244 /* make sure the sparse subtitles don't participate in the preroll */ |
866 /* Take a ref */ |
1245 g_object_set (elem, "async", FALSE, NULL); |
867 playsink->textoverlay_element = GST_ELEMENT_CAST (gst_object_ref (overlay)); |
1246 /* we have a custom sink, this will be our subpsinkpad */ |
868 |
1247 subpsinkpad = gst_element_get_static_pad (chain->sink, "sink"); |
869 /* we know this will succeed, as the video bin already created one before */ |
1248 if (subpsinkpad) { |
870 csp = gst_element_factory_make ("ffmpegcolorspace", "subtitlecsp"); |
1249 /* we're all fine now and we can add the sink to the chain */ |
871 |
1250 GST_DEBUG_OBJECT (playsink, "adding custom text sink"); |
872 /* Add our elements */ |
1251 gst_bin_add (bin, chain->sink); |
873 gst_bin_add_many (GST_BIN_CAST (element), csp, overlay, vbin, NULL); |
1252 } else { |
874 |
1253 GST_WARNING_OBJECT (playsink, |
875 /* Link */ |
1254 "can't find a sink pad on custom text sink"); |
876 gst_element_link_pads (csp, "src", overlay, "video_sink"); |
1255 gst_object_unref (chain->sink); |
877 gst_element_link_pads (overlay, "src", vbin, "sink"); |
1256 chain->sink = NULL; |
878 |
1257 } |
879 /* Add ghost pads on the subtitle bin */ |
1258 /* try to set sync to true but it's no biggie when we can't */ |
880 pad = gst_element_get_pad (overlay, "text_sink"); |
1259 if ((elem = |
881 gst_element_add_pad (element, gst_ghost_pad_new ("text_sink", pad)); |
1260 gst_play_sink_find_property_sinks (playsink, chain->sink, |
882 gst_object_unref (pad); |
1261 "sync"))) |
883 |
1262 g_object_set (elem, "sync", TRUE, NULL); |
884 pad = gst_element_get_pad (csp, "sink"); |
1263 } else { |
885 gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad)); |
1264 GST_WARNING_OBJECT (playsink, |
886 gst_object_unref (pad); |
1265 "can't find async property in custom text sink"); |
887 |
1266 } |
888 /* Set state to READY */ |
1267 } |
889 gst_element_set_state (element, GST_STATE_READY); |
1268 if (subpsinkpad == NULL) { |
890 |
1269 GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN, |
891 return element; |
1270 (_("Custom text sink element is not usable.")), |
892 |
1271 ("fallback to default dvdspu overlay")); |
893 /* ERRORS */ |
1272 } |
894 no_overlay: |
1273 } |
895 { |
1274 |
896 post_missing_element_message (playsink, "textoverlay"); |
1275 /* make a little queue */ |
897 GST_WARNING_OBJECT (playsink, |
1276 chain->queue = gst_element_factory_make ("queue", "vqueue"); |
898 "No overlay (pango) element, subtitles disabled"); |
1277 g_object_set (G_OBJECT (chain->queue), "max-size-buffers", 3, |
899 return vbin; |
1278 "max-size-bytes", 0, "max-size-time", (gint64) 0, NULL); |
900 } |
1279 gst_bin_add (bin, chain->queue); |
901 } |
1280 head = chain->queue; |
902 #endif |
1281 |
903 |
1282 /* video goes into the queue */ |
|
1283 videosinkpad = gst_element_get_static_pad (chain->queue, "sink"); |
|
1284 |
|
1285 if (subpsinkpad == NULL) { |
|
1286 if (!(playsink->flags & GST_PLAY_FLAG_NATIVE_VIDEO)) { |
|
1287 /* no custom sink, try to setup the colorspace and textoverlay elements */ |
|
1288 chain->conv = gst_element_factory_make ("ffmpegcolorspace", "tconv"); |
|
1289 if (chain->conv == NULL) { |
|
1290 /* not really needed, it might work without colorspace */ |
|
1291 post_missing_element_message (playsink, "ffmpegcolorspace"); |
|
1292 GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN, |
|
1293 (_("Missing element '%s' - check your GStreamer installation."), |
|
1294 "ffmpegcolorspace"), ("subpicture rendering might fail")); |
|
1295 } else { |
|
1296 gst_bin_add (bin, chain->conv); |
|
1297 gst_element_link_pads (head, "src", chain->conv, "sink"); |
|
1298 head = chain->conv; |
|
1299 } |
|
1300 } |
|
1301 |
|
1302 chain->overlay = gst_element_factory_make ("dvdspu", "spuoverlay"); |
|
1303 if (chain->overlay == NULL) { |
|
1304 post_missing_element_message (playsink, "dvdspu"); |
|
1305 GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN, |
|
1306 (_("Missing element '%s' - check your GStreamer installation."), |
|
1307 "dvdspu"), ("subpicture rendering disabled")); |
|
1308 } else { |
|
1309 gst_bin_add (bin, chain->overlay); |
|
1310 /* Set some parameters */ |
|
1311 subpsinkpad = gst_element_get_static_pad (chain->overlay, "subpicture"); |
|
1312 /* link to the next element */ |
|
1313 gst_element_link_pads (head, "src", chain->overlay, "video"); |
|
1314 head = chain->overlay; |
|
1315 } |
|
1316 } |
|
1317 srcpad = gst_element_get_static_pad (head, "src"); |
|
1318 chain->srcpad = gst_ghost_pad_new ("src", srcpad); |
|
1319 gst_object_unref (srcpad); |
|
1320 gst_element_add_pad (chain->chain.bin, chain->srcpad); |
|
1321 |
|
1322 /* expose the ghostpads */ |
|
1323 chain->videosinkpad = gst_ghost_pad_new ("sink", videosinkpad); |
|
1324 gst_object_unref (videosinkpad); |
|
1325 gst_element_add_pad (chain->chain.bin, chain->videosinkpad); |
|
1326 |
|
1327 if (subpsinkpad) { |
|
1328 chain->subpsinkpad = gst_ghost_pad_new ("subpicture", subpsinkpad); |
|
1329 gst_object_unref (subpsinkpad); |
|
1330 gst_element_add_pad (chain->chain.bin, chain->subpsinkpad); |
|
1331 } |
|
1332 return chain; |
|
1333 } |
904 |
1334 |
905 /* make the chain that contains the elements needed to perform |
1335 /* make the chain that contains the elements needed to perform |
906 * audio playback. |
1336 * audio playback. |
907 * |
1337 * |
908 * We add a tee as the first element so that we can link the visualisation chain |
1338 * We add a tee as the first element so that we can link the visualisation chain |
948 /* we have to add a queue when we need to decouple for the video sink in |
1391 /* we have to add a queue when we need to decouple for the video sink in |
949 * visualisations */ |
1392 * visualisations */ |
950 GST_DEBUG_OBJECT (playsink, "adding audio queue"); |
1393 GST_DEBUG_OBJECT (playsink, "adding audio queue"); |
951 chain->queue = gst_element_factory_make ("queue", "aqueue"); |
1394 chain->queue = gst_element_factory_make ("queue", "aqueue"); |
952 gst_bin_add (bin, chain->queue); |
1395 gst_bin_add (bin, chain->queue); |
953 } |
1396 prev = head = chain->queue; |
954 |
1397 } else { |
955 if (raw) { |
1398 head = chain->sink; |
|
1399 prev = NULL; |
|
1400 } |
|
1401 |
|
1402 /* check if the sink, or something within the sink, has the volume property. |
|
1403 * If it does we don't need to add a volume element. */ |
|
1404 elem = gst_play_sink_find_property_sinks (playsink, chain->sink, "volume"); |
|
1405 if (elem) { |
|
1406 chain->volume = elem; |
|
1407 |
|
1408 GST_DEBUG_OBJECT (playsink, "the sink has a volume property"); |
|
1409 have_volume = TRUE; |
|
1410 chain->sink_volume = TRUE; |
|
1411 /* if the sink also has a mute property we can use this as well. We'll only |
|
1412 * use the mute property if there is a volume property. We can simulate the |
|
1413 * mute with the volume otherwise. */ |
|
1414 chain->mute = |
|
1415 gst_play_sink_find_property_sinks (playsink, chain->sink, "mute"); |
|
1416 if (chain->mute) { |
|
1417 GST_DEBUG_OBJECT (playsink, "the sink has a mute property"); |
|
1418 } |
|
1419 /* use the sink to control the volume and mute */ |
|
1420 if (playsink->volume_changed) { |
|
1421 g_object_set (G_OBJECT (chain->volume), "volume", playsink->volume, NULL); |
|
1422 } |
|
1423 if (playsink->mute_changed) { |
|
1424 if (chain->mute) { |
|
1425 g_object_set (chain->mute, "mute", playsink->mute, NULL); |
|
1426 } else { |
|
1427 if (playsink->mute) |
|
1428 g_object_set (chain->volume, "volume", (gdouble) 0.0, NULL); |
|
1429 } |
|
1430 } |
|
1431 } else { |
|
1432 /* no volume, we need to add a volume element when we can */ |
|
1433 GST_DEBUG_OBJECT (playsink, "the sink has no volume property"); |
|
1434 have_volume = FALSE; |
|
1435 chain->sink_volume = FALSE; |
|
1436 } |
|
1437 |
|
1438 if (raw && !(playsink->flags & GST_PLAY_FLAG_NATIVE_AUDIO)) { |
|
1439 GST_DEBUG_OBJECT (playsink, "creating audioconvert"); |
956 chain->conv = gst_element_factory_make ("audioconvert", "aconv"); |
1440 chain->conv = gst_element_factory_make ("audioconvert", "aconv"); |
957 if (chain->conv == NULL) |
1441 if (chain->conv == NULL) { |
958 goto no_audioconvert; |
1442 post_missing_element_message (playsink, "audioconvert"); |
959 gst_bin_add (bin, chain->conv); |
1443 GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN, |
960 |
1444 (_("Missing element '%s' - check your GStreamer installation."), |
|
1445 "audioconvert"), ("possibly a liboil version mismatch?")); |
|
1446 } else { |
|
1447 gst_bin_add (bin, chain->conv); |
|
1448 if (prev) { |
|
1449 if (!gst_element_link_pads (prev, "src", chain->conv, "sink")) |
|
1450 goto link_failed; |
|
1451 } else { |
|
1452 head = chain->conv; |
|
1453 } |
|
1454 prev = chain->conv; |
|
1455 } |
|
1456 |
|
1457 GST_DEBUG_OBJECT (playsink, "creating audioresample"); |
961 chain->resample = gst_element_factory_make ("audioresample", "aresample"); |
1458 chain->resample = gst_element_factory_make ("audioresample", "aresample"); |
962 if (chain->resample == NULL) |
1459 if (chain->resample == NULL) { |
963 goto no_audioresample; |
1460 post_missing_element_message (playsink, "audioresample"); |
964 gst_bin_add (bin, chain->resample); |
1461 GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN, |
965 |
1462 (_("Missing element '%s' - check your GStreamer installation."), |
966 res = gst_element_link_pads (chain->conv, "src", chain->resample, "sink"); |
1463 "audioresample"), ("possibly a liboil version mismatch?")); |
967 |
1464 } else { |
968 /* FIXME check if the sink has the volume property */ |
1465 gst_bin_add (bin, chain->resample); |
969 |
1466 if (prev) { |
970 if (playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME) { |
1467 if (!gst_element_link_pads (prev, "src", chain->resample, "sink")) |
|
1468 goto link_failed; |
|
1469 } else { |
|
1470 head = chain->resample; |
|
1471 } |
|
1472 prev = chain->resample; |
|
1473 } |
|
1474 |
|
1475 if (!have_volume && playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME) { |
|
1476 GST_DEBUG_OBJECT (playsink, "creating volume"); |
971 chain->volume = gst_element_factory_make ("volume", "volume"); |
1477 chain->volume = gst_element_factory_make ("volume", "volume"); |
972 if (chain->volume == NULL) |
1478 if (chain->volume == NULL) { |
973 goto no_volume; |
1479 post_missing_element_message (playsink, "volume"); |
974 |
1480 GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN, |
975 /* volume also has the mute property */ |
1481 (_("Missing element '%s' - check your GStreamer installation."), |
976 chain->mute = gst_object_ref (chain->volume); |
1482 "volume"), ("possibly a liboil version mismatch?")); |
977 |
1483 } else { |
978 /* configure with the latest volume */ |
1484 have_volume = TRUE; |
979 g_object_set (G_OBJECT (chain->volume), "volume", playsink->volume, NULL); |
1485 |
980 gst_bin_add (bin, chain->volume); |
1486 /* volume also has the mute property */ |
981 |
1487 chain->mute = chain->volume; |
982 res &= |
1488 |
983 gst_element_link_pads (chain->resample, "src", chain->volume, "sink"); |
1489 /* configure with the latest volume and mute */ |
984 res &= gst_element_link_pads (chain->volume, "src", chain->sink, NULL); |
1490 g_object_set (G_OBJECT (chain->volume), "volume", playsink->volume, |
985 } else { |
1491 NULL); |
986 res &= gst_element_link_pads (chain->resample, "src", chain->sink, NULL); |
1492 g_object_set (G_OBJECT (chain->mute), "mute", playsink->mute, NULL); |
987 } |
1493 gst_bin_add (bin, chain->volume); |
988 if (!res) |
1494 |
|
1495 if (prev) { |
|
1496 if (!gst_element_link_pads (prev, "src", chain->volume, "sink")) |
|
1497 goto link_failed; |
|
1498 } else { |
|
1499 head = chain->volume; |
|
1500 } |
|
1501 prev = chain->volume; |
|
1502 } |
|
1503 } |
|
1504 } |
|
1505 |
|
1506 if (prev) { |
|
1507 /* we only have to link to the previous element if we have something in |
|
1508 * front of the sink */ |
|
1509 GST_DEBUG_OBJECT (playsink, "linking to sink"); |
|
1510 if (!gst_element_link_pads (prev, "src", chain->sink, NULL)) |
989 goto link_failed; |
1511 goto link_failed; |
990 |
1512 } |
991 if (queue) { |
1513 |
992 res = gst_element_link_pads (chain->queue, "src", chain->conv, "sink"); |
1514 /* post a warning if we have no way to configure the volume */ |
993 pad = gst_element_get_pad (chain->queue, "sink"); |
1515 if (!have_volume) { |
994 } else { |
1516 GST_ELEMENT_WARNING (playsink, STREAM, NOT_IMPLEMENTED, |
995 pad = gst_element_get_pad (chain->conv, "sink"); |
1517 (_("No volume control found")), ("Volume/mute is not available")); |
996 } |
1518 } |
997 } else { |
1519 |
998 if (queue) { |
1520 /* and ghost the sinkpad of the headmost element */ |
999 res = gst_element_link_pads (chain->queue, "src", chain->sink, "sink"); |
1521 GST_DEBUG_OBJECT (playsink, "ghosting sink pad"); |
1000 pad = gst_element_get_pad (chain->queue, "sink"); |
1522 pad = gst_element_get_static_pad (head, "sink"); |
1001 } else { |
1523 chain->sinkpad = gst_ghost_pad_new ("sink", pad); |
1002 pad = gst_element_get_pad (chain->sink, "sink"); |
|
1003 } |
|
1004 } |
|
1005 chain->chain.sinkpad = gst_ghost_pad_new ("sink", pad); |
|
1006 gst_object_unref (pad); |
1524 gst_object_unref (pad); |
1007 gst_element_add_pad (chain->chain.bin, chain->chain.sinkpad); |
1525 gst_element_add_pad (chain->chain.bin, chain->sinkpad); |
1008 |
1526 |
1009 return (GstPlayChain *) chain; |
1527 return chain; |
1010 |
1528 |
1011 /* ERRORS */ |
1529 /* ERRORS */ |
1012 no_sinks: |
1530 no_sinks: |
1013 { |
1531 { |
1014 post_missing_element_message (playsink, "autoaudiosink"); |
1532 if (!elem) { |
1015 GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN, |
1533 post_missing_element_message (playsink, "autoaudiosink"); |
1016 (_("Both autoaudiosink and alsasink elements are missing.")), (NULL)); |
1534 GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN, |
1017 free_chain ((GstPlayChain *) chain); |
1535 (_("Both autoaudiosink and alsasink elements are missing.")), (NULL)); |
1018 return NULL; |
1536 } else { |
1019 } |
1537 GST_ELEMENT_ERROR (playsink, CORE, STATE_CHANGE, |
1020 no_audioconvert: |
1538 (_("Both autoaudiosink and alsasink elements are not working.")), |
1021 { |
1539 (NULL)); |
1022 post_missing_element_message (playsink, "audioconvert"); |
1540 } |
1023 GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN, |
|
1024 (_("Missing element '%s' - check your GStreamer installation."), |
|
1025 "audioconvert"), ("possibly a liboil version mismatch?")); |
|
1026 free_chain ((GstPlayChain *) chain); |
|
1027 return NULL; |
|
1028 } |
|
1029 no_audioresample: |
|
1030 { |
|
1031 post_missing_element_message (playsink, "audioresample"); |
|
1032 GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN, |
|
1033 (_("Missing element '%s' - check your GStreamer installation."), |
|
1034 "audioresample"), ("possibly a liboil version mismatch?")); |
|
1035 free_chain ((GstPlayChain *) chain); |
|
1036 return NULL; |
|
1037 } |
|
1038 no_volume: |
|
1039 { |
|
1040 post_missing_element_message (playsink, "volume"); |
|
1041 GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN, |
|
1042 (_("Missing element '%s' - check your GStreamer installation."), |
|
1043 "volume"), ("possibly a liboil version mismatch?")); |
|
1044 free_chain ((GstPlayChain *) chain); |
1541 free_chain ((GstPlayChain *) chain); |
1045 return NULL; |
1542 return NULL; |
1046 } |
1543 } |
1047 link_failed: |
1544 link_failed: |
1048 { |
1545 { |
1049 GST_ELEMENT_ERROR (playsink, CORE, PAD, |
1546 GST_ELEMENT_ERROR (playsink, CORE, PAD, |
1050 (NULL), ("Failed to configure the audio sink.")); |
1547 (NULL), ("Failed to configure the audio sink.")); |
1051 free_chain ((GstPlayChain *) chain); |
1548 free_chain ((GstPlayChain *) chain); |
1052 return NULL; |
1549 return NULL; |
1053 } |
1550 } |
|
1551 } |
|
1552 |
|
1553 static gboolean |
|
1554 setup_audio_chain (GstPlaySink * playsink, gboolean raw, gboolean queue) |
|
1555 { |
|
1556 GstElement *elem; |
|
1557 GstPlayAudioChain *chain; |
|
1558 GstStateChangeReturn ret; |
|
1559 |
|
1560 chain = playsink->audiochain; |
|
1561 |
|
1562 /* if the chain was active we don't do anything */ |
|
1563 if (GST_PLAY_CHAIN (chain)->activated == TRUE) |
|
1564 return TRUE; |
|
1565 |
|
1566 if (chain->chain.raw != raw) |
|
1567 return FALSE; |
|
1568 |
|
1569 /* try to set the sink element to READY again */ |
|
1570 ret = gst_element_set_state (chain->sink, GST_STATE_READY); |
|
1571 if (ret == GST_STATE_CHANGE_FAILURE) |
|
1572 return FALSE; |
|
1573 |
|
1574 /* check if the sink, or something within the sink, has the volume property. |
|
1575 * If it does we don't need to add a volume element. */ |
|
1576 elem = gst_play_sink_find_property_sinks (playsink, chain->sink, "volume"); |
|
1577 if (elem) { |
|
1578 chain->volume = elem; |
|
1579 |
|
1580 if (playsink->volume_changed) { |
|
1581 GST_DEBUG_OBJECT (playsink, "the sink has a volume property, setting %f", |
|
1582 playsink->volume); |
|
1583 /* use the sink to control the volume */ |
|
1584 g_object_set (G_OBJECT (chain->volume), "volume", playsink->volume, NULL); |
|
1585 } |
|
1586 /* if the sink also has a mute property we can use this as well. We'll only |
|
1587 * use the mute property if there is a volume property. We can simulate the |
|
1588 * mute with the volume otherwise. */ |
|
1589 chain->mute = |
|
1590 gst_play_sink_find_property_sinks (playsink, chain->sink, "mute"); |
|
1591 if (chain->mute) { |
|
1592 GST_DEBUG_OBJECT (playsink, "the sink has a mute property"); |
|
1593 } |
|
1594 } else { |
|
1595 /* no volume, we need to add a volume element when we can */ |
|
1596 GST_DEBUG_OBJECT (playsink, "the sink has no volume property"); |
|
1597 if (!raw) { |
|
1598 GST_LOG_OBJECT (playsink, "non-raw format, can't do soft volume control"); |
|
1599 chain->volume = NULL; |
|
1600 chain->mute = NULL; |
|
1601 } else { |
|
1602 /* both last and current chain are raw audio, there should be a volume |
|
1603 * element already, unless the sink changed from one with a volume |
|
1604 * property to one that hasn't got a volume property, in which case we |
|
1605 * re-generate the chain */ |
|
1606 if (chain->volume == NULL) { |
|
1607 GST_DEBUG_OBJECT (playsink, "no existing volume element to re-use"); |
|
1608 return FALSE; |
|
1609 } |
|
1610 |
|
1611 GST_DEBUG_OBJECT (playsink, "reusing existing volume element"); |
|
1612 } |
|
1613 } |
|
1614 return TRUE; |
1054 } |
1615 } |
1055 |
1616 |
1056 /* |
1617 /* |
1057 * +-------------------------------------------------------------------+ |
1618 * +-------------------------------------------------------------------+ |
1058 * | visbin | |
1619 * | visbin | |
1162 free_chain ((GstPlayChain *) chain); |
1731 free_chain ((GstPlayChain *) chain); |
1163 return NULL; |
1732 return NULL; |
1164 } |
1733 } |
1165 } |
1734 } |
1166 |
1735 |
1167 #if 0 |
|
1168 static gboolean |
|
1169 activate_vis (GstPlaySink * playsink, gboolean activate) |
|
1170 { |
|
1171 /* need to have an audio chain */ |
|
1172 if (!playsink->audiochain || !playsink->vischain) |
|
1173 return FALSE; |
|
1174 |
|
1175 if (playsink->vischain->activated == activate) |
|
1176 return TRUE; |
|
1177 |
|
1178 if (activate) { |
|
1179 /* activation: Add the vis chain to the sink bin . Take a new srcpad from |
|
1180 * the tee of the audio chain and link it to the sinkpad of the vis chain. |
|
1181 */ |
|
1182 |
|
1183 } else { |
|
1184 /* deactivation: release the srcpad from the tee of the audio chain. Set the |
|
1185 * vis chain to NULL and remove it from the sink bin */ |
|
1186 |
|
1187 } |
|
1188 return TRUE; |
|
1189 } |
|
1190 #endif |
|
1191 |
|
1192 /* this function is called when all the request pads are requested and when we |
1736 /* this function is called when all the request pads are requested and when we |
1193 * have to construct the final pipeline. |
1737 * have to construct the final pipeline. Based on the flags we construct the |
|
1738 * final output pipelines. |
1194 */ |
1739 */ |
1195 #ifdef __SYMBIAN32__ |
1740 #ifdef __SYMBIAN32__ |
1196 EXPORT_C |
1741 EXPORT_C |
1197 #endif |
1742 #endif |
1198 |
1743 |
1199 gboolean |
1744 gboolean |
1200 gst_play_sink_reconfigure (GstPlaySink * playsink) |
1745 gst_play_sink_reconfigure (GstPlaySink * playsink) |
1201 { |
1746 { |
1202 GstPlayFlags flags; |
1747 GstPlayFlags flags; |
1203 gboolean need_audio, need_video, need_vis; |
1748 gboolean need_audio, need_video, need_vis, need_text, need_subp; |
1204 |
1749 |
1205 GST_DEBUG_OBJECT (playsink, "reconfiguring"); |
1750 GST_DEBUG_OBJECT (playsink, "reconfiguring"); |
1206 |
1751 |
1207 /* assume we need nothing */ |
1752 /* assume we need nothing */ |
1208 need_audio = need_video = need_vis = FALSE; |
1753 need_audio = need_video = need_vis = need_text = need_subp = FALSE; |
1209 |
1754 |
1210 GST_PLAY_SINK_LOCK (playsink); |
1755 GST_PLAY_SINK_LOCK (playsink); |
1211 GST_OBJECT_LOCK (playsink); |
1756 GST_OBJECT_LOCK (playsink); |
1212 /* get flags, there are protected with the object lock */ |
1757 /* get flags, there are protected with the object lock */ |
1213 flags = playsink->flags; |
1758 flags = playsink->flags; |
1214 GST_OBJECT_UNLOCK (playsink); |
1759 GST_OBJECT_UNLOCK (playsink); |
1215 |
1760 |
1216 /* figure out which components we need */ |
1761 /* figure out which components we need */ |
1217 if (flags & GST_PLAY_FLAG_VIDEO && playsink->video_pad) { |
1762 if (flags & GST_PLAY_FLAG_TEXT && (playsink->text_pad || playsink->subp_pad)) { |
|
1763 /* we have a text_pad and we need text rendering, in this case we need a |
|
1764 * video_pad to combine the video with the text */ |
|
1765 if (!playsink->video_pad) |
|
1766 goto subs_but_no_video; |
|
1767 |
|
1768 /* we have subtitles and we are requested to show it, we also need to show |
|
1769 * video in this case. */ |
|
1770 need_video = TRUE; |
|
1771 need_text = (playsink->text_pad != NULL); |
|
1772 need_subp = (playsink->subp_pad != NULL); |
|
1773 |
|
1774 /* we can't handle both of them yet */ |
|
1775 if (need_text && need_subp) |
|
1776 goto subs_and_text; |
|
1777 } else if (flags & GST_PLAY_FLAG_VIDEO && playsink->video_pad) { |
1218 /* we have video and we are requested to show it */ |
1778 /* we have video and we are requested to show it */ |
1219 need_video = TRUE; |
1779 need_video = TRUE; |
1220 } |
1780 } |
1221 if (playsink->audio_pad) { |
1781 if (playsink->audio_pad) { |
1222 if (flags & GST_PLAY_FLAG_AUDIO) { |
1782 if (flags & GST_PLAY_FLAG_AUDIO) { |
1223 need_audio = TRUE; |
1783 need_audio = TRUE; |
1224 } |
1784 } |
1225 if (flags & GST_PLAY_FLAG_VIS && !need_video) { |
1785 if (playsink->audio_pad_raw) { |
1226 /* also add video when we add visualisation */ |
1786 /* only can do vis with raw uncompressed audio */ |
1227 need_video = TRUE; |
1787 if (flags & GST_PLAY_FLAG_VIS && !need_video) { |
1228 need_vis = TRUE; |
1788 /* also add video when we add visualisation */ |
1229 } |
1789 need_video = TRUE; |
1230 } |
1790 need_vis = TRUE; |
1231 |
1791 } |
|
1792 } |
|
1793 } |
|
1794 |
|
1795 /* set up video pipeline */ |
1232 if (need_video) { |
1796 if (need_video) { |
|
1797 gboolean raw, async, queue; |
|
1798 |
|
1799 /* we need a raw sink when we do vis or when we have a raw pad */ |
|
1800 raw = need_vis ? TRUE : playsink->video_pad_raw; |
|
1801 /* we try to set the sink async=FALSE when we need vis, this way we can |
|
1802 * avoid a queue in the audio chain. */ |
|
1803 async = !need_vis; |
|
1804 /* put a little queue in front of the video but only if we are not doing |
|
1805 * subpictures because then we will add the queue in front of the subpicture |
|
1806 * mixer to minimize latency. */ |
|
1807 queue = (need_subp == FALSE); |
|
1808 |
1233 GST_DEBUG_OBJECT (playsink, "adding video, raw %d", |
1809 GST_DEBUG_OBJECT (playsink, "adding video, raw %d", |
1234 playsink->video_pad_raw); |
1810 playsink->video_pad_raw); |
|
1811 |
|
1812 if (playsink->videochain) { |
|
1813 /* try to reactivate the chain */ |
|
1814 if (!setup_video_chain (playsink, raw, async, queue)) { |
|
1815 add_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE); |
|
1816 activate_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE); |
|
1817 free_chain ((GstPlayChain *) playsink->videochain); |
|
1818 playsink->videochain = NULL; |
|
1819 } |
|
1820 } |
|
1821 |
1235 if (!playsink->videochain) { |
1822 if (!playsink->videochain) { |
1236 gboolean raw, async; |
1823 playsink->videochain = gen_video_chain (playsink, raw, async, queue); |
1237 |
1824 } |
1238 /* we need a raw sink when we do vis or when we have a raw pad */ |
1825 if (playsink->videochain) { |
1239 raw = need_vis ? TRUE : playsink->video_pad_raw; |
1826 GST_DEBUG_OBJECT (playsink, "adding video chain"); |
1240 /* we try to set the sink async=FALSE when we need vis, this way we can |
1827 add_chain (GST_PLAY_CHAIN (playsink->videochain), TRUE); |
1241 * avoid a queue in the audio chain. */ |
1828 activate_chain (GST_PLAY_CHAIN (playsink->videochain), TRUE); |
1242 async = !need_vis; |
1829 /* if we are not part of vis or subtitles, set the ghostpad target */ |
1243 |
1830 if (!need_vis && !need_text && playsink->text_pad == NULL) { |
1244 playsink->videochain = gen_video_chain (playsink, raw, async); |
1831 GST_DEBUG_OBJECT (playsink, "ghosting video sinkpad"); |
1245 } |
1832 gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->video_pad), |
1246 add_chain (playsink->videochain, TRUE); |
1833 playsink->videochain->sinkpad); |
1247 activate_chain (playsink->videochain, TRUE); |
1834 } |
1248 if (!need_vis) |
1835 } |
1249 gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->video_pad), |
|
1250 playsink->videochain->sinkpad); |
|
1251 } else { |
1836 } else { |
|
1837 GST_DEBUG_OBJECT (playsink, "no video needed"); |
1252 if (playsink->videochain) { |
1838 if (playsink->videochain) { |
1253 add_chain (playsink->videochain, FALSE); |
1839 GST_DEBUG_OBJECT (playsink, "removing video chain"); |
1254 activate_chain (playsink->videochain, FALSE); |
1840 if (playsink->vischain) { |
|
1841 GstPad *srcpad; |
|
1842 |
|
1843 GST_DEBUG_OBJECT (playsink, "unlinking vis chain"); |
|
1844 |
|
1845 /* also had visualisation, release the tee srcpad before we then |
|
1846 * unlink the video from it */ |
|
1847 if (playsink->audio_tee_vissrc) { |
|
1848 gst_element_release_request_pad (playsink->audio_tee, |
|
1849 playsink->audio_tee_vissrc); |
|
1850 gst_object_unref (playsink->audio_tee_vissrc); |
|
1851 playsink->audio_tee_vissrc = NULL; |
|
1852 } |
|
1853 srcpad = |
|
1854 gst_element_get_static_pad (playsink->vischain->chain.bin, "src"); |
|
1855 gst_pad_unlink (srcpad, playsink->videochain->sinkpad); |
|
1856 } |
|
1857 add_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE); |
|
1858 activate_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE); |
1255 } |
1859 } |
1256 if (playsink->video_pad) |
1860 if (playsink->video_pad) |
1257 gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->video_pad), NULL); |
1861 gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->video_pad), NULL); |
1258 } |
1862 } |
1259 |
1863 |
|
1864 if (need_text) { |
|
1865 GST_DEBUG_OBJECT (playsink, "adding text"); |
|
1866 if (!playsink->textchain) { |
|
1867 GST_DEBUG_OBJECT (playsink, "creating text chain"); |
|
1868 playsink->textchain = gen_text_chain (playsink); |
|
1869 } |
|
1870 if (playsink->textchain) { |
|
1871 GST_DEBUG_OBJECT (playsink, "adding text chain"); |
|
1872 add_chain (GST_PLAY_CHAIN (playsink->textchain), TRUE); |
|
1873 gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->text_pad), |
|
1874 playsink->textchain->textsinkpad); |
|
1875 gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->video_pad), |
|
1876 playsink->textchain->videosinkpad); |
|
1877 gst_pad_link (playsink->textchain->srcpad, playsink->videochain->sinkpad); |
|
1878 activate_chain (GST_PLAY_CHAIN (playsink->textchain), TRUE); |
|
1879 if (playsink->textchain->overlay) |
|
1880 g_object_set (playsink->textchain->overlay, "silent", FALSE, NULL); |
|
1881 } |
|
1882 } else { |
|
1883 GST_DEBUG_OBJECT (playsink, "no text needed"); |
|
1884 /* we have no subtitles/text or we are requested to not show them */ |
|
1885 if (playsink->textchain) { |
|
1886 if (playsink->text_pad == NULL) { |
|
1887 /* no text pad, remove the chain entirely */ |
|
1888 GST_DEBUG_OBJECT (playsink, "removing text chain"); |
|
1889 add_chain (GST_PLAY_CHAIN (playsink->textchain), FALSE); |
|
1890 activate_chain (GST_PLAY_CHAIN (playsink->textchain), FALSE); |
|
1891 } else { |
|
1892 /* we have a chain and a textpad, turn the subtitles off */ |
|
1893 GST_DEBUG_OBJECT (playsink, "turning off the text"); |
|
1894 if (playsink->textchain->overlay) |
|
1895 g_object_set (playsink->textchain->overlay, "silent", TRUE, NULL); |
|
1896 } |
|
1897 } |
|
1898 if (!need_video && playsink->video_pad) |
|
1899 gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->video_pad), NULL); |
|
1900 if (playsink->text_pad) |
|
1901 gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->text_pad), NULL); |
|
1902 } |
|
1903 |
|
1904 if (need_subp && playsink->videochain) { |
|
1905 GST_DEBUG_OBJECT (playsink, "adding subpicture"); |
|
1906 if (!playsink->subpchain) { |
|
1907 GST_DEBUG_OBJECT (playsink, "creating subpicture chain"); |
|
1908 playsink->subpchain = gen_subp_chain (playsink); |
|
1909 } |
|
1910 if (playsink->subpchain) { |
|
1911 GST_DEBUG_OBJECT (playsink, "adding subp chain"); |
|
1912 add_chain (GST_PLAY_CHAIN (playsink->subpchain), TRUE); |
|
1913 gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->subp_pad), |
|
1914 playsink->subpchain->subpsinkpad); |
|
1915 gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->video_pad), |
|
1916 playsink->subpchain->videosinkpad); |
|
1917 gst_pad_link (playsink->subpchain->srcpad, playsink->videochain->sinkpad); |
|
1918 activate_chain (GST_PLAY_CHAIN (playsink->subpchain), TRUE); |
|
1919 } |
|
1920 } else { |
|
1921 GST_DEBUG_OBJECT (playsink, "no subpicture needed"); |
|
1922 /* we have no subpicture or we are requested to not show them */ |
|
1923 if (playsink->subpchain) { |
|
1924 if (playsink->subp_pad == NULL) { |
|
1925 /* no subpicture pad, remove the chain entirely */ |
|
1926 GST_DEBUG_OBJECT (playsink, "removing subp chain"); |
|
1927 add_chain (GST_PLAY_CHAIN (playsink->subpchain), FALSE); |
|
1928 activate_chain (GST_PLAY_CHAIN (playsink->subpchain), FALSE); |
|
1929 } else { |
|
1930 /* we have a chain and a subpicture pad, turn the subtitles off */ |
|
1931 GST_DEBUG_OBJECT (playsink, "turning off the subp"); |
|
1932 } |
|
1933 } |
|
1934 if (!need_video && playsink->video_pad) |
|
1935 gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->video_pad), NULL); |
|
1936 if (playsink->subp_pad) |
|
1937 gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->subp_pad), NULL); |
|
1938 } |
|
1939 |
1260 if (need_audio) { |
1940 if (need_audio) { |
|
1941 gboolean raw, queue; |
|
1942 |
1261 GST_DEBUG_OBJECT (playsink, "adding audio"); |
1943 GST_DEBUG_OBJECT (playsink, "adding audio"); |
|
1944 |
|
1945 /* get a raw sink if we are asked for a raw pad */ |
|
1946 raw = playsink->audio_pad_raw; |
|
1947 if (need_vis && playsink->videochain) { |
|
1948 /* If we are dealing with visualisations, we need to add a queue to |
|
1949 * decouple the audio from the video part. We only have to do this when |
|
1950 * the video part is async=true */ |
|
1951 queue = ((GstPlayVideoChain *) playsink->videochain)->async; |
|
1952 GST_DEBUG_OBJECT (playsink, "need audio queue for vis: %d", queue); |
|
1953 } else { |
|
1954 /* no vis, we can avoid a queue */ |
|
1955 GST_DEBUG_OBJECT (playsink, "don't need audio queue"); |
|
1956 queue = FALSE; |
|
1957 } |
|
1958 |
|
1959 if (playsink->audiochain) { |
|
1960 /* try to reactivate the chain */ |
|
1961 if (!setup_audio_chain (playsink, raw, queue)) { |
|
1962 GST_DEBUG_OBJECT (playsink, "removing current audio chain"); |
|
1963 if (playsink->audio_tee_asrc) { |
|
1964 gst_element_release_request_pad (playsink->audio_tee, |
|
1965 playsink->audio_tee_asrc); |
|
1966 gst_object_unref (playsink->audio_tee_asrc); |
|
1967 playsink->audio_tee_asrc = NULL; |
|
1968 } |
|
1969 add_chain (GST_PLAY_CHAIN (playsink->audiochain), FALSE); |
|
1970 activate_chain (GST_PLAY_CHAIN (playsink->audiochain), FALSE); |
|
1971 playsink->audiochain->volume = NULL; |
|
1972 playsink->audiochain->mute = NULL; |
|
1973 free_chain ((GstPlayChain *) playsink->audiochain); |
|
1974 playsink->audiochain = NULL; |
|
1975 playsink->volume_changed = playsink->mute_changed = FALSE; |
|
1976 } |
|
1977 } |
|
1978 |
1262 if (!playsink->audiochain) { |
1979 if (!playsink->audiochain) { |
1263 gboolean raw, queue; |
1980 GST_DEBUG_OBJECT (playsink, "creating new audio chain"); |
1264 |
|
1265 /* get a raw sink if we are asked for a raw pad */ |
|
1266 raw = playsink->audio_pad_raw; |
|
1267 if (need_vis) { |
|
1268 /* If we are dealing with visualisations, we need to add a queue to |
|
1269 * decouple the audio from the video part. We only have to do this when |
|
1270 * the video part is async=true */ |
|
1271 queue = ((GstPlayVideoChain *) playsink->videochain)->async; |
|
1272 GST_DEBUG_OBJECT (playsink, "need audio queue for vis: %d", queue); |
|
1273 } else { |
|
1274 /* no vis, we can avoid a queue */ |
|
1275 GST_DEBUG_OBJECT (playsink, "don't need audio queue"); |
|
1276 queue = FALSE; |
|
1277 } |
|
1278 |
|
1279 playsink->audiochain = gen_audio_chain (playsink, raw, queue); |
1981 playsink->audiochain = gen_audio_chain (playsink, raw, queue); |
1280 } |
1982 } |
1281 add_chain (playsink->audiochain, TRUE); |
1983 |
1282 gst_pad_link (playsink->audio_tee_asrc, playsink->audiochain->sinkpad); |
1984 if (playsink->audiochain) { |
1283 activate_chain (playsink->audiochain, TRUE); |
1985 GST_DEBUG_OBJECT (playsink, "adding audio chain"); |
|
1986 if (playsink->audio_tee_asrc == NULL) { |
|
1987 playsink->audio_tee_asrc = |
|
1988 gst_element_get_request_pad (playsink->audio_tee, "src%d"); |
|
1989 } |
|
1990 add_chain (GST_PLAY_CHAIN (playsink->audiochain), TRUE); |
|
1991 activate_chain (GST_PLAY_CHAIN (playsink->audiochain), TRUE); |
|
1992 gst_pad_link (playsink->audio_tee_asrc, playsink->audiochain->sinkpad); |
|
1993 } |
1284 } else { |
1994 } else { |
|
1995 GST_DEBUG_OBJECT (playsink, "no audio needed"); |
1285 /* we have no audio or we are requested to not play audio */ |
1996 /* we have no audio or we are requested to not play audio */ |
1286 if (playsink->audiochain) { |
1997 if (playsink->audiochain) { |
1287 gst_pad_unlink (playsink->audio_tee_asrc, playsink->audiochain->sinkpad); |
1998 GST_DEBUG_OBJECT (playsink, "removing audio chain"); |
1288 add_chain (playsink->audiochain, FALSE); |
1999 /* release the audio pad */ |
1289 activate_chain (playsink->audiochain, FALSE); |
2000 if (playsink->audio_tee_asrc) { |
|
2001 gst_element_release_request_pad (playsink->audio_tee, |
|
2002 playsink->audio_tee_asrc); |
|
2003 gst_object_unref (playsink->audio_tee_asrc); |
|
2004 playsink->audio_tee_asrc = NULL; |
|
2005 } |
|
2006 if (playsink->audiochain->sink_volume) { |
|
2007 playsink->audiochain->volume = NULL; |
|
2008 playsink->audiochain->mute = NULL; |
|
2009 } |
|
2010 add_chain (GST_PLAY_CHAIN (playsink->audiochain), FALSE); |
|
2011 activate_chain (GST_PLAY_CHAIN (playsink->audiochain), FALSE); |
1290 } |
2012 } |
1291 } |
2013 } |
1292 |
2014 |
1293 if (need_vis) { |
2015 if (need_vis) { |
1294 GstPad *srcpad; |
2016 GstPad *srcpad; |
1296 if (!playsink->vischain) |
2018 if (!playsink->vischain) |
1297 playsink->vischain = gen_vis_chain (playsink); |
2019 playsink->vischain = gen_vis_chain (playsink); |
1298 |
2020 |
1299 GST_DEBUG_OBJECT (playsink, "adding visualisation"); |
2021 GST_DEBUG_OBJECT (playsink, "adding visualisation"); |
1300 |
2022 |
1301 srcpad = |
2023 if (playsink->vischain) { |
1302 gst_element_get_pad (GST_ELEMENT_CAST (playsink->vischain->bin), "src"); |
2024 GST_DEBUG_OBJECT (playsink, "setting up vis chain"); |
1303 add_chain (playsink->vischain, TRUE); |
2025 srcpad = |
1304 gst_pad_link (playsink->audio_tee_vissrc, playsink->vischain->sinkpad); |
2026 gst_element_get_static_pad (playsink->vischain->chain.bin, "src"); |
1305 gst_pad_link (srcpad, playsink->videochain->sinkpad); |
2027 add_chain (GST_PLAY_CHAIN (playsink->vischain), TRUE); |
1306 gst_object_unref (srcpad); |
2028 activate_chain (GST_PLAY_CHAIN (playsink->vischain), TRUE); |
1307 activate_chain (playsink->vischain, TRUE); |
2029 if (playsink->audio_tee_vissrc == NULL) { |
|
2030 playsink->audio_tee_vissrc = |
|
2031 gst_element_get_request_pad (playsink->audio_tee, "src%d"); |
|
2032 } |
|
2033 gst_pad_link (playsink->audio_tee_vissrc, playsink->vischain->sinkpad); |
|
2034 gst_pad_link (srcpad, playsink->videochain->sinkpad); |
|
2035 gst_object_unref (srcpad); |
|
2036 } |
1308 } else { |
2037 } else { |
|
2038 GST_DEBUG_OBJECT (playsink, "no vis needed"); |
1309 if (playsink->vischain) { |
2039 if (playsink->vischain) { |
1310 add_chain (playsink->vischain, FALSE); |
2040 if (playsink->audio_tee_vissrc) { |
1311 activate_chain (playsink->vischain, FALSE); |
2041 gst_element_release_request_pad (playsink->audio_tee, |
1312 } |
2042 playsink->audio_tee_vissrc); |
1313 } |
2043 gst_object_unref (playsink->audio_tee_vissrc); |
|
2044 playsink->audio_tee_vissrc = NULL; |
|
2045 } |
|
2046 GST_DEBUG_OBJECT (playsink, "removing vis chain"); |
|
2047 add_chain (GST_PLAY_CHAIN (playsink->vischain), FALSE); |
|
2048 activate_chain (GST_PLAY_CHAIN (playsink->vischain), FALSE); |
|
2049 } |
|
2050 } |
|
2051 do_async_done (playsink); |
1314 GST_PLAY_SINK_UNLOCK (playsink); |
2052 GST_PLAY_SINK_UNLOCK (playsink); |
1315 |
2053 |
1316 return TRUE; |
2054 return TRUE; |
1317 } |
2055 |
|
2056 /* ERRORS */ |
|
2057 subs_but_no_video: |
|
2058 { |
|
2059 GST_ELEMENT_ERROR (playsink, STREAM, FORMAT, |
|
2060 (_("Can't play a text file without video.")), |
|
2061 ("Have text pad but no video pad")); |
|
2062 GST_PLAY_SINK_UNLOCK (playsink); |
|
2063 return FALSE; |
|
2064 } |
|
2065 subs_and_text: |
|
2066 { |
|
2067 GST_ELEMENT_ERROR (playsink, STREAM, FORMAT, |
|
2068 (_("Can't play a text subtitles and subpictures.")), |
|
2069 ("Have text pad and subpicture pad")); |
|
2070 GST_PLAY_SINK_UNLOCK (playsink); |
|
2071 return FALSE; |
|
2072 } |
|
2073 } |
|
2074 |
|
2075 /** |
|
2076 * gst_play_sink_set_flags: |
|
2077 * @playsink: a #GstPlaySink |
|
2078 * @flags: #GstPlayFlags |
|
2079 * |
|
2080 * Configure @flags on @playsink. The flags control the behaviour of @playsink |
|
2081 * when constructing the sink pipelins. |
|
2082 * |
|
2083 * Returns: TRUE if the flags could be configured. |
|
2084 */ |
1318 #ifdef __SYMBIAN32__ |
2085 #ifdef __SYMBIAN32__ |
1319 EXPORT_C |
2086 EXPORT_C |
1320 #endif |
2087 #endif |
1321 |
2088 |
1322 |
|
1323 gboolean |
2089 gboolean |
1324 gst_play_sink_set_flags (GstPlaySink * playsink, GstPlayFlags flags) |
2090 gst_play_sink_set_flags (GstPlaySink * playsink, GstPlayFlags flags) |
1325 { |
2091 { |
1326 g_return_val_if_fail (GST_IS_PLAY_SINK (playsink), FALSE); |
2092 g_return_val_if_fail (GST_IS_PLAY_SINK (playsink), FALSE); |
1327 |
2093 |
1518 static gboolean |
2445 static gboolean |
1519 gst_play_sink_send_event (GstElement * element, GstEvent * event) |
2446 gst_play_sink_send_event (GstElement * element, GstEvent * event) |
1520 { |
2447 { |
1521 gboolean res = FALSE; |
2448 gboolean res = FALSE; |
1522 GstEventType event_type = GST_EVENT_TYPE (event); |
2449 GstEventType event_type = GST_EVENT_TYPE (event); |
|
2450 GstPlaySink *playsink; |
|
2451 |
|
2452 playsink = GST_PLAY_SINK_CAST (element); |
1523 |
2453 |
1524 switch (event_type) { |
2454 switch (event_type) { |
1525 case GST_EVENT_SEEK: |
2455 case GST_EVENT_SEEK: |
1526 GST_DEBUG_OBJECT (element, "Sending seek event to a sink"); |
2456 GST_DEBUG_OBJECT (element, "Sending event to a sink"); |
1527 res = gst_play_sink_send_event_to_sink (GST_PLAY_SINK (element), event); |
2457 res = gst_play_sink_send_event_to_sink (playsink, event); |
1528 break; |
2458 break; |
|
2459 case GST_EVENT_STEP: |
|
2460 { |
|
2461 GstFormat format; |
|
2462 guint64 amount; |
|
2463 gdouble rate; |
|
2464 gboolean flush, intermediate; |
|
2465 |
|
2466 gst_event_parse_step (event, &format, &amount, &rate, &flush, |
|
2467 &intermediate); |
|
2468 |
|
2469 if (format == GST_FORMAT_BUFFERS) { |
|
2470 /* for buffers, we will try to step video frames, for other formats we |
|
2471 * send the step to all sinks */ |
|
2472 res = gst_play_sink_send_event_to_sink (playsink, event); |
|
2473 } else { |
|
2474 res = |
|
2475 GST_ELEMENT_CLASS (gst_play_sink_parent_class)->send_event (element, |
|
2476 event); |
|
2477 } |
|
2478 break; |
|
2479 } |
1529 default: |
2480 default: |
1530 res = parent_class->send_event (element, event); |
2481 res = |
|
2482 GST_ELEMENT_CLASS (gst_play_sink_parent_class)->send_event (element, |
|
2483 event); |
1531 break; |
2484 break; |
1532 } |
2485 } |
1533 return res; |
2486 return res; |
1534 } |
2487 } |
1535 |
2488 |
1536 static GstStateChangeReturn |
2489 static GstStateChangeReturn |
1537 gst_play_sink_change_state (GstElement * element, GstStateChange transition) |
2490 gst_play_sink_change_state (GstElement * element, GstStateChange transition) |
1538 { |
2491 { |
1539 GstStateChangeReturn ret; |
2492 GstStateChangeReturn ret; |
|
2493 GstStateChangeReturn bret; |
|
2494 |
1540 GstPlaySink *playsink; |
2495 GstPlaySink *playsink; |
1541 |
2496 |
1542 playsink = GST_PLAY_SINK (element); |
2497 playsink = GST_PLAY_SINK (element); |
1543 |
2498 |
1544 switch (transition) { |
2499 switch (transition) { |
1545 case GST_STATE_CHANGE_READY_TO_PAUSED: |
2500 case GST_STATE_CHANGE_READY_TO_PAUSED: |
|
2501 /* we want to go async to PAUSED until we managed to configure and add the |
|
2502 * sinks */ |
|
2503 do_async_start (playsink); |
|
2504 ret = GST_STATE_CHANGE_ASYNC; |
|
2505 break; |
|
2506 case GST_STATE_CHANGE_PAUSED_TO_READY: |
|
2507 case GST_STATE_CHANGE_READY_TO_NULL: |
|
2508 if (playsink->audiochain && playsink->audiochain->sink_volume) { |
|
2509 /* remove our links to the mute and volume elements when they were |
|
2510 * provided by a sink */ |
|
2511 playsink->audiochain->volume = NULL; |
|
2512 playsink->audiochain->mute = NULL; |
|
2513 } |
|
2514 ret = GST_STATE_CHANGE_SUCCESS; |
1546 break; |
2515 break; |
1547 default: |
2516 default: |
1548 break; |
2517 /* all other state changes return SUCCESS by default, this value can be |
1549 } |
2518 * overridden by the result of the children */ |
1550 |
2519 ret = GST_STATE_CHANGE_SUCCESS; |
1551 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); |
2520 break; |
1552 if (ret == GST_STATE_CHANGE_FAILURE) |
2521 } |
1553 return ret; |
2522 |
|
2523 /* do the state change of the children */ |
|
2524 bret = |
|
2525 GST_ELEMENT_CLASS (gst_play_sink_parent_class)->change_state (element, |
|
2526 transition); |
|
2527 /* now look at the result of our children and adjust the return value */ |
|
2528 switch (bret) { |
|
2529 case GST_STATE_CHANGE_FAILURE: |
|
2530 /* failure, we stop */ |
|
2531 goto activate_failed; |
|
2532 case GST_STATE_CHANGE_NO_PREROLL: |
|
2533 /* some child returned NO_PREROLL. This is strange but we never know. We |
|
2534 * commit our async state change (if any) and return the NO_PREROLL */ |
|
2535 do_async_done (playsink); |
|
2536 ret = bret; |
|
2537 break; |
|
2538 case GST_STATE_CHANGE_ASYNC: |
|
2539 /* some child was async, return this */ |
|
2540 ret = bret; |
|
2541 break; |
|
2542 default: |
|
2543 /* return our previously configured return value */ |
|
2544 break; |
|
2545 } |
1554 |
2546 |
1555 switch (transition) { |
2547 switch (transition) { |
1556 case GST_STATE_CHANGE_READY_TO_PAUSED: |
2548 case GST_STATE_CHANGE_READY_TO_PAUSED: |
1557 break; |
2549 break; |
1558 case GST_STATE_CHANGE_PLAYING_TO_PAUSED: |
2550 case GST_STATE_CHANGE_PLAYING_TO_PAUSED: |
1559 /* FIXME Release audio device when we implement that */ |
2551 /* FIXME Release audio device when we implement that */ |
|
2552 playsink->need_async_start = TRUE; |
1560 break; |
2553 break; |
1561 case GST_STATE_CHANGE_PAUSED_TO_READY: |
2554 case GST_STATE_CHANGE_PAUSED_TO_READY: |
|
2555 case GST_STATE_CHANGE_READY_TO_NULL: |
1562 /* remove sinks we added */ |
2556 /* remove sinks we added */ |
1563 if (playsink->videochain) { |
2557 if (playsink->videochain) { |
1564 activate_chain (playsink->videochain, FALSE); |
2558 activate_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE); |
1565 add_chain (playsink->videochain, FALSE); |
2559 add_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE); |
1566 } |
2560 } |
1567 if (playsink->audiochain) { |
2561 if (playsink->audiochain) { |
1568 activate_chain (playsink->audiochain, FALSE); |
2562 activate_chain (GST_PLAY_CHAIN (playsink->audiochain), FALSE); |
1569 add_chain (playsink->audiochain, FALSE); |
2563 add_chain (GST_PLAY_CHAIN (playsink->audiochain), FALSE); |
1570 } |
2564 } |
|
2565 if (playsink->vischain) { |
|
2566 activate_chain (GST_PLAY_CHAIN (playsink->vischain), FALSE); |
|
2567 add_chain (GST_PLAY_CHAIN (playsink->vischain), FALSE); |
|
2568 } |
|
2569 if (playsink->textchain) { |
|
2570 activate_chain (GST_PLAY_CHAIN (playsink->textchain), FALSE); |
|
2571 add_chain (GST_PLAY_CHAIN (playsink->textchain), FALSE); |
|
2572 } |
|
2573 if (playsink->subpchain) { |
|
2574 activate_chain (GST_PLAY_CHAIN (playsink->subpchain), FALSE); |
|
2575 add_chain (GST_PLAY_CHAIN (playsink->subpchain), FALSE); |
|
2576 } |
|
2577 do_async_done (playsink); |
1571 break; |
2578 break; |
1572 default: |
2579 default: |
1573 break; |
2580 break; |
1574 } |
2581 } |
1575 |
|
1576 return ret; |
2582 return ret; |
1577 } |
2583 |
|
2584 /* ERRORS */ |
|
2585 activate_failed: |
|
2586 { |
|
2587 GST_DEBUG_OBJECT (element, |
|
2588 "element failed to change states -- activation problem?"); |
|
2589 return GST_STATE_CHANGE_FAILURE; |
|
2590 } |
|
2591 } |