From: <do...@us...> - 2010-02-02 14:48:50
|
Revision: 1464 http://iaxclient.svn.sourceforge.net/iaxclient/?rev=1464&view=rev Author: dohpaz Date: 2010-02-02 14:48:34 +0000 (Tue, 02 Feb 2010) Log Message: ----------- Merge trunk r1449:1463 out to elbunce branch. Modified Paths: -------------- branches/team/elbunce/iaxclient/lib/audio_portaudio.c branches/team/elbunce/iaxclient/lib/codec_ffmpeg.c branches/team/elbunce/iaxclient/lib/codec_theora.c branches/team/elbunce/iaxclient/lib/iaxclient.h branches/team/elbunce/iaxclient/lib/iaxclient_lib.h branches/team/elbunce/iaxclient/lib/slice.c branches/team/elbunce/iaxclient/lib/slice.h branches/team/elbunce/iaxclient/lib/video.c branches/team/elbunce/iaxclient/simpleclient/stresstest/file.c branches/team/elbunce/iaxclient/simpleclient/stresstest/stresstest.c Property Changed: ---------------- branches/team/elbunce/iaxclient/ Property changes on: branches/team/elbunce/iaxclient ___________________________________________________________________ Added: svn:mergeinfo + /trunk:1450-1463 Modified: branches/team/elbunce/iaxclient/lib/audio_portaudio.c =================================================================== --- branches/team/elbunce/iaxclient/lib/audio_portaudio.c 2010-01-29 17:41:25 UTC (rev 1463) +++ branches/team/elbunce/iaxclient/lib/audio_portaudio.c 2010-02-02 14:48:34 UTC (rev 1464) @@ -551,51 +551,67 @@ return 0; } +// NOTE: pa_open does not require an input device for success static int pa_open(int single, int inMono, int outMono) { PaError err; - PaDeviceInfo *result; + PaDeviceInfo *in_dev_info, *out_dev_info; - struct PaStreamParameters in_stream_params, out_stream_params, no_device; + struct PaStreamParameters in_stream_params, out_stream_params, *in_params; + + if ( selectedInput != paNoDevice ) + { + in_dev_info = (PaDeviceInfo *)Pa_GetDeviceInfo(selectedInput); + if ( in_dev_info == NULL ) + return -1; + in_stream_params.device = selectedInput; in_stream_params.channelCount = (inMono ? 1 : 2); in_stream_params.sampleFormat = paInt16; - result = (PaDeviceInfo *)Pa_GetDeviceInfo(selectedInput); - if ( result == NULL ) return -1; - in_stream_params.suggestedLatency = result->defaultLowInputLatency; + in_stream_params.suggestedLatency = in_dev_info->defaultLowInputLatency; in_stream_params.hostApiSpecificStreamInfo = NULL; + in_params = &in_stream_params; + } + else + in_params = NULL; + + out_dev_info = (PaDeviceInfo *)Pa_GetDeviceInfo(selectedOutput); + if ( out_dev_info == NULL ) + return -1; + out_stream_params.device = selectedOutput; out_stream_params.channelCount = (outMono ? 1 : 2); out_stream_params.sampleFormat = paInt16; - result = (PaDeviceInfo *)Pa_GetDeviceInfo(selectedOutput); - if ( result == NULL ) return -1; - out_stream_params.suggestedLatency = result->defaultLowOutputLatency; + out_stream_params.suggestedLatency = out_dev_info->defaultLowOutputLatency; out_stream_params.hostApiSpecificStreamInfo = NULL; - no_device.device = paNoDevice; - no_device.channelCount = 0; - no_device.sampleFormat = paInt16; - result = (PaDeviceInfo *)Pa_GetDeviceInfo(selectedInput); - if ( result == NULL ) return -1; - no_device.suggestedLatency = result->defaultLowInputLatency; // FEEDBACK - unsure if appropriate - no_device.hostApiSpecificStreamInfo = NULL; - - if ( single ) + // if there is no input device, there's no point in dual streams + if ( single || selectedInput == paNoDevice ) { - err = Pa_OpenStream(&iStream, - &in_stream_params, + err = Pa_OpenStream(&oStream, + in_params, &out_stream_params, iaxci_sample_rate, SAMPLES_PER_FRAME, paNoFlag, (PaStreamCallback *)pa_callback, NULL); - if (err != paNoError) return -1; - oStream = iStream; + if (err != paNoError) + return -1; + + iStream = oStream; oneStream = 1; } else { + struct PaStreamParameters no_device; + + no_device.device = paNoDevice; + no_device.channelCount = 0; + no_device.sampleFormat = paInt16; + no_device.suggestedLatency = in_dev_info->defaultLowInputLatency; // FEEDBACK - unsure if appropriate + no_device.hostApiSpecificStreamInfo = NULL; + err = Pa_OpenStream(&iStream, &in_stream_params, &no_device, @@ -604,7 +620,8 @@ paNoFlag, (PaStreamCallback *)pa_callback, NULL); - if ( err != paNoError ) return -1; + if ( err != paNoError ) + return -1; err = Pa_OpenStream(&oStream, &no_device, @@ -762,19 +779,28 @@ if ( pa_openstreams(d) ) return -1; - if ( Pa_StartStream(iStream) != paNoError ) + if ( selectedInput == paNoDevice ) + { + if ( Pa_StartStream(oStream) != paNoError ) return -1; + oMixer = Px_OpenMixer(oStream, 0); + } + else + { + if ( Pa_StartStream(iStream) != paNoError ) + return -1; + iMixer = Px_OpenMixer(iStream, 0); if ( !oneStream ) { - PaError err = Pa_StartStream(oStream); - oMixer = Px_OpenMixer(oStream, 0); - if ( err != paNoError ) + if ( Pa_StartStream(oStream) != paNoError ) { Pa_StopStream(iStream); return -1; + } + oMixer = Px_OpenMixer(oStream, 0); } } @@ -842,13 +868,13 @@ if ( sounds ) return 0; - err = Pa_AbortStream(iStream); - err = Pa_CloseStream(iStream); + err = Pa_AbortStream(oStream); + err = Pa_CloseStream(oStream); if ( !oneStream ) { - err = Pa_AbortStream(oStream); - err = Pa_CloseStream(oStream); + err = Pa_AbortStream(iStream); + err = Pa_CloseStream(iStream); } if ( auxStream ) @@ -865,8 +891,8 @@ * I bet if it's gone, no one will miss it. Such a cold, cold world! static void pa_shutdown() { - CloseAudioStream( iStream ); - if(!oneStream) CloseAudioStream( oStream ); + CloseAudioStream( oStream ); + if(!oneStream) CloseAudioStream( iStream ); if(auxStream) CloseAudioStream( aStream ); } */ Modified: branches/team/elbunce/iaxclient/lib/codec_ffmpeg.c =================================================================== --- branches/team/elbunce/iaxclient/lib/codec_ffmpeg.c 2010-01-29 17:41:25 UTC (rev 1463) +++ branches/team/elbunce/iaxclient/lib/codec_ffmpeg.c 2010-02-02 14:48:34 UTC (rev 1464) @@ -209,7 +209,7 @@ } static int decode_iaxc_slice(struct iaxc_video_codec * c, int inlen, - char * in, int * outlen, char * out) + char * in, int * outlen, char * out, int * frames_dropped) { struct decoder_ctx *d = (struct decoder_ctx *) c->decstate; struct slice_header_t * sh_saved = &d->slice_header; @@ -217,10 +217,15 @@ char * inp; int ret; + *frames_dropped = 0; + inp = parse_slice_header(in, &sh_this); if ( !inp ) + { + *frames_dropped = 1; return -1; + } inlen -= inp - in; @@ -237,6 +242,8 @@ } else if ( frame_delta > 0 ) { + *frames_dropped = frame_delta - 1; + /* This slice belongs to a future frame */ if ( sh_saved->slice_index > 0 ) { @@ -254,7 +261,10 @@ reset_decoder_frame_state(d); if ( ret ) + { + *frames_dropped += 1; return -1; + } } sh_saved->frame_index = sh_this.frame_index; @@ -272,6 +282,7 @@ { fprintf(stderr, "codec_ffmpeg: decode: slice overflows decoder frame buffer\n"); + *frames_dropped = 1; return -1; } @@ -294,7 +305,10 @@ reset_decoder_frame_state(d); if ( ret ) + { + *frames_dropped = 1; return -1; + } return 0; } Modified: branches/team/elbunce/iaxclient/lib/codec_theora.c =================================================================== --- branches/team/elbunce/iaxclient/lib/codec_theora.c 2010-01-29 17:41:25 UTC (rev 1463) +++ branches/team/elbunce/iaxclient/lib/codec_theora.c 2010-02-02 14:48:34 UTC (rev 1464) @@ -66,6 +66,7 @@ theora_comment tc; struct deslicer_context *dsc; int got_key_frame; + unsigned short prev_src_id; }; struct theora_encoder @@ -112,7 +113,7 @@ } static int decode(struct iaxc_video_codec *c, int inlen, const char *in, - int *outlen, char *out) + int *outlen, char *out, int * frames_dropped) { struct theora_decoder *d; ogg_packet op; @@ -123,6 +124,8 @@ int flen; char *frame; + *frames_dropped = 0; + // Sanity checks if ( !c || !c->decstate || !in || inlen <= 0 || !out || !outlen ) return -1; @@ -132,7 +135,7 @@ if ( !d->dsc ) return -1; - frame = deslice(in, inlen, &flen, d->dsc); + frame = deslice(in, inlen, &flen, d->dsc, frames_dropped); if ( frame == NULL ) return 1; @@ -141,8 +144,12 @@ op.bytes = flen; op.packet = (unsigned char *)frame; - /* reject all incoming frames until we get a key frame */ - if ( !d->got_key_frame ) + /* Reject all incoming frames until we get a key frame. + * Similarly, check for a change in who is sending the video. + * We shouldn't use frames from a new source until + * we get a keyframe + */ + if ( !d->got_key_frame || d->prev_src_id != d->dsc->source_id ) { if ( theora_packet_iskeyframe(&op) ) d->got_key_frame = 1; @@ -177,6 +184,10 @@ return -1; } + // keep track of the source id (from the most + // recent valid desliced frame) to detect a switch + d->prev_src_id = d->dsc->source_id; + //clear output memset(out, 127, my_out_len); @@ -304,7 +315,11 @@ slice_set->key_frame = theora_packet_iskeyframe(&op) == 1; // Slice the frame - slice((char *)op.packet, op.bytes, slice_set, e->sc); + if ( slice((char *)op.packet, op.bytes, slice_set, e->sc) ) + { + fprintf(stderr, "codec_theora: failed to slice an encoded packet\n"); + return -1; + } return 0; } Modified: branches/team/elbunce/iaxclient/lib/iaxclient.h =================================================================== --- branches/team/elbunce/iaxclient/lib/iaxclient.h 2010-01-29 17:41:25 UTC (rev 1463) +++ branches/team/elbunce/iaxclient/lib/iaxclient.h 2010-02-02 14:48:34 UTC (rev 1464) @@ -270,7 +270,7 @@ int format; /*! - The audio format of the call. + The video format of the call. \see IAXC_FORMAT_JPEG, IAXC_FORMAT_PNG, IAXC_FORMAT_H261, IAXC_FORMAT_H263, IAXC_FORMAT_H263_PLUS, IAXC_FORMAT_H264, IAXC_FORMAT_MPEG4, Modified: branches/team/elbunce/iaxclient/lib/iaxclient_lib.h =================================================================== --- branches/team/elbunce/iaxclient/lib/iaxclient_lib.h 2010-01-29 17:41:25 UTC (rev 1463) +++ branches/team/elbunce/iaxclient/lib/iaxclient_lib.h 2010-02-02 14:48:34 UTC (rev 1464) @@ -171,8 +171,10 @@ void (*destroy) ( struct iaxc_audio_codec *codec); }; +//FIXME: This is all very static. What of higher +// bitrates, that require more slices? #define MAX_TRUNK_LEN (1<<16) -#define MAX_NO_SLICES 32 +#define MAX_NO_SLICES 64 struct slice_set_t { @@ -197,7 +199,8 @@ int (*encode)(struct iaxc_video_codec * codec, int inlen, const char * in, struct slice_set_t * out); int (*decode)(struct iaxc_video_codec * codec, int inlen, - const char * in, int * outlen, char * out); + const char * in, int * outlen, char * out, + int * frames_dropped); void (*destroy)(struct iaxc_video_codec * codec); }; Modified: branches/team/elbunce/iaxclient/lib/slice.c =================================================================== --- branches/team/elbunce/iaxclient/lib/slice.c 2010-01-29 17:41:25 UTC (rev 1463) +++ branches/team/elbunce/iaxclient/lib/slice.c 2010-02-02 14:48:34 UTC (rev 1464) @@ -41,10 +41,30 @@ int i, ssize; if ( data == NULL || slice_set == NULL || sc == NULL) + { + fprintf(stderr, "slice: invalid param(s): data=%p, set=%p, context=%p\n", + data, slice_set, sc); return -1; + } + // Theora packets can be 0-byte (delta-frame with no coded blocks) + if ( size ) + { // Figure out how many slices we need slice_set->num_slices = (size - 1) / sc->slice_size + 1; + + if ( slice_set->num_slices > MAX_NO_SLICES ) + { + fprintf(stderr, "slice: %d-byte frame is too large " + "- would require %d slices\n", + size, slice_set->num_slices); + return -1; + } + } + else + { + slice_set->num_slices = 1; + } for ( i = 0; i < slice_set->num_slices; i++ ) { @@ -94,11 +114,13 @@ } char * -deslice(const char *in, int inlen, int *outlen, struct deslicer_context *dsc) +deslice(const char *in, int inlen, int *outlen, struct deslicer_context *dsc, int *frames_dropped) { unsigned char frame_index, slice_index, num_slices, version; unsigned short source_id; + *frames_dropped = 0; + // Sanity checks if ( dsc == NULL || in == NULL || inlen <= 0 || outlen == NULL ) return NULL; @@ -139,10 +161,14 @@ /* Slice belongs to a new frame */ dsc->frame_index = frame_index; + *frames_dropped += frame_delta - 1; + if ( dsc->slice_count > 0 ) { /* Current frame is incomplete, drop it */ reset_deslicer_context(dsc); + + *frames_dropped += 1; } } } else @@ -159,6 +185,9 @@ if ( dsc->slice_size * slice_index + inlen > MAX_ENCODED_FRAME_SIZE ) { // Frame would be too large, ignore slice + fprintf(stderr, "deslice: dropping frame that's > %d bytes\n", + MAX_ENCODED_FRAME_SIZE); + *frames_dropped = 1; return NULL; } Modified: branches/team/elbunce/iaxclient/lib/slice.h =================================================================== --- branches/team/elbunce/iaxclient/lib/slice.h 2010-01-29 17:41:25 UTC (rev 1463) +++ branches/team/elbunce/iaxclient/lib/slice.h 2010-02-02 14:48:34 UTC (rev 1464) @@ -39,7 +39,12 @@ #include "iaxclient_lib.h" -#define MAX_ENCODED_FRAME_SIZE 48 * 1024 +// We don't bother deslicing frames larger than this, +// but we DO slice-up frames as long as they don't exceed +// MAX_NO_SLICES, each up to MAX_TRUNK_LEN long +// ( see definition of struct slice_set_t ) +//FIXME: this doesn't depend on the bitrate +#define MAX_ENCODED_FRAME_SIZE 96 * 1024 struct slicer_context { @@ -104,6 +109,7 @@ * outlen with the frame size if successful */ char * -deslice(const char *in, int inlen, int *outlen, struct deslicer_context *dsc); +deslice(const char *in, int inlen, int *outlen, struct deslicer_context *dsc, + int * frames_dropped); #endif Modified: branches/team/elbunce/iaxclient/lib/video.c =================================================================== --- branches/team/elbunce/iaxclient/lib/video.c 2010-01-29 17:41:25 UTC (rev 1463) +++ branches/team/elbunce/iaxclient/lib/video.c 2010-02-02 14:48:34 UTC (rev 1464) @@ -1255,6 +1255,7 @@ int ret; struct timeval now; long time; + int frames_dropped; if ( !call ) return 0; @@ -1311,8 +1312,10 @@ call->vdecoder->video_stats.acc_recv_size * 8000 / time; ret = call->vdecoder->decode(call->vdecoder, encoded_video_len, - (char *)encoded_video, &out_size, yuv_buf); + (char *)encoded_video, &out_size, yuv_buf, &frames_dropped); + call->vdecoder->video_stats.dropped_frames += (unsigned long) frames_dropped; + if ( ret < 0 ) { fprintf(stderr, "ERROR: decode error\n"); @@ -1823,7 +1826,14 @@ vinfo.sc = create_slicer_context((unsigned short)rand(), vfinfo.fragsize); - slice(data, size, &slice_set, vinfo.sc); + if ( slice(data, size, &slice_set, vinfo.sc) ) + { + fprintf(stderr, "iaxc_push_video: Failed to slice frame," + " call %d, size %d\n", + selected_call, size); + return -1; + } + for ( i = 0 ; i < slice_set.num_slices ; i++ ) { if ( iax_send_video_trunk(call->session, Modified: branches/team/elbunce/iaxclient/simpleclient/stresstest/file.c =================================================================== --- branches/team/elbunce/iaxclient/simpleclient/stresstest/file.c 2010-01-29 17:41:25 UTC (rev 1463) +++ branches/team/elbunce/iaxclient/simpleclient/stresstest/file.c 2010-02-02 14:48:34 UTC (rev 1464) @@ -199,8 +199,8 @@ read_speex_cb(oggz, op, serialno, data); } else { - mylog("Got unknown ogg packet, serialno=%d, size=%d, " - "packetno=%d, granulepos=%d\n", + mylog("Got unknown ogg packet, serialno=%ld, size=%ld, " + "packetno=%lld, granulepos=%lld\n", serialno, op->bytes, op->packetno, op->granulepos); } Modified: branches/team/elbunce/iaxclient/simpleclient/stresstest/stresstest.c =================================================================== --- branches/team/elbunce/iaxclient/simpleclient/stresstest/stresstest.c 2010-01-29 17:41:25 UTC (rev 1463) +++ branches/team/elbunce/iaxclient/simpleclient/stresstest/stresstest.c 2010-02-02 14:48:34 UTC (rev 1464) @@ -69,8 +69,9 @@ static int fragsize = 1400; static int call_established = 0; -static int running = 0; +static int running = 1; +static int camera_enabled_sent = 0; static int send_video = 1; static int send_audio = 1; static int print_netstats = 0; @@ -221,27 +222,31 @@ return 0; } -void process_text_message(char *message) +void process_text_message(const char * message) { unsigned int prefs; + const char ctrl_str[] = "CONTROL:"; + const int ctrl_strlen = strlen(ctrl_str); - if ( strncmp(message, "CONTROL:", strlen("CONTROL:")) == 0 ) + if ( strncmp(message, ctrl_str, ctrl_strlen) == 0 ) { - message += strlen("CONTROL:"); + message += ctrl_strlen; if ( strcmp(message, "STOPVIDEO") == 0 ) { // Stop sending video prefs = iaxc_get_video_prefs(); prefs = prefs | IAXC_VIDEO_PREF_SEND_DISABLE ; iaxc_set_video_prefs(prefs); - } else if ( strcmp(message, "STARTVIDEO") == 0 ) + } + else if ( strcmp(message, "STARTVIDEO") == 0 ) { // Start sending video prefs = iaxc_get_video_prefs(); prefs = prefs & ~IAXC_VIDEO_PREF_SEND_DISABLE ; iaxc_set_video_prefs(prefs); } - } else + } + else mylog("Text message received: %s\n", message); } @@ -534,8 +539,7 @@ // Wait for the call to be established; while ( !call_established && running ) { - struct timeval now; - now = get_now(); + struct timeval now = get_now(); if ( connect_timeout_ms > 0 && msecdiff(&start_time, &now) > connect_timeout_ms ) { @@ -546,7 +550,6 @@ iaxc_millisleep(5); } - running = 1; while ( running ) { struct timeval now = get_now(); @@ -571,7 +574,15 @@ if ( !loop && video_is_eos() ) break; if ( send_video && op != NULL && op->bytes > 0 ) + { + if ( !camera_enabled_sent ) + { + /* Let app_conference know that we can send video */ + iaxc_send_text("CONTROL:CAMERA_ENABLED"); + camera_enabled_sent = 1; + } iaxc_push_video(op->packet, op->bytes, 1); + } } // Tight spinloops are bad, mmmkay? This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |