[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
- Previous message: [PD-cvs] externals/pidip/include pdp_mp4audiosource.h,NONE,1.1 pdp_mp4audiosync.h,NONE,1.1 pdp_mp4config.h,NONE,1.1 pdp_mp4configset.h,NONE,1.1 pdp_mp4playermedia.h,NONE,1.1 pdp_mp4playersession.h,NONE,1.1 pdp_mp4player~.h,NONE,1.1 pdp_mp4rtpbytestream.h,NONE,1.1 pdp_mp4videosource.h,NONE,1.1 pdp_mp4videosync.h,NONE,1.1
- Next message: [PD-cvs] externals/pidip/patches pdp_cabaret.pd,NONE,1.1
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
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);
}
- Previous message: [PD-cvs] externals/pidip/include pdp_mp4audiosource.h,NONE,1.1 pdp_mp4audiosync.h,NONE,1.1 pdp_mp4config.h,NONE,1.1 pdp_mp4configset.h,NONE,1.1 pdp_mp4playermedia.h,NONE,1.1 pdp_mp4playersession.h,NONE,1.1 pdp_mp4player~.h,NONE,1.1 pdp_mp4rtpbytestream.h,NONE,1.1 pdp_mp4videosource.h,NONE,1.1 pdp_mp4videosync.h,NONE,1.1
- Next message: [PD-cvs] externals/pidip/patches pdp_cabaret.pd,NONE,1.1
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the Pd-cvs
mailing list