📄 tv.c
字号:
/* TV Interface for MPlayer (C) Alex Beregszaszi API idea based on libvo2 Feb 19, 2002: Significant rewrites by Charles R. Henrich (henrich@msu.edu) to add support for audio, and bktr *BSD support.*/#include <mplaylib.h>#include <mplaylib.h>#include <mplaylib.h>#include <mplaylib.h>#include <ctype.h>#include <sys/time.h>#include "config.h"#include "mp_msg.h"#include "help_mp.h"#include "stream.h"#include "libmpdemux/demuxer.h"#include "libmpdemux/stheader.h"#include "libaf/af_format.h"#include "libmpcodecs/img_format.h"#include "libavutil/avstring.h"#include "osdep/timer.h"#include "tv.h"#include "frequencies.h"tv_channels_t *tv_channel_list;tv_channels_t *tv_channel_current, *tv_channel_last;char *tv_channel_last_real;/* enumerating drivers (like in stream.c) */extern tvi_info_t tvi_info_dummy;#ifdef HAVE_TV_V4L1extern tvi_info_t tvi_info_v4l;#endif#ifdef HAVE_TV_V4L2extern tvi_info_t tvi_info_v4l2;#endif#ifdef HAVE_TV_BSDBT848extern tvi_info_t tvi_info_bsdbt848;#endif/** List of drivers in autodetection order */static const tvi_info_t* tvi_driver_list[]={#ifdef HAVE_TV_V4L2 &tvi_info_v4l2,#endif#ifdef HAVE_TV_V4L1 &tvi_info_v4l,#endif#ifdef HAVE_TV_BSDBT848 &tvi_info_bsdbt848,#endif &tvi_info_dummy, NULL};void tv_start_scan(tvi_handle_t *tvh, int start){ mp_msg(MSGT_TV,MSGL_INFO,"start scan\n"); tvh->tv_param->scan=start?1:0;}static void tv_scan(tvi_handle_t *tvh){ unsigned int now; struct CHANLIST cl; tv_channels_t *tv_channel_tmp=NULL; tv_channels_t *tv_channel_add=NULL; tv_scan_t* scan; int found=0, index=1; scan = tvh->scan; now=GetTimer(); if (!scan) { scan=calloc(1,sizeof(tv_scan_t)); tvh->scan=scan; cl = tvh->chanlist_s[scan->channel_num]; tv_set_freq(tvh, (unsigned long)(((float)cl.freq/1000)*16)); scan->scan_timer=now+1e6*tvh->tv_param->scan_period; } if(scan->scan_timer>now) return; if (tv_get_signal(tvh)>tvh->tv_param->scan_threshold) { cl = tvh->chanlist_s[scan->channel_num]; tv_channel_tmp=tv_channel_list; while (tv_channel_tmp) { index++; if (cl.freq==tv_channel_tmp->freq){ found=1; break; } tv_channel_add=tv_channel_tmp; tv_channel_tmp=tv_channel_tmp->next; } if (!found) { mp_msg(MSGT_TV, MSGL_INFO, "Found new channel: %s (#%d). \n",cl.name,index); scan->new_channels++; tv_channel_tmp = malloc(sizeof(tv_channels_t)); tv_channel_tmp->index=index; tv_channel_tmp->next=NULL; tv_channel_tmp->prev=tv_channel_add; tv_channel_tmp->freq=cl.freq; snprintf(tv_channel_tmp->name,sizeof(tv_channel_tmp->name),"ch%d",index); strncpy(tv_channel_tmp->number, cl.name, 5); tv_channel_tmp->number[4]='\0'; if (!tv_channel_list) tv_channel_list=tv_channel_tmp; else { tv_channel_add->next=tv_channel_tmp; tv_channel_list->prev=tv_channel_tmp; } }else mp_msg(MSGT_TV, MSGL_INFO, "Found existing channel: %s-%s.\n", tv_channel_tmp->number,tv_channel_tmp->name); } scan->channel_num++; scan->scan_timer=now+1e6*tvh->tv_param->scan_period; if (scan->channel_num>=chanlists[tvh->chanlist].count) { tvh->tv_param->scan=0; mp_msg(MSGT_TV, MSGL_INFO, "TV scan end. Found %d new channels.\n", scan->new_channels); tv_channel_tmp=tv_channel_list; if(tv_channel_tmp){ mp_msg(MSGT_TV,MSGL_INFO,"channels="); while(tv_channel_tmp){ mp_msg(MSGT_TV,MSGL_INFO,"%s-%s",tv_channel_tmp->number,tv_channel_tmp->name); if(tv_channel_tmp->next) mp_msg(MSGT_TV,MSGL_INFO,","); tv_channel_tmp=tv_channel_tmp->next; } } if (!tv_channel_current) tv_channel_current=tv_channel_list; if (tv_channel_current) tv_set_freq(tvh, (unsigned long)(((float)tv_channel_current->freq/1000)*16)); free(tvh->scan); tvh->scan=NULL; }else{ cl = tvh->chanlist_s[scan->channel_num]; tv_set_freq(tvh, (unsigned long)(((float)cl.freq/1000)*16)); mp_msg(MSGT_TV, MSGL_INFO, "Trying: %s (%.2f). \n",cl.name,1e-3*cl.freq); }}/* ================== DEMUX_TV ===================== *//* Return value: 0 = EOF(?) or no stream 1 = successfully read a packet*//* fill demux->video and demux->audio */static int demux_tv_fill_buffer(demuxer_t *demux, demux_stream_t *ds){ tvi_handle_t *tvh=(tvi_handle_t*)(demux->priv); demux_packet_t* dp; unsigned int len=0; /* ================== ADD AUDIO PACKET =================== */ if (ds==demux->audio && tvh->tv_param->noaudio == 0 && tvh->functions->control(tvh->priv, TVI_CONTROL_IS_AUDIO, 0) == TVI_CONTROL_TRUE) { len = tvh->functions->get_audio_framesize(tvh->priv); dp=new_demux_packet(len); dp->flags|=1; /* Keyframe */ dp->pts=tvh->functions->grab_audio_frame(tvh->priv, dp->buffer,len); ds_add_packet(demux->audio,dp); } /* ================== ADD VIDEO PACKET =================== */ if (ds==demux->video && tvh->functions->control(tvh->priv, TVI_CONTROL_IS_VIDEO, 0) == TVI_CONTROL_TRUE) { len = tvh->functions->get_video_framesize(tvh->priv); dp=new_demux_packet(len); dp->flags|=1; /* Keyframe */ dp->pts=tvh->functions->grab_video_frame(tvh->priv, dp->buffer, len); ds_add_packet(demux->video,dp); } if (tvh->tv_param->scan) tv_scan(tvh); return 1;}static int norm_from_string(tvi_handle_t *tvh, char* norm){#ifdef HAVE_TV_V4L2 if (strcmp(tvh->tv_param->driver, "v4l2") != 0) {#endif if (!strcasecmp(norm, "pal")) return TV_NORM_PAL; else if (!strcasecmp(norm, "ntsc")) return TV_NORM_NTSC; else if (!strcasecmp(norm, "secam")) return TV_NORM_SECAM; else if (!strcasecmp(norm, "palnc")) return TV_NORM_PALNC; else if (!strcasecmp(norm, "palm")) return TV_NORM_PALM; else if (!strcasecmp(norm, "paln")) return TV_NORM_PALN; else if (!strcasecmp(norm, "ntscjp")) return TV_NORM_NTSCJP; else { mp_msg(MSGT_TV, MSGL_WARN, MSGTR_TV_BogusNormParameter, norm, "PAL"); return TV_NORM_PAL; }#ifdef HAVE_TV_V4L2 } else { tvi_functions_t *funcs = tvh->functions; char str[8]; strncpy(str, norm, sizeof(str)-1); str[sizeof(str)-1] = '\0'; if (funcs->control(tvh->priv, TVI_CONTROL_SPC_GET_NORMID, str) != TVI_CONTROL_TRUE) { mp_msg(MSGT_TV, MSGL_WARN, MSGTR_TV_BogusNormParameter, norm,"default"); return 0; } return *(int *)str; }#endif}static void parse_channels(tvi_handle_t *tvh){ char** channels = tvh->tv_param->channels; mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TV_ChannelNamesDetected); tv_channel_list = malloc(sizeof(tv_channels_t)); tv_channel_list->index=1; tv_channel_list->next=NULL; tv_channel_list->prev=NULL; tv_channel_current = tv_channel_list; while (*channels) { char* tmp = *(channels++); char* sep = strchr(tmp,'-'); int i; struct CHANLIST cl; if (!sep) continue; // Wrong syntax, but mplayer should not crash av_strlcpy(tv_channel_current->name, sep + 1, sizeof(tv_channel_current->name)); sep[0] = '\0'; strncpy(tv_channel_current->number, tmp, 5); tv_channel_current->number[4]='\0'; while ((sep=strchr(tv_channel_current->name, '_'))) sep[0] = ' '; // if channel number is a number and larger than 1000 threat it as frequency // tmp still contain pointer to null-terminated string with channel number here if (atoi(tmp)>1000){ tv_channel_current->freq=atoi(tmp); }else{ tv_channel_current->freq = 0; for (i = 0; i < chanlists[tvh->chanlist].count; i++) { cl = tvh->chanlist_s[i]; if (!strcasecmp(cl.name, tv_channel_current->number)) { tv_channel_current->freq=cl.freq; break; } } } if (tv_channel_current->freq == 0) mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_NoFreqForChannel, tv_channel_current->number, tv_channel_current->name); else { sep = strchr(tv_channel_current->name, '-'); if ( !sep ) sep = strchr(tv_channel_current->name, '+'); if ( sep ) { i = atoi (sep+1); if ( sep[0] == '+' ) tv_channel_current->freq += i * 100; if ( sep[0] == '-' ) tv_channel_current->freq -= i * 100; sep[0] = '\0'; } } /*mp_msg(MSGT_TV, MSGL_INFO, "-- Detected channel %s - %s (%5.3f)\n", tv_channel_current->number, tv_channel_current->name, (float)tv_channel_current->freq/1000);*/ tv_channel_current->next = malloc(sizeof(tv_channels_t)); tv_channel_current->next->index = tv_channel_current->index + 1; tv_channel_current->next->prev = tv_channel_current; tv_channel_current->next->next = NULL; tv_channel_current = tv_channel_current->next; } if (tv_channel_current->prev) tv_channel_current->prev->next = NULL; free(tv_channel_current);}static int open_tv(tvi_handle_t *tvh){ int i; tvi_functions_t *funcs = tvh->functions; int tv_fmt_list[] = { IMGFMT_YV12, IMGFMT_I420, IMGFMT_UYVY, IMGFMT_YUY2, IMGFMT_RGB32, IMGFMT_RGB24, IMGFMT_RGB16, IMGFMT_RGB15 }; if (funcs->control(tvh->priv, TVI_CONTROL_IS_VIDEO, 0) != TVI_CONTROL_TRUE) { mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_NoVideoInputPresent); return 0; } if (tvh->tv_param->outfmt == -1) for (i = 0; i < sizeof (tv_fmt_list) / sizeof (*tv_fmt_list); i++) { tvh->tv_param->outfmt = tv_fmt_list[i]; if (funcs->control (tvh->priv, TVI_CONTROL_VID_SET_FORMAT, &tvh->tv_param->outfmt) == TVI_CONTROL_TRUE) break; } else { switch(tvh->tv_param->outfmt) { case IMGFMT_YV12: case IMGFMT_I420: case IMGFMT_UYVY: case IMGFMT_YUY2: case IMGFMT_RGB32: case IMGFMT_RGB24: case IMGFMT_BGR32: case IMGFMT_BGR24: case IMGFMT_BGR16: case IMGFMT_BGR15:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -