diff options
Diffstat (limited to 'modules/pdp_mp4player~.cpp')
-rw-r--r-- | modules/pdp_mp4player~.cpp | 384 |
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 |