前言

这篇记录退出、暂停、播放。

快进快退想了下,没啥思路。囧。

关于退出

一直没怎么管退出,但是始终是个问题,无论是中途退出还是播放完毕退出。

想要做到的:

中途退出(点窗口的x)能立即退出

播放完窗口停住,等待x掉。

需要解决的问题

1.如何判断一个流结束?

关于播完退出,想过的方法:

判断packet队列是否为空,空的话延时一段时间再判断一次(或多次),如果再为空就退出。

问题:如果延时,延时多长呢? 判断几次好呢?

获取时长,大于等于的时候退出。(好像靠谱)

获取总时长:AFStream的duration * AFStream的time_base[当然要用av_p2d转换了]

获取当前时长:AFPacket的pts * AFStream 的time_base[同样要转换]。

这种方法感觉是可以的,但是在这份代码中用这个方法,最后的packet的pts总是小于总的时长,就算再加一个两帧间的delay也还是小。所以最后还是用了第一种方法

如何处理退出? 如果有两个流,一个长一个短,如何才能不互相影响?

如何处理退出和播放音视频的代码有关

本程序中:

音频是主线程打开(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(" is pressed.\n");
}
if (state[SDL_SCANCODE_RIGHT] && state[SDL_SCANCODE_UP]) {
printf("Right and Up Keys Pressed.\n");
}
break;
}


SDL_SCANCODE_RIGHT这些就是表示是哪个按键。

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())开设备,哪个就调用这两个比较好。(目前实践情况,不一定对)。