⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 stream_radio.c

📁 君正早期ucos系统(只有早期的才不没有打包成库),MPLAYER,文件系统,图片解码,浏览,电子书,录音,想学ucos,识货的人就下吧 russblock fmradio explore set
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *     Radio support *  *     Initially wrote by Vladimir Voroshilov <voroshil@univer.omsk.su>. *     Based on tv.c and tvi_v4l2.c code. * *     This program 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. * *     This program 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 St, Fifth Floor, Boston, MA 02110-1301 USA * * *     Abilities: *     * Listening v4l compatible radio cards using line-in or *       similar cable *     * Grabbing audio data using -ao pcm or -dumpaudio *       (must be compiled with --enable-radio-capture). */#include "config.h"#include <mplaylib.h>#include <mplaylib.h>#include <mplaylib.h>#include <sys/ioctl.h>#include <errno.h>#include <mplaylib.h>#ifdef HAVE_RADIO_BSDBT848#include <sys/param.h>#ifdef IOCTL_BT848_H_NAME#include IOCTL_BT848_H_NAME#endif#else // HAVE_RADIO_BSDBT848#include <linux/types.h>#ifdef HAVE_RADIO_V4L2#include <linux/videodev2.h>#endif#ifdef HAVE_RADIO_V4L#include <linux/videodev.h>#warning  "V4L is deprecated and will be removed in future"#endif#endif // !IOCTL_BT848_H_NAME#include "stream.h"#include "libmpdemux/demuxer.h"#include "m_struct.h"#include "m_option.h"#include "mp_msg.h"#include "help_mp.h"#include "stream_radio.h"#include "libavutil/avstring.h"#ifdef USE_RADIO_CAPTURE#include "audio_in.h"#ifdef HAVE_SYS_SOUNDCARD_H#include <sys/soundcard.h>#else#ifdef HAVE_SOUNDCARD_H#include <soundcard.h>#else#include <linux/soundcard.h>#endif#endif#endif#undef memcpy#define memcpy uc_memcpytypedef struct radio_channels_s {    int index;     ///< channel index in channels list    float freq;    ///< frequency in MHz    char name[20]; ///< channel name    struct radio_channels_s * next;    struct radio_channels_s * prev;} radio_channels_t;/// default values for optionsradio_param_t stream_radio_defaults={#ifdef HAVE_RADIO_BSDBT848    "/dev/tuner0", //device    87.50,         //freq_min    108.00,        //freq_max#else    "/dev/radio0", //device;#endif    "default",     //driver    NULL,          //channels    100,           //volume    NULL,          //adevice    44100,         //arate    2,             //achannels    0,             //freq_channel    NULL,          //capture};typedef struct radio_priv_s {    int                 radio_fd;          ///< radio device descriptor    int                 frac;              ///< fraction value (see comment to init_frac)    radio_channels_t*   radio_channel_list;    radio_channels_t*   radio_channel_current;    float rangelow;                        ///< lowest tunable frequency in MHz    float rangehigh;                       ///< highest tunable frequency in MHz    const struct radio_driver_s*     driver;    int                 old_snd_volume;#ifdef USE_RADIO_CAPTURE    volatile int        do_capture;        ///< is capture enabled    audio_in_t          audio_in;    unsigned char*      audio_ringbuffer;    int                 audio_head;        ///< start of meanfull data in ringbuffer    int                 audio_tail;        ///< end of meanfull data in ringbuffer    int                 audio_buffer_size; ///< size of ringbuffer    int                 audio_cnt;         ///< size of meanfull data inringbuffer    int                 audio_drop;        ///< number of dropped bytes    int                 audio_inited;#endif    radio_param_t       *radio_param;} radio_priv_t;typedef struct radio_driver_s {    char* name;    char* info;    int (*init_frac)(radio_priv_t* priv);    void (*set_volume)(radio_priv_t* priv,int volume);    int (*get_volume)(radio_priv_t* priv,int* volume);    int (*set_frequency)(radio_priv_t* priv,float frequency);    int (*get_frequency)(radio_priv_t* priv,float* frequency);} radio_driver_t;#define ST_OFF(f) M_ST_OFF(radio_param_t,f)static m_option_t stream_opts_fields[] = {    {"hostname", ST_OFF(freq_channel), CONF_TYPE_FLOAT, 0, 0 ,0, NULL},    {"filename", ST_OFF(capture), CONF_TYPE_STRING, 0, 0 ,0, NULL},    { NULL, NULL, 0, 0, 0, 0,  NULL }};static struct m_struct_st stream_opts = {    "radio",    sizeof(radio_param_t),    &stream_radio_defaults,    stream_opts_fields};static void close_s(struct stream_st * stream);#ifdef USE_RADIO_CAPTUREstatic int clear_buffer(radio_priv_t* priv);#endif/***************************************************************** * \brief parse channels parameter and store result into list * \param freq_channel if channels!=NULL this mean channel number, otherwise - frequency * \param pfreq selected frequency (from selected channel or from URL) * \result STREAM_OK if success, STREAM_ERROR otherwise * *  channels option must be in the following format *  <frequency>-<name>,<frequency>-<name>,... * *  '_' will be replaced with spaces. * *  If channels option is not null, number in movie URL will be treated as *  channel position in channel list. */static int parse_channels(radio_priv_t* priv,float freq_channel,float* pfreq){    char** channels;    int i;    int channel = 0;    if (priv->radio_param->channels){        /*parsing channels string*/        channels=priv->radio_param->channels;        mp_msg(MSGT_RADIO, MSGL_INFO, MSGTR_RADIO_ChannelNamesDetected);        priv->radio_channel_list = malloc(sizeof(radio_channels_t));        priv->radio_channel_list->index=1;        priv->radio_channel_list->next=NULL;        priv->radio_channel_list->prev=NULL;        priv->radio_channel_current = priv->radio_channel_list;        while (*channels) {            char* tmp = *(channels++);            char* sep = strchr(tmp,'-');            if (!sep) continue; // Wrong syntax, but mplayer should not crash            av_strlcpy(priv->radio_channel_current->name, sep + 1,sizeof(priv->radio_channel_current->name)-1);            sep[0] = '\0';            priv->radio_channel_current->freq=atof(tmp);            if ((priv->radio_channel_current->freq>priv->rangehigh)||(priv->radio_channel_current->freq<priv->rangelow))                mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_WrongFreqForChannel,                    priv->radio_channel_current->name);            while ((sep=strchr(priv->radio_channel_current->name, '_'))) sep[0] = ' ';            priv->radio_channel_current->next = malloc(sizeof(radio_channels_t));            priv->radio_channel_current->next->index = priv->radio_channel_current->index + 1;            priv->radio_channel_current->next->prev = priv->radio_channel_current;            priv->radio_channel_current->next->next = NULL;            priv->radio_channel_current = priv->radio_channel_current->next;        }        if (priv->radio_channel_current->prev)            priv->radio_channel_current->prev->next = NULL;        free(priv->radio_channel_current);        if (freq_channel)            channel = freq_channel;        else            channel = 1;        priv->radio_channel_current = priv->radio_channel_list;        for (i = 1; i < channel; i++)            if (priv->radio_channel_current->next)                priv->radio_channel_current = priv->radio_channel_current->next;        if (priv->radio_channel_current->index!=channel){            if (((float)((int)freq_channel))!=freq_channel)                mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_WrongChannelNumberFloat,freq_channel);            else                mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_WrongChannelNumberInt,(int)freq_channel);            return STREAM_ERROR;        }        mp_msg(MSGT_RADIO, MSGL_INFO, MSGTR_RADIO_SelectedChannel, priv->radio_channel_current->index,            priv->radio_channel_current->name, priv->radio_channel_current->freq);        *pfreq=priv->radio_channel_current->freq;    }else{        if (freq_channel){            mp_msg(MSGT_RADIO, MSGL_INFO, MSGTR_RADIO_FreqParameterDetected);            priv->radio_channel_list=malloc(sizeof(radio_channels_t));            priv->radio_channel_list->next=NULL;            priv->radio_channel_list->prev=NULL;            priv->radio_channel_list->index=1;            snprintf(priv->radio_channel_list->name,sizeof(priv->radio_channel_current->name)-1,"Freq: %.2f",freq_channel);            priv->radio_channel_current=priv->radio_channel_list;            *pfreq=freq_channel;        }    }    mp_msg(MSGT_RADIO, MSGL_DBG2, MSGTR_RADIO_DoneParsingChannels);    return STREAM_OK;}#ifdef HAVE_RADIO_V4L2/***************************************************************** * \brief get fraction value for using in set_frequency and get_frequency * \return STREAM_OK if success, STREAM_ERROR otherwise * * V4L2_TUNER_CAP_LOW: * unit=62.5Hz * frac= 1MHz/unit=1000000/62.5 =16000 * * otherwise: * unit=62500Hz * frac= 1MHz/unit=1000000/62500 =16 */static int init_frac_v4l2(radio_priv_t* priv){    struct v4l2_tuner tuner;    memset(&tuner,0,sizeof(tuner));    tuner.index=0;    if (ioctl(priv->radio_fd, VIDIOC_G_TUNER, &tuner)<0){        mp_msg(MSGT_RADIO,MSGL_WARN,MSGTR_RADIO_GetTunerFailed,strerror(errno),priv->frac);        return  STREAM_ERROR;    }    if(tuner.type!=V4L2_TUNER_RADIO){        mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_NotRadioDevice,priv->radio_param->device);        return STREAM_ERROR;    }    if(tuner.capability & V4L2_TUNER_CAP_LOW){        priv->frac=16000;        mp_msg(MSGT_RADIO,MSGL_DBG2,MSGTR_RADIO_TunerCapLowYes,priv->frac);    }    else{        priv->frac=16;        mp_msg(MSGT_RADIO,MSGL_DBG2,MSGTR_RADIO_TunerCapLowNo,priv->frac);    }    priv->rangelow=((float)tuner.rangelow)/priv->frac;    priv->rangehigh=((float)tuner.rangehigh)/priv->frac;    mp_msg(MSGT_RADIO,MSGL_V,MSGTR_RADIO_FreqRange,priv->rangelow,priv->rangehigh);    return STREAM_OK;}/***************************************************************** * \brief tune card to given frequency * \param frequency frequency in MHz * \return STREAM_OK if success, STREAM_ERROR otherwise */static int set_frequency_v4l2(radio_priv_t* priv,float frequency){    struct v4l2_frequency freq;    memset(&freq,0,sizeof(freq));    freq.tuner=0;    freq.type=V4L2_TUNER_RADIO;    freq.frequency=frequency*priv->frac;    if(ioctl(priv->radio_fd,VIDIOC_S_FREQUENCY,&freq)<0){        mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_SetFreqFailed,freq.frequency,        frequency,strerror(errno));        return  STREAM_ERROR;    }    return STREAM_OK;}/***************************************************************** * \brief get current tuned frequency from card * \param frequency where to store frequency in MHz * \return STREAM_OK if success, STREAM_ERROR otherwise */static int get_frequency_v4l2(radio_priv_t* priv,float* frequency){    struct v4l2_frequency freq;    memset(&freq,0,sizeof(freq));    if (ioctl(priv->radio_fd, VIDIOC_G_FREQUENCY, &freq) < 0) {        mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_GetFreqFailed,strerror(errno));        return  STREAM_ERROR;    }    *frequency=((float)freq.frequency)/priv->frac;    return STREAM_OK;}/***************************************************************** * \brief set volume on radio card * \param volume volume level (0..100) * \return STREAM_OK if success, STREAM_ERROR otherwise */static void set_volume_v4l2(radio_priv_t* priv,int volume){    struct v4l2_queryctrl qctrl;    struct v4l2_control control;    /*arg must be between 0 and 100*/    if (volume > 100) volume = 100;    if (volume < 0) volume = 0;    memset(&control,0,sizeof(control));    control.id=V4L2_CID_AUDIO_MUTE;    control.value = (volume==0?1:0);    if (ioctl(priv->radio_fd, VIDIOC_S_CTRL, &control)<0){        mp_msg(MSGT_RADIO,MSGL_WARN,MSGTR_RADIO_SetMuteFailed,strerror(errno));    }    memset(&qctrl,0,sizeof(qctrl));    qctrl.id = V4L2_CID_AUDIO_VOLUME;    if (ioctl(priv->radio_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) {        mp_msg(MSGT_RADIO, MSGL_WARN, MSGTR_RADIO_QueryControlFailed,strerror(errno));        return;    }    memset(&control,0,sizeof(control));    control.id=V4L2_CID_AUDIO_VOLUME;    control.value=qctrl.minimum+volume*(qctrl.maximum-qctrl.minimum)/100;    if (ioctl(priv->radio_fd, VIDIOC_S_CTRL, &control) < 0) {        mp_msg(MSGT_RADIO, MSGL_WARN,MSGTR_RADIO_SetVolumeFailed,strerror(errno));    }}/***************************************************************** * \brief get current volume from radio card * \param volume where to store volume level (0..100) * \return STREAM_OK if success, STREAM_ERROR otherwise */static int get_volume_v4l2(radio_priv_t* priv,int* volume){    struct v4l2_queryctrl qctrl;    struct v4l2_control control;    memset(&qctrl,0,sizeof(qctrl));    qctrl.id = V4L2_CID_AUDIO_VOLUME;    if (ioctl(priv->radio_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) {        mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_QueryControlFailed,strerror(errno));        return STREAM_ERROR;    }    memset(&control,0,sizeof(control));    control.id=V4L2_CID_AUDIO_VOLUME;    if (ioctl(priv->radio_fd, VIDIOC_G_CTRL, &control) < 0) {        mp_msg(MSGT_RADIO, MSGL_ERR,MSGTR_RADIO_GetVolumeFailed,strerror(errno));        return STREAM_ERROR;    }    if (qctrl.maximum==qctrl.minimum)        *volume=qctrl.minimum;    else        *volume=100*(control.value-qctrl.minimum)/(qctrl.maximum-qctrl.minimum);    /*arg must be between 0 and 100*/    if (*volume > 100) *volume = 100;    if (*volume < 0) *volume = 0;    return STREAM_OK;}/* v4l2 driver info structure */static const radio_driver_t radio_driver_v4l2={    "v4l2",    MSGTR_RADIO_DriverV4L2,    init_frac_v4l2,    set_volume_v4l2,    get_volume_v4l2,    set_frequency_v4l2,    get_frequency_v4l2};#endif //HAVE_RADIO_V4L2#ifdef HAVE_RADIO_V4L/***************************************************************** * \brief get fraction value for using in set_frequency and get_frequency * \return STREAM_OK if success, STREAM_ERROR otherwise * * V4L2_TUNER_CAP_LOW: * unit=62.5Hz * frac= 1MHz/unit=1000000/62.5 =16000 * * otherwise:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -