mirror of
https://github.com/mpv-player/mpv
synced 2025-01-18 04:51:52 +00:00
Applied patch by Jürgen Keil (jk@tools.de), improves smoothness of video playback.
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@1197 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
parent
a43e6724b9
commit
600ae0bdde
261
libao2/ao_sun.c
261
libao2/ao_sun.c
@ -1,12 +1,14 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/audioio.h>
|
||||
#ifdef __svr4__
|
||||
#include <stropts.h>
|
||||
@ -20,18 +22,23 @@
|
||||
|
||||
static ao_info_t info =
|
||||
{
|
||||
"Sun audio output",
|
||||
"sun",
|
||||
"jk@tools.de",
|
||||
""
|
||||
"Sun audio output",
|
||||
"sun",
|
||||
"jk@tools.de",
|
||||
""
|
||||
};
|
||||
|
||||
LIBAO_EXTERN(sun)
|
||||
|
||||
|
||||
/* These defines are missing on NetBSD */
|
||||
#ifndef AUDIO_PRECISION_8
|
||||
#define AUDIO_PRECISION_8 8
|
||||
#define AUDIO_PRECISION_16 16
|
||||
#define AUDIO_PRECISION_8 8
|
||||
#define AUDIO_PRECISION_16 16
|
||||
#endif
|
||||
#ifndef AUDIO_CHANNELS_MONO
|
||||
#define AUDIO_CHANNELS_MONO 1
|
||||
#define AUDIO_CHANNELS_STEREO 2
|
||||
#endif
|
||||
|
||||
|
||||
@ -43,9 +50,19 @@ LIBAO_EXTERN(sun)
|
||||
// ao_outburst
|
||||
// ao_buffersize
|
||||
|
||||
static char *dsp="/dev/audio";
|
||||
static char *audio_dev = "/dev/audio";
|
||||
static int queued_bursts = 0;
|
||||
static int audio_fd=-1;
|
||||
static int queued_samples = 0;
|
||||
static int bytes_per_sample = 0;
|
||||
static int audio_fd = -1;
|
||||
static enum {
|
||||
RTSC_UNKNOWN = 0,
|
||||
RTSC_ENABLED,
|
||||
RTSC_DISABLED
|
||||
} enable_sample_timing;
|
||||
|
||||
extern int verbose;
|
||||
|
||||
|
||||
// convert an OSS audio format specification into a sun audio encoding
|
||||
static int oss2sunfmt(int oss_format)
|
||||
@ -68,16 +85,127 @@ static int oss2sunfmt(int oss_format)
|
||||
}
|
||||
}
|
||||
|
||||
// try to figure out, if the soundcard driver provides usable (precise)
|
||||
// sample counter information
|
||||
static int realtime_samplecounter_available(char *dev)
|
||||
{
|
||||
int fd = -1;
|
||||
audio_info_t info;
|
||||
int rtsc_ok = RTSC_DISABLED;
|
||||
int len;
|
||||
void *silence = NULL;
|
||||
struct timeval start, end;
|
||||
struct timespec delay;
|
||||
int usec_delay;
|
||||
unsigned last_samplecnt;
|
||||
unsigned increment;
|
||||
unsigned min_increment;
|
||||
|
||||
len = 44100 * 4 / 4; // amount of data for 0.25sec of 44.1khz, stereo, 16bit
|
||||
silence = calloc(1, len);
|
||||
if (silence == NULL)
|
||||
goto error;
|
||||
|
||||
if ((fd = open(dev, O_WRONLY)) < 0)
|
||||
goto error;
|
||||
|
||||
AUDIO_INITINFO(&info);
|
||||
info.play.sample_rate = 44100;
|
||||
info.play.channels = AUDIO_CHANNELS_STEREO;
|
||||
info.play.precision = AUDIO_PRECISION_16;
|
||||
info.play.encoding = AUDIO_ENCODING_LINEAR;
|
||||
info.play.samples = 0;
|
||||
if (ioctl(fd, AUDIO_SETINFO, &info)) {
|
||||
if (verbose)
|
||||
printf("rtsc: SETINFO failed\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (write(fd, silence, len) != len) {
|
||||
if (verbose)
|
||||
printf("rtsc: write failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (ioctl(fd, AUDIO_GETINFO, &info)) {
|
||||
if (verbose)
|
||||
perror("rtsc: GETINFO1");
|
||||
goto error;
|
||||
}
|
||||
|
||||
last_samplecnt = info.play.samples;
|
||||
min_increment = ~0;
|
||||
|
||||
gettimeofday(&start, NULL);
|
||||
for (;;) {
|
||||
delay.tv_sec = 0;
|
||||
delay.tv_nsec = 10000000;
|
||||
nanosleep(&delay, NULL);
|
||||
gettimeofday(&end, NULL);
|
||||
usec_delay = (end.tv_sec - start.tv_sec) * 1000000
|
||||
+ end.tv_usec - start.tv_usec;
|
||||
|
||||
// stop monitoring sample counter after 0.2 seconds
|
||||
if (usec_delay > 200000)
|
||||
break;
|
||||
|
||||
if (ioctl(fd, AUDIO_GETINFO, &info)) {
|
||||
if (verbose)
|
||||
perror("rtsc: GETINFO2 failed");
|
||||
goto error;
|
||||
}
|
||||
if (info.play.samples < last_samplecnt) {
|
||||
if (verbose)
|
||||
printf("rtsc: %d > %d?\n", last_samplecnt, info.play.samples);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((increment = info.play.samples - last_samplecnt) > 0) {
|
||||
if (verbose)
|
||||
printf("ao_sun: sample counter increment: %d\n", increment);
|
||||
if (increment < min_increment) {
|
||||
min_increment = increment;
|
||||
if (min_increment < 2000)
|
||||
break; // looks good
|
||||
}
|
||||
}
|
||||
last_samplecnt = info.play.samples;
|
||||
}
|
||||
|
||||
if (min_increment < 2000)
|
||||
rtsc_ok = RTSC_ENABLED;
|
||||
|
||||
if (verbose)
|
||||
printf("ao_sun: minimum sample counter increment per 10msec interval: %d\n"
|
||||
"\t%susing sample counter based timing code\n",
|
||||
min_increment, rtsc_ok == RTSC_ENABLED ? "" : "not ");
|
||||
|
||||
|
||||
error:
|
||||
if (silence != NULL) free(silence);
|
||||
if (fd >= 0) {
|
||||
#ifdef __svr4__
|
||||
// remove the 0 bytes from the above measurement from the
|
||||
// audio driver's STREAMS queue
|
||||
ioctl(fd, I_FLUSH, FLUSHW);
|
||||
#endif
|
||||
//ioctl(fd, AUDIO_DRAIN, 0);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return rtsc_ok;
|
||||
}
|
||||
|
||||
// to set/get/query special features/parameters
|
||||
static int control(int cmd,int arg){
|
||||
switch(cmd){
|
||||
case AOCONTROL_SET_DEVICE:
|
||||
dsp=(char*)arg;
|
||||
return CONTROL_OK;
|
||||
case AOCONTROL_QUERY_FORMAT:
|
||||
return CONTROL_TRUE;
|
||||
}
|
||||
return CONTROL_UNKNOWN;
|
||||
switch(cmd){
|
||||
case AOCONTROL_SET_DEVICE:
|
||||
audio_dev=(char*)arg;
|
||||
return CONTROL_OK;
|
||||
case AOCONTROL_QUERY_FORMAT:
|
||||
return CONTROL_TRUE;
|
||||
}
|
||||
return CONTROL_UNKNOWN;
|
||||
}
|
||||
|
||||
// open & setup audio device
|
||||
@ -87,11 +215,17 @@ static int init(int rate,int channels,int format,int flags){
|
||||
audio_info_t info;
|
||||
int byte_per_sec;
|
||||
|
||||
printf("ao2: %d Hz %d chans 0x%X\n",rate,channels,format);
|
||||
if (enable_sample_timing == RTSC_UNKNOWN
|
||||
&& !getenv("AO_SUN_DISABLE_SAMPLE_TIMING")) {
|
||||
enable_sample_timing = realtime_samplecounter_available(audio_dev);
|
||||
}
|
||||
|
||||
audio_fd=open(dsp, O_WRONLY);
|
||||
printf("ao2: %d Hz %d chans %s [0x%X]\n",
|
||||
rate,channels,audio_out_format_name(format),format);
|
||||
|
||||
audio_fd=open(audio_dev, O_WRONLY);
|
||||
if(audio_fd<0){
|
||||
printf("Can't open audio device %s -> nosound\n",dsp);
|
||||
printf("Can't open audio device %s, %s -> nosound\n", audio_dev, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -101,15 +235,12 @@ static int init(int rate,int channels,int format,int flags){
|
||||
info.play.encoding = oss2sunfmt(ao_format = format);
|
||||
info.play.precision = (format==AFMT_S16_LE? AUDIO_PRECISION_16:AUDIO_PRECISION_8);
|
||||
info.play.channels = ao_channels = channels;
|
||||
--ao_channels;
|
||||
info.play.sample_rate = ao_samplerate = rate;
|
||||
info.play.samples = 0;
|
||||
info.play.eof = 0;
|
||||
if(ioctl (audio_fd, AUDIO_SETINFO, &info)<0)
|
||||
printf("audio_setup: your card doesn't support %d channel, %s, %d Hz samplerate\n",channels,audio_out_format_name(format),rate);
|
||||
byte_per_sec = (channels * info.play.precision * rate);
|
||||
ao_outburst=byte_per_sec > 100000 ? 16384 : 8192;
|
||||
queued_bursts = 0;
|
||||
bytes_per_sample = channels * info.play.precision / 8;
|
||||
byte_per_sec = bytes_per_sample * rate;
|
||||
ao_outburst = byte_per_sec > 100000 ? 16384 : 8192;
|
||||
|
||||
if(ao_buffersize==-1){
|
||||
// Measuring buffer size:
|
||||
@ -141,11 +272,24 @@ static int init(int rate,int channels,int format,int flags){
|
||||
#endif
|
||||
}
|
||||
|
||||
return 1;
|
||||
AUDIO_INITINFO(&info);
|
||||
info.play.samples = 0;
|
||||
info.play.eof = 0;
|
||||
info.play.error = 0;
|
||||
ioctl (audio_fd, AUDIO_SETINFO, &info);
|
||||
|
||||
queued_bursts = 0;
|
||||
queued_samples = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// close audio device
|
||||
static void uninit(){
|
||||
#ifdef __svr4__
|
||||
// throw away buffered data in the audio driver's STREAMS queue
|
||||
ioctl(audio_fd, I_FLUSH, FLUSHW);
|
||||
#endif
|
||||
close(audio_fd);
|
||||
}
|
||||
|
||||
@ -153,14 +297,10 @@ static void uninit(){
|
||||
static void reset(){
|
||||
audio_info_t info;
|
||||
|
||||
#ifdef __svr4__
|
||||
// throw away buffered data in the audio driver's STREAMS queue
|
||||
ioctl(audio_fd, I_FLUSH, FLUSHW);
|
||||
#endif
|
||||
uninit();
|
||||
audio_fd=open(dsp, O_WRONLY);
|
||||
audio_fd=open(audio_dev, O_WRONLY);
|
||||
if(audio_fd<0){
|
||||
printf("\nFatal error: *** CANNOT RE-OPEN / RESET AUDIO DEVICE ***\n");
|
||||
printf("\nFatal error: *** CANNOT RE-OPEN / RESET AUDIO DEVICE (%s) ***\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -169,12 +309,14 @@ static void reset(){
|
||||
AUDIO_INITINFO(&info);
|
||||
info.play.encoding = oss2sunfmt(ao_format);
|
||||
info.play.precision = (ao_format==AFMT_S16_LE? AUDIO_PRECISION_16:AUDIO_PRECISION_8);
|
||||
info.play.channels = ao_channels+1;
|
||||
info.play.channels = ao_channels;
|
||||
info.play.sample_rate = ao_samplerate;
|
||||
info.play.samples = 0;
|
||||
info.play.eof = 0;
|
||||
info.play.error = 0;
|
||||
ioctl (audio_fd, AUDIO_SETINFO, &info);
|
||||
queued_bursts = 0;
|
||||
queued_samples = 0;
|
||||
}
|
||||
|
||||
// stop playing, keep buffers (for pause)
|
||||
@ -198,49 +340,54 @@ static void audio_resume()
|
||||
|
||||
// return: how many bytes can be played without blocking
|
||||
static int get_space(){
|
||||
int playsize=ao_outburst;
|
||||
int playsize = ao_outburst;
|
||||
audio_info_t info;
|
||||
|
||||
// check buffer
|
||||
#ifdef HAVE_AUDIO_SELECT
|
||||
{ fd_set rfds;
|
||||
struct timeval tv;
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(audio_fd, &rfds);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
if(!select(audio_fd+1, NULL, &rfds, NULL, &tv)) return 0; // not block!
|
||||
{
|
||||
fd_set rfds;
|
||||
struct timeval tv;
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(audio_fd, &rfds);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
if(!select(audio_fd+1, NULL, &rfds, NULL, &tv)) return 0; // not block!
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
audio_info_t info;
|
||||
ioctl(audio_fd, AUDIO_GETINFO, &info);
|
||||
if(queued_bursts - info.play.eof > 2)
|
||||
return 0;
|
||||
}
|
||||
return ao_outburst;
|
||||
if (queued_bursts - info.play.eof > 2)
|
||||
return 0;
|
||||
|
||||
return ao_outburst;
|
||||
}
|
||||
|
||||
// plays 'len' bytes of 'data'
|
||||
// it should round it down to outburst*n
|
||||
// return: number of bytes played
|
||||
static int play(void* data,int len,int flags){
|
||||
len/=ao_outburst;
|
||||
len=write(audio_fd,data,len*ao_outburst);
|
||||
if(len>0) {
|
||||
queued_bursts ++;
|
||||
write(audio_fd,data,0);
|
||||
if (len < ao_outburst) return 0;
|
||||
len /= ao_outburst;
|
||||
len = write(audio_fd, data, len*ao_outburst);
|
||||
if(len > 0) {
|
||||
queued_samples += len / bytes_per_sample;
|
||||
if (write(audio_fd,data,0) < 0)
|
||||
perror("ao_sun: send EOF audio record");
|
||||
else
|
||||
queued_bursts ++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static int audio_delay_method=2;
|
||||
|
||||
// return: how many unplayed bytes are in the buffer
|
||||
static int get_delay(){
|
||||
int q;
|
||||
audio_info_t info;
|
||||
ioctl(audio_fd, AUDIO_GETINFO, &info);
|
||||
return (queued_bursts - info.play.eof) * ao_outburst;
|
||||
if (info.play.samples && enable_sample_timing == RTSC_ENABLED)
|
||||
return (queued_samples - info.play.samples) * bytes_per_sample;
|
||||
else
|
||||
return (queued_bursts - info.play.eof) * ao_outburst;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user