使用FFmpeg&SDL开发音视频播放器

转自:http://www.if4ever.com/?p=57

通过上一个简单的ffmpeg使用事例,对ffmpeg的整体有了一个初步的了解。然后想通过ffmpeg和sdl来开发一个自己的简单的视频播放器。解码的整体思路基本上没有根本的变化,但是为了时间控制,使用多线程开发,使得整个架构变得更加复杂。开发的第一个版本,为了简单和熟练ffmpeg开发,只对视频的图像进行decode和display,没有处理subtitle和audio,但是因为是模仿ffplay.c的整个架构,所以来说未来的二次开发,再将这些功能整合进去也是可以的。
参考了 ffplay的原理这个老版本的ffplay.c的分析。新版加入了许多新的代码,但是整体的结构未变。所以参照这个资料,大大加快了读懂ffplay.c的进度。
首先是程序的结构图:

从数据流的走向来分析。首先数据是存入在编码后的多媒体文件中,decode thread将packet从文件中解码出来并放入packet queue中。然后,video thread 将packet解压成原始图像并进行缩放存入picture queue中。最终,refresh thread 触发display动作,主线程读取picture queue中的图像显示到屏幕上,完成视频的播放。

在我的理解中,由于解码工作ffmpeg都可以方便提供(废话要不然怎么会用ffmpeg),所以整个程序的难点就在于如何定时地显示ffmpeg解码出来的图片。
视频播放是按照一定的时间间隔不停地播放视频帧,由于人的视觉暂留特性使得观看者产生连续的播放效果,如果视频帧刷新的太快或者太慢都会使观看者产生不悦感。在每种视频格式的编码中,都规则了每秒必须播放的帧数,例如:24 25 29.97等等。这样在视频播放中,我们只要每隔 1/帧数 秒刷新一次图像就可以完成任务。这样看来就有两种方法来刷新:
1)使用一个线程来固定时间来刷新,这样做的坏处就是灵活性太差,无法对视频播放方便的进行操作,比如跳跃,暂停。而且 1/29.97 的浮点的存在,积累的误差也很难被修正。

for (;;) {
	    display(img);
	    usleep(micro_secs);
	}

  

2)利用一个线程固定触发刷新事件,另外一个线程来接受事件并且判断是否要显示图片。由于1/29.97s对于计算机来说是一个相当漫长的时间,所以我们可以设定一个比较小的时间来不停的触发事件,当视频播放的时间到底下一个帧的时候就播放它。像我们的程序所作的那样。而且也可以设定其他的事件,让程序可以方便的完成各种操作。

void thread_1() {
	pushEvent(refresh);
	usleep(micro_secs);
}

void thread_2() {
	for (;;) {
		waitEvent(event);
		if (event == refresh) {
			if (it_time_to_refresh()) {
				display(img);
			}
		}
	}
}

 

另外一个地方就是数据的缓存问题。在ffplay.c中packet可以事先解码出比较多个存入在packet queue中,但是picture的解码只需要2个就足够了。这样做,我猜大约是因为packet是压缩的图像,大小比较小可以事先存放多个。但是picture是原始图像比较大,而一帧停留的时间在 1/每秒帧数 的时间长度。这个时间对于video线程来从packet解码一个picture是远远足够的。所以只用解码2帧就可以了。例外一帧用来判断是否跳过还是其他的用途(这个还未理解完全).

到这里基本上整个结构和难点就清楚了,照着完成就可以事先一个简单的只有图片的播放器啦。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值