Esempio n. 1
0
File: af_format.c Progetto: benf/mpv
// Check for unsupported formats
static int check_format(int format)
{
  char buf[256];
  if ((format & AF_FORMAT_SPECIAL_MASK) == 0)
    return AF_OK;
  mp_msg(MSGT_AFILTER, MSGL_ERR, "[format] Sample format %s not yet supported \n",
         af_fmt2str(format,buf,256));
  return AF_ERROR;
}
Esempio n. 2
0
// Check for unsupported formats
static int check_format(int format)
{
  char buf[256];
  switch(format & AF_FORMAT_SPECIAL_MASK){
  case(AF_FORMAT_IMA_ADPCM):
  case(AF_FORMAT_MPEG2):
  case(AF_FORMAT_AC3):
    mp_msg(MSGT_AFILTER, MSGL_ERR, "[format] Sample format %s not yet supported \n",
	 af_fmt2str(format,buf,256));
    return AF_ERROR;
  }
  return AF_OK;
}
Esempio n. 3
0
enum AVSampleFormat affmt2samplefmt(int fmt)
{
    char str[50];
    int i;
    enum AVSampleFormat sample_fmt;
    for (i = 0; samplefmt_conversion_map[i].fmt; i++)
        if (samplefmt_conversion_map[i].fmt == fmt)
            break;
    sample_fmt = samplefmt_conversion_map[i].sample_fmt;
    if (sample_fmt == AV_SAMPLE_FMT_NONE)
        mp_msg(MSGT_GLOBAL, MSGL_ERR, "Unsupported format %s\n",
               af_fmt2str(fmt, str, sizeof(str)));
    return sample_fmt;
}
Esempio n. 4
0
static int af_open(af_instance_t* af){

    af_ac3enc_t *s = calloc(1,sizeof(af_ac3enc_t));
    af->control=control;
    af->uninit=uninit;
    af->play=play;
    af->mul=1;
    af->data=calloc(1,sizeof(af_data_t));
    af->setup=s;

    s->lavc_acodec = avcodec_find_encoder_by_name("ac3");
    if (!s->lavc_acodec) {
        mp_tmsg(MSGT_AFILTER, MSGL_ERR, "Audio LAVC, couldn't find encoder for codec %s.\n", "ac3");
        return AF_ERROR;
    }

    s->lavc_actx = avcodec_alloc_context3(s->lavc_acodec);
    if (!s->lavc_actx) {
        mp_tmsg(MSGT_AFILTER, MSGL_ERR, "Audio LAVC, couldn't allocate context!\n");
        return AF_ERROR;
    }
    const enum AVSampleFormat *fmts = s->lavc_acodec->sample_fmts;
    for (int i = 0; ; i++) {
        if (fmts[i] == AV_SAMPLE_FMT_NONE) {
            mp_msg(MSGT_AFILTER, MSGL_ERR, "Audio LAVC, encoder doesn't "
                   "support expected sample formats!\n");
            return AF_ERROR;
        } else if (fmts[i] == AV_SAMPLE_FMT_S16) {
            s->in_sampleformat = AF_FORMAT_S16_NE;
            s->lavc_actx->sample_fmt = fmts[i];
            break;
        } else if (fmts[i] == AV_SAMPLE_FMT_FLT) {
            s->in_sampleformat = AF_FORMAT_FLOAT_NE;
            s->lavc_actx->sample_fmt = fmts[i];
            break;
        }
    }
    char buf[100];
    mp_msg(MSGT_AFILTER, MSGL_V, "[af_lavcac3enc]: in sample format: %s\n",
           af_fmt2str(s->in_sampleformat, buf, 100));
    s->pending_data_size = AF_NCH * AC3_FRAME_SIZE *
        af_fmt2bits(s->in_sampleformat) / 8;
    s->pending_data = malloc(s->pending_data_size);

    return AF_OK;
}
Esempio n. 5
0
static demuxer_t* demux_open_tv(demuxer_t *demuxer)
{
    tvi_handle_t *tvh;
    sh_video_t *sh_video;
    sh_audio_t *sh_audio = NULL;
    const tvi_functions_t *funcs;

    demuxer->priv=NULL;
    if(!(tvh=tv_begin(demuxer->stream->priv))) return NULL;
    if (!tvh->functions->init(tvh->priv)) return NULL;

    tvh->demuxer = demuxer;
    tvh->functions->control(tvh->priv,TVI_CONTROL_VBI_INIT,
                            &(tvh->tv_param->teletext.device));
    tvh->functions->control(tvh->priv,TVI_CONTROL_GET_VBI_PTR,
                            &demuxer->teletext);

    if (!open_tv(tvh)) {
        tv_uninit(tvh);
        return NULL;
    }
    funcs = tvh->functions;
    demuxer->priv=tvh;

    sh_video = new_sh_video(demuxer, 0);

    /* get IMAGE FORMAT */
    funcs->control(tvh->priv, TVI_CONTROL_VID_GET_FORMAT, &sh_video->format);
//    if (IMGFMT_IS_RGB(sh_video->format) || IMGFMT_IS_BGR(sh_video->format))
//	sh_video->format = 0x0;

    /* set FPS and FRAMETIME */

    if(!sh_video->fps)
    {
        float tmp;
        if (funcs->control(tvh->priv, TVI_CONTROL_VID_GET_FPS, &tmp) != TVI_CONTROL_TRUE)
            sh_video->fps = 25.0f; /* on PAL */
        else sh_video->fps = tmp;
    }

    if (tvh->tv_param->fps != -1.0f)
        sh_video->fps = tvh->tv_param->fps;

    sh_video->frametime = 1.0f/sh_video->fps;

    /* If playback only mode, go to immediate mode, fail silently */
    if(tvh->tv_param->immediate == 1)
    {
        funcs->control(tvh->priv, TVI_CONTROL_IMMEDIATE, 0);
        tvh->tv_param->noaudio = 1;
    }

    /* disable TV audio if -nosound is present */
    if (!demuxer->audio || demuxer->audio->id == -2) {
        tvh->tv_param->noaudio = 1;
    }

    /* set width */
    funcs->control(tvh->priv, TVI_CONTROL_VID_GET_WIDTH, &sh_video->disp_w);

    /* set height */
    funcs->control(tvh->priv, TVI_CONTROL_VID_GET_HEIGHT, &sh_video->disp_h);

    demuxer->video->sh = sh_video;
    sh_video->ds = demuxer->video;
    demuxer->video->id = 0;
    demuxer->seekable = 0;

    /* here comes audio init */
    if (tvh->tv_param->noaudio == 0 && funcs->control(tvh->priv, TVI_CONTROL_IS_AUDIO, 0) == TVI_CONTROL_TRUE)
    {
        int audio_format;
        int sh_audio_format;
        char buf[128];

        /* yeah, audio is present */

        funcs->control(tvh->priv, TVI_CONTROL_AUD_SET_SAMPLERATE,
                       &tvh->tv_param->audiorate);

        if (funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_FORMAT, &audio_format) != TVI_CONTROL_TRUE)
            goto no_audio;

        switch(audio_format)
        {
        case AF_FORMAT_U8:
        case AF_FORMAT_S8:
        case AF_FORMAT_U16_LE:
        case AF_FORMAT_U16_BE:
        case AF_FORMAT_S16_LE:
        case AF_FORMAT_S16_BE:
        case AF_FORMAT_S32_LE:
        case AF_FORMAT_S32_BE:
            sh_audio_format = 0x1; /* PCM */
            break;
        case AF_FORMAT_IMA_ADPCM:
        case AF_FORMAT_MU_LAW:
        case AF_FORMAT_A_LAW:
        case AF_FORMAT_MPEG2:
        default:
            mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_UnsupportedAudioType,
                   af_fmt2str(audio_format, buf, 128), audio_format);
            goto no_audio;
        }

        sh_audio = new_sh_audio(demuxer, 0, NULL);

        funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_SAMPLERATE,
                       &sh_audio->samplerate);
        funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_SAMPLESIZE,
                       &sh_audio->samplesize);
        funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_CHANNELS,
                       &sh_audio->channels);

        sh_audio->format = sh_audio_format;
        sh_audio->sample_format = audio_format;

        sh_audio->i_bps = sh_audio->o_bps =
                              sh_audio->samplerate * sh_audio->samplesize *
                              sh_audio->channels;

        // emulate WF for win32 codecs:
        sh_audio->wf = malloc(sizeof(*sh_audio->wf));
        sh_audio->wf->wFormatTag = sh_audio->format;
        sh_audio->wf->nChannels = sh_audio->channels;
        sh_audio->wf->wBitsPerSample = sh_audio->samplesize * 8;
        sh_audio->wf->nSamplesPerSec = sh_audio->samplerate;
        sh_audio->wf->nBlockAlign = sh_audio->samplesize * sh_audio->channels;
        sh_audio->wf->nAvgBytesPerSec = sh_audio->i_bps;

        mp_msg(MSGT_DECVIDEO, MSGL_V, "  TV audio: %d channels, %d bits, %d Hz\n",
               sh_audio->wf->nChannels, sh_audio->wf->wBitsPerSample,
               sh_audio->wf->nSamplesPerSec);

        demuxer->audio->sh = sh_audio;
        sh_audio->ds = demuxer->audio;
        demuxer->audio->id = 0;
    }
