日期:2016.10.10
作者:isshe
github:github.com/isshe
邮箱:i.sshe@outlook.com
平台:ubuntu16.04 64bit + ffmepg3 + SDL2
前言
这篇记录退出、暂停、播放。
快进快退想了下,没啥思路。囧。
关于退出
一直没怎么管退出,但是始终是个问题,无论是中途退出还是播放完毕退出。
- 想要做到的:
- 中途退出(点窗口的x)能立即退出
- 播放完窗口停住,等待x掉。
需要解决的问题
-
1.如何判断一个流结束?
关于播完退出,想过的方法:
- 判断packet队列是否为空,空的话延时一段时间再判断一次(或多次),如果再为空就退出。
问题:如果延时,延时多长呢? 判断几次好呢? - 获取时长,大于等于的时候退出。(好像靠谱)
- 获取总时长:AFStream的duration * AFStream的time_base[当然要用av_p2d转换了]
- 获取当前时长:AFPacket的pts * AFStream 的time_base[同样要转换]。
这种方法感觉是可以的,但是在这份代码中用这个方法,最后的packet的pts总是小于总的时长,就算再加一个两帧间的delay也还是小。所以最后还是用了第一种方法
- 判断packet队列是否为空,空的话延时一段时间再判断一次(或多次),如果再为空就退出。
-
如何处理退出? 如果有两个流,一个长一个短,如何才能不互相影响?
如何处理退出和播放音视频的代码有关本程序中:
- 音频是主线程打开(SDL_OpenAudio())设备后,SDL_OpenAudio()开线程调用callback()函数取声音数据来解码发出声音。
- 视频是主线程配置好相关信息,然后开一个线程运行刷新函数(refresh_func)循环发出刷新事件,主线程接收事件再调用显示函数(代码中是decode_and_show())。
- 这个实现中退出视频播放比较简单,只要跳出刷新函数(refresh_func)中的循环即可。
- 退出音频,思路是:让callback()不再运行。SDL_PauseAudio()实现这个功能。如有必要再SDL_CloseAudio()
(更新的函数是SDL_OpenAudioDevice()和SDL_CloseAudioDevice())
「需要注意:哪个线程调用打开,哪个线程调用关闭,类似的, 哪个线程调用创建窗口(SDL_CreateWindow())之类的函数,就用哪个线程调用显示函数,否则容易出现core dump和显示不出来」
暂停/播放
实现的是用键盘的space空格键控制播放、暂停。第一感觉就是用SDL的Event,也确实可行。
如何使用键盘Event?
- 按键事件的触发方式:
方法一:
case SDL_KEYDOWN:
{
const Uint8 *state = SDL_GetKeyboardState(NULL);
if (state[SDL_SCANCODE_RETURN]) {
printf("<RETURN> is pressed.\n");
}
if (state[SDL_SCANCODE_RIGHT] && state[SDL_SCANCODE_UP]) {
printf("Right and Up Keys Pressed.\n");
}
break;
}
- SDL_SCANCODE_RIGHT这些就是表示是哪个按键。
- 对应的按键代号在这里:http://wiki.libsdl.org/SDL_Scancode
方法二:
case SDL_KEYDOWN:
{
switch(event.key.keysym.sym)
{
case SDLK_LEFT:
break;
case SDLK_RIGHT:
break;
case SDLK_UP:
break;
case SDLK_DOWN:
break;
}
}
如何实现暂停/播放?
这个实现中:用一个变量(player_state)表示视频的状态。
-1: 退出;
0: 播放;
1: 暂停:
…
- 视频:
- 暂停:键盘事件触发以后把视频的状态设置为1, 刷新函数(refresh_func)检测到player_state == 1, 就进入一个循环,类似:
- 播放:就是refresh_func()退出这个循环,继续Push Event个主线程了。「中间隔了代码后缩进不对了,放上来…」
while(ps->player_state == 1)
{
SDL_Delay(20); //delay的时间没有多尝试
}
- 音频:
- 暂停: SDL_PauseAudio(1), 停止callback()。
- 播放:SDL_PauseAudio(0), 继续callback()。
在callback里面操作这两个函数也是可以的。
但是不要放到callback里面,因为,SDL_PauseAudio(1)就是停止调用callback()的,停止以后,就调用不了SDL_PauseAudio(0)了,所以,这两个函数哪个线程调用(SDL_OpenAudio())开设备,哪个就调用这两个比较好。(目前实践情况,不一定对)。
参考资料
SDL: http://wiki.libsdl.org/SDL_PauseAudio
代码下载
github: https://github.com/isshe/Practice-project/tree/master/Player/blog/chapter6/player_v1.6
csdn: http://download.csdn.net/detail/i_scream_/9649398