aboutsummaryrefslogtreecommitdiff
path: root/modules/pdp_mp4player~.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/pdp_mp4player~.cpp')
-rw-r--r--modules/pdp_mp4player~.cpp384
1 files changed, 384 insertions, 0 deletions
diff --git a/modules/pdp_mp4player~.cpp b/modules/pdp_mp4player~.cpp
new file mode 100644
index 0000000..613f673
--- /dev/null
+++ b/modules/pdp_mp4player~.cpp
@@ -0,0 +1,384 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@free.fr)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* This object is a quicktime stream picker object
+ * A lot of this object code is inspired by the code from mpeg4ip
+ * Copyright (c) 2000, 2001, 2002 Dave Mackie, Bill May & others
+ * The rest is written by Yves Degoyon ( ydegoyon@free.fr )
+ */
+
+
+#include "pdp_mp4player~.h"
+
+static char *pdp_mp4player_version = "pdp_mp4player~: version 0.1, a mpeg4ip stream decoder ( ydegoyon@free.fr).";
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+static void pdp_mp4player_audio(t_pdp_mp4player *x, t_floatarg faudio )
+{
+ if ( ( faudio == 0. ) || ( faudio == 1. ) )
+ {
+ x->x_audio = (int)faudio;
+ }
+}
+
+static void pdp_mp4player_overtcp(t_pdp_mp4player *x, t_floatarg fovertcp )
+{
+ if ( ( fovertcp == 0. ) || ( fovertcp == 1. ) )
+ {
+ x->x_rtpovertcp = (t_int)fovertcp;
+ config.set_config_value(CONFIG_USE_RTP_OVER_RTSP, x->x_rtpovertcp);
+ if ( x->x_rtpovertcp )
+ {
+ post("pdp_mp4player~ : using rtp over rtsp (tcp)" );
+ }
+ else
+ {
+ post("pdp_mp4player~ : using rtp mode (udp)" );
+ }
+ }
+}
+
+static void pdp_mp4player_priority(t_pdp_mp4player *x, t_floatarg fpriority )
+{
+ if ( ( x->x_priority >= MIN_PRIORITY ) && ( x->x_priority <= MAX_PRIORITY ) )
+ {
+ x->x_priority = (int)fpriority;
+ }
+}
+
+static void pdp_mp4player_vwidth(t_pdp_mp4player *x, t_floatarg fWidth )
+{
+ if ( ( (t_int) fWidth <= 0 ) )
+ {
+ post("pdp_mp4player~ : wrong width : %d", fWidth );
+ return;
+ }
+
+ post( "pdp_mp4player~ : setting width : %d", (t_int) fWidth );
+ config.set_config_value( CONFIG_VIDEO_RAW_WIDTH, (t_int) fWidth );
+
+}
+
+static void pdp_mp4player_vheight(t_pdp_mp4player *x, t_floatarg fHeight )
+{
+ if ( ( (t_int) fHeight <= 0 ) )
+ {
+ post("pdp_mp4player~ : wrong height : %d", fHeight );
+ return;
+ }
+
+ post( "pdp_mp4player~ : setting height : %d", (t_int) fHeight );
+ config.set_config_value( CONFIG_VIDEO_RAW_HEIGHT, (t_int) fHeight );
+
+}
+
+static void pdp_mp4player_disconnect(t_pdp_mp4player *x)
+{
+ if (!x->x_streaming)
+ {
+ post("pdp_mp4player~ : close request but no stream is played ... ignored" );
+ return;
+ }
+
+ x->x_streaming = 0;
+
+ outlet_float( x->x_outlet_streaming, x->x_streaming );
+ x->x_nbframes = 0;
+ outlet_float( x->x_outlet_nbframes, x->x_nbframes );
+
+ post( "pdp_mp4player~ : deleting session" );
+ delete x->x_psession;
+ post( "pdp_mp4player~ : deleting semaphore" );
+ SDL_DestroySemaphore(x->x_psem);
+}
+
+static void *pdp_mp4player_decode(void *tdata)
+{
+ t_pdp_mp4player *x = (t_pdp_mp4player*)tdata;
+ struct sched_param schedprio;
+ t_int pmin, pmax;
+ struct timespec twait, mwait;
+
+ twait.tv_sec = 0;
+ twait.tv_nsec = 10000000; // 10 ms
+
+ schedprio.sched_priority = 0;
+ if ( sched_setscheduler(0, SCHED_OTHER, &schedprio) == -1)
+ {
+ post("pdp_mp4player~ : couldn't set scheduler for decoding thread.\n");
+ }
+ if ( setpriority( PRIO_PROCESS, 0, x->x_priority ) < 0 )
+ {
+ post("pdp_mp4player~ : couldn't set priority to %d for decoding thread.\n", x->x_priority );
+ }
+ else
+ {
+ post("pdp_mp4player~ : priority set to %d for thread %d.\n", x->x_priority, x->x_decodechild );
+ }
+
+ while ( x->x_streaming )
+ {
+ x->x_decodingstate = x->x_psession->sync_thread(x->x_decodingstate);
+ nanosleep( &twait, NULL ); // nothing to read, just wait
+ }
+
+ post( "pdp_mp4player~ : decoding thread %d exiting....", x->x_decodechild );
+ x->x_decodechild = 0;
+ pthread_exit(NULL);
+}
+
+
+static void pdp_mp4player_connect(t_pdp_mp4player *x, t_symbol *s)
+{
+ t_int ret, i;
+ char buffer[1024];
+ char errmsg[512];
+ pthread_attr_t decode_child_attr;
+
+ if ( x->x_streaming )
+ {
+ post("pdp_mp4player~ : connection request but a connection is pending ... disconnecting" );
+ pdp_mp4player_disconnect(x);
+ }
+
+ if ( x->x_url ) free( x->x_url );
+ x->x_url = (char*) malloc( strlen( s->s_name ) + 1 );
+ strcpy( x->x_url, s->s_name );
+
+ x->x_psem = SDL_CreateSemaphore(0);
+ snprintf(buffer, sizeof(buffer), "pdp_mp4player~ - %s", x->x_url);
+ x->x_psession = new CPlayerSession(&x->x_queue, x->x_psem, buffer, x);
+ if (x->x_psession == NULL)
+ {
+ post("pdp_mp4player~ : FATAL : could not create session" );
+ return;
+ }
+
+ ret = parse_name_for_session(x->x_psession, x->x_url, errmsg, sizeof(errmsg), NULL);
+ if (ret < 0)
+ {
+ post("pdp_mp4player~ : FATAL : wrong url : %s : reason : %s", x->x_url, errmsg );
+ delete x->x_psession;
+ return;
+ }
+
+ if (ret > 0)
+ {
+ post("pdp_mp4player~ : %s", errmsg );
+ }
+
+ x->x_psession->set_up_sync_thread();
+
+ if (x->x_psession->play_all_media(TRUE) != 0) {
+ post("pdp_mp4player~ : FATAL : couldn't play all medias" );
+ delete x->x_psession;
+ return;
+ }
+
+ // launch decoding thread
+ if ( pthread_attr_init( &decode_child_attr ) < 0 )
+ {
+ post( "pdp_mp4player~ : could not launch decoding thread" );
+ perror( "pthread_attr_init" );
+ return;
+ }
+ if ( pthread_create( &x->x_decodechild, &decode_child_attr, pdp_mp4player_decode, x ) < 0 )
+ {
+ post( "pdp_mp4player~ : could not launch decoding thread" );
+ perror( "pthread_create" );
+ return;
+ }
+
+ post("pdp_mp4player~ : session started" );
+ x->x_streaming = 1;
+
+ return;
+}
+
+ /* decode the stream to fill up buffers */
+static t_int *pdp_mp4player_perform(t_int *w)
+{
+ t_float *out1 = (t_float *)(w[1]); // left audio inlet
+ t_float *out2 = (t_float *)(w[2]); // right audio inlet
+ t_pdp_mp4player *x = (t_pdp_mp4player *)(w[3]);
+ int n = (int)(w[4]); // number of samples
+ short sampleL, sampleR;
+ struct timeval etime;
+ t_int sn;
+
+ // just read the buffer
+ if ( x->x_audioon )
+ {
+ sn=0;
+ n=n*DEFAULT_CHANNELS;
+ while (n--)
+ {
+ sampleL=x->x_audio_in[ sn++ ];
+ *(out1) = ((t_float)sampleL)/32768.0;
+ if ( DEFAULT_CHANNELS == 1 )
+ {
+ *(out2) = *(out1);
+ }
+ if ( DEFAULT_CHANNELS == 2 )
+ {
+ sampleR=x->x_audio_in[ sn++ ];
+ *(out2) = ((t_float)sampleR)/32768.0;
+ }
+ out1++;
+ out2++;
+ }
+ x->x_audioin_position-=sn;
+ memcpy( &x->x_audio_in[0], &x->x_audio_in[sn], 4*MAX_AUDIO_PACKET_SIZE-sn );
+ // post( "pdp_mp4player~ : audio in position : %d", x->x_audioin_position );
+ if ( x->x_audioin_position <= sn )
+ {
+ x->x_audioon = 0;
+ // post( "pdp_mp4player~ : audio off" );
+ }
+ }
+ else
+ {
+ // post("pdp_mp4player~ : no available audio" );
+ while (n--)
+ {
+ *(out1++) = 0.0;
+ *(out2++) = 0.0;
+ }
+ }
+
+ // check if the framerate has been exceeded
+ if ( gettimeofday(&etime, NULL) == -1)
+ {
+ post("pdp_mp4player~ : could not read time" );
+ }
+ if ( etime.tv_sec != x->x_cursec )
+ {
+ x->x_cursec = etime.tv_sec;
+ outlet_float( x->x_outlet_framerate, x->x_secondcount );
+ x->x_secondcount = 0;
+ }
+
+ if ( x->x_newpicture )
+ {
+ pdp_packet_pass_if_valid(x->x_pdp_out, &x->x_packet0);
+
+ // update streaming status
+ outlet_float( x->x_outlet_streaming, x->x_streaming );
+ x->x_nbframes++;
+ x->x_secondcount++;
+ outlet_float( x->x_outlet_nbframes, x->x_nbframes );
+ }
+
+ return (w+5);
+}
+
+static void pdp_mp4player_dsp(t_pdp_mp4player *x, t_signal **sp)
+{
+ dsp_add(pdp_mp4player_perform, 4, sp[0]->s_vec, sp[1]->s_vec, x, sp[0]->s_n);
+}
+
+static void pdp_mp4player_free(t_pdp_mp4player *x)
+{
+ int i;
+
+ if ( x->x_streaming )
+ {
+ pdp_mp4player_disconnect(x);
+ }
+ post( "pdp_mp4player~ : freeing object" );
+ pdp_packet_mark_unused(x->x_packet0);
+
+ // remove invalid global ports
+ close_plugins();
+}
+
+t_class *pdp_mp4player_class;
+
+void *pdp_mp4player_new(void)
+{
+ int i;
+
+ t_pdp_mp4player *x = (t_pdp_mp4player *)pd_new(pdp_mp4player_class);
+
+ x->x_pdp_out = outlet_new(&x->x_obj, &s_anything);
+
+ x->x_outlet_left = outlet_new(&x->x_obj, &s_signal);
+ x->x_outlet_right = outlet_new(&x->x_obj, &s_signal);
+
+ x->x_outlet_streaming = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet_nbframes = outlet_new(&x->x_obj, &s_float);
+ x->x_outlet_framerate = outlet_new(&x->x_obj, &s_float);
+
+ x->x_packet0 = -1;
+ x->x_nbframes = 0;
+ x->x_cursec = 0;
+ x->x_secondcount = 0;
+ x->x_audioin_position = 0;
+ x->x_priority = DEFAULT_PRIORITY;
+ x->x_decodechild = 0;
+ x->x_newpicture = 0;
+
+ memset( &x->x_audio_buf[0], 0x0, 4*MAX_AUDIO_PACKET_SIZE*sizeof(short) );
+ memset( &x->x_audio_in[0], 0x0, 4*MAX_AUDIO_PACKET_SIZE*sizeof(short) );
+
+ // initialize mpeg4hippies
+ initialize_plugins();
+ config.read_config_file();
+ rtsp_set_error_func(player_library_message);
+ rtsp_set_loglevel(config.get_config_value(CONFIG_RTSP_DEBUG));
+ rtp_set_error_msg_func(player_library_message);
+ rtp_set_loglevel(config.get_config_value(CONFIG_RTP_DEBUG));
+ sdp_set_error_func(player_library_message);
+ sdp_set_loglevel(config.get_config_value(CONFIG_SDP_DEBUG));
+ http_set_error_func(player_library_message);
+ http_set_loglevel(config.get_config_value(CONFIG_HTTP_DEBUG));
+
+ x->x_rtpovertcp = 0;
+ config.set_config_value(CONFIG_USE_RTP_OVER_RTSP, x->x_rtpovertcp);
+
+ return (void *)x;
+}
+
+
+void pdp_mp4player_tilde_setup(void)
+{
+ // post( pdp_mp4player_version );
+ pdp_mp4player_class = class_new(gensym("pdp_mp4player~"), (t_newmethod)pdp_mp4player_new,
+ (t_method)pdp_mp4player_free, sizeof(t_pdp_mp4player), 0, A_NULL);
+
+ class_addmethod(pdp_mp4player_class, (t_method)pdp_mp4player_dsp, gensym("dsp"), A_NULL);
+ class_addmethod(pdp_mp4player_class, (t_method)pdp_mp4player_connect, gensym("connect"), A_SYMBOL, A_NULL);
+ class_addmethod(pdp_mp4player_class, (t_method)pdp_mp4player_disconnect, gensym("disconnect"), A_NULL);
+ class_addmethod(pdp_mp4player_class, (t_method)pdp_mp4player_audio, gensym("audio"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_mp4player_class, (t_method)pdp_mp4player_overtcp, gensym("overtcp"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_mp4player_class, (t_method)pdp_mp4player_priority, gensym("priority"), A_FLOAT, A_NULL);
+ class_addmethod(pdp_mp4player_class, (t_method)pdp_mp4player_vwidth, gensym("vwidth"), A_DEFFLOAT, A_NULL);
+ class_addmethod(pdp_mp4player_class, (t_method)pdp_mp4player_vheight, gensym("vheight"), A_DEFFLOAT, A_NULL);
+ class_sethelpsymbol( pdp_mp4player_class, gensym("pdp_mp4player~.pd") );
+
+}
+
+#ifdef __cplusplus
+}
+#endif