您自己的 AVI 编辑器





5.00/5 (4投票s)
创建您自己的 AVI 编辑应用程序,并通过简单的代码添加来探索一些有趣的技巧
引言
使用市面上流行的媒体程序可以修改AVI文件,但这些程序无法让您加入自己的创意。
在本文中,我们将构建自己的AVI编辑应用程序,并通过一些简单的代码添加来探索有趣的技巧。
背景
本项目适合中级MFC开发者。安装MSVS-2015 pro是正确理解本文的前提。
前提条件是安装了MSVS-2015 pro。
演示说明
作为示例,我们选择了饱受摧残的、众所周知的“披头士”gif:只有懒惰的人才不会尝试“改进”这个视频。在 enclosed 的MyAviShopDemo
目录中启动MyAviShop.exe。只需按照下面的步骤操作,完成后您将对该程序的功能有一个全面的了解。
1.1 AVI 打开和控件
使用菜单命令File->Open Avi选择DemoSample/Beatles_01.avi文件。下面的示例演示了某些控件的使用。
1.2 已检测对象的蒙版处理
选择菜单Polygon->New Polygon,并输入新蒙版多边形所需的点数。使用标准的Rechittest
过程移动和调整已检测对象的所有多边形(请注意Keep Ratio checkbox条件)。
在提供的示例中,这项工作已经完成;因此,选择菜单Polygon->Delete All Polygons,选择菜单Polygon->Open Polygonset并选择Beatles_a.pl2文件;接下来,使用菜单Polygon->Mask PolygonSet创建已检测对象的蒙版图像列表,其背景为单色,可以叠加在任何AVI视频之上。
在提供的示例中,这项工作已经为每个人完成了,并固定在文件中,如Beatles_01_of_Beatles_a.mpl,用于a, b, c, d
蒙版。
现在我们将排列单色背景中移动的人的副本。
- 使用菜单File Avi->Open Avi命令打开Blank.avi作为目标文件;
- 使用菜单Mask Edit->MaskCapture捕获Beatles_a.avi、Beatles_b.avi、Beatles_c.avi、Beatles_d.avi的Blank.avi蒙版,并打开相应的*.mpl文件。
- 使用
您可以在Beatles_Blank.avi中看到结果。
现在我们将排列以改变顺序移动的人的蒙版,并使用File Avi->Save as Avi命令保存当前的 AVI(您可以在Beatles_Blank_r.avi中看到结果)。
接下来,将此蒙版应用于空街道(您可以在Beatles_r.avi中看到结果)。
在这个文章的标题 AVI 中,人们看起来像在转圈。这是可能的最小的安排技巧。
1.3 屏幕捕获
调用菜单File Images->Screen Capture从屏幕捕获图像;(结果在ScreenCap February 02_2019_15_56.avi文件中)
2. 项目源文件存储和构建说明
项目的源文件位于两个目录中:
MyAviShop
– 使用标准的MFC AppWizard创建:
- MyAviShop.cpp, MyAviShopDoc.cpp, MyAviShopView.cpp, MainFrm.cpp, MyAviShop.rc, resource.h - 使用标准的MFC AppWizard创建,所有消息处理程序也使用MFC标准进行安排;
- Splitter.cpp已被插入,取代了最初由MFC创建的ChildFrm.cpp;
- 所有相关的对话框类均使用标准的MFC AppWizard创建;
- MaskHandle.cpp和MaskUnit.cpp – 由作者创建,用于蒙版图像处理;
GlobUse
– 程序集,包含独立于主项目的过程,可根据需要包含在任何MFC项目中。
- EasyAVI.cpp - 借用自 Andy Bantly 的文章“Easy AVI”;
- MyRectTrack.cpp - 由作者为本项目创建,用于对
Mask Recttrack
进行灵活操作; - 其他代码由作者早期创建,并已用于其他项目,包括CodeProject。
即使您是第一次使用MSVS,只需选择菜单Debug->Start without debugging,项目MyAviShop
就应该开始构建并运行。
3. 代码解释
所有菜单和控件处理命令均使用标准的MFC AppWizard技术完成。因此,我认为没有什么比标准教程更能解释的了。我只介绍一些我自己的开发点。
3.1 蒙版可视化
包含在某个多边形区域内的蒙版可以使用两个图形上下文(黑白和某个缓冲区)进行划分。
//if number points in polygon:
if (m_pCurPolygon->m_PointList.GetCount() > 2) //if polygon has some points
{
double scale = m_pDoc->m_Scale;
//fill white some bw contest:
m_bwDC.BitBlt(tRect.left, tRect.top, tRect.Width(),
tRect.Height(), NULL, 0, 0, WHITENESS);
//draw black area enclosed with the polygon
m_pCurPolygon->DrawBlackStroke(&m_bwDC, Vector_2D(1), 0,
m_pCurPolygon->turnPoint*scale, 0, scale, scale, FALSE, TRUE);
//revert colors: white polygon with black background
m_bwDC.BitBlt(tRect.left, tRect.top, tRect.Width(),
tRect.Height(), NULL, 0, 0, DSTINVERT);
//put the image into some buf contest:
pImg->StretchBlt(m_bufDC.m_hDC, m_pixOffSet.x, m_pixOffSet.y,
int(scale * pImg->GetWidth()), int(scale * pImg->GetHeight()));
//put bw mask from bw contents on to buf contents using SRCAND:
//on the buf content we have the mask of the image enclosed with polygon
//on the black background:
m_bufDC.BitBlt(tRect.left, tRect.top, tRect.Width(),
tRect.Height(), &m_bwDC, 0, 0, SRCAND);
//fill the final contest with the gray grey color:
m_memDC.FillRect(tRect, &CBrush(RGB(127, 127, 127)));
//put the image into some buf contest using SRCAND:we have dimmed image
pImg->StretchBlt(m_memDC.m_hDC, m_pixOffSet.x, m_pixOffSet.y,
int(scale * pImg->GetWidth()), int(scale * pImg->GetHeight()), SRCAND);
//put the mask from buf contest
m_memDC.TransparentBlt(tRect.left, tRect.top, tRect.Width(),
tRect.Height(), &m_bufDC, tRect.left, tRect.top, tRect.Width(),
tRect.Height(), RGB(255, 255, 255));
//draw polygon iself:
m_pCurPolygon->DrawSolidStroke(&m_memDC, Vector_2D(1), 0,
m_pCurPolygon->turnPoint*scale, 0, scale, scale, FALSE, TRUE);
}
- 黑白上下文用白色填充;
- 绘制被多边形包围的黑色区域;
- 反转颜色:带黑色的白色多边形;
- 将原始图像放入缓冲区上下文;
- 使用
SRCAND
将黑白上下文中的黑白蒙版放在缓冲区内容上:在缓冲区上下文中,我们得到了被多边形包围的图像蒙版,背景为黑色。
3.2 蒙版 Recttrack
为了处理蒙版,插入了一些特殊类:
CMyRectTrack
– 派生自Polygon_2D
类;用于蒙版的移动、调整大小和旋转;CMaskUnit
- 派生自CObject
类;用于存储蒙版信息:位置、大小、旋转角度、蒙版图像列表中的编号;CMaskHandle
- 派生自CObject
类;用于管理CMaskUnit Objects
列表,并同时引用目标图像列表和蒙版图像列表。
蒙版绘制过程如下:
//for all mask sets captured by this window
for (POSITION pos = m_maskWindowList.GetHeadPosition(); pos != NULL;)
{
//select next mask set captured by this window
CMyAviShopDoc * pDoc = (CMyAviShopDoc *)m_maskWindowList.GetNext(pos);
//for all CMackHandle objects obtained by current mask AVI window:
for (POSITION psn = pDoc->m_maskHandleList.GetHeadPosition(); psn != NULL;)
{
//select next CMackHandle object obtained by current mask AVI window:
CMaskHandle * ptr = (CMaskHandle *)pDoc->m_maskHandleList.GetNext(psn);
//if current CMackHandle object has the reference to this Window
if (ptr->m_pAviHost == m_pDoc)
{
//select the CMaskUnit Object corresponding to the
//number of current frame in this window:
POSITION psa = ptr->m_maskUnitList.FindIndex(nn);
if (psa != NULL)
{
CMaskUnit * pMsk = (CMaskUnit *)ptr->m_maskUnitList.GetAt(psa);
m_pDoc->m_pCurMaskUnit = pMsk;
// if CMaskUnit Object found it gives the info
//of position, size and angle to Mask RectTrack:
m_pMyRectTrack->m_angle = pMsk->m_angle;
m_pMyRectTrack->SetRect(pMsk->m_tgtRect);
//Draw Mask RectTrack if fit:
if (m_pDoc->m_bDrawMaskRect && pMsk->m_number >= 0)
m_pMyRectTrack->DrawRectTrack(&m_memDC, m_pDoc->m_Scale);
else
m_pMyRectTrack->DrawRectTrack(&m_bwDC, m_pDoc->m_Scale);
//Draw mask on to the current image of this window
pMsk->SetMask(&m_memDC, &m_bufDC, &m_bwDC, m_pMyRectTrack, m_pDoc->m_Scale);
}
break;
}//if (ptr->m_pAviHost == this)
}
}//for (POSITION pos = m_maskWindowList.GetHeadPosition(); pos != NULL;)
4. 使用此项目开发您自己的应用程序
您可以采用整个项目,将其重命名为我的前一篇CodeProject文章“MFC Project from Existing Code in One Click”的项目,并按您喜欢的方式组合和改进代码。
或者,您可以从本项目中选择GlobUse目录中的任何文件,并通过菜单Project->Existing Item将其包含到任何MFC项目中。
或者,您也可以简单地使用提供的演示中的MyAviShop.exe来“改进”任何AVI和/或网络场景捕获。
如果您引用我的代码,我将不胜感激。
讨论
本文的目的是,提供的项目可以为普通的 AVI 编辑程序提供良好的支持,甚至可以开发您自己的AVI Shop程序。
这展示了CodeProject在帮助开发者解决任何问题方面的性能。
结论、兴趣点和致谢
gif 插图是用MyAviShop
本身创建的:一个会话执行操作,另一个会话“监视”执行过程。
本项目是用于实现您喜欢的一些技巧和效果的工具,请记住代码是开放的。
我早期版本的此作业的一些示例可在 YouTube/vl2525 上找到。
非常感谢 Andy Bantly 和 Darryl Bryk 的出色工作。
历史
- 2019 年 4 月 2 日:初稿