[PD-cvs] externals/pidip/modules pdp_ieee1394.c,NONE,1.1 pdp_mp4audiosource.cpp,NONE,1.1 pdp_mp4audiosync.cpp,NONE,1.1 pdp_mp4config.cpp,NONE,1.1 pdp_mp4live~.cpp,NONE,1.1 pdp_mp4playermedia.cpp,NONE,1.1 pdp_mp4playersession.cpp,NONE,1.1 pdp_mp4player~.cpp,NONE,1.1 pdp_mp4videosource.cpp,NONE,1.1 pdp_mp4videosync.cpp,NONE,1.1 pdp_spotlight.c,NONE,1.1

Yves Degoyon sevyves at users.sourceforge.net
Tue Mar 30 04:59:57 CEST 2004


Update of /cvsroot/pure-data/externals/pidip/modules
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21968/modules

Added Files:
	pdp_ieee1394.c pdp_mp4audiosource.cpp pdp_mp4audiosync.cpp 
	pdp_mp4config.cpp pdp_mp4live~.cpp pdp_mp4playermedia.cpp 
	pdp_mp4playersession.cpp pdp_mp4player~.cpp 
	pdp_mp4videosource.cpp pdp_mp4videosync.cpp pdp_spotlight.c 
Log Message:
New in PiDiP 0.12.13

--- NEW FILE: pdp_mp4config.cpp ---
/*
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 * 
 * The Original Code is MPEG4IP.
 * 
 * The Initial Developer of the Original Code is Cisco Systems Inc.
 * Portions created by Cisco Systems Inc. are
 * Copyright (C) Cisco Systems Inc. 2000, 2001.  All Rights Reserved.
 * 
 * Contributor(s): 
 *		Dave Mackie		dmackie at cisco.com
 *		Bill May 		wmay at cisco.com
 *
 * Adapted for PD/PDP by Yves Degoyon (ydegoyon at free.fr)
 */

#include "pdp_mp4config.h"

CLiveConfig::CLiveConfig(
	SConfigVariable* variables, 
	config_index_t numVariables, 
	const char* defaultFileName)
: CConfigSet(variables, numVariables, defaultFileName) 
{
	m_appAutomatic = false;
	m_videoEncode = true;
	m_videoMaxWidth = 768;
	m_videoMaxHeight = 576;
	m_videoNeedRgbToYuv = false;
	m_videoMpeg4ConfigLength = 0;
	m_videoMpeg4Config = NULL;
	m_videoMaxVopSize = 128 * 1024;
	m_audioEncode = true;
}

CLiveConfig::~CLiveConfig()
{
	CHECK_AND_FREE(m_videoMpeg4Config);
}

// recalculate derived values
void CLiveConfig::Update() 
{
	UpdateVideo();
	UpdateAudio();
}

void CLiveConfig::UpdateVideo() 
{
	m_videoEncode = true;

	CalculateVideoFrameSize();

	GenerateMpeg4VideoConfig(this);
}

void CLiveConfig::UpdateFileHistory(const char* fileName)
{
}

void CLiveConfig::CalculateVideoFrameSize()
{
	u_int16_t frameHeight;
	float aspectRatio = GetFloatValue(CONFIG_VIDEO_ASPECT_RATIO);

	// crop video to appropriate aspect ratio modulo 16 pixels
	if ((aspectRatio - VIDEO_STD_ASPECT_RATIO) < 0.1) {
		frameHeight = GetIntegerValue(CONFIG_VIDEO_RAW_HEIGHT);
	} else {
		frameHeight = (u_int16_t)(
			(float)GetIntegerValue(CONFIG_VIDEO_RAW_WIDTH) 
			/ aspectRatio);

		if ((frameHeight % 16) != 0) {
			frameHeight += 16 - (frameHeight % 16);
		}

		if (frameHeight > GetIntegerValue(CONFIG_VIDEO_RAW_HEIGHT)) {
			// OPTION might be better to insert black lines 
			// to pad image but for now we crop down
			frameHeight = GetIntegerValue(CONFIG_VIDEO_RAW_HEIGHT);
			if ((frameHeight % 16) != 0) {
				frameHeight -= (frameHeight % 16);
			}
		}
	}

	m_videoWidth = GetIntegerValue(CONFIG_VIDEO_RAW_WIDTH);
	m_videoHeight = frameHeight;

	m_ySize = m_videoWidth * m_videoHeight;
	m_uvSize = m_ySize / 4;
	m_yuvSize = (m_ySize * 3) / 2;
}

void CLiveConfig::UpdateAudio() 
{
	m_audioEncode = true;
}

void CLiveConfig::UpdateRecord()
{
}

bool CLiveConfig::IsOneSource()
{
   return true;
}

bool CLiveConfig::IsCaptureVideoSource()
{
   return false;
}

bool CLiveConfig::IsCaptureAudioSource()
{
   return false;
}

bool CLiveConfig::IsFileVideoSource()
{
   return false;
}

bool CLiveConfig::IsFileAudioSource()
{
   return false;
}

--- NEW FILE: pdp_mp4player~.cpp ---
/*
 *   PiDiP module.
 *   Copyright (c) by Yves Degoyon (ydegoyon at 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 at free.fr )
 */


#include "pdp_mp4player~.h"

static char   *pdp_mp4player_version = "pdp_mp4player~: version 0.1, a mpeg4ip stream decoder ( ydegoyon at 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

--- NEW FILE: pdp_mp4playersession.cpp ---
/*
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 * 
 * The Original Code is MPEG4IP.
 * 
 * The Initial Developer of the Original Code is Cisco Systems Inc.
 * Portions created by Cisco Systems Inc. are
 * Copyright (C) Cisco Systems Inc. 2000, 2001.  All Rights Reserved.
 * 
 * Contributor(s): 
 *              Bill May        wmay at cisco.com
[...1006 lines suppressed...]
      if (m_video_sync != NULL) 
	m_video_sync->flush_sync_buffers();
      if (m_audio_sync != NULL) 
	m_audio_sync->flush_sync_buffers();
      break;
    }
  }
  return (state);
}

int pdp_sync_thread (void *data)
{
  CPlayerSession *p;
  int state = SYNC_STATE_INIT;
  p = (CPlayerSession *)data;
  do {
   state = p->sync_thread(state);
  } while (state != SYNC_STATE_EXIT);
  return (0);
}

--- NEW FILE: pdp_mp4videosync.cpp ---
/*
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 * 
 * The Original Code is MPEG4IP.
 * 
 * The Initial Developer of the Original Code is Cisco Systems Inc.
 * Portions created by Cisco Systems Inc. are
 * Copyright (C) Cisco Systems Inc. 2000, 2001.  All Rights Reserved.
 * 
 * Contributor(s): 
 *              Bill May        wmay at cisco.com
 *              video aspect ratio by:
 *              Peter Maersk-Moller peter at maersk-moller.net
 *
 * Adapted to PD/PDP by Yves Degoyon (ydegoyon at free.fr)
 */

/*
 * video.cpp - provides codec to video hardware class
 */

#include <string.h>
#include "pdp_mp4videosync.h"
#include "pdp_mp4playersession.h"
#include "player_util.h"
#include "m_pd.h"

#define video_message(loglevel, fmt...) message(loglevel, "videosync", fmt)

CPDPVideoSync::CPDPVideoSync (CPlayerSession *psptr, t_pdp_mp4player *pdp_father) : CVideoSync(psptr)
{
  char buf[32];

  m_screen = NULL;
  m_image = NULL;
  m_video_initialized = 0;
  m_config_set = 0;
  m_have_data = 0;
  m_y_buffer[0] = NULL;
  m_u_buffer[0] = NULL;
  m_v_buffer[0] = NULL;
  m_buffer_filled[0] = 0;
  m_play_index = m_fill_index = 0;
  m_decode_waiting = 0;
  m_dont_fill = 0;
  m_paused = 1;
  m_behind_frames = 0;
  m_total_frames = 0;
  m_behind_time = 0;
  m_behind_time_max = 0;
  m_skipped_render = 0;
  m_video_scale = 2;
  m_msec_per_frame = 0;
  m_consec_skipped = 0;
  m_fullscreen = 0;
  m_filled_frames = 0;
  m_double_width = 0;
  m_pixel_width = 0;
  m_pixel_height = 0;
  m_max_width = 0;
  m_max_height = 0;
  m_father = pdp_father;
}

CPDPVideoSync::~CPDPVideoSync (void)
{
  if (m_fullscreen != 0) {
    m_fullscreen = 0;
    do_video_resize();
  }
  if (m_image) {
    m_image = NULL;
  }
  if (m_screen) {
    m_screen = NULL;
  }
  if (m_y_buffer[0] != NULL) {
    free(m_y_buffer[0]);
    m_y_buffer[0] = NULL;
  }
  if (m_u_buffer[0] != NULL) {
    free(m_u_buffer[0]);
    m_u_buffer[0] = NULL;
  }
  if (m_v_buffer[0] != NULL) {
    free(m_v_buffer[0]);
    m_v_buffer[0] = NULL;
  }
}

void CPDPVideoSync::config (int w, int h)
{
  m_width = w;
  m_height = h;
  m_y_buffer[0] = (uint8_t *)malloc(w * h * sizeof(uint8_t));
  m_u_buffer[0] = (uint8_t *)malloc(w/2 * h/2 * sizeof(uint8_t));
  m_v_buffer[0] = (uint8_t *)malloc(w/2 * h/2 * sizeof(uint8_t));
  m_buffer_filled[0] = 0;
  m_config_set = 1;
  post( "pdp_mp4videosync : configuration done : %dx%d", m_width, m_height );
}

int CPDPVideoSync::initialize_video (const char *name)
{
  if (m_video_initialized == 0) {
    if (m_config_set) {
      int ret;
      int video_scale = m_video_scale;

      int w = m_width * video_scale / 2;
      if (m_double_width) w *= 2;
      int h = m_height * video_scale / 2;
      m_video_initialized = 1;
      post( "pdp_mp4videosync : video initialized : %dx%d", m_width, m_height );
      return (1);
    } else {
     return (0);
    }
  }
  return (1);
}

int CPDPVideoSync::is_video_ready (uint64_t &disptime)
{
  return 1;
}

void CPDPVideoSync::play_video (void) 
{

}

int64_t CPDPVideoSync::play_video_at (uint64_t current_time, int &have_eof)
{
  uint64_t play_this_at;
  unsigned int ix;
  uint8_t *to, *from;

  post( "pdp_mp4videosync : play video at  : %ld", current_time );
  
  return (10);
}

int CPDPVideoSync::get_video_buffer(uint8_t **y,
				 uint8_t **u,
				 uint8_t **v)
{
  
  post( "pdp_mp4videosync : get video buffer" );
  *y = m_y_buffer[m_fill_index];
  *u = m_u_buffer[m_fill_index];
  *v = m_v_buffer[m_fill_index];
  return (1);
}

void CPDPVideoSync::filled_video_buffers (uint64_t time)
{
  int ix;
  // post( "pdp_mp4videosync : filled video buffer : %ld", time );
  m_psptr->wake_sync_thread();
}

void CPDPVideoSync::set_video_frame(const uint8_t *y, 
				    const uint8_t *u, 
				    const uint8_t *v,
				    int pixelw_y, 
				    int pixelw_uv, 
				    uint64_t time)
{
  // post( "pdp_mp4videosync : set video frame : %dx%d", m_width, m_height );
  m_psptr->wake_sync_thread();

  // pass the data to the pdp object
  m_father->x_newpicture = 1;
  return;
}

