Hi, I noticed yesterday that xawtv does not support switching between mono/stereo/lang1/lang2 when using the xfree86 Xvideo extension (the v4l module). Out of impulse I hacked right away... Attached are two patches, one for xawtv-3.88, and one for xfree86-4.X (against the newest v4l.c fetched from xfree86 CVS). I didn't do much testing but it seems to work as I expected. Johannes
--- xc/programs/Xserver/hw/xfree86/drivers/v4l/v4l.c.cvs 2003-08-07 00:06:51.000000000 +0200 +++ xc/programs/Xserver/hw/xfree86/drivers/v4l/v4l.c 2003-08-07 01:13:59.000000000 +0200 @@ -122,6 +122,7 @@ typedef struct _PortPrivRec { /* attributes */ struct video_picture pict; struct video_audio audio; + int audio_mode; XF86VideoEncodingPtr enc; int *input; @@ -148,12 +149,13 @@ typedef struct _PortPrivRec { #define XV_FREQ "XV_FREQ" #define XV_MUTE "XV_MUTE" +#define XV_AUDIO_MODE "XV_AUDIO_MODE" #define XV_VOLUME "XV_VOLUME" #define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) static Atom xvEncoding, xvBrightness, xvContrast, xvSaturation, xvHue; -static Atom xvFreq, xvMute, xvVolume; +static Atom xvFreq, xvMute, xvAudioMode, xvVolume; static XF86VideoFormatRec InputVideoFormats[] = { @@ -176,6 +178,8 @@ static const XF86AttributeRec VolumeAttr {XvSettable | XvGettable, -1000, 1000, XV_VOLUME}; static const XF86AttributeRec MuteAttr = {XvSettable | XvGettable, 0, 1, XV_MUTE}; +static const XF86AttributeRec AudioModeAttr = + {XvSettable | XvGettable, 0, 15, XV_AUDIO_MODE}; static const XF86AttributeRec FreqAttr = {XvSettable | XvGettable, 0, 16*1000, XV_FREQ}; @@ -549,6 +553,7 @@ V4lSetPortAttribute(ScrnInfoPtr pScrn, pPPriv->cenc = value; chan.channel = pPPriv->input[value]; chan.norm = pPPriv->norm[value]; + pPPriv->audio_mode = 0; if (-1 == ioctl(V4L_FD,VIDIOCSCHAN,&chan)) perror("ioctl VIDIOCSCHAN"); } else { @@ -566,6 +571,7 @@ V4lSetPortAttribute(ScrnInfoPtr pScrn, if (-1 == ioctl(V4L_FD,VIDIOCSPICT,&pPPriv->pict)) perror("ioctl VIDIOCSPICT"); } else if (attribute == xvMute || + attribute == xvAudioMode || attribute == xvVolume) { ioctl(V4L_FD,VIDIOCGAUDIO,&pPPriv->audio); if (attribute == xvMute) { @@ -573,12 +579,24 @@ V4lSetPortAttribute(ScrnInfoPtr pScrn, pPPriv->audio.flags |= VIDEO_AUDIO_MUTE; else pPPriv->audio.flags &= ~VIDEO_AUDIO_MUTE; + } else if (attribute == xvAudioMode) { + if (value < 0) + value = 0; + else if (value > 8) + value = 8; + pPPriv->audio_mode = value; } else if (attribute == xvVolume) { if (pPPriv->audio.flags & VIDEO_AUDIO_VOLUME) pPPriv->audio.volume = xv_to_v4l(value); } else { ret = BadValue; } + /* have to set that all the time as read and write have + * slightly different semantics: + * read == bitmask with all available modes flagged + * write == one bit set (for the selected mode, zero is autodetect) + */ + pPPriv->audio.mode = pPPriv->audio_mode; if (ret != BadValue) if (-1 == ioctl(V4L_FD,VIDIOCSAUDIO,&pPPriv->audio)) perror("ioctl VIDIOCSAUDIO"); @@ -624,10 +642,13 @@ V4lGetPortAttribute(ScrnInfoPtr pScrn, if (attribute == xvSaturation) *value = v4l_to_xv(pPPriv->pict.colour); if (attribute == xvHue) *value = v4l_to_xv(pPPriv->pict.hue); } else if (attribute == xvMute || + attribute == xvAudioMode || attribute == xvVolume) { ioctl(V4L_FD,VIDIOCGAUDIO,&pPPriv->audio); if (attribute == xvMute) { *value = (pPPriv->audio.flags & VIDEO_AUDIO_MUTE) ? 1 : 0; + } else if (attribute == xvAudioMode) { + *value = pPPriv->audio.mode; } else if (attribute == xvVolume) { if (pPPriv->audio.flags & VIDEO_AUDIO_VOLUME) *value = v4l_to_xv(pPPriv->audio.volume); @@ -948,6 +969,8 @@ V4LInit(ScrnInfoPtr pScrn, XF86VideoAdap if (pPPriv->audio.flags & VIDEO_AUDIO_MUTABLE) v4l_add_attr(&VAR[i]->pAttributes, &VAR[i]->nAttributes, &MuteAttr); + v4l_add_attr(&VAR[i]->pAttributes, &VAR[i]->nAttributes, + &AudioModeAttr); } if (pPPriv->cap.type & VID_TYPE_TUNER) { /* tuner attributes */ @@ -1003,6 +1026,7 @@ V4LInit(ScrnInfoPtr pScrn, XF86VideoAdap xvFreq = MAKE_ATOM(XV_FREQ); xvMute = MAKE_ATOM(XV_MUTE); + xvAudioMode = MAKE_ATOM(XV_AUDIO_MODE); xvVolume = MAKE_ATOM(XV_VOLUME); DEBUG(xf86Msg(X_INFO, "v4l: init done, %d device(s) found\n",i));
--- xawtv-3.88/x11/xv.c.orig 2003-08-07 00:16:42.000000000 +0200 +++ xawtv-3.88/x11/xv.c 2003-08-07 01:02:56.000000000 +0200 @@ -41,6 +41,15 @@ static XvAdaptorInfo *ai; static XvEncodingInfo *ei; static XvAttribute *at; +static struct STRTAB stereo[] = { + { 0, "auto" }, + { 1, "mono" }, + { 2, "stereo" }, + { 4, "lang1" }, + { 8, "lang2" }, + { -1, NULL }, +}; + static int xv_overlay(void *handle, struct ng_video_fmt *fmt, int x, int y, struct OVERLAY_CLIP *oc, int count, int aspect) @@ -82,16 +91,17 @@ static const struct XVATTR { int type; char *atom; } xvattr[] = { - { ATTR_ID_COLOR, ATTR_TYPE_INTEGER, "XV_COLOR" }, - { ATTR_ID_COLOR, ATTR_TYPE_INTEGER, "XV_SATURATION" }, - { ATTR_ID_HUE, ATTR_TYPE_INTEGER, "XV_HUE", }, - { ATTR_ID_BRIGHT, ATTR_TYPE_INTEGER, "XV_BRIGHTNESS", }, - { ATTR_ID_CONTRAST, ATTR_TYPE_INTEGER, "XV_CONTRAST", }, - { ATTR_ID_MUTE, ATTR_TYPE_BOOL, "XV_MUTE", }, - { ATTR_ID_VOLUME, ATTR_TYPE_INTEGER, "XV_VOLUME", }, - { -1, -1, "XV_COLORKEY", }, - { -1, -1, "XV_FREQ", }, - { -1, -1, "XV_ENCODING", }, + { ATTR_ID_COLOR, ATTR_TYPE_INTEGER, "XV_COLOR" }, + { ATTR_ID_COLOR, ATTR_TYPE_INTEGER, "XV_SATURATION" }, + { ATTR_ID_HUE, ATTR_TYPE_INTEGER, "XV_HUE", }, + { ATTR_ID_BRIGHT, ATTR_TYPE_INTEGER, "XV_BRIGHTNESS", }, + { ATTR_ID_CONTRAST, ATTR_TYPE_INTEGER, "XV_CONTRAST", }, + { ATTR_ID_MUTE, ATTR_TYPE_BOOL, "XV_MUTE", }, + { ATTR_ID_AUDIO_MODE, ATTR_TYPE_CHOICE, "XV_AUDIO_MODE", }, + { ATTR_ID_VOLUME, ATTR_TYPE_INTEGER, "XV_VOLUME", }, + { -1, -1, "XV_COLORKEY", }, + { -1, -1, "XV_FREQ", }, + { -1, -1, "XV_ENCODING", }, {} }; @@ -422,8 +432,12 @@ void xv_video_init(unsigned int port, in at[i].min_value,at[i].max_value); if (0 == strcmp("XV_ENCODING",at[i].name)) handle->xv_encoding = XV_ENCODING; - if (0 == strcmp("XV_FREQ",at[i].name)) + else if (0 == strcmp("XV_FREQ",at[i].name)) handle->xv_freq = XV_FREQ; + else if (0 == strcmp("XV_AUDIO_MODE",at[i].name)) { + xv_add_attr(handle, 0, 0, 0, stereo, at+i); + continue; + } #if 0 if (0 == strcmp("XV_COLORKEY",at[i].name)) handle->xv_colorkey = XV_COLORKEY;