#include "define.h"
#include "SDL_Wraper.h"
#include "datequeue.h"
#include "parser_stream.h"
#include "callback.h"
#include "thread.h"
double get_audio_clock(VideoState *is)
{
double pts;
int hw_buf_size, bytes_per_sec, n;
pts = is->audio_clock;
hw_buf_size = is->audio_buf_size - is->audio_buf_index;
bytes_per_sec = 0;
n = is->audio_ctx->channels * 2;
if (is->audio_st) {
bytes_per_sec = is->audio_ctx->sample_rate * n;
}
if (bytes_per_sec) {
pts -= (double)hw_buf_size / bytes_per_sec;
}
return pts;
}
//定时发送事件
static Uint32 sdl_refresh_timer_cb(Uint32 interval, void *opaque) {
SDL_Event event;
event.type = FF_REFRESH_EVENT;
event.user.data1 = opaque;
SDL_PushEvent(&event);
SDL_Delay(40);
return 0;
}
//添加一个定时器
static void schedule_refresh(VideoState *is, int delay) {
SDL_AddTimer(delay, sdl_refresh_timer_cb, is);
}
void video_refresh_timer(void *userdata)
{
VideoState *is = (VideoState *)userdata;
AVFrame *vp;
int64_t delay, sync_threshold, ref_clock;
double actual_delay;
if (is->video_st)
{
if (is->pictq_size == 0)
{
schedule_refresh(is, 1);
}
else
{
vp = &is->pictq[is->pictq_rindex];
delay = vp->pts - is->frame_last_pts;
//存储pts和delay下次使用
is->frame_last_delay = delay;
is->frame_last_pts = vp->pts;
//获取音频延迟时间
ref_clock = get_audio_clock(is);
double diff = vp->pts * av_q2d(is->video_st->time_base) - ref_clock;
/* Skip or repeat the frame. Take delay into account
FFPlay still doesn't "know if this is the best guess." */
sync_threshold = (delay > AV_SYNC_THRESHOLD) ? delay : AV_SYNC_THRESHOLD;
if (fabs(diff) < AV_NOSYNC_THRESHOLD)
{
if (diff <= -sync_threshold) {
delay = 0;
}
else if (diff >= sync_threshold) {
delay = 2 * delay;
}
}
is->frame_timer += delay * av_q2d(is->video_st->time_base);
//计算真正的延迟时间
actual_delay = is->frame_timer - (av_gettime() / 1000000.0);
if (actual_delay < 0.010)
{
actual_delay = 0.010;
}
//std::cout << actual_delay << "frame_timer" << is->frame_timer << std::endl;
schedule_refresh(is, (int)(actual_delay * 1000 + 0.5));
//显示视频帧
video_display(is);
//刷新视频信息,为下次刷新做准备
if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) {
is->pictq_rindex = 0;
}
SDL_LockMutex(is->pictq_mutex);
is->pictq_size--;
SDL_CondSignal(is->pictq_cond);
SDL_UnlockMutex(is->pictq_mutex);
}
}
else
{
schedule_refresh(is, 100);
}
}
int main(int argc, char *argv[])
{
int ret = -1;
SDL_Event event;
if (argc < 2)
{
printf("Usage: command <file>\n");
return ret;
}
//初始化SDL
InitSDL();
//初始化各种变量
g_state = (VideoState*)av_mallocz(sizeof(VideoState));
g_state->pictq_mutex = SDL_CreateMutex();
g_state->pictq_cond = SDL_CreateCond();
memcpy(g_state->filename, argv[1], sizeof(g_state->filename));
//解封装的线程
g_state->parse_tid = SDL_CreateThread(demux_thread, "demux_thread", g_state);
if (!g_state->parse_tid)
{
av_free(g_state);
goto __FAIL;
}
while (!g_state->video_ctx)
{
SDL_Delay(10);
}
//创建窗口渲染视频,在子线程里面创建会阻塞主线程的时间循环
win = SDL_CreateWindow("Feifei Player",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
g_state->video_ctx->width, g_state->video_ctx->height,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
renderer = SDL_CreateRenderer(win, -1, 0);
texture = SDL_CreateTexture(renderer,
SDL_PIXELFORMAT_IYUV,
SDL_TEXTUREACCESS_STREAMING,
g_state->video_ctx->width, g_state->video_ctx->height);
schedule_refresh(g_state, 40);
while (1)
{
SDL_WaitEvent(&event);
switch (event.type)
{
case FF_QUIT_EVENT:
case SDL_QUIT:
g_state->quit = 1;
goto __QUIT;
break;
case FF_REFRESH_EVENT:
video_refresh_timer(event.user.data1);
break;
default:
break;
}
}
__QUIT:
ret = 0;
__FAIL:
SDL_Quit();
return ret;
}
评论0