Exemplo n.º 1
0
void CHdmvSub::EnqueuePresentationSegment(REFERENCE_TIME rt)
{
    if (m_pCurrentPresentationSegment) {
        if (m_pCurrentPresentationSegment->objectCount > 0) {
            m_pCurrentPresentationSegment->rtStop = rt;
            m_pCurrentPresentationSegment->CLUT = m_CLUTs[m_pCurrentPresentationSegment->CLUT.id];

            // Get the objects' data
            POSITION pos = m_pCurrentPresentationSegment->objects.GetHeadPosition();
            while (pos) {
                CompositionObject* pObject = m_pCurrentPresentationSegment->objects.GetNext(pos);

                CompositionObject& pObjectData = m_compositionObjects[pObject->m_object_id_ref];

                pObject->m_width = pObjectData.m_width;
                pObject->m_height = pObjectData.m_height;

                pObject->SetRLEData(pObjectData.GetRLEData(), pObjectData.GetRLEDataSize(), pObjectData.GetRLEDataSize());
            }

            m_pPresentationSegments.AddTail(m_pCurrentPresentationSegment);
            TRACE_HDMVSUB( (_T("CHdmvSub: Enqueue Presentation Segment %d - %lS => %lS\n"), m_pCurrentPresentationSegment->composition_descriptor.nNumber,
                          ReftimeToCString(m_pCurrentPresentationSegment->rtStart), ReftimeToCString(m_pCurrentPresentationSegment->rtStop)) );
        } else {
            TRACE_HDMVSUB( (_T("CHdmvSub: Delete empty Presentation Segment %d\n"), m_pCurrentPresentationSegment->composition_descriptor.nNumber) );
            delete m_pCurrentPresentationSegment;
        }

        m_pCurrentPresentationSegment = NULL;
    }
}
Exemplo n.º 2
0
void CDVBSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, RECT& bbox)
{
    DVB_PAGE* pPage = FindPage(rt);

    if (pPage != NULL) {
        pPage->Rendered = true;
        for (int i = 0; i < pPage->RegionCount; i++) {
            CDVBSub::DVB_REGION* pRegion = &pPage->Regions[i];
            for (int j = 0; j < pRegion->ObjectCount; j++) {
                CompositionObject*  pObject = FindObject(pPage, pRegion->Objects[j].object_id);
                if (pObject) {
                    short nX, nY;
                    nX = pRegion->HorizAddr + pRegion->Objects[j].object_horizontal_position;
                    nY = pRegion->VertAddr  + pRegion->Objects[j].object_vertical_position;
                    pObject->m_width  = pRegion->width;
                    pObject->m_height = pRegion->height;
                    pObject->SetPalette(pRegion->Clut.Size, pRegion->Clut.Palette, m_Display.width > 720);
                    pObject->RenderDvb(spd, nX, nY);
                }
            }
        }

        bbox.left   = 0;
        bbox.top    = 0;
        bbox.right  = m_Display.width;
        bbox.bottom = m_Display.height;

    }
}
Exemplo n.º 3
0
HRESULT CDVBSub::ParseObject(CGolombBuffer& gb, WORD wSegLength)
{
    HRESULT hr = E_FAIL;

    if (m_pCurrentPage && wSegLength > 2) {
        CompositionObject* pObject = DNew CompositionObject();
        BYTE object_coding_method;

        pObject->m_object_id_ref  = gb.ReadShort();
        pObject->m_version_number = (BYTE)gb.BitRead(4);

        object_coding_method = (BYTE)gb.BitRead(2); // object_coding_method
        gb.BitRead(1);  // non_modifying_colour_flag
        gb.BitRead(1);  // reserved

        if (object_coding_method == 0x00) {
            pObject->SetRLEData(gb.GetBufferPos(), wSegLength - 3, wSegLength - 3);
            gb.SkipBytes(wSegLength - 3);
            m_pCurrentPage->Objects.AddTail(pObject);
            hr = S_OK;
        } else {
            delete pObject;
            hr = E_NOTIMPL;
        }
    }


    return hr;
}
Exemplo n.º 4
0
void CDVBSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, RECT& bbox)
{
    DVB_PAGE* pPage = FindPage(rt);

    if (pPage != NULL) {
        pPage->rendered = true;
        TRACE_DVB(_T("DVB - Renderer - %s - %s\n"), ReftimeToString(pPage->rtStart), ReftimeToString(pPage->rtStop));
        for (int i = 0; i < pPage->regionCount; i++) {
            DVB_REGION* pRegion = &pPage->regions[i];

            DVB_CLUT* pCLUT = FindClut(pPage, pRegion->CLUT_id);
            if (pCLUT) {
                for (int j = 0; j < pRegion->objectCount; j++) {
                    CompositionObject*  pObject = FindObject(pPage, pRegion->objects[j].object_id);
                    if (pObject) {
                        short nX, nY;
                        nX = pRegion->horizAddr + pRegion->objects[j].object_horizontal_position;
                        nY = pRegion->vertAddr  + pRegion->objects[j].object_vertical_position;
                        pObject->m_width  = pRegion->width;
                        pObject->m_height = pRegion->height;
                        pObject->SetPalette(pCLUT->size, pCLUT->palette, m_Display.width > 720);
                        pObject->RenderDvb(spd, nX, nY);
                        TRACE_DVB(_T(" --> %d/%d - %d/%d\n"), i + 1, pPage->regionCount, j + 1, pRegion->objectCount);
                    }
                }
            }
        }

        bbox.left   = 0;
        bbox.top    = 0;
        bbox.right  = m_Display.width;
        bbox.bottom = m_Display.height;
    }
}
Exemplo n.º 5
0
void CHdmvSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, RECT& bbox)
{
    HDMV_PRESENTATION_SEGMENT* pPresentationSegment = FindPresentationSegment(rt);

    bbox.left   = LONG_MAX;
    bbox.top    = LONG_MAX;
    bbox.right  = 0;
    bbox.bottom = 0;

    if (pPresentationSegment) {
        POSITION pos = pPresentationSegment->objects.GetHeadPosition();

        TRACE_HDMVSUB(_T("CHdmvSub:Render Presentation segment %d --> %s - %s\n"), pPresentationSegment->composition_descriptor.nNumber,
                      ReftimeToString(pPresentationSegment->rtStart), ReftimeToString(pPresentationSegment->rtStop));

        while (pos) {
            CompositionObject* pObject = pPresentationSegment->objects.GetNext(pos);

            if (pObject->GetRLEDataSize() && pObject->m_width > 0 && pObject->m_height > 0
                    && spd.w >= (pObject->m_horizontal_position + pObject->m_width) && spd.h >= (pObject->m_vertical_position + pObject->m_height)) {
                pObject->SetPalette(pPresentationSegment->CLUT.size, pPresentationSegment->CLUT.palette, pPresentationSegment->video_descriptor.nVideoWidth > 720);

                bbox.left   = min(pObject->m_horizontal_position, bbox.left);
                bbox.top    = min(pObject->m_vertical_position, bbox.top);
                bbox.right  = max(pObject->m_horizontal_position + pObject->m_width, bbox.right);
                bbox.bottom = max(pObject->m_vertical_position + pObject->m_height, bbox.bottom);

                TRACE_HDMVSUB(_T(" --> Object %d (Res=%dx%d, SPDRes=%dx%d)\n"), pObject->m_object_id_ref, pObject->m_width, pObject->m_height, spd.w, spd.h);
                pObject->RenderHdmv(spd);
            } else {
                TRACE_HDMVSUB(_T(" --> Invalid object %d\n"), pObject->m_object_id_ref);
            }
        }
    }
}
STDMETHODIMP CXSUBSubtitle::Render(SubPicDesc& spd, REFERENCE_TIME rt, double fps, RECT& bbox)
{
	CAutoLock cAutoLock(&m_csCritSec);

	bbox.left	= LONG_MAX;
	bbox.top	= LONG_MAX;
	bbox.right	= 0;
	bbox.bottom	= 0;

	POSITION pos = m_pObjects.GetHeadPosition();
	while (pos) {
		CompositionObject* pObject = m_pObjects.GetAt (pos);

		if (pObject && rt >= pObject->m_rtStart && rt < pObject->m_rtStop && pObject->HavePalette()) {

			// To fit in current surface size on render - looks very crooked
			int delta_x = (m_size.cx - (pObject->m_horizontal_position + pObject->m_width)) * spd.w/m_size.cx;
			int delta_y = (m_size.cy - (pObject->m_vertical_position + pObject->m_height)) * spd.h/m_size.cy;

			if (spd.w < (pObject->m_horizontal_position + pObject->m_width)) {
				pObject->m_horizontal_position = max(0, spd.w - pObject->m_width - delta_x);
			}

			if (spd.h < (pObject->m_vertical_position + pObject->m_height)) {
				pObject->m_vertical_position = max(0, spd.h - pObject->m_height - delta_y);
			}

			if (pObject->GetRLEDataSize() && pObject->m_width > 0 && pObject->m_height > 0 &&
					spd.w >= (pObject->m_horizontal_position + pObject->m_width) &&
					spd.h >= (pObject->m_vertical_position + pObject->m_height)) {

				bbox.left	= min(pObject->m_horizontal_position, bbox.left);
				bbox.top	= min(pObject->m_vertical_position, bbox.top);
				bbox.right	= max(pObject->m_horizontal_position + pObject->m_width, bbox.right);
				bbox.bottom	= max(pObject->m_vertical_position + pObject->m_height, bbox.bottom);

				ASSERT(spd.h>=0);
				bbox.left	= bbox.left > 0 ? bbox.left : 0;
				bbox.top	= bbox.top > 0 ? bbox.top : 0;
				bbox.right	= bbox.right < spd.w ? bbox.right : spd.w;
				bbox.bottom	= bbox.bottom < spd.h ? bbox.bottom : spd.h;

				pObject->RenderXSUB(spd);
			}
		}

		m_pObjects.GetNext(pos);
	}

	CleanOld(rt - 60*10000000i64);

	return S_OK;
}
Exemplo n.º 7
0
void CHdmvSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, RECT& bbox)
{
    HDMV_PRESENTATION_SEGMENT* pPresentationSegment = FindPresentationSegment(rt);

    bbox.left   = LONG_MAX;
    bbox.top    = LONG_MAX;
    bbox.right  = 0;
    bbox.bottom = 0;

    if (pPresentationSegment) {
        POSITION pos = pPresentationSegment->objects.GetHeadPosition();

        TRACE_HDMVSUB( (_T("CHdmvSub:Render Presentation segment %d --> %lS - %lS\n"), pPresentationSegment->composition_descriptor.nNumber,
                      ReftimeToCString(pPresentationSegment->rtStart), ReftimeToCString(pPresentationSegment->rtStop)) );

        while (pos) {
            CompositionObject* pObject = pPresentationSegment->objects.GetNext(pos);

            if (pObject->GetRLEDataSize() && pObject->m_width > 0 && pObject->m_height > 0
                && spd.w >= (pObject->m_horizontal_position + pObject->m_width) 
                && spd.h >= (pObject->m_vertical_position + pObject->m_height)) 
            {
                CompositionObject::ColorType color_type = m_colorTypeSetting;
                if (color_type==CompositionObject::NONE)
                {
                    color_type = pPresentationSegment->video_descriptor.nVideoWidth > 720 ? 
                        CompositionObject::YUV_Rec709 : CompositionObject::YUV_Rec601;
                }
                pObject->SetPalette(pPresentationSegment->CLUT.size, pPresentationSegment->CLUT.palette, color_type, 
                    m_yuvRangeSetting==CompositionObject::RANGE_NONE ? CompositionObject::RANGE_TV : m_yuvRangeSetting);

                bbox.left   = min(pObject->m_horizontal_position, bbox.left);
                bbox.top    = min(pObject->m_vertical_position, bbox.top);
                bbox.right  = max(pObject->m_horizontal_position + pObject->m_width, bbox.right);
                bbox.bottom = max(pObject->m_vertical_position + pObject->m_height, bbox.bottom);

                ASSERT(spd.h>=0);
                bbox.left = bbox.left > 0 ? bbox.left : 0;
                bbox.top = bbox.top > 0 ? bbox.top : 0;
                bbox.right = bbox.right < spd.w ? bbox.right : spd.w;
                bbox.bottom = bbox.bottom < spd.h ? bbox.bottom : spd.h;

                pObject->InitColor(spd);
                TRACE_HDMVSUB( (_T(" --> Object %d (Pos=%dx%d, Res=%dx%d, SPDRes=%dx%d)\n"),
                              pObject->m_object_id_ref, pObject->m_horizontal_position, pObject->m_vertical_position, pObject->m_width, pObject->m_height, spd.w, spd.h) );
                pObject->RenderHdmv(spd);
            } else {
                TRACE_HDMVSUB( (_T(" --> Invalid object %d\n"), pObject->m_object_id_ref) );
            }
        }
    }
}
Exemplo n.º 8
0
POSITION CHdmvSub::GetStartPosition(REFERENCE_TIME rt, double fps)
{
	CompositionObject*	pObject;

	// Cleanup old PG
	while (m_pObjects.GetCount()>0) {
		pObject = m_pObjects.GetHead();
		if (pObject->m_rtStop < rt) {
			TRACE_HDMVSUB ("CHdmvSub:HDMV remove object %d  %S => %S (rt=%S)\n", pObject->GetRLEDataSize(),
						   ReftimeToString (pObject->m_rtStart), ReftimeToString(pObject->m_rtStop), ReftimeToString(rt));
			m_pObjects.RemoveHead();
			delete pObject;
		} else {
			break;
		}
	}

	return m_pObjects.GetHeadPosition();
}
Exemplo n.º 9
0
void CDVBSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, RECT& bbox)
{
	DVB_PAGE* pPage = FindPage (rt);

	if (pPage != NULL) {
		pPage->Rendered = true;
		for (int i=0; i<pPage->RegionCount; i++) {
			CDVBSub::DVB_REGION* pRegion = &pPage->Regions[i];
			for (int j=0; j<pRegion->ObjectCount; j++) {
				CompositionObject* pObject = FindObject (pPage, pRegion->Objects[j].object_id);
				if (pObject) {
					SHORT nX, nY;
					nX = pRegion->HorizAddr + pRegion->Objects[j].object_horizontal_position;
					nY = pRegion->VertAddr  + pRegion->Objects[j].object_vertical_position;
					pObject->m_width  = pRegion->width;
					pObject->m_height = pRegion->height;
					CDVBSub::DVB_CLUT* pClut = FindClut(pPage, pRegion->CLUT_id);
					if (pClut != NULL) {
						pObject->SetPalette(pClut->Size, pClut->Palette, m_Display.width > 720);
					}

					TRACE_DVB (_T("CDVBSub::Render() : size = %ld, %d:%d, ObjRes = %dx%d, SPDRes = %dx%d, %I64d = %ws, [%ws => %ws]\n"),
									pObject->GetRLEDataSize(),
									nX, nY,
									pObject->m_width, pObject->m_height, spd.w, spd.h,
									rt, ReftimeToString(rt),
									ReftimeToString(pPage->rtStart), ReftimeToString(pPage->rtStop));

					
					pObject->RenderDvb(spd, nX, nY);
				}
			}
		}

		bbox.left	= 0;
		bbox.top	= 0;
		bbox.right	= m_Display.width < spd.w ? m_Display.width : spd.w;
		ASSERT(spd.h >= 0);
		bbox.bottom	= m_Display.height < spd.h ? m_Display.height : spd.h;
	}
}
Exemplo n.º 10
0
void CHdmvSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, RECT& bbox)
{
	CompositionObject*	pObject = FindObject (rt);

	ASSERT (pObject!=NULL && spd.w >= pObject->m_width && spd.h >= pObject->m_height);

	if (pObject && spd.w >= pObject->m_width && spd.h >= pObject->m_height) {
		if (!pObject->HavePalette()) {
			pObject->SetPalette (m_nDefaultPaletteNbEntry, m_pDefaultPalette, m_VideoDescriptor.nVideoWidth>720);
		}

		TRACE_HDMVSUB ("CHdmvSub:Render	    size=%ld,  ObjRes=%dx%d,  SPDRes=%dx%d\n", pObject->GetRLEDataSize(),
					   pObject->m_width, pObject->m_height, spd.w, spd.h);
		pObject->RenderHdmv(spd);

		bbox.left	= 0;
		bbox.top	= 0;
		bbox.right	= bbox.left + pObject->m_width;
		bbox.bottom	= bbox.top  + pObject->m_height;
	}
}
HRESULT CXSUBSubtitle::ParseSample (IMediaSample* pSample)
{
	CAutoLock cAutoLock(&m_csCritSec);
	HRESULT		hr = E_FAIL;

	CheckPointer (pSample, E_POINTER);
	BYTE*	pData = NULL;
	int		lSampleLen;

	hr = pSample->GetPointer(&pData);
	if (FAILED(hr) || pData == NULL) {
		return hr;
	}
	lSampleLen = pSample->GetActualDataLength();
	if (lSampleLen < (27 + 7 * 2 + 4 * 3)) {
		return E_FAIL;
	}

	if (pData[0] != '[' || pData[13] != '-' || pData[26] != ']') {
		return E_FAIL;
	}

	REFERENCE_TIME rtStart = INVALID_TIME, rtStop = INVALID_TIME;
	CString tmp((char*)pData, 26);
	rtStart	= StringToReftime(tmp.Mid(1, 12));
	rtStop	= StringToReftime(tmp.Mid(14, 12));

	if (rtStop <= rtStart) {
		return E_FAIL;
	}

	CompositionObject*	pSub = DNew CompositionObject;
	pSub->m_rtStart	= rtStart;
	pSub->m_rtStop	= rtStop;

	CGolombBuffer gb(pData + 27, lSampleLen - 27);
	pSub->m_width				= gb.ReadShortLE();
	pSub->m_height				= gb.ReadShortLE();
	pSub->m_horizontal_position	= gb.ReadShortLE();
	pSub->m_vertical_position	= gb.ReadShortLE();
	// skip bottom right position
	gb.ReadShortLE();
	gb.ReadShortLE();
	// length of the RLE data
	gb.ReadShortLE();
	// Palette, 4 color entries
	HDMV_PALETTE Palette[4];
	for (int entry=0; entry < 4; entry++) {
		Palette[entry].entry_id	= entry;
		Palette[entry].Y	= gb.ReadByte();	// red
		Palette[entry].Cr	= gb.ReadByte();	// green
		Palette[entry].Cb	= gb.ReadByte();	// blue
		if (entry) {
			Palette[entry].T = 0xFF; // first entry - background, fully transparent
		}
	}

	pSub->SetPalette(4, Palette, false, true);

	int RLESize = gb.GetSize() - gb.GetPos();
	pSub->SetRLEData(gb.GetBufferPos(), RLESize, RLESize);

	m_pObjects.AddTail(pSub);

	hr = S_OK;

	return hr;
}
Exemplo n.º 12
0
void CHdmvSub::ParsePresentationSegment(CGolombBuffer* pGBuffer, REFERENCE_TIME rtTime)
{
	COMPOSITION_DESCRIPTOR	CompositionDescriptor;
	BYTE					nObjectNumber;
	bool					palette_update_flag;
	BYTE					palette_id_ref;

	ParseVideoDescriptor(pGBuffer, &m_VideoDescriptor);
	ParseCompositionDescriptor(pGBuffer, &CompositionDescriptor);
	palette_update_flag	= !!(pGBuffer->ReadByte() & 0x80);
	UNREFERENCED_PARAMETER(palette_update_flag);
	palette_id_ref		= pGBuffer->ReadByte();
	nObjectNumber		= pGBuffer->ReadByte();

	TRACE_HDMVSUB(_T("CHdmvSub::ParsePresentationSegment() : Size = %d, nObjectNumber = %d, palette_id_ref = %d, compositionNumber = %d\n"),
					pGBuffer->GetSize(), nObjectNumber, palette_id_ref, CompositionDescriptor.nNumber);

	if (m_pCurrentWindow && m_pCurrentWindow->m_nObjectNumber && m_pCurrentWindow->m_compositionNumber != -1) {
		for (int i = 0; i < m_pCurrentWindow->m_nObjectNumber; i++) {
			if (m_pCurrentWindow->Objects[i]) {
				CompositionObject* pObject		= m_pCurrentWindow->Objects[i];
				CompositionObject& pObjectData	= m_ParsedObjects[pObject->m_object_id_ref];
				if (pObjectData.m_width) {
					pObject->m_rtStop	= rtTime;
					pObject->m_width	= pObjectData.m_width;
					pObject->m_height	= pObjectData.m_height;

					pObject->SetRLEData(pObjectData.GetRLEData(), pObjectData.GetRLEDataSize(), pObjectData.GetRLEDataSize());

					if (!pObject->HavePalette() && m_CLUT[palette_id_ref].Palette) {
						pObject->SetPalette(m_CLUT[palette_id_ref].pSize, m_CLUT[palette_id_ref].Palette, m_VideoDescriptor.nVideoWidth > 720);
					}

					TRACE_HDMVSUB(_T("			store Segment : m_object_id_ref = %d, m_window_id_ref = %d, compositionNumber = %d, [%10I64d -> %10I64d], [%s -> %s]\n"),
									m_pCurrentWindow->Objects[i]->m_object_id_ref,
									m_pCurrentWindow->Objects[i]->m_window_id_ref,
									m_pCurrentWindow->Objects[i]->m_compositionNumber,
									m_pCurrentWindow->Objects[i]->m_rtStart, m_pCurrentWindow->Objects[i]->m_rtStop,
									ReftimeToString(m_pCurrentWindow->Objects[i]->m_rtStart), ReftimeToString(m_pCurrentWindow->Objects[i]->m_rtStop));

					m_pObjects.AddTail (m_pCurrentWindow->Objects[i]);
				} else {
					delete m_pCurrentWindow->Objects[i];
				}
			}
			m_pCurrentWindow->Objects[i] = NULL;
		}
	}

	if (!m_pCurrentWindow) {
		m_pCurrentWindow = DNew HDMV_WindowDefinition();
	} else {
		m_pCurrentWindow->Reset();
	}

	if (nObjectNumber > 0) {
		m_pCurrentWindow->m_nObjectNumber		= nObjectNumber;
		m_pCurrentWindow->m_palette_id_ref		= (SHORT)palette_id_ref;
		m_pCurrentWindow->m_compositionNumber	= CompositionDescriptor.nNumber;

		for (int i = 0; i < nObjectNumber; i++) {
			m_pCurrentWindow->Objects[i]						= DNew CompositionObject();
			m_pCurrentWindow->Objects[i]->m_rtStart				= rtTime;
			m_pCurrentWindow->Objects[i]->m_rtStop				= _I64_MAX;
			m_pCurrentWindow->Objects[i]->m_compositionNumber	= CompositionDescriptor.nNumber;

			ParseCompositionObject(pGBuffer, m_pCurrentWindow->Objects[i]);
		}
	}
}
Exemplo n.º 13
0
void CHdmvSub::Render(SubPicDesc& spd, REFERENCE_TIME rt, RECT& bbox)
{
	bbox.left	= LONG_MAX;
	bbox.top	= LONG_MAX;
	bbox.right	= 0;
	bbox.bottom	= 0;

	POSITION pos = m_pObjects.GetHeadPosition();
	while (pos) {
		CompositionObject* pObject = m_pObjects.GetAt (pos);

		if (pObject && rt >= pObject->m_rtStart && rt < pObject->m_rtStop) {
			if (pObject->GetRLEDataSize() && pObject->m_width > 0 && pObject->m_height > 0 &&
					m_VideoDescriptor.nVideoWidth >= (pObject->m_horizontal_position + pObject->m_width) &&
					m_VideoDescriptor.nVideoHeight >= (pObject->m_vertical_position + pObject->m_height)) {

				if (g_bForcedSubtitle && !pObject->m_forced_on_flag) {
					TRACE_HDMVSUB(_T("CHdmvSub::Render() : skip non forced subtitle - forced = %d, %I64d = %s"), pObject->m_forced_on_flag, rt, ReftimeToString(rt));
					return;
				}

				if (!pObject->HavePalette() && m_DefaultCLUT.Palette) {
					pObject->SetPalette(m_DefaultCLUT.pSize, m_DefaultCLUT.Palette, m_VideoDescriptor.nVideoWidth > 720);
				}

				if (!pObject->HavePalette()) {
					TRACE_HDMVSUB(_T("CHdmvSub::Render() : The palette is missing - cancel rendering\n"));
					return;
				}

				bbox.left	= min(pObject->m_horizontal_position, bbox.left);
				bbox.top	= min(pObject->m_vertical_position, bbox.top);
				bbox.right	= max(pObject->m_horizontal_position + pObject->m_width, bbox.right);
				bbox.bottom	= max(pObject->m_vertical_position + pObject->m_height, bbox.bottom);

				bbox.left	= bbox.left > 0 ? bbox.left : 0;
				bbox.top	= bbox.top > 0 ? bbox.top : 0;
				if (m_VideoDescriptor.nVideoWidth > spd.w) {
					bbox.left	= MulDiv(bbox.left, spd.w, m_VideoDescriptor.nVideoWidth);
					bbox.right	= MulDiv(bbox.right, spd.w, m_VideoDescriptor.nVideoWidth);
				}
				if (m_VideoDescriptor.nVideoHeight > spd.h) {
					bbox.top	= MulDiv(bbox.top, spd.h, m_VideoDescriptor.nVideoHeight);
					bbox.bottom	= MulDiv(bbox.bottom, spd.h, m_VideoDescriptor.nVideoHeight);
				}

				TRACE_HDMVSUB(_T("CHdmvSub::Render() : size = %ld, ObjRes = %dx%d, SPDRes = %dx%d, %I64d = %s\n"),
								pObject->GetRLEDataSize(),
								pObject->m_width, pObject->m_height, spd.w, spd.h,
								rt, ReftimeToString(rt));

				InitSpd(spd, m_VideoDescriptor.nVideoWidth, m_VideoDescriptor.nVideoHeight);
				pObject->RenderHdmv(spd, m_bResizedRender ? &m_spd : NULL);
			}
		}

		m_pObjects.GetNext(pos);
	}

	FinalizeRender(spd);
}