📄 vop.cpp
字号:
/*************************************************************************
This software module was originally developed by
Ming-Chieh Lee (mingcl@microsoft.com), Microsoft Corporation
Wei-ge Chen (wchen@microsoft.com), Microsoft Corporation
Bruce Lin (blin@microsoft.com), Microsoft Corporation
Chuang Gu (chuanggu@microsoft.com), Microsoft Corporation
(date: March, 1996)
in the course of development of the MPEG-4 Video (ISO/IEC 14496-2).
This software module is an implementation of a part of one or more MPEG-4 Video tools
as specified by the MPEG-4 Video.
ISO/IEC gives users of the MPEG-4 Video free license to this software module or modifications
thereof for use in hardware or software products claiming conformance to the MPEG-4 Video.
Those intending to use this software module in hardware or software products are advised that its use may infringe existing patents.
The original developer of this software module and his/her company,
the subsequent editors and their companies,
and ISO/IEC have no liability for use of this software module or modifications thereof in an implementation.
Copyright is not released for non MPEG-4 Video conforming products.
Microsoft retains full right to use the code for his/her own purpose,
assign or donate the code to a third party and to inhibit third parties from using the code for non <MPEG standard> conforming products.
This copyright notice must be included in all copies or derivative works.
Copyright (c) 1996, 1997.
Module Name:
vop.hpp
Abstract:
class for Video Object Plane
Revision History:
*************************************************************************/
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "basic.hpp"
#include "transf.hpp"
#include "warp.hpp"
#include "vop.hpp"
#include "typeapi.h"
#ifdef __MFC_
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
#endif // __MFC_
Int numPln = 4;
CVideoObjectPlane::~CVideoObjectPlane ()
{
delete [] m_ppxl;
}
Void CVideoObjectPlane::allocate (CRct r, CPixel pxl)
{
m_rc = r;
delete [] m_ppxl, m_ppxl = NULL;
// allocate pixels and initialize
if (m_rc.empty()) return;
m_ppxl = new CPixel [m_rc.area ()];
for (UInt i = 0; i < m_rc.area (); i++)
m_ppxl [i] = pxl;
// memset (m_ppxl, pxl, m_rc.area () * sizeof (CPixel));
}
Void CVideoObjectPlane::copyConstruct (const CVideoObjectPlane& vop, CRct r)
{
if (!r.valid())
r = vop.where ();
if (!vop.valid () || (!vop.m_rc.empty () && vop.m_ppxl == NULL))
assert (FALSE);
allocate (r, transpPixel);
if (!valid ()) return;
// Copy data
if (r == vop.where ())
memcpy (m_ppxl, vop.pixels (), m_rc.area () * sizeof (PixelF));
else {
r.clip (vop.where ()); // find the intersection
CoordI x = r.left; // copy pixels
Int cbLine = r.width * numPln;
CPixel* ppxl = (CPixel*) pixels (x, r.top);
const CPixel* ppxlVop = vop.pixels (x, r.top);
Int widthCurr = where ().width;
Int widthVop = vop.where ().width;
for (CoordI y = r.top; y < r.bottom; y++) {
memcpy (ppxl, ppxlVop, cbLine);
ppxl += widthCurr;
ppxlVop += widthVop;
}
}
}
Void CVideoObjectPlane::swap (CVideoObjectPlane& vop)
{
assert (this && &vop);
CRct rcT = vop.m_rc;
vop.m_rc = m_rc;
m_rc = rcT;
CPixel* ppxlT = vop.m_ppxl;
vop.m_ppxl = m_ppxl;
m_ppxl = ppxlT;
}
CVideoObjectPlane::CVideoObjectPlane (const CVideoObjectPlane& vop, CRct r) : m_ppxl (NULL)
{
copyConstruct (vop, r);
}
CVideoObjectPlane::CVideoObjectPlane (CRct r, CPixel pxl) : m_ppxl (NULL)
{
allocate (r, pxl);
}
CVideoObjectPlane::CVideoObjectPlane (const Char* vdlFileName) : m_ppxl (NULL)
{
FILE* pf = fopen (vdlFileName, "rb");
// write overhead
Int c0 = getc (pf);
Int c1 = getc (pf);
assert (c0 == 'V' && (c1 == 'M' || c1 == 'B') );
CRct rc;
if (c1 == 'M'){
fread (&rc.left, sizeof (CoordI), 1, pf);
fread (&rc.top, sizeof (CoordI), 1, pf);
fread (&rc.right, sizeof (CoordI), 1, pf);
fread (&rc.bottom, sizeof (CoordI), 1, pf);
rc.width = rc.right - rc.left;
}
else {
U8 byte1, byte2;
Int sign;
byte1 = getc (pf);
byte2 = getc (pf);
sign = ((byte1 / 128) == 1) ? 1 : -1;
rc.left = byte1 % 128;
rc.left = (rc.left * 256) + byte2;
rc.left *= sign;
byte1 = getc (pf);
byte2 = getc (pf);
sign = ((byte1 / 128) > 0) ? 1 : -1;
rc.top = byte1 % 128;
rc.top = (rc.top * 256) + byte2;
rc.top *= sign;
byte1 = getc (pf);
byte2 = getc (pf);
sign = ((byte1 / 128) > 0) ? 1 : -1;
rc.right = byte1 % 128;
rc.right = (rc.right * 256) + byte2;
rc.right *= sign;
byte1 = getc (pf);
byte2 = getc (pf);
sign = ((byte1 / 128) > 0) ? 1 : -1;
rc.bottom = byte1 % 128;
rc.bottom = (rc.bottom * 256) + byte2;
rc.bottom *= sign;
rc.width = rc.right - rc.left;
}
allocate (rc);
// read the actual data
fread (m_ppxl, sizeof (CPixel), where ().area (), pf);
fclose (pf);
}
CVideoObjectPlane::CVideoObjectPlane (
const Char* pchFileName,
UInt ifr,
const CRct& rct,
ChromType chrType,
Int nszHeader
) : m_ppxl (NULL)
{
assert (!rct.empty ());
assert (ifr >= 0);
assert (nszHeader >= 0);
Int iWidth = rct.width, iHeight = rct.height ();
UInt area = rct.area ();
Int iUVWidth = iWidth, iUVHeight = iHeight;
Int uiXSubsample = 1, uiYSubsample = 1;
if (chrType == FOUR_TWO_TWO) {
uiXSubsample = 2;
iUVWidth = (iWidth + 1) / uiXSubsample;
}
else if (chrType == FOUR_TWO_ZERO) {
uiXSubsample = 2;
uiYSubsample = 2;
iUVWidth = (iWidth + 1) / uiXSubsample;
iUVHeight = (iHeight + 1) / uiYSubsample;
}
UInt iUVArea = iUVWidth * iUVHeight;
// allocate mem for buffers
U8* pchyBuffer = new U8 [area];
U8* pchuBuffer = new U8 [iUVArea];
U8* pchvBuffer = new U8 [iUVArea];
U8* pchyBuffer0 = pchyBuffer;
U8* pchuBuffer0 = pchuBuffer;
U8* pchvBuffer0 = pchvBuffer;
// read data from a file
FILE* fpYuvSrc = fopen (pchFileName, "rb");
assert (fpYuvSrc != NULL);
UInt skipSize = (UInt) ((Float) (ifr * sizeof (U8) * (area + 2 * iUVArea)));
fseek (fpYuvSrc, nszHeader + skipSize, SEEK_SET);
Int size = (Int) fread (pchyBuffer, sizeof (U8), area, fpYuvSrc);
assert (size != 0);
size = (Int) fread (pchuBuffer, 1, iUVArea, fpYuvSrc);
assert (size != 0);
size = (Int) fread (pchvBuffer, 1, iUVArea, fpYuvSrc);
assert (size != 0);
fclose(fpYuvSrc);
// assign buffers to a vframe
allocate (rct, opaquePixel);
CPixel* p = (CPixel*) pixels ();
for (CoordI y = 0; y < iHeight; y++) {
if ((y % uiYSubsample) == 1) {
pchuBuffer -= iUVWidth;
pchvBuffer -= iUVWidth;
}
for (CoordI x = 0; x < iWidth; x++) {
p -> pxlU.yuv.y = *pchyBuffer++;
p -> pxlU.yuv.u = *pchuBuffer;
p -> pxlU.yuv.v = *pchvBuffer;
if (chrType == FOUR_FOUR_FOUR || (x % uiXSubsample) != 0) {
pchuBuffer++;
pchvBuffer++;
}
p++;
}
}
delete [] pchyBuffer0;
delete [] pchuBuffer0;
delete [] pchvBuffer0;
}
Void CVideoObjectPlane::where (const CRct& r)
{
if (!valid ()) return;
if (where () == r) return;
CVideoObjectPlane* pvop = new CVideoObjectPlane (*this, r);
swap (*pvop);
delete pvop;
}
CRct CVideoObjectPlane::whereVisible() const
{
if (!valid () || !m_rc.valid ()) return CRct ();
CoordI left = where ().right - 1;
CoordI top = where ().bottom - 1;
CoordI right = where ().left;
CoordI bottom = where ().top;
const CPixel* ppxlThis = pixels ();
for (CoordI y = where ().top; y < where ().bottom; y++) {
for (CoordI x = where ().left; x < where ().right; x++) {
if (ppxlThis -> pxlU.rgb.a != transpValue) {
left = min (left, x);
top = min (top, y);
right = max (right, x);
bottom = max (bottom, y);
}
ppxlThis++;
}
}
right++;
bottom++;
return CRct (left, top, right, bottom);
if (!valid () || !m_rc.valid ()) return CRct ();}
CPixel CVideoObjectPlane::pixel (CoordI x, CoordI y, UInt accuracy_ori) const
{
UInt accuracy1 = accuracy_ori + 1;
CoordI left = (CoordI) floor ((Double) (x >> accuracy1)); // find the coordinates of the four corners
CoordI wLeft = where ().left, wRight1 = where ().right - 1, wTop = where ().top, wBottom1 = where ().bottom - 1;
left = checkrange (left, wLeft, wRight1);
CoordI right = (CoordI) ceil ((Double) (x >> accuracy1));
right = checkrange (right, wLeft, wRight1);
CoordI top = (CoordI) floor ((Double) (y >> accuracy1));
top = checkrange (top, wTop, wBottom1);
CoordI bottom = (CoordI) ceil ((Double) (y >> accuracy1));
bottom = checkrange (bottom, wTop, wBottom1);
UInt accuracy2 = (accuracy_ori << 1) + 2;
const CPixel lt = pixel (left, top);
const CPixel rt = pixel (right, top);
const CPixel lb = pixel (left, bottom);
const CPixel rb = pixel (right, bottom);
const Int distX = (x - left) << accuracy1;
const Int distY = (y - top) << accuracy1;
Int x01 = (distX * (rt.pxlU.rgb.r - lt.pxlU.rgb.r) + (Int) lt.pxlU.rgb.r) << accuracy1; // use p.59's notation (Wolberg, Digital Image Warping)
Int x23 = (distX * (rb.pxlU.rgb.r - lb.pxlU.rgb.r) + (Int) lb.pxlU.rgb.r) << accuracy1;
Int r = checkrange (((x01 << accuracy1) + (x23 - x01) * distY) >> accuracy2, 0, 255);
x01 = (distX * (rt.pxlU.rgb.g - lt.pxlU.rgb.g) + (Int) lt.pxlU.rgb.g) << accuracy1; // use p.59's notation
x23 = (distX * (rb.pxlU.rgb.g - lb.pxlU.rgb.g) + (Int) lb.pxlU.rgb.g) << accuracy1;
Int g = checkrange (((x01 << accuracy1) + (x23 - x01) * distY) >> accuracy2, 0, 255);
x01 = (distX * (rt.pxlU.rgb.b - lt.pxlU.rgb.b) + (Int) lt.pxlU.rgb.b) << accuracy1; // use p.59's notation
x23 = (distX * (rb.pxlU.rgb.b - lb.pxlU.rgb.b) + (Int) lb.pxlU.rgb.b) << accuracy1;
Int b = checkrange (((x01 << accuracy1) + (x23 - x01) * distY) >> accuracy2, 0, 255);
x01 = (distX * (rt.pxlU.rgb.a - lt.pxlU.rgb.a) + (Int) lt.pxlU.rgb.a) << accuracy1; // use p.59's notation
x23 = (distX * (rb.pxlU.rgb.a - lb.pxlU.rgb.a) + (Int) lb.pxlU.rgb.a) << accuracy1;
Int a = checkrange (((x01 << accuracy1) + (x23 - x01) * distY) >> accuracy2, 0, 255);
return CPixel ((U8) r, (U8) g, (U8) b, (U8) a);
}
CPixel CVideoObjectPlane::pixel (CoordD x, CoordD y) const
{
CoordI left = (CoordI) floor (x); // find the coordinates of the four corners
CoordI wLeft = where ().left, wRight1 = where ().right - 1, wTop = where ().top, wBottom1 = where ().bottom - 1;
left = checkrange (left, wLeft, wRight1);
CoordI right = (CoordI) ceil (x);
right = checkrange (right, wLeft, wRight1);
CoordI top = (CoordI) floor (y);
top = checkrange (top, wTop, wBottom1);
CoordI bottom = (CoordI) ceil (y);
bottom = checkrange (bottom, wTop, wBottom1);
const CPixel lt = pixel (left, top);
const CPixel rt = pixel (right, top);
const CPixel lb = pixel (left, bottom);
const CPixel rb = pixel (right, bottom);
const Double distX = x - left;
const Double distY = y - top;
Double x01 = distX * (rt.pxlU.rgb.r - lt.pxlU.rgb.r) + lt.pxlU.rgb.r; // use p.59's notation (Wolberg, Digital Image Warping)
Double x23 = distX * (rb.pxlU.rgb.r - lb.pxlU.rgb.r) + lb.pxlU.rgb.r;
Int r = checkrange ((Int) (x01 + (x23 - x01) * distY + .5), 0, 255);
x01 = distX * (rt.pxlU.rgb.g - lt.pxlU.rgb.g) + lt.pxlU.rgb.g; // use p.59's notation
x23 = distX * (rb.pxlU.rgb.g - lb.pxlU.rgb.g) + lb.pxlU.rgb.g;
Int g = checkrange ((Int) (x01 + (x23 - x01) * distY + .5), 0, 255);
x01 = distX * (rt.pxlU.rgb.b - lt.pxlU.rgb.b) + lt.pxlU.rgb.b; // use p.59's notation
x23 = distX * (rb.pxlU.rgb.b - lb.pxlU.rgb.b) + lb.pxlU.rgb.b;
Int b = checkrange ((Int) (x01 + (x23 - x01) * distY + .5), 0, 255);
x01 = distX * (rt.pxlU.rgb.a - lt.pxlU.rgb.a) + lt.pxlU.rgb.a; // use p.59's notation
x23 = distX * (rb.pxlU.rgb.a - lb.pxlU.rgb.a) + lb.pxlU.rgb.a;
Int a = checkrange ((Int) (x01 + (x23 - x01) * distY + .5), 0, 255);
return CPixel ((U8) r, (U8) g, (U8) b, (U8) a);
}
own CVideoObjectPlane* CVideoObjectPlane::warp (const CAffine2D& aff) const // affine warp
{
CSiteD stdLeftTopWarp = aff * CSiteD (where ().left, where ().top);
CSiteD stdRightTopWarp = aff * CSiteD (where ().right, where ().top);
CSiteD stdLeftBottomWarp = aff * CSiteD (where ().left, where ().bottom);
CSiteD stdRightBottomWarp = aff * CSiteD (where ().right, where ().bottom);
CRct rctWarp (stdLeftTopWarp, stdRightTopWarp, stdLeftBottomWarp, stdRightBottomWarp);
CVideoObjectPlane* pvopRet = new CVideoObjectPlane (rctWarp);
CPixel* ppxlRet = (CPixel*) pvopRet -> pixels ();
CAffine2D affInv = aff.inverse ();
for (CoordI y = rctWarp.top; y < rctWarp.bottom; y++) {
for (CoordI x = rctWarp.left; x < rctWarp.right; x++) {
CSiteD src = affInv * CSiteD (x, y);
CoordI fx = (CoordI) floor (src.x); //.5 is for better truncation
CoordI fy = (CoordI) floor (src.y); //.5 is for better truncation
CoordI cx = (CoordI) ceil (src.x); //.5 is for better truncation
CoordI cy = (CoordI) ceil (src.y); //.5 is for better truncation
if (
where ().includes (fx, fy) &&
where ().includes (fx, cy) &&
where ().includes (cx, fy) &&
where ().includes (cx, cy)
)
*ppxlRet = pixel (src);
ppxlRet++;
}
}
return pvopRet;
}
own CVideoObjectPlane* CVideoObjectPlane::warp (const CAffine2D& aff, const CRct& rctWarp) const // affine warp
{
CVideoObjectPlane* pvopRet = new CVideoObjectPlane (rctWarp);
CPixel* ppxlRet = (CPixel*) pvopRet -> pixels ();
//CAffine2D affInv = aff.inverse ();
for (CoordI y = rctWarp.top; y < rctWarp.bottom; y++) {
for (CoordI x = rctWarp.left; x < rctWarp.right; x++) {
CSiteD src = aff * CSiteD (x, y);
CoordI fx = (CoordI) floor (src.x); //.5 is for better truncation
CoordI fy = (CoordI) floor (src.y); //.5 is for better truncation
CoordI cx = (CoordI) ceil (src.x); //.5 is for better truncation
CoordI cy = (CoordI) ceil (src.y); //.5 is for better truncation
if (
where ().includes (fx, fy) &&
where ().includes (fx, cy) &&
where ().includes (cx, fy) &&
where ().includes (cx, cy)
)
*ppxlRet = pixel (src);
ppxlRet++;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -