diff options
Diffstat (limited to 'src')
81 files changed, 2415 insertions, 2250 deletions
diff --git a/src/audio_dec/xine_mad_decoder.c b/src/audio_dec/xine_mad_decoder.c index de7590f4e..74c04924f 100644 --- a/src/audio_dec/xine_mad_decoder.c +++ b/src/audio_dec/xine_mad_decoder.c @@ -48,6 +48,20 @@ #define INPUT_BUF_SIZE 16384 +/* According to Rob Leslie (libmad author) : + * The absolute theoretical maximum frame size is 2881 bytes: MPEG 2.5 Layer II, + * 8000 Hz @ 160 kbps, with a padding slot. (Such a frame is unlikely, but it was + * a useful exercise to compute all possible frame sizes.) Add to this an 8 byte + * MAD_BUFFER_GUARD, and the minimum buffer size you should be streaming to + * libmad in the general case is 2889 bytes. + + * Theoretical frame sizes for Layer III range from 24 to 1441 bytes, but there + * is a "soft" limit imposed by the standard of 960 bytes. Nonetheless MAD can + * decode frames of any size as long as they fit entirely in the buffer you pass, + * not including the MAD_BUFFER_GUARD bytes. + */ +#define MAD_MIN_SIZE 2889 + typedef struct { audio_decoder_class_t decoder_class; } mad_class_t; @@ -135,9 +149,10 @@ static int head_check(mad_decoder_t *this) { static void mad_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { mad_decoder_t *this = (mad_decoder_t *) this_gen; + int bytes_in_buffer_at_pts; + + lprintf ("decode data, size: %d, decoder_flags: %d\n", buf->size, buf->decoder_flags); - lprintf ("decode data, decoder_flags: %d\n", buf->decoder_flags); - if (buf->size>(INPUT_BUF_SIZE-this->bytes_in_buffer)) { xprintf (this->xstream->xine, XINE_VERBOSITY_DEBUG, "libmad: ALERT input buffer too small (%d bytes, %d avail)!\n", @@ -156,6 +171,8 @@ static void mad_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { this->preview_mode = 1; } + bytes_in_buffer_at_pts = this->bytes_in_buffer; + xine_fast_memcpy (&this->buffer[this->bytes_in_buffer], buf->content, buf->size); this->bytes_in_buffer += buf->size; @@ -167,6 +184,9 @@ static void mad_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { mad_stream_buffer (&this->stream, this->buffer, this->bytes_in_buffer); + if (this->bytes_in_buffer < MAD_MIN_SIZE) + return; + while (1) { if (mad_frame_decode (&this->frame, &this->stream) != 0) { @@ -187,6 +207,7 @@ static void mad_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { return; default: + lprintf ("error 0x%04X, mad_stream_buffer %d bytes\n", this->stream.error, this->bytes_in_buffer); mad_stream_buffer (&this->stream, this->buffer, this->bytes_in_buffer); } @@ -253,6 +274,8 @@ static void mad_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { struct mad_pcm *pcm = &this->synth.pcm; audio_buffer_t *audio_buffer; uint16_t *output; + int bitrate; + int pts_offset; audio_buffer = this->xstream->audio_out->get_buffer (this->xstream->audio_out); output = audio_buffer->mem; @@ -273,7 +296,22 @@ static void mad_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { } audio_buffer->num_frames = pcm->length; - audio_buffer->vpts = buf->pts; + + /* pts computing */ + if (this->frame.header.bitrate > 0) { + bitrate = this->frame.header.bitrate; + } else { + bitrate = _x_stream_info_get(this->xstream, XINE_STREAM_INFO_AUDIO_BITRATE); + lprintf("offset %d bps\n", bitrate); + } + audio_buffer->vpts = buf->pts; + if (audio_buffer->vpts && (bitrate > 0)) { + pts_offset = (bytes_in_buffer_at_pts * 8 * 90) / (bitrate / 1000); + lprintf("pts: %"PRId64", offset: %d pts, %d bytes\n", buf->pts, pts_offset, bytes_in_buffer_at_pts); + if (audio_buffer->vpts < pts_offset) + pts_offset = audio_buffer->vpts; + audio_buffer->vpts -= pts_offset; + } this->xstream->audio_out->put_buffer (this->xstream->audio_out, audio_buffer, this->xstream); diff --git a/src/audio_out/audio_fusionsound_out.c b/src/audio_out/audio_fusionsound_out.c index a79d21213..b33850c5e 100644 --- a/src/audio_out/audio_fusionsound_out.c +++ b/src/audio_out/audio_fusionsound_out.c @@ -47,6 +47,12 @@ #define FUSIONSOUND_VERSION_CODE VERSION_CODE( FUSIONSOUND_MAJOR_VERSION, \ FUSIONSOUND_MINOR_VERSION, \ FUSIONSOUND_MICRO_VERSION ) + +#if FUSIONSOUND_VERSION_CODE >= VERSION_CODE(1,1,0) +# include <fusionsound_limits.h> /* defines FS_MAX_CHANNELS */ +#else +# define FS_MAX_CHANNELS 2 +#endif #define AO_OUT_FS_IFACE_VERSION 9 @@ -100,7 +106,29 @@ static int ao_fusionsound_open(ao_driver_t *ao_driver, break; case AO_CAP_MODE_STEREO: dsc.channels = 2; - break; + break; +#if FS_MAX_CHANNELS > 2 + case AO_CAP_MODE_4CHANNEL: + dsc.channels = 4; + dsc.channelmode = FSCM_SURROUND40_2F2R; + dsc.flags |= FSBDF_CHANNELMODE; + break; + case AO_CAP_MODE_4_1CHANNEL: + dsc.channels = 5; + dsc.channelmode = FSCM_SURROUND41_2F2R; + dsc.flags |= FSBDF_CHANNELMODE; + break; + case AO_CAP_MODE_5CHANNEL: + dsc.channels = 5; + dsc.channelmode = FSCM_SURROUND50; + dsc.flags |= FSBDF_CHANNELMODE; + break; + case AO_CAP_MODE_5_1CHANNEL: + dsc.channels = 6; + dsc.channelmode = FSCM_SURROUND51; + dsc.flags |= FSBDF_CHANNELMODE; + break; +#endif default: xprintf (this->xine, XINE_VERBOSITY_LOG, "audio_fusionsound_out: mode %#x not supported\n", mode); @@ -250,13 +278,18 @@ static void ao_fusionsound_close(ao_driver_t *ao_driver){ */ static uint32_t ao_fusionsound_get_capabilities(ao_driver_t *ao_driver) { + uint32_t caps = AO_CAP_MODE_MONO | AO_CAP_MODE_STEREO | + AO_CAP_MIXER_VOL | AO_CAP_MUTE_VOL | + AO_CAP_8BITS | AO_CAP_16BITS | + AO_CAP_24BITS; #if FUSIONSOUND_VERSION_CODE >= VERSION_CODE(0,9,26) - return (AO_CAP_MODE_MONO | AO_CAP_MODE_STEREO | AO_CAP_MIXER_VOL | - AO_CAP_8BITS | AO_CAP_16BITS | AO_CAP_24BITS | AO_CAP_FLOAT32); -#else - return (AO_CAP_MODE_MONO | AO_CAP_MODE_STEREO | AO_CAP_MIXER_VOL | - AO_CAP_8BITS | AO_CAP_16BITS | AO_CAP_24BITS); + caps |= AO_CAP_FLOAT32; +#endif +#if FS_MAX_CHANNELS > 2 + caps |= AO_CAP_MODE_4CHANNEL | AO_CAP_MODE_4_1CHANNEL | + AO_CAP_MODE_5CHANNEL | AO_CAP_MODE_5_1CHANNEL; #endif + return caps; } static void ao_fusionsound_exit(ao_driver_t *ao_driver) { diff --git a/src/audio_out/audio_pulse_out.c b/src/audio_out/audio_pulse_out.c index b4ec0b156..0235a4321 100644 --- a/src/audio_out/audio_pulse_out.c +++ b/src/audio_out/audio_pulse_out.c @@ -246,7 +246,7 @@ static int ao_pulse_open(ao_driver_t *this_gen, pa_threaded_mainloop_lock(this->pa_class->mainloop); ret = pa_context_connect(this->pa_class->context, this->host, 1, NULL); if ( ret < 0 ) - goto fail; + goto fail_unlock; pa_context_set_state_callback(this->pa_class->context, __xine_pa_context_status_callback, this); @@ -289,8 +289,9 @@ static int ao_pulse_open(ao_driver_t *this_gen, return this->sample_rate; -fail: + fail_unlock: pa_threaded_mainloop_unlock(this->pa_class->mainloop); + fail: this_gen->close(this_gen); return 0; } diff --git a/src/combined/ffmpeg/ff_video_decoder.c b/src/combined/ffmpeg/ff_video_decoder.c index 8f6864ea1..7cb584593 100644 --- a/src/combined/ffmpeg/ff_video_decoder.c +++ b/src/combined/ffmpeg/ff_video_decoder.c @@ -44,7 +44,11 @@ #include "ffmpeg_decoder.h" #include "ff_mpeg_parser.h" -#include <postprocess.h> +#ifdef HAVE_FFMPEG_AVCODEC_H +# include <postprocess.h> +#else +# include <libpostproc/postprocess.h> +#endif #define VIDEOBUFSIZE (128*1024) #define SLICE_BUFFER_SIZE (1194*1024) @@ -310,6 +314,7 @@ static const ff_codec_t ff_video_lookup[] = { {BUF_VIDEO_KMVC, CODEC_ID_KMVC, "Karl Morton's Video Codec (ffmpeg)"}, {BUF_VIDEO_FLASHSV, CODEC_ID_FLASHSV, "Flash Screen Video (ffmpeg)"}, {BUF_VIDEO_CAVS, CODEC_ID_CAVS, "Chinese AVS (ffmpeg)"}, + {BUF_VIDEO_VMNC, CODEC_ID_VMNC, "VMware Screen Codec (ffmpeg)"}, {BUF_VIDEO_THEORA_RAW, CODEC_ID_THEORA, "Theora (ffmpeg)"}, }; @@ -1692,6 +1697,9 @@ static const uint32_t supported_video_types[] = { BUF_VIDEO_KMVC, BUF_VIDEO_FLASHSV, BUF_VIDEO_CAVS, +#endif +#if defined(HAVE_FFMPEG) || CONFIG_VMNC_DECODER + BUF_VIDEO_VMNC, BUF_VIDEO_THEORA_RAW, 0 }; diff --git a/src/combined/ffmpeg/ffmpeg_decoder.h b/src/combined/ffmpeg/ffmpeg_decoder.h index bfe71a6b1..adf0908dd 100644 --- a/src/combined/ffmpeg/ffmpeg_decoder.h +++ b/src/combined/ffmpeg/ffmpeg_decoder.h @@ -25,7 +25,11 @@ #include "config.h" #endif -#include <avcodec.h> +#ifdef HAVE_FFMPEG_AVCODEC_H +# include <avcodec.h> +#else +# include <libavcodec/avcodec.h> +#endif typedef struct ff_codec_s { uint32_t type; diff --git a/src/combined/flac_demuxer.c b/src/combined/flac_demuxer.c index bab42876c..22ee2319b 100644 --- a/src/combined/flac_demuxer.c +++ b/src/combined/flac_demuxer.c @@ -713,7 +713,8 @@ demux_flac_init_class (xine_t *xine, void *data) { this->demux_class.open_plugin = open_plugin; this->demux_class.description = N_("FLAC demux plugin"); this->demux_class.identifier = "FLAC"; - this->demux_class.mimetypes = "application/x-flac: flac: FLAC Audio;"; + this->demux_class.mimetypes = "application/x-flac: flac: FLAC Audio;" + "application/flac: flac: FLAC Audio;"; this->demux_class.extensions = "flac"; this->demux_class.dispose = default_demux_class_dispose; diff --git a/src/combined/wavpack_demuxer.c b/src/combined/wavpack_demuxer.c index 9c0831cfa..403d136d1 100644 --- a/src/combined/wavpack_demuxer.c +++ b/src/combined/wavpack_demuxer.c @@ -368,7 +368,7 @@ void *demux_wv_init_plugin (xine_t *const xine, void *const data) { this->demux_class.open_plugin = open_plugin; this->demux_class.description = N_("Wavpack demux plugin"); this->demux_class.identifier = "Wavpack"; - this->demux_class.mimetypes = NULL; + this->demux_class.mimetypes = "audio/x-wavpack"; this->demux_class.extensions = "wv"; this->demux_class.dispose = default_demux_class_dispose; diff --git a/src/combined/xine_ogg_demuxer.c b/src/combined/xine_ogg_demuxer.c index d6b5ea214..88fcea08a 100644 --- a/src/combined/xine_ogg_demuxer.c +++ b/src/combined/xine_ogg_demuxer.c @@ -892,7 +892,10 @@ static void decode_video_header (demux_ogg_t *this, const int stream_num, ogg_pa this->si[stream_num]->buf_types = _x_fourcc_to_buf_video (locsubtype); if( !this->si[stream_num]->buf_types ) + { this->si[stream_num]->buf_types = BUF_VIDEO_UNKNOWN; + _x_report_video_fourcc (this->stream->xine, LOG_MODULE, locsubtype); + } this->si[stream_num]->buf_types |= channel; this->si[stream_num]->headers = 0; /* header is sent below */ @@ -977,9 +980,8 @@ static void decode_audio_header (demux_ogg_t *this, const int stream_num, ogg_pa if( this->si[stream_num]->buf_types ) { this->si[stream_num]->buf_types |= channel; } else { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ogg: unknown audio codec type 0x%x\n", codec); this->si[stream_num]->buf_types = BUF_AUDIO_UNKNOWN; + _x_report_audio_format_tag (this->stream->xine, LOG_MODULE, codec); /*break;*/ } @@ -1044,7 +1046,10 @@ static void decode_dshow_header (demux_ogg_t *this, const int stream_num, ogg_pa this->si[stream_num]->buf_types = _x_fourcc_to_buf_video (fcc); if( !this->si[stream_num]->buf_types ) + { this->si[stream_num]->buf_types = BUF_VIDEO_UNKNOWN; + _x_report_video_fourcc (this->stream->xine, LOG_MODULE, fcc); + } this->si[stream_num]->buf_types |= channel; bih.biSize = sizeof(xine_bmiheader); @@ -2079,7 +2084,13 @@ static void *anx_init_class (xine_t *xine, void *data) { this->demux_class.open_plugin = anx_open_plugin; this->demux_class.description = N_("Annodex demux plugin"); this->demux_class.identifier = "Annodex"; - this->demux_class.mimetypes = "application/x-annodex: ogg: Annodex media;"; + this->demux_class.mimetypes = + "application/annodex: anx: Annodex media;" + "application/x-annodex: anx: Annodex media;" + "audio/annodex: axa: Annodex audio;" + "audio/x-annodex: axa: Annodex audio;" + "video/annodex: axv: Annodex video;" + "video/x-annodex: axv: Annodex video;"; this->demux_class.extensions = "anx axa axv"; this->demux_class.dispose = default_demux_class_dispose; @@ -2098,11 +2109,13 @@ static void *ogg_init_class (xine_t *xine, void *data) { this->demux_class.description = N_("OGG demux plugin"); this->demux_class.identifier = "OGG"; this->demux_class.mimetypes = - "audio/x-ogg: ogg: OggVorbis Audio;" - "audio/x-speex: ogg: Speex Audio;" - "application/x-ogg: ogg: Ogg Stream;" - "application/ogg: ogg: Ogg Stream;"; - this->demux_class.extensions = "ogg ogm spx"; + "application/ogg: ogx: Ogg Stream;" + "application/x-ogg: ogx: Ogg Stream;" + "audio/ogg: oga: Ogg Audio;" + "audio/x-ogg: oga: Ogg Audio;" + "video/ogg: ogv: Ogg Video;"; + "video/x-ogg: ogv: Ogg Video;"; + this->demux_class.extensions = "ogx ogv oga ogg spx ogm"; this->demux_class.dispose = default_demux_class_dispose; return this; diff --git a/src/combined/xine_vorbis_decoder.c b/src/combined/xine_vorbis_decoder.c index 6d651f153..ad3a07188 100644 --- a/src/combined/xine_vorbis_decoder.c +++ b/src/combined/xine_vorbis_decoder.c @@ -41,6 +41,7 @@ #include <vorbis/codec.h> #define MAX_NUM_SAMPLES 4096 +#define INIT_BUFSIZE 8192 typedef struct { audio_decoder_class_t decoder_class; @@ -70,6 +71,11 @@ typedef struct vorbis_decoder_s { xine_stream_t *stream; + /* data accumulation stuff */ + unsigned char *buf; + int bufsize; + int size; + } vorbis_decoder_t; @@ -78,6 +84,7 @@ static void vorbis_reset (audio_decoder_t *this_gen) { vorbis_decoder_t *this = (vorbis_decoder_t *) this_gen; if( this->header_count ) return; + this->size = 0; /* clear block first, as it might contain allocated data */ vorbis_block_clear(&this->vb); @@ -136,126 +143,147 @@ static void get_metadata (vorbis_decoder_t *this) { _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, "vorbis"); } +static void vorbis_check_bufsize (vorbis_decoder_t *this, int size) { + if (size > this->bufsize) { + this->bufsize = size + size / 2; + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + _("vorbis: increasing buffer to %d to avoid overflow.\n"), + this->bufsize); + this->buf = realloc(this->buf, this->bufsize); + } +} + static void vorbis_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { vorbis_decoder_t *this = (vorbis_decoder_t *) this_gen; memset( &this->op, 0, sizeof(this->op) ); - this->op.packet = buf->content; - this->op.bytes = buf->size; - - if ( (buf->decoder_flags & BUF_FLAG_HEADER) && - !(buf->decoder_flags & BUF_FLAG_STDHEADER) ) { - lprintf ("%d headers to go\n", this->header_count); - if (this->header_count) { - int res = 0; + /* data accumulation */ + vorbis_check_bufsize(this, this->size + buf->size); + xine_fast_memcpy (&this->buf[this->size], buf->content, buf->size); + this->size += buf->size; - if (this->header_count == 3) - this->op.b_o_s = 1; + if (buf->decoder_flags & BUF_FLAG_FRAME_END) { + this->op.packet = this->buf; + this->op.bytes = this->size; - - if( (res = vorbis_synthesis_headerin(&this->vi,&this->vc,&this->op)) < 0 ){ - /* error case; not a vorbis header */ - xine_log(this->stream->xine, XINE_LOG_MSG, "libvorbis: this bitstream does not contain vorbis audio data. Following first 64 bytes (return: %d).\n", res); - xine_hexdump((char *)this->op.packet, this->op.bytes < 64 ? this->op.bytes : 64); - return; - } - - this->header_count--; - - if (!this->header_count) { - - int mode = AO_CAP_MODE_MONO; - - get_metadata (this); - - mode = _x_ao_channels2mode(this->vi.channels); - - this->convsize=MAX_NUM_SAMPLES/this->vi.channels; - - if (!this->output_open) { - this->output_open = (this->stream->audio_out->open) (this->stream->audio_out, - this->stream, - 16, - this->vi.rate, - mode) ; - - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, - this->vi.bitrate_nominal); - - } - - /* OK, got and parsed all three headers. Initialize the Vorbis - * packet->PCM decoder. */ - lprintf("all three headers parsed. initializing decoder.\n"); - /* initialize central decode state */ - vorbis_synthesis_init(&this->vd,&this->vi); - /* initialize local state for most of the decode so multiple - * block decodes can proceed in parallel. We could init - * multiple vorbis_block structures for vd here */ - vorbis_block_init(&this->vd,&this->vb); + /* reset accumultaion buffer */ + this->size = 0; + + if ( (buf->decoder_flags & BUF_FLAG_HEADER) && + !(buf->decoder_flags & BUF_FLAG_STDHEADER) ) { + + lprintf ("%d headers to go\n", this->header_count); + + if (this->header_count) { + int res = 0; + + if (this->header_count == 3) + this->op.b_o_s = 1; + + if ( (res = vorbis_synthesis_headerin(&this->vi,&this->vc,&this->op)) < 0 ) { + /* error case; not a vorbis header */ + xine_log(this->stream->xine, XINE_LOG_MSG, "libvorbis: this bitstream does not contain vorbis audio data. Following first 64 bytes (return: %d).\n", res); + xine_hexdump((char *)this->op.packet, this->op.bytes < 64 ? this->op.bytes : 64); + return; + } + + this->header_count--; + + if (!this->header_count) { + + int mode = AO_CAP_MODE_MONO; + + get_metadata (this); + + mode = _x_ao_channels2mode(this->vi.channels); + + this->convsize=MAX_NUM_SAMPLES/this->vi.channels; + + if (!this->output_open) { + this->output_open = (this->stream->audio_out->open) (this->stream->audio_out, + this->stream, + 16, + this->vi.rate, + mode) ; + + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, + this->vi.bitrate_nominal); + + } + + /* OK, got and parsed all three headers. Initialize the Vorbis + * packet->PCM decoder. */ + lprintf("all three headers parsed. initializing decoder.\n"); + /* initialize central decode state */ + vorbis_synthesis_init(&this->vd,&this->vi); + /* initialize local state for most of the decode so multiple + * block decodes can proceed in parallel. We could init + * multiple vorbis_block structures for vd here */ + vorbis_block_init(&this->vd,&this->vb); + } } - } - - } else if (this->output_open) { - - float **pcm; - int samples; - - if(vorbis_synthesis(&this->vb,&this->op)==0) - vorbis_synthesis_blockin(&this->vd,&this->vb); - - if (buf->pts!=0) - this->pts=buf->pts; - - while ((samples=vorbis_synthesis_pcmout(&this->vd,&pcm))>0){ - - /* **pcm is a multichannel float vector. In stereo, for - * example, pcm[0][...] is left, and pcm[1][...] is right. - * samples is the size of each channel. Convert the float - * values (-1.<=range<=1.) to whatever PCM format and write - * it out - */ - - int i,j; - int bout=(samples<this->convsize?samples:this->convsize); - audio_buffer_t *audio_buffer; - - audio_buffer = this->stream->audio_out->get_buffer (this->stream->audio_out); - - /* convert floats to 16 bit signed ints (host order) and - interleave */ - for(i=0;i<this->vi.channels;i++){ - ogg_int16_t *ptr=audio_buffer->mem+i; - float *mono=pcm[i]; - for(j=0;j<bout;j++){ - int val=(mono[j] + 1.0f) * 32768.f; - val -= 32768; - /* might as well guard against clipping */ - if(val>32767){ - val=32767; - } else if(val<-32768){ - val=-32768; - } - *ptr=val; - ptr+=this->vi.channels; - } + + } else if (this->output_open) { + + float **pcm; + int samples; + + if(vorbis_synthesis(&this->vb,&this->op)==0) + vorbis_synthesis_blockin(&this->vd,&this->vb); + + if (buf->pts!=0) + this->pts=buf->pts; + + while ((samples=vorbis_synthesis_pcmout(&this->vd,&pcm))>0){ + + /* **pcm is a multichannel float vector. In stereo, for + * example, pcm[0][...] is left, and pcm[1][...] is right. + * samples is the size of each channel. Convert the float + * values (-1.<=range<=1.) to whatever PCM format and write + * it out + */ + + int i,j; + int bout=(samples<this->convsize?samples:this->convsize); + audio_buffer_t *audio_buffer; + + audio_buffer = this->stream->audio_out->get_buffer (this->stream->audio_out); + + /* convert floats to 16 bit signed ints (host order) and + interleave */ + for(i=0;i<this->vi.channels;i++){ + ogg_int16_t *ptr=audio_buffer->mem+i; + float *mono=pcm[i]; + for(j=0;j<bout;j++){ + int val=(mono[j] + 1.0f) * 32768.f; + val -= 32768; + /* might as well guard against clipping */ + if(val>32767){ + val=32767; + } else if(val<-32768){ + val=-32768; + } + *ptr=val; + ptr+=this->vi.channels; + } + } + + audio_buffer->vpts = this->pts; + this->pts=0; + audio_buffer->num_frames = bout; + + this->stream->audio_out->put_buffer (this->stream->audio_out, audio_buffer, this->stream); + + buf->pts=0; + + /* tell libvorbis how many samples we actually consumed */ + vorbis_synthesis_read(&this->vd,bout); } - - audio_buffer->vpts = this->pts; - this->pts=0; - audio_buffer->num_frames = bout; - - this->stream->audio_out->put_buffer (this->stream->audio_out, audio_buffer, this->stream); - - buf->pts=0; - - /* tell libvorbis how many samples we actually consumed */ - vorbis_synthesis_read(&this->vd,bout); + } else { + lprintf("output not open\n"); } - } else { - lprintf("output not open\n"); } } @@ -299,6 +327,10 @@ static audio_decoder_t *open_plugin (audio_decoder_class_t *class_gen, this->header_count = 3; this->convsize = 0; + this->bufsize = INIT_BUFSIZE; + this->buf = xine_xmalloc(INIT_BUFSIZE); + this->size = 0; + vorbis_info_init(&this->vi); vorbis_comment_init(&this->vc); diff --git a/src/demuxers/asfheader.c b/src/demuxers/asfheader.c index 97537c337..75ad11c75 100644 --- a/src/demuxers/asfheader.c +++ b/src/demuxers/asfheader.c @@ -140,9 +140,9 @@ static uint8_t *asf_reader_get_bytes(asf_reader_t *reader, size_t size) { static char *asf_reader_get_string(asf_reader_t *reader, size_t size, iconv_t cd) {
char *inbuf, *outbuf;
size_t inbytesleft, outbytesleft;
- char scratch[2048];
+ char scratch[2048];
- if ((reader->size - reader->pos) < size)
+ if ((size == 0) ||((reader->size - reader->pos) < size))
return NULL;
inbuf = (char *)reader->buffer + reader->pos;
@@ -596,6 +596,12 @@ static int asf_header_parse_content_description(asf_header_t *header_pub, uint8_ content->description = asf_reader_get_string(&reader, description_length, iconv_cd);
content->rating = asf_reader_get_string(&reader, rating_length, iconv_cd);
+ lprintf("title: %d chars: \"%s\"\n", title_length, content->title);
+ lprintf("author: %d chars: \"%s\"\n", author_length, content->author);
+ lprintf("copyright: %d chars: \"%s\"\n", copyright_length, content->copyright);
+ lprintf("description: %d chars: \"%s\"\n", description_length, content->description);
+ lprintf("rating: %d chars: \"%s\"\n", rating_length, content->rating);
+
header->pub.content = content;
iconv_close(iconv_cd);
diff --git a/src/demuxers/demux_asf.c b/src/demuxers/demux_asf.c index 1a97e12bf..73f70eeb3 100644 --- a/src/demuxers/demux_asf.c +++ b/src/demuxers/demux_asf.c @@ -379,10 +379,21 @@ static int asf_read_header (demux_asf_t *this) { uint8_t *asf_header_buffer = NULL; asf_header_len = get_le64(this); - asf_header_buffer = alloca(asf_header_len); + if (asf_header_len > 4 * 1024 * 1024) + { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_asf: asf_read_header: overly-large header? (%"PRIu64" bytes)\n", + asf_header_len); + return 0; + } + + asf_header_buffer = malloc (asf_header_len); if (this->input->read (this->input, asf_header_buffer, asf_header_len) != asf_header_len) + { + free (asf_header_buffer); return 0; + } /* delete previous header */ if (this->asf_header) { @@ -395,7 +406,11 @@ static int asf_read_header (demux_asf_t *this) { */ this->asf_header = asf_header_new(asf_header_buffer, asf_header_len); if (!this->asf_header) + { + free (asf_header_buffer); return 0; + } + free (asf_header_buffer); lprintf("asf header parsing ok\n"); @@ -449,10 +464,9 @@ static int asf_read_header (demux_asf_t *this) { demux_stream->buf_type = _x_formattag_to_buf_audio ( ((xine_waveformatex *)asf_stream->private_data)->wFormatTag ); if ( !demux_stream->buf_type ) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_asf: unknown audio type 0x%x\n", - ((xine_waveformatex *)asf_stream->private_data)->wFormatTag); demux_stream->buf_type = BUF_AUDIO_UNKNOWN; + _x_report_audio_format_tag (this->stream->xine, LOG_MODULE, + ((xine_waveformatex *)asf_stream->private_data)->wFormatTag); } _x_meta_info_set(this->stream, XINE_META_INFO_AUDIOCODEC, _x_buf_audio_name(demux_stream->buf_type)); @@ -495,10 +509,8 @@ static int asf_read_header (demux_asf_t *this) { demux_stream->buf_type = _x_fourcc_to_buf_video(bmiheader->biCompression); if( !demux_stream->buf_type ) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_asf: unknown video format %.4s\n", (char*)&(bmiheader->biCompression)); - demux_stream->buf_type = BUF_VIDEO_UNKNOWN; + _x_report_video_fourcc (this->stream->xine, LOG_MODULE, bmiheader->biCompression); } _x_meta_info_set(this->stream, XINE_META_INFO_VIDEOCODEC, _x_buf_video_name(demux_stream->buf_type)); @@ -722,6 +734,9 @@ static void asf_send_buffer_nodefrag (demux_asf_t *this, asf_demux_stream_t *str buf->size = bufsize; timestamp = 0; + if (stream->frag_offset == 0) + buf->decoder_flags |= BUF_FLAG_FRAME_START; + stream->frag_offset += bufsize; frag_len -= bufsize; @@ -732,10 +747,6 @@ static void asf_send_buffer_nodefrag (demux_asf_t *this, asf_demux_stream_t *str else check_newpts (this, buf->pts, PTS_AUDIO, package_done); - - if (frag_offset == 0) - buf->decoder_flags |= BUF_FLAG_FRAME_START; - /* test if whole packet read */ if (package_done) { buf->decoder_flags |= BUF_FLAG_FRAME_END; diff --git a/src/demuxers/demux_avi.c b/src/demuxers/demux_avi.c index c6a73ebde..27dfce443 100644 --- a/src/demuxers/demux_avi.c +++ b/src/demuxers/demux_avi.c @@ -1871,7 +1871,12 @@ static void demux_avi_send_headers (demux_plugin_t *this_gen) { if (!this->avi->bih->biCompression) this->avi->video_type = BUF_VIDEO_RGB; else + { this->avi->video_type = _x_fourcc_to_buf_video(this->avi->bih->biCompression); + if (!this->avi->video_type) + _x_report_video_fourcc (this->stream->xine, LOG_MODULE, + this->avi->bih->biCompression); + } for(i=0; i < this->avi->n_audio; i++) { this->avi->audio[i]->audio_type = _x_formattag_to_buf_audio (this->avi->audio[i]->wavex->wFormatTag); @@ -1884,10 +1889,10 @@ static void demux_avi_send_headers (demux_plugin_t *this_gen) { } if( !this->avi->audio[i]->audio_type ) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "unknown audio type 0x%x\n", - this->avi->audio[i]->wavex->wFormatTag); this->no_audio = 1; this->avi->audio[i]->audio_type = BUF_AUDIO_UNKNOWN; + _x_report_audio_format_tag (this->stream->xine, LOG_MODULE, + this->avi->audio[i]->wavex->wFormatTag); } else xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "demux_avi: audio type %s (wFormatTag 0x%x)\n", _x_buf_audio_name(this->avi->audio[i]->audio_type), @@ -1899,8 +1904,8 @@ static void demux_avi_send_headers (demux_plugin_t *this_gen) { * however, at least for this case (compressor: xvid biCompression: DIVX), the * xvid fourcc must prevail as it is used by ffmpeg to detect encoder bugs. [MF] */ - if( _x_fourcc_to_buf_video(this->avi->compressor) == BUF_VIDEO_XVID && - _x_fourcc_to_buf_video(this->avi->bih->biCompression) == BUF_VIDEO_MPEG4 ) { + if( this->avi->video_type == BUF_VIDEO_MPEG4 && + _x_fourcc_to_buf_video(this->avi->compressor) == BUF_VIDEO_XVID ) { this->avi->bih->biCompression = this->avi->compressor; this->avi->video_type = BUF_VIDEO_XVID; } @@ -1949,6 +1954,8 @@ static void demux_avi_send_headers (demux_plugin_t *this_gen) { this->avi->compressor = this->avi->bih->biCompression; } else { this->avi->video_type = _x_fourcc_to_buf_video(this->avi->compressor); + if (!this->avi->video_type) + _x_fourcc_to_buf_video(this->avi->bih->biCompression); } _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_FOURCC, diff --git a/src/demuxers/demux_film.c b/src/demuxers/demux_film.c index cc9e90d66..193d8850b 100644 --- a/src/demuxers/demux_film.c +++ b/src/demuxers/demux_film.c @@ -201,7 +201,11 @@ static int open_film_file(demux_film_t *film) { film->video_type = _x_fourcc_to_buf_video(*(uint32_t *)&film_header[i + 8]); if( !film->video_type ) + { film->video_type = BUF_VIDEO_UNKNOWN; + _x_report_video_fourcc (film->stream->xine, LOG_MODULE, + *(uint32_t *)&film_header[i + 8]); + } /* fetch the audio information if the chunk size checks out */ if (chunk_size == 32) { diff --git a/src/demuxers/demux_flac.c b/src/demuxers/demux_flac.c index b4c5427c5..ed974a69c 100644 --- a/src/demuxers/demux_flac.c +++ b/src/demuxers/demux_flac.c @@ -189,7 +189,7 @@ static int open_flac_file(demux_flac_t *flac) { case 4: lprintf ("VORBIS_COMMENT metadata\n"); { - char comments[block_length]; + char comments[block_length + 1]; /* last byte for NUL termination */ char *ptr = comments; uint32_t length, user_comment_list_length, cn; char *comment; @@ -201,18 +201,25 @@ static int open_flac_file(demux_flac_t *flac) { length = _X_LE_32(ptr); ptr += 4 + length; + if (length > block_length - 8) + return 0; /* bad length or too little left in the buffer */ user_comment_list_length = _X_LE_32(ptr); ptr += 4; cn = 0; for (; cn < user_comment_list_length; cn++) { + if (ptr > comments + block_length - 4) + return 0; /* too little left in the buffer */ + length = _X_LE_32(ptr); ptr += 4; + if (length >= block_length || ptr + length > comments + block_length) + return 0; /* bad length */ comment = (char*) ptr; c = comment[length]; - comment[length] = 0; + comment[length] = 0; /* NUL termination */ lprintf ("comment[%02d] = %s\n", cn, comment); @@ -247,8 +254,8 @@ static int open_flac_file(demux_flac_t *flac) { } if ((tracknumber > 0) && (tracktotal > 0)) { - char tn[16]; - snprintf (tn, 16, "%02d/%02d", tracknumber, tracktotal); + char tn[24]; + snprintf (tn, 24, "%02d/%02d", tracknumber, tracktotal); _x_meta_info_set(flac->stream, XINE_META_INFO_TRACK_NUMBER, tn); } else if (tracknumber > 0) { @@ -520,7 +527,9 @@ void *demux_flac_init_plugin (xine_t *xine, void *data) { this->demux_class.open_plugin = open_plugin; this->demux_class.description = N_("Free Lossless Audio Codec (flac) demux plugin"); this->demux_class.identifier = "FLAC"; - this->demux_class.mimetypes = NULL; + this->demux_class.mimetypes = + "audio/x-flac: flac: FLAC Audio;" + "audio/flac: flac: FLAC Audio;"; this->demux_class.extensions = "flac"; this->demux_class.dispose = default_demux_class_dispose; diff --git a/src/demuxers/demux_flv.c b/src/demuxers/demux_flv.c index e6a7e234a..38855c027 100644 --- a/src/demuxers/demux_flv.c +++ b/src/demuxers/demux_flv.c @@ -306,9 +306,12 @@ static int parse_flv_var(demux_flv_t *this, num = _X_BE_32(tmp); tmp += 4; if (key && keylen == 5 && !strncmp(key, "times", 5)) { - free (this->index); - this->index = xine_xcalloc(num, sizeof(flv_index_entry_t)); - this->num_indices = num; + if (!this->index || this->num_indices != num) { + if (this->index) + free(this->index); + this->index = xine_xcalloc(num, sizeof(flv_index_entry_t)); + this->num_indices = num; + } for (num = 0; num < this->num_indices && tmp < end; num++) { if (*tmp++ == FLV_DATA_TYPE_NUMBER) { lprintf(" got number (%f)\n", BE_F64(tmp)); @@ -319,16 +322,20 @@ static int parse_flv_var(demux_flv_t *this, break; } if (key && keylen == 13 && !strncmp(key, "filepositions", 13)) { - if (this->index && this->num_indices == num) { - for (num = 0; num < this->num_indices && tmp < end; num++) { - if (*tmp++ == FLV_DATA_TYPE_NUMBER) { - lprintf(" got number (%f)\n", BE_F64(tmp)); - this->index[num].offset = BE_F64(tmp); - tmp += 8; - } + if (!this->index || this->num_indices != num) { + if (this->index) + free(this->index); + this->index = xine_xcalloc(num, sizeof(flv_index_entry_t)); + this->num_indices = num; + } + for (num = 0; num < this->num_indices && tmp < end; num++) { + if (*tmp++ == FLV_DATA_TYPE_NUMBER) { + lprintf(" got number (%f)\n", BE_F64(tmp)); + this->index[num].offset = BE_F64(tmp); + tmp += 8; } - break; } + break; } while (num-- && tmp < end) { len = parse_flv_var(this, tmp, end-tmp, NULL, 0); @@ -501,9 +508,9 @@ static int read_flv_packet(demux_flv_t *this, int preview) { case FLV_TAG_TYPE_SCRIPT: lprintf(" got script tag...\n"); - parse_flv_script(this, remaining_bytes); - if (preview) { + parse_flv_script(this, remaining_bytes); + /* send init info to decoders using script information as reference */ if (!this->got_audio_header && this->audiocodec) { buf = this->audio_fifo->buffer_pool_alloc(this->audio_fifo); @@ -569,7 +576,9 @@ static int read_flv_packet(demux_flv_t *this, int preview) { } return this->status; - } + } + /* no preview */ + this->input->seek(this->input, remaining_bytes, SEEK_CUR); continue; default: @@ -661,7 +670,7 @@ static void seek_flv_file(demux_flv_t *this, off_t seek_pos, int seek_pts) { } } - if (seek_pos && this->videocodec) { + if (seek_pos && this->videocodec && abs(seek_pts-this->cur_pts) > 300000) { off_t pos, size; pos = this->input->get_current_pos(this->input); @@ -899,4 +908,3 @@ const plugin_info_t xine_plugin_info[] EXPORTED = { { PLUGIN_DEMUX, 27, "flashvideo", XINE_VERSION_CODE, &demux_info_flv, init_plugin }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; - diff --git a/src/demuxers/demux_matroska.c b/src/demuxers/demux_matroska.c index 4a99492ef..ec932aacb 100644 --- a/src/demuxers/demux_matroska.c +++ b/src/demuxers/demux_matroska.c @@ -1303,6 +1303,8 @@ static int parse_track_entry(demux_matroska_t *this, matroska_track_t *track) { _x_bmiheader_le2me(bih); track->buf_type = _x_fourcc_to_buf_video(bih->biCompression); + if (!track->buf_type) + _x_report_video_fourcc (this->stream->xine, LOG_MODULE, bih->biCompression); init_codec = init_codec_video; } else if (!strcmp(track->codec_id, MATROSKA_CODEC_ID_V_UNCOMPRESSED)) { @@ -1413,6 +1415,8 @@ static int parse_track_entry(demux_matroska_t *this, matroska_track_t *track) { _x_waveformatex_le2me(wfh); track->buf_type = _x_formattag_to_buf_audio(wfh->wFormatTag); + if (!track->buf_type) + _x_report_audio_format_tag (this->stream->xine, LOG_MODULE, wfh->wFormatTag); init_codec = init_codec_audio; } else if (!strncmp(track->codec_id, MATROSKA_CODEC_ID_A_AAC, sizeof(MATROSKA_CODEC_ID_A_AAC) - 1)) { @@ -1829,11 +1833,20 @@ static int read_block_data (demux_matroska_t *this, int len) { return 1; } +static int parse_int16(uint8_t *data) { + int value = (int)_X_BE_16(data); + if (value & 1<<15) + { + value -= 1<<16; + } + return value; +} + static int parse_block (demux_matroska_t *this, uint64_t block_size, uint64_t cluster_timecode, uint64_t block_duration, int normpos, int is_key) { matroska_track_t *track; - int64_t track_num; + uint64_t track_num; uint8_t *data; uint8_t flags; int gap, lacing, num_len; @@ -1842,17 +1855,18 @@ static int parse_block (demux_matroska_t *this, uint64_t block_size, int decoder_flags = 0; data = this->block_data; - if (!(num_len = parse_ebml_sint(this, data, &track_num))) + if (!(num_len = parse_ebml_uint(this, data, &track_num))) return 0; data += num_len; - - timecode_diff = (int)_X_BE_16(data); + + /* timecode_diff is signed */ + timecode_diff = parse_int16(data); data += 2; flags = *data; data += 1; - lprintf("track_num: %" PRId64 ", timecode_diff: %d, flags: 0x%x\n", track_num, timecode_diff, flags); + lprintf("track_num: %" PRIu64 ", timecode_diff: %d, flags: 0x%x\n", track_num, timecode_diff, flags); gap = flags & 1; lacing = (flags >> 1) & 0x3; @@ -1860,7 +1874,7 @@ static int parse_block (demux_matroska_t *this, uint64_t block_size, if (!find_track_by_id(this, (int)track_num, &track)) { xprintf(this->stream->xine, XINE_VERBOSITY_LOG, - "demux_matroska: invalid track id: %" PRId64 "\n", track_num); + "demux_matroska: invalid track id: %" PRIu64 "\n", track_num); return 0; } @@ -1969,24 +1983,51 @@ static int parse_block (demux_matroska_t *this, uint64_t block_size, break; case MATROSKA_EBML_LACING: { - int64_t tmp; + uint64_t first_frame_size; lprintf("ebml lacing\n"); /* size of each frame */ - if (!(num_len = parse_ebml_sint(this, data, &tmp))) + if (!(num_len = parse_ebml_uint(this, data, &first_frame_size))) + return 0; + if (num_len > block_size_left) { + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + "demux_matroska: block too small\n"); return 0; + } + if (first_frame_size > INT_MAX) { + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + "demux_matroska: invalid first frame size (%" PRId64 ")\n", + first_frame_size); + return 0; + } data += num_len; block_size_left -= num_len; - frame[0] = (int) tmp; + frame[0] = (int) first_frame_size; lprintf("first frame len: %d\n", frame[0]); block_size_left -= frame[0]; for (i = 1; i < lace_num; i++) { - if (!(num_len = parse_ebml_sint(this, data, &tmp))) + int64_t frame_size_diff; + int64_t frame_size; + + if (!(num_len = parse_ebml_sint(this, data, &frame_size_diff))) return 0; + if (num_len > block_size_left) { + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + "demux_matroska: block too small\n"); + return 0; + } data += num_len; block_size_left -= num_len; - frame[i] = frame[i-1] + tmp; + + frame_size = frame[i-1] + frame_size_diff; + if (frame_size > INT_MAX || frame_size < 0) { + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + "demux_matroska: invalid frame size (%" PRId64 ")\n", + frame_size); + return 0; + } + frame[i] = frame_size; block_size_left -= frame[i]; } diff --git a/src/demuxers/demux_mpgaudio.c b/src/demuxers/demux_mpgaudio.c index 27ee7f56b..6eb4ee622 100644 --- a/src/demuxers/demux_mpgaudio.c +++ b/src/demuxers/demux_mpgaudio.c @@ -33,7 +33,7 @@ #include <string.h> #include <stdlib.h> -#define LOG_MODULE "demux_mpeg_audio" +#define LOG_MODULE "demux_mpgaudio" #define LOG_VERBOSE /* #define LOG @@ -51,8 +51,8 @@ * the second mp3 frame is sent to the decoder */ #define NUM_PREVIEW_BUFFERS 2 +#define NUM_VALID_FRAMES 3 -#define WRAP_THRESHOLD 120000 #define FOURCC_TAG BE_FOURCC #define RIFF_CHECK_BYTES 1024 @@ -64,6 +64,7 @@ /* Xing header stuff */ #define XING_TAG FOURCC_TAG('X', 'i', 'n', 'g') +#define INFO_TAG FOURCC_TAG('I', 'n', 'f', 'o') #define XING_FRAMES_FLAG 0x0001 #define XING_BYTES_FLAG 0x0002 #define XING_TOC_FLAG 0x0004 @@ -76,16 +77,16 @@ /* mp3 frame struct */ typedef struct { /* header */ - double duration; - uint32_t size; /* in bytes */ + double duration; /* in milliseconds */ + uint32_t size; /* in bytes; including padding */ uint32_t bitrate; /* in bit per second */ uint16_t freq; /* in Hz */ - uint8_t layer; - uint8_t version_idx:2; /* 0: mpeg1, 1: mpeg2, 2: mpeg2.5 */ uint8_t lsf_bit:1; uint8_t channel_mode:3; + uint8_t padding:3; /* in bytes */ + uint8_t is_free_bitrate:1; } mpg_audio_frame_t; /* Xing Vbr Header struct */ @@ -124,7 +125,13 @@ typedef struct { int br; /* bitrate in bits/second */ uint32_t blocksize; + /* current mp3 frame */ mpg_audio_frame_t cur_frame; + + /* next mp3 frame, used when the frame size cannot be computed from the + * current frame header */ + mpg_audio_frame_t next_frame; + double cur_time; /* in milliseconds */ off_t mpg_frame_start; /* offset */ @@ -134,7 +141,15 @@ typedef struct { int check_vbr_header; xing_header_t *xing_header; vbri_header_t *vbri_header; - + + int found_next_frame:1; + int free_bitrate_count; + off_t free_bitrate_size; /* use this size if 3 free bitrate frames are encountered */ + uint8_t next_header[4]; + int mpg_version; + int mpg_layer; + int valid_frames; + } demux_mpgaudio_t ; /* demuxer class struct */ @@ -205,14 +220,14 @@ static int parse_frame_header(mpg_audio_frame_t *const frame, const uint8_t *con const uint32_t head = _X_BE_32(buf); const uint16_t frame_sync = head >> 21; - lprintf("header: %08X\n", head); if (frame_sync != 0x7ff) { - lprintf("invalid frame sync\n"); + lprintf("invalid frame sync %08X\n", head); return 0; } + lprintf("header: %08X\n", head); frame_header.mpeg25_bit = (head >> 20) & 0x1; - frame->lsf_bit = (head >> 19) & 0x1; + frame->lsf_bit = (head >> 19) & 0x1; if (!frame_header.mpeg25_bit) { if (frame->lsf_bit) { lprintf("reserved mpeg25 lsf combination\n"); @@ -233,14 +248,14 @@ static int parse_frame_header(mpg_audio_frame_t *const frame, const uint8_t *con } frame_header.bitrate_idx = (head >> 12) & 0xf; - if ((frame_header.bitrate_idx == 0) || (frame_header.bitrate_idx == 15)) { - lprintf("invalid bitrate index\n"); + if (frame_header.bitrate_idx == 15) { + lprintf("invalid bitrate index: %d\n", frame_header.bitrate_idx); return 0; } frame_header.freq_idx = (head >> 10) & 0x3; if (frame_header.freq_idx == 3) { - lprintf("invalid frequence index\n"); + lprintf("invalid frequence index: %d\n", frame_header.freq_idx); return 0; } @@ -273,19 +288,27 @@ static int parse_frame_header(mpg_audio_frame_t *const frame, const uint8_t *con const uint16_t samples = mp3_samples[frame->version_idx][frame->layer - 1]; frame->bitrate = mp3_bitrates[frame->version_idx][frame->layer - 1][frame_header.bitrate_idx] * 1000; frame->freq = mp3_freqs[frame->version_idx][frame_header.freq_idx]; - - frame->size = samples * (frame->bitrate / 8); - frame->size /= frame->freq; - /* Padding: only if padding_bit is set; 4 bytes for Layer 1 and 1 byte for others */ - frame->size += ( frame_header.padding_bit ? ( frame->layer == 1 ? 4 : 1 ) : 0 ); - frame->duration = 1000.0f * (double)samples / (double)frame->freq; + frame->padding = ( frame_header.padding_bit ? ( frame->layer == 1 ? 4 : 1 ) : 0 ); + frame->channel_mode = frame_header.channel_mode; + + if (frame->bitrate > 0) { + frame->size = samples * (frame->bitrate / 8); + frame->size /= frame->freq; + /* Padding: only if padding_bit is set; 4 bytes for Layer 1 and 1 byte for others */ + frame->size += frame->padding; + } else { + /* Free bitrate frame, the size of the frame cannot be computed from the header. */ + frame->is_free_bitrate = 1; + frame->size = 0; + } } - lprintf("mpeg %d, layer %d\n", frame->version_idx + 1, frame->layer); - lprintf("bitrate: %d bps, samplerate: %d Hz\n", frame->bitrate, frame->freq); + lprintf("mpeg %d, layer %d, channel_mode: %d\n", frame->version_idx + 1, + frame->layer, frame->channel_mode); + lprintf("bitrate: %d bps, output freq: %d Hz\n", frame->bitrate, frame->freq); lprintf("length: %d bytes, %f ms\n", frame->size, frame->duration); - lprintf("padding: %d bytes\n", ( frame_header.padding_bit ? ( frame->layer == 1 ? 4 : 1 ) : 0 )); + lprintf("padding: %d bytes\n", frame->padding); return 1; } @@ -295,16 +318,8 @@ static int parse_frame_header(mpg_audio_frame_t *const frame, const uint8_t *con */ static xing_header_t* parse_xing_header(mpg_audio_frame_t *frame, uint8_t *buf, int bufsize) { - -#ifdef LOG - int i; -#endif uint8_t *ptr = buf; - xing_header_t *xing; - - xing = xine_xmalloc (sizeof (xing_header_t)); - if (!xing) - return NULL; + xing_header_t *xing = NULL; /* offset of the Xing header */ if (frame->lsf_bit) { @@ -319,52 +334,87 @@ static xing_header_t* parse_xing_header(mpg_audio_frame_t *frame, ptr += (9 + 4); } - if (ptr >= (buf + bufsize - 4)) return 0; + if (ptr >= (buf + bufsize - 4)) goto exit_error; lprintf("checking %08X\n", *ptr); + if (_X_BE_32(ptr) == XING_TAG) { - lprintf("Xing header found\n"); + int has_frames_flag = 0; + int has_bytes_flag = 0; + + xing = xine_xmalloc (sizeof (xing_header_t)); + if (!xing) + goto exit_error; + + lprintf("found Xing header\n"); ptr += 4; - if (ptr >= (buf + bufsize - 4)) return 0; + if (ptr >= (buf + bufsize - 4)) goto exit_error; xing->flags = _X_BE_32(ptr); ptr += 4; if (xing->flags & XING_FRAMES_FLAG) { - if (ptr >= (buf + bufsize - 4)) return 0; + if (ptr >= (buf + bufsize - 4)) goto exit_error; xing->stream_frames = _X_BE_32(ptr); ptr += 4; lprintf("stream frames: %d\n", xing->stream_frames); + has_frames_flag = 1; } if (xing->flags & XING_BYTES_FLAG) { - if (ptr >= (buf + bufsize - 4)) return 0; + if (ptr >= (buf + bufsize - 4)) goto exit_error; xing->stream_size = _X_BE_32(ptr); ptr += 4; lprintf("stream size: %d\n", xing->stream_size); + has_bytes_flag = 1; } + + /* check if it's a useful Xing header */ + if (!has_frames_flag || !has_bytes_flag) { + lprintf("Stupid Xing tag, cannot do anything with it !\n"); + goto exit_error; + } + if (xing->flags & XING_TOC_FLAG) { + int i; + lprintf("toc found\n"); - if (ptr >= (buf + bufsize - XING_TOC_LENGTH)) return 0; + if (ptr >= (buf + bufsize - XING_TOC_LENGTH)) goto exit_error; memcpy(xing->toc, ptr, XING_TOC_LENGTH); #ifdef LOG for (i = 0; i < XING_TOC_LENGTH; i++) { - lprintf("%d ", xing->toc[i]); + printf("%d ", xing->toc[i]); } - lprintf("\n"); + printf("\n"); #endif + /* check the table validity + * - MUST start with 0 + * - values MUST increase + */ + if (xing->toc[0] != 0) { + lprintf("invalid Xing toc\n"); + goto exit_error; + } + for (i = 1; i < XING_TOC_LENGTH; i++) { + if (xing->toc[i] < xing->toc[i-1]) { + lprintf("invalid Xing toc\n"); + goto exit_error; + } + } ptr += XING_TOC_LENGTH; } xing->vbr_scale = -1; if (xing->flags & XING_VBR_SCALE_FLAG) { - if (ptr >= (buf + bufsize - 4)) return 0; + if (ptr >= (buf + bufsize - 4)) goto exit_error; xing->vbr_scale = _X_BE_32(ptr); lprintf("vbr_scale: %d\n", xing->vbr_scale); } - - return xing; } else { lprintf("Xing header not found\n"); + } + return xing; + +exit_error: + lprintf("Xing header parse error\n"); free(xing); return NULL; } -} /* * Parse a Vbri header @@ -386,7 +436,7 @@ static vbri_header_t* parse_vbri_header(mpg_audio_frame_t *frame, if ((ptr + 4) >= (buf + bufsize)) return 0; lprintf("Checking %08X\n", *ptr); if (_X_BE_32(ptr) == VBRI_TAG) { - lprintf("Vbri header found\n"); + lprintf("found Vbri header\n"); ptr += 4; if ((ptr + 22) >= (buf + bufsize)) return 0; @@ -450,6 +500,7 @@ static vbri_header_t* parse_vbri_header(mpg_audio_frame_t *frame, } } + /* * Parse a mp3 frame paylod * return 1 on success, 0 on error @@ -460,43 +511,97 @@ static int parse_frame_payload(demux_mpgaudio_t *this, buf_element_t *buf; off_t frame_pos, len; uint64_t pts = 0; + int payload_size = 0; frame_pos = this->input->get_current_pos(this->input) - 4; - lprintf("frame_pos = %"PRId64"\n", frame_pos); + lprintf("frame_pos = %"PRId64", header: %08X\n", frame_pos, _X_BE_32(frame_header)); buf = this->audio_fifo->buffer_pool_alloc(this->audio_fifo); if (this->cur_frame.size > buf->max_size) { xprintf(this->stream->xine, XINE_VERBOSITY_LOG, - "demux_mpgaudio: frame size is greater than fifo buffer size\n"); + LOG_MODULE ": frame size is greater than fifo buffer size\n"); buf->free_buffer(buf); return 0; } - - /* the decoder needs the frame header */ - memcpy(buf->mem, frame_header, 4); - len = this->input->read(this->input, buf->mem + 4, this->cur_frame.size - 4); - if (len != (this->cur_frame.size - 4)) { - buf->free_buffer(buf); - return 0; + memcpy(buf->content, frame_header, 4); + + /* compute the payload size */ + if (this->cur_frame.size > 0) { + payload_size = this->cur_frame.size - 4; + this->free_bitrate_count = 0; + } else if (this->free_bitrate_count >= NUM_VALID_FRAMES) { + payload_size = this->free_bitrate_size + this->cur_frame.padding - 4; + this->cur_frame.size = payload_size + 4; + } else { + this->free_bitrate_count++; + payload_size = 0; + } + + /* Read the payload data. */ + if (payload_size > 0) { + off_t len; + + /* If we know the payload size, it's easy */ + this->found_next_frame = 0; + len = this->input->read(this->input, buf->content + 4, payload_size); + if (len != payload_size) { + buf->free_buffer(buf); + return 0; + } + } else { + /* Search for the beginning of the next frame and deduce the size of the + * current frame from the position of the next one. */ + int payload_size = 0; + int max_size = buf->max_size - 4; + + while (payload_size < max_size) { + len = this->input->read(this->input, &buf->content[4 + payload_size], 1); + if (len != 1) { + lprintf("EOF\n"); + buf->free_buffer(buf); + return 0; + } + payload_size += len; + + if (parse_frame_header(&this->next_frame, &buf->content[payload_size])) { + lprintf("found next frame header\n"); + + if (this->free_bitrate_size == 0) { + this->free_bitrate_size = payload_size - this->cur_frame.padding; + } + + /* don't read the frame header twice */ + this->found_next_frame = 1; + memcpy(&this->next_header[0], &buf->content[payload_size], 4); + payload_size -= 4; + break; + } + } + this->cur_frame.size = payload_size + 4; + this->cur_frame.bitrate = 8000 * this->cur_frame.size / this->cur_frame.duration; + lprintf("free bitrate: bitrate: %d, frame size: %d\n", this->br, this->cur_frame.size); } if (this->check_vbr_header) { this->check_vbr_header = 0; this->mpg_frame_start = frame_pos; - this->xing_header = parse_xing_header(&this->cur_frame, buf->mem, this->cur_frame.size); + this->xing_header = parse_xing_header(&this->cur_frame, buf->content, this->cur_frame.size); if (this->xing_header) { buf->free_buffer(buf); + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + LOG_MODULE ": found Xing header at offset %"PRId64"\n", frame_pos); return 1; } - this->vbri_header = parse_vbri_header(&this->cur_frame, buf->mem, this->cur_frame.size); + this->vbri_header = parse_vbri_header(&this->cur_frame, buf->content, this->cur_frame.size); if (this->vbri_header) { buf->free_buffer(buf); + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + LOG_MODULE ": found Vbri header at offset %"PRId64"\n", frame_pos); return 1; } } - pts = (int64_t)(this->cur_time * 90.0f); @@ -505,14 +610,13 @@ static int parse_frame_payload(demux_mpgaudio_t *this, buf->extra_info->input_time = this->cur_time; buf->pts = pts; - buf->size = len + 4; - buf->content = buf->mem; + buf->size = this->cur_frame.size; buf->type = BUF_AUDIO_MPEG; buf->decoder_info[0] = 1; buf->decoder_flags = decoder_flags|BUF_FLAG_FRAME_END; + lprintf("send buffer: size=%d, pts=%"PRId64"\n", buf->size, pts); this->audio_fifo->put(this->audio_fifo, buf); - lprintf("send buffer: pts=%"PRId64"\n", pts); this->cur_time += this->cur_frame.duration; return 1; } @@ -522,11 +626,12 @@ static int parse_frame_payload(demux_mpgaudio_t *this, * 32-bit MP3 frame header. * return 1 if found, 0 if not found */ -static int sniff_buffer_looks_like_mp3 (uint8_t *buf, int buflen) +static int sniff_buffer_looks_like_mp3 (uint8_t *buf, int buflen, int *version, int *layer) { int offset; mpg_audio_frame_t frame; + *version = *layer = 0; if (buf == NULL) return 0; @@ -535,20 +640,21 @@ static int sniff_buffer_looks_like_mp3 (uint8_t *buf, int buflen) if (parse_frame_header(&frame, buf + offset)) { size_t size = frame.size; - /* Since one frame is available, is there another frame - * just to be sure this is more likely to be a real MP3 - * buffer? */ - offset += size; - - if (offset + 4 >= buflen) { - return 0; - } + if (size > 0) { + /* Since one frame is available, is there another frame + * just to be sure this is more likely to be a real MP3 + * buffer? */ + if (offset + size + 4 >= buflen) { + return 0; + } - if (parse_frame_header(&frame, buf + offset)) { - lprintf("mpeg audio frame detected\n"); - return 1; + if (parse_frame_header(&frame, buf + offset + size)) { + *version = frame.version_idx + 1; + *layer = frame.layer; + lprintf("frame detected, mpeg %d layer %d\n", *version, *layer); + return 1; + } } - break; } } return 0; @@ -576,40 +682,51 @@ static int read_frame_header(demux_mpgaudio_t *this, uint8_t *header_buf, int by * Parse next mp3 frame */ static int demux_mpgaudio_next (demux_mpgaudio_t *this, int decoder_flags, int send_header) { - uint8_t header_buf[4]; - int bytes = 4; - - for (;;) { - - if (read_frame_header(this, header_buf, bytes)) { - - if (parse_frame_header(&this->cur_frame, header_buf)) { - - /* send header buffer */ - if ( send_header ) { - buf_element_t *buf; - - buf = this->audio_fifo->buffer_pool_alloc(this->audio_fifo); - - buf->type = BUF_AUDIO_MPEG; - buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END; - - buf->decoder_info[0] = 0; - buf->decoder_info[1] = this->cur_frame.freq; - buf->decoder_info[2] = 0; /* bits_per_sample */ - - /* Only for channel_mode == 3 (mono) there is one channel, for any other case, there are 2 */ - buf->decoder_info[3] = ( this->cur_frame.channel_mode == 3 ) ? 1 : 2; - - buf->size = 0; /* No extra header data */ - - this->audio_fifo->put(this->audio_fifo, buf); - } - - return parse_frame_payload(this, header_buf, decoder_flags); - - } else if ( id3v2_istag(_X_ME_32(header_buf)) ) { - if (!id3v2_parse_tag(this->input, this->stream, _X_ME_32(header_buf))) { + uint8_t buffer[4]; + uint8_t *header = buffer; + + if (this->found_next_frame) { + lprintf("skip header reading\n"); + header = this->next_header; + memcpy(&this->cur_frame, &this->next_frame, sizeof(mpg_audio_frame_t)); + } else { + int bytes = 4; + int loose_sync = 0; + + for (;;) { + if (!read_frame_header(this, header, bytes)) + return 0; + if (parse_frame_header(&this->cur_frame, header)) { + lprintf("frame found\n"); + + /* additionnal checks */ + if ((this->mpg_version == (this->cur_frame.version_idx + 1)) && + (this->mpg_layer == this->cur_frame.layer)) { + this->valid_frames++; + break; + } else { + if (this->valid_frames >= NUM_VALID_FRAMES) { + lprintf("invalid frame. expected mpeg %d, layer %d\n", this->mpg_version, this->mpg_layer); + } else { + this->mpg_version = this->cur_frame.version_idx + 1; + this->mpg_layer = this->cur_frame.layer; + this->valid_frames = 0; + break; + } + } + } + + if (!loose_sync) { + off_t frame_pos = this->input->get_current_pos(this->input) - 4; + loose_sync = 1; + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + LOG_MODULE ": loose mp3 sync at offset %"PRId64"\n", frame_pos); + } + /* the stream is broken, don't keep info about previous frames */ + this->free_bitrate_size = 0; + + if ( id3v2_istag(_X_ME_32(header)) ) { + if (!id3v2_parse_tag(this->input, this->stream, _X_ME_32(header))) { xprintf(this->stream->xine, XINE_VERBOSITY_LOG, LOG_MODULE ": ID3V2 tag parsing error\n"); bytes = 1; /* resync */ @@ -620,12 +737,31 @@ static int demux_mpgaudio_next (demux_mpgaudio_t *this, int decoder_flags, int s /* skip */ bytes = 1; } - - } else { - lprintf("read error\n"); - return 0; } } + + /* send header buffer */ + if ( send_header ) { + buf_element_t *buf; + + buf = this->audio_fifo->buffer_pool_alloc(this->audio_fifo); + + buf->type = BUF_AUDIO_MPEG; + buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END; + + buf->decoder_info[0] = 0; + buf->decoder_info[1] = this->cur_frame.freq; + buf->decoder_info[2] = 0; /* bits_per_sample */ + + /* Only for channel_mode == 3 (mono) there is one channel, for any other case, there are 2 */ + buf->decoder_info[3] = ( this->cur_frame.channel_mode == 3 ) ? 1 : 2; + + buf->size = 0; /* No extra header data */ + + this->audio_fifo->put(this->audio_fifo, buf); + } + + return parse_frame_payload(this, header, decoder_flags); } static int demux_mpgaudio_send_chunk (demux_plugin_t *this_gen) { @@ -672,12 +808,13 @@ static int demux_mpgaudio_read_head(input_plugin_t *input, uint8_t *buf) { * mp3 stream detection * return 1 if detected, 0 otherwise */ -static int detect_mpgaudio_file(input_plugin_t *input) { - mpg_audio_frame_t frame; +static int detect_mpgaudio_file(input_plugin_t *input, + int *version, int *layer) { uint8_t buf[MAX_PREVIEW_SIZE]; int preview_len; uint32_t head; + *version = *layer = 0; preview_len = demux_mpgaudio_read_head(input, buf); if (preview_len < 4) return 0; @@ -701,15 +838,15 @@ static int detect_mpgaudio_file(input_plugin_t *input) { lprintf("cannot read mp3 frame header\n"); return 0; } - if (!parse_frame_header(&frame, &buf[10 + tag_size])) { - lprintf ("invalid mp3 frame header\n"); + if (!sniff_buffer_looks_like_mp3(&buf[10 + tag_size], preview_len - 10 - tag_size, version, layer)) { + lprintf ("sniff_buffer_looks_like_mp3 failed\n"); return 0; } else { lprintf ("a valid mp3 frame follows the id3v2 tag\n"); } } else if (head == MPEG_MARKER) { return 0; - } else if (!sniff_buffer_looks_like_mp3(buf, preview_len)) { + } else if (!sniff_buffer_looks_like_mp3(buf, preview_len, version, layer)) { lprintf ("sniff_buffer_looks_like_mp3 failed\n"); return 0; } @@ -748,11 +885,12 @@ static void demux_mpgaudio_send_headers (demux_plugin_t *this_gen) { */ this->check_vbr_header = 1; for (i = 0; i < NUM_PREVIEW_BUFFERS; i++) { + lprintf("preview buffer number %d / %d\n", i + 1, NUM_PREVIEW_BUFFERS); if (!demux_mpgaudio_next (this, BUF_FLAG_PREVIEW, i == 0)) { break; } } - + if (this->xing_header) { xing_header_t *xing = this->xing_header; @@ -763,7 +901,7 @@ static void demux_mpgaudio_send_headers (demux_plugin_t *this_gen) { if (this->stream_length) { this->br = ((uint64_t)xing->stream_size * 8 * 1000) / this->stream_length; } - + } else if (this->vbri_header) { vbri_header_t *vbri = this->vbri_header; @@ -806,7 +944,7 @@ static void demux_mpgaudio_send_headers (demux_plugin_t *this_gen) { { char scratch_buf[256]; static const char mpeg_ver[3][4] = {"1", "2", "2.5"}; - + snprintf(scratch_buf, 256, "MPEG %s Layer %1d%s", mpeg_ver[this->cur_frame.version_idx], this->cur_frame.layer, (this->xing_header)? " VBR" : " CBR" ); @@ -919,7 +1057,7 @@ static int demux_mpgaudio_seek (demux_plugin_t *this_gen, if (this->stream_length > 0) { if (this->xing_header && - (this->xing_header->flags & (XING_TOC_FLAG | XING_BYTES_FLAG))) { + (this->xing_header->flags & XING_TOC_FLAG)) { seek_pos += xing_get_seek_point(this->xing_header, start_time, this->stream_length); lprintf("time seek: xing: time=%d, pos=%"PRId64"\n", start_time, seek_pos); } else if (this->vbri_header) { @@ -934,7 +1072,8 @@ static int demux_mpgaudio_seek (demux_plugin_t *this_gen, /* assume seeking is always perfect... */ this->cur_time = start_time; this->input->seek (this->input, seek_pos, SEEK_SET); - + this->found_next_frame = 0; + if (playing) { _x_demux_flush_engine(this->stream); } @@ -969,13 +1108,15 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str input_plugin_t *input) { demux_mpgaudio_t *this; + int version = 0; + int layer = 0; lprintf("trying to open %s...\n", input->get_mrl(input)); switch (stream->content_detection_method) { case METHOD_BY_CONTENT: { - if (!detect_mpgaudio_file(input)) + if (!detect_mpgaudio_file(input, &version, &layer)) return NULL; } break; @@ -987,7 +1128,7 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str default: return NULL; } - + this = xine_xmalloc (sizeof (demux_mpgaudio_t)); this->demux_plugin.send_headers = demux_mpgaudio_send_headers; @@ -999,12 +1140,17 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str this->demux_plugin.get_capabilities = demux_mpgaudio_get_capabilities; this->demux_plugin.get_optional_data = demux_mpgaudio_get_optional_data; this->demux_plugin.demux_class = class_gen; - - this->input = input; - this->audio_fifo = stream->audio_fifo; - this->status = DEMUX_FINISHED; - this->stream = stream; - + + this->input = input; + this->audio_fifo = stream->audio_fifo; + this->status = DEMUX_FINISHED; + this->stream = stream; + + this->mpg_version = version; + this->mpg_layer = layer; + if (version || layer) { + this->valid_frames = NUM_VALID_FRAMES; + } return &this->demux_plugin; } diff --git a/src/demuxers/demux_nsv.c b/src/demuxers/demux_nsv.c index 74f98c7cd..43b1fbc88 100644 --- a/src/demuxers/demux_nsv.c +++ b/src/demuxers/demux_nsv.c @@ -305,13 +305,21 @@ static int open_nsv_file(demux_nsv_t *this) { if (_X_BE_32(&preview[4]) == NONE_TAG) this->video_type = 0; else + { this->video_type = _x_fourcc_to_buf_video(this->video_fourcc); + if (!this->video_type) + _x_report_video_fourcc (this->stream->xine, LOG_MODULE, this->video_fourcc); + } this->audio_fourcc = _X_ME_32(&preview[8]); if (_X_BE_32(&preview[8]) == NONE_TAG) this->audio_type = 0; else + { this->audio_type = _x_formattag_to_buf_audio(this->audio_fourcc); + if (!this->audio_type) + _x_report_audio_format_tag (this->stream->xine, LOG_MODULE, this->audio_fourcc); + } this->bih.biSize = sizeof(this->bih); this->bih.biWidth = _X_LE_16(&preview[12]); diff --git a/src/demuxers/demux_qt.c b/src/demuxers/demux_qt.c index 6b2aa5eea..ecd2c319a 100644 --- a/src/demuxers/demux_qt.c +++ b/src/demuxers/demux_qt.c @@ -2628,7 +2628,11 @@ static void demux_qt_send_headers(demux_plugin_t *this_gen) { if( !video_trak->properties->video.codec_buftype && video_trak->properties->video.codec_fourcc ) + { video_trak->properties->video.codec_buftype = BUF_VIDEO_UNKNOWN; + _x_report_video_fourcc (this->stream->xine, LOG_MODULE, + video_trak->properties->video.codec_fourcc); + } _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 1); _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, @@ -2670,7 +2674,11 @@ static void demux_qt_send_headers(demux_plugin_t *this_gen) { if( !audio_trak->properties->audio.codec_buftype && audio_trak->properties->audio.codec_fourcc ) + { audio_trak->properties->audio.codec_buftype = BUF_AUDIO_UNKNOWN; + _x_report_audio_format_tag (this->stream->xine, LOG_MODULE, + audio_trak->properties->audio.codec_fourcc); + } _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, 1); _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_CHANNELS, diff --git a/src/demuxers/demux_real.c b/src/demuxers/demux_real.c index 21308bd45..41c6fb4a2 100644 --- a/src/demuxers/demux_real.c +++ b/src/demuxers/demux_real.c @@ -459,6 +459,9 @@ static void real_parse_headers (demux_real_t *this) { this->num_audio_streams++; + if (!this->audio_streams[this->num_audio_streams].buf_type) + _x_report_audio_format_tag (this->stream->xine, LOG_MODULE, fourcc); + } else if(_X_BE_32(mdpr->type_specific_data + 4) == VIDO_TAG) { if(this->num_video_streams == MAX_VIDEO_STREAMS) { @@ -479,6 +482,9 @@ static void real_parse_headers (demux_real_t *this) { this->num_video_streams++; + if (!this->video_streams[this->num_video_streams].buf_type) + _x_report_video_fourcc (this->stream->xine, LOG_MODULE, fourcc); + } else { lprintf("unrecognised type specific data\n"); @@ -800,12 +806,22 @@ static int demux_real_parse_references( demux_real_t *this) { if (!strncmp(buf,"http://",7)) { - for (i = 0; buf[i] && !isspace(buf[i]); ++i) - /**/; - buf[i] = 0; - lprintf("reference [%s] found\n", buf); - - _x_demux_send_mrl_reference (this->stream, 0, buf, NULL, 0, 0); + i = 0; + while (buf[i]) + { + j = i; + while (buf[i] && !isspace(buf[i])) + ++i; /* skip non-space */ + len = buf[i]; + buf[i] = 0; + if (strncmp (buf + j, "http://", 7) || (i - j) < 8) + break; /* stop at the first non-http reference */ + lprintf("reference [%s] found\n", buf + j); + _x_demux_send_mrl_reference (this->stream, 0, buf + j, NULL, 0, 0); + buf[i] = (char) len; + while (buf[i] && isspace(buf[i])) + ++i; /* skip spaces */ + } } else for (i = 0; i < buf_used; ++i) { diff --git a/src/demuxers/demux_smjpeg.c b/src/demuxers/demux_smjpeg.c index 10cdf8120..d9b436032 100644 --- a/src/demuxers/demux_smjpeg.c +++ b/src/demuxers/demux_smjpeg.c @@ -147,6 +147,8 @@ static int open_smjpeg_file(demux_smjpeg_t *this) { this->bih.biHeight = _X_BE_16(&header_chunk[10]); this->bih.biCompression = *(uint32_t *)&header_chunk[12]; this->video_type = _x_fourcc_to_buf_video(this->bih.biCompression); + if (!this->video_type) + _x_report_video_fourcc (this->stream->xine, LOG_MODULE, this->bih.biCompression); break; case _SND_TAG: @@ -166,6 +168,8 @@ static int open_smjpeg_file(demux_smjpeg_t *this) { } else { audio_codec = *(uint32_t *)&header_chunk[8]; this->audio_type = _x_formattag_to_buf_audio(audio_codec); + if (!this->audio_type) + _x_report_audio_format_tag (this->stream->xine, LOG_MODULE, audio_codec); } break; diff --git a/src/demuxers/demux_ts.c b/src/demuxers/demux_ts.c index 9de28aacc..5d85a5597 100644 --- a/src/demuxers/demux_ts.c +++ b/src/demuxers/demux_ts.c @@ -1175,6 +1175,15 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num return; } + if (!section_length) { + free (this->pmt[program_count]); + this->pmt[program_count] = NULL; +#ifdef TS_PMT_LOG + printf ("ts_demux: eek, zero-length section?\n"); +#endif + return; + } + #ifdef TS_PMT_LOG printf ("ts_demux: have all TS packets for the PMT section\n"); #endif diff --git a/src/demuxers/ebml.c b/src/demuxers/ebml.c index 772b848eb..41a91371e 100644 --- a/src/demuxers/ebml.c +++ b/src/demuxers/ebml.c @@ -234,6 +234,7 @@ int ebml_read_uint(ebml_parser_t *ebml, ebml_elem_t *elem, uint64_t *num) { return 1; } +#if 0 int ebml_read_sint (ebml_parser_t *ebml, ebml_elem_t *elem, int64_t *num) { uint8_t data[8]; uint64_t size = elem->len; @@ -260,6 +261,7 @@ int ebml_read_sint (ebml_parser_t *ebml, ebml_elem_t *elem, int64_t *num) { return 1; } +#endif int ebml_read_float (ebml_parser_t *ebml, ebml_elem_t *elem, double *num) { @@ -304,6 +306,7 @@ int ebml_read_ascii(ebml_parser_t *ebml, ebml_elem_t *elem, char *str) { return 1; } +#if 0 int ebml_read_utf8 (ebml_parser_t *ebml, ebml_elem_t *elem, char *str) { return ebml_read_ascii (ebml, elem, str); } @@ -311,6 +314,7 @@ int ebml_read_utf8 (ebml_parser_t *ebml, ebml_elem_t *elem, char *str) { int ebml_read_date (ebml_parser_t *ebml, ebml_elem_t *elem, int64_t *date) { return ebml_read_sint (ebml, elem, date); } +#endif int ebml_read_master (ebml_parser_t *ebml, ebml_elem_t *elem) { ebml_elem_t *top_elem; diff --git a/src/demuxers/ebml.h b/src/demuxers/ebml.h index 7ebd68da2..31d825e35 100644 --- a/src/demuxers/ebml.h +++ b/src/demuxers/ebml.h @@ -83,15 +83,19 @@ int ebml_skip(ebml_parser_t *ebml, ebml_elem_t *elem); /* EBML types */ int ebml_read_uint(ebml_parser_t *ebml, ebml_elem_t *elem, uint64_t *val); +#if 0 int ebml_read_sint(ebml_parser_t *ebml, ebml_elem_t *elem, int64_t *val); +#endif int ebml_read_float(ebml_parser_t *ebml, ebml_elem_t *elem, double *val); int ebml_read_ascii(ebml_parser_t *ebml, ebml_elem_t *elem, char *str); +#if 0 int ebml_read_utf8(ebml_parser_t *ebml, ebml_elem_t *elem, char *str); int ebml_read_date(ebml_parser_t *ebml, ebml_elem_t *elem, int64_t *date); +#endif int ebml_read_master(ebml_parser_t *ebml, ebml_elem_t *elem); diff --git a/src/demuxers/id3.c b/src/demuxers/id3.c index b9bb75744..71cb5e743 100644 --- a/src/demuxers/id3.c +++ b/src/demuxers/id3.c @@ -341,21 +341,21 @@ int id3v22_parse_tag(input_plugin_t *input, if (tag_header.flags & ID3V22_ZERO_FLAG) { /* invalid flags */ xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: invalid header flags (%02x)\n", tag_header.flags); + LOG_MODULE ": invalid header flags (%02x)\n", tag_header.flags); input->seek (input, tag_header.size - pos, SEEK_CUR); return 0; } if (tag_header.flags & ID3V22_COMPRESS_FLAG) { /* compressed tag: not supported */ xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: compressed tags are not supported\n"); + LOG_MODULE ": compressed tags are not supported\n"); input->seek (input, tag_header.size - pos, SEEK_CUR); return 0; } if (tag_header.flags & ID3V22_UNSYNCH_FLAG) { /* unsynchronized tag: not supported */ xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: unsynchronized tags are not supported\n"); + LOG_MODULE ": unsynchronized tags are not supported\n"); input->seek (input, tag_header.size - pos, SEEK_CUR); return 0; } @@ -367,11 +367,11 @@ int id3v22_parse_tag(input_plugin_t *input, if ((pos + tag_frame_header.size) <= tag_header.size) { if (!id3v22_interp_frame(input, stream, &tag_frame_header)) { xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: invalid frame content\n"); + LOG_MODULE ": invalid frame content\n"); } } else { xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: invalid frame header\n"); + LOG_MODULE ": invalid frame header\n"); input->seek (input, tag_header.size - pos, SEEK_CUR); return 1; } @@ -383,13 +383,13 @@ int id3v22_parse_tag(input_plugin_t *input, } } else { xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: id3v2_parse_frame_header problem\n"); + LOG_MODULE ": id3v2_parse_frame_header problem\n"); return 0; } } return 1; } else { - xprintf(stream->xine, XINE_VERBOSITY_DEBUG, "id3: id3v2_parse_header problem\n"); + xprintf(stream->xine, XINE_VERBOSITY_DEBUG, LOG_MODULE ": id3v2_parse_header problem\n"); return 0; } } @@ -527,14 +527,14 @@ int id3v23_parse_tag(input_plugin_t *input, if (tag_header.flags & ID3V23_ZERO_FLAG) { /* invalid flags */ xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: invalid header flags (%02x)\n", tag_header.flags); + LOG_MODULE ": invalid header flags (%02x)\n", tag_header.flags); input->seek (input, tag_header.size - pos, SEEK_CUR); return 0; } if (tag_header.flags & ID3V23_UNSYNCH_FLAG) { /* unsynchronized tag: not supported */ xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: unsynchronized tags are not supported\n"); + LOG_MODULE ": unsynchronized tags are not supported\n"); input->seek (input, tag_header.size - pos, SEEK_CUR); return 0; } @@ -543,6 +543,7 @@ int id3v23_parse_tag(input_plugin_t *input, if (!id3v23_parse_frame_ext_header(input, &tag_frame_ext_header)) { return 0; } + pos += tag_frame_ext_header.size; } /* frame parsing */ while ((pos + ID3V23_FRAME_HEADER_SIZE) <= tag_header.size) { @@ -552,29 +553,30 @@ int id3v23_parse_tag(input_plugin_t *input, if ((pos + tag_frame_header.size) <= tag_header.size) { if (!id3v23_interp_frame(input, stream, &tag_frame_header)) { xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: invalid frame content\n"); + LOG_MODULE ": invalid frame content\n"); } } else { xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: invalid frame header\n"); + LOG_MODULE ": invalid frame header\n"); input->seek (input, tag_header.size - pos, SEEK_CUR); return 1; } pos += tag_frame_header.size; } else { /* end of frames, the rest is padding */ - input->seek (input, tag_header.size - pos, SEEK_CUR); + lprintf("skipping padding %d bytes\n", tag_header.size - pos); + input->seek (input, tag_header.size - pos, SEEK_CUR); return 1; } } else { xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: id3v2_parse_frame_header problem\n"); + LOG_MODULE ": id3v2_parse_frame_header problem\n"); return 0; } } return 1; } else { - xprintf(stream->xine, XINE_VERBOSITY_DEBUG, "id3v23: id3v2_parse_header problem\n"); + xprintf(stream->xine, XINE_VERBOSITY_DEBUG, LOG_MODULE ": id3v2_parse_header problem\n"); return 0; } } @@ -770,7 +772,7 @@ int id3v24_parse_tag(input_plugin_t *input, if (tag_header.flags & ID3V24_ZERO_FLAG) { /* invalid flags */ xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: invalid header flags (%02x)\n", tag_header.flags); + LOG_MODULE ": invalid header flags (%02x)\n", tag_header.flags); input->seek (input, tag_header.size - pos, SEEK_CUR); return 0; } @@ -785,6 +787,7 @@ int id3v24_parse_tag(input_plugin_t *input, if (!id3v24_parse_ext_header(input, &tag_frame_ext_header)) { return 0; } + pos += tag_frame_ext_header.size; } /* frame parsing */ while ((pos + ID3V24_FRAME_HEADER_SIZE) <= tag_header.size) { @@ -794,11 +797,11 @@ int id3v24_parse_tag(input_plugin_t *input, if ((pos + tag_frame_header.size) <= tag_header.size) { if (!id3v24_interp_frame(input, stream, &tag_frame_header)) { xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: invalid frame content\n"); + LOG_MODULE ": invalid frame content\n"); } } else { xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: invalid frame header\n"); + LOG_MODULE ": invalid frame header\n"); input->seek (input, tag_header.size - pos, SEEK_CUR); return 1; } @@ -810,7 +813,7 @@ int id3v24_parse_tag(input_plugin_t *input, } } else { xprintf(stream->xine, XINE_VERBOSITY_DEBUG, - "id3: id3v2_parse_frame_header problem\n"); + LOG_MODULE ": id3v2_parse_frame_header problem\n"); return 0; } } @@ -820,7 +823,7 @@ int id3v24_parse_tag(input_plugin_t *input, } return 1; } else { - xprintf(stream->xine, XINE_VERBOSITY_DEBUG, "id3v23: id3v2_parse_header problem\n"); + xprintf(stream->xine, XINE_VERBOSITY_DEBUG, LOG_MODULE ": id3v2_parse_header problem\n"); return 0; } } @@ -832,19 +835,19 @@ int id3v2_parse_tag(input_plugin_t *input, switch(id3_signature) { case ID3V22_TAG: - xprintf(stream->xine, XINE_VERBOSITY_LOG, "ID3V2.2 tag\n"); + xprintf(stream->xine, XINE_VERBOSITY_LOG, LOG_MODULE ": ID3V2.2 tag\n"); return id3v22_parse_tag(input, stream, id3_signature); case ID3V23_TAG: - xprintf(stream->xine, XINE_VERBOSITY_LOG, "ID3V2.3 tag\n"); + xprintf(stream->xine, XINE_VERBOSITY_LOG, LOG_MODULE ": ID3V2.3 tag\n"); return id3v23_parse_tag(input, stream, id3_signature); case ID3V24_TAG: - xprintf(stream->xine, XINE_VERBOSITY_LOG, "ID3V2.4 tag\n"); + xprintf(stream->xine, XINE_VERBOSITY_LOG, LOG_MODULE ": ID3V2.4 tag\n"); return id3v24_parse_tag(input, stream, id3_signature); default: - xprintf(stream->xine, XINE_VERBOSITY_LOG, "Unknown ID3v2 signature: 0x%08x.\n", be2me_32(id3_signature)); + xprintf(stream->xine, XINE_VERBOSITY_LOG, LOG_MODULE ": Unknown ID3v2 signature: 0x%08x.\n", be2me_32(id3_signature)); } return 0; diff --git a/src/input/http_helper.c b/src/input/http_helper.c index 83562c9dc..f4950a084 100644 --- a/src/input/http_helper.c +++ b/src/input/http_helper.c @@ -220,29 +220,6 @@ error: return 0; } -char *_x_canonicalise_url (const char *base, const char *url) { - - size_t base_length; - char *cut, *ret; - - if ((cut = strstr (url, "://"))) - return strdup (url); - - cut = strstr (base, "://"); - if (url[0] == '/') { - /* absolute - base up to first '/' after "://", then url */ - cut = strchr (cut + 3, '/'); - } - else { - /* relative - base up to & inc. last '/', then url */ - cut = strrchr (cut, '/'); - if (cut) - ++cut; - } - base_length = cut ? (size_t)(cut - base) : strlen (base); - asprintf (&ret, "%.*s%s", (int)base_length, base, url); - return ret; -} #ifdef TEST_URL /* diff --git a/src/input/http_helper.h b/src/input/http_helper.h index 3ce3f2b7c..9baa05235 100644 --- a/src/input/http_helper.h +++ b/src/input/http_helper.h @@ -43,6 +43,28 @@ int _x_parse_url (char *url, char **proto, char** host, int *port, * return: * the canonicalised URL (caller must free() it) */ -char *_x_canonicalise_url (const char *base, const char *url); +static inline char *_x_canonicalise_url (const char *base, const char *url) { + + size_t base_length; + char *cut, *ret; + + if ((cut = strstr (url, "://"))) + return strdup (url); + + cut = strstr (base, "://"); + if (url[0] == '/') { + /* absolute - base up to first '/' after "://", then url */ + cut = strchr (cut + 3, '/'); + } + else { + /* relative - base up to & inc. last '/', then url */ + cut = strrchr (cut, '/'); + if (cut) + ++cut; + } + base_length = cut ? (size_t)(cut - base) : strlen (base); + asprintf (&ret, "%.*s%s", (int)base_length, base, url); + return ret; +} #endif /* HTTP_HELPER_H */ diff --git a/src/input/input_cdda.c b/src/input/input_cdda.c index d84c442cf..4f7e7cc3a 100644 --- a/src/input/input_cdda.c +++ b/src/input/input_cdda.c @@ -72,6 +72,7 @@ #include <xine/xineutils.h> #include <xine/input_plugin.h> #include "media_helper.h" +#include "base64.h" #if defined(__sun) #define DEFAULT_CDDA_DEVICE "/vol/dev/aliases/cdrom0" diff --git a/src/input/input_dvb.c b/src/input/input_dvb.c index 51e4d47aa..1b86fcac5 100644 --- a/src/input/input_dvb.c +++ b/src/input/input_dvb.c @@ -2501,9 +2501,6 @@ static off_t dvb_plugin_read (input_plugin_t *this_gen, "input_dvb: reading %" PRIdMAX " bytes...\n", (intmax_t)len); #endif -#ifndef DVB_NO_BUFFERING - nbc_check_buffers (this->nbc); -#endif /* protect against channel changes */ have_mutex = pthread_mutex_lock(&this->channel_change_mutex); total=0; diff --git a/src/input/input_pnm.c b/src/input/input_pnm.c index 3271a04c9..e11e3b361 100644 --- a/src/input/input_pnm.c +++ b/src/input/input_pnm.c @@ -83,8 +83,6 @@ static off_t pnm_plugin_read (input_plugin_t *this_gen, lprintf ("pnm_plugin_read: %"PRId64" bytes ...\n", len); - nbc_check_buffers (this->nbc); - n = pnm_read (this->pnm, buf, len); this->curpos += n; diff --git a/src/input/input_pvr.c b/src/input/input_pvr.c index 50ba4720e..740d51665 100644 --- a/src/input/input_pvr.c +++ b/src/input/input_pvr.c @@ -1008,19 +1008,21 @@ static void pvr_event_handler (pvr_input_plugin_t *this) { /* change input */ if (v4l2_data->input != -1 && v4l2_data->input != this->input) { - lprintf("change input to:%d\n", v4l2_data->input); this->input = v4l2_data->input; /* as of ivtv 0.10.6: must close and reopen to set input */ close(this->dev_fd); this->dev_fd = open (this->class->devname, O_RDWR); - if (this->dev_fd == -1) { + if (this->dev_fd < 0) { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "input_pvr: error opening device %s\n", this->class->devname ); } else { - if( ioctl(this->dev_fd, VIDIOC_S_INPUT, &this->input) ) + if( ioctl(this->dev_fd, VIDIOC_S_INPUT, &this->input) == 0 ) { + lprintf("Tuner Input set to:%d\n", v4l2_data->input); + } else { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "input_pvr: error setting v4l2 input\n"); + } } } @@ -1032,14 +1034,30 @@ static void pvr_event_handler (pvr_input_plugin_t *this) { /* change frequency */ if (v4l2_data->frequency != -1 && v4l2_data->frequency != this->frequency) { - lprintf("changing frequency to:%.2f\n", (float)v4l2_data->frequency * 62.5); + double freq = (double)v4l2_data->frequency / 1000.0; struct v4l2_frequency vf; + struct v4l2_tuner vt; + double fac = 16; + + memset(&vf, 0, sizeof(vf)); + memset(&vt, 0, sizeof(vt)); + this->frequency = v4l2_data->frequency; - vf.frequency = this->frequency; + + if (ioctl(this->dev_fd, VIDIOC_G_TUNER, &vt) == 0) { + fac = (vt.capability & V4L2_TUNER_CAP_LOW) ? 16000 : 16; + } + vf.tuner = 0; - if( ioctl(this->dev_fd, VIDIOC_S_FREQUENCY, &vf) ) + vf.type = vt.type; + vf.frequency = (__u32)(freq * fac); + + if (ioctl(this->dev_fd, VIDIOC_S_FREQUENCY, &vf) == 0) { + lprintf("Tuner Frequency set to %d (%f.3 MHz)\n", vf.frequency, vf.frequency / fac); + } else { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "input_pvr: error setting v4l2 frequency\n"); + } } pthread_mutex_unlock(&this->dev_lock); diff --git a/src/input/input_rtsp.c b/src/input/input_rtsp.c index bee192c0d..e2b1bae99 100644 --- a/src/input/input_rtsp.c +++ b/src/input/input_rtsp.c @@ -83,8 +83,6 @@ static off_t rtsp_plugin_read (input_plugin_t *this_gen, lprintf ("rtsp_plugin_read: %"PRId64" bytes ...\n", len); - nbc_check_buffers (this->nbc); - n = rtsp_session_read (this->rtsp, buf, len); this->curpos += n; diff --git a/src/input/input_v4l.c b/src/input/input_v4l.c index 28e5b16ce..df0e0e48b 100644 --- a/src/input/input_v4l.c +++ b/src/input/input_v4l.c @@ -114,8 +114,11 @@ static const char *const tv_standard_names[] = { "PAL", "NTSC", "SECAM", NULL }; static const int tv_standard_values[] = { VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_SECAM }; #define NUM_RESOLUTIONS (sizeof(resolutions)/sizeof(resolutions[0])) -#define RADIO_DEV "/dev/v4l/radio0" -#define VIDEO_DEV "/dev/v4l/video0" +#define RADIO_DEV "/dev/radio0" +#define VIDEO_DEV "/dev/video0" +#ifdef HAVE_ALSA +#define AUDIO_DEV "plughw:0,0" +#endif #if !defined(NDELAY) && defined(O_NDELAY) #define FNDELAY O_NDELAY @@ -1732,6 +1735,9 @@ static input_plugin_t *v4l_class_get_instance (input_class_t *cls_gen, { /* v4l_input_class_t *cls = (v4l_input_class_t *) cls_gen; */ v4l_input_plugin_t *this; +#ifdef HAVE_ALSA + cfg_entry_t *entry; +#endif char *mrl = strdup(data); /* Example mrl: v4l:/Television/62500 */ @@ -1752,13 +1758,14 @@ static input_plugin_t *v4l_class_get_instance (input_class_t *cls_gen, this->event_queue = NULL; this->scr = NULL; #ifdef HAVE_ALSA - this->pcm_name = NULL; this->pcm_data = NULL; this->pcm_hwparams = NULL; /* Audio */ this->pcm_stream = SND_PCM_STREAM_CAPTURE; - this->pcm_name = strdup("plughw:0,0"); + entry = this->stream->xine->config->lookup_entry(this->stream->xine->config, + "media.video4linux.audio_device"); + this->pcm_name = strdup (entry->str_value); this->audio_capture = 1; #endif this->rate = 44100; @@ -1928,6 +1935,14 @@ static void *init_video_class (xine_t *xine, void *data) _("Selects the TV standard of the input signals. " "Either: PAL, NTSC and SECAM. "), 20, NULL, NULL); +#ifdef HAVE_ALSA + config->register_filename (config, "media.video4linux.audio_device", + AUDIO_DEV, 0, + _("v4l ALSA audio input device"), + _("The name of the audio device which corresponds " + "to your Video4Linux video device."), + 10, NULL, NULL); +#endif return this; } diff --git a/src/input/libreal/rmff.c b/src/input/libreal/rmff.c index c12fff1d6..1600e967a 100644 --- a/src/input/libreal/rmff.c +++ b/src/input/libreal/rmff.c @@ -35,9 +35,13 @@ * writes header data to a buffer */ -static void rmff_dump_fileheader(rmff_fileheader_t *fileheader, uint8_t *buffer) { +static int rmff_dump_fileheader(rmff_fileheader_t *fileheader, uint8_t *buffer, int bufsize) { + + if (!fileheader) return 0; + + if (bufsize < RMFF_FILEHEADER_SIZE) + return -1; - if (!fileheader) return; fileheader->object_id=_X_BE_32(&fileheader->object_id); fileheader->size=_X_BE_32(&fileheader->size); fileheader->object_version=_X_BE_16(&fileheader->object_version); @@ -53,11 +57,17 @@ static void rmff_dump_fileheader(rmff_fileheader_t *fileheader, uint8_t *buffer) fileheader->file_version=_X_BE_32(&fileheader->file_version); fileheader->num_headers=_X_BE_32(&fileheader->num_headers); fileheader->object_id=_X_BE_32(&fileheader->object_id); + + return RMFF_FILEHEADER_SIZE; } -static void rmff_dump_prop(rmff_prop_t *prop, uint8_t *buffer) { +static int rmff_dump_prop(rmff_prop_t *prop, uint8_t *buffer, int bufsize) { + + if (!prop) return 0; + + if (bufsize < RMFF_PROPHEADER_SIZE) + return -1; - if (!prop) return; prop->object_id=_X_BE_32(&prop->object_id); prop->size=_X_BE_32(&prop->size); prop->object_version=_X_BE_16(&prop->object_version); @@ -93,13 +103,19 @@ static void rmff_dump_prop(rmff_prop_t *prop, uint8_t *buffer) { prop->num_streams=_X_BE_16(&prop->num_streams); prop->flags=_X_BE_16(&prop->flags); prop->object_id=_X_BE_32(&prop->object_id); + + return RMFF_PROPHEADER_SIZE; } -static void rmff_dump_mdpr(rmff_mdpr_t *mdpr, uint8_t *buffer) { +static int rmff_dump_mdpr(rmff_mdpr_t *mdpr, uint8_t *buffer, int bufsize) { int s1, s2, s3; - if (!mdpr) return; + if (!mdpr) return 0; + + if (bufsize < RMFF_MDPRHEADER_SIZE + mdpr->type_specific_len + mdpr->stream_name_size + mdpr->mime_type_size) + return -1; + mdpr->object_id=_X_BE_32(&mdpr->object_id); mdpr->size=_X_BE_32(&mdpr->size); mdpr->object_version=_X_BE_16(&mdpr->object_version); @@ -141,13 +157,19 @@ static void rmff_dump_mdpr(rmff_mdpr_t *mdpr, uint8_t *buffer) { mdpr->duration=_X_BE_32(&mdpr->duration); mdpr->object_id=_X_BE_32(&mdpr->object_id); + return RMFF_MDPRHEADER_SIZE + s1 + s2 + s3; } -static void rmff_dump_cont(rmff_cont_t *cont, uint8_t *buffer) { +static int rmff_dump_cont(rmff_cont_t *cont, uint8_t *buffer, int bufsize) { int p; - if (!cont) return; + if (!cont) return 0; + + if (bufsize < RMFF_CONTHEADER_SIZE + cont->title_len + cont->author_len + + cont->copyright_len + cont->comment_len) + return -1; + cont->object_id=_X_BE_32(&cont->object_id); cont->size=_X_BE_32(&cont->size); cont->object_version=_X_BE_16(&cont->object_version); @@ -181,11 +203,18 @@ static void rmff_dump_cont(rmff_cont_t *cont, uint8_t *buffer) { cont->size=_X_BE_32(&cont->size); cont->object_version=_X_BE_16(&cont->object_version); cont->object_id=_X_BE_32(&cont->object_id); + + return RMFF_CONTHEADER_SIZE + cont->title_len + cont->author_len + + cont->copyright_len + cont->comment_len; } -static void rmff_dump_dataheader(rmff_data_t *data, uint8_t *buffer) { +static int rmff_dump_dataheader(rmff_data_t *data, uint8_t *buffer, int bufsize) { + + if (!data) return 0; + + if (bufsize < RMFF_DATAHEADER_SIZE) + return -1; - if (!data) return; data->object_id=_X_BE_32(&data->object_id); data->size=_X_BE_32(&data->size); data->object_version=_X_BE_16(&data->object_version); @@ -201,32 +230,43 @@ static void rmff_dump_dataheader(rmff_data_t *data, uint8_t *buffer) { data->size=_X_BE_32(&data->size); data->object_version=_X_BE_16(&data->object_version); data->object_id=_X_BE_32(&data->object_id); + + return RMFF_DATAHEADER_SIZE; } int rmff_dump_header(rmff_header_t *h, void *buf_gen, int max) { uint8_t *buffer = buf_gen; - int written=0; + int written=0, size; rmff_mdpr_t **stream=h->streams; - rmff_dump_fileheader(h->fileheader, &buffer[written]); - written+=h->fileheader->size; - rmff_dump_prop(h->prop, &buffer[written]); - written+=h->prop->size; - rmff_dump_cont(h->cont, &buffer[written]); - written+=h->cont->size; + if ((size=rmff_dump_fileheader(h->fileheader, &buffer[written], max)) < 0) + return -1; + written+=size; + max -= size; + if ((size=rmff_dump_prop(h->prop, &buffer[written], max)) < 0) + return -1; + written+=size; + max -= size; + if ((size=rmff_dump_cont(h->cont, &buffer[written], max)) < 0) + return -1; + written+=size; + max -= size; if (stream) { while(*stream) { - rmff_dump_mdpr(*stream, &buffer[written]); - written+=(*stream)->size; + if ((size=rmff_dump_mdpr(*stream, &buffer[written], max)) < 0) + return -1; + written+=size; + max -= size; stream++; } } - rmff_dump_dataheader(h->data, &buffer[written]); - written+=18; + if ((size=rmff_dump_dataheader(h->data, &buffer[written], max)) < 0) + return -1; + written+=size; return written; } @@ -435,6 +475,7 @@ rmff_header_t *rmff_scan_header(const char *data) { return header; } +#if 0 rmff_header_t *rmff_scan_header_stream(int fd) { rmff_header_t *header; @@ -485,6 +526,7 @@ void rmff_scan_pheader(rmff_pheader_t *h, char *data) { h->reserved=(uint8_t)data[10]; h->flags=(uint8_t)data[11]; } +#endif rmff_fileheader_t *rmff_new_fileheader(uint32_t num_headers) { @@ -630,6 +672,7 @@ rmff_data_t *rmff_new_dataheader(uint32_t num_packets, uint32_t next_data_header return data; } +#if 0 void rmff_print_header(rmff_header_t *h) { rmff_mdpr_t **stream; @@ -696,6 +739,7 @@ void rmff_print_header(rmff_header_t *h) { printf("next DATA : 0x%08x\n", h->data->next_data_header); } } +#endif void rmff_fix_header(rmff_header_t *h) { @@ -804,6 +848,7 @@ void rmff_fix_header(rmff_header_t *h) { } } +#if 0 int rmff_get_header_size(rmff_header_t *h) { if (!h) return 0; @@ -843,3 +888,4 @@ void rmff_free_header(rmff_header_t *h) { } free(h); } +#endif diff --git a/src/input/libreal/rmff.h b/src/input/libreal/rmff.h index 010ee5154..3fe3af284 100644 --- a/src/input/libreal/rmff.h +++ b/src/input/libreal/rmff.h @@ -39,6 +39,12 @@ #define RMFF_HEADER_SIZE 0x12 +#define RMFF_FILEHEADER_SIZE 18 +#define RMFF_PROPHEADER_SIZE 50 +#define RMFF_MDPRHEADER_SIZE 46 +#define RMFF_CONTHEADER_SIZE 18 +#define RMFF_DATAHEADER_SIZE 18 + #define FOURCC_TAG( ch0, ch1, ch2, ch3 ) \ (((long)(unsigned char)(ch3) ) | \ ( (long)(unsigned char)(ch2) << 8 ) | \ @@ -216,6 +222,7 @@ rmff_data_t *rmff_new_dataheader( */ rmff_header_t *rmff_scan_header(const char *data); +#if 0 /* * scans a data packet header. Notice, that this function does not allocate * the header struct itself. @@ -231,16 +238,19 @@ rmff_header_t *rmff_scan_header_stream(int fd); * prints header information in human readible form to stdout */ void rmff_print_header(rmff_header_t *h); +#endif /* * does some checks and fixes header if possible */ void rmff_fix_header(rmff_header_t *h); +#if 0 /* * returns the size of the header (incl. first data-header) */ int rmff_get_header_size(rmff_header_t *h); +#endif /* * dumps the header <h> to <buffer>. <max> is the size of <buffer> @@ -252,9 +262,11 @@ int rmff_dump_header(rmff_header_t *h, void *buffer, int max); */ void rmff_dump_pheader(rmff_pheader_t *h, uint8_t *data); +#if 0 /* * frees a header struct */ void rmff_free_header(rmff_header_t *h); +#endif #endif diff --git a/src/input/librtsp/rtsp.c b/src/input/librtsp/rtsp.c index cd844654b..c660751fe 100644 --- a/src/input/librtsp/rtsp.c +++ b/src/input/librtsp/rtsp.c @@ -359,12 +359,14 @@ int rtsp_request_play(rtsp_t *s, const char *what) { return rtsp_get_answers(s); } +#if 0 int rtsp_request_tearoff(rtsp_t *s, const char *what) { rtsp_send_request(s,"TEAROFF",what); return rtsp_get_answers(s); } +#endif /* * read opaque data from stream @@ -557,6 +559,7 @@ char *rtsp_search_answers(rtsp_t *s, const char *tag) { return NULL; } +#if 0 /* * session id management */ @@ -574,6 +577,7 @@ char *rtsp_get_session(rtsp_t *s) { return s->session; } +#endif char *rtsp_get_mrl(rtsp_t *s) { @@ -597,6 +601,7 @@ void rtsp_schedule_field(rtsp_t *s, const char *string) { s->scheduled[i]=strdup(string); } +#if 0 /* * removes the first scheduled field which prefix matches string. */ @@ -617,6 +622,7 @@ void rtsp_unschedule_field(rtsp_t *s, const char *string) { *(ptr-1)=*ptr; } while(*ptr); } +#endif /* * unschedule all fields diff --git a/src/input/librtsp/rtsp.h b/src/input/librtsp/rtsp.h index 3c829e2e8..1cec57e1e 100644 --- a/src/input/librtsp/rtsp.h +++ b/src/input/librtsp/rtsp.h @@ -47,7 +47,9 @@ int rtsp_request_describe(rtsp_t *s, const char *what); int rtsp_request_setup(rtsp_t *s, const char *what); int rtsp_request_setparameter(rtsp_t *s, const char *what); int rtsp_request_play(rtsp_t *s, const char *what); +#if 0 int rtsp_request_tearoff(rtsp_t *s, const char *what); +#endif int rtsp_send_ok(rtsp_t *s); @@ -61,15 +63,19 @@ void rtsp_free_answers(rtsp_t *this); int rtsp_read (rtsp_t *this, char *data, int len); void rtsp_close (rtsp_t *this); +#if 0 void rtsp_set_session(rtsp_t *s, const char *id); char *rtsp_get_session(rtsp_t *s); +#endif char *rtsp_get_mrl(rtsp_t *s); /*int rtsp_peek_header (rtsp_t *this, char *data); */ void rtsp_schedule_field(rtsp_t *s, const char *string); +#if 0 void rtsp_unschedule_field(rtsp_t *s, const char *string); +#endif void rtsp_unschedule_all(rtsp_t *s); #endif diff --git a/src/input/librtsp/rtsp_session.c b/src/input/librtsp/rtsp_session.c index 5cb0dfb63..d8f7ae583 100644 --- a/src/input/librtsp/rtsp_session.c +++ b/src/input/librtsp/rtsp_session.c @@ -148,6 +148,11 @@ connect: rtsp_session->header_left = rtsp_session->header_len = rmff_dump_header(h,rtsp_session->header,HEADER_SIZE); + if (rtsp_session->header_len < 0) { + xprintf (stream->xine, XINE_VERBOSITY_LOG, + _("rtsp_session: rtsp server returned overly-large headers, session can not be established.\n")); + goto session_abort; + } xine_buffer_copyin(rtsp_session->recv, 0, rtsp_session->header, rtsp_session->header_len); rtsp_session->recv_size = rtsp_session->header_len; @@ -157,6 +162,7 @@ connect: { xprintf(stream->xine, XINE_VERBOSITY_LOG, _("rtsp_session: rtsp server type '%s' not supported yet. sorry.\n"), server); + session_abort: rtsp_close(rtsp_session->s); free(server); xine_buffer_free(rtsp_session->recv); diff --git a/src/input/net_buf_ctrl.c b/src/input/net_buf_ctrl.c index aaf575e40..03a24d38f 100644 --- a/src/input/net_buf_ctrl.c +++ b/src/input/net_buf_ctrl.c @@ -113,10 +113,6 @@ static void nbc_set_speed_normal (nbc_t *this) { stream->xine->clock->set_option (stream->xine->clock, CLOCK_SCR_ADJUSTABLE, 1); } -void nbc_check_buffers (nbc_t *this) { - /* Deprecated */ -} - static void display_stats (nbc_t *this) { static const char buffering[2][4] = {" ", "buf"}; static const char enabled[2][4] = {"off", "on "}; @@ -564,22 +560,3 @@ void nbc_close (nbc_t *this) { free (this); xprintf(xine, XINE_VERBOSITY_DEBUG, "\nnet_buf_ctrl: nbc_close: done\n"); } - - -void nbc_set_high_water_mark(nbc_t *this, int value) { -/* - Deprecated - this->high_water_mark = value; -*/ - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "\nnet_buf_ctrl: this method is deprecated, please fix the input plugin\n"); -} - -void nbc_set_low_water_mark(nbc_t *this, int value) { -/* - Deprecated - this->low_water_mark = value; -*/ - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "\nnet_buf_ctrl: this method is deprecated, please fix the input plugin\n"); -} diff --git a/src/input/net_buf_ctrl.h b/src/input/net_buf_ctrl.h index c35187179..87d6d84a1 100644 --- a/src/input/net_buf_ctrl.h +++ b/src/input/net_buf_ctrl.h @@ -29,12 +29,6 @@ typedef struct nbc_s nbc_t; nbc_t *nbc_init (xine_stream_t *xine); -void nbc_check_buffers (nbc_t *this); - void nbc_close (nbc_t *this); -void nbc_set_high_water_mark(nbc_t *this, int value); - -void nbc_set_low_water_mark(nbc_t *this, int value); - #endif diff --git a/src/libreal/real_common.c b/src/libreal/real_common.c index 531fb780e..6cc1d8785 100644 --- a/src/libreal/real_common.c +++ b/src/libreal/real_common.c @@ -77,8 +77,8 @@ void _x_real_codecs_init(xine_t *const xine) { default_real_codecs_path[0] = 0; -#define UL64 0x05 /* /usr/{,local/}lib64 */ -#define UL 0x0A /* /usr/{,local/}lib */ +#define UL64 0x03 /* /usr/{,local/}lib64 */ +#define UL 0x0C /* /usr/{,local/}lib */ #define O 0x10 /* /opt */ #define OL64 0x20 /* /opt/lib64 */ #define OL 0x40 /* /opt/lib */ diff --git a/src/post/audio/stretch.c b/src/post/audio/stretch.c index bc079fd8d..5a0382895 100644 --- a/src/post/audio/stretch.c +++ b/src/post/audio/stretch.c @@ -662,7 +662,7 @@ static post_plugin_t *stretch_open_plugin(post_class_t *class_gen, int inputs, /* plugin class initialization function */ void *stretch_init_plugin(xine_t *xine, void *data) { - post_class_stretch_t *class = (post_class_stretch_t *)malloc(sizeof(post_class_stretch_t)); + post_class_stretch_t *class = (post_class_stretch_t *)xine_xmalloc(sizeof(post_class_stretch_t)); if (!class) return NULL; diff --git a/src/post/audio/upmix.c b/src/post/audio/upmix.c index 30fbb452b..573354450 100644 --- a/src/post/audio/upmix.c +++ b/src/post/audio/upmix.c @@ -417,7 +417,7 @@ static post_plugin_t *upmix_open_plugin(post_class_t *class_gen, int inputs, /* plugin class initialization function */ void *upmix_init_plugin(xine_t *xine, void *data) { - post_class_upmix_t *class = (post_class_upmix_t *)malloc(sizeof(post_class_upmix_t)); + post_class_upmix_t *class = (post_class_upmix_t *)xine_xmalloc(sizeof(post_class_upmix_t)); if (!class) return NULL; diff --git a/src/post/audio/upmix_mono.c b/src/post/audio/upmix_mono.c index 53fd23109..82ceb1877 100644 --- a/src/post/audio/upmix_mono.c +++ b/src/post/audio/upmix_mono.c @@ -332,7 +332,7 @@ static post_plugin_t *upmix_mono_open_plugin(post_class_t *class_gen, int inputs /* plugin class initialization function */ void *upmix_mono_init_plugin(xine_t *xine, void *data) { - post_class_upmix_mono_t *class = (post_class_upmix_mono_t *)malloc(sizeof(post_class_upmix_mono_t)); + post_class_upmix_mono_t *class = (post_class_upmix_mono_t *)xine_xmalloc(sizeof(post_class_upmix_mono_t)); if (!class) return NULL; diff --git a/src/post/audio/volnorm.c b/src/post/audio/volnorm.c index 4fb2a0411..de4ebde87 100644 --- a/src/post/audio/volnorm.c +++ b/src/post/audio/volnorm.c @@ -450,7 +450,7 @@ static post_plugin_t *volnorm_open_plugin(post_class_t *class_gen, int inputs, /* plugin class initialization function */ void *volnorm_init_plugin(xine_t *xine, void *data) { - post_class_volnorm_t *class = (post_class_volnorm_t *)malloc(sizeof(post_class_volnorm_t)); + post_class_volnorm_t *class = (post_class_volnorm_t *)xine_xmalloc(sizeof(post_class_volnorm_t)); if (!class) return NULL; diff --git a/src/post/visualizations/fft.c b/src/post/visualizations/fft.c index e9a99911a..01044987b 100644 --- a/src/post/visualizations/fft.c +++ b/src/post/visualizations/fft.c @@ -184,18 +184,6 @@ double fft_amp (int n, complex_t wave[], int bits) } /* - * Calculate phase of component n in the decimated wave[] array. - */ -double fft_phase (int n, complex_t wave[], int bits) -{ - n = PERMUTE (n, bits); - if (REAL(n) != 0.0) - return (atan (IMAG(n) / REAL(n))); - else - return (0.0); -} - -/* * Scale sampled values. * Do this *before* the fft. */ diff --git a/src/post/visualizations/fft.h b/src/post/visualizations/fft.h index dff3cd7e8..1600430bc 100644 --- a/src/post/visualizations/fft.h +++ b/src/post/visualizations/fft.h @@ -44,7 +44,6 @@ void fft_compute (fft_t *fft, complex_t wave[]); void fft_window (fft_t *fft, complex_t wave[]); double fft_amp (int n, complex_t wave[], int bits); -double fft_phase (int n, complex_t wave[], int bits); void fft_scale (complex_t wave[], int bits); #endif /* FFT_H */ diff --git a/src/post/visualizations/fftgraph.c b/src/post/visualizations/fftgraph.c index c31c529f2..39d17c730 100644 --- a/src/post/visualizations/fftgraph.c +++ b/src/post/visualizations/fftgraph.c @@ -455,7 +455,7 @@ static post_plugin_t *fftgraph_open_plugin(post_class_t *class_gen, int inputs, /* plugin class initialization function */ void *fftgraph_init_plugin(xine_t *xine, void *data) { - post_class_fftgraph_t *class = (post_class_fftgraph_t *)malloc(sizeof(post_class_fftgraph_t)); + post_class_fftgraph_t *class = (post_class_fftgraph_t *)xine_xmalloc(sizeof(post_class_fftgraph_t)); if (!class) return NULL; diff --git a/src/post/visualizations/fftscope.c b/src/post/visualizations/fftscope.c index dd474bd6f..1a9ea905a 100644 --- a/src/post/visualizations/fftscope.c +++ b/src/post/visualizations/fftscope.c @@ -476,7 +476,7 @@ static post_plugin_t *fftscope_open_plugin(post_class_t *class_gen, int inputs, /* plugin class initialization function */ void *fftscope_init_plugin(xine_t *xine, void *data) { - post_class_fftscope_t *class = (post_class_fftscope_t *)malloc(sizeof(post_class_fftscope_t)); + post_class_fftscope_t *class = (post_class_fftscope_t *)xine_xmalloc(sizeof(post_class_fftscope_t)); if (!class) return NULL; diff --git a/src/post/visualizations/fooviz.c b/src/post/visualizations/fooviz.c index 2cf77cadc..3e5702168 100644 --- a/src/post/visualizations/fooviz.c +++ b/src/post/visualizations/fooviz.c @@ -287,7 +287,7 @@ static post_plugin_t *fooviz_open_plugin(post_class_t *class_gen, int inputs, /* plugin class initialization function */ static void *fooviz_init_plugin(xine_t *xine, void *data) { - post_class_fooviz_t *class = (post_class_fooviz_t *)malloc(sizeof(post_class_fooviz_t)); + post_class_fooviz_t *class = (post_class_fooviz_t *)xine_xmalloc(sizeof(post_class_fooviz_t)); if (!class) return NULL; diff --git a/src/post/visualizations/oscope.c b/src/post/visualizations/oscope.c index 1d498980a..7c9faeeaa 100644 --- a/src/post/visualizations/oscope.c +++ b/src/post/visualizations/oscope.c @@ -358,7 +358,7 @@ static post_plugin_t *oscope_open_plugin(post_class_t *class_gen, int inputs, /* plugin class initialization function */ void *oscope_init_plugin(xine_t *xine, void *data) { - post_class_oscope_t *class = (post_class_oscope_t *)malloc(sizeof(post_class_oscope_t)); + post_class_oscope_t *class = (post_class_oscope_t *)xine_xmalloc(sizeof(post_class_oscope_t)); if (!class) return NULL; diff --git a/src/spu_dec/sputext_decoder.c b/src/spu_dec/sputext_decoder.c index 093fca1e7..0cc0ee21b 100644 --- a/src/spu_dec/sputext_decoder.c +++ b/src/spu_dec/sputext_decoder.c @@ -507,11 +507,52 @@ static void read_ssa_tag(sputext_decoder_t *this, const char* text, (*sub_x), (*sub_y), (*max_width), (*alignment)); } +static int is_cjk_encoding(const char *enc) { + /* CJK charset strings defined in iconvdata/gconv-modules of glibc */ + static const char cjk_encoding_strings[][16] = { + "SJIS", + "CP932", + "EUC-KR", + "UHC", + "JOHAB", + "BIG5", + "BIG5HKSCS", + "EUC-JP-MS", + "EUC-JP", + "EUC-CN", + "GBBIG5", + "GBK", + "GBGBK", + "EUC-TW", + "ISO-2022-JP", + "ISO-2022-JP-2", + "ISO-2022-JP-3", + "ISO-2022-KR", + "ISO-2022-CN", + "ISO-2022-CN-EXT", + "GB18030", + "EUC-JISX0213", + "SHIFT_JISX0213", + }; + + int pstr; + + /* return 1 if encoding string is one of the CJK(Chinese,Jananese,Korean) + * character set strings. */ + for (pstr = 0; pstr < sizeof (cjk_encoding_strings) / sizeof (cjk_encoding_strings[0]); pstr++) + if (strcasecmp (enc, cjk_encoding_strings[pstr]) == 0) + return 1; + + return 0; +} + static void draw_subtitle(sputext_decoder_t *this, int64_t sub_start, int64_t sub_end ) { int line, y; int font_size; char *font; + const char *encoding = (this->buf_encoding)?this->buf_encoding: + this->class->src_encoding; int sub_x, sub_y, max_width; int alignment; int rebuild_all; @@ -720,7 +761,12 @@ static void draw_subtitle(sputext_decoder_t *this, int64_t sub_start, int64_t su } } - ogm_render_line(this, x, y + line*this->line_height, this->text[line]); + if( is_cjk_encoding(encoding) ) { + this->renderer->render_text (this->osd, x, y + line * this->line_height, + this->text[line], OSD_TEXT1); + } else { + ogm_render_line(this, x, y + line*this->line_height, this->text[line]); + } } if( font_size != this->font_size ) diff --git a/src/vdr/post_vdr_audio.c b/src/vdr/post_vdr_audio.c index ca45ecd35..49de8f9cf 100644 --- a/src/vdr/post_vdr_audio.c +++ b/src/vdr/post_vdr_audio.c @@ -71,7 +71,7 @@ static void vdr_audio_port_put_buffer(xine_audio_port_t *port_gen, aud void *vdr_audio_init_plugin(xine_t *xine, void *data) { - post_class_t *class = (post_class_t *)malloc(sizeof (post_class_t)); + post_class_t *class = (post_class_t *)xine_xmalloc(sizeof (post_class_t)); if (!class) return NULL; diff --git a/src/vdr/post_vdr_video.c b/src/vdr/post_vdr_video.c index ff6c32504..178538655 100644 --- a/src/vdr/post_vdr_video.c +++ b/src/vdr/post_vdr_video.c @@ -23,9 +23,9 @@ */ #define LOG_MODULE "vdr_video" -#define LOG_VERBOSE /* #define LOG +#define LOG_VERBOSE */ #include <xine/xine_internal.h> @@ -94,7 +94,7 @@ static int vdr_video_draw(vo_frame_t *frame, xine_stream_t *stream); void *vdr_video_init_plugin(xine_t *xine, void *data) { - post_class_t *class = (post_class_t *)malloc(sizeof (post_class_t)); + post_class_t *class = (post_class_t *)xine_xmalloc(sizeof (post_class_t)); if (!class) return NULL; @@ -437,12 +437,14 @@ static int vdr_video_draw(vo_frame_t *frame, xine_stream_t *stream) frame->next->pts = 0; } */ +#if defined(LOG) && defined(LOG_VERBOSE) { int a = 0, b = 0, c = 0, d = 0; if (stream) _x_query_buffer_usage(stream, &a, &b, &c, &d); - fprintf(stderr, "buffer usage: %3d, %2d, %2d, %2d, %p\n", a, b, c, d, stream); + lprintf("buffer usage: %3d, %2d, %2d, %2d, %p\n", a, b, c, d, stream); } +#endif if (!this->enabled || frame->bad_frame diff --git a/src/video_out/Makefile.am b/src/video_out/Makefile.am index 0a60d242e..062c7aa68 100644 --- a/src/video_out/Makefile.am +++ b/src/video_out/Makefile.am @@ -12,7 +12,7 @@ endif EXTRA_DIST = video_out_directx.c video_out_macosx.m -noinst_HEADERS = video_out_syncfb.h yuv2rgb.h x11osd.h xcbosd.h +noinst_HEADERS = yuv2rgb.h x11osd.h xcbosd.h xv_common.h if HAVE_X11 X11OSD = x11osd.c @@ -29,9 +29,6 @@ endif if ENABLE_OPENGL opengl_module = xineplug_vo_out_opengl.la endif -if ENABLE_SYNCFB -syncfb_module = xineplug_vo_out_syncfb.la -endif if ENABLE_SUNFB if ENABLE_SUNDGA pgx64_module = xineplug_vo_out_pgx64.la @@ -99,7 +96,6 @@ libyuv2rgb_la_LIBADD = $(XINE_LIB) $(MLIB_LIBS) $(AVUTIL_LIBS) xineplug_LTLIBRARIES = $(xshm_module) $(xv_module) $(xvmc_module) \ $(opengl_module) \ - $(syncfb_module) \ $(pgx64_module) $(pgx32_module)\ $(vidix_module) \ $(aa_module) \ @@ -141,12 +137,9 @@ xineplug_vo_out_xxmc_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) $(XV_CFLAGS) -fno-stri xineplug_vo_out_opengl_la_SOURCES = video_out_opengl.c myglext.h $(X11OSD) xineplug_vo_out_opengl_la_LIBADD = libyuv2rgb.la $(OPENGL_LIBS) $(GLUT_LIBS) \ - $(GLU_LIBS) $(X_LIBS) $(XINE_LIB) $(PTHREAD_LIBS) $(DYNAMIC_LD_LIBS) $(LTLIBINTL) $(AVUTIL_LIBS) + $(GLUT_LIBS) $(GLU_LIBS) $(X_LIBS) $(XINE_LIB) $(PTHREAD_LIBS) $(DYNAMIC_LD_LIBS) $(LTLIBINTL) $(AVUTIL_LIBS) xineplug_vo_out_opengl_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) $(AVUTIL_CFLAGS) -fno-strict-aliasing -xineplug_vo_out_syncfb_la_SOURCES = video_out_syncfb.c -xineplug_vo_out_syncfb_la_LIBADD = $(XINE_LIB) $(X_LIBS) $(PTHREAD_LIBS) $(LTLIBINTL) - xineplug_vo_out_pgx64_la_SOURCES = video_out_pgx64.c xineplug_vo_out_pgx64_la_LIBADD = $(XINE_LIB) $(X_LIBS) $(SUNDGA_LIBS) $(PTHREAD_LIBS) $(LTLIBINTL) xineplug_vo_out_pgx64_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) diff --git a/src/video_out/macosx/XineOpenGLView.m b/src/video_out/macosx/XineOpenGLView.m index 5ed515704..cad087551 100644 --- a/src/video_out/macosx/XineOpenGLView.m +++ b/src/video_out/macosx/XineOpenGLView.m @@ -336,7 +336,7 @@ NSColorToYUV(NSColor *color) // http://developer.apple.com/samplecode/Sample_Code/Graphics_3D/TextureRange/MainOpenGLView.m.htm glTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, videoSize.width, videoSize.height, GL_YCBCR_422_APPLE, -#if WORDS_BIG_ENDIAN +#if WORDS_BIGENDIAN GL_UNSIGNED_SHORT_8_8_APPLE, #else GL_UNSIGNED_SHORT_8_8_REV_APPLE, diff --git a/src/video_out/video_out_directfb.c b/src/video_out/video_out_directfb.c index d85df411a..fecc2c5b0 100644 --- a/src/video_out/video_out_directfb.c +++ b/src/video_out/video_out_directfb.c @@ -1742,6 +1742,20 @@ static void directfb_frame_output_cb (void *user_data, int video_width, int vide /*** DirectFB plugin functions ***/ +static inline int convert_caps (DFBDisplayLayerCapabilities caps) +{ + int vo = VO_CAP_YV12 | VO_CAP_YUY2 | VO_CAP_CROP | VO_CAP_ZOOM_X | VO_CAP_ZOOM_Y; + if (caps & DLCAPS_HUE) + vo |= VO_CAP_HUE; + if (caps & DLCAPS_SATURATION) + vo |= VO_CAP_SATURATION; + if (caps & DLCAPS_CONTRAST) + vo |= VO_CAP_CONTRAST; + if (caps & DLCAPS_BRIGHTNESS) + vo |= VO_CAP_BRIGHTNESS; + return vo; +} + static vo_driver_t *open_plugin_fb (video_driver_class_t *class_gen, const void *visual_gen) { directfb_class_t *class = (directfb_class_t *) class_gen; directfb_driver_t *this; @@ -1821,7 +1835,7 @@ static vo_driver_t *open_plugin_fb (video_driver_class_t *class_gen, const void return NULL; } - this->capabilities = VO_CAP_YV12 | VO_CAP_YUY2 | VO_CAP_CROP; + this->capabilities = convert_caps (this->caps); /* set default configuration */ this->buffermode = 1; // double this->vsync = 0; @@ -2000,7 +2014,7 @@ static vo_driver_t *open_plugin_x11 (video_driver_class_t *class_gen, const void xprintf (this->xine, XINE_VERBOSITY_LOG, _("video_out_directfb: using display layer #%d.\n"), id); - this->capabilities = VO_CAP_YV12 | VO_CAP_YUY2 | VO_CAP_CROP; + this->capabilities = convert_caps (this->caps); /* set default configuration */ this->buffermode = 1; // double this->vsync = 0; diff --git a/src/video_out/video_out_fb.c b/src/video_out/video_out_fb.c index cb327109e..dc3d683e1 100644 --- a/src/video_out/video_out_fb.c +++ b/src/video_out/video_out_fb.c @@ -156,7 +156,7 @@ typedef struct static uint32_t fb_get_capabilities(vo_driver_t *this_gen) { - return VO_CAP_YV12 | VO_CAP_YUY2; + return VO_CAP_YV12 | VO_CAP_YUY2 | VO_CAP_BRIGHTNESS | VO_CAP_CONTRAST | VO_CAP_SATURATION; } static void fb_frame_proc_slice(vo_frame_t *vo_img, uint8_t **src) diff --git a/src/video_out/video_out_opengl.c b/src/video_out/video_out_opengl.c index febf44519..c1416963c 100644 --- a/src/video_out/video_out_opengl.c +++ b/src/video_out/video_out_opengl.c @@ -1202,7 +1202,7 @@ static void *render_run (opengl_driver_t *this) { static uint32_t opengl_get_capabilities (vo_driver_t *this_gen) { /* opengl_driver_t *this = (opengl_driver_t *) this_gen; */ - uint32_t capabilities = VO_CAP_YV12 | VO_CAP_YUY2; + uint32_t capabilities = VO_CAP_YV12 | VO_CAP_YUY2 | VO_CAP_BRIGHTNESS | VO_CAP_CONTRAST | VO_CAP_SATURATION; /* TODO: somehow performance goes down during the first few frames */ /* if (this->xoverlay) */ diff --git a/src/video_out/video_out_pgx64.c b/src/video_out/video_out_pgx64.c index d0e74b1e3..0bdcc35fe 100644 --- a/src/video_out/video_out_pgx64.c +++ b/src/video_out/video_out_pgx64.c @@ -552,8 +552,7 @@ static uint32_t pgx64_get_capabilities(vo_driver_t *this_gen) { /*pgx64_driver_t *this = (pgx64_driver_t *)(void *)this_gen;*/ - return VO_CAP_YV12 | - VO_CAP_YUY2; + return VO_CAP_YV12 | VO_CAP_YUY2 | VO_CAP_BRIGHTNESS | VO_CAP_SATURATION; } static vo_frame_t *pgx64_alloc_frame(vo_driver_t *this_gen) diff --git a/src/video_out/video_out_syncfb.c b/src/video_out/video_out_syncfb.c deleted file mode 100644 index 983cd9b64..000000000 --- a/src/video_out/video_out_syncfb.c +++ /dev/null @@ -1,1116 +0,0 @@ -/* - * Copyright (C) 2000-2003 the xine project - * - * This file is part of xine, a free video player. - * - * xine 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. - * - * xine 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * video_out_syncfb.c, SyncFB (for Matrox G200/G400 cards) interface for xine - * - * based on video_out_xv.c by (see file for original authors) - * - * with lot's of code from: - * video_out_syncfb.c by Joachim Koenig <joachim.koenig@gmx.net> - * and by Matthias Oelmann <mao@well.com> - * video_out_mga by Aaron Holtzman <aholtzma@ess.engr.uvic.ca> - * - * glued together for xine by Matthias Dahl <matthew2k@web.de> - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef __sun -#include <sys/ioccom.h> -#endif - -#include <sys/ioctl.h> -#if defined (__FreeBSD__) -#include <sys/types.h> -#endif -#include <sys/mman.h> -#include <math.h> -#include <fcntl.h> -#include <unistd.h> - -#include <X11/Xlib.h> -#include <X11/Xutil.h> - -#include "video_out_syncfb.h" - -#include "xine.h" -#include <xine/video_out.h> -#include <xine/xine_internal.h> -#include <xine/xineutils.h> -#include <xine/vo_scale.h> - -/*#define DEBUG_OUTPUT*/ - -typedef struct syncfb_driver_s syncfb_driver_t; - -typedef struct { - int value; - int min; - int max; -} syncfb_property_t; - -typedef struct { - vo_frame_t vo_frame; -/* uint8_t* data_mem[3];*/ - int width, height, format; - double ratio; -} syncfb_frame_t; - -struct syncfb_driver_s { - - vo_driver_t vo_driver; - - config_values_t *config; - - /* X11 related stuff */ - Display *display; - int screen; - Drawable drawable; - XVisualInfo vinfo; - GC gc; - XColor black; - - vo_scale_t sc; - - int virtual_screen_width; - int virtual_screen_height; - int screen_depth; - - syncfb_property_t props[VO_NUM_PROPERTIES]; - - syncfb_frame_t* cur_frame; - vo_overlay_t* overlay; - - /* syncfb module related stuff */ - int fd; /* file descriptor of the syncfb device */ - int yuv_format; /* either YUV420P3, YUV420P2 or YUV422 */ - int overlay_state; /* 0 = off, 1 = on */ - uint8_t* video_mem; /* mmapped video memory */ - int default_repeat; /* how many times a frame will be repeatedly displayed */ - uint32_t supported_capabilities; - - syncfb_config_t syncfb_config; - syncfb_capability_t capabilities; - syncfb_buffer_info_t bufinfo; - syncfb_param_t params; - - int video_win_visibility; - xine_t *xine; - - alphablend_t alphablend_extra_data; -}; - -typedef struct { - video_driver_class_t driver_class; - - config_values_t *config; - char *device_name; - xine_t *xine; -} syncfb_class_t; - -/* - * internal video_out_syncfb functions - */ - -/* returns boolean value (1 success, 0 failure) */ -static int syncfb_overlay_on(syncfb_driver_t* this) -{ - if(ioctl(this->fd, SYNCFB_ON)) { - xprintf(this->xine, XINE_VERBOSITY_DEBUG, - "video_out_syncfb: error. (on ioctl failed)\n"); - return 0; - } else { - this->overlay_state = 1; - return 1; - } -} - -/* returns boolean value (1 success, 0 failure) */ -static int syncfb_overlay_off(syncfb_driver_t* this) -{ - if(ioctl(this->fd, SYNCFB_OFF)) { - xprintf(this->xine, XINE_VERBOSITY_DEBUG, - "video_out_syncfb: error. (off ioctl failed)\n"); - return 0; - } else { - this->overlay_state = 0; - return 1; - } -} - -static void write_frame_YUV422(syncfb_driver_t* this, syncfb_frame_t* frame) -{ - uint8_t* y = (uint_8 *)frame->vo_frame.base[0]; - uint8_t* cb = (uint_8 *)frame->vo_frame.base[1]; - uint8_t* cr = (uint_8 *)frame->vo_frame.base[2]; - uint8_t* crp; - uint8_t* cbp; - uint32_t* dst32 = (uint32_t *)(this->video_mem + this->bufinfo.offset); - int h,w; - - for(h = 0; h < (frame->height / 2); h++) { - cbp = cb; - crp = cr; - - for(w = 0; w < (frame->width / 2); w++) { - *dst32++ = (*y) + ((*cb)<<8) + ((*(y+1))<<16) + ((*cr)<<24); - y++; y++; cb++; cr++; - } - - dst32 += (this->syncfb_config.src_pitch - frame->width) / 2; - - for(w=0; w < (frame->width / 2); w++) { - *dst32++ = (*y) + ((*cbp)<<8) + ((*(y+1))<<16) + ((*crp)<<24); - y++; y++; cbp++; crp++; - } - - dst32 += (this->syncfb_config.src_pitch - frame->width) / 2; - } -} - -static void write_frame_YUV420P2(syncfb_driver_t* this, syncfb_frame_t* frame) -{ - uint8_t* y = (uint8_t *)frame->vo_frame.base[0]; - uint8_t* cb = (uint8_t *)frame->vo_frame.base[1]; - uint8_t* cr = (uint8_t *)frame->vo_frame.base[2]; - uint8_t* dst8 = this->video_mem + this->bufinfo.offset_p2; - int h, w; - - register uint32_t* tmp32; - register uint8_t* rcr; - register uint8_t* rcb; - - rcr = cr; - rcb = cb; - - for(h = 0; h < (frame->height / 2); h++) { - tmp32 = (uint32_t *)dst8; - w = (frame->width / 8) * 2; - - while(w--) { - register uint32_t temp; - - temp = (*rcb) | (*rcr << 8); - rcr++; - rcb++; - temp |= (*rcb << 16) | (*rcr << 24); - rcr++; - rcb++; - *tmp32 = temp; - tmp32++; - } - - dst8 += this->syncfb_config.src_pitch; - } - - dst8 = this->video_mem + this->bufinfo.offset; - for(h = 0; h < frame->height; h++) { - xine_fast_memcpy(dst8, y, frame->width); - y += frame->width; - dst8 += this->syncfb_config.src_pitch; - } -} - -static void write_frame_YUV420P3(syncfb_driver_t* this, syncfb_frame_t* frame) -{ - uint8_t* y = (uint8_t *)frame->vo_frame.base[0]; - uint8_t* cb = (uint8_t *)frame->vo_frame.base[1]; - uint8_t* cr = (uint8_t *)frame->vo_frame.base[2]; - uint8_t* dst8 = this->video_mem + this->bufinfo.offset; - int h, half_width = (frame->width/2); - - for(h = 0; h < frame->height; h++) { - xine_fast_memcpy(dst8, y, frame->width); - y += frame->width; - dst8 += this->syncfb_config.src_pitch; - } - - dst8 = this->video_mem; - for(h = 0; h < (frame->height / 2); h++) { - xine_fast_memcpy((dst8 + this->bufinfo.offset_p2), cb, half_width); - xine_fast_memcpy((dst8 + this->bufinfo.offset_p3), cr, half_width); - - cb += half_width; - cr += half_width; - - dst8 += (this->syncfb_config.src_pitch / 2); - } -} - -static void write_frame_YUY2(syncfb_driver_t* this, syncfb_frame_t* frame) -{ - uint8_t* src8 = (uint8_t *)frame->vo_frame.base[0]; - uint8_t* dst8 = (uint8_t *)(this->video_mem + this->bufinfo.offset); - int h, double_width = (frame->width * 2); - - for(h = 0; h < frame->height; h++) { - xine_fast_memcpy(dst8, src8, double_width); - - dst8 += (this->syncfb_config.src_pitch * 2); - src8 += double_width; - } -} - -static void write_frame_sfb(syncfb_driver_t* this, syncfb_frame_t* frame) -{ - switch(frame->format) { - case XINE_IMGFMT_YUY2: - if(this->capabilities.palettes & (1<<VIDEO_PALETTE_YUV422)) - write_frame_YUY2(this, frame); - else - xprintf(this->xine, XINE_VERBOSITY_LOG, - _("video_out_syncfb: error. (YUY2 not supported by your graphic card)\n")); - break; - - case XINE_IMGFMT_YV12: - switch(this->yuv_format) { - case VIDEO_PALETTE_YUV422: - write_frame_YUV422(this, frame); - break; - case VIDEO_PALETTE_YUV420P2: - write_frame_YUV420P2(this, frame); - break; - case VIDEO_PALETTE_YUV420P3: - write_frame_YUV420P3(this, frame); - break; - default: - xprintf(this->xine, XINE_VERBOSITY_LOG, - _("video_out_syncfb: error. (YV12 not supported by your graphic card)\n")); - } - break; - - default: - xprintf(this->xine, XINE_VERBOSITY_DEBUG, "video_out_syncfb: error. (unknown frame format)\n"); - break; - } - - frame->vo_frame.free(&frame->vo_frame); -} - -static void free_framedata(syncfb_frame_t* frame) -{ -/* if(frame->data_mem[0]) { - free(frame->data_mem[0]); - frame->data_mem[0] = NULL; - } - - if(frame->data_mem[1]) { - free(frame->data_mem[1]); - frame->data_mem[1] = NULL; - } - - if(frame->data_mem[2]) { - free(frame->data_mem[2]); - frame->data_mem[2] = NULL; - }*/ - - if(frame->vo_frame.base[0]) { - free(frame->vo_frame.base[0]); - frame->vo_frame.base[0] = NULL; - } - - if(frame->vo_frame.base[1]) { - free(frame->vo_frame.base[1]); - frame->vo_frame.base[1] = NULL; - } - - if(frame->vo_frame.base[2]) { - free(frame->vo_frame.base[2]); - frame->vo_frame.base[2] = NULL; - } -} - -static void syncfb_clean_output_area(syncfb_driver_t* this) -{ - XLockDisplay (this->display); - - XSetForeground (this->display, this->gc, this->black.pixel); - - XFillRectangle(this->display, this->drawable, this->gc, - this->sc.gui_x, this->sc.gui_y, this->sc.gui_width, this->sc.gui_height); - - XUnlockDisplay (this->display); -} - - -static void syncfb_compute_ideal_size (syncfb_driver_t *this) -{ - _x_vo_scale_compute_ideal_size( &this->sc ); -} - -/* make ideal width/height "fit" into the gui */ -static void syncfb_compute_output_size(syncfb_driver_t *this) -{ - _x_vo_scale_compute_output_size( &this->sc ); - -#ifdef DEBUG_OUTPUT - printf("video_out_syncfb: debug. (frame source %d x %d, screen output %d x %d)\n", - this->sc.delivered_width, this->sc.delivered_height, - this->sc.output_width, this->sc.output_height); -#endif - - /* - * configuring SyncFB module from this point on. - */ - syncfb_overlay_off(this); - - /* sanity checking - certain situations *may* crash the SyncFB module, so - * take care that we always have valid numbers. - */ - if(this->sc.output_xoffset >= 0 && this->sc.output_yoffset >= 0 && - this->cur_frame->width > 0 && this->cur_frame->height > 0 && - this->sc.output_width > 0 && this->sc.output_height > 0 && - this->cur_frame->format > 0 && this->video_win_visibility) { - - if(ioctl(this->fd, SYNCFB_GET_CONFIG, &this->syncfb_config)) - xprintf(this->xine, XINE_VERBOSITY_DEBUG, - "video_out_syncfb: error. (get_config ioctl failed)\n"); - - this->syncfb_config.syncfb_mode = SYNCFB_FEATURE_SCALE | SYNCFB_FEATURE_CROP; - - if(this->props[VO_PROP_INTERLACED].value) - this->syncfb_config.syncfb_mode |= SYNCFB_FEATURE_DEINTERLACE; - - switch(this->cur_frame->format) { - case XINE_IMGFMT_YV12: - this->syncfb_config.src_palette = this->yuv_format; - break; - case XINE_IMGFMT_YUY2: - this->syncfb_config.src_palette = VIDEO_PALETTE_YUV422; - break; - default: - xprintf(this->xine, XINE_VERBOSITY_DEBUG, - "video_out_syncfb: error. (unknown frame format)\n"); - this->syncfb_config.src_palette = 0; - break; - } - - this->syncfb_config.fb_screen_size = this->virtual_screen_width * this->virtual_screen_height * (this->screen_depth / 8) * 2; - this->syncfb_config.src_width = this->cur_frame->width; - this->syncfb_config.src_height = this->cur_frame->height; - - this->syncfb_config.image_width = this->sc.output_width; - this->syncfb_config.image_height = this->sc.output_height; - - this->syncfb_config.image_xorg = this->sc.output_xoffset + this->sc.gui_win_x; - this->syncfb_config.image_yorg = this->sc.output_yoffset + this->sc.gui_win_y; - - this->syncfb_config.src_crop_top = this->sc.displayed_yoffset; - this->syncfb_config.src_crop_bot = (this->props[VO_PROP_INTERLACED].value && this->sc.displayed_yoffset == 0) ? 1 : this->sc.displayed_yoffset; - this->syncfb_config.src_crop_left = this->sc.displayed_xoffset; - this->syncfb_config.src_crop_right = this->sc.displayed_xoffset; - - this->syncfb_config.default_repeat = (this->props[VO_PROP_INTERLACED].value) ? 1 : this->default_repeat; - - if(this->capabilities.palettes & (1<<this->syncfb_config.src_palette)) { - if(ioctl(this->fd,SYNCFB_SET_CONFIG,&this->syncfb_config)) - xprintf(this->xine, XINE_VERBOSITY_DEBUG, "video_out_syncfb: error. (set_config ioctl failed)\n"); - - syncfb_overlay_on(this); - } - } -} - -/* - * public functions defined and used by the xine interface - */ - -static int syncfb_redraw_needed(vo_driver_t* this_gen) -{ - syncfb_driver_t* this = (syncfb_driver_t *) this_gen; - - int ret = 0; - - if( _x_vo_scale_redraw_needed( &this->sc ) ) { - - syncfb_compute_output_size (this); - - syncfb_clean_output_area (this); - - ret = 1; - } - - return ret; -} - -static uint32_t syncfb_get_capabilities (vo_driver_t *this_gen) -{ - syncfb_driver_t *this = (syncfb_driver_t *) this_gen; - - return this->supported_capabilities; -} - -static void syncfb_frame_field (vo_frame_t *vo_img, int which_field) -{ - /* not needed for SyncFB */ -} - -static void syncfb_frame_dispose(vo_frame_t* vo_img) -{ - syncfb_frame_t* frame = (syncfb_frame_t *) vo_img; - - if(frame) { - free_framedata(frame); - free(frame); - } -} - -static vo_frame_t* syncfb_alloc_frame(vo_driver_t* this_gen) -{ - /* syncfb_driver_t *this = (syncfb_driver_t *) this_gen; */ - syncfb_frame_t *frame; - - frame = (syncfb_frame_t *) xine_xmalloc(sizeof(syncfb_frame_t)); - if(!frame) - return NULL; - - pthread_mutex_init(&frame->vo_frame.mutex, NULL); - - frame->vo_frame.base[0] = NULL; - frame->vo_frame.base[1] = NULL; - frame->vo_frame.base[2] = NULL; - - /* - * supply required functions - */ - frame->vo_frame.proc_slice = NULL; - frame->vo_frame.proc_frame = NULL; - frame->vo_frame.field = syncfb_frame_field; - frame->vo_frame.dispose = syncfb_frame_dispose; - - frame->vo_frame.driver = this_gen; - - return (vo_frame_t *) frame; -} - -static void syncfb_update_frame_format(vo_driver_t* this_gen, - vo_frame_t* frame_gen, - uint32_t width, uint32_t height, - double ratio, int format, int flags) -{ - syncfb_driver_t *this = (syncfb_driver_t *) this_gen; - syncfb_frame_t *frame = (syncfb_frame_t *) frame_gen; - /* uint32_t frame_size = width*height; */ - - if((frame->width != width) - || (frame->height != height) - || (frame->format != format)) { - -#ifdef DEBUG_OUTPUT - printf("video_out_syncfb: debug. (update frame format: old values [width=%d, height=%d, format=%04x], new values [width=%d, height=%d, format=%04x])\n", frame->width, frame->height, frame->format, width, height, format); -#endif - free_framedata(frame); - - frame->width = width; - frame->height = height; - frame->format = format; - - switch(format) { - case XINE_IMGFMT_YV12: - frame->vo_frame.pitches[0] = 8*((width + 7) / 8); - frame->vo_frame.pitches[1] = 8*((width + 15) / 16); - frame->vo_frame.pitches[2] = 8*((width + 15) / 16); - frame->vo_frame.base[0] = malloc(frame->vo_frame.pitches[0] * height); - frame->vo_frame.base[1] = malloc(frame->vo_frame.pitches[1] * ((height+1)/2)); - frame->vo_frame.base[2] = malloc(frame->vo_frame.pitches[2] * ((height+1)/2)); - break; - case XINE_IMGFMT_YUY2: - frame->vo_frame.pitches[0] = 8*((width + 3) / 4); - frame->vo_frame.base[0] = malloc(frame->vo_frame.pitches[0] * height); - frame->vo_frame.base[1] = NULL; - frame->vo_frame.base[2] = NULL; - break; - default: - xprintf(this->xine, XINE_VERBOSITY_DEBUG, - "video_out_syncfb: error. (unable to allocate " - "framedata because of unknown frame format: %04x)\n", format); - } - -/* if((format == IMGFMT_YV12 && (frame->data_mem[0] == NULL || frame->data_mem[1] == NULL || frame->data_mem[2] == NULL)) - || (format == IMGFMT_YUY2 && frame->data_mem[0] == NULL)) {*/ - if((format == XINE_IMGFMT_YV12 && (frame->vo_frame.base[0] == NULL || frame->vo_frame.base[1] == NULL || frame->vo_frame.base[2] == NULL)) - || (format == XINE_IMGFMT_YUY2 && frame->vo_frame.base[0] == NULL)) { - xprintf(this->xine, XINE_VERBOSITY_DEBUG, - "video_out_syncfb: error. (framedata allocation failed: out of memory)\n"); - - free_framedata(frame); - } - } - - frame->ratio = ratio; -} - -static void syncfb_overlay_blend(vo_driver_t* this_gen, vo_frame_t* frame_gen, vo_overlay_t* overlay) -{ - syncfb_frame_t* frame = (syncfb_frame_t *) frame_gen; - syncfb_driver_t* this = (syncfb_driver_t *) this_gen; - - this->alphablend_extra_data.offset_x = frame_gen->overlay_offset_x; - this->alphablend_extra_data.offset_y = frame_gen->overlay_offset_y; - - /* alpha blend here */ - if (overlay->rle) { - if (frame->format == XINE_IMGFMT_YV12) - _x_blend_yuv(frame->vo_frame.base, overlay, frame->width, frame->height, frame->vo_frame.pitches, &this->alphablend_extra_data); - else - _x_blend_yuy2(frame->vo_frame.base[0], overlay, frame->width, frame->height, frame->vo_frame.pitches[0], &this->alphablend_extra_data); - } -} - -static void syncfb_display_frame(vo_driver_t* this_gen, vo_frame_t* frame_gen) -{ - syncfb_driver_t* this = (syncfb_driver_t *) this_gen; - syncfb_frame_t* frame = (syncfb_frame_t *) frame_gen; - - this->cur_frame = frame; - - /* - * let's see if this frame is different in size / aspect - * ratio from the previous one - */ - if((frame->width != this->sc.delivered_width) - || (frame->height != this->sc.delivered_height) - || (frame->ratio != this->sc.delivered_ratio)) { -#ifdef DEBUG_OUTPUT - printf("video_out_syncfb: debug. (frame format changed)\n"); -#endif - - this->sc.delivered_width = frame->width; - this->sc.delivered_height = frame->height; - this->sc.delivered_ratio = frame->ratio; - - this->sc.crop_left = frame->vo_frame.crop_left; - this->sc.crop_right = frame->vo_frame.crop_right; - this->sc.crop_top = frame->vo_frame.crop_top; - this->sc.crop_bottom = frame->vo_frame.crop_bottom; - - syncfb_compute_ideal_size(this); - - this->sc.force_redraw = 1; - } - - /* - * tell gui that we are about to display a frame, - * ask for offset and output size - */ - syncfb_redraw_needed(this_gen); - - /* the rest is only successful and safe, if the overlay is really on */ - if(this->overlay_state) { - if(this->bufinfo.id != -1) { - xprintf(this->xine, XINE_VERBOSITY_DEBUG, - "video_out_syncfb: error. (invalid syncfb image buffer state)\n"); - frame->vo_frame.free(&frame->vo_frame); - - return; - } - - if(ioctl(this->fd, SYNCFB_REQUEST_BUFFER, &this->bufinfo)) - xprintf(this->xine, XINE_VERBOSITY_DEBUG, "video_out_syncfb: error. (request ioctl failed)\n"); - - if(this->bufinfo.id == -1) { - xprintf(this->xine, XINE_VERBOSITY_DEBUG, - "video_out_syncfb: error. (syncfb module couldn't allocate image buffer)\n"); - frame->vo_frame.free(&frame->vo_frame); - - /* - * there are several "fixable" situations when this request will fail. - * for example when the screen resolution changes, the kernel module - * will get confused - reinitializing everything will fix things for - * the next frame in that case. - */ - syncfb_compute_ideal_size(this); - syncfb_compute_output_size(this); - syncfb_clean_output_area(this); - - return; - } - - write_frame_sfb(this, frame); - - if(ioctl(this->fd, SYNCFB_COMMIT_BUFFER, &this->bufinfo)) - xprintf(this->xine, XINE_VERBOSITY_DEBUG, "video_out_syncfb: error. (commit ioctl failed)\n"); - } - else - frame->vo_frame.free(&frame->vo_frame); - - this->bufinfo.id = -1; -} - -static int syncfb_get_property(vo_driver_t* this_gen, int property) -{ - syncfb_driver_t* this = (syncfb_driver_t *) this_gen; - - switch (property) { - case VO_PROP_WINDOW_WIDTH: - this->props[property].value = this->sc.gui_width; - break; - case VO_PROP_WINDOW_HEIGHT: - this->props[property].value = this->sc.gui_height; - break; - case VO_PROP_OUTPUT_WIDTH: - this->props[property].value = this->sc.output_width; - break; - case VO_PROP_OUTPUT_HEIGHT: - this->props[property].value = this->sc.output_height; - break; - case VO_PROP_OUTPUT_XOFFSET: - this->props[property].value = this->sc.output_xoffset; - break; - case VO_PROP_OUTPUT_YOFFSET: - this->props[property].value = this->sc.output_yoffset; - break; - } - - return this->props[property].value; -} - -static int syncfb_set_property(vo_driver_t* this_gen, int property, int value) -{ - syncfb_driver_t* this = (syncfb_driver_t *) this_gen; - - switch (property) { - case VO_PROP_INTERLACED: - this->props[property].value = value; - -#ifdef DEBUG_OUTPUT - printf("video_out_syncfb: debug. (VO_PROP_INTERLACED(%d))\n", - this->props[property].value); -#endif - - syncfb_compute_ideal_size(this); - syncfb_compute_output_size(this); - syncfb_clean_output_area(this); - break; - - case VO_PROP_ASPECT_RATIO: - if(value >= XINE_VO_ASPECT_NUM_RATIOS) - value = XINE_VO_ASPECT_AUTO; - - this->props[property].value = value; - this->sc.user_ratio = value; - -#ifdef DEBUG_OUTPUT - printf("video_out_syncfb: debug. (VO_PROP_ASPECT_RATIO(%d))\n", - this->props[property].value); -#endif - - syncfb_compute_ideal_size(this); - syncfb_compute_output_size(this); - syncfb_clean_output_area(this); - break; - - case VO_PROP_ZOOM_X: - if ((value >= XINE_VO_ZOOM_MIN) && (value <= XINE_VO_ZOOM_MAX)) { - this->props[property].value = value; - this->sc.zoom_factor_x = (double)value / (double)XINE_VO_ZOOM_STEP; - - syncfb_compute_ideal_size (this); - - this->sc.force_redraw = 1; - } -/* - printf("video_out_syncfb: info. (the zooming feature is not supported at the moment because of a bug with the SyncFB kernel driver, please refer to README.syncfb)\n"); -*/ - break; - - case VO_PROP_ZOOM_Y: - if ((value >= XINE_VO_ZOOM_MIN) && (value <= XINE_VO_ZOOM_MAX)) { - this->props[property].value = value; - this->sc.zoom_factor_y = (double)value / (double)XINE_VO_ZOOM_STEP; - - syncfb_compute_ideal_size (this); - - this->sc.force_redraw = 1; - } -/* - printf("video_out_syncfb: info. (the zooming feature is not supported at the moment because of a bug with the SyncFB kernel driver, please refer to README.syncfb)\n"); -*/ - break; - - case VO_PROP_CONTRAST: - this->props[property].value = value; - -#ifdef DEBUG_OUTPUT - printf("video_out_syncfb: debug. (VO_PROP_CONTRAST(%d))\n", - this->props[property].value); -#endif - - this->params.contrast = value; - this->params.brightness = this->props[VO_PROP_BRIGHTNESS].value; - this->params.image_width = this->syncfb_config.image_width; /* FIXME */ - this->params.image_height = this->syncfb_config.image_height; - this->params.image_xorg = this->syncfb_config.image_xorg; - this->params.image_yorg = this->syncfb_config.image_yorg; - - if(ioctl(this->fd,SYNCFB_SET_PARAMS,&this->params)) - xprintf(this->xine, XINE_VERBOSITY_DEBUG, - "video_out_syncfb: error. (setting of contrast value failed)\n"); - - break; - - case VO_PROP_BRIGHTNESS: - this->props[property].value = value; - -#ifdef DEBUG_OUTPUT - printf("video_out_syncfb: debug. (VO_PROP_BRIGHTNESS(%d))\n", - this->props[property].value); -#endif - - this->params.brightness = value; - this->params.contrast = this->props[VO_PROP_CONTRAST].value; - this->params.image_width = this->syncfb_config.image_width; /* FIXME */ - this->params.image_height = this->syncfb_config.image_height; - this->params.image_xorg = this->syncfb_config.image_xorg; - this->params.image_yorg = this->syncfb_config.image_yorg; - - if(ioctl(this->fd,SYNCFB_SET_PARAMS,&this->params)) - xprintf(this->xine, XINE_VERBOSITY_DEBUG, - "video_out_syncfb: error. (setting of brightness value failed)\n"); - - break; - } - - return value; -} - -static void syncfb_get_property_min_max(vo_driver_t *this_gen, - int property, int *min, int *max) -{ - syncfb_driver_t* this = (syncfb_driver_t *) this_gen; - - *min = this->props[property].min; - *max = this->props[property].max; -} - -static int syncfb_gui_data_exchange(vo_driver_t* this_gen, int data_type, - void *data) -{ - syncfb_driver_t* this = (syncfb_driver_t *) this_gen; - - switch (data_type) { - case XINE_GUI_SEND_DRAWABLE_CHANGED: - this->drawable = (Drawable) data; - - XLockDisplay (this->display); - XFreeGC(this->display, this->gc); - this->gc = XCreateGC (this->display, this->drawable, 0, NULL); - XUnlockDisplay (this->display); - break; - case XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO: - { - int x1, y1, x2, y2; - x11_rectangle_t *rect = data; - - _x_vo_scale_translate_gui2video(&this->sc, rect->x, rect->y, - &x1, &y1); - _x_vo_scale_translate_gui2video(&this->sc, rect->x + rect->w, rect->y + rect->h, - &x2, &y2); - rect->x = x1; - rect->y = y1; - rect->w = x2-x1; - rect->h = y2-y1; - } - break; - /* - case XINE_GUI_DATA_EX_VIDEOWIN_VISIBLE: - this->video_win_visibility = (int)(int *)data; - syncfb_compute_output_size(this); - break; - */ - - default: - return -1; - } - - return 0; -} - -static void syncfb_dispose(vo_driver_t *this_gen) -{ - syncfb_driver_t *this = (syncfb_driver_t *) this_gen; - - /* get it off the screen - I wanna see my desktop again :-) */ - syncfb_overlay_off(this); - - /* don't know if it is necessary are even right, but anyway...?! */ - munmap(0, this->capabilities.memory_size); - - close(this->fd); - - XLockDisplay (this->display); - XFreeGC(this->display, this->gc); - XUnlockDisplay (this->display); - - _x_alphablend_free(&this->alphablend_extra_data); - - free(this); -} - -static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *visual_gen) { - - syncfb_class_t *class = (syncfb_class_t *) class_gen; - config_values_t *config = class->config; - syncfb_driver_t* this; - Display* display = NULL; - unsigned int i; - x11_visual_t* visual = (x11_visual_t *) visual_gen; - XColor dummy; - XWindowAttributes attr; - - display = visual->display; - - if(!(this = xine_xmalloc(sizeof (syncfb_driver_t)))) - return NULL; - - _x_alphablend_init(&this->alphablend_extra_data, class->xine); - - /* check for syncfb device */ - if((this->fd = open(class->device_name, O_RDWR)) < 0) { - xprintf(class->xine, XINE_VERBOSITY_DEBUG, - "video_out_syncfb: aborting. (unable to open syncfb device \"%s\")\n", class->device_name); - free(this); - return NULL; - } - - this->xine = class->xine; - - /* get capabilities from the syncfb module */ - if(ioctl(this->fd, SYNCFB_GET_CAPS, &this->capabilities)) { - xprintf(this->xine, XINE_VERBOSITY_DEBUG, - "video_out_syncfb: aborting. (syncfb_get_caps ioctl failed)\n"); - - close(this->fd); - free(this); - - return NULL; - } - - /* mmap whole video memory */ - this->video_mem = (uint8_t *) mmap(0, this->capabilities.memory_size, PROT_WRITE, MAP_SHARED, this->fd, 0); - - if(this->video_mem == MAP_FAILED) { - xprintf(this->xine, XINE_VERBOSITY_DEBUG, - "video_out_syncfb: aborting. (mmap of video memory failed)\n"); - - close(this->fd); - free(this); - - return NULL; - } - - /* - * init properties and capabilities - */ - for (i = 0; i<VO_NUM_PROPERTIES; i++) { - this->props[i].value = 0; - this->props[i].min = 0; - this->props[i].max = 0; - } - - this->props[VO_PROP_INTERLACED].value = 0; - this->sc.user_ratio = this->props[VO_PROP_ASPECT_RATIO].value = XINE_VO_ASPECT_AUTO; - this->props[VO_PROP_ZOOM_X].value = 100; - this->props[VO_PROP_ZOOM_Y].value = 100; - - /* check for formats we need... */ - this->supported_capabilities = VO_CAP_CROP; - this->yuv_format = 0; - - /* - * simple fallback mechanism - we want YUV 4:2:0 (3 plane) but we can also - * convert YV12 material to YUV 4:2:0 (2 plane) and YUV 4:2:2 ... - */ - if(this->capabilities.palettes & (1<<VIDEO_PALETTE_YUV420P3)) { - this->supported_capabilities |= VO_CAP_YV12; - this->yuv_format = VIDEO_PALETTE_YUV420P3; - xprintf(this->xine, XINE_VERBOSITY_LOG, - _("video_out_syncfb: info. (SyncFB module supports YUV 4:2:0 (3 plane))\n")); - } else if(this->capabilities.palettes & (1<<VIDEO_PALETTE_YUV420P2)) { - this->supported_capabilities |= VO_CAP_YV12; - this->yuv_format = VIDEO_PALETTE_YUV420P2; - xprintf(this->xine, XINE_VERBOSITY_LOG, - _("video_out_syncfb: info. (SyncFB module supports YUV 4:2:0 (2 plane))\n")); - } else if(this->capabilities.palettes & (1<<VIDEO_PALETTE_YUV422)) { - this->supported_capabilities |= VO_CAP_YV12; - this->yuv_format = VIDEO_PALETTE_YUV422; - xprintf(this->xine, XINE_VERBOSITY_DEBUG, - _("video_out_syncfb: info. (SyncFB module supports YUV 4:2:2)\n")); - } - - if(this->capabilities.palettes & (1<<VIDEO_PALETTE_YUV422)) { - this->supported_capabilities |= VO_CAP_YUY2; - xprintf(this->xine, XINE_VERBOSITY_DEBUG, - _("video_out_syncfb: info. (SyncFB module supports YUY2)\n")); - } - if(this->capabilities.palettes & (1<<VIDEO_PALETTE_RGB565)) { - /* FIXME: no RGB support yet - * this->supported_capabilities |= VO_CAP_RGB; - */ - xprintf(this->xine, XINE_VERBOSITY_DEBUG, - _("video_out_syncfb: info. (SyncFB module supports RGB565)\n")); - } - - if(!this->supported_capabilities) { - xprintf(this->xine, XINE_VERBOSITY_DEBUG, - _("video_out_syncfb: aborting. (SyncFB module does not support YV12, YUY2 nor RGB565)\n")); - - munmap(0, this->capabilities.memory_size); - close(this->fd); - free(this); - - return NULL; - } - - if(ioctl(this->fd,SYNCFB_GET_PARAMS,&this->params) == 0) { - this->props[VO_PROP_CONTRAST].value = this->params.contrast; - this->props[VO_PROP_CONTRAST].min = 0; - this->props[VO_PROP_CONTRAST].max = 255; - - this->props[VO_PROP_BRIGHTNESS].value = this->params.brightness; - this->props[VO_PROP_BRIGHTNESS].min = -128; - this->props[VO_PROP_BRIGHTNESS].max = 127; - } else { - xprintf(this->xine, XINE_VERBOSITY_LOG, - _("video_out_syncfb: info. (brightness/contrast control won\'t be available because " - "your SyncFB kernel module seems to be outdated. Please refer to README." - "syncfb for informations on how to update it.)\n")); - } - - /* check for virtual screen size and screen depth - this is rather important - because that data is later used for free memory calculation */ - XGetWindowAttributes(visual->display, DefaultRootWindow(visual->display), &attr); - - this->virtual_screen_height = attr.height; - this->virtual_screen_width = attr.width; - this->screen_depth = attr.depth; - - /* initialize the rest of the variables now with default values */ - this->bufinfo.id = -1; - this->config = config; - this->cur_frame = NULL; - - /* FIXME: setting the default_repeat to anything higher than 1 will result - in a distorted video, so for now, set this manually to 0 until - the kernel driver is fixed... */ -#if 0 - this->default_repeat = config->register_range(config, - "video.device.syncfb_default_repeat", 3, 1, 4, - _("default number of frame repetitions"), - _("This specifies how many times a single video " - "frame will be displayed consecutively."), - 10, NULL, NULL); -#endif - this->default_repeat = 0; - - this->display = visual->display; - this->drawable = visual->d; - this->gc = XCreateGC (this->display, this->drawable, 0, NULL); - - _x_vo_scale_init (&this->sc, 1, 0, config ); - this->sc.frame_output_cb = visual->frame_output_cb; - this->sc.user_data = visual->user_data; - - this->overlay = NULL; - this->screen = visual->screen; - this->video_win_visibility = 1; - - XAllocNamedColor(this->display, - DefaultColormap(this->display, this->screen), - "black", &this->black, &dummy); - - this->vo_driver.get_capabilities = syncfb_get_capabilities; - this->vo_driver.alloc_frame = syncfb_alloc_frame; - this->vo_driver.update_frame_format = syncfb_update_frame_format; - this->vo_driver.overlay_begin = NULL; /* not used */ - this->vo_driver.overlay_blend = syncfb_overlay_blend; - this->vo_driver.overlay_end = NULL; /* not used */ - this->vo_driver.display_frame = syncfb_display_frame; - this->vo_driver.get_property = syncfb_get_property; - this->vo_driver.set_property = syncfb_set_property; - this->vo_driver.get_property_min_max = syncfb_get_property_min_max; - this->vo_driver.gui_data_exchange = syncfb_gui_data_exchange; - this->vo_driver.dispose = syncfb_dispose; - this->vo_driver.redraw_needed = syncfb_redraw_needed; - - return &this->vo_driver; -} - -/* - * class functions - */ -static void *init_class (xine_t *xine, void *visual_gen) { - - syncfb_class_t *this; - char* device_name; - int fd; - - device_name = xine->config->register_filename(xine->config, "video.device.syncfb_device", "/dev/syncfb", - XINE_CONFIG_STRING_IS_DEVICE_NAME, - _("SyncFB device name"), - _("Specifies the file name for the SyncFB (TeleTux) device " - "to be used.\nThis setting is security critical, " - "because when changed to a different file, xine " - "can be used to fill this file with arbitrary content. " - "So you should be careful that the value you enter " - "really is a proper framebuffer device."), - XINE_CONFIG_SECURITY, NULL, NULL); - - /* check for syncfb device */ - if((fd = open(device_name, O_RDWR)) < 0) { - xprintf(xine, XINE_VERBOSITY_DEBUG, - "video_out_syncfb: aborting. (unable to open syncfb device \"%s\")\n", device_name); - return NULL; - } - close(fd); - - /* - * from this point on, nothing should go wrong anymore - */ - this = (syncfb_class_t *) xine_xmalloc (sizeof (syncfb_class_t)); - - this->driver_class.open_plugin = open_plugin; - this->driver_class.identifier = "SyncFB"; - this->driver_class.description = N_("xine video output plugin using the SyncFB module for Matrox G200/G400 cards"); - this->driver_class.dispose = default_video_driver_class_dispose; - - this->config = xine->config; - this->xine = xine; - this->device_name = device_name; - - return this; -} - -static const vo_info_t vo_info_syncfb = { - 7, /* priority */ - XINE_VISUAL_TYPE_X11 /* visual type */ -}; - -/* - * exported plugin catalog entry - */ - -const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ - { PLUGIN_VIDEO_OUT, 22, "SyncFB", XINE_VERSION_CODE, &vo_info_syncfb, init_class }, - { PLUGIN_NONE, 0, "", 0, NULL, NULL } -}; - diff --git a/src/video_out/video_out_syncfb.h b/src/video_out/video_out_syncfb.h deleted file mode 100644 index 1fc3df83a..000000000 --- a/src/video_out/video_out_syncfb.h +++ /dev/null @@ -1,236 +0,0 @@ -#ifndef __LINUX_SYNCFB_H -#define __LINUX_SYNCFB_H - -#ifdef __KERNEL__ -#include <linux/version.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/malloc.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/videodev.h> - -#include <asm/mtrr.h> -#include <asm/uaccess.h> -#include <asm/system.h> -#include <asm/io.h> - -#define TRUE 1 -#define FALSE 0 - -#define SFB_STATUS_FREE 0 -#define SFB_STATUS_OFFS 1 -#define SFB_STATUS_WAIT 2 -#define SFB_STATUS_LIVE 3 - -#endif /* KERNEL */ - - -#ifndef AARONS_TYPES -typedef unsigned long uint_32; -typedef unsigned char uint_8; -#endif - -#define SYNCFB_MAJOR 178 - -#define SYNCFB_ERROR_NO_ERROR 0; -#define SYNCFB_ERROR_NO_BUFFER_AVAILABLE 1; -#define SYNCFB_ERROR_PALETTE_NOT_SUPPORTED 2; -#define SYNCFB_ERROR_NOT_ENOUGH_MEMORY 3; - - - -#ifndef __LINUX_VIDEODEV_H -#define VIDEO_PALETTE_GREY 1 /* Linear greyscale */ -#define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */ -#define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */ -#define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */ -#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */ -#define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */ -#define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */ -#define VIDEO_PALETTE_YUYV 8 -#define VIDEO_PALETTE_UYVY 9 /* The great thing about standards is ... */ -#define VIDEO_PALETTE_YUV420 10 -#define VIDEO_PALETTE_YUV411 11 /* YUV411 capture */ -#define VIDEO_PALETTE_RAW 12 /* RAW capture (BT848) */ -#define VIDEO_PALETTE_YUV422P 13 /* YUV 4:2:2 Planar */ -#define VIDEO_PALETTE_YUV411P 14 /* YUV 4:1:1 Planar */ -#define VIDEO_PALETTE_YUV420P 15 /* YUV 4:2:0 Planar */ -#define VIDEO_PALETTE_YUV410P 16 /* YUV 4:1:0 Planar */ -#define VIDEO_PALETTE_PLANAR 13 /* start of planar entries */ -#define VIDEO_PALETTE_COMPONENT 7 /* start of component entries */ -#endif - - -#define VIDEO_PALETTE_YUV422P3 13 /* YUV 4:2:2 Planar (3 Plane, same as YUV422P) */ -#define VIDEO_PALETTE_YUV422P2 17 /* YUV 4:2:2 Planar (2 Plane) */ - -#define VIDEO_PALETTE_YUV411P3 14 /* YUV 4:1:1 Planar (3 Plane, same as YUV411P) */ -#define VIDEO_PALETTE_YUV411P2 18 /* YUV 4:1:1 Planar (2 Plane) */ - -#define VIDEO_PALETTE_YUV420P3 15 /* YUV 4:2:0 Planar (3 Plane, same as YUV420P) */ -#define VIDEO_PALETTE_YUV420P2 19 /* YUV 4:2:0 Planar (2 Plane) */ - -#define VIDEO_PALETTE_YUV410P3 16 /* YUV 4:1:0 Planar (3 Plane, same as YUV410P) */ -#define VIDEO_PALETTE_YUV410P2 20 /* YUV 4:1:0 Planar (2 Plane) */ - - - -#define SYNCFB_FEATURE_SCALE_H 1 -#define SYNCFB_FEATURE_SCALE_V 2 -#define SYNCFB_FEATURE_SCALE 3 -#define SYNCFB_FEATURE_CROP 4 -#define SYNCFB_FEATURE_OFFSET 8 -#define SYNCFB_FEATURE_DEINTERLACE 16 -#define SYNCFB_FEATURE_PROCAMP 32 -#define SYNCFB_FEATURE_TRANSITIONS 64 -#define SYNCFB_FEATURE_COLKEY 128 -#define SYNCFB_FEATURE_MIRROR_H 256 -#define SYNCFB_FEATURE_MIRROR_V 512 -#define SYNCFB_FEATURE_BLOCK_REQUEST 1024 -#define SYNCFB_FEATURE_FREQDIV2 2048 - - -typedef struct syncfb_config_s -{ - uint_32 syncfb_mode; /* bitfield: turn on/off the available features */ - uint_32 error_code; /* RO: returns 0 on successful config calls, error code otherwise */ - - uint_32 fb_screen_size; /* WO, size in bytes of video memory reserved for fbdev */ - uint_32 fb_screen_width; /* WO, visible screen width in pixel */ - uint_32 fb_screen_height; /* WO, visible screen height in pixel */ - - uint_32 buffers; /* RO, number of available buffers */ - uint_32 buffer_size; /* RO, filled in by syncfb */ - - uint_32 default_repeat; /* default repeat time for a single frame, can be overridden in syncfb_buffer_info_t */ - - uint_32 src_width; /* source image width in pixel */ - uint_32 src_height; /* source image height in pixel */ - uint_32 src_palette; /* set palette mode, see videodev.h for palettes */ - uint_32 src_pitch; /* RO: filled in by ioctl: actual line length in pixel */ - - uint_32 image_xorg; /* x position of the image on the screen */ - uint_32 image_yorg; /* y position of the image on the screen */ - - /* if syncfb has FEATURE_SCALE */ - uint_32 scale_filters; /* 0: no filtering, 255: all filters on */ - uint_32 image_width; /* onscreen image width */ - uint_32 image_height; /* onscreen image height */ - - /* if syncfb has FEATURE_CROP */ - uint_32 src_crop_left; /* */ - uint_32 src_crop_right; /* */ - uint_32 src_crop_top; /* */ - uint_32 src_crop_bot; /* */ - - /* if syncfb has FEATURE_OFFSET */ - uint_32 image_offset_left; /* */ - uint_32 image_offset_right; /* */ - uint_32 image_offset_top; /* */ - uint_32 image_offset_bot; /* */ - - /* if syncfb has FEATURE_COLKEY */ - uint_8 colkey_red; - uint_8 colkey_green; - uint_8 colkey_blue; - -} syncfb_config_t; - - -/* - picture parameters, -*/ -typedef struct syncfb_param_s -{ - /* the idea is to enable smooth transitions between eg. image sizes (not yet implemented) */ - /* if syncfb has FEATURE_TRANSITIONS */ - uint_32 transition_time; - - /* if syncfb has FEATURE_PROCAMP */ - uint_32 contrast; /* 0: least contrast, 1000: normal contrast, */ - uint_32 brightness; - uint_32 color; /* for syncfb_matrox: color=0: b/w else: full color */ - - /* if syncfb has FEATURE_SCALE , currently only supported in CONFIG call */ - uint_8 scale_filters; /* 0: no filtering, 255: all filters on */ - uint_32 image_xorg; /* x position of the image on the screen */ - uint_32 image_yorg; /* y position of the image on the screen */ - uint_32 image_width; /* onscreen image width */ - uint_32 image_height; /* onscreen image height */ - -} syncfb_param_t; - - - -typedef struct syncfb_status_info_s -{ - uint_32 field_cnt; /* basically all vbi's since the start of syncfb */ - uint_32 frame_cnt; /* number of frames comitted & output */ - - uint_32 hold_field_cnt; /* number of repeated fields becaus no new data was available */ - uint_32 skip_field_cnt; /* skipped fields when fifo was about to fill up */ - - uint_32 request_frames; /* number of request_buffer calls */ - uint_32 commit_frames; /* number of commit_buffer calls */ - - uint_32 failed_requests; /* number of calls to request_buffer that failed */ - - uint_32 buffers_waiting; - uint_32 buffers_free; - -} syncfb_status_info_t; - - - - -typedef struct syncfb_capability_s -{ - char name[64]; /* A name for the syncfb ... */ - uint_32 palettes; /* supported palettes - see videodev.h for palettes, test the corresponding bit here */ - uint_32 features; /* supported features - see SYNCFB_FEATURE_* */ - uint_32 memory_size; /* total size of mappable video memory */ - -} syncfb_capability_t; - - - -typedef struct syncfb_buffer_info_s -{ - int id; /* buffer id: a return value of -1 means no buffer available */ - uint_32 repeat; /* the buffer will be shown <repeat> times */ - uint_32 offset; /* buffer offset from start of video memory */ - uint_32 offset_p2; /* yuv plane 2 buffer offset from start of video memory */ - uint_32 offset_p3; /* yuv plane 3 buffer offset from start of video memory */ - -} syncfb_buffer_info_t; - - - - - - - -/* get syncfb capabilities */ -#define SYNCFB_GET_CAPS _IOR('J', 1, syncfb_config_t) - -#define SYNCFB_GET_CONFIG _IOR('J', 2, syncfb_config_t) -#define SYNCFB_SET_CONFIG _IOR('J', 3, syncfb_config_t) -#define SYNCFB_ON _IO ('J', 4) -#define SYNCFB_OFF _IO ('J', 5) -#define SYNCFB_REQUEST_BUFFER _IOR ('J', 6, syncfb_buffer_info_t) -#define SYNCFB_COMMIT_BUFFER _IOR ('J', 7, syncfb_buffer_info_t) -#define SYNCFB_STATUS _IOR ('J', 8, syncfb_status_info_t) -#define SYNCFB_VBI _IO ('J', 9) /* simulate interrupt - debugging only */ -#define SYNCFB_SET_PARAMS _IOR('J', 10, syncfb_param_t) -#define SYNCFB_GET_PARAMS _IOR('J', 11, syncfb_param_t) - - - - -#endif /* __LINUX_SYNCFB_H */ - diff --git a/src/video_out/video_out_vidix.c b/src/video_out/video_out_vidix.c index f4b74ad2a..586268513 100644 --- a/src/video_out/video_out_vidix.c +++ b/src/video_out/video_out_vidix.c @@ -964,7 +964,7 @@ static vidix_driver_t *open_plugin (video_driver_class_t *class_gen) { this->config = config; this->got_frame_data = 0; - this->capabilities = VO_CAP_CROP; + this->capabilities = VO_CAP_CROP | VO_CAP_ZOOM_X | VO_CAP_ZOOM_Y; /* Find what equalizer flags are supported */ if(this->vidix_cap.flags & FLAG_EQUALIZER) { @@ -973,24 +973,28 @@ static vidix_driver_t *open_plugin (video_driver_class_t *class_gen) { "video_out_vidix: couldn't get equalizer capabilities: %s\n", strerror(err)); } else { if(this->vidix_eq.cap & VEQ_CAP_BRIGHTNESS) { + this->capabilities |= VO_CAP_BRIGHTNESS; this->props[VO_PROP_BRIGHTNESS].value = 0; this->props[VO_PROP_BRIGHTNESS].min = -1000; this->props[VO_PROP_BRIGHTNESS].max = 1000; } if(this->vidix_eq.cap & VEQ_CAP_CONTRAST) { + this->capabilities |= VO_CAP_CONTRAST; this->props[VO_PROP_CONTRAST].value = 0; this->props[VO_PROP_CONTRAST].min = -1000; this->props[VO_PROP_CONTRAST].max = 1000; } if(this->vidix_eq.cap & VEQ_CAP_SATURATION) { + this->capabilities |= VO_CAP_SATURATION; this->props[VO_PROP_SATURATION].value = 0; this->props[VO_PROP_SATURATION].min = -1000; this->props[VO_PROP_SATURATION].max = 1000; } if(this->vidix_eq.cap & VEQ_CAP_HUE) { + this->capabilities |= VO_CAP_HUE; this->props[VO_PROP_HUE].value = 0; this->props[VO_PROP_HUE].min = -1000; this->props[VO_PROP_HUE].max = 1000; diff --git a/src/video_out/video_out_xcbshm.c b/src/video_out/video_out_xcbshm.c index e8fd33860..7443529d1 100644 --- a/src/video_out/video_out_xcbshm.c +++ b/src/video_out/video_out_xcbshm.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000-2003, 2007 the xine project + * Copyright (C) 2000-2003, 2007-2008 the xine project * * This file is part of xine, a free video player. * @@ -222,7 +222,7 @@ static void dispose_ximage(xshm_driver_t *this, xshm_frame_t *frame) static uint32_t xshm_get_capabilities (vo_driver_t *this_gen) { xshm_driver_t *this = (xshm_driver_t *) this_gen; - uint32_t capabilities = VO_CAP_YV12 | VO_CAP_YUY2; + uint32_t capabilities = VO_CAP_YV12 | VO_CAP_YUY2 | VO_CAP_BRIGHTNESS | VO_CAP_CONTRAST | VO_CAP_SATURATION; if( this->xoverlay ) capabilities |= VO_CAP_UNSCALED_OVERLAY; @@ -740,45 +740,43 @@ static int xshm_set_property (vo_driver_t *this_gen, int property, int value) { xshm_driver_t *this = (xshm_driver_t *) this_gen; - if ( property == VO_PROP_ASPECT_RATIO) { - + switch (property) { + case VO_PROP_ASPECT_RATIO: if (value>=XINE_VO_ASPECT_NUM_RATIOS) value = XINE_VO_ASPECT_AUTO; this->sc.user_ratio = value; xprintf(this->xine, XINE_VERBOSITY_DEBUG, LOG_MODULE ": aspect ratio changed to %s\n", _x_vo_scale_aspect_ratio_name_table[value]); + break; - } else if (property == VO_PROP_BRIGHTNESS) { - + case VO_PROP_BRIGHTNESS: this->yuv2rgb_brightness = value; this->yuv2rgb_factory->set_csc_levels (this->yuv2rgb_factory, this->yuv2rgb_brightness, this->yuv2rgb_contrast, this->yuv2rgb_saturation); - this->sc.force_redraw = 1; + break; - } else if (property == VO_PROP_CONTRAST) { - + case VO_PROP_CONTRAST: this->yuv2rgb_contrast = value; this->yuv2rgb_factory->set_csc_levels (this->yuv2rgb_factory, this->yuv2rgb_brightness, this->yuv2rgb_contrast, this->yuv2rgb_saturation); - this->sc.force_redraw = 1; + break; - } else if (property == VO_PROP_SATURATION) { - + case VO_PROP_SATURATION: this->yuv2rgb_saturation = value; this->yuv2rgb_factory->set_csc_levels (this->yuv2rgb_factory, this->yuv2rgb_brightness, this->yuv2rgb_contrast, this->yuv2rgb_saturation); - this->sc.force_redraw = 1; + break; - } else { + default: xprintf (this->xine, XINE_VERBOSITY_DEBUG, LOG_MODULE ": tried to set unsupported property %d\n", property); } diff --git a/src/video_out/video_out_xcbxv.c b/src/video_out/video_out_xcbxv.c index 19a387732..d77917a70 100644 --- a/src/video_out/video_out_xcbxv.c +++ b/src/video_out/video_out_xcbxv.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000-2004, 2007 the xine project + * Copyright (C) 2000-2004, 2007-2008 the xine project * * This file is part of xine, a free video player. * @@ -64,6 +64,7 @@ #include <xine/xineutils.h> #include <xine/vo_scale.h> #include "xcbosd.h" +#include "xv_common.h" typedef struct xv_driver_s xv_driver_t; @@ -944,6 +945,8 @@ static int xv_check_yv12(xcb_connection_t *connection, xcb_xv_port_t port) { list_formats_cookie = xcb_xv_list_image_formats(connection, port); list_formats_reply = xcb_xv_list_image_formats_reply(connection, list_formats_cookie, NULL); + if (!list_formats_reply) + return 1; /* no formats listed; probably due to an invalid port no. */ format_it = xcb_xv_list_image_formats_format_iterator(list_formats_reply); for (; format_it.rem; xcb_xv_image_format_info_next(&format_it)) @@ -965,7 +968,7 @@ static void xv_check_capability (xv_driver_t *this, char *config_help) { int int_default; cfg_entry_t *entry; - char *str_prop = xcb_xv_attribute_info_name(attr); + const char *str_prop = xcb_xv_attribute_info_name(attr); xcb_xv_get_port_attribute_cookie_t get_attribute_cookie; xcb_xv_get_port_attribute_reply_t *get_attribute_reply; @@ -1083,19 +1086,87 @@ static void xv_update_XV_DOUBLE_BUFFER(void *this_gen, xine_cfg_entry_t *entry) LOG_MODULE ": double buffering mode = %d\n", xv_double_buffer); } +static void xv_update_XV_SYNC_TO_VBLANK(void *this_gen, xine_cfg_entry_t *entry) { + xv_driver_t *this = (xv_driver_t *) this_gen; + int xv_sync_to_vblank; + + xcb_intern_atom_cookie_t atom_cookie; + xcb_intern_atom_reply_t *atom_reply; + + xv_sync_to_vblank = entry->num_value; + + pthread_mutex_lock(&this->main_mutex); + atom_cookie = xcb_intern_atom(this->connection, 0, sizeof("XV_SYNC_TO_VBLANK"), "XV_SYNC_TO_VBLANK"); + atom_reply = xcb_intern_atom_reply(this->connection, atom_cookie, NULL); + xcb_xv_set_port_attribute(this->connection, this->xv_port, atom_reply->atom, xv_sync_to_vblank); + free(atom_reply); + pthread_mutex_unlock(&this->main_mutex); + + xprintf(this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xcbxv: sync to vblank = %d\n", xv_sync_to_vblank); +} + + static void xv_update_xv_pitch_alignment(void *this_gen, xine_cfg_entry_t *entry) { xv_driver_t *this = (xv_driver_t *) this_gen; this->use_pitch_alignment = entry->num_value; } +static xcb_xv_port_t xv_open_port (xv_driver_t *this, xcb_xv_port_t port) { + xcb_xv_grab_port_cookie_t grab_port_cookie; + xcb_xv_grab_port_reply_t *grab_port_reply; + + if (xv_check_yv12 (this->connection, port)) + return 0; + + grab_port_cookie = xcb_xv_grab_port (this->connection, port, XCB_CURRENT_TIME); + grab_port_reply = xcb_xv_grab_port_reply (this->connection, grab_port_cookie, NULL); + + if (grab_port_reply && (grab_port_reply->result == XCB_GRAB_STATUS_SUCCESS)) + { + free (grab_port_reply); + return port; + } + free (grab_port_reply); + return 0; +} + +static xcb_xv_adaptor_info_iterator_t * +xv_find_adaptor_by_port (int port, xcb_xv_adaptor_info_iterator_t *adaptor_it) +{ + for (; adaptor_it->rem; xcb_xv_adaptor_info_next(adaptor_it)) + if (adaptor_it->data->type & XCB_XV_TYPE_IMAGE_MASK) + if (port >= adaptor_it->data->base_id && + port < adaptor_it->data->base_id + adaptor_it->data->num_ports) + return adaptor_it; + return NULL; /* shouldn't happen */ +} + +static xcb_xv_port_t xv_autodetect_port(xv_driver_t *this, + xcb_xv_adaptor_info_iterator_t *adaptor_it, + xcb_xv_port_t base) +{ + for (; adaptor_it->rem; xcb_xv_adaptor_info_next(adaptor_it)) + if (adaptor_it->data->type & XCB_XV_TYPE_IMAGE_MASK) + { + int j; + for (j = 0; j < adaptor_it->data->num_ports; ++j) + { + xcb_xv_port_t port = adaptor_it->data->base_id + j; + if (port >= base && xv_open_port (this, port)) + return port; + } + } + return 0; +} + static vo_driver_t *open_plugin(video_driver_class_t *class_gen, const void *visual_gen) { xv_class_t *class = (xv_class_t *) class_gen; config_values_t *config = class->config; xv_driver_t *this; int i; xcb_visual_t *visual = (xcb_visual_t *) visual_gen; - unsigned int j; xcb_xv_port_t xv_port; const xcb_query_extension_reply_t *query_extension_reply; @@ -1146,28 +1217,21 @@ static vo_driver_t *open_plugin(video_driver_class_t *class_gen, const void *vis } adaptor_it = xcb_xv_query_adaptors_info_iterator(query_adaptors_reply); - - xv_port = 0; - - for (; adaptor_it.rem && !xv_port; xcb_xv_adaptor_info_next(&adaptor_it)) { - - if (adaptor_it.data->type & XCB_XV_TYPE_IMAGE_MASK) { - - for (j = 0; j < adaptor_it.data->num_ports; j++) - if (!xv_check_yv12(this->connection, adaptor_it.data->base_id + j)) { - xcb_xv_grab_port_cookie_t grab_port_cookie; - xcb_xv_grab_port_reply_t *grab_port_reply; - grab_port_cookie = xcb_xv_grab_port(this->connection, adaptor_it.data->base_id + j, XCB_CURRENT_TIME); - grab_port_reply = xcb_xv_grab_port_reply(this->connection, grab_port_cookie, NULL); - if (grab_port_reply && (grab_port_reply->result == XCB_GRAB_STATUS_SUCCESS)) { - free(grab_port_reply); - xv_port = adaptor_it.data->base_id + j; - break; - } - free(grab_port_reply); - } - } + xv_port = config->register_num (config, "video.device.xv_port", 0, + VIDEO_DEVICE_XV_PORT_HELP, + 10, NULL, NULL); + + if (xv_port != 0) { + if (! xv_open_port(this, xv_port)) { + xprintf(class->xine, XINE_VERBOSITY_NONE, + _("%s: could not open Xv port %d - autodetecting\n"), + LOG_MODULE, xv_port); + xv_port = xv_autodetect_port (this, &adaptor_it, xv_port); + } else + xv_find_adaptor_by_port (xv_port, &adaptor_it); } + if (!xv_port) + xv_port = xv_autodetect_port (this, &adaptor_it, 0); if (!xv_port) { xprintf(class->xine, XINE_VERBOSITY_LOG, @@ -1192,7 +1256,7 @@ static vo_driver_t *open_plugin(video_driver_class_t *class_gen, const void *vis this->gc = xcb_generate_id(this->connection); xcb_create_gc(this->connection, this->gc, this->window, 0, NULL); - this->capabilities = VO_CAP_CROP; + this->capabilities = VO_CAP_CROP | VO_CAP_ZOOM_X | VO_CAP_ZOOM_Y; this->use_shm = 1; this->use_colorkey = 0; this->colorkey = 0; @@ -1245,75 +1309,72 @@ static vo_driver_t *open_plugin(video_driver_class_t *class_gen, const void *vis for (; attribute_it.rem; xcb_xv_attribute_info_next(&attribute_it)) { if ((attribute_it.data->flags & XCB_XV_ATTRIBUTE_FLAG_SETTABLE) && (attribute_it.data->flags & XCB_XV_ATTRIBUTE_FLAG_GETTABLE)) { + const char *const name = xcb_xv_attribute_info_name(attribute_it.data); /* store initial port attribute value */ - xv_store_port_attribute(this, xcb_xv_attribute_info_name(attribute_it.data)); - - if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_HUE")) { + xv_store_port_attribute(this, name); + + if(!strcmp(name, "XV_HUE")) { if (!strncmp(xcb_xv_adaptor_info_name(adaptor_it.data), "NV", 2)) { xprintf (this->xine, XINE_VERBOSITY_NONE, LOG_MODULE ": ignoring broken XV_HUE settings on NVidia cards\n"); } else { + this->capabilities |= VO_CAP_HUE; xv_check_capability (this, VO_PROP_HUE, attribute_it.data, adaptor_it.data->base_id, NULL, NULL, NULL); } - } else if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_SATURATION")) { + } else if(!strcmp(name, "XV_SATURATION")) { + this->capabilities |= VO_CAP_SATURATION; xv_check_capability (this, VO_PROP_SATURATION, attribute_it.data, adaptor_it.data->base_id, NULL, NULL, NULL); - - } else if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_BRIGHTNESS")) { + } else if(!strcmp(name, "XV_BRIGHTNESS")) { + this->capabilities |= VO_CAP_BRIGHTNESS; xv_check_capability (this, VO_PROP_BRIGHTNESS, attribute_it.data, adaptor_it.data->base_id, NULL, NULL, NULL); - - } else if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_CONTRAST")) { + } else if(!strcmp(name, "XV_CONTRAST")) { + this->capabilities |= VO_CAP_CONTRAST; xv_check_capability (this, VO_PROP_CONTRAST, attribute_it.data, adaptor_it.data->base_id, NULL, NULL, NULL); - - } else if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_COLORKEY")) { + } else if(!strcmp(name, "XV_COLORKEY")) { + this->capabilities |= VO_CAP_COLORKEY; xv_check_capability (this, VO_PROP_COLORKEY, attribute_it.data, adaptor_it.data->base_id, "video.device.xv_colorkey", - _("video overlay colour key"), - _("The colour key is used to tell the graphics card where to " - "overlay the video image. Try different values, if you experience " - "windows becoming transparent.")); - - } else if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_AUTOPAINT_COLORKEY")) { + VIDEO_DEVICE_XV_COLORKEY_HELP); + } else if(!strcmp(name, "XV_AUTOPAINT_COLORKEY")) { + this->capabilities |= VO_CAP_AUTOPAINT_COLORKEY; xv_check_capability (this, VO_PROP_AUTOPAINT_COLORKEY, attribute_it.data, adaptor_it.data->base_id, "video.device.xv_autopaint_colorkey", - _("autopaint colour key"), - _("Make Xv autopaint its colour key.")); - - } else if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_FILTER")) { + VIDEO_DEVICE_XV_AUTOPAINT_COLORKEY_HELP); + } else if(!strcmp(name, "XV_FILTER")) { int xv_filter; /* This setting is specific to Permedia 2/3 cards. */ xv_filter = config->register_range (config, "video.device.xv_filter", 0, attribute_it.data->min, attribute_it.data->max, - _("bilinear scaling mode"), - _("Selects the bilinear scaling mode for Permedia cards. " - "The individual values are:\n\n" - "Permedia 2\n" - "0 - disable bilinear filtering\n" - "1 - enable bilinear filtering\n\n" - "Permedia 3\n" - "0 - disable bilinear filtering\n" - "1 - horizontal linear filtering\n" - "2 - enable full bilinear filtering"), + VIDEO_DEVICE_XV_FILTER_HELP, 20, xv_update_XV_FILTER, this); config->update_num(config,"video.device.xv_filter",xv_filter); - } else if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_DOUBLE_BUFFER")) { - int xv_double_buffer; - xv_double_buffer = + } else if(!strcmp(name, "XV_DOUBLE_BUFFER")) { + int xv_double_buffer = config->register_bool (config, "video.device.xv_double_buffer", 1, - _("enable double buffering"), - _("Double buffering will synchronize the update of the video image to the " - "repainting of the entire screen (\"vertical retrace\"). This eliminates " - "flickering and tearing artifacts, but will use more graphics memory."), - 20, xv_update_XV_DOUBLE_BUFFER, this); + VIDEO_DEVICE_XV_DOUBLE_BUFFER_HELP, + 20, xv_update_XV_DOUBLE_BUFFER, this); config->update_num(config,"video.device.xv_double_buffer",xv_double_buffer); + } else if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_SYNC_TO_VBLANK")) { + int xv_sync_to_vblank; + xv_sync_to_vblank = + config->register_bool (config, "video.device.xv_sync_to_vblank", 1, + _("enable vblank sync"), + _("This option will synchronize the update of the video image to the " + "repainting of the entire screen (\"vertical retrace\"). This eliminates " + "flickering and tearing artifacts. On nvidia cards one may also " + "need to run \"nvidia-settings\" and choose which display device to " + "sync to under the XVideo Settings tab"), + 20, xv_update_XV_SYNC_TO_VBLANK, this); + config->update_num(config,"video.device.xv_sync_to_vblank",xv_sync_to_vblank); } } } @@ -1341,16 +1402,21 @@ static vo_driver_t *open_plugin(video_driver_class_t *class_gen, const void *vis (format_it.data->format == XCB_XV_IMAGE_FORMAT_INFO_FORMAT_PACKED) ? "packed" : "planar"); - if (format_it.data->id == XINE_IMGFMT_YV12) { + switch (format_it.data->id) { + case XINE_IMGFMT_YV12: this->xv_format_yv12 = format_it.data->id; this->capabilities |= VO_CAP_YV12; xprintf(this->xine, XINE_VERBOSITY_LOG, - _("%s: this adaptor supports the yv12 format.\n"), LOG_MODULE); - } else if (format_it.data->id == XINE_IMGFMT_YUY2) { + _("%s: this adaptor supports the %s format.\n"), LOG_MODULE, "YV12"); + break; + case XINE_IMGFMT_YUY2: this->xv_format_yuy2 = format_it.data->id; this->capabilities |= VO_CAP_YUY2; xprintf(this->xine, XINE_VERBOSITY_LOG, - _("%s: this adaptor supports the yuy2 format.\n"), LOG_MODULE); + _("%s: this adaptor supports the %s format.\n"), LOG_MODULE, "YUY2"); + break; + default: + break; } } @@ -1358,8 +1424,7 @@ static vo_driver_t *open_plugin(video_driver_class_t *class_gen, const void *vis this->use_pitch_alignment = config->register_bool (config, "video.device.xv_pitch_alignment", 0, - _("pitch alignment workaround"), - _("Some buggy video drivers need a workaround to function properly."), + VIDEO_DEVICE_XV_PITCH_ALIGNMENT_HELP, 10, xv_update_xv_pitch_alignment, this); if(this->use_colorkey==1) { diff --git a/src/video_out/video_out_xshm.c b/src/video_out/video_out_xshm.c index 97c879af3..0df5c2806 100644 --- a/src/video_out/video_out_xshm.c +++ b/src/video_out/video_out_xshm.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000-2003 the xine project + * Copyright (C) 2000-2003, 2008 the xine project * * This file is part of xine, a free video player. * @@ -315,7 +315,7 @@ static void dispose_ximage (xshm_driver_t *this, static uint32_t xshm_get_capabilities (vo_driver_t *this_gen) { xshm_driver_t *this = (xshm_driver_t *) this_gen; - uint32_t capabilities = VO_CAP_YV12 | VO_CAP_YUY2; + uint32_t capabilities = VO_CAP_YV12 | VO_CAP_YUY2 | VO_CAP_BRIGHTNESS | VO_CAP_CONTRAST | VO_CAP_SATURATION; if( this->xoverlay ) capabilities |= VO_CAP_UNSCALED_OVERLAY; @@ -829,45 +829,43 @@ static int xshm_set_property (vo_driver_t *this_gen, int property, int value) { xshm_driver_t *this = (xshm_driver_t *) this_gen; - if ( property == VO_PROP_ASPECT_RATIO) { - + switch (property) { + case VO_PROP_ASPECT_RATIO: if (value>=XINE_VO_ASPECT_NUM_RATIOS) value = XINE_VO_ASPECT_AUTO; this->sc.user_ratio = value; xprintf(this->xine, XINE_VERBOSITY_DEBUG, LOG_MODULE ": aspect ratio changed to %s\n", _x_vo_scale_aspect_ratio_name_table[value]); + break; - } else if (property == VO_PROP_BRIGHTNESS) { - + case VO_PROP_BRIGHTNESS: this->yuv2rgb_brightness = value; this->yuv2rgb_factory->set_csc_levels (this->yuv2rgb_factory, this->yuv2rgb_brightness, this->yuv2rgb_contrast, this->yuv2rgb_saturation); - this->sc.force_redraw = 1; + break; - } else if (property == VO_PROP_CONTRAST) { - + case VO_PROP_CONTRAST: this->yuv2rgb_contrast = value; this->yuv2rgb_factory->set_csc_levels (this->yuv2rgb_factory, this->yuv2rgb_brightness, this->yuv2rgb_contrast, this->yuv2rgb_saturation); - this->sc.force_redraw = 1; + break; - } else if (property == VO_PROP_SATURATION) { - + case VO_PROP_SATURATION: this->yuv2rgb_saturation = value; this->yuv2rgb_factory->set_csc_levels (this->yuv2rgb_factory, this->yuv2rgb_brightness, this->yuv2rgb_contrast, this->yuv2rgb_saturation); - this->sc.force_redraw = 1; + break; - } else { + default: xprintf (this->xine, XINE_VERBOSITY_DEBUG, LOG_MODULE ": tried to set unsupported property %d\n", property); } diff --git a/src/video_out/video_out_xv.c b/src/video_out/video_out_xv.c index d6419c00b..a874e4cdf 100644 --- a/src/video_out/video_out_xv.c +++ b/src/video_out/video_out_xv.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000-2004 the xine project + * Copyright (C) 2000-2004, 2008 the xine project * * This file is part of xine, a free video player. * @@ -69,6 +69,7 @@ #include <xine/xineutils.h> #include <xine/vo_scale.h> #include "x11osd.h" +#include "xv_common.h" #define LOCK_DISPLAY(this) {if(this->lock_display) this->lock_display(this->user_data); \ else XLockDisplay(this->display);} @@ -1028,14 +1029,13 @@ static int xv_check_yv12 (Display *display, XvPortID port) { /* called xlocked */ static void xv_check_capability (xv_driver_t *this, - int property, XvAttribute attr, - int base_id, + int property, XvAttribute attr, int base_id, const char *config_name, const char *config_desc, const char *config_help) { int int_default; cfg_entry_t *entry; - char *str_prop = attr.name; + const char *str_prop = attr.name; /* * some Xv drivers (Gatos ATI) report some ~0 as max values, this is confusing. @@ -1130,12 +1130,70 @@ static void xv_update_XV_DOUBLE_BUFFER(void *this_gen, xine_cfg_entry_t *entry) LOG_MODULE ": double buffering mode = %d\n", xv_double_buffer); } +static void xv_update_XV_SYNC_TO_VBLANK(void *this_gen, xine_cfg_entry_t *entry) { + xv_driver_t *this = (xv_driver_t *) this_gen; + Atom atom; + int xv_sync_to_vblank; + + xv_sync_to_vblank = entry->num_value; + + LOCK_DISPLAY(this); + atom = XInternAtom (this->display, "XV_SYNC_TO_VBLANK", False); + XvSetPortAttribute (this->display, this->xv_port, atom, xv_sync_to_vblank); + UNLOCK_DISPLAY(this); + + xprintf(this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xv: sync to vblank = %d\n", xv_sync_to_vblank); +} + static void xv_update_xv_pitch_alignment(void *this_gen, xine_cfg_entry_t *entry) { xv_driver_t *this = (xv_driver_t *) this_gen; this->use_pitch_alignment = entry->num_value; } +static int xv_open_port (xv_driver_t *this, XvPortID port) { + int ret; + x11_InstallXErrorHandler (this); + ret = ! xv_check_yv12(this->display, port) + && XvGrabPort(this->display, port, 0) == Success; + x11_DeInstallXErrorHandler (this); + return ret; +} + +static unsigned int +xv_find_adaptor_by_port (int port, unsigned int adaptors, + XvAdaptorInfo *adaptor_info) +{ + unsigned int an; + for (an = 0; an < adaptors; an++) + if (adaptor_info[an].type & XvImageMask) + if (port >= adaptor_info[an].base_id && + port < adaptor_info[an].base_id + adaptor_info[an].num_ports) + return an; + return 0; /* shouldn't happen */ +} + +static XvPortID xv_autodetect_port(xv_driver_t *this, + unsigned int adaptors, + XvAdaptorInfo *adaptor_info, + unsigned int *adaptor_num, + XvPortID base) { + unsigned int an, j; + + for (an = 0; an < adaptors; an++) + if (adaptor_info[an].type & XvImageMask) + for (j = 0; j < adaptor_info[an].num_ports; j++) { + XvPortID port = adaptor_info[an].base_id + j; + if (port >= base && xv_open_port(this, port)) { + *adaptor_num = an; + return port; + } + } + + return 0; +} + /* expects XINE_VISUAL_TYPE_X11_2 with configurable locking */ static vo_driver_t *open_plugin_2 (video_driver_class_t *class_gen, const void *visual_gen) { xv_class_t *class = (xv_class_t *) class_gen; @@ -1148,7 +1206,7 @@ static vo_driver_t *open_plugin_2 (video_driver_class_t *class_gen, const void * x11_visual_t *visual = (x11_visual_t *) visual_gen; XColor dummy; XvImage *myimage; - unsigned int adaptors, j; + unsigned int adaptors; unsigned int ver,rel,req,ev,err; XShmSegmentInfo myshminfo; XvPortID xv_port; @@ -1191,25 +1249,21 @@ static vo_driver_t *open_plugin_2 (video_driver_class_t *class_gen, const void * return NULL; } - xv_port = 0; - - for ( adaptor_num = 0; (adaptor_num < adaptors) && !xv_port; adaptor_num++ ) { - - if (adaptor_info[adaptor_num].type & XvImageMask) { - - for (j = 0; j < adaptor_info[adaptor_num].num_ports && !xv_port; j++) - if (( !(xv_check_yv12 (this->display, - adaptor_info[adaptor_num].base_id + j))) - && (XvGrabPort (this->display, - adaptor_info[adaptor_num].base_id + j, - 0) == Success)) { - xv_port = adaptor_info[adaptor_num].base_id + j; - } - - if( xv_port ) - break; - } + xv_port = config->register_num (config, "video.device.xv_port", 0, + VIDEO_DEVICE_XV_PORT_HELP, + 10, NULL, NULL); + + if (xv_port != 0) { + if (! xv_open_port(this, xv_port)) { + xprintf(class->xine, XINE_VERBOSITY_NONE, + _("%s: could not open Xv port %d - autodetecting\n"), + LOG_MODULE, xv_port); + xv_port = xv_autodetect_port(this, adaptors, adaptor_info, &adaptor_num, xv_port); + } else + adaptor_num = xv_find_adaptor_by_port (xv_port, adaptors, adaptor_info); } + if (!xv_port) + xv_port = xv_autodetect_port(this, adaptors, adaptor_info, &adaptor_num, 0); if (!xv_port) { xprintf(class->xine, XINE_VERBOSITY_LOG, @@ -1239,7 +1293,7 @@ static vo_driver_t *open_plugin_2 (video_driver_class_t *class_gen, const void * LOCK_DISPLAY(this); this->gc = XCreateGC (this->display, this->drawable, 0, NULL); UNLOCK_DISPLAY(this); - this->capabilities = VO_CAP_CROP; + this->capabilities = VO_CAP_CROP | VO_CAP_ZOOM_X | VO_CAP_ZOOM_Y; this->use_shm = 1; this->use_colorkey = 0; this->colorkey = 0; @@ -1298,75 +1352,72 @@ static vo_driver_t *open_plugin_2 (video_driver_class_t *class_gen, const void * for(k = 0; k < nattr; k++) { if((attr[k].flags & XvSettable) && (attr[k].flags & XvGettable)) { + const char *const name = attr[k].name; /* store initial port attribute value */ - xv_store_port_attribute(this, attr[k].name); + xv_store_port_attribute(this, name); - if(!strcmp(attr[k].name, "XV_HUE")) { + if(!strcmp(name, "XV_HUE")) { if (!strncmp(adaptor_info[adaptor_num].name, "NV", 2)) { xprintf (this->xine, XINE_VERBOSITY_NONE, LOG_MODULE ": ignoring broken XV_HUE settings on NVidia cards\n"); } else { + this->capabilities |= VO_CAP_HUE; xv_check_capability (this, VO_PROP_HUE, attr[k], adaptor_info[adaptor_num].base_id, NULL, NULL, NULL); } - } else if(!strcmp(attr[k].name, "XV_SATURATION")) { + } else if(!strcmp(name, "XV_SATURATION")) { + this->capabilities |= VO_CAP_SATURATION; xv_check_capability (this, VO_PROP_SATURATION, attr[k], adaptor_info[adaptor_num].base_id, NULL, NULL, NULL); - - } else if(!strcmp(attr[k].name, "XV_BRIGHTNESS")) { + } else if(!strcmp(name, "XV_BRIGHTNESS")) { + this->capabilities |= VO_CAP_BRIGHTNESS; xv_check_capability (this, VO_PROP_BRIGHTNESS, attr[k], adaptor_info[adaptor_num].base_id, NULL, NULL, NULL); - - } else if(!strcmp(attr[k].name, "XV_CONTRAST")) { + } else if(!strcmp(name, "XV_CONTRAST")) { + this->capabilities |= VO_CAP_CONTRAST; xv_check_capability (this, VO_PROP_CONTRAST, attr[k], adaptor_info[adaptor_num].base_id, NULL, NULL, NULL); - - } else if(!strcmp(attr[k].name, "XV_COLORKEY")) { + } else if(!strcmp(name, "XV_COLORKEY")) { + this->capabilities |= VO_CAP_COLORKEY; xv_check_capability (this, VO_PROP_COLORKEY, attr[k], adaptor_info[adaptor_num].base_id, "video.device.xv_colorkey", - _("video overlay colour key"), - _("The colour key is used to tell the graphics card where to " - "overlay the video image. Try different values, if you experience " - "windows becoming transparent.")); - - } else if(!strcmp(attr[k].name, "XV_AUTOPAINT_COLORKEY")) { + VIDEO_DEVICE_XV_COLORKEY_HELP); + } else if(!strcmp(name, "XV_AUTOPAINT_COLORKEY")) { + this->capabilities |= VO_CAP_AUTOPAINT_COLORKEY; xv_check_capability (this, VO_PROP_AUTOPAINT_COLORKEY, attr[k], adaptor_info[adaptor_num].base_id, "video.device.xv_autopaint_colorkey", - _("autopaint colour key"), - _("Make Xv autopaint its colour key.")); - - } else if(!strcmp(attr[k].name, "XV_FILTER")) { + VIDEO_DEVICE_XV_AUTOPAINT_COLORKEY_HELP); + } else if(!strcmp(name, "XV_FILTER")) { int xv_filter; /* This setting is specific to Permedia 2/3 cards. */ xv_filter = config->register_range (config, "video.device.xv_filter", 0, attr[k].min_value, attr[k].max_value, - _("bilinear scaling mode"), - _("Selects the bilinear scaling mode for Permedia cards. " - "The individual values are:\n\n" - "Permedia 2\n" - "0 - disable bilinear filtering\n" - "1 - enable bilinear filtering\n\n" - "Permedia 3\n" - "0 - disable bilinear filtering\n" - "1 - horizontal linear filtering\n" - "2 - enable full bilinear filtering"), + VIDEO_DEVICE_XV_FILTER_HELP, 20, xv_update_XV_FILTER, this); config->update_num(config,"video.device.xv_filter",xv_filter); - } else if(!strcmp(attr[k].name, "XV_DOUBLE_BUFFER")) { - int xv_double_buffer; - xv_double_buffer = + } else if(!strcmp(name, "XV_DOUBLE_BUFFER")) { + int xv_double_buffer = config->register_bool (config, "video.device.xv_double_buffer", 1, - _("enable double buffering"), - _("Double buffering will synchronize the update of the video image to the " - "repainting of the entire screen (\"vertical retrace\"). This eliminates " - "flickering and tearing artifacts, but will use more graphics memory."), - 20, xv_update_XV_DOUBLE_BUFFER, this); + VIDEO_DEVICE_XV_DOUBLE_BUFFER_HELP, + 20, xv_update_XV_DOUBLE_BUFFER, this); config->update_num(config,"video.device.xv_double_buffer",xv_double_buffer); + } else if(!strcmp(attr[k].name, "XV_SYNC_TO_VBLANK")) { + int xv_sync_to_vblank; + xv_sync_to_vblank = + config->register_bool (config, "video.device.xv_sync_to_vblank", 1, + _("enable vblank sync"), + _("This option will synchronize the update of the video image to the " + "repainting of the entire screen (\"vertical retrace\"). This eliminates " + "flickering and tearing artifacts. On nvidia cards one may also " + "need to run \"nvidia-settings\" and choose which display device to " + "sync to under the XVideo Settings tab"), + 20, xv_update_XV_SYNC_TO_VBLANK, this); + config->update_num(config,"video.device.xv_sync_to_vblank",xv_sync_to_vblank); } } } @@ -1391,16 +1442,21 @@ static vo_driver_t *open_plugin_2 (video_driver_class_t *class_gen, const void * fo[i].id, (char*)&fo[i].id, (fo[i].format == XvPacked) ? "packed" : "planar"); - if (fo[i].id == XINE_IMGFMT_YV12) { + switch (fo[i].id) { + case XINE_IMGFMT_YV12: this->xv_format_yv12 = fo[i].id; this->capabilities |= VO_CAP_YV12; xprintf(this->xine, XINE_VERBOSITY_LOG, - _("%s: this adaptor supports the yv12 format.\n"), LOG_MODULE); - } else if (fo[i].id == XINE_IMGFMT_YUY2) { + _("%s: this adaptor supports the %s format.\n"), LOG_MODULE, "YV12"); + break; + case XINE_IMGFMT_YUY2: this->xv_format_yuy2 = fo[i].id; this->capabilities |= VO_CAP_YUY2; xprintf(this->xine, XINE_VERBOSITY_LOG, - _("%s: this adaptor supports the yuy2 format.\n"), LOG_MODULE); + _("%s: this adaptor supports the %s format.\n"), LOG_MODULE, "YUY2"); + break; + default: + break; } } @@ -1422,8 +1478,7 @@ static vo_driver_t *open_plugin_2 (video_driver_class_t *class_gen, const void * this->use_pitch_alignment = config->register_bool (config, "video.device.xv_pitch_alignment", 0, - _("pitch alignment workaround"), - _("Some buggy video drivers need a workaround to function properly."), + VIDEO_DEVICE_XV_PITCH_ALIGNMENT_HELP, 10, xv_update_xv_pitch_alignment, this); LOCK_DISPLAY(this); diff --git a/src/video_out/video_out_xvmc.c b/src/video_out/video_out_xvmc.c index 6aa8f430d..7f282ee53 100644 --- a/src/video_out/video_out_xvmc.c +++ b/src/video_out/video_out_xvmc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000-2004 the xine project + * Copyright (C) 2000-2004, 2008 the xine project * * This file is part of xine, a free video player. * @@ -72,6 +72,7 @@ #include <xine/xineutils.h> #include <xine/vo_scale.h> +#include "xv_common.h" /* #define LOG1 */ /* #define DLOG */ @@ -217,8 +218,6 @@ typedef struct { Display *display; config_values_t *config; XvPortID xv_port; - XvAdaptorInfo *adaptor_info; - unsigned int adaptor_num; int surface_type_id; unsigned int max_surface_width; @@ -1224,13 +1223,13 @@ static void xvmc_dispose (vo_driver_t *this_gen) { /* called xlocked */ static void xvmc_check_capability (xvmc_driver_t *this, - int property, XvAttribute attr, - int base_id, char *str_prop, - char *config_name, - char *config_desc, - char *config_help) { + int property, XvAttribute attr, int base_id, + const char *config_name, + const char *config_desc, + const char *config_help) { int int_default; cfg_entry_t *entry; + const char *str_prop = attr.name; /* * some Xv drivers (Gatos ATI) report some ~0 as max values, this is confusing. @@ -1253,13 +1252,13 @@ static void xvmc_check_capability (xvmc_driver_t *this, if ((attr.min_value == 0) && (attr.max_value == 1)) { this->config->register_bool (this->config, config_name, int_default, config_desc, - NULL, 20, xvmc_property_callback, &this->props[property]); + config_help, 20, xvmc_property_callback, &this->props[property]); } else { this->config->register_range (this->config, config_name, int_default, this->props[property].min, this->props[property].max, config_desc, - NULL, 20, xvmc_property_callback, &this->props[property]); + config_help, 20, xvmc_property_callback, &this->props[property]); } entry = this->config->lookup_entry (this->config, config_name); @@ -1297,7 +1296,6 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi xvmc_class_t *class = (xvmc_class_t *) class_gen; config_values_t *config = class->config; xvmc_driver_t *this = NULL; - Display *display = NULL; unsigned int i, formats; XvPortID xv_port = class->xv_port; XvAttribute *attr; @@ -1305,13 +1303,12 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi int nattr; x11_visual_t *visual = (x11_visual_t *) visual_gen; XColor dummy; + XvAdaptorInfo *adaptor_info; + unsigned int adaptor_num; /* XvImage *myimage; */ lprintf ("open_plugin\n"); - display = visual->display; - - /* TODO ??? */ this = (xvmc_driver_t *) xine_xmalloc (sizeof (xvmc_driver_t)); if (!this) @@ -1335,7 +1332,7 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi XLockDisplay(this->display); this->gc = XCreateGC(this->display, this->drawable, 0, NULL); XUnlockDisplay(this->display); - this->capabilities = VO_CAP_XVMC_MOCOMP | VO_CAP_CROP; + this->capabilities = VO_CAP_XVMC_MOCOMP | VO_CAP_CROP | VO_CAP_ZOOM_X | VO_CAP_ZOOM_Y; this->surface_type_id = class->surface_type_id; this->max_surface_width = class->max_surface_width; @@ -1393,56 +1390,53 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi this->capabilities |= VO_CAP_XVMC_IDCT; XLockDisplay(this->display); - attr = XvQueryPortAttributes(display, xv_port, &nattr); + attr = XvQueryPortAttributes(this->display, xv_port, &nattr); if(attr && nattr) { int k; for(k = 0; k < nattr; k++) { if((attr[k].flags & XvSettable) && (attr[k].flags & XvGettable)) { - if(!strcmp(attr[k].name, "XV_HUE")) { - xvmc_check_capability (this, VO_PROP_HUE, attr[k], - class->adaptor_info[class->adaptor_num].base_id, "XV_HUE", - NULL, NULL, NULL); - - } else if(!strcmp(attr[k].name, "XV_SATURATION")) { + const char *const name = attr[k].name; + if(!strcmp(name, "XV_HUE")) { + if (!strncmp(adaptor_info[adaptor_num].name, "NV", 2)) { + xprintf (this->xine, XINE_VERBOSITY_NONE, LOG_MODULE ": ignoring broken XV_HUE settings on NVidia cards\n"); + } else { + this->capabilities |= VO_CAP_HUE; + xvmc_check_capability (this, VO_PROP_HUE, attr[k], + adaptor_info[adaptor_num].base_id, + NULL, NULL, NULL); + } + } else if(!strcmp(name, "XV_SATURATION")) { + this->capabilities |= VO_CAP_SATURATION; xvmc_check_capability (this, VO_PROP_SATURATION, attr[k], - class->adaptor_info[class->adaptor_num].base_id, "XV_SATURATION", + adaptor_info[adaptor_num].base_id, NULL, NULL, NULL); - } else if(!strcmp(attr[k].name, "XV_BRIGHTNESS")) { + this->capabilities |= VO_CAP_BRIGHTNESS; xvmc_check_capability (this, VO_PROP_BRIGHTNESS, attr[k], - class->adaptor_info[class->adaptor_num].base_id, "XV_BRIGHTNESS", + adaptor_info[adaptor_num].base_id, NULL, NULL, NULL); - - } else if(!strcmp(attr[k].name, "XV_CONTRAST")) { + } else if(!strcmp(name, "XV_CONTRAST")) { + this->capabilities |= VO_CAP_CONTRAST; xvmc_check_capability (this, VO_PROP_CONTRAST, attr[k], - class->adaptor_info[class->adaptor_num].base_id, "XV_CONTRAST", + adaptor_info[adaptor_num].base_id, NULL, NULL, NULL); - - } else if(!strcmp(attr[k].name, "XV_COLORKEY")) { + } else if(!strcmp(name, "XV_COLORKEY")) { + this->capabilities |= VO_CAP_COLORKEY; xvmc_check_capability (this, VO_PROP_COLORKEY, attr[k], - class->adaptor_info[class->adaptor_num].base_id, "XV_COLORKEY", + adaptor_info[adaptor_num].base_id, "video.device.xv_colorkey", - _("video overlay colour key"), - _("The colour key is used to tell the graphics card where to " - "overlay the video image. Try different values, if you experience " - "windows becoming transparent.")); - - } else if(!strcmp(attr[k].name, "XV_AUTOPAINT_COLORKEY")) { + VIDEO_DEVICE_XV_COLORKEY_HELP); + } else if(!strcmp(name, "XV_AUTOPAINT_COLORKEY")) { + this->capabilities |= VO_CAP_AUTOPAINT_COLORKEY; xvmc_check_capability (this, VO_PROP_AUTOPAINT_COLORKEY, attr[k], - class->adaptor_info[class->adaptor_num].base_id, "XV_AUTOPAINT_COLORKEY", + adaptor_info[adaptor_num].base_id, "video.device.xv_autopaint_colorkey", - _("autopaint colour key"), - _("Make Xv autopaint its colour key.")); - - } else if(!strcmp(attr[k].name, "XV_DOUBLE_BUFFER")) { - int xvmc_double_buffer; - xvmc_double_buffer = config->register_bool (config, "video.device.xv_double_buffer", 1, - _("enable double buffering"), - _("Double buffering will synchronize the update of the video image to the " - "repainting of the entire screen (\"vertical retrace\"). This eliminates " - "flickering and tearing artifacts, but will use more graphics memory."), - 20, xvmc_update_XV_DOUBLE_BUFFER, this); + VIDEO_DEVICE_XV_AUTOPAINT_COLORKEY_HELP); + } else if(!strcmp(name, "XV_DOUBLE_BUFFER")) { + int xvmc_double_buffer = config->register_bool (config, "video.device.xv_double_buffer", 1, + VIDEO_DEVICE_XV_DOUBLE_BUFFER_HELP, + 20, xvmc_update_XV_DOUBLE_BUFFER, this); config->update_num(config,"video.device.xv_double_buffer",xvmc_double_buffer); } } @@ -1457,7 +1451,7 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi /* * check supported image formats */ - fo = XvListImageFormats(display, this->xv_port, (int*)&formats); + fo = XvListImageFormats(this->display, this->xv_port, (int*)&formats); XUnlockDisplay(this->display); this->xvmc_format_yv12 = 0; @@ -1468,15 +1462,21 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi fo[i].id, (char*)&fo[i].id, (fo[i].format == XvPacked) ? "packed" : "planar"); - if (fo[i].id == XINE_IMGFMT_YV12) { + switch (fo[i].id) { + case XINE_IMGFMT_YV12: this->xvmc_format_yv12 = fo[i].id; - this->capabilities |= VO_CAP_YV12; - lprintf("this adaptor supports the yv12 format.\n"); - } - else if (fo[i].id == XINE_IMGFMT_YUY2) { + this->capabilities |= VO_CAP_YV12; + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("%s: this adaptor supports the %s format.\n"), LOG_MODULE, "YV12"); + break; + case XINE_IMGFMT_YUY2: this->xvmc_format_yuy2 = fo[i].id; - this->capabilities |= VO_CAP_YUY2; - lprintf("this adaptor supports the yuy2 format.\n"); + this->capabilities |= VO_CAP_YUY2; + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("%s: this adaptor supports the %s format.\n"), LOG_MODULE, "YUY2"); + break; + default: + break; } } @@ -1509,10 +1509,6 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi static void dispose_class (video_driver_class_t *this_gen) { xvmc_class_t *this = (xvmc_class_t *) this_gen; - XLockDisplay(this->display); - XvFreeAdaptorInfo (this->adaptor_info); - XUnlockDisplay(this->display); - free (this); } @@ -1685,8 +1681,6 @@ static void *init_class (xine_t *xine, void *visual_gen) { this->display = display; this->config = xine->config; this->xv_port = xv_port; - this->adaptor_info = adaptor_info; - this->adaptor_num = adaptor_num; this->surface_type_id = surface_type; this->max_surface_width = max_width; this->max_surface_height = max_height; diff --git a/src/video_out/video_out_xxmc.c b/src/video_out/video_out_xxmc.c index 98ce99f1f..1ef3652a9 100644 --- a/src/video_out/video_out_xxmc.c +++ b/src/video_out/video_out_xxmc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000-2004 the xine project + * Copyright (C) 2000-2004, 2008 the xine project * Copyright (C) 2004 the Unichrome project * * This file is part of xine, a free video player. @@ -34,9 +34,9 @@ */ - #include "xxmc.h" #include <unistd.h> +#include "xv_common.h" static int gX11Fail; @@ -2101,13 +2101,13 @@ static int xxmc_check_yv12 (Display *display, XvPortID port) { /* called xlocked */ static void xxmc_check_capability (xxmc_driver_t *this, - int property, XvAttribute attr, - int base_id, char *str_prop, - char *config_name, - char *config_desc, - char *config_help) { + int property, XvAttribute attr, int base_id, + const char *config_name, + const char *config_desc, + const char *config_help) { int int_default; cfg_entry_t *entry; + const char *str_prop = attr.name; if (VO_PROP_COLORKEY && (attr.max_value == ~0)) attr.max_value = 2147483615; @@ -2237,6 +2237,48 @@ static void xxmc_update_disable_bob_for_scaled_osd(void *this_gen, xine_cfg_entr this->disable_bob_for_scaled_osd = entry->num_value; } +static int xxmc_open_port (xxmc_driver_t *this, XvPortID port) { + int ret; + x11_InstallXErrorHandler (this); + ret = ! xxmc_check_yv12(this->display, port) + && XvGrabPort(this->display, port, 0) == Success; + x11_DeInstallXErrorHandler (this); + return ret; +} + +static unsigned int +xxmc_find_adaptor_by_port (int port, unsigned int adaptors, + XvAdaptorInfo *adaptor_info) +{ + unsigned int an; + for (an = 0; an < adaptors; an++) + if (adaptor_info[an].type & XvImageMask) + if (port >= adaptor_info[an].base_id && + port < adaptor_info[an].base_id + adaptor_info[an].num_ports) + return an; + return 0; /* shouldn't happen */ +} + +static XvPortID xxmc_autodetect_port(xxmc_driver_t *this, + unsigned int adaptors, + XvAdaptorInfo *adaptor_info, + unsigned int *adaptor_num, + XvPortID base) { + unsigned int an, j; + + for (an = 0; an < adaptors; an++) + if (adaptor_info[an].type & XvImageMask) + for (j = 0; j < adaptor_info[an].num_ports; j++) { + XvPortID port = adaptor_info[an].base_id + j; + if (port >= base && xxmc_open_port(this, port)) { + *adaptor_num = an; + return port; + } + } + + return 0; +} + static void checkXvMCCap( xxmc_driver_t *this, XvPortID xv_port) { @@ -2436,25 +2478,21 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi return NULL; } - xv_port = 0; - - for ( adaptor_num = 0; (adaptor_num < adaptors) && !xv_port; adaptor_num++ ) { - - if (adaptor_info[adaptor_num].type & XvImageMask) { + xv_port = config->register_num (config, "video.device.xv_port", 0, + VIDEO_DEVICE_XV_PORT_HELP, + 10, NULL, NULL); - for (j = 0; j < adaptor_info[adaptor_num].num_ports && !xv_port; j++) - if (( !(xxmc_check_yv12 (this->display, - adaptor_info[adaptor_num].base_id + j))) - && (XvGrabPort (this->display, - adaptor_info[adaptor_num].base_id + j, - 0) == Success)) { - xv_port = adaptor_info[adaptor_num].base_id + j; - } - - if( xv_port ) - break; - } + if (xv_port != 0) { + if (! xxmc_open_port(this, xv_port)) { + xprintf(class->xine, XINE_VERBOSITY_NONE, + _("%s: could not open Xv port %d - autodetecting\n"), + LOG_MODULE, xv_port); + xv_port = xxmc_autodetect_port(this, adaptors, adaptor_info, &adaptor_num, xv_port); + } else + adaptor_num = xxmc_find_adaptor_by_port (xv_port, adaptors, adaptor_info); } + if (!xv_port) + xv_port = xxmc_autodetect_port(this, adaptors, adaptor_info, &adaptor_num, 0); if (!xv_port) { xprintf(class->xine, XINE_VERBOSITY_LOG, @@ -2484,7 +2522,7 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi XLockDisplay (this->display); this->gc = XCreateGC (this->display, this->drawable, 0, NULL); XUnlockDisplay (this->display); - this->capabilities = VO_CAP_CROP; + this->capabilities = VO_CAP_CROP | VO_CAP_ZOOM_X | VO_CAP_ZOOM_Y; this->use_shm = 1; this->use_colorkey = 0; this->colorkey = 0; @@ -2543,70 +2581,55 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi for(k = 0; k < nattr; k++) { if((attr[k].flags & XvSettable) && (attr[k].flags & XvGettable)) { - if(!strcmp(attr[k].name, "XV_HUE")) { + const char *const name = attr[k].name; + if(!strcmp(name, "XV_HUE")) { if (!strncmp(adaptor_info[adaptor_num].name, "NV", 2)) { xprintf (this->xine, XINE_VERBOSITY_NONE, LOG_MODULE ": ignoring broken XV_HUE settings on NVidia cards\n"); } else { + this->capabilities |= VO_CAP_HUE; xxmc_check_capability (this, VO_PROP_HUE, attr[k], - adaptor_info[adaptor_num].base_id, "XV_HUE", + adaptor_info[adaptor_num].base_id, NULL, NULL, NULL); } - } else if(!strcmp(attr[k].name, "XV_SATURATION")) { + } else if(!strcmp(name, "XV_SATURATION")) { + this->capabilities |= VO_CAP_SATURATION; xxmc_check_capability (this, VO_PROP_SATURATION, attr[k], - adaptor_info[adaptor_num].base_id, "XV_SATURATION", + adaptor_info[adaptor_num].base_id, NULL, NULL, NULL); - - } else if(!strcmp(attr[k].name, "XV_BRIGHTNESS")) { + } else if(!strcmp(name, "XV_BRIGHTNESS")) { + this->capabilities |= VO_CAP_BRIGHTNESS; xxmc_check_capability (this, VO_PROP_BRIGHTNESS, attr[k], - adaptor_info[adaptor_num].base_id, "XV_BRIGHTNESS", + adaptor_info[adaptor_num].base_id, NULL, NULL, NULL); - - } else if(!strcmp(attr[k].name, "XV_CONTRAST")) { + } else if(!strcmp(name, "XV_CONTRAST")) { + this->capabilities |= VO_CAP_CONTRAST; xxmc_check_capability (this, VO_PROP_CONTRAST, attr[k], - adaptor_info[adaptor_num].base_id, "XV_CONTRAST", + adaptor_info[adaptor_num].base_id, NULL, NULL, NULL); - - } else if(!strcmp(attr[k].name, "XV_COLORKEY")) { + } else if(!strcmp(name, "XV_COLORKEY")) { + this->capabilities |= VO_CAP_COLORKEY; xxmc_check_capability (this, VO_PROP_COLORKEY, attr[k], - adaptor_info[adaptor_num].base_id, "XV_COLORKEY", + adaptor_info[adaptor_num].base_id, "video.device.xv_colorkey", - _("video overlay colour key"), - _("The colour key is used to tell the graphics card where to " - "overlay the video image. Try different values, if you experience " - "windows becoming transparent.")); - - } else if(!strcmp(attr[k].name, "XV_AUTOPAINT_COLORKEY")) { + VIDEO_DEVICE_XV_COLORKEY_HELP); + } else if(!strcmp(name, "XV_AUTOPAINT_COLORKEY")) { + this->capabilities |= VO_CAP_AUTOPAINT_COLORKEY; xxmc_check_capability (this, VO_PROP_AUTOPAINT_COLORKEY, attr[k], - adaptor_info[adaptor_num].base_id, "XV_AUTOPAINT_COLORKEY", + adaptor_info[adaptor_num].base_id, "video.device.xv_autopaint_colorkey", - _("autopaint colour key"), - _("Make Xv autopaint its colour key.")); - - } else if(!strcmp(attr[k].name, "XV_FILTER")) { + VIDEO_DEVICE_XV_AUTOPAINT_COLORKEY_HELP); + } else if(!strcmp(name, "XV_FILTER")) { int xv_filter; /* This setting is specific to Permedia 2/3 cards. */ xv_filter = config->register_range (config, "video.device.xv_filter", 0, attr[k].min_value, attr[k].max_value, - _("bilinear scaling mode"), - _("Selects the bilinear scaling mode for Permedia cards. " - "The individual values are:\n\n" - "Permedia 2\n" - "0 - disable bilinear filtering\n" - "1 - enable bilinear filtering\n\n" - "Permedia 3\n" - "0 - disable bilinear filtering\n" - "1 - horizontal linear filtering\n" - "2 - enable full bilinear filtering"), + VIDEO_DEVICE_XV_FILTER_HELP, 20, xxmc_update_XV_FILTER, this); config->update_num(config,"video.device.xv_filter",xv_filter); - } else if(!strcmp(attr[k].name, "XV_DOUBLE_BUFFER")) { - int xv_double_buffer; - xv_double_buffer = + } else if(!strcmp(name, "XV_DOUBLE_BUFFER")) { + int xv_double_buffer = config->register_bool (config, "video.device.xv_double_buffer", 1, - _("enable double buffering"), - _("Double buffering will synchronize the update of the video image to the " - "repainting of the entire screen (\"vertical retrace\"). This eliminates " - "flickering and tearing artifacts, but will use more graphics memory."), + VIDEO_DEVICE_XV_DOUBLE_BUFFER_HELP, 20, xxmc_update_XV_DOUBLE_BUFFER, this); config->update_num(config,"video.device.xv_double_buffer",xv_double_buffer); } @@ -2640,16 +2663,21 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi fo[i].id, (char*)&fo[i].id, (fo[i].format == XvPacked) ? "packed" : "planar"); - if (fo[i].id == XINE_IMGFMT_YV12) { + switch (fo[i].id) { + case XINE_IMGFMT_YV12: this->xv_format_yv12 = fo[i].id; this->capabilities |= VO_CAP_YV12; xprintf(this->xine, XINE_VERBOSITY_LOG, - _("%s: this adaptor supports the yv12 format.\n"), LOG_MODULE); - } else if (fo[i].id == XINE_IMGFMT_YUY2) { + _("%s: this adaptor supports the %s format.\n"), LOG_MODULE, "YV12"); + break; + case XINE_IMGFMT_YUY2: this->xv_format_yuy2 = fo[i].id; this->capabilities |= VO_CAP_YUY2; xprintf(this->xine, XINE_VERBOSITY_LOG, - _("%s: this adaptor supports the yuy2 format.\n"), LOG_MODULE); + _("%s: this adaptor supports the %s format.\n"), LOG_MODULE, "YUY2"); + break; + default: + break; } } @@ -2672,8 +2700,7 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi this->use_pitch_alignment = config->register_bool (config, "video.device.xv_pitch_alignment", 0, - _("pitch alignment workaround"), - _("Some buggy video drivers need a workaround to function properly."), + VIDEO_DEVICE_XV_PITCH_ALIGNMENT_HELP, 10, xxmc_update_xv_pitch_alignment, this); use_more_frames= diff --git a/src/video_out/xv_common.h b/src/video_out/xv_common.h new file mode 100644 index 000000000..ee2ab9a10 --- /dev/null +++ b/src/video_out/xv_common.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2008 the xine project + * + * This file is part of xine, a free video player. + * + * xine 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. + * + * xine 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * xv_common.h: X11 Xv common bits + */ + +#define VIDEO_DEVICE_XV_COLORKEY_HELP \ + _("video overlay colour key"), \ + _("The colour key is used to tell the graphics card where to " \ + "overlay the video image. Try different values, if you "\ + "experience windows becoming transparent.") + +#define VIDEO_DEVICE_XV_AUTOPAINT_COLORKEY_HELP \ + _("autopaint colour key"), \ + _("Make Xv autopaint its colour key.") + +#define VIDEO_DEVICE_XV_FILTER_HELP \ + _("bilinear scaling mode"), \ + _("Selects the bilinear scaling mode for Permedia cards. " \ + "The individual values are:\n\n" \ + "Permedia 2\n" \ + "0 - disable bilinear filtering\n" \ + "1 - enable bilinear filtering\n\n" \ + "Permedia 3\n" \ + "0 - disable bilinear filtering\n" \ + "1 - horizontal linear filtering\n" \ + "2 - enable full bilinear filtering") + +#define VIDEO_DEVICE_XV_DOUBLE_BUFFER_HELP \ + _("enable double buffering"), \ + _("Double buffering will synchronize the update of the video " \ + "image to the repainting of the entire screen (\"vertical " \ + "retrace\"). This eliminates flickering and tearing artifacts, " \ + "but will use more graphics memory.") + +#define VIDEO_DEVICE_XV_PORT_HELP \ + _("Xv port number"), \ + _("Selects the Xv port number to use (0 to autodetect).") + +#define VIDEO_DEVICE_XV_PITCH_ALIGNMENT_HELP \ + _("pitch alignment workaround"), \ + _("Some buggy video drivers need a workaround to function properly.") diff --git a/src/xine-engine/Makefile.am b/src/xine-engine/Makefile.am index e4c57710a..dcecbfcab 100644 --- a/src/xine-engine/Makefile.am +++ b/src/xine-engine/Makefile.am @@ -35,7 +35,7 @@ libxine_la_LIBADD = $(PTHREAD_LIBS) $(DYNAMIC_LD_LIBS) $(LTLIBINTL) $(ZLIB_LIBS) $(LIBXINEPOSIX) $(RT_LIBS) $(NET_LIBS) $(XDG_BASEDIR_LIBS) \ $(AVUTIL_LIBS) -libxine_la_LDFLAGS = $(AM_LDFLAGS) $(def_ldflags) \ +libxine_la_LDFLAGS = $(AM_LDFLAGS) $(def_ldflags) $(GCSECTIONS) \ -version-info $(XINE_LT_CURRENT):$(XINE_LT_REVISION):$(XINE_LT_AGE) $(XINEUTILS_LIB): diff --git a/src/xine-engine/audio_out.c b/src/xine-engine/audio_out.c index 5162c1883..855051582 100644 --- a/src/xine-engine/audio_out.c +++ b/src/xine-engine/audio_out.c @@ -291,6 +291,7 @@ struct audio_fifo_s { int num_buffers; }; +static int ao_get_property (xine_audio_port_t *this_gen, int property); static int ao_set_property (xine_audio_port_t *this_gen, int property, int value); static audio_fifo_t *fifo_new (xine_t *xine) { @@ -1614,13 +1615,17 @@ static void ao_close(xine_audio_port_t *this_gen, xine_stream_t *stream) { xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_out: no streams left, closing driver\n"); if (this->audio_loop_running) { + /* make sure there are no more buffers on queue */ if (this->clock->speed == XINE_SPEED_PAUSE || (this->clock->speed != XINE_FINE_SPEED_NORMAL && !this->slow_fast_audio)) { - /* discard buffers, otherwise we'll wait forever */ + int discard = ao_get_property(this_gen, AO_PROP_DISCARD_BUFFERS); + /* discard buffers while waiting, otherwise we'll wait forever */ ao_set_property(this_gen, AO_PROP_DISCARD_BUFFERS, 1); + fifo_wait_empty(this->out_fifo); + ao_set_property(this_gen, AO_PROP_DISCARD_BUFFERS, discard); } - /* make sure there are no more buffers on queue */ - fifo_wait_empty(this->out_fifo); + else + fifo_wait_empty(this->out_fifo); } pthread_mutex_lock( &this->driver_lock ); diff --git a/src/xine-engine/buffer_types.c b/src/xine-engine/buffer_types.c index 08ff194fa..b0e01db31 100644 --- a/src/xine-engine/buffer_types.c +++ b/src/xine-engine/buffer_types.c @@ -33,6 +33,8 @@ #include <stdlib.h> #include <inttypes.h> #include <xine/buffer.h> +#include <xine/xineutils.h> +#include <xine/xine_internal.h> #include "bswap.h" typedef struct video_db_s { @@ -771,6 +773,14 @@ static const video_db_t video_db[] = { BUF_VIDEO_KMVC, "Karl Morton's Video Codec" }, +{ + { + ME_FOURCC('V','M','n','c'), + 0 + }, + BUF_VIDEO_VMNC, + "VMware Screen Codec" +}, { { 0 }, 0, "last entry" } }; @@ -1201,6 +1211,43 @@ int i; return ""; } + +static void code_to_text (char ascii[5], uint32_t code) +{ + int i; + for (i = 0; i < 4; ++i) + { + int byte = code & 0xFF; + ascii[i] = (byte < ' ') ? ' ' : (byte >= 0x7F) ? '.' : (char) byte; + code >>= 8; + } +} + +void _x_report_video_fourcc (xine_t *xine, const char *module, uint32_t code) +{ + if (code) + { + char ascii[5]; + code_to_text (ascii, code); + xprintf (xine, XINE_VERBOSITY_LOG, + _("%s: unknown video FourCC code %#x \"%s\"\n"), + module, code, ascii); + } +} + +void _x_report_audio_format_tag (xine_t *xine, const char *module, uint32_t code) +{ + if (code) + { + char ascii[5]; + code_to_text (ascii, code); + xprintf (xine, XINE_VERBOSITY_LOG, + _("%s: unknown audio format tag code %#x \"%s\"\n"), + module, code, ascii); + } +} + + void _x_bmiheader_le2me( xine_bmiheader *bih ) { /* OBS: fourcc must be read using machine endianness * so don't play with biCompression here! diff --git a/src/xine-engine/configfile.c b/src/xine-engine/configfile.c index 3e3c0f7b5..37a4e38ad 100644 --- a/src/xine-engine/configfile.c +++ b/src/xine-engine/configfile.c @@ -32,6 +32,8 @@ #include <string.h> #include <unistd.h> #include <xine/configfile.h> +#include "bswap.h" +#include "base64.h" #define LOG_MODULE "configfile" #define LOG_VERBOSE @@ -182,8 +184,6 @@ static const xine_config_entry_translation_t config_entry_translation[] = { { "video.pgx64_overlay_mode", "" }, { "video.pgx64_saturation", "video.output.pgx64_saturation" }, { "video.sdl_hw_accel", "video.device.sdl_hw_accel" }, - { "video.syncfb_default_repeat", "video.device.syncfb_default_repeat" }, - { "video.syncfb_device", "video.device.syncfb_device" }, { "video.unichrome_cpu_save", "video.device.unichrome_cpu_save" }, { "video.vertical_position", "video.output.vertical_position" }, { "video.vidix_blue_intensity", "video.output.vidix_blue_intensity" }, @@ -455,6 +455,8 @@ static void config_reset_value(cfg_entry_t *entry) { entry->num_value = 0; } +static void config_shallow_copy(xine_cfg_entry_t *dest, cfg_entry_t *src); + static cfg_entry_t *config_register_key (config_values_t *this, const char *key, int exp_level, @@ -488,6 +490,14 @@ static cfg_entry_t *config_register_key (config_values_t *this, entry->callback_data = cb_data; } + /* we created a new entry, call the callback */ + if (this->new_entry_cb) { + xine_cfg_entry_t cb_entry; + + config_shallow_copy(&cb_entry, entry); + this->new_entry_cb(this->new_entry_cbdata, &cb_entry); + } + return entry; } @@ -1195,6 +1205,322 @@ static void config_unregister_cb (config_values_t *this, const char *key) { } } +static void config_set_new_entry_callback (config_values_t *this, xine_config_cb_t new_entry_cb, void* cbdata) { + pthread_mutex_lock(&this->config_lock); + this->new_entry_cb = new_entry_cb; + this->new_entry_cbdata = cbdata; + pthread_mutex_unlock(&this->config_lock); +} + +static void config_unset_new_entry_callback (config_values_t *this) { + pthread_mutex_lock(&this->config_lock); + this->new_entry_cb = NULL; + this->new_entry_cbdata = NULL; + pthread_mutex_unlock(&this->config_lock); +} + +static int put_int(uint8_t *buffer, int pos, int value) { + int32_t value_int32 = (int32_t)value; + + buffer[pos] = value_int32 & 0xFF; + buffer[pos + 1] = (value_int32 >> 8) & 0xFF; + buffer[pos + 2] = (value_int32 >> 16) & 0xFF; + buffer[pos + 3] = (value_int32 >> 24) & 0xFF; + + return 4; +} + +static int put_string(uint8_t *buffer, int pos, const char *value, int value_len) { + pos += put_int(buffer, pos, value_len); + memcpy(&buffer[pos], value, value_len); + + return 4 + value_len; +} + +static char* config_get_serialized_entry (config_values_t *this, const char *key) { + char *output = NULL; + cfg_entry_t *entry, *prev; + + pthread_mutex_lock(&this->config_lock); + config_lookup_entry_int(this, key, &entry, &prev); + + if (entry) { + /* now serialize this stuff + fields to serialize : + int type; + int range_min; + int range_max; + int exp_level; + int num_default; + int num_value; + char *key; + char *str_default; + char *description; + char *help; + char **enum_values; + */ + + int key_len = 0; + int str_default_len = 0; + int description_len = 0; + int help_len = 0; + unsigned long output_len; + unsigned long total_len; + int value_count; + int value_len[10]; + int pos = 0; + int i; + + if (entry->key) + key_len = strlen(entry->key); + if (entry->str_default) + str_default_len = strlen(entry->str_default); + if (entry->description) + description_len = strlen(entry->description); + if (entry->help) + help_len = strlen(entry->help); + + /* integers */ + /* value: 4 bytes */ + total_len = 6 * sizeof(int32_t); + + /* strings (size + char buffer) + * length: 4 bytes + * buffer: length bytes + */ + total_len += sizeof(int32_t) + key_len; + total_len += sizeof(int32_t) + str_default_len; + total_len += sizeof(int32_t) + description_len; + total_len += sizeof(int32_t) + help_len; + + /* enum values... + * value count: 4 bytes + * for each value: + * length: 4 bytes + * buffer: length bytes + */ + value_count = 0; + total_len += sizeof(int32_t); /* value count */ + + char **cur_value = entry->enum_values; + if (cur_value) { + while (*cur_value && (value_count < (sizeof(value_len) / sizeof(int) ))) { + value_len[value_count] = strlen(*cur_value); + total_len += sizeof(int32_t) + value_len[value_count]; + value_count++; + cur_value++; + } + } + + /* Now we have the length needed to serialize the entry and the length of each string */ + uint8_t *buffer = malloc (total_len); + if (!buffer) return NULL; + + /* Let's go */ + + /* the integers */ + pos += put_int(buffer, pos, entry->type); + pos += put_int(buffer, pos, entry->range_min); + pos += put_int(buffer, pos, entry->range_max); + pos += put_int(buffer, pos, entry->exp_level); + pos += put_int(buffer, pos, entry->num_default); + pos += put_int(buffer, pos, entry->num_value); + + /* the strings */ + pos += put_string(buffer, pos, entry->key, key_len); + pos += put_string(buffer, pos, entry->str_default, str_default_len); + pos += put_string(buffer, pos, entry->description, description_len); + pos += put_string(buffer, pos, entry->help, help_len); + + /* the enum stuff */ + pos += put_int(buffer, pos, value_count); + cur_value = entry->enum_values; + + for (i = 0; i < value_count; i++) { + pos += put_string(buffer, pos, *cur_value, value_len[i]); + cur_value++; + } + + /* and now the output encoding */ + output = _x_base64_encode (buffer, total_len, &output_len); + + free(buffer); + } + pthread_mutex_unlock(&this->config_lock); + + return output; + +} + +static int get_int(uint8_t *buffer, int buffer_size, int pos, int *value) { + int32_t value_int32; + + if ((pos + sizeof(int32_t)) > buffer_size) + return 0; + + value_int32 = _X_LE_32(&buffer[pos]); + *value = (int)value_int32; + return sizeof(int32_t); +} + +static int get_string(uint8_t *buffer, int buffer_size, int pos, char **value) { + int len; + int bytes = get_int(buffer, buffer_size, pos, &len); + *value = NULL; + + if (!bytes || (len < 0) || (len > 1024*64)) + return 0; + + char *str = malloc(len + 1); + pos += bytes; + memcpy(str, &buffer[pos], len); + str[len] = 0; + + *value = str; + return bytes + len; +} + +static char* config_register_serialized_entry (config_values_t *this, const char *value) { + /* + fields serialized : + int type; + int range_min; + int range_max; + int exp_level; + int num_default; + int num_value; + char *key; + char *str_default; + char *description; + char *help; + char **enum_values; + */ + int type; + int range_min; + int range_max; + int exp_level; + int num_default; + int num_value; + char *key = NULL; + char *str_default = NULL; + char *description = NULL; + char *help = NULL; + char **enum_values = NULL; + + int bytes; + int pos; + void *output = NULL; + unsigned long output_len; + int value_count = 0; + int i; + + output = _x_base64_decode (value, strlen(value), &output_len); + + pos = 0; + pos += bytes = get_int(output, output_len, pos, &type); + if (!bytes) goto exit; + + pos += bytes = get_int(output, output_len, pos, &range_min); + if (!bytes) goto exit; + + pos += bytes = get_int(output, output_len, pos, &range_max); + if (!bytes) goto exit; + + pos += bytes = get_int(output, output_len, pos, &exp_level); + if (!bytes) goto exit; + + pos += bytes = get_int(output, output_len, pos, &num_default); + if (!bytes) goto exit; + + pos += bytes = get_int(output, output_len, pos, &num_value); + if (!bytes) goto exit; + + pos += bytes = get_string(output, output_len, pos, &key); + if (!bytes) goto exit; + + pos += bytes = get_string(output, output_len, pos, &str_default); + if (!bytes) goto exit; + + pos += bytes = get_string(output, output_len, pos, &description); + if (!bytes) goto exit; + + pos += bytes = get_string(output, output_len, pos, &help); + if (!bytes) goto exit; + + pos += bytes = get_int(output, output_len, pos, &value_count); + if (!bytes) goto exit; + if ((value_count < 0) || (value_count > 256)) goto exit; + + enum_values = malloc (sizeof(void*) * value_count + 1); + for (i = 0; i < value_count; i++) { + pos += bytes = get_string(output, output_len, pos, &enum_values[i]); + if (!bytes) goto exit; + } + enum_values[value_count] = NULL; + +#ifdef LOG + printf("config entry deserialization:\n"); + printf(" key : %s\n", key); + printf(" type : %d\n", type); + printf(" exp_level : %d\n", exp_level); + printf(" num_default: %d\n", num_default); + printf(" num_value : %d\n", num_value); + printf(" str_default: %s\n", str_default); + printf(" range_min : %d\n", range_min); + printf(" range_max : %d\n", range_max); + printf(" description: %s\n", description); + printf(" help : %s\n", help); + printf(" enum : %d values\n", value_count); + + for (i = 0; i < value_count; i++) { + printf(" enum[%2d]: %s\n", i, enum_values[i]); + } + printf("\n"); +#endif + + switch (type) { + case XINE_CONFIG_TYPE_STRING: + switch (num_value) { + case 0: + this->register_string(this, key, str_default, description, help, exp_level, NULL, NULL); + break; + default: + this->register_filename(this, key, str_default, num_value, description, help, exp_level, NULL, NULL); + break; + } + break; + case XINE_CONFIG_TYPE_RANGE: + this->register_range(this, key, num_default, range_min, range_max, description, help, exp_level, NULL, NULL); + break; + case XINE_CONFIG_TYPE_ENUM: + this->register_enum(this, key, num_default, enum_values, description, help, exp_level, NULL, NULL); + break; + case XINE_CONFIG_TYPE_NUM: + this->register_num(this, key, num_default, description, help, exp_level, NULL, NULL); + break; + case XINE_CONFIG_TYPE_BOOL: + this->register_bool(this, key, num_default, description, help, exp_level, NULL, NULL); + break; + case XINE_CONFIG_TYPE_UNKNOWN: + break; + } + +exit: + /* cleanup */ + free(str_default); + free(description); + free(help); + free(output); + + if (enum_values) { + for (i = 0; i < value_count; i++) { + free(enum_values[i]); + } + free(enum_values); + } + + return key; +} config_values_t *_x_config_init (void) { @@ -1221,18 +1547,22 @@ config_values_t *_x_config_init (void) { pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&this->config_lock, &attr); - this->register_string = config_register_string; - this->register_filename = config_register_filename; - this->register_range = config_register_range; - this->register_enum = config_register_enum; - this->register_num = config_register_num; - this->register_bool = config_register_bool; - this->update_num = config_update_num; - this->update_string = config_update_string; - this->parse_enum = config_parse_enum; - this->lookup_entry = config_lookup_entry; - this->unregister_callback = config_unregister_cb; - this->dispose = config_dispose; + this->register_string = config_register_string; + this->register_filename = config_register_filename; + this->register_range = config_register_range; + this->register_enum = config_register_enum; + this->register_num = config_register_num; + this->register_bool = config_register_bool; + this->register_serialized_entry = config_register_serialized_entry; + this->update_num = config_update_num; + this->update_string = config_update_string; + this->parse_enum = config_parse_enum; + this->lookup_entry = config_lookup_entry; + this->unregister_callback = config_unregister_cb; + this->dispose = config_dispose; + this->set_new_entry_callback = config_set_new_entry_callback; + this->unset_new_entry_callback = config_unset_new_entry_callback; + this->get_serialized_entry = config_get_serialized_entry; return this; } diff --git a/src/xine-engine/load_plugins.c b/src/xine-engine/load_plugins.c index b179a135d..8e4a10a60 100644 --- a/src/xine-engine/load_plugins.c +++ b/src/xine-engine/load_plugins.c @@ -49,6 +49,7 @@ /* #define LOG +#define DEBUG */ #define XINE_ENABLE_EXPERIMENTAL_FEATURES 1 @@ -65,6 +66,8 @@ #include <xine/xineutils.h> #include <xine/compat.h> +#define LINE_MAX_LENGTH (1024 * 32) /* 32 KiB */ + #if 0 static char *plugin_name; @@ -96,7 +99,7 @@ static void remove_segv_handler(void){ #endif #endif /* 0 */ -#define CACHE_CATALOG_VERSION 2 +#define CACHE_CATALOG_VERSION 3 static const int plugin_iface_versions[] = { INPUT_PLUGIN_IFACE_VERSION, @@ -250,26 +253,26 @@ static void _decoder_priority_cb(void *data, xine_cfg_entry_t *cfg) { map_decoders((xine_t *)data); } -static plugin_info_t *_get_cached_info (xine_t *this, +static plugin_node_t *_get_cached_node (xine_t *this, char *filename, off_t filesize, time_t filemtime, - plugin_info_t *previous_info) { + plugin_node_t *previous_node) { xine_sarray_t *list = this->plugin_catalog->cache_list; int list_id, list_size; list_size = xine_sarray_size (list); for (list_id = 0; list_id < list_size; list_id++) { plugin_node_t *node = xine_sarray_get (list, list_id); - if( !previous_info && + if( !previous_node && node->file->filesize == filesize && node->file->filemtime == filemtime && !strcmp( node->file->filename, filename )) { - return node->info; + return node; } /* skip previously returned items */ - if( node->info == previous_info ) - previous_info = NULL; + if( node == previous_node ) + previous_node = NULL; } return NULL; @@ -299,6 +302,7 @@ static plugin_file_t *_insert_file (xine_t *this, static void _insert_node (xine_t *this, xine_sarray_t *list, plugin_file_t *file, + plugin_node_t *node_cache, plugin_info_t *info, int api_version){ @@ -338,6 +342,7 @@ static void _insert_node (xine_t *this, entry->file = file; entry->ref = 0; entry->priority = 0; /* default priority */ + entry->config_entry_list = (node_cache) ? node_cache->config_entry_list : NULL; switch (info->type & PLUGIN_TYPE_MASK){ @@ -480,7 +485,8 @@ static plugin_catalog_t *_new_catalog(void){ return catalog; } -static void _register_plugins_internal(xine_t *this, plugin_file_t *file, plugin_info_t *info) { +static void _register_plugins_internal(xine_t *this, plugin_file_t *file, + plugin_node_t *node_cache, plugin_info_t *info) { _x_assert(this); _x_assert(info); @@ -506,7 +512,7 @@ static void _register_plugins_internal(xine_t *this, plugin_file_t *file, plugin int plugin_type = info->type & PLUGIN_TYPE_MASK; if ((plugin_type > 0) && (plugin_type <= PLUGIN_TYPE_MAX)) { - _insert_node (this, this->plugin_catalog->plugin_lists[plugin_type - 1], file, info, + _insert_node (this, this->plugin_catalog->plugin_lists[plugin_type - 1], file, node_cache, info, plugin_iface_versions[plugin_type - 1]); if ((plugin_type == PLUGIN_AUDIO_DECODER) || @@ -530,7 +536,8 @@ static void _register_plugins_internal(xine_t *this, plugin_file_t *file, plugin /* get next info */ if( file && !file->lib_handle ) { lprintf("get cached info\n"); - info = _get_cached_info (this, file->filename, file->filesize, file->filemtime, info); + node_cache = _get_cached_node (this, file->filename, file->filesize, file->filemtime, node_cache); + info = (node_cache) ? node_cache->info : NULL; } else { info++; } @@ -538,7 +545,7 @@ static void _register_plugins_internal(xine_t *this, plugin_file_t *file, plugin } void xine_register_plugins(xine_t *self, plugin_info_t *info) { - _register_plugins_internal(self, NULL, info); + _register_plugins_internal(self, NULL, NULL, info); } /* @@ -569,6 +576,7 @@ static void collect_plugins(xine_t *this, char *path){ size_t new_str_size, d_len; void *lib = NULL; plugin_info_t *info = NULL; + plugin_node_t *node = NULL; struct stat statbuffer; @@ -611,7 +619,8 @@ static void collect_plugins(xine_t *this, char *path){ lib = NULL; /* get the first plugin_info_t */ - info = _get_cached_info (this, str, statbuffer.st_size, statbuffer.st_mtime, NULL); + node = _get_cached_node (this, str, statbuffer.st_size, statbuffer.st_mtime, NULL); + info = (node) ? node->info : NULL; #ifdef LOG if( info ) printf("load_plugins: using cached %s\n", str); @@ -632,7 +641,7 @@ static void collect_plugins(xine_t *this, char *path){ file = _insert_file(this, this->plugin_catalog->file_list, str, &statbuffer, lib); - _register_plugins_internal(this, file, info); + _register_plugins_internal(this, file, node, info); } else { const char *error = dlerror(); @@ -689,6 +698,25 @@ static inline int _plugin_info_equal(const plugin_info_t *a, return 1; } +static void _attach_entry_to_node (plugin_node_t *node, char *key) { + + if (!node->config_entry_list) { + node->config_entry_list = xine_list_new(); + } + + xine_list_push_back(node->config_entry_list, key); +} + +/* + * This callback is called by the config entry system when a plugin register a + * new config entry. + */ +static void _new_entry_cb (void *user_data, xine_cfg_entry_t *entry) { + plugin_node_t *node = (plugin_node_t *)user_data; + + _attach_entry_to_node(node, strdup(entry->key)); +} + static int _load_plugin_class(xine_t *this, plugin_node_t *node, void *data) { @@ -716,9 +744,17 @@ static int _load_plugin_class(xine_t *this, if ((info = dlsym(node->file->lib_handle, "xine_plugin_info"))) { /* TODO: use sigsegv handler */ - while (info->type != PLUGIN_NONE){ - if (_plugin_info_equal(info, target)){ - if ((node->plugin_class = info->init(this, data))) { + while (info->type != PLUGIN_NONE) { + if (_plugin_info_equal(info, target)) { + config_values_t *config = this->config; + + /* the callback is called for each entry registered by this plugin */ + lprintf("plugin init %s\n", node->info->id); + config->set_new_entry_callback(config, _new_entry_cb, node); + node->plugin_class = info->init(this, data); + config->unset_new_entry_callback(config); + + if (node->plugin_class) { inc_file_ref(node->file); return 1; } else { @@ -797,8 +833,12 @@ static void _load_required_plugins(xine_t *this, xine_sarray_t *list) { while (list_id < list_size) { plugin_node_t *node = xine_sarray_get(list, list_id); - if( (node->info->type & PLUGIN_MUST_PRELOAD) && !node->plugin_class ) { - + /* + * preload plugins if not cached + */ + if( (node->info->type & PLUGIN_MUST_PRELOAD) && !node->plugin_class && + node->file->lib_handle ) { + lprintf("preload plugin %s from %s\n", node->info->id, node->file->filename); if (! _load_plugin_class (this, node, NULL)) { @@ -827,7 +867,7 @@ static void load_required_plugins(xine_t *this) { /* * save plugin list information to file (cached catalog) */ -static void save_plugin_list(FILE *fp, xine_sarray_t *list) { +static void save_plugin_list(xine_t *this, FILE *fp, xine_sarray_t *list) { const plugin_node_t *node; const plugin_file_t *file; @@ -837,7 +877,6 @@ static void save_plugin_list(FILE *fp, xine_sarray_t *list) { const vo_info_t *vo_info; const ao_info_t *ao_info; const post_info_t *post_info; - int i; int list_id = 0; int list_size; @@ -854,9 +893,9 @@ static void save_plugin_list(FILE *fp, xine_sarray_t *list) { fprintf(fp, "api=%d\n", node->info->API ); fprintf(fp, "id=%s\n", node->info->id ); fprintf(fp, "version=%lu\n", (unsigned long) node->info->version ); - + switch (node->info->type & PLUGIN_TYPE_MASK){ - + case PLUGIN_VIDEO_OUT: vo_info = node->info->special_info; fprintf(fp, "visual_type=%d\n", vo_info->visual_type ); @@ -884,7 +923,7 @@ static void save_plugin_list(FILE *fp, xine_sarray_t *list) { demuxer_info = node->info->special_info; fprintf(fp, "demuxer_priority=%d\n", demuxer_info->priority); break; - + case PLUGIN_INPUT: input_info = node->info->special_info; fprintf(fp, "input_priority=%d\n", input_info->priority); @@ -892,10 +931,27 @@ static void save_plugin_list(FILE *fp, xine_sarray_t *list) { case PLUGIN_POST: post_info = node->info->special_info; - fprintf(fp, "post_type=%lu\n", (unsigned long)post_info->type); - break; - } - + fprintf(fp, "post_type=%lu\n", (unsigned long)post_info->type); + break; + } + + /* config entries */ + if (node->config_entry_list) { + xine_list_iterator_t ite = xine_list_front(node->config_entry_list); + while (ite) { + char *key = xine_list_get_value(node->config_entry_list, ite); + + /* now serialize the config key */ + char *key_value = this->config->get_serialized_entry(this->config, key); + + lprintf(" config key: %s, serialization: %d bytes\n", key, strlen(key_value)); + fprintf(fp, "config_key=%s\n", key_value); + + free (key_value); + ite = xine_list_next(node->config_entry_list, ite); + } + } + fprintf(fp, "\n"); list_id++; } @@ -904,7 +960,7 @@ static void save_plugin_list(FILE *fp, xine_sarray_t *list) { /* * load plugin list information from file (cached catalog) */ -static void load_plugin_list(FILE *fp, xine_sarray_t *plugins) { +static void load_plugin_list(xine_t *this, FILE *fp, xine_sarray_t *plugins) { plugin_node_t *node; plugin_file_t *file; @@ -917,20 +973,29 @@ static void load_plugin_list(FILE *fp, xine_sarray_t *plugins) { int i; uint64_t llu; unsigned long lu; - char line[1024]; + char *line; char *value; + size_t line_len; int version_ok = 0; + line = malloc(LINE_MAX_LENGTH); + if (!line) + return; + node = NULL; file = NULL; - while (fgets (line, 1023, fp)) { + while (fgets (line, LINE_MAX_LENGTH, fp)) { if (line[0] == '#') continue; - - if( (value = strchr(line, '\r')) || (value = strchr(line, '\n')) ) - *value = (char) 0; /* eliminate any cr/lf */ + line_len = strlen(line); + if (line_len < 3) + continue; + + value = &line[line_len - 1]; + if( (*value == '\r') || (*value == '\n') ) + *value-- = (char) 0; /* eliminate any cr/lf */ - if( (value = strchr(line, '\r')) || (value = strchr(line, '\n')) ) + if( (*value == '\r') || (*value == '\n') ) *value = (char) 0; /* eliminate any cr/lf */ if (line[0] == '[' && version_ok) { @@ -1005,11 +1070,11 @@ static void load_plugin_list(FILE *fp, xine_sarray_t *plugins) { xine_xmalloc(sizeof(decoder_info_t)); break; - case PLUGIN_POST: - node->info->special_info = post_info = - xine_xmalloc(sizeof(post_info_t)); - break; - } + case PLUGIN_POST: + node->info->special_info = post_info = + xine_xmalloc(sizeof(post_info_t)); + break; + } } else if( !strcmp("api",line) ) { sscanf(value," %d",&i); @@ -1050,8 +1115,18 @@ static void load_plugin_list(FILE *fp, xine_sarray_t *plugins) { sscanf(value," %d",&i); input_info->priority = i; } else if( !strcmp("post_type",line) && post_info ) { - sscanf(value," %lu",&lu); - post_info->type = lu; + sscanf(value," %lu",&lu); + post_info->type = lu; + } else if( !strcmp("config_key",line) ) { + char* cfg_key; + + cfg_key = this->config->register_serialized_entry(this->config, value); + if (cfg_key) { + /* this node is a cached node */ + _attach_entry_to_node(node, cfg_key); + } else { + lprintf("failed to deserialize config entry key\n"); + } } } } @@ -1060,6 +1135,8 @@ static void load_plugin_list(FILE *fp, xine_sarray_t *plugins) { if( node ) { xine_sarray_add (plugins, node); } + + free (line); } /** @@ -1132,7 +1209,7 @@ static void save_catalog (xine_t *this) { fprintf(fp, "cache_catalog_version=%d\n\n", CACHE_CATALOG_VERSION); for (i = 0; i < PLUGIN_TYPE_MAX; i++) { - save_plugin_list (fp, this->plugin_catalog->plugin_lists[i]); + save_plugin_list (this, fp, this->plugin_catalog->plugin_lists[i]); } fclose(fp); } @@ -1149,21 +1226,31 @@ static void load_cached_catalog (xine_t *this) { /* It can't return NULL without creating directories */ if( (fp = fopen(cachefile,"r")) != NULL ) { - load_plugin_list (fp, this->plugin_catalog->cache_list); + load_plugin_list (this, fp, this->plugin_catalog->cache_list); fclose(fp); } free(cachefile); } +/* helper function for _x_scan_plugins */ +static void push_if_dir (xine_list_t *plugindirs, void *path) +{ + struct stat st; + if (!stat (path, &st) && S_ISDIR (st.st_mode)) + xine_list_push_back (plugindirs, path); + else + free (path); +} + /* * initialize catalog, load all plugins into new catalog */ void _x_scan_plugins (xine_t *this) { - - char *homedir, *plugindir, *pluginpath; - int i,j; - int lenpluginpath; + + char *homedir, *pluginpath; + xine_list_t *plugindirs = xine_list_new (); + xine_list_iterator_t iter; lprintf("_x_scan_plugins()\n"); @@ -1175,48 +1262,44 @@ void _x_scan_plugins (xine_t *this) { homedir = strdup(xine_get_homedir()); this->plugin_catalog = _new_catalog(); - load_cached_catalog (this); - - if ((pluginpath = getenv("XINE_PLUGIN_PATH")) != NULL) { - pluginpath = strdup(pluginpath); + XINE_PROFILE(load_cached_catalog (this)); + + if ((pluginpath = getenv("XINE_PLUGIN_PATH")) != NULL && *pluginpath) { + char *p = pluginpath - 1; + while (p[1]) + { + char *dir, *q = p; + p = strchr (p + 1, XINE_PATH_SEPARATOR_CHAR); + if (q[0] == '~' && q[1] == '/') + asprintf (&dir, "%s%.*s", homedir, (int)(p - q - 1), q + 1); + else + dir = strndup (q, p - q); + push_if_dir (plugindirs, dir); /* store or free it */ + } } else { - const char *str1, *str2; - int len; - - str1 = "~/.xine/plugins"; - str2 = XINE_PLUGINDIR; - len = strlen(str1) + strlen(str2) + 2; - pluginpath = xine_xmalloc(len); - snprintf(pluginpath, len, "%s" XINE_PATH_SEPARATOR_STRING "%s", str1, str2); - } - plugindir = xine_xmalloc(strlen(pluginpath)+strlen(homedir)+2); - j=0; - lenpluginpath = strlen(pluginpath); - for (i=0; i <= lenpluginpath; ++i){ - switch (pluginpath[i]){ - case XINE_PATH_SEPARATOR_CHAR: - case '\0': - plugindir[j] = '\0'; - collect_plugins(this, plugindir); - j = 0; - break; - case '~': - if (j == 0){ - strcpy(plugindir, homedir); - j = strlen(plugindir); - break; - } - default: - plugindir[j++] = pluginpath[i]; + char *dir; + int i; + asprintf (&dir, "%s/.xine/plugins", homedir); + push_if_dir (plugindirs, dir); + for (i = 0; i <= XINE_LT_AGE; ++i) + { + asprintf (&dir, "%s.%d", XINE_PLUGINROOT, XINE_LT_AGE - i); + push_if_dir (plugindirs, dir); } } - free(plugindir); - free(pluginpath); + for (iter = xine_list_front (plugindirs); iter; + iter = xine_list_next (plugindirs, iter)) + { + char *dir = xine_list_get_value (plugindirs, iter); + collect_plugins(this, dir); + free (dir); + } + xine_list_delete (plugindirs); free(homedir); - save_catalog (this); - load_required_plugins (this); + + XINE_PROFILE(save_catalog (this)); map_decoders (this); } @@ -2604,7 +2687,7 @@ char *xine_get_demux_for_mime_type (xine_t *self, const char *mime_type) { } -static void dispose_plugin_list (xine_sarray_t *list) { +static void dispose_plugin_list (xine_sarray_t *list, int is_cache) { plugin_node_t *node; decoder_info_t *decoder_info; @@ -2641,6 +2724,19 @@ static void dispose_plugin_list (xine_sarray_t *list) { /* free info structure and string copies */ free (node->info->id); free (node->info); + + /* don't free the entry list if the node is cache */ + if (!is_cache) { + if (node->config_entry_list) { + xine_list_iterator_t ite = xine_list_front (node->config_entry_list); + while (ite) { + char *key = xine_list_get_value (node->config_entry_list, ite); + free (key); + ite = xine_list_next (node->config_entry_list, ite); + } + xine_list_delete(node->config_entry_list); + } + } free (node); } xine_sarray_delete(list); @@ -2673,10 +2769,10 @@ void _x_dispose_plugins (xine_t *this) { int i; for (i = 0; i < PLUGIN_TYPE_MAX; i++) { - dispose_plugin_list (this->plugin_catalog->plugin_lists[i]); + dispose_plugin_list (this->plugin_catalog->plugin_lists[i], 0); } - dispose_plugin_list (this->plugin_catalog->cache_list); + dispose_plugin_list (this->plugin_catalog->cache_list, 1); dispose_plugin_file_list (this->plugin_catalog->file_list); for (i = 0; this->plugin_catalog->prio_desc[i]; i++) diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c index 3da311dfc..c6dc8a2ce 100644 --- a/src/xine-engine/xine.c +++ b/src/xine-engine/xine.c @@ -52,6 +52,7 @@ #define LOG_VERBOSE /* #define LOG +#define DEBUG */ #define XINE_ENABLE_EXPERIMENTAL_FEATURES @@ -822,6 +823,19 @@ void _x_flush_events_queues (xine_stream_t *stream) { pthread_mutex_unlock (&stream->event_queues_lock); } +static inline int _x_path_looks_like_mrl (const char *path) +{ + if ((*path & 0xDF) < 'A' || (*path & 0xDF) > 'Z') + return 0; + + for (++path; *path; ++path) + if ((*path != '-' && *path < '0') || (*path > '9' && *path < 'A') || + (*path > 'Z' && *path < 'a') || *path > 'z') + break; + + return path[0] == ':' && path[1] == '/'; +} + static int open_internal (xine_stream_t *stream, const char *mrl) { const char *stream_setup = NULL; @@ -960,6 +974,7 @@ static int open_internal (xine_stream_t *stream, const char *mrl) { memcpy(filename, tmp, strlen(tmp)); filename[strlen(tmp)] = '\0'; } + _x_mrl_unescape(filename); xine_log(stream->xine, XINE_LOG_MSG, _("xine: join rip input plugin\n")); input_saver = _x_rip_plugin_get_instance (stream, filename); @@ -1134,7 +1149,9 @@ static int open_internal (xine_stream_t *stream, const char *mrl) { memcpy(subtitle_mrl, tmp, strlen(tmp)); subtitle_mrl[strlen(tmp)] = '\0'; } - _x_mrl_unescape(subtitle_mrl); + /* unescape for xine_open() if the MRL looks like a raw pathname */ + if (!_x_path_looks_like_mrl(subtitle_mrl)) + _x_mrl_unescape(subtitle_mrl); stream->slave = xine_stream_new (stream->xine, NULL, stream->video_out ); stream->slave_affection = XINE_MASTER_SLAVE_PLAY | XINE_MASTER_SLAVE_STOP; if( xine_open( stream->slave, subtitle_mrl ) ) { @@ -1683,7 +1700,7 @@ void xine_init (xine_t *this) { /* * plugins */ - _x_scan_plugins(this); + XINE_PROFILE(_x_scan_plugins(this)); #ifdef HAVE_SETLOCALE if (!setlocale(LC_CTYPE, "")) diff --git a/src/xine-utils/Makefile.am b/src/xine-utils/Makefile.am index 75cab2131..c17328ffd 100644 --- a/src/xine-utils/Makefile.am +++ b/src/xine-utils/Makefile.am @@ -16,6 +16,8 @@ endif endif libxineutils_la_SOURCES = $(pppc_files) \ + base64.h \ + base64.c \ cpu_accel.c \ color.c \ copy.c \ diff --git a/src/xine-utils/base64.c b/src/xine-utils/base64.c new file mode 100644 index 000000000..5730f30db --- /dev/null +++ b/src/xine-utils/base64.c @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2000 Robert Kaye + * + * This file is part of xine, a free video player. + * + * xine 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. + * + * xine 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Base64 encoding modified for Musicbrainz + * relicensed under the GNU General Public License for use in xine-lib + */ +/* -------------------------------------------------------------------------- + + MusicBrainz -- The Internet music metadatabase + + Copyright (C) 2000 Robert Kaye + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + +----------------------------------------------------------------------------*/ +/* + * Program: RFC-822 routines (originally from SMTP) + * + * Author: Mark Crispin + * Networks and Distributed Computing + * Computing & Communications + * University of Washington + * Administration Building, AG-44 + * Seattle, WA 98195 + * Internet: MRC@CAC.Washington.EDU + * + * Date: 27 July 1988 + * Last Edited: 10 September 1998 + * + * Sponsorship: The original version of this work was developed in the + * Symbolic Systems Resources Group of the Knowledge Systems + * Laboratory at Stanford University in 1987-88, and was funded + * by the Biomedical Research Technology Program of the National + * Institutes of Health under grant number RR-00785. + * + * Original version Copyright 1988 by The Leland Stanford Junior University + * Copyright 1998 by the University of Washington + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notices appear in all copies and that both the + * above copyright notices and this permission notice appear in supporting + * documentation, and that the name of the University of Washington or The + * Leland Stanford Junior University not be used in advertising or publicity + * pertaining to distribution of the software without specific, written prior + * permission. This software is made available "as is", and + * THE UNIVERSITY OF WASHINGTON AND THE LELAND STANFORD JUNIOR UNIVERSITY + * DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE, + * INCLUDING WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE UNIVERSITY OF + * WASHINGTON OR THE LELAND STANFORD JUNIOR UNIVERSITY BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <ctype.h> +#include <stdio.h> +#include <time.h> +#include <stdlib.h> + +#include "base64.h" + + +/* NOTE: This is not true RFC822 anymore. The use of the characters + '/', '+', and '=' is no bueno when the ID will be used as part of a URL. + '_', '.', and '-' have been used instead +*/ + +/* Convert binary contents to BASE64 + * Accepts: source + * length of source + * pointer to return destination length + * Returns: destination as BASE64 + */ + +unsigned char *_x_rfc822_binary (void *src,unsigned long srcl,unsigned long *len) +{ + unsigned char *ret,*d; + unsigned char *s = (unsigned char *) src; + static const char v[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._"; + unsigned long i = ((srcl + 2) / 3) * 4; + *len = i += 2 * ((i / 60) + 1); + d = ret = (unsigned char *) malloc ((size_t) ++i); + for (i = 0; srcl; s += 3) { /* process tuplets */ + *d++ = v[s[0] >> 2]; /* byte 1: high 6 bits (1) */ + /* byte 2: low 2 bits (1), high 4 bits (2) */ + *d++ = v[((s[0] << 4) + (--srcl ? (s[1] >> 4) : 0)) & 0x3f]; + /* byte 3: low 4 bits (2), high 2 bits (3) */ + *d++ = srcl ? v[((s[1] << 2) + (--srcl ? (s[2] >> 6) : 0)) & 0x3f] : '-'; + /* byte 4: low 6 bits (3) */ + *d++ = srcl ? v[s[2] & 0x3f] : '-'; + if (srcl) srcl--; /* count third character if processed */ + if ((++i) == 15) { /* output 60 characters? */ + i = 0; /* restart line break count, insert CRLF */ + *d++ = '\015'; *d++ = '\012'; + } + } + *d = '\0'; /* tie off string */ + + return ret; /* return the resulting string */ +} + +char *_x_base64_encode (const void *src, unsigned long srcl, unsigned long *len) +{ + char *ret, *d; + unsigned char *s = (unsigned char *) src; + char *v = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._"; + unsigned long i = ((srcl + 2) / 3) * 4; + *len = i; + d = ret = (char *) malloc ((size_t) ++i); + for (i = 0; srcl; s += 3) { /* process tuplets */ + *d++ = v[s[0] >> 2]; /* byte 1: high 6 bits (1) */ + /* byte 2: low 2 bits (1), high 4 bits (2) */ + *d++ = v[((s[0] << 4) + (--srcl ? (s[1] >> 4) : 0)) & 0x3f]; + /* byte 3: low 4 bits (2), high 2 bits (3) */ + *d++ = srcl ? v[((s[1] << 2) + (--srcl ? (s[2] >> 6) : 0)) & 0x3f] : '-'; + /* byte 4: low 6 bits (3) */ + *d++ = srcl ? v[s[2] & 0x3f] : '-'; + if (srcl) srcl--; /* count third character if processed */ + } + *d = '\0'; /* tie off string */ + + return ret; /* return the resulting string */ +} + +void *_x_base64_decode (const char *src, unsigned long srcl, unsigned long *len) +{ + void *ret; + unsigned char *d; + unsigned long i = ((srcl + 3) / 4) * 3; + *len = i; + d = ret = (void *) malloc ((size_t)i); + for (i = 0; srcl; src += 4) { /* process tuplets */ + unsigned char tuplet[4]; + int j; + + for (j = 0; j < 4; j += 1) { + if (srcl) { + if ((src[j] >= 'A') && (src[j] <= 'Z')) { + tuplet[j] = src[j] - 'A'; + } else if ((src[j] >= 'a') && (src[j] <= 'z')) { + tuplet[j] = src[j] - 'a' + 26; + } else if ((src[j] >= '0') && (src[j] <= '9')) { + tuplet[j] = src[j] - '0' + 52; + } else if (src[j] == '.') { + tuplet[j] = 62; + } else if (src[j] == '_') { + tuplet[j] = 63; + } else { + tuplet[j] = 64; + } + srcl--; + } else { + (*len)--; + } + } + + *d++ = (tuplet[0] << 2) + ((tuplet[1] & 0x3f) >> 4); + *d++ = (tuplet[1] << 4) + ((tuplet[2] & 0x3f) >> 2); + *d++ = (tuplet[2] << 6) + (tuplet[3] & 0x3f); + } + + return ret; /* return the resulting string */ +} diff --git a/src/xine-utils/base64.h b/src/xine-utils/base64.h new file mode 100644 index 000000000..f22f9b0c4 --- /dev/null +++ b/src/xine-utils/base64.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2000 Robert Kaye + * + * This file is part of xine, a free video player. + * + * xine 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. + * + * xine 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * Base64 encoding modified for Musicbrainz + * relicensed under the GNU General Public License for use in xine-lib + */ +/* -------------------------------------------------------------------------- + + MusicBrainz -- The Internet music metadatabase + + Copyright (C) 2000 Robert Kaye + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + +----------------------------------------------------------------------------*/ +/* + * Program: RFC-822 routines (originally from SMTP) + * + * Author: Mark Crispin + * Networks and Distributed Computing + * Computing & Communications + * University of Washington + * Administration Building, AG-44 + * Seattle, WA 98195 + * Internet: MRC@CAC.Washington.EDU + * + * Date: 27 July 1988 + * Last Edited: 10 September 1998 + * + * Sponsorship: The original version of this work was developed in the + * Symbolic Systems Resources Group of the Knowledge Systems + * Laboratory at Stanford University in 1987-88, and was funded + * by the Biomedical Research Technology Program of the National + * Institutes of Health under grant number RR-00785. + * + * Original version Copyright 1988 by The Leland Stanford Junior University + * Copyright 1998 by the University of Washington + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notices appear in all copies and that both the + * above copyright notices and this permission notice appear in supporting + * documentation, and that the name of the University of Washington or The + * Leland Stanford Junior University not be used in advertising or publicity + * pertaining to distribution of the software without specific, written prior + * permission. This software is made available "as is", and + * THE UNIVERSITY OF WASHINGTON AND THE LELAND STANFORD JUNIOR UNIVERSITY + * DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE, + * INCLUDING WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE UNIVERSITY OF + * WASHINGTON OR THE LELAND STANFORD JUNIOR UNIVERSITY BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef BASE64_H +#define BASE64_H + +unsigned char *_x_rfc822_binary (void *src,unsigned long srcl,unsigned long *len) XINE_PROTECTED; + +char *_x_base64_encode (const void *src, unsigned long srcl, unsigned long *len) XINE_PROTECTED; +void *_x_base64_decode (const char *src, unsigned long srcl, unsigned long *len) XINE_PROTECTED; + +#endif diff --git a/src/xine-utils/utils.c b/src/xine-utils/utils.c index 8363f5831..d2105c5a2 100644 --- a/src/xine-utils/utils.c +++ b/src/xine-utils/utils.c @@ -346,22 +346,18 @@ const char *xine_get_homedir(void) { char *s; int len; - if (!homedir[0]) { - len = xine_strcpy_command(GetCommandLine(), homedir, sizeof(homedir)); - s = strdup(homedir); - GetFullPathName(s, sizeof(homedir), homedir, NULL); - free(s); - if ((s = strrchr(homedir, '\\'))) *s = '\0'; - } + len = xine_strcpy_command(GetCommandLine(), homedir, sizeof(homedir)); + s = strdup(homedir); + GetFullPathName(s, sizeof(homedir), homedir, NULL); + free(s); + if ((s = strrchr(homedir, '\\'))) + *s = '\0'; return homedir; #else struct passwd pwd, *pw = NULL; static char homedir[BUFSIZ] = {0,}; - if(homedir[0]) - return homedir; - #ifdef HAVE_GETPWUID_R if(getpwuid_r(getuid(), &pwd, homedir, sizeof(homedir), &pw) != 0 || pw == NULL) { #else diff --git a/src/xine-utils/xmllexer.c b/src/xine-utils/xmllexer.c index 579007e52..75a1aafec 100644 --- a/src/xine-utils/xmllexer.c +++ b/src/xine-utils/xmllexer.c @@ -531,27 +531,28 @@ int lexer_get_token_d(char ** _tok, int * _tok_size, int fixed) { /* Terminate the current token */ tok[tok_pos] = '\0'; switch (state) { - case 0: - case 1: - case 2: + case STATE_IDLE: + case STATE_EOL: + case STATE_SEPAR: return T_EOF; break; - case 3: + case STATE_T_M_START: return T_M_START_1; break; - case 4: + case STATE_T_M_STOP_1: return T_M_STOP_1; break; - case 5: + case STATE_T_M_STOP_2: return T_ERROR; break; - case 6: + case STATE_T_EQUAL: return T_EQUAL; break; - case 7: + case STATE_T_STRING_SINGLE: + case STATE_T_STRING_DOUBLE: return T_STRING; break; - case 100: + case STATE_IDENT: return T_DATA; break; default: |