由于最近在Gstreamer下编写各种插件(如http,hls等),需要实现在点播过程中,可以随时监测键值从而实现退出、暂停的功能,而且监测键值是非阻塞的,不会影响到视频播放正常退出。
基于这样一个需求,上网查询资料,发现有两种方法来实现。
1) 可以将监测键值单独放在一个线程中进行,设置非阻塞模式read()或者getchar()等。
设置非阻塞方式为:fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0) | O_NONBLOCK);
若按键并未按下,则会立即返回,并不会占用CPU资源;
若有按键按下,判断是否为‘q’,若是则退出播放。
2) 在linux下实现windows中kbhit的功能
声明:该部分参考http://hi.baidu.com/jtntiivtemcnsue/item/90689ce172ee912c5a7cfb1b
/* init_keyboard与close_keyboard在程序的开始和结束配置终端 */
函数tcgetattr具体用法:
函数tcsetattr具体用法:
http://baike.baidu.com/view/8022475.htm#include
#include
#include
#include
void init_keyboard()
{
tcgetattr(0,&initial_settings); /* get stdin(fd=0) parameter and store into init.. */
new_settings = initial_settings;
new_settings.c_lflag &= ~ICANON; /* use the standard input style */
new_settings.c_lflag &= ~ECHO; /* display the input char */
new_settings.c_lflag &= ~ISIG; /* when input INTR/QUIT/SUSP/DSUSP, send associated signal */
new_settings.c_cc[VMIN] = 1; /* read the min num of char is 1 */
new_settings.c_cc[VTIME] = 0;
tcsetattr(0, TCSANOW, &new_settings); /* set the attr of terminal */
}
void close_keyboard()
{
tcsetattr(0, TCSANOW, &initial_settings);
}
/* 实现kbhit的功能,若有键值按下则返回1,同时将键值压入stdin中;若无键值按下,则返回0 */
int kbhit(void)
{
struct termios oldt, newt;
int ch;
int oldf;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
/* set the nonblock */
fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0) | O_NONBLOCK);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0));
if (ch != EOF)
{
ungetc(ch, stdin); /* back the ch to stdin */
return 1;
}
return 0;
}
注意:由于该功能实现不能影响到后续程序的运行,且它是一个事件(event)触发的函数,只有当监测到按键按下时,才运行该kbhit函数。其他时候,程序是不在此中运行的。*/
int main(void)
{
int ch;
while (TURE)
{
if ((ch = getchar()) != NULL) /* 如果没有这个判断,按下按键是无法监测到的,也就是进不了kbhit函数 */
{
if (kbhit()) /* 经过测试,发现getchar()那里依然是非阻塞形式,无法自动退出 */
{
if ('q' == ch)
{
printf("Prapare to quit!\n");
break;
}
}
}
/* other codes */
...
}
return 0;
}
最后,还是决定由多线程来实现键值的读取。经测试成功。