no_audio:

    if(!(funcs->start(tvh->priv))) {
        // start failed :(
        tv_uninit(tvh);
        return NULL;
    }

    /* set color eq */
    tv_set_color_options(tvh, TV_COLOR_BRIGHTNESS, tvh->tv_param->brightness);
    tv_set_color_options(tvh, TV_COLOR_HUE, tvh->tv_param->hue);
    tv_set_color_options(tvh, TV_COLOR_SATURATION, tvh->tv_param->saturation);
    tv_set_color_options(tvh, TV_COLOR_CONTRAST, tvh->tv_param->contrast);

    if(tvh->tv_param->gain!=-1)
        if(funcs->control(tvh->priv,TVI_CONTROL_VID_SET_GAIN,&tvh->tv_param->gain)!=TVI_CONTROL_TRUE)
            mp_msg(MSGT_TV,MSGL_WARN,"Unable to set gain control!\n");

    teletext_control(demuxer->teletext,TV_VBI_CONTROL_RESET,
                     &tvh->tv_param->teletext);

    return demuxer;
}
Esempio n. 6
0
// Initialization and runtime control
static int control(struct af_instance_s* af, int cmd, void* arg)
{
  switch(cmd){
  case AF_CONTROL_REINIT:{
    char buf1[256];
    char buf2[256];
    af_data_t *data = arg;

    // Make sure this filter isn't redundant
    if(af->data->format == data->format &&
       af->data->bps == data->bps)
      return AF_DETACH;

    // Allow trivial AC3-endianness conversion
    if (!AF_FORMAT_IS_AC3(af->data->format) || !AF_FORMAT_IS_AC3(data->format))
    // Check for errors in configuration
    if((AF_OK != check_bps(data->bps)) ||
       (AF_OK != check_format(data->format)) ||
       (AF_OK != check_bps(af->data->bps)) ||
       (AF_OK != check_format(af->data->format)))
      return AF_ERROR;

    mp_msg(MSGT_AFILTER, MSGL_V, "[format] Changing sample format from %s to %s\n",
	   af_fmt2str(data->format,buf1,256),
	   af_fmt2str(af->data->format,buf2,256));

    af->data->rate = data->rate;
    af->data->nch  = data->nch;
    af->mul        = (double)af->data->bps / data->bps;

    af->play = play; // set default

    // look whether only endianness differences are there
    if ((af->data->format & ~AF_FORMAT_END_MASK) ==
	(data->format & ~AF_FORMAT_END_MASK))
    {
	mp_msg(MSGT_AFILTER, MSGL_V, "[format] Accelerated endianness conversion only\n");
	af->play = play_swapendian;
    }
    if ((data->format == AF_FORMAT_FLOAT_NE) &&
	(af->data->format == AF_FORMAT_S16_NE))
    {
	mp_msg(MSGT_AFILTER, MSGL_V, "[format] Accelerated %s to %s conversion\n",
	   af_fmt2str(data->format,buf1,256),
	   af_fmt2str(af->data->format,buf2,256));
	af->play = play_float_s16;
    }
    if ((data->format == AF_FORMAT_S16_NE) &&
	(af->data->format == AF_FORMAT_FLOAT_NE))
    {
	mp_msg(MSGT_AFILTER, MSGL_V, "[format] Accelerated %s to %s conversion\n",
	   af_fmt2str(data->format,buf1,256),
	   af_fmt2str(af->data->format,buf2,256));
	af->play = play_s16_float;
    }
    return AF_OK;
  }
  case AF_CONTROL_COMMAND_LINE:{
    int format = af_str2fmt_short(bstr0(arg));
    if (format == -1) {
      mp_msg(MSGT_AFILTER, MSGL_ERR, "[format] %s is not a valid format\n", (char *)arg);
      return AF_ERROR;
    }
    if(AF_OK != af->control(af,AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET,&format))
      return AF_ERROR;
    return AF_OK;
  }
  case AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET:{
    // Check for errors in configuration
    if(!AF_FORMAT_IS_AC3(*(int*)arg) && AF_OK != check_format(*(int*)arg))
      return AF_ERROR;

    af->data->format = *(int*)arg;
    af->data->bps = af_fmt2bits(af->data->format)/8;

    return AF_OK;
  }
  }
  return AF_UNKNOWN;
}
Esempio n. 7
0
File: tv.c Progetto: pushrax/mpv
static int demux_open_tv(demuxer_t *demuxer, enum demux_check check)
{
    tvi_handle_t *tvh;
    sh_video_t *sh_video;
    sh_audio_t *sh_audio = NULL;
    const tvi_functions_t *funcs;

    if (check > DEMUX_CHECK_REQUEST || demuxer->stream->type != STREAMTYPE_TV)
        return -1;

    demuxer->priv=NULL;
    if(!(tvh=tv_begin(demuxer->stream->priv))) return -1;
    if (!tvh->functions->init(tvh->priv)) return -1;

    tvh->demuxer = demuxer;

    if (!open_tv(tvh)){
	tv_uninit(tvh);
	return -1;
    }
    funcs = tvh->functions;
    demuxer->priv=tvh;

    struct sh_stream *sh_v = new_sh_stream(demuxer, STREAM_VIDEO);
    sh_video = sh_v->video;

    /* get IMAGE FORMAT */
    int fourcc;
    funcs->control(tvh->priv, TVI_CONTROL_VID_GET_FORMAT, &fourcc);
    if (fourcc == MP_FOURCC_MJPEG) {
        sh_video->gsh->codec = "mjpeg";
    } else {
        sh_video->gsh->codec = "rawvideo";
        sh_video->format = fourcc;
    }

    /* set FPS and FRAMETIME */

    if(!sh_video->fps)
    {
        float tmp;
        if (funcs->control(tvh->priv, TVI_CONTROL_VID_GET_FPS, &tmp) != TVI_CONTROL_TRUE)
             sh_video->fps = 25.0f; /* on PAL */
        else sh_video->fps = tmp;
    }

    if (tvh->tv_param->fps != -1.0f)
        sh_video->fps = tvh->tv_param->fps;

    /* If playback only mode, go to immediate mode, fail silently */
    if(tvh->tv_param->immediate == 1)
        {
        funcs->control(tvh->priv, TVI_CONTROL_IMMEDIATE, 0);
        tvh->tv_param->noaudio = 1;
        }

    /* set width */
    funcs->control(tvh->priv, TVI_CONTROL_VID_GET_WIDTH, &sh_video->disp_w);

    /* set height */
    funcs->control(tvh->priv, TVI_CONTROL_VID_GET_HEIGHT, &sh_video->disp_h);

    demuxer->seekable = 0;

    /* here comes audio init */
    if (tvh->tv_param->noaudio == 0 && funcs->control(tvh->priv, TVI_CONTROL_IS_AUDIO, 0) == TVI_CONTROL_TRUE)
    {
	int audio_format;
	char buf[128];

	/* yeah, audio is present */

	funcs->control(tvh->priv, TVI_CONTROL_AUD_SET_SAMPLERATE,
				  &tvh->tv_param->audiorate);

	if (funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_FORMAT, &audio_format) != TVI_CONTROL_TRUE)
	    goto no_audio;

	switch(audio_format)
	{
	    case AF_FORMAT_U8:
	    case AF_FORMAT_S8:
	    case AF_FORMAT_U16_LE:
	    case AF_FORMAT_U16_BE:
	    case AF_FORMAT_S16_LE:
	    case AF_FORMAT_S16_BE:
	    case AF_FORMAT_S32_LE:
	    case AF_FORMAT_S32_BE:
		break;
	    case AF_FORMAT_MPEG2:
	    default:
		mp_tmsg(MSGT_TV, MSGL_ERR, "Audio type '%s (%x)' unsupported!\n",
		    af_fmt2str(audio_format, buf, 128), audio_format);
		goto no_audio;
	}

	struct sh_stream *sh_a = new_sh_stream(demuxer, STREAM_AUDIO);
	sh_audio = sh_a->audio;

	funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_SAMPLERATE,
                   &sh_audio->samplerate);
	funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_SAMPLESIZE,
                   &sh_audio->samplesize);
        int nchannels = sh_audio->channels.num;
	funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_CHANNELS,
                   &nchannels);
        mp_chmap_from_channels(&sh_audio->channels, nchannels);

        sh_audio->gsh->codec = "mp-pcm";
	sh_audio->format = audio_format;

	sh_audio->i_bps =
	    sh_audio->samplerate * sh_audio->samplesize *
	    sh_audio->channels.num;

	// emulate WF for win32 codecs:
	sh_audio->wf = malloc(sizeof(*sh_audio->wf));
	sh_audio->wf->wFormatTag = sh_audio->format;
	sh_audio->wf->nChannels = sh_audio->channels.num;
	sh_audio->wf->wBitsPerSample = sh_audio->samplesize * 8;
	sh_audio->wf->nSamplesPerSec = sh_audio->samplerate;
	sh_audio->wf->nBlockAlign = sh_audio->samplesize * sh_audio->channels.num;
	sh_audio->wf->nAvgBytesPerSec = sh_audio->i_bps;

	mp_tmsg(MSGT_DECVIDEO, MSGL_V, "  TV audio: %d channels, %d bits, %d Hz\n",
          sh_audio->wf->nChannels, sh_audio->wf->wBitsPerSample,
          sh_audio->wf->nSamplesPerSec);
    }
no_audio:

    if(!(funcs->start(tvh->priv))){
	// start failed :(
	tv_uninit(tvh);
	return -1;
    }

    /* set color eq */
    tv_set_color_options(tvh, TV_COLOR_BRIGHTNESS, tvh->tv_param->brightness);
    tv_set_color_options(tvh, TV_COLOR_HUE, tvh->tv_param->hue);
    tv_set_color_options(tvh, TV_COLOR_SATURATION, tvh->tv_param->saturation);
    tv_set_color_options(tvh, TV_COLOR_CONTRAST, tvh->tv_param->contrast);

    if(tvh->tv_param->gain!=-1)
        if(funcs->control(tvh->priv,TVI_CONTROL_VID_SET_GAIN,&tvh->tv_param->gain)!=TVI_CONTROL_TRUE)
            mp_msg(MSGT_TV,MSGL_WARN,"Unable to set gain control!\n");

    return 0;
}
Esempio n. 8
0
File: af_format.c Progetto: benf/mpv
// Initialization and runtime control
static int control(struct af_instance* af, int cmd, void* arg)
{
  switch(cmd){
  case AF_CONTROL_REINIT:{
    char buf1[256];
    char buf2[256];
    struct mp_audio *data = arg;
    int supported_ac3 = 0;

    // Make sure this filter isn't redundant
    if(af->data->format == data->format)
      return AF_DETACH;

    // A bit complex because we can convert AC3
    // to generic iec61937 but not the other way
    // round.
    if (AF_FORMAT_IS_AC3(af->data->format))
      supported_ac3 = AF_FORMAT_IS_AC3(data->format);
    else if (AF_FORMAT_IS_IEC61937(af->data->format))
      supported_ac3 = AF_FORMAT_IS_IEC61937(data->format);

    // Allow trivial AC3-endianness conversion
    if (!supported_ac3)
    // Check for errors in configuration
    if((AF_OK != check_bps(data->bps)) ||
       (AF_OK != check_format(data->format)) ||
       (AF_OK != check_bps(af->data->bps)) ||
       (AF_OK != check_format(af->data->format)))
      return AF_ERROR;

    af_fmt2str(data->format,buf1,256);
    af_fmt2str(af->data->format,buf2,256);
    mp_msg(MSGT_AFILTER, MSGL_V, "[format] Changing sample format from %s to %s\n",
	   buf1, buf2);

    af->data->rate = data->rate;
    mp_audio_set_channels(af->data, &data->channels);
    af->mul        = (double)af->data->bps / data->bps;

    af->play = play; // set default

    // look whether only endianness differences are there
    if ((af->data->format & ~AF_FORMAT_END_MASK) ==
	(data->format & ~AF_FORMAT_END_MASK))
    {
	mp_msg(MSGT_AFILTER, MSGL_V, "[format] Accelerated endianness conversion only\n");
	af->play = play_swapendian;
    }
    if ((data->format == AF_FORMAT_FLOAT_NE) &&
	(af->data->format == AF_FORMAT_S16_NE))
    {
	mp_msg(MSGT_AFILTER, MSGL_V, "[format] Accelerated %s to %s conversion\n",
	   buf1, buf2);
	af->play = play_float_s16;
    }
    if ((data->format == AF_FORMAT_S16_NE) &&
	(af->data->format == AF_FORMAT_FLOAT_NE))
    {
	mp_msg(MSGT_AFILTER, MSGL_V, "[format] Accelerated %s to %s conversion\n",
	   buf1, buf2);
	af->play = play_s16_float;
    }
    return AF_OK;
  }
  case AF_CONTROL_COMMAND_LINE:{
    int format = af_str2fmt_short(bstr0(arg));
    if (!format) {
      mp_msg(MSGT_AFILTER, MSGL_ERR, "[format] %s is not a valid format\n", (char *)arg);
      return AF_ERROR;
    }
    if(AF_OK != af->control(af, AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET,&format))
      return AF_ERROR;
    return AF_OK;
  }
  case AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET:{
    // Check for errors in configuration
    if(!AF_FORMAT_IS_AC3(*(int*)arg) && AF_OK != check_format(*(int*)arg))
      return AF_ERROR;

    mp_audio_set_format(af->data, *(int*)arg);

    return AF_OK;
  }
  }
  return AF_UNKNOWN;
}
Esempio n. 9
0
// open & setup audio device
// return: 1=success 0=fail
static int init(int rate,int channels,int format,int flags){

    audio_info_t info;
    int pass;
    int ok;
    int convert_u8_s8;

    setup_device_paths();

    if (enable_sample_timing == RTSC_UNKNOWN
	&& !getenv("AO_SUN_DISABLE_SAMPLE_TIMING")) {
	enable_sample_timing = realtime_samplecounter_available(audio_dev);
    }

    mp_msg(MSGT_AO,MSGL_STATUS,"ao2: %d Hz  %d chans  %s [0x%X]\n",
	   rate,channels,af_fmt2str_short(format),format);

    audio_fd=open(audio_dev, O_WRONLY);
    if(audio_fd<0){
	mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_SUN_CantOpenAudioDev, audio_dev, strerror(errno));
	return 0;
    }

    if (af2sunfmt(format) == AUDIO_ENCODING_NONE)
      format = AF_FORMAT_S16_NE;

    for (ok = pass = 0; pass <= 5; pass++) { /* pass 6&7 not useful */

	AUDIO_INITINFO(&info);
	info.play.encoding = af2sunfmt(ao_data.format = format);
	info.play.precision =
	    (format==AF_FORMAT_S16_NE
	     ? AUDIO_PRECISION_16
	     : AUDIO_PRECISION_8);
	info.play.channels = ao_data.channels = channels;
	info.play.sample_rate = ao_data.samplerate = rate;

	convert_u8_s8 = 0;

	if (pass & 1) {
	    /*
	     * on some sun audio drivers, 8-bit unsigned LINEAR8 encoding is
	     * not supported, but 8-bit signed encoding is.
	     *
	     * Try S8, and if it works, use our own U8->S8 conversion before
	     * sending the samples to the sound driver.
	     */
#ifdef AUDIO_ENCODING_LINEAR8
	    if (info.play.encoding != AUDIO_ENCODING_LINEAR8)
#endif
		continue;
	    info.play.encoding = AUDIO_ENCODING_LINEAR;
	    convert_u8_s8 = 1;
	}

	if (pass & 2) {
	    /*
	     * on some sun audio drivers, only certain fixed sample rates are
	     * supported.
	     *
	     * In case the requested sample rate is very close to one of the
	     * supported rates,  use the fixed supported rate instead.
	     */
	    if (!(info.play.sample_rate =
		  find_close_samplerate_match(audio_fd, rate)))
	      continue;

	    /*
	     * I'm not returning the correct sample rate in
	     * |ao_data.samplerate|, to avoid software resampling.
	     *
	     * ao_data.samplerate = info.play.sample_rate;
	     */
	}

	if (pass & 4) {
	    /* like "pass & 2", but use the highest supported sample rate */
	    if (!(info.play.sample_rate
		  = ao_data.samplerate
		  = find_highest_samplerate(audio_fd)))
		continue;
	}

	ok = ioctl(audio_fd, AUDIO_SETINFO, &info) >= 0;
	if (ok) {
	    /* audio format accepted by audio driver */
	    break;
	}

	/*
	 * format not supported?
	 * retry with different encoding and/or sample rate
	 */
    }

    if (!ok) {
	char buf[128];
	mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_SUN_UnsupSampleRate,
	       channels, af_fmt2str(format, buf, 128), rate);
	return 0;
    }

    if (convert_u8_s8)
      ao_data.format = AF_FORMAT_S8;

    bytes_per_sample = channels * info.play.precision / 8;
    ao_data.bps = byte_per_sec = bytes_per_sample * ao_data.samplerate;
    ao_data.outburst = byte_per_sec > 100000 ? 16384 : 8192;

    reset();

    return 1;
}