void CPDPVideoSync::flush_sync_buffers (void)
{
  post( "pdp_mp4videosync : flush sync buffer" );
}

void CPDPVideoSync::flush_decode_buffers (void)
{
  post( "pdp_mp4videosync : flush decode buffer" );
}

static void pdp_video_configure (void *ifptr,
			      int w,
			      int h,
			      int format,
                              double aspect_ratio )
{
  ((CPDPVideoSync *)ifptr)->config(w, h);
}

static int pdp_video_get_buffer (void *ifptr, 
			       uint8_t **y,
			       uint8_t **u,
			       uint8_t **v)
{
  return (((CPDPVideoSync *)ifptr)->get_video_buffer(y, u, v));
}

static void pdp_video_filled_buffer(void *ifptr, uint64_t time)
{
  ((CPDPVideoSync *)ifptr)->filled_video_buffers(time);
}

static void pdp_video_have_frame (void *ifptr,
			       const uint8_t *y,
			       const uint8_t *u,
			       const uint8_t *v,
			       int m_pixelw_y,
			       int m_pixelw_uv,
			       uint64_t time)
{
  CPDPVideoSync *foo = (CPDPVideoSync *)ifptr;

  foo->set_video_frame(y, u, v, m_pixelw_y, m_pixelw_uv, time);
}

video_vft_t video_vft = 
{
  message,
  pdp_video_configure,
  pdp_video_get_buffer,
  pdp_video_filled_buffer,
  pdp_video_have_frame,
};

video_vft_t *get_video_vft (void)
{
  return (&video_vft);
}

CPDPVideoSync *pdp_create_video_sync (CPlayerSession *psptr, t_pdp_mp4player *pdp_father) 
{
  return new CPDPVideoSync(psptr, pdp_father);
}

--- NEW FILE: pdp_spotlight.c ---
/*
 *   PiDiP module.
 *   Copyright (c) by Yves Degoyon (ydegoyon at 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 an adaptation of lens effect from effectv
 *  Originally written by Fukuchi Kentaro & others
 *  Pd-fication by Yves Degoyon                                 
 */



#include "pdp.h"
#include "yuv.h"
#include <math.h>

static char   *pdp_spotlight_version = "pdp_spotlight: version 0.1, specially made for cabaret, written by Yves Degoyon (ydegoyon at free.fr)";

typedef struct pdp_spotlight_struct
{
    t_object x_obj;
    t_float x_f;

    t_outlet *x_outlet0;
    t_int x_packet0;
    t_int x_packet1;
    t_int x_dropped;
    t_int x_queue_id;

    t_int x_vwidth;
    t_int x_vheight;
    t_int x_vsize;
    t_int x_cx;         // coordinates of lens center
    t_int x_cy;         // coordinates of lens center
    t_int x_ssize;      // width of the spotlight
    t_float x_strength; // strength of the light (0<=strength<=1) 
    
    t_int x_colorR;   // red component of the color
    t_int x_colorG;   // green component of the color
    t_int x_colorB;   // blue component of the color

} t_pdp_spotlight;

static void pdp_spotlight_ssize(t_pdp_spotlight *x, t_floatarg fssize )
{
    if ( fssize>=0 )
    {
       x->x_ssize = (int)fssize;
    }
}

static void pdp_spotlight_cy(t_pdp_spotlight *x, t_floatarg fcy )
{
    if ( fcy>0 )
    {
       x->x_cy = (int)fcy;
    }
}

static void pdp_spotlight_cx(t_pdp_spotlight *x, t_floatarg fcx )
{
    if ( fcx>0 )
    {
       x->x_cx = (int)fcx;
    }
}

static void pdp_spotlight_r(t_pdp_spotlight *x, t_floatarg fr )
{
   if ( ( fr >= 0 ) && ( fr <= 255 ) )
   {
      x->x_colorR = (int)fr;
   }
}

static void pdp_spotlight_g(t_pdp_spotlight *x, t_floatarg fg )
{
   if ( ( fg >= 0 ) && ( fg <= 255 ) )
   {
      x->x_colorG = (int)fg;
   }
}

static void pdp_spotlight_b(t_pdp_spotlight *x, t_floatarg fb )
{
   if ( ( fb >= 0 ) && ( fb <= 255 ) )
   {
      x->x_colorB = (int)fb;
   }
}

static void pdp_spotlight_strength(t_pdp_spotlight *x, t_floatarg fstrength )
{
   if ( ( fstrength >= 0.0 ) && ( fstrength <= 1.0 ) )
   {
      x->x_strength = fstrength;
   }
}

static void pdp_spotlight_process_yv12(t_pdp_spotlight *x)
{
    t_pdp     *header = pdp_packet_header(x->x_packet0);
    short int *data   = (short int *)pdp_packet_data(x->x_packet0);
    t_pdp     *newheader = pdp_packet_header(x->x_packet1);
    short int *newdata = (short int *)pdp_packet_data(x->x_packet1);
    int       i;

    short int *poy, *pou, *pov, *pny, *pnu, *pnv;
    short int pmx, pMx, pmy, pMy;
    int px, py, ray2;

    x->x_vwidth = header->info.image.width;
    x->x_vheight = header->info.image.height;
    x->x_vsize = x->x_vwidth*x->x_vheight;

    newheader->info.image.encoding = header->info.image.encoding;
    newheader->info.image.width = x->x_vwidth;
    newheader->info.image.height = x->x_vheight;

    memcpy(newdata, data, (x->x_vsize + (x->x_vsize>>1))<<1);

    poy = data;
    pou = data + x->x_vsize;
    pov = data + x->x_vsize + (x->x_vsize>>2);
    pny = newdata;
    pnu = newdata + x->x_vsize;
    pnv = newdata + x->x_vsize + (x->x_vsize>>2);
    if ( x->x_cy-x->x_ssize < 0 ) 
    {
      pmy=0; 
    }
    else
    {
      pmy=x->x_cy-x->x_ssize; 
    }
    if ( x->x_cy+x->x_ssize > x->x_vheight ) 
    {
      pMy=x->x_vheight-1; 
    }
    else
    {
      pMy=x->x_cy+x->x_ssize; 
    }
    if ( x->x_cx-x->x_ssize < 0 ) 
    {
      pmx=0; 
    }
    else
    {
      pmx=x->x_cx-x->x_ssize; 
    }
    if ( x->x_cx+x->x_ssize > x->x_vwidth ) 
    {
      pMx=x->x_vwidth-1; 
    }
    else
    {
      pMx=x->x_cx+x->x_ssize; 
    }
    ray2 = pow( x->x_ssize, 2 );
    for (py = pmy; py <= pMy ; py++) 
    {
      for (px = pmx; px <= pMx; px++) 
      {
        if ( ( pow( (px-x->x_cx), 2 ) + pow( (py-x->x_cy), 2 ) ) < ray2 )
        {
           *(pny+py*x->x_vwidth+px) = 
              (t_float)(*(pny+py*x->x_vwidth+px))*(1.-x->x_strength) +
                (t_float)(((yuv_RGBtoY( (x->x_colorB << 16) + (x->x_colorG << 8) + x->x_colorR ))<<7))
                                *(x->x_strength);
           *(pnu+(py>>1)*(x->x_vwidth>>1)+(px>>1)) = 
              (t_float)(*(pnu+(py>>1)*(x->x_vwidth>>1)+(px>>1)))*(1.-x->x_strength) +  
                (t_float)(((yuv_RGBtoU( (x->x_colorB << 16) + (x->x_colorG << 8) 
                               + x->x_colorR ))-128)<<8)*(x->x_strength);
           *(pnv+(py>>1)*(x->x_vwidth>>1)+(px>>1)) = 
              (t_float)(*(pnv+(py>>1)*(x->x_vwidth>>1)+(px>>1)))*(1.-x->x_strength) +
                (t_float)(((yuv_RGBtoV( (x->x_colorB << 16) + (x->x_colorG << 8) 
                               + x->x_colorR ))-128)<<8)*(x->x_strength);
        }
      }
    }

    return;
}

static void pdp_spotlight_sendpacket(t_pdp_spotlight *x)
{
    /* release the packet */
    pdp_packet_mark_unused(x->x_packet0);
    x->x_packet0 = -1;

    /* unregister and propagate if valid dest packet */
    pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet1);
}

static void pdp_spotlight_process(t_pdp_spotlight *x)
{
   int encoding;
   t_pdp *header = 0;

   /* check if image data packets are compatible */
   if ( (header = pdp_packet_header(x->x_packet0))
	&& (PDP_IMAGE == header->type)){
    
	/* pdp_spotlight_process inputs and write into active inlet */
	switch(pdp_packet_header(x->x_packet0)->info.image.encoding){

	case PDP_IMAGE_YV12:
            x->x_packet1 = pdp_packet_clone_rw(x->x_packet0);
            pdp_queue_add(x, pdp_spotlight_process_yv12, pdp_spotlight_sendpacket, &x->x_queue_id);
	    break;

	default:
	    /* don't know the type, so dont pdp_spotlight_process */
	    break;
	    
	}
    }
}

static void pdp_spotlight_input_0(t_pdp_spotlight *x, t_symbol *s, t_floatarg f)
{
    /* if this is a register_ro message or register_rw message, register with packet factory */

    if (s== gensym("register_rw"))
    {
       x->x_dropped = pdp_packet_convert_ro_or_drop(&x->x_packet0, (int)f, pdp_gensym("image/YCrCb/*") );
    }

    if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped))
    {
        /* add the process method and callback to the process queue */
        pdp_spotlight_process(x);

    }
}

static void pdp_spotlight_free(t_pdp_spotlight *x)
{
  int i;

    pdp_queue_finish(x->x_queue_id);
    pdp_packet_mark_unused(x->x_packet0);
}

t_class *pdp_spotlight_class;

