vs filter_threadlocal原理

vs filter_threadlocal原理VsFilter是一个字幕叠加的库,目前由MPC-HC维护,其最新版本为2.41,本文即基于此版本

vs

VsFilter是一个字幕叠加的库,目前由MPC-HC维护,其最新版本为2.41,本文即基于此版本。
从实现层面上来说,其内部是一个DirectShow的Transform Filter,负责将字幕文件中的字幕转换成bitmap并叠加在从输入Pin进入的图像,并交给输出Pin。

线程结构:

VsFilter接口是线程安全的,主要包含两个线程:
1.文件监控线程:CDirectVobSubFilter::ThreadProc,监控文件的修改,如果文件状态变化,需要重新加载;
2.字幕图片生成线程:CSubPicQueue::ThreadProc,CSubPicQueue内部维护一个队列,字幕文件加载后,立刻转换10条字幕成图片,放入该队列,每消耗一个图片,则立即补充一个,直到字幕播放结束。

主要模块:

1.CDirectVobSubFilter:Filter的实现,提供Filter接口实现、Pin的基本操作、Transform函数实现(也就是叠加)、文件监控线程;
2.SubPic:字幕图片缓存维护,CSubPicProviderImpl数据提供者接口;
3.Subtitles:字幕到图片转换的实现算法,主要包含:
1)STS:CSimpleTextSubtitle,加载字幕文件获得字幕信息条目STSEntry;
struct STSEntry {

CStringW str;
bool fUnicode;
CString style, actor, effect;
CRect marginRect;
  int layer;
REFERENCE_TIME start, end;
int readorder;
};
2)STS:CRenderedTextSubtitle,派生自STS:CSimpleTextSubtitle,从字幕信息条目STSEntry生成并维护字幕对象CSubtitle,CSubtitle(派生自CAtlList<CLine*>)->CAtlList<CWord*>->CPoint,也就是维护了字幕形状的基本信息;
3)Rasterizer:光栅化(bitmap生成),CWord从其派生,将字的形状信息转化成像素,从而可以叠加到图片上。

主要流程:

1.加载VsFilter.dll,创建VsFilter的com实例,并获取IID_IDirectVobSub接口,此时将创建文件监控线程;
2.连接Source Filter、VsFilter、Render Filter,此时将创建字幕图片生成线程;
3.调用IID_IDirectVobSub接口的put_FileName方法,设置字幕文件,VsFilter将加载该字幕文件,同时字幕图片生成线程将建立字幕图片缓存;
4.Filter Graph开始工作后,CDirectVobSubFilter::Transform函数获得输入Sample以及时间戳,通过输入sample的时间戳查找SubPic缓存队列中的图片,如果查不到,则从Entry中查找并生成bitmap,然后将字幕bitmap与输入sample的surface进行叠加(alphablt),叠加完成进行适当的转换(转成YUY2),然后拷贝到输出Sample。SubPic缓存队列维持长度为10,每消耗一条,则补充一条。

关键的数据流程:

1.CSimpleTextSubtitle::Open,获得CAtlArray<STSEntry>,加载字幕文件;
2.CRenderedTextSubtitle::GetSubtitle,获得CAtlMap<int, CSubtitle*> m_subtitleCache,将字幕信息转化成字幕图形信息CSubtitle;
3.CSubPicQueue::ThreadProc->CSubPicQueueImpl::RenderTo->CRenderedTextSubtitle::Render->CLine::PaintOutline->CWord::Paint->CText::CreatePath()
        BeginPath(g_hDC);
        TextOutW(g_hDC, 0, 0, m_str, m_str.GetLength());
        EndPath(g_hDC);
->Rasterizer::ScanConvert->Rasterizer::Rasterize
通过BeginPath、TextOutW、EndPath这3个GDI函数获得文字的路径点集合,并以这个路径为基础构建轮廓、阴影等像素,从而实现光栅化。
4.CSubPicQueue::EnqueueSubPic,缓存生成的bitmap图片;
5.CDirectVobSubFilter::Transform->CSubPicQueue::LookupSubPic->CMemSubPic::AlphaBlt,Source Filter推送过来一个Sample,通过输入sample的时间戳从bitmap缓存中查找对应的bitmap,然后进行透明度混合。
如过是YV12输入,有以下步骤:
Y分量叠加:
if (s2[3] < 0xff) {

d2[0] = (((d2[0] – 0x10) * s2[3]) >> 8) + s2[1];
 }
U、V分量叠加:
unsigned int ia = (s2[3] + s2[3 + src.pitch] + is2[3] + is2[3 + src.pitch]) >> 2;
if (ia < 0xff) {

*d2 = BYTE((((*d2 – 0x80) * ia) >> 8) + ((s2[0] + s2[src.pitch]) >> 1));
}
6.CBaseVideoFilter::CopyBuffer(如果需要则先进行必要的转换,如BitBltFromI420ToYUY2)->CTransformOutputPin::Deliver,拷贝叠加后的图片到输出sample。

总结:

VsFilter通过获取输出的文字路径点集合,转化成形状,并光栅化成bitmap像素,然后与输入的图像进行alpha混合,达到字幕叠加的目的,实际上是图像叠加。所有的操作都是使用CPU进行计算,所以会明显增加CPU的开销。

今天的文章
vs filter_threadlocal原理分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/81306.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注