General bug fixes, like missing includes, formats that were incorrectly

claimed to be supported etc. Patch by dega (dega quickclic net)


git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@16668 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
reimar 2005-10-04 22:23:51 +00:00
parent 1e4a90cd2b
commit 42f5436396
1 changed files with 134 additions and 30 deletions

View File

@ -7,12 +7,15 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <dmedia/audio.h> #include <dmedia/audio.h>
#include "audio_out.h" #include "audio_out.h"
#include "audio_out_internal.h" #include "audio_out_internal.h"
#include "mp_msg.h" #include "mp_msg.h"
#include "help_mp.h" #include "help_mp.h"
#include "libaf/af_format.h"
static ao_info_t info = static ao_info_t info =
{ {
@ -29,32 +32,110 @@ static ALconfig ao_config;
static ALport ao_port; static ALport ao_port;
static int sample_rate; static int sample_rate;
static int queue_size; static int queue_size;
static int bytes_per_frame;
/**
* \param [in/out] format
* \param [out] width
*
* \return the closest matching SGI AL sample format
*
* \note width is set to required per-channel sample width
* format is updated to match the SGI AL sample format
*/
static int fmt2sgial(int *format, int *width) {
int smpfmt = AL_SAMPFMT_TWOSCOMP;
/* SGI AL only supports float and signed integers in native
* endianess. If this is something else, we must rely on the audio
* filter to convert it to a compatible format. */
/* 24-bit audio is supported, but only with 32-bit alignment.
* mplayer's 24-bit format is packed, unfortunately.
* So we must upgrade 24-bit requests to 32 bits. Then we drop the
* lowest 8 bits during playback. */
switch(*format) {
case AF_FORMAT_U8:
case AF_FORMAT_S8:
*width = AL_SAMPLE_8;
*format = AF_FORMAT_S8;
break;
case AF_FORMAT_U16_LE:
case AF_FORMAT_U16_BE:
case AF_FORMAT_S16_LE:
case AF_FORMAT_S16_BE:
*width = AL_SAMPLE_16;
*format = AF_FORMAT_S16_NE;
break;
case AF_FORMAT_U24_LE:
case AF_FORMAT_U24_BE:
case AF_FORMAT_S24_LE:
case AF_FORMAT_S24_BE:
case AF_FORMAT_U32_LE:
case AF_FORMAT_U32_BE:
case AF_FORMAT_S32_LE:
case AF_FORMAT_S32_BE:
*width = AL_SAMPLE_24;
*format = AF_FORMAT_S32_NE;
break;
case AF_FORMAT_FLOAT_LE:
case AF_FORMAT_FLOAT_BE:
*width = 4;
*format = AF_FORMAT_FLOAT_NE;
smpfmt = AL_SAMPFMT_FLOAT;
break;
default:
*width = AL_SAMPLE_16;
*format = AF_FORMAT_S16_NE;
break;
}
return smpfmt;
}
// to set/get/query special features/parameters // to set/get/query special features/parameters
static int control(int cmd, void *arg){ static int control(int cmd, void *arg){
mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_INFO); mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_INFO);
return -1; switch(cmd) {
case AOCONTROL_QUERY_FORMAT:
/* Do not reject any format: return the closest matching
* format if the request is not supported natively. */
return CONTROL_TRUE;
}
return CONTROL_UNKNOWN;
} }
// open & setup audio device // open & setup audio device
// return: 1=success 0=fail // return: 1=success 0=fail
static int init(int rate, int channels, int format, int flags) { static int init(int rate, int channels, int format, int flags) {
int smpwidth, smpfmt;
int rv = AL_DEFAULT_OUTPUT;
smpfmt = fmt2sgial(&format, &smpwidth);
mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_InitInfo, rate, (channels > 1) ? "Stereo" : "Mono", af_fmt2str_short(format)); mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_InitInfo, rate, (channels > 1) ? "Stereo" : "Mono", af_fmt2str_short(format));
{ /* from /usr/share/src/dmedia/audio/setrate.c */ { /* from /usr/share/src/dmedia/audio/setrate.c */
int fd; double frate, realrate;
int rv;
double frate;
ALpv x[2]; ALpv x[2];
rv = alGetResourceByName(AL_SYSTEM, "out.analog", AL_DEVICE_TYPE); if(ao_subdevice) {
if (!rv) { rv = alGetResourceByName(AL_SYSTEM, ao_subdevice, AL_OUTPUT_DEVICE_TYPE);
mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_SGI_InvalidDevice); if (!rv) {
return 0; mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_SGI_InvalidDevice);
return 0;
}
} }
frate = rate; frate = rate;
@ -76,15 +157,21 @@ static int init(int rate, int channels, int format, int flags) {
mp_msg(MSGT_AO, MSGL_WARN, MSGTR_AO_SGI_CantGetParms, alGetErrorString(oserror())); mp_msg(MSGT_AO, MSGL_WARN, MSGTR_AO_SGI_CantGetParms, alGetErrorString(oserror()));
} }
if (frate != alFixedToDouble(x[0].value.ll)) { realrate = alFixedToDouble(x[0].value.ll);
mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_SampleRateInfo, alFixedToDouble(x[0].value.ll), frate); if (frate != realrate) {
mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_SampleRateInfo, realrate, frate);
} }
sample_rate = (int)frate; sample_rate = (int)realrate;
} }
bytes_per_frame = channels * smpwidth;
ao_data.samplerate = sample_rate;
ao_data.channels = channels;
ao_data.format = format;
ao_data.bps = sample_rate * bytes_per_frame;
ao_data.buffersize=131072; ao_data.buffersize=131072;
ao_data.outburst = ao_data.buffersize/16; ao_data.outburst = ao_data.buffersize/16;
ao_data.channels = channels;
ao_config = alNewConfig(); ao_config = alNewConfig();
@ -93,14 +180,11 @@ static int init(int rate, int channels, int format, int flags) {
return 0; return 0;
} }
if(channels == 2) alSetChannels(ao_config, AL_STEREO); if(alSetChannels(ao_config, channels) < 0 ||
else alSetChannels(ao_config, AL_MONO); alSetWidth(ao_config, smpwidth) < 0 ||
alSetSampFmt(ao_config, smpfmt) < 0 ||
alSetWidth(ao_config, AL_SAMPLE_16); alSetQueueSize(ao_config, sample_rate) < 0 ||
alSetSampFmt(ao_config, AL_SAMPFMT_TWOSCOMP); alSetDevice(ao_config, rv) < 0) {
alSetQueueSize(ao_config, 48000);
if (alSetDevice(ao_config, AL_DEFAULT_OUTPUT) < 0) {
mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_SGI_InitConfigError, alGetErrorString(oserror())); mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_SGI_InitConfigError, alGetErrorString(oserror()));
return 0; return 0;
} }
@ -125,11 +209,16 @@ static void uninit(int immed) {
mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_Uninit); mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_Uninit);
if (ao_config) {
alFreeConfig(ao_config);
ao_config = NULL;
}
if (ao_port) { if (ao_port) {
if (!immed) if (!immed)
while(alGetFilled(ao_port) > 0) sginap(1); while(alGetFilled(ao_port) > 0) sginap(1);
alClosePort(ao_port); alClosePort(ao_port);
alFreeConfig(ao_config); ao_port = NULL;
} }
} }
@ -139,6 +228,7 @@ static void reset() {
mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_Reset); mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_Reset);
alDiscardFrames(ao_port, queue_size);
} }
// stop playing, keep buffers (for pause) // stop playing, keep buffers (for pause)
@ -158,10 +248,10 @@ static void audio_resume() {
// return: how many bytes can be played without blocking // return: how many bytes can be played without blocking
static int get_space() { static int get_space() {
// printf("ao_sgi, get_space: (ao_outburst %d)\n", ao_outburst); // printf("ao_sgi, get_space: (ao_outburst %d)\n", ao_data.outburst);
// printf("ao_sgi, get_space: alGetFillable [%d] \n", alGetFillable(ao_port)); // printf("ao_sgi, get_space: alGetFillable [%d] \n", alGetFillable(ao_port));
return alGetFillable(ao_port)*(2*ao_data.channels); return alGetFillable(ao_port) * bytes_per_frame;
} }
@ -171,12 +261,24 @@ static int get_space() {
// return: number of bytes played // return: number of bytes played
static int play(void* data, int len, int flags) { static int play(void* data, int len, int flags) {
// printf("ao_sgi, play: len %d flags %d (%d %d)\n", len, flags, ao_port, ao_config); /* Always process data in quadword-aligned chunks (64-bits). */
// printf("channels %d\n", ao_channels); const int plen = len / (sizeof(uint64_t) * bytes_per_frame);
const int framecount = plen * sizeof(uint64_t);
alWriteFrames(ao_port, data, len/(2*ao_data.channels)); // printf("ao_sgi, play: len %d flags %d (%d %d)\n", len, flags, ao_port, ao_config);
// printf("channels %d\n", ao_data.channels);
return len;
if(ao_data.format == AF_FORMAT_S32_NE) {
/* The zen of this is explained in fmt2sgial() */
int32_t *smpls = data;
const int32_t *smple = smpls + (framecount * ao_data.channels);
while(smpls < smple)
*smpls++ >>= 8;
}
alWriteFrames(ao_port, data, framecount);
return framecount * bytes_per_frame;
} }
@ -185,8 +287,10 @@ static float get_delay(){
// printf("ao_sgi, get_delay: (ao_buffersize %d)\n", ao_buffersize); // printf("ao_sgi, get_delay: (ao_buffersize %d)\n", ao_buffersize);
//return 0; // return (float)queue_size/((float)sample_rate);
return (float)queue_size/((float)sample_rate); const int outstanding = alGetFilled(ao_port);
return (float)((outstanding < 0) ? queue_size : outstanding) /
((float)sample_rate);
} }