void *pdp_spotlight_new(void)
{
    int i;

    t_pdp_spotlight *x = (t_pdp_spotlight *)pd_new(pdp_spotlight_class);
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("cx"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("cy"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("ssize"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("r"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("g"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("b"));
    inlet_new(&x->x_obj, &x->x_obj.ob_pd, &s_float, gensym("strength"));

    x->x_outlet0 = outlet_new(&x->x_obj, &s_anything); 

    x->x_packet0 = -1;
    x->x_packet1 = -1;
    x->x_queue_id = -1;

    x->x_cx = 70;
    x->x_cy = 70;
    x->x_ssize = 50;
    x->x_colorR = 255;
    x->x_colorG = 255;
    x->x_colorB = 255;
    x->x_strength = 0.5;

    return (void *)x;
}


#ifdef __cplusplus
extern "C"
{
#endif


void pdp_spotlight_setup(void)
{
//    post( pdp_spotlight_version );
    pdp_spotlight_class = class_new(gensym("pdp_spotlight"), (t_newmethod)pdp_spotlight_new,
    	(t_method)pdp_spotlight_free, sizeof(t_pdp_spotlight), 0, A_NULL);

    class_addmethod(pdp_spotlight_class, (t_method)pdp_spotlight_input_0, gensym("pdp"),  A_SYMBOL, A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_spotlight_class, (t_method)pdp_spotlight_cx, gensym("cx"),  A_FLOAT, A_NULL);
    class_addmethod(pdp_spotlight_class, (t_method)pdp_spotlight_cy, gensym("cy"),  A_FLOAT, A_NULL);
    class_addmethod(pdp_spotlight_class, (t_method)pdp_spotlight_ssize, gensym("ssize"),  A_FLOAT, A_NULL);
    class_addmethod(pdp_spotlight_class, (t_method)pdp_spotlight_r, gensym("r"),  A_FLOAT, A_NULL);
    class_addmethod(pdp_spotlight_class, (t_method)pdp_spotlight_g, gensym("g"),  A_FLOAT, A_NULL);
    class_addmethod(pdp_spotlight_class, (t_method)pdp_spotlight_b, gensym("b"),  A_FLOAT, A_NULL);
    class_addmethod(pdp_spotlight_class, (t_method)pdp_spotlight_strength, gensym("strength"),  A_FLOAT, A_NULL);
    class_sethelpsymbol( pdp_spotlight_class, gensym("pdp_spotlight.pd") );

}

#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_mp4videosource.cpp ---
/*
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 * 
 * The Original Code is MPEG4IP.
 * 
 * The Initial Developer of the Original Code is Cisco Systems Inc.
 * Portions created by Cisco Systems Inc. are
 * Copyright (C) Cisco Systems Inc. 2000, 2001.  All Rights Reserved.
 * 
 * Contributor(s): 
 *        Dave Mackie        dmackie at cisco.com
 *        Bill May         wmay at cisco.com
 *
 * Adapted for PD/PDP by Yves Degoyon (ydegoyon at free.fr)
 */

#ifndef debug_message
#define debug_message post 
#endif

#include <sys/mman.h>

#include "m_pd.h"
#include "pdp_mp4videosource.h"
#include "video_util_rgb.h"

//#define DEBUG_TIMESTAMPS 1

int CPDPVideoSource::ThreadMain(void)
{
   // just a stub, the threaded mode is not used ( never called )
   return 0;
}

void CPDPVideoSource::DoStart(void)
{
  if (m_source) return;
  if (!Init()) return;
  m_source = true;
}

void CPDPVideoSource::DoStop(void)
{
  if (!m_source) return;
  DoStopVideo();
  m_source = false;
}

bool CPDPVideoSource::Init(void)
{

    if (m_pConfig->GetIntegerValue(CONFIG_VIDEO_SIGNAL) == VIDEO_SIGNAL_NTSC) 
    {
      m_videoSrcFrameRate = VIDEO_NTSC_FRAME_RATE;
    } 
    else 
    {
      m_videoSrcFrameRate = VIDEO_PAL_FRAME_RATE;
    }

    m_videoMbuf.frames = 2;
    m_cacheTimestamp = false;
    m_videoFrameMap = (struct video_mmap*) malloc(m_videoMbuf.frames * sizeof(struct video_mmap));
    if ( !m_videoFrameMap ) 
    {
      post("pdp_mp4live~ : video source init : failed to allocate enough memory");
      return false;
    }

    m_videoFrameMapFrame = (uint64_t *)malloc(m_videoMbuf.frames * sizeof(uint64_t));
    m_videoFrameMapTimestamp = (uint64_t *)malloc(m_videoMbuf.frames * sizeof(Timestamp));
    m_captureHead = 0;
    m_encodeHead = -1;

    m_videoFrames = 0;
    m_videoSrcFrameDuration = (Duration)(((float)TimestampTicks / m_videoSrcFrameRate) + 0.5);
    for (int i = 0; i < m_videoMbuf.frames; i++) 
    {
       // initialize frame map
       m_videoFrameMap[i].frame = i;
       m_videoFrameMap[i].width = m_pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_WIDTH);
       m_videoFrameMap[i].height = m_pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_HEIGHT);
       m_videoFrameMap[i].format = VIDEO_PALETTE_YUV420P;

       if (i == 0) 
       {
         m_videoCaptureStartTimestamp = GetTimestamp();
       }
       m_lastVideoFrameMapFrameLoaded = m_videoFrameMapFrame[i] = i;
       m_lastVideoFrameMapTimestampLoaded =
       m_videoFrameMapTimestamp[i] = CalculateVideoTimestampFromFrames(i);
    }

    m_pConfig->CalculateVideoFrameSize();

    InitVideo(
        (m_pConfig->m_videoNeedRgbToYuv ?
            RGBVIDEOFRAME :
            YUVVIDEOFRAME),
        true);

    SetVideoSrcSize(
        m_pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_WIDTH),
        m_pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_HEIGHT),
        m_pConfig->GetIntegerValue(CONFIG_VIDEO_RAW_WIDTH),
        true);

    m_maxPasses = (u_int8_t)(m_videoSrcFrameRate + 0.5);

    return true;
}

int8_t CPDPVideoSource::StartTimeStamp(Timestamp &frameTimestamp)
{
    if (m_cacheTimestamp)
      frameTimestamp = m_videoFrameMapTimestamp[m_captureHead];
    else
      frameTimestamp = GetTimestamp();

    int8_t capturedFrame = m_captureHead;
    m_captureHead = (m_captureHead + 1) % m_videoMbuf.frames;

    return capturedFrame;
}

bool CPDPVideoSource::EndTimeStamp(int8_t frameNumber)
{
  Timestamp calc = GetTimestamp();

  if (calc > m_videoSrcFrameDuration + m_lastVideoFrameMapTimestampLoaded) {
#ifdef DEBUG_TIMESTAMPS
    debug_message("pdp_mp4live~ : video frame delay past end of buffer - time is %llu should be %llu",
          calc,
          m_videoSrcFrameDuration + m_lastVideoFrameMapTimestampLoaded);
#endif
    m_videoCaptureStartTimestamp = calc;
    m_videoFrameMapFrame[frameNumber] = 0;
    m_videoFrameMapTimestamp[frameNumber] = calc;
  } else {
    m_videoFrameMapFrame[frameNumber] = m_lastVideoFrameMapFrameLoaded + 1;
    m_videoFrameMapTimestamp[frameNumber] =
      CalculateVideoTimestampFromFrames(m_videoFrameMapFrame[frameNumber]);
  }

  m_lastVideoFrameMapFrameLoaded = m_videoFrameMapFrame[frameNumber];
  m_lastVideoFrameMapTimestampLoaded = m_videoFrameMapTimestamp[frameNumber];
  return true;
}

void CPDPVideoSource::ProcessVideo(u_int8_t *pY, u_int8_t *pU, u_int8_t *pV)
{
    // for efficiency, process ~1 second before returning to check for commands
  Timestamp frameTimestamp;
    for (int pass = 0; pass < m_maxPasses; pass++) {

        // get next frame from video capture device
        m_encodeHead = StartTimeStamp(frameTimestamp);
        if (m_encodeHead == -1) {
            continue;
        }

        ProcessVideoYUVFrame(
            pY, 
            pU, 
            pV,
            m_videoSrcWidth,
            m_videoSrcWidth >> 1,
            frameTimestamp);

        // release video frame buffer back to video capture device
        if (EndTimeStamp(m_encodeHead)) {
            m_encodeHead = (m_encodeHead + 1) % m_videoMbuf.frames;
        } else {
            debug_message("pdp_mp4live~ : couldn't release capture buffer!");
        }
    }
}

--- NEW FILE: pdp_mp4live~.cpp ---
/*
 *   PiDiP module.
 *   Copyright (c) by Yves Degoyon (ydegoyon at 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 mpeg4ip streaming object towards a Darwin or Quicktime streaming server
 *  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 at free.fr )                             
 */


#include "pdp.h"
#include <math.h>
#include <time.h>
#include <sys/time.h>

/* mpeg4ip includes taken from the source tree ( not exported ) */
#include <mp4.h>
#define  DECLARE_CONFIG_VARIABLES
#include "config_set.h"

#undef CONFIG_BOOL
#define CONFIG_BOOL(var, name, defval) \
 { &(var), (name), CONFIG_TYPE_BOOL, (defval), (defval) }
#undef CONFIG_FLOAT
#define CONFIG_FLOAT(var, name, defval) \
 { &(var), (name), CONFIG_TYPE_FLOAT,(float) (defval), (float) (defval) }
#undef CONFIG_INT
#define CONFIG_INT(var, name, defval) \
 { &(var), (name), CONFIG_TYPE_INTEGER,(config_integer_t) (defval), (config_integer_t)(defval) }
#undef CONFIG_STRING
#define CONFIG_STRING(var, name, defval) \
 { &(var), (name), CONFIG_TYPE_STRING, (defval), (defval) }

#include "pdp_mp4config.h"

#undef   DECLARE_CONFIG_VARIABLES
#ifndef debug_message
#define debug_message post 
#endif
#include "rtp_transmitter.h"
#include "pdp_mp4videosource.h"
#include "pdp_mp4audiosource.h"

#define VIDEO_BUFFER_SIZE (1024*1024)
#define MAX_AUDIO_PACKET_SIZE (128 * 1024)
#define AUDIO_PACKET_SIZE (2*1024) /* using aac encoding */

static char   *pdp_mp4live_version = "pdp_mp4live~: version 0.1, an mpeg4ip video streaming object ( ydegoyon at free.fr )";

typedef struct pdp_mp4live_struct
{
    t_object x_obj;
    t_float x_f;

    t_int x_packet0;
    t_int x_dropped;
    t_int x_queue_id;

    t_int x_vwidth;
    t_int x_vheight;
    t_int x_vsize;

    t_outlet *x_outlet_streaming;  // indicates the status of streaming
    t_outlet *x_outlet_nbframes;   // number of frames emitted
    t_outlet *x_outlet_framerate;  // current frame rate

    t_int x_streaming;   // streaming flag
    t_int x_nbframes;    // number of frames emitted
    t_int x_framerate;   // framerate

    t_int x_cursec;   // current second
    t_int x_secondcount; // number of frames emitted in the current second

      /* audio structures */
    short x_audio_buf[2*MAX_AUDIO_PACKET_SIZE]; /* buffer for incoming audio */
    short x_audio_enc_buf[2*MAX_AUDIO_PACKET_SIZE]; /* buffer for audio to be encoded */
    uint8_t x_audio_out[4*MAX_AUDIO_PACKET_SIZE]; /* buffer for encoded audio */
    t_int x_audioin_position; // writing position for incoming audio
    t_int x_audio_per_frame;  // number of audio samples to transmit for each frame

      /* mpeg4ip data */
    CLiveConfig *x_mp4Config;
    CRtpTransmitter *x_rtpTransmitter;
    CPDPVideoSource *x_videosource;
    CPDPAudioSource *x_audiosource;

} t_pdp_mp4live;

#ifdef __cplusplus
extern "C"
{
#endif

static void pdp_mp4live_add_sink(t_pdp_mp4live *x, CMediaSink* pSink)
{
   if (x->x_videosource)
   {
      x->x_videosource->AddSink(pSink);
   }
   if (x->x_audiosource)
   {
      x->x_audiosource->AddSink(pSink);
   }
}

static void pdp_mp4live_remove_sink(t_pdp_mp4live *x, CMediaSink* pSink)
{
   if (x->x_videosource)
   {
      x->x_videosource->RemoveSink(pSink);
   }
   if (x->x_audiosource)
   {
      x->x_audiosource->RemoveSink(pSink);
   }
}

static void pdp_mp4live_disconnect(t_pdp_mp4live *x)
{
 t_int ret, i;

   if (!x->x_streaming)
   {
     post("pdp_mp4live~ : disconnect request but not connected ... ignored" );
     return;
   }

   if (x->x_audiosource) 
   {
     x->x_audiosource->DoStop();
     delete x->x_audiosource;
     x->x_audiosource = NULL;
   }

   if (x->x_videosource) 
   {
     x->x_videosource->DoStop();
     delete x->x_videosource;
     x->x_videosource = NULL;
   }

   if (x->x_rtpTransmitter) 
   {
     pdp_mp4live_remove_sink(x, x->x_rtpTransmitter);
     x->x_rtpTransmitter->StopThread();
     delete x->x_rtpTransmitter;
     x->x_rtpTransmitter = NULL;
   }

   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 );
   x->x_framerate = 0;
   outlet_float( x->x_outlet_framerate, x->x_framerate );
}

static void pdp_mp4live_connect(t_pdp_mp4live *x )
{
  t_int ret, i;

   if (x->x_streaming)
   {
     post("pdp_mp4live~ : connect request but already connected ... ignored" );
     return;
   }

   post("pdp_mp4live~ : creating video source");
   if ( x->x_videosource == NULL )
   {
      x->x_videosource = new CPDPVideoSource();
      x->x_videosource->SetConfig(x->x_mp4Config);
   }
   
   post("pdp_mp4live~ : creating audio source");
   if ( x->x_audiosource == NULL )
   {
       x->x_audiosource = new CPDPAudioSource(x->x_mp4Config);
   }

   post("pdp_mp4live~ : creating rtp transmitter");
   x->x_rtpTransmitter = new CRtpTransmitter(x->x_mp4Config);
   x->x_rtpTransmitter->StartThread();

   post("pdp_mp4live~ : creating audio destination");
   x->x_rtpTransmitter->CreateAudioRtpDestination(0,
                      x->x_mp4Config->GetStringValue(CONFIG_RTP_AUDIO_DEST_ADDRESS),
                      x->x_mp4Config->GetIntegerValue(CONFIG_RTP_AUDIO_DEST_PORT),
                      0);

   post("pdp_mp4live~ : creating video destination");
   x->x_rtpTransmitter->CreateVideoRtpDestination(0,
                     x->x_mp4Config->GetStringValue(CONFIG_RTP_DEST_ADDRESS),
                     x->x_mp4Config->GetIntegerValue(CONFIG_RTP_VIDEO_DEST_PORT),
                     0);

   post("pdp_mp4live~ : starting rtp");
   if ( x->x_rtpTransmitter )
   {
      pdp_mp4live_add_sink(x, x->x_rtpTransmitter);
      x->x_rtpTransmitter->Start();
   }

   if (x->x_videosource) 
   {
      post("pdp_mp4live~ : starting video source");
      x->x_videosource->DoStart();
      post("pdp_mp4live~ : generating key frame");
      x->x_videosource->GenerateKeyFrame();
   }

   if (x->x_audiosource) 
   {
      post("pdp_mp4live~ : starting audio source");
      x->x_audiosource->DoStart();
   }

   x->x_streaming = 1;
   outlet_float( x->x_outlet_streaming, x->x_streaming );
   x->x_nbframes = 0;
   outlet_float( x->x_outlet_nbframes, x->x_nbframes );
   x->x_framerate = 0;
   outlet_float( x->x_outlet_framerate, x->x_framerate );

}

static void pdp_mp4live_ipaddr(t_pdp_mp4live *x, t_symbol *sIpAddr )
{
  t_int a, b, c, d;

   if ( !strcmp( sIpAddr->s_name, "" ) )
   {
     post("pdp_mp4live~ : wrong ip address" );
     return;
   }

   if ( sscanf( sIpAddr->s_name, "%d.%d.%d.%d", &a, &b, &c, &d ) < 4 )
   {
     post("pdp_mp4live~ : wrong ip address : %s", sIpAddr->s_name );
     return;
   }

   post( "pdp_mp4live~ : setting ip address: %s", sIpAddr->s_name );
   x->x_mp4Config->SetStringValue( CONFIG_RTP_DEST_ADDRESS, sIpAddr->s_name );
   x->x_mp4Config->SetStringValue( CONFIG_RTP_AUDIO_DEST_ADDRESS, sIpAddr->s_name );
}

static void pdp_mp4live_aport(t_pdp_mp4live *x, t_floatarg fAudioPort )
{
   if ( ( (t_int) fAudioPort <= 0 ) || ( (t_int) fAudioPort > 65535 ) )
   {
     post("pdp_mp4live~ : wrong audio port : %d", fAudioPort );
     return;
   }

   post( "pdp_mp4live~ : setting audio port: %d", (t_int) fAudioPort );
   x->x_mp4Config->SetIntegerValue( CONFIG_RTP_AUDIO_DEST_PORT, (t_int) fAudioPort );

}

static void pdp_mp4live_vport(t_pdp_mp4live *x, t_floatarg fVideoPort )
{
   if ( ( (t_int) fVideoPort <= 0 ) || ( (t_int) fVideoPort > 65535 ) )
   {
     post("pdp_mp4live~ : wrong video port : %d", fVideoPort );
     return;
   }

   post( "pdp_mp4live~ : setting video port: %d", (t_int) fVideoPort );
   x->x_mp4Config->SetIntegerValue( CONFIG_RTP_VIDEO_DEST_PORT, (t_int) fVideoPort );

}

static void pdp_mp4live_ttl(t_pdp_mp4live *x, t_floatarg fTtl )
{
   if ( ( (t_int) fTtl <= 0 ) || ( (t_int) fTtl > 255 ) )
   {
     post("pdp_mp4live~ : wrong ttl : %d", fTtl );
     return;
   }

   post( "pdp_mp4live~ : setting ttl : %d", (t_int) fTtl );
   x->x_mp4Config->SetIntegerValue( CONFIG_RTP_MCAST_TTL, (t_int) fTtl );

}

static void pdp_mp4live_vwidth(t_pdp_mp4live *x, t_floatarg fWidth )
{
   if ( ( (t_int) fWidth <= 0 ) )
   {
     post("pdp_mp4live~ : wrong width : %d", fWidth );
     return;
   }

   post( "pdp_mp4live~ : setting width : %d", (t_int) fWidth );
   x->x_mp4Config->SetIntegerValue( CONFIG_VIDEO_RAW_WIDTH, (t_int) fWidth );

}

static void pdp_mp4live_vheight(t_pdp_mp4live *x, t_floatarg fHeight )
{
   if ( ( (t_int) fHeight <= 0 ) )
   {
     post("pdp_mp4live~ : wrong height : %d", fHeight );
     return;
   }

   post( "pdp_mp4live~ : setting height : %d", (t_int) fHeight );
   x->x_mp4Config->SetIntegerValue( CONFIG_VIDEO_RAW_HEIGHT, (t_int) fHeight );

}

static void pdp_mp4live_framerate(t_pdp_mp4live *x, t_floatarg fFrameRate )
{
   if ( ( (t_int) fFrameRate <= 0 ) )
   {
     post("pdp_mp4live~ : wrong framerate : %d", fFrameRate );
     return;
   }

   post( "pdp_mp4live~ : setting framerate : %d", (t_int) fFrameRate );
   x->x_mp4Config->SetFloatValue( CONFIG_VIDEO_FRAME_RATE, (t_float) fFrameRate );

}

static void pdp_mp4live_vbitrate(t_pdp_mp4live *x, t_floatarg fVBitrate )
{
   if ( ( (t_int) fVBitrate <= 0 ) )
   {
     post("pdp_mp4live~ : wrong video bit rate : %d", fVBitrate );
     return;
   }

   post( "pdp_mp4live~ : setting video bit rate : %d", (t_int) fVBitrate );
   x->x_mp4Config->SetIntegerValue( CONFIG_VIDEO_BIT_RATE, (t_int) fVBitrate );

}

static void pdp_mp4live_samplerate(t_pdp_mp4live *x, t_floatarg fSampleRate )
{
   if ( ( (t_int) fSampleRate != 44100 ) &&
        ( (t_int) fSampleRate != 22050 ) &&
        ( (t_int) fSampleRate != 11025 ) &&
        ( (t_int) fSampleRate != 8000 )
        )
   {
     post("pdp_mp4live~ : wrong samplerate : %d", fSampleRate );
     return;
   }

   post( "pdp_mp4live~ : setting samplerate : %d", (t_int) fSampleRate );
   x->x_mp4Config->SetIntegerValue( CONFIG_AUDIO_SAMPLE_RATE, (t_int) fSampleRate );

}

static void pdp_mp4live_abitrate(t_pdp_mp4live *x, t_floatarg fABitrate )
{
   if ( ( (t_int) fABitrate <= 0 ) )
   {
     post("pdp_mp4live~ : wrong audio bit rate : %d", fABitrate );
     return;
   }

   post( "pdp_mp4live~ : setting audio bit rate : %d", (t_int) fABitrate );
   x->x_mp4Config->SetIntegerValue( CONFIG_AUDIO_BIT_RATE_KBPS, (t_int) fABitrate );
   x->x_mp4Config->SetIntegerValue( CONFIG_AUDIO_BIT_RATE, ((t_int) fABitrate)*1000 );

}

static void pdp_mp4live_sdp(t_pdp_mp4live *x, t_symbol *sSdpFile )
{
  t_int ret;

   post( "pdp_mp4live~ : setting sdp filename : %s", (char *) sSdpFile->s_name );
   x->x_mp4Config->SetStringValue( CONFIG_SDP_FILE_NAME, (char *) sSdpFile->s_name );

   post( "pdp_mp4live~ : writing sdp file : %s", (char *) sSdpFile->s_name );
   if ( ( ret = GenerateSdpFile( x->x_mp4Config ) ) )
   {
     post( "pdp_mp4live~ : written sdp file : %s", (char *) sSdpFile->s_name );
   }
   else
   {
     post( "pdp_mp4live~ : could not write sdp file : %s", 
            (char *) sSdpFile->s_name );
   }
}

static void pdp_mp4live_process_yv12(t_pdp_mp4live *x)
{
    t_pdp     *header = pdp_packet_header(x->x_packet0);
    u_int8_t  *data   = (uint8_t *)pdp_packet_data(x->x_packet0);
    u_int8_t  *pY, *pU, *pV;
    struct timeval etime;

        /* allocate all ressources */
    if ( ((int)header->info.image.width != x->x_vwidth) ||
         ((int)header->info.image.height != x->x_vheight) )
    {
        x->x_vwidth = header->info.image.width;
        x->x_vheight = header->info.image.height;
        x->x_vsize = x->x_vwidth*x->x_vheight;
    }

    if ( x->x_streaming )
    {
         pY = data;
         pU = data+x->x_vsize;
         pV = data+x->x_vsize+(x->x_vsize>>2);

         x->x_videosource->ProcessVideo( pY, pV, pU );
   
            /* update frames counter */

         if ( gettimeofday(&etime, NULL) == -1)
         {
            post("pdp_ffmpeg~ : could not read time" );
         }
         if ( etime.tv_sec != x->x_cursec )
         {
            x->x_cursec = etime.tv_sec;
            x->x_framerate = x->x_secondcount;
            x->x_secondcount = 0;
         }
         x->x_nbframes++;
         x->x_secondcount++;

            /* send an audio frame */
         if ( x->x_audioin_position > x->x_audio_per_frame )
         {
            x->x_audiosource->ProcessAudio( (u_int8_t*)x->x_audio_buf, 
                           (u_int32_t)x->x_audio_per_frame*sizeof(short) );

            /* output resampled raw samples */
            memcpy( x->x_audio_buf, x->x_audio_buf+x->x_audio_per_frame, 
                    x->x_audioin_position-x->x_audio_per_frame ); 
            x->x_audioin_position-=x->x_audio_per_frame;
         }
    }
    return;
}

static void pdp_mp4live_killpacket(t_pdp_mp4live *x)
{
    /* delete source packet */
    pdp_packet_mark_unused(x->x_packet0);
    x->x_packet0 = -1;
}

    /* store audio data in PCM format and stream it */
static t_int *pdp_mp4live_perform(t_int *w)
{
  t_float *in1   = (t_float *)(w[1]);       // left audio inlet
  t_float *in2   = (t_float *)(w[2]);       // right audio inlet 
  t_pdp_mp4live *x = (t_pdp_mp4live *)(w[3]);
  int n = (int)(w[4]);                      // number of samples 
  t_float fsample;
  t_int   isample, i;

    // just fills the buffer ( a pcm buffer )
    while (n--)
    {
       fsample=*(in1++); 
       if (fsample > 1.0) { fsample = 1.0; }
       if (fsample < -1.0) { fsample = -1.0; }
       isample=(short) (32767.0 * fsample);
       *(x->x_audio_buf+x->x_audioin_position)=isample;
       x->x_audioin_position=(x->x_audioin_position+1)%(2*MAX_AUDIO_PACKET_SIZE); 
       if ( x->x_audioin_position == 2*MAX_AUDIO_PACKET_SIZE-1 ) 
       {
          // post( "pdp_mp4live~ : reaching end of audio buffer" );
       }
       fsample=*(in2++); 
       if (fsample > 1.0) { fsample = 1.0; }
       if (fsample < -1.0) { fsample = -1.0; }
       isample=(short) (32767.0 * fsample);
       *(x->x_audio_buf+x->x_audioin_position)=isample;
       x->x_audioin_position=(x->x_audioin_position+1)%(2*MAX_AUDIO_PACKET_SIZE); 
       if ( x->x_audioin_position == 2*MAX_AUDIO_PACKET_SIZE-1 ) 
       {
          // post( "pdp_mp4live~ : reaching end of audio buffer" );
       }
    }

    return (w+5);
}

static void pdp_mp4live_dsp(t_pdp_mp4live *x, t_signal **sp)
{
    dsp_add(pdp_mp4live_perform, 4, sp[0]->s_vec, sp[1]->s_vec, x, sp[0]->s_n);
}

static void pdp_mp4live_process(t_pdp_mp4live *x)
{
   int encoding;
   t_pdp *header = 0;

   /* check if image data packets are compatible */
   if ( (header = pdp_packet_header(x->x_packet0))
	&& (PDP_BITMAP == header->type)){
    
	/* pdp_mp4live_process inputs and write into active inlet */
	switch(pdp_packet_header(x->x_packet0)->info.image.encoding)
        {

	  case PDP_BITMAP_YV12:
            pdp_queue_add(x, (void*) pdp_mp4live_process_yv12, (void*) pdp_mp4live_killpacket, &x->x_queue_id);
            outlet_float( x->x_outlet_nbframes, x->x_nbframes );
            outlet_float( x->x_outlet_framerate, x->x_framerate );
	    break;

	  default:
	    /* don't know the type, so dont pdp_mp4live_process */
            post( "pdp_mp4live~ : hey!! i don't know about that type of image : %d", 
                  pdp_packet_header(x->x_packet0)->info.image.encoding );
	    break;
	    
	}
    }

}

static void pdp_mp4live_input_0(t_pdp_mp4live *x, t_symbol *s, t_floatarg f)
{

    /* if this is a register_ro message or register_rw message, register with packet factory */

    if (s== gensym("register_rw"))
    {
       x->x_dropped = pdp_packet_convert_ro_or_drop(&x->x_packet0, (int)f, pdp_gensym("bitmap/yv12/*") );
    }

    if ((s == gensym("process")) && (-1 != x->x_packet0) && (!x->x_dropped))
    {
        /* add the process method and callback to the process queue */
        pdp_mp4live_process(x);
    }

}

static void pdp_mp4live_free(t_pdp_mp4live *x)
{
  int i;

    pdp_queue_finish(x->x_queue_id);
    pdp_packet_mark_unused(x->x_packet0);
}

t_class *pdp_mp4live_class;

void *pdp_mp4live_new(void)
{
    int i;

    t_pdp_mp4live *x = (t_pdp_mp4live *)pd_new(pdp_mp4live_class);
    inlet_new (&x->x_obj, &x->x_obj.ob_pd, gensym ("signal"), gensym ("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_queue_id = -1;
    x->x_nbframes = 0;
    x->x_framerate = 0;
    x->x_secondcount = 0;
    x->x_audioin_position = 0;

    x->x_mp4Config = new CLiveConfig(PdpConfigVariables,
                     sizeof(PdpConfigVariables) / sizeof(SConfigVariable),
                     "none");
    if ( x->x_mp4Config == NULL )
    {
       post( "pdp_mp4live~ : couldn't allocate default config" );
       return NULL;
    }

    x->x_mp4Config->InitializeIndexes();

    x->x_mp4Config->Update();

    // update sample rate with the actual sample rate
    x->x_mp4Config->SetIntegerValue( CONFIG_AUDIO_SAMPLE_RATE, (t_int) sys_getsr() );

    x->x_videosource = NULL;
    x->x_audiosource = NULL;

    x->x_audio_per_frame = AUDIO_PACKET_SIZE;

    return (void *)x;
}


void pdp_mp4live_tilde_setup(void)
{
    // post( pdp_mp4live_version );
    pdp_mp4live_class = class_new(gensym("pdp_mp4live~"), (t_newmethod)pdp_mp4live_new,
    	(t_method)pdp_mp4live_free, sizeof(t_pdp_mp4live), 0, A_NULL);

    CLASS_MAINSIGNALIN(pdp_mp4live_class, t_pdp_mp4live, x_f );
    class_addmethod(pdp_mp4live_class, (t_method)pdp_mp4live_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_mp4live_class, (t_method)pdp_mp4live_dsp, gensym("dsp"), A_NULL);
    class_addmethod(pdp_mp4live_class, (t_method)pdp_mp4live_connect, gensym("connect"), A_NULL);
    class_addmethod(pdp_mp4live_class, (t_method)pdp_mp4live_ipaddr, gensym("ipaddr"), A_SYMBOL, A_NULL);
    class_addmethod(pdp_mp4live_class, (t_method)pdp_mp4live_aport, gensym("audioport"), A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_mp4live_class, (t_method)pdp_mp4live_vport, gensym("videoport"), A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_mp4live_class, (t_method)pdp_mp4live_ttl, gensym("ttl"), A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_mp4live_class, (t_method)pdp_mp4live_vwidth, gensym("vwidth"), A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_mp4live_class, (t_method)pdp_mp4live_vheight, gensym("vheight"), A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_mp4live_class, (t_method)pdp_mp4live_framerate, gensym("framerate"), A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_mp4live_class, (t_method)pdp_mp4live_vbitrate, gensym("vbitrate"), A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_mp4live_class, (t_method)pdp_mp4live_samplerate, gensym("samplerate"), A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_mp4live_class, (t_method)pdp_mp4live_abitrate, gensym("abitrate"), A_DEFFLOAT, A_NULL);
    class_addmethod(pdp_mp4live_class, (t_method)pdp_mp4live_disconnect, gensym("disconnect"), A_NULL);
    class_addmethod(pdp_mp4live_class, (t_method)pdp_mp4live_sdp, gensym("sdp"), A_SYMBOL, A_NULL);
    class_sethelpsymbol( pdp_mp4live_class, gensym("pdp_mp4live~.pd") );
}

#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_mp4audiosync.cpp ---
/*
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 * 
 * The Original Code is MPEG4IP.
 * 
 * The Initial Developer of the Original Code is Cisco Systems Inc.
 * Portions created by Cisco Systems Inc. are
 * Copyright (C) Cisco Systems Inc. 2000, 2001.  All Rights Reserved.
 * 
 * Contributor(s): 
 *              Bill May        wmay at cisco.com
 *
 * Adapted to PD/PDP by Yves Degoyon (ydegoyon at free.fr)
 */

/*
 * audio.cpp provides an interface (CPDPAudioSync) between the codec and
 * the SDL audio APIs.
 */
#include <stdlib.h>
#include <string.h>
#include "pdp_mp4playersession.h"
#include "pdp_mp4audiosync.h"
#include "player_util.h"
#include "our_config_file.h"
#include "m_pd.h"

#define audio_message(loglevel, fmt...) message(loglevel, "audiosync", fmt)

static void pdp_audio_callback (void *userdata, Uint8 *stream, int len)
{
  CPDPAudioSync *a = (CPDPAudioSync *)userdata;
  a->audio_callback(stream, len);
}

CPDPAudioSync::CPDPAudioSync (CPlayerSession *psptr, t_pdp_mp4player *pdp_father) : CAudioSync(psptr)
{
  m_fill_index = m_play_index = 0;
  for (int ix = 0; ix < DECODE_BUFFERS_MAX; ix++) {
    m_buffer_filled[ix] = 0;
    m_sample_buffer[ix] = NULL;
  }
  m_buffer_size = 0;
  m_config_set = 0;
  m_audio_initialized = 0;
  m_audio_paused = 1;
  m_resync_required = 0;
  m_dont_fill = 0;
  m_consec_no_buffers = 0;
  m_audio_waiting_buffer = 0;
  m_skipped_buffers = 0;
  m_didnt_fill_buffers = 0;
  m_play_time = 0         ;
  m_buffer_latency = 0;
  m_first_time = 1;
  m_first_filled = 1;
  m_buffer_offset_on = 0;
  m_buffer_ts = 0;
  m_load_audio_do_next_resync = 0;
  m_convert_buffer = NULL;
  m_father = pdp_father;
}

CPDPAudioSync::~CPDPAudioSync (void)
{
  for (int ix = 0; ix < DECODE_BUFFERS_MAX; ix++) {
    if (m_sample_buffer[ix] != NULL)
      free(m_sample_buffer[ix]);
    m_sample_buffer[ix] = NULL;
  }
  CHECK_AND_FREE(m_convert_buffer);
  audio_message(LOG_NOTICE, 
		"Audio sync skipped %u buffers", 
		m_skipped_buffers);
  audio_message(LOG_NOTICE, "didn't fill %u buffers", m_didnt_fill_buffers);
}

void CPDPAudioSync::set_config (int freq, 
			     int channels, 
			     int format, 
			     uint32_t sample_size) 
{
  if (m_config_set != 0) 
    return;
  
  if (format == AUDIO_U8 || format == AUDIO_S8)
    m_bytes_per_sample = 1;
  else
    m_bytes_per_sample = 2;

  if (sample_size == 0) {
    int temp;
    temp = freq;
    while ((temp & 0x1) == 0) temp >>= 1;
    sample_size = temp;
    while (sample_size < 1024) sample_size *= 2;
    while (((sample_size * 1000) % freq) != 0) sample_size *= 2;
  } 
  
  m_buffer_size = channels * sample_size * m_bytes_per_sample;

  for (int ix = 0; ix < DECODE_BUFFERS_MAX; ix++) {
    m_buffer_filled[ix] = 0;
    m_sample_buffer[ix] = (uint8_t *)malloc(2 * m_buffer_size);
  }
  m_freq = freq;
  m_channels = channels;
  m_format = format;
  if (m_format == AUDIO_U8) {
    m_silence = 0x80;
  } else {
    m_silence = 0x00;
  }
  m_config_set = 1;
  m_msec_per_frame = (sample_size * 1000) / m_freq;
  audio_message(LOG_DEBUG, "buffer size %d msec per frame %d", m_buffer_size, m_msec_per_frame);
};

uint8_t *CPDPAudioSync::get_audio_buffer (void)
{
  int ret;
  int locked = 0;
  if (m_dont_fill == 1) {
    return (NULL);
  }

  if (m_audio_initialized != 0) {
    locked = 1;
  }
  ret = m_buffer_filled[m_fill_index];
  if (ret == 1) {
    m_audio_waiting_buffer = 1;
    m_audio_waiting_buffer = 0;
    if (m_dont_fill != 0) {
      return (NULL);
    }
    locked = 0;
    if (m_audio_initialized != 0) {
      locked = 1;
    }
    ret = m_buffer_filled[m_fill_index];
    if (locked)
    if (ret == 1) {
      post("pdp_mp4audiosync : no buffer");
      return (NULL);
    }
  }
  return (m_sample_buffer[m_fill_index]);
}

void CPDPAudioSync::load_audio_buffer (uint8_t *from, 
				       uint32_t bytes, 
				       uint64_t ts, 
				       int resync)
{
  uint8_t *to;
  uint32_t copied;
  copied = 0;
  if (m_buffer_offset_on == 0) {
    int64_t diff = ts - m_buffer_ts;

    if (m_buffer_ts != 0 && diff > 1) {
      m_load_audio_do_next_resync = 1;
      audio_message(LOG_DEBUG, "timeslot doesn't match - %llu %llu",
		    ts, m_buffer_ts);
    }
    m_buffer_ts = ts;
  } else {
    int64_t check;
    check = ts - m_loaded_next_ts;
    if (check > m_msec_per_frame) {
      audio_message(LOG_DEBUG, "potential resync at ts "U64" should be ts "U64,
		    ts, m_loaded_next_ts);
      uint32_t left;
      left = m_buffer_size - m_buffer_offset_on;
      to = get_audio_buffer();
      memset(to + m_buffer_offset_on, 0, left);
      filled_audio_buffer(m_buffer_ts, 0);
      m_buffer_offset_on = 0;
      m_load_audio_do_next_resync = 1;
      m_buffer_ts = ts;
    }
  }
  m_loaded_next_ts = bytes * M_64;
  m_loaded_next_ts /= m_bytes_per_sample;
  m_loaded_next_ts /= m_freq;
  m_loaded_next_ts += ts;

  while ( bytes > 0) {
    to = get_audio_buffer();
    if (to == NULL) {
      return;
    }
    int copy;
    uint32_t left;

    left = m_buffer_size - m_buffer_offset_on;
    copy = MIN(left, bytes);
    memcpy(to + m_buffer_offset_on, from, copy);
    bytes -= copy;
    copied += copy;
    from += copy;
    m_buffer_offset_on += copy;
    if (m_buffer_offset_on >= m_buffer_size) {
      m_buffer_offset_on = 0;
      filled_audio_buffer(m_buffer_ts, resync | m_load_audio_do_next_resync);
      m_buffer_ts += m_msec_per_frame;
      resync = 0;
      m_load_audio_do_next_resync = 0;
    }
  }
  return;
}

void CPDPAudioSync::filled_audio_buffer (uint64_t ts, int resync)
{
  uint32_t fill_index;
  int locked;
  // m_dont_fill will be set when we have a pause
  if (m_dont_fill == 1) {
    return;
  }
  //  resync = 0;
  fill_index = m_fill_index;
  m_fill_index++;
  m_fill_index %= DECODE_BUFFERS_MAX;

  locked = 0;
  if (m_audio_initialized != 0) {
    locked = 1;
  }
  if (m_first_filled != 0) {
    m_first_filled = 0;
    resync = 0;
    m_resync_required = 0;
  } else {
    int64_t diff;
    diff = ts - m_last_fill_timestamp;
    if (diff - m_msec_per_frame > m_msec_per_frame) {
      // have a hole here - don't want to resync
      if (diff > ((m_msec_per_frame + 1) * 4)) {
	resync = 1;
      } else {
	// try to fill the holes
	m_last_fill_timestamp += m_msec_per_frame + 1; // fill plus extra
	int64_t ts_diff;
	do {
	  uint8_t *retbuffer;
	  // Get and swap buffers.
	  retbuffer = get_audio_buffer();
	  if (retbuffer == NULL) {
	    return;
	  }
	  if (retbuffer != m_sample_buffer[m_fill_index]) {
	    audio_message(LOG_ERR, "retbuffer not fill index in audio sync");
	    return;
	  }
	  locked = 0;
	  if (m_audio_initialized != 0) {
	    locked = 1;
	  }
	  m_sample_buffer[m_fill_index] = m_sample_buffer[fill_index];
	  m_sample_buffer[fill_index] = retbuffer;
	  memset(retbuffer, m_silence, m_buffer_size);
	  m_buffer_time[fill_index] = m_last_fill_timestamp;
	  m_buffer_filled[fill_index] = 1;
	  m_samples_loaded += m_buffer_size;
	  fill_index++;
	  fill_index %= DECODE_BUFFERS_MAX;
	  m_fill_index++;
	  m_fill_index %= DECODE_BUFFERS_MAX;
	  audio_message(LOG_NOTICE, "Filling timestamp %llu with silence",
			m_last_fill_timestamp);
	  m_last_fill_timestamp += m_msec_per_frame + 1; // fill plus extra
	  ts_diff = ts - m_last_fill_timestamp;
	  audio_message(LOG_DEBUG, "diff is %lld", ts_diff);
	} while (ts_diff > 0);
	locked = 0;
	if (m_audio_initialized != 0) {
	  locked = 1;
	}
      }
    } else {
      if (m_last_fill_timestamp == ts) {
	audio_message(LOG_NOTICE, "Repeat timestamp with audio %llu", ts);
	return;
      }
    }
  }
  m_last_fill_timestamp = ts;
  m_buffer_filled[fill_index] = 1;
  m_samples_loaded += m_buffer_size;
  m_buffer_time[fill_index] = ts;
  if (resync) {
    m_resync_required = 1;
    m_resync_buffer = fill_index;
#ifdef DEBUG_AUDIO_FILL
    audio_message(LOG_DEBUG, "Resync from filled_audio_buffer");
#endif
  }

  // Check this - we might not want to do this unless we're resyncing
  if (resync) m_psptr->wake_sync_thread();
#ifdef DEBUG_AUDIO_FILL
  audio_message(LOG_DEBUG, "Filling " LLU " %u %u", ts, fill_index, m_samples_loaded);
#endif
}

void CPDPAudioSync::set_eof(void) 
{ 
  uint8_t *to;
  if (m_buffer_offset_on != 0) {
    to = get_audio_buffer();
    if (to != NULL) {
      uint32_t left;
      left = m_buffer_size - m_buffer_offset_on;
      memset(to + m_buffer_offset_on, 0, left);
      m_buffer_offset_on = 0;
      filled_audio_buffer(m_buffer_ts, 0);
      m_buffer_ts += m_msec_per_frame;
    }
  }
  CAudioSync::set_eof();
}

int CPDPAudioSync::initialize_audio (int have_video) 
{
  return (1);
}

int CPDPAudioSync::is_audio_ready (uint64_t &disptime)
{
  disptime = m_buffer_time[m_play_index];
  return (m_dont_fill == 0 && m_buffer_filled[m_play_index] == 1);
}

uint64_t CPDPAudioSync::check_audio_sync (uint64_t current_time, int &have_eof)
{
  return (0);
}

void CPDPAudioSync::audio_callback (Uint8 *stream, int ilen)
{
  int freed_buffer = 0;
  uint32_t bufferBytes = (uint32_t)ilen;
  uint64_t this_time;
  int delay = 0;
  int playtime;

}

void CPDPAudioSync::play_audio (void)
{
  m_first_time = 1;
  m_audio_paused = 0;
  m_play_sample_index = 0;
}

void CPDPAudioSync::flush_sync_buffers (void)
{
  clear_eof();
  m_dont_fill = 1;
  if (m_audio_waiting_buffer) {
    m_audio_waiting_buffer = 0;
  }
}

void CPDPAudioSync::flush_decode_buffers (void)
{
  int locked = 0;
  if (m_audio_initialized != 0) {
    locked = 1;
  }
  m_dont_fill = 0;
  m_first_filled = 1;
  for (int ix = 0; ix < DECODE_BUFFERS_MAX; ix++) {
    m_buffer_filled[ix] = 0;
  }
  m_buffer_offset_on = 0;
  m_play_index = m_fill_index = 0;
  m_audio_paused = 1;
  m_resync_buffer = 0;
  m_samples_loaded = 0;
}

void CPDPAudioSync::set_volume (int volume)
{
  m_volume = (volume * SDL_MIX_MAXVOLUME)/100;
}

void CPDPAudioSync::audio_convert_data (void *from, uint32_t samples)
{
  if (m_obtained.format == AUDIO_U8 || m_obtained.format == AUDIO_S8) {
    // bytewise - easy
    int8_t *src, *dst;
    src = (int8_t *) from;
    dst = (int8_t *) m_convert_buffer;
    if (m_channels == 2) {
      // we got 1, wanted 2
      for (uint32_t ix = 0; ix < samples; ix++) {
	int16_t sum = *src++;
	sum += *src++;
	sum /= 2;
	if (sum < -128) sum = -128;
	else if (sum > 128) sum = 128;
	*dst++ = sum & 0xff;
      }
    } else {
      // we got 2, wanted 1
      for (uint32_t ix = 0; ix < samples; ix++) {
	*dst++ = *src;
	*dst++ = *src++;
      }
    }
  } else {
    int16_t *src, *dst;
    src = (int16_t *) from;
    dst = (int16_t *) m_convert_buffer;
    samples /= 2;
    if (m_channels == 1) {
      // 1 channel to 2
      for (uint32_t ix = 0; ix < samples; ix++) {
	*dst++ = *src;
	*dst++ = *src;
	src++;
      }
    } else {
      // 2 channels to 1
      for (uint32_t ix = 0; ix < samples; ix++) {
	int32_t sum = *src++;
	sum += *src++;
	sum /= 2;
	if (sum < -32768) sum = -32768;
	else if (sum > 32767) sum = 32767;
	*dst++ = sum & 0xffff;
      }
    }

  }
}

static void pdp_audio_config (void *ifptr, int freq, 
			    int chans, int format, uint32_t max_buffer_size)
{
  ((CPDPAudioSync *)ifptr)->set_config(freq,
				    chans,
				    format,
				    max_buffer_size);
}

static uint8_t *pdp_get_audio_buffer (void *ifptr)
{
  return ((CPDPAudioSync *)ifptr)->get_audio_buffer();
}

static void pdp_filled_audio_buffer (void *ifptr,
				   uint64_t ts,
				   int resync_req)
{
  ((CPDPAudioSync *)ifptr)->filled_audio_buffer(ts, 
					     resync_req);
}

static void pdp_load_audio_buffer (void *ifptr, 
				     uint8_t *from, 
				     uint32_t bytes, 
				     uint64_t ts, 
				     int resync)
{
  ((CPDPAudioSync *)ifptr)->load_audio_buffer(from,
					      bytes,
					      ts, 
					      resync);
}
  
audio_vft_t audio_vft = {
  message,
  pdp_audio_config,
  pdp_get_audio_buffer,
  pdp_filled_audio_buffer,
  pdp_load_audio_buffer
};

audio_vft_t *get_audio_vft (void)
{
  return &audio_vft;
}

CPDPAudioSync *pdp_create_audio_sync (CPlayerSession *psptr, t_pdp_mp4player *pdp_father)
{
  return new CPDPAudioSync(psptr, pdp_father);
}

int do_we_have_audio (void) 
{
  return 1;
}

--- NEW FILE: pdp_ieee1394.c ---
/*
 *   PiDiP module.
 *   Copyright (c) by Yves Degoyon (ydegoyon at 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 ieee1394 video input object for OSX, using QuickTime
 *  Some code is inspired by pix_video from Gem
 *  Written by Yves Degoyon
 */

#include "pdp_config.h"
#include "pdp.h"
#include "pdp_llconv.h"
#include "pdp_imageproc.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sched.h>
#include <pthread.h>
#include <Carbon/Carbon.h>
#include <Quicktime/QuickTime.h>
#include <Quicktime/QuickTimeComponents.h>

#define DEFAULT_WIDTH 320
#define DEFAULT_HEIGHT 240

typedef struct pdp_ieee1394_struct
{
  t_object x_obj;
  t_float x_f;
  
  t_outlet *x_outlet0;

  bool x_initialized;
  bool x_auto_open;

  t_int        x_packet;
  t_pdp*       x_header;
  short int    *x_data;
  unsigned char *x_sdata; // static data to hold the grabbed images

  unsigned int x_width;
  unsigned int x_height;
  unsigned int x_size;
  int          x_channel;
  pthread_t    x_thread_id;
  int          x_continue_thread;
  unsigned int x_framerate;
  int          x_frame_ready;
  t_int        x_quality;

  SeqGrabComponent x_sg;   
  SGChannel        x_vc;  
  short            x_pixelDepth;
  Rect             x_srcRect;  
  GWorldPtr        x_srcGWorld;
  PixMapHandle     x_pixMap;  
  Ptr              x_baseAddr;
  long             x_rowBytes;

} t_pdp_ieee1394;

static void pdp_ieee1394_close(t_pdp_ieee1394 *x)
{
  void *dummy;

    /* terminate thread if there is one */
    if(x->x_continue_thread)
    {
	x->x_continue_thread = 0;
	// pthread_join (x->x_thread_id, &dummy);
    }

    // free sequence grabber
    // if (x->x_vc) 
    // {
    //   if (SGDisposeChannel(x->x_sg, x->x_vc)) 
    //   {
    //     post("pdp_ieee1394: unable to dispose video channel");
    //   }
    //   x->x_vc = NULL;
    //   post("pdp_ieee1394: disposed video channel");
    // }
    // if (x->x_sg) 
    // {
    //   if (CloseComponent(x->x_sg)) 
    //   {
    //     post("pdp_ieee1394: unable to free sequence grabber.");
    //   }
    //   x->x_sg = NULL;
    //   post("pdp_ieee1394: freed sequence grabber.");
    // }
    // if (x->x_srcGWorld) 
    // {
    //     DisposeGWorld(x->x_srcGWorld);
    //     post("pdp_ieee1394: disposed world.");
    //     x->x_srcGWorld = NULL;
    // }

}

static void pdp_ieee1394_capture_frame(t_pdp_ieee1394* x)
{
  OSErr       err;

    err = SGIdle(x->x_sg);
    if (err != noErr)
    {
      post("pdp_ieee1394: SGIdle failed.");
      x->x_frame_ready = 0;
    } 
    else 
    {
      x->x_frame_ready = 1;
    }
}


static void *pdp_ieee1394_thread(void *voidx)
{
  t_pdp_ieee1394 *x = ((t_pdp_ieee1394 *)voidx);

    /* capture with a double buffering scheme */
    while (true)
    {
      if (x->x_continue_thread)
      {
	/* schedule capture command for next frame */
	pdp_ieee1394_capture_frame(x);
      }
      else
      {
        sleep(1);
      }
    }

    x->x_thread_id = 0;
    return 0;
}

static void pdp_ieee1394_reset(t_pdp_ieee1394 *x)
{
  OSErr anErr;

  if ( !x->x_initialized )
  {
    post("pdp_ieee1394: trying to reset but the sequence grabber is not initialized");
    return;
  }

  post("pdp_ieee1394: resetting....");

  switch (x->x_quality)
  {
    case 0:
        anErr = SGSetChannelPlayFlags(x->x_vc, channelPlayNormal);
        post("pdp_ieee1394: set sequence grabber to : normal quality");
        break;
    case 1:
        anErr = SGSetChannelPlayFlags(x->x_vc, channelPlayHighQuality);
        post("pdp_ieee1394: set sequence grabber to : high quality");
        break;
    case 2:
        anErr = SGSetChannelPlayFlags(x->x_vc, channelPlayFast);
        post("pdp_ieee1394: set sequence grabber to : fast quality");
        break;
    case 3:
        anErr = SGSetChannelPlayFlags(x->x_vc, channelPlayAllData);
        post("pdp_ieee1394: set sequence grabber to : play all data");
        break;
    }

  post("pdp_ieee1394: done.");
}

static void pdp_ieee1394_quality(t_pdp_ieee1394 *x, t_floatarg fquality)
{
  if ( ( (t_int)fquality < 0 ) || ( (t_int)fquality > 3 ) )
  {
     post("pdp_ieee1394: wrong quality %d", (t_int)fquality );
     return;
  }
  else
  {
     x->x_quality = (t_int)fquality;
  }
}

static void pdp_ieee1394_free(t_pdp_ieee1394 *x)
{
    pdp_ieee1394_close(x);
}

static t_int pdp_ieee1394_init_grabber(t_pdp_ieee1394 *x)
{
  OSErr anErr;
  x->x_srcRect.top = 0;
  x->x_srcRect.left = 0;
  x->x_srcRect.bottom = x->x_height;
  x->x_srcRect.right = x->x_width;

  x->x_sg = OpenDefaultComponent(SeqGrabComponentType, 0);
  if(x->x_sg==NULL)
  {
    post("pdp_ieee1394: could not open default component");
    return -1;
  }    
  else
  {
    post("pdp_ieee1394: opened default component");
  }

  anErr = SGInitialize(x->x_sg);
  if(anErr!=noErr)
  {
    post("pdp_ieee1394: could not initialize sequence grabber");
    return -1;
  }
  else
  {
    post("pdp_ieee1394: initialized sequence grabber");
  }

  anErr = SGSetDataRef(x->x_sg, 0, 0, seqGrabDontMakeMovie);
  if (anErr != noErr)
  {
    post("pdp_ieee1394: couldn't set data ref");
    return -1;
  }
  else
  {
    post("pdp_ieee1394: set data ref ok.");
  }

  anErr = SGNewChannel(x->x_sg, VideoMediaType, &x->x_vc);
  if(anErr!=noErr)
  {
    post("pdp_ieee1394: could not create new sequence grabber channnel");
    return -1;
  }
  else
  {
    post("pdp_ieee1394: created new sequence grabber channnel.");
  }

  anErr = SGSetChannelBounds(x->x_vc, &x->x_srcRect);
  if(anErr!=noErr)
  {
    post("pdp_ieee1394: could not set sequence grabber ChannelBounds ");
    return -1;
  }
  else
  {
    post("pdp_ieee1394: set sequence grabber ChannelBounds");
  }

  anErr = SGSetChannelUsage(x->x_vc, seqGrabPreview);
  if(anErr!=noErr)
  {
    post("pdp_ieee1394: could not set sequence grabber ChannelUsage ");
    return -1;
  }
  else
  {
    post("pdp_ieee1394: set sequence grabber ChannelUsage");
  }

  switch (x->x_quality)
  {
    case 0:
        anErr = SGSetChannelPlayFlags(x->x_vc, channelPlayNormal);
        post("pdp_ieee1394: set sequence grabber to : normal quality");
        break;
    case 1:
        anErr = SGSetChannelPlayFlags(x->x_vc, channelPlayHighQuality);
        post("pdp_ieee1394: set sequence grabber to : high quality");
        break;
    case 2:
        anErr = SGSetChannelPlayFlags(x->x_vc, channelPlayFast);
        post("pdp_ieee1394: set sequence grabber to : fast quality");
        break;
    case 3:
        anErr = SGSetChannelPlayFlags(x->x_vc, channelPlayAllData);
        post("pdp_ieee1394: set sequence grabber to : play all data");
        break;
  }

  anErr = QTNewGWorldFromPtr (&x->x_srcGWorld,
                              k422YpCbCr8CodecType,
                              &x->x_srcRect,
                              NULL,
                              NULL,
                              0,
                              x->x_sdata,
                              x->x_width*2);
  if (anErr!= noErr)
  {
    post ("pdp_ieee1394: QTNewGWorldFromPtr returned %d", anErr);
    return -1;
  }

  if (NULL == x->x_srcGWorld)
  {
    post ("pdp_ieee1394: could not allocate off screen");
    return -1;
  }
  SGSetGWorld(x->x_sg,(CGrafPtr)x->x_srcGWorld, NULL);
  SGStartPreview(x->x_sg);

  return 0;
}

static void pdp_ieee1394_open(t_pdp_ieee1394 *x)
{

    x->x_initialized = true;
    x->x_continue_thread = 1;

    /* create thread */
    if ( x->x_thread_id == 0 )
    {
      if ( pdp_ieee1394_init_grabber( x ) != 0 )
      {
        post("pdp_ieee1394: grabber initialization failed");
        return;
      }
      x->x_frame_ready = 0;
      pthread_create(&x->x_thread_id, 0, pdp_ieee1394_thread, x);
    }
}

static void pdp_ieee1394_bang(t_pdp_ieee1394 *x)
{
  unsigned char *pQ;
  short int *pY, *pU, *pV;
  t_int px, py;

    if (!(x->x_continue_thread))
    {
      post("pdp_ieee1394: not initialized.");

      if (x->x_auto_open)
      {
        post("pdp_ieee1394: attempting auto open");
        pdp_ieee1394_open(x);
        if (!(x->x_initialized))
        {
          post("pdp_ieee1394: auto open failed");
          return;
        }
      }
      else return;
    }

    /* do nothing if there is no frame ready */
    if (!x->x_frame_ready) return;

    x->x_packet = pdp_packet_new_image_YCrCb(x->x_width, x->x_height);
    x->x_header = pdp_packet_header(x->x_packet);

    if (!x->x_header) 
    {
      post("pdp_ieee1394: FATAL: can't allocate packet");
      return;
    }

    x->x_data = (short int *) pdp_packet_data(x->x_packet);
    memset( x->x_data, 0x0, (x->x_size+(x->x_size>>1))<<1 );
    pQ = x->x_sdata;
    pY = x->x_data;
    pV = x->x_data+x->x_size;
    pU = x->x_data+x->x_size+(x->x_size>>2);
    for ( py=0; py<(t_int)x->x_height; py++ )
    {
      for ( px=0; px<(t_int)x->x_width; px++ )
      {
        *(pY+py*x->x_width+px) = (*(pQ+1+2*(py*x->x_width+px)))<<7;
        if ( px%2 == 0 )
        {
          *(pU+((py>>1)*(x->x_width>>1)+(px>>1))) = (*(pQ+2*(py*x->x_width+px))-128)<<8;
        }
        if ( px%2 == 1 )
        {
          *(pV+((py>>1)*(x->x_width>>1)+(px>>1))) = (*(pQ+2*(py*x->x_width+px))-128)<<8;
        }
      }
    }

    pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet);

    x->x_frame_ready = 0;
}

t_class *pdp_ieee1394_class;

void *pdp_ieee1394_new(t_floatarg fwidth, t_floatarg fheight)
{
  t_pdp_ieee1394 *x = (t_pdp_ieee1394 *)pd_new(pdp_ieee1394_class);

    x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
    x->x_initialized = false;

    x->x_auto_open = true;

    x->x_continue_thread = 0;

    if (fwidth > 0.)
    {
      x->x_width = (int)fwidth;
    }
    else
    {
      x->x_width = DEFAULT_WIDTH;
    }

    if (fheight > 0.)
    {
      x->x_height = (int)fheight;
    }
    else
    {
      x->x_height = DEFAULT_WIDTH;
    }
    x->x_size = x->x_width*x->x_height;
    x->x_sdata = (unsigned char*) getbytes( (x->x_size+(x->x_size>>1))<<1 );
    if ( !x->x_sdata )
    {
      post ("pdp_ieee1394: FATAL : couldn't allocate static data.");
      return NULL;
    }

    x->x_quality = 1;
    x->x_thread_id = 0;

    return (void *)x;
}


#ifdef __cplusplus
extern "C"
{
#endif


void pdp_ieee1394_setup(void)
{
    pdp_ieee1394_class = class_new(gensym("pdp_ieee1394"), (t_newmethod)pdp_ieee1394_new,
    	(t_method)pdp_ieee1394_free, sizeof(t_pdp_ieee1394), 0, A_DEFFLOAT, A_DEFFLOAT, A_NULL);

    class_addmethod(pdp_ieee1394_class, (t_method)pdp_ieee1394_bang, gensym("bang"), A_NULL);
    class_addmethod(pdp_ieee1394_class, (t_method)pdp_ieee1394_close, gensym("close"), A_NULL);
    class_addmethod(pdp_ieee1394_class, (t_method)pdp_ieee1394_open, gensym("open"), A_NULL);
    class_addmethod(pdp_ieee1394_class, (t_method)pdp_ieee1394_reset, gensym("reset"), A_NULL);
    class_addmethod(pdp_ieee1394_class, (t_method)pdp_ieee1394_quality, gensym("quality"), A_DEFFLOAT, A_NULL);
}

#ifdef __cplusplus
}
#endif

--- NEW FILE: pdp_mp4audiosource.cpp ---
/*
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 * 
 * The Original Code is MPEG4IP.
 * 
 * The Initial Developer of the Original Code is Cisco Systems Inc.
 * Portions created by Cisco Systems Inc. are
 * Copyright (C) Cisco Systems Inc. 2000-2002.  All Rights Reserved.
 * 
 * Contributor(s): 
 *		Dave Mackie		dmackie at cisco.com
 *		Bill May 		wmay at cisco.com
 *
 * Adapted for PD/PDP by Yves Degoyon (ydegoyon at free.fr)
 */

#include "m_pd.h"

#ifndef debug_message
#define debug_message post
#endif
#include "pdp_mp4audiosource.h"

//#define DEBUG_TIMESTAMPS 1

CPDPAudioSource::CPDPAudioSource(CLiveConfig *pConfig) : CMediaSource() 
{
  SetConfig(pConfig);

  m_pcmFrameBuffer = NULL;
  m_prevTimestamp = 0;
  m_timestampOverflowArray = NULL;
  m_timestampOverflowArrayIndex = 0;
  m_audioOssMaxBufferSize = 0;
}

int CPDPAudioSource::ThreadMain(void) 
{
  // just a stub, we don't use the threaded mode
  return 0;
}

void CPDPAudioSource::DoStart()
{
  if (m_source) {
    return;
  }

  if (!Init()) {
    return;
  }

  m_source = true;
}

void CPDPAudioSource::DoStop()
{
  if (!m_source) {
    return;
  }

  CMediaSource::DoStopAudio();

  CHECK_AND_FREE(m_timestampOverflowArray);
  free(m_pcmFrameBuffer);
  m_pcmFrameBuffer = NULL;

  m_source = false;
}

bool CPDPAudioSource::Init(void)
{
  bool rc = InitAudio(true);
  if (!rc) {
    return false;
  }

  m_channelsConfigured = m_pConfig->GetIntegerValue(CONFIG_AUDIO_CHANNELS);
  
  debug_message("pdp_mp4live~ : init audio : (m_audioDstChannels=%d m_audioDstSampleRate=%d )", 
                           m_audioDstChannels, m_audioDstSampleRate);

  rc = SetAudioSrc(PCMAUDIOFRAME,
                   m_channelsConfigured,
                   m_pConfig->GetIntegerValue(CONFIG_AUDIO_SAMPLE_RATE));

  if (!rc) {
    return false;
  }

  debug_message("pdp_mp4live~ : set audio src : (m_audioDstSamplesPerFrame=%d m_audioSrcChannels=%d)", 
                           m_audioDstSamplesPerFrame, m_audioSrcChannels);

  // for live capture we can match the source to the destination
  m_audioSrcSamplesPerFrame = m_audioDstSamplesPerFrame;
  m_pcmFrameSize = 
    m_audioSrcSamplesPerFrame * m_audioSrcChannels * sizeof(u_int16_t);

  if (m_audioOssMaxBufferSize > 0) {
    size_t array_size;
    m_audioOssMaxBufferFrames = m_audioOssMaxBufferSize / m_pcmFrameSize;
    array_size = m_audioOssMaxBufferFrames * sizeof(*m_timestampOverflowArray);
    m_timestampOverflowArray = (Timestamp *)malloc(array_size);
    memset(m_timestampOverflowArray, 0, array_size);
  }
    
  m_pcmFrameBuffer = (u_int8_t*)malloc(m_pcmFrameSize);
  if (!m_pcmFrameBuffer) {
    goto init_failure;
  }

  // maximum number of passes in ProcessAudio, approx 1 sec.
  m_maxPasses = m_audioSrcSampleRate / m_audioSrcSamplesPerFrame;

  debug_message("pdp_mp4live~ : audio source initialization done : ( frame size=%d )", m_pcmFrameSize );

  return true;

 init_failure:
  debug_message("pdp_mp4live~ : audio initialization failed");

  free(m_pcmFrameBuffer);
  m_pcmFrameBuffer = NULL;

  return false;
}

void CPDPAudioSource::ProcessAudio(u_int8_t* pcmBuffer, u_int32_t pcmBufferSize)
{
  audio_buf_info info;
  Timestamp currentTime = GetTimestamp();
  Timestamp timestamp;

    if ( pcmBufferSize > m_pcmFrameSize )
    {
       debug_message( "pdp_mp4live~ : too many audio samples : %d should be %d",
                      pcmBufferSize, m_pcmFrameSize );
       memcpy( m_pcmFrameBuffer, pcmBuffer, m_pcmFrameSize );
    }
    else if ( pcmBufferSize < m_pcmFrameSize )
    {
       debug_message( "pdp_mp4live~ : too little audio samples : %d should be %d",
                      pcmBufferSize, m_pcmFrameSize );
       memcpy( m_pcmFrameBuffer, pcmBuffer, pcmBufferSize );
    }
    else
    {
       memcpy( m_pcmFrameBuffer, pcmBuffer, pcmBufferSize );
    }

    if (info.bytes == m_audioOssMaxBufferSize) {
      // means the audio buffer is full, and not capturing
      // we want to make the timestamp based on the previous one
      // When we hit this case, we start using the m_timestampOverflowArray
      // This will give us a timestamp for when the array is full.
      // 
      // In other words, if we have a full audio buffer (ie: it's not loading
      // any more), we start storing the current timestamp into the array.
      // This will let us "catch up", and have a somewhat accurate timestamp
      // when we loop around
      // 
      // wmay - I'm not convinced that this actually works - if the buffer
      // cleans up, we'll ignore m_timestampOverflowArray
      if (m_timestampOverflowArray != NULL && 
	  m_timestampOverflowArray[m_timestampOverflowArrayIndex] != 0) {
	timestamp = m_timestampOverflowArray[m_timestampOverflowArrayIndex];
      } else {
	timestamp = m_prevTimestamp + SrcSamplesToTicks(m_audioSrcSamplesPerFrame);
      }

      if (m_timestampOverflowArray != NULL)
	m_timestampOverflowArray[m_timestampOverflowArrayIndex] = currentTime;

      debug_message("pdp_mp4live~ : audio buffer full !");

    } else {
      // buffer is not full - so, we make the timestamp based on the number
      // of bytes in the buffer that we read.
      timestamp = currentTime - SrcSamplesToTicks(SrcBytesToSamples(info.bytes));
      if (m_timestampOverflowArray != NULL)
	m_timestampOverflowArray[m_timestampOverflowArrayIndex] = 0;
    }

#ifdef DEBUG_TIMESTAMPS
    debug_message("pdp_mp4live~ : info.bytes=%d t=%llu timestamp=%llu delta=%llu",
                  info.bytes, currentTime, timestamp, timestamp - m_prevTimestamp);
#endif

    m_prevTimestamp = timestamp;
    if (m_timestampOverflowArray != NULL) {
      m_timestampOverflowArrayIndex = (m_timestampOverflowArrayIndex + 1) % 
	m_audioOssMaxBufferFrames;
    }

    ProcessAudioFrame(m_pcmFrameBuffer, m_pcmFrameSize, timestamp, false);
}

--- NEW FILE: pdp_mp4playermedia.cpp ---
/*
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 * 
 * The Original Code is MPEG4IP.
 * 
 * The Initial Developer of the Original Code is Cisco Systems Inc.
 * Portions created by Cisco Systems Inc. are
 * Copyright (C) Cisco Systems Inc. 2000, 2001.  All Rights Reserved.
 * 
 * Contributor(s): 
 *              Bill May        wmay at cisco.com
[...1990 lines suppressed...]
    double secs;
    secs = last_div;
    secs /= 1000.0;
    secs += total_secs;

    fps = frames_decoded;
    fps /= secs;
    bps = UINT64_TO_DOUBLE(bytes_decoded);
    bps *= 8.0 / secs;
    media_message(LOG_NOTICE, "%s - bytes "U64", seconds %g, fps %g bps "U64,
		  m_is_video ? "video" : "audio", 
		  bytes_decoded, secs, 
		  fps, bytes_decoded * 8 / total_secs);
  }
  if (m_plugin) {
    m_plugin->c_close(m_plugin_data);
    m_plugin_data = NULL;
  }
  return (0);
}





More information about the Pd-cvs mailing list