예제 #1
0
HRESULT CSubtitleInputPin::CompleteConnect(IPin* pReceivePin)
{
    CAutoLock cAutoLock(m_pSubLock);
    XY_LOG_DEBUG(XY_LOG_VAR_2_STR(pReceivePin));
    delete m_helper; m_helper = NULL;
    m_helper = CreateHelper(m_mt, pReceivePin);
    if (!m_helper)
    {
        XY_LOG_ERROR("Failed to Create helper. ");
        return E_FAIL;
    }
    AddSubStream(m_helper->GetSubStream());

    return __super::CompleteConnect(pReceivePin);
}
예제 #2
0
void CompositionObject::InitColor(const SubPicDesc& spd)
{
#define COMBINE_AYUV(a, y, u, v) ((((((((int)(a))<<8)|y)<<8)|u)<<8)|v)
    //fix me: move all color conv function into color_conv_table or dsutil
#define FULL_TYPE(x,y) (((x)<<8)|y)

    int paletteNumber = m_Palette.GetCount();
    if (m_colorType!=spd.type)
    {
        m_colorType = -1;
        ColorConvTable::YuvMatrixType cur_type;
        ColorConvTable::YuvRangeType cur_range;
        if (m_OriginalColorType==YUV_Rec601)
        {
            cur_type = ColorConvTable::BT601;
        }
        else if (m_OriginalColorType==YUV_Rec709)
        {
            cur_type = ColorConvTable::BT709;
        }
        else
        {
            XY_LOG_ERROR("Not supported");
            ASSERT(0);
            return;
        }
        if (m_OriginalYuvRangeType==RANGE_TV)
        {
            cur_range = ColorConvTable::RANGE_TV;
        }
        else if (m_OriginalYuvRangeType==RANGE_PC)
        {
            cur_range = ColorConvTable::RANGE_PC;
        }
        else
        {
            XY_LOG_ERROR("Not supported");
            ASSERT(0);
            return;
        }

        m_colorType = spd.type;
        switch(spd.type)
        {
        case MSP_AYUV_PLANAR:
        case MSP_AYUV:
            if (FULL_TYPE(cur_type,cur_range)==
                FULL_TYPE(ColorConvTable::GetDefaultYUVType(), ColorConvTable::GetDefaultRangeType()))
            {
                for (int i=0;i<paletteNumber;i++)
                {
                    m_Colors[m_Palette[i].entry_id] = COMBINE_AYUV(m_Palette[i].T, m_Palette[i].Y, m_Palette[i].Cb
                        , m_Palette[i].Cr);
                }
            }
            else if (cur_type==ColorConvTable::GetDefaultYUVType())
            {
                if (cur_range==ColorConvTable::RANGE_PC)
                {
                    for (int i=0;i<paletteNumber;i++)
                    {
                        m_Colors[m_Palette[i].entry_id] = ColorConvTable::A8Y8U8V8_PC_To_TV(m_Palette[i].T, m_Palette[i].Y
                            , m_Palette[i].Cb, m_Palette[i].Cr);
                    }
                }
                else if (cur_range==ColorConvTable::RANGE_TV)
                {
                    for (int i=0;i<paletteNumber;i++)
                    {
                        m_Colors[m_Palette[i].entry_id] = ColorConvTable::A8Y8U8V8_TV_To_PC(m_Palette[i].T, m_Palette[i].Y
                            , m_Palette[i].Cb, m_Palette[i].Cr);
                    }
                }
            }
            else if (FULL_TYPE(cur_type,cur_range)==
                FULL_TYPE(ColorConvTable::BT709, ColorConvTable::RANGE_TV))
            {
                for (int i=0;i<paletteNumber;i++)
                {
                    DWORD argb = ColorConvTable::A8Y8U8V8_To_ARGB_TV_BT709(m_Palette[i].T, m_Palette[i].Y
                        , m_Palette[i].Cb, m_Palette[i].Cr);
                    m_Colors[m_Palette[i].entry_id] = ColorConvTable::Argb2Ayuv(argb);
                }
            }
            else if (FULL_TYPE(cur_type,cur_range)==
                FULL_TYPE(ColorConvTable::BT709, ColorConvTable::RANGE_PC))
            {
                for (int i=0;i<paletteNumber;i++)
                {
                    DWORD argb = ColorConvTable::A8Y8U8V8_To_ARGB_PC_BT709(m_Palette[i].T, m_Palette[i].Y
                        , m_Palette[i].Cb, m_Palette[i].Cr);
                    m_Colors[m_Palette[i].entry_id] = ColorConvTable::Argb2Ayuv(argb);
                }
            }
            else if (FULL_TYPE(cur_type,cur_range)==
                FULL_TYPE(ColorConvTable::BT601, ColorConvTable::RANGE_TV))
            {
                for (int i=0;i<paletteNumber;i++)
                {
                    DWORD argb = ColorConvTable::A8Y8U8V8_To_ARGB_TV_BT601(m_Palette[i].T, m_Palette[i].Y
                        , m_Palette[i].Cb, m_Palette[i].Cr);
                    m_Colors[m_Palette[i].entry_id] = ColorConvTable::Argb2Ayuv(argb);
                }
            }
            else if (FULL_TYPE(cur_type,cur_range)==
                FULL_TYPE(ColorConvTable::BT601, ColorConvTable::RANGE_PC))
            {
                for (int i=0;i<paletteNumber;i++)
                {
                    DWORD argb = ColorConvTable::A8Y8U8V8_To_ARGB_PC_BT601(m_Palette[i].T, m_Palette[i].Y
                        , m_Palette[i].Cb, m_Palette[i].Cr);
                    m_Colors[m_Palette[i].entry_id] = ColorConvTable::Argb2Ayuv(argb);
                }
            }
            else
            {
                XY_LOG_ERROR("Not supported");
                ASSERT(0);
                return;
            }
            break;
        case MSP_XY_AUYV:
            if (FULL_TYPE(cur_type,cur_range)==
                FULL_TYPE(ColorConvTable::GetDefaultYUVType(), ColorConvTable::GetDefaultRangeType()))
            {
                for (int i=0;i<paletteNumber;i++)
                {
                    m_Colors[m_Palette[i].entry_id] = COMBINE_AYUV(m_Palette[i].T, m_Palette[i].Cb, m_Palette[i].Y
                        , m_Palette[i].Cr);
                }
            }
            else if (cur_type==ColorConvTable::GetDefaultYUVType())
            {
                if (cur_range==ColorConvTable::RANGE_PC)
                {
                    for (int i=0;i<paletteNumber;i++)
                    {
                        DWORD ayuv = ColorConvTable::A8Y8U8V8_PC_To_TV(m_Palette[i].T, m_Palette[i].Y
                            , m_Palette[i].Cb, m_Palette[i].Cr);
                        m_Colors[m_Palette[i].entry_id] = ColorConvTable::Ayuv2Auyv(ayuv);
                    }
                }
                else if (cur_range==ColorConvTable::RANGE_TV)
                {
                    for (int i=0;i<paletteNumber;i++)
                    {
                        DWORD ayuv = ColorConvTable::A8Y8U8V8_TV_To_PC(m_Palette[i].T, m_Palette[i].Y
                            , m_Palette[i].Cb, m_Palette[i].Cr);
                        m_Colors[m_Palette[i].entry_id] = ColorConvTable::Ayuv2Auyv(ayuv);
                    }
                }
            }
            else if (FULL_TYPE(cur_type,cur_range)==
                FULL_TYPE(ColorConvTable::BT709, ColorConvTable::RANGE_TV))
            {
                for (int i=0;i<paletteNumber;i++)
                {
                    DWORD argb = ColorConvTable::A8Y8U8V8_To_ARGB_TV_BT709(m_Palette[i].T, m_Palette[i].Y
                        , m_Palette[i].Cb, m_Palette[i].Cr);
                    m_Colors[m_Palette[i].entry_id] = ColorConvTable::Argb2Auyv(argb);
                }
            }
            else if (FULL_TYPE(cur_type,cur_range)==
                FULL_TYPE(ColorConvTable::BT709, ColorConvTable::RANGE_PC))
            {
                for (int i=0;i<paletteNumber;i++)
                {
                    DWORD argb = ColorConvTable::A8Y8U8V8_To_ARGB_PC_BT709(m_Palette[i].T, m_Palette[i].Y
                        , m_Palette[i].Cb, m_Palette[i].Cr);
                    m_Colors[m_Palette[i].entry_id] = ColorConvTable::Argb2Auyv(argb);
                }
            }
            else if (FULL_TYPE(cur_type,cur_range)==
                FULL_TYPE(ColorConvTable::BT601, ColorConvTable::RANGE_TV))
            {
                for (int i=0;i<paletteNumber;i++)
                {
                    DWORD argb = ColorConvTable::A8Y8U8V8_To_ARGB_TV_BT601(m_Palette[i].T, m_Palette[i].Y
                        , m_Palette[i].Cb, m_Palette[i].Cr);
                    m_Colors[m_Palette[i].entry_id] = ColorConvTable::Argb2Auyv(argb);
                }
            }
            else if (FULL_TYPE(cur_type,cur_range)==
                FULL_TYPE(ColorConvTable::BT601, ColorConvTable::RANGE_PC))
            {
                for (int i=0;i<paletteNumber;i++)
                {
                    DWORD argb = ColorConvTable::A8Y8U8V8_To_ARGB_PC_BT601(m_Palette[i].T, m_Palette[i].Y
                        , m_Palette[i].Cb, m_Palette[i].Cr);
                    m_Colors[m_Palette[i].entry_id] = ColorConvTable::Argb2Auyv(argb);
                }
            }
            else
            {
                XY_LOG_ERROR("Not supported");
                ASSERT(0);
                return;
            }
            break;
        case MSP_RGBA:
            if (FULL_TYPE(cur_type,cur_range)==
                FULL_TYPE(ColorConvTable::BT709, ColorConvTable::RANGE_TV))
            {
                for (int i=0;i<paletteNumber;i++)
                {
                    DWORD argb = ColorConvTable::A8Y8U8V8_To_ARGB_TV_BT709(m_Palette[i].T, m_Palette[i].Y
                        , m_Palette[i].Cb, m_Palette[i].Cr);
                    m_Colors[m_Palette[i].entry_id] = argb;
                }
            }
            else if (FULL_TYPE(cur_type,cur_range)==
                FULL_TYPE(ColorConvTable::BT709, ColorConvTable::RANGE_PC))
            {
                for (int i=0;i<paletteNumber;i++)
                {
                    DWORD argb = ColorConvTable::A8Y8U8V8_To_ARGB_PC_BT709(m_Palette[i].T, m_Palette[i].Y
                        , m_Palette[i].Cb, m_Palette[i].Cr);
                    m_Colors[m_Palette[i].entry_id] = argb;
                }
            }
            else if (FULL_TYPE(cur_type,cur_range)==
                FULL_TYPE(ColorConvTable::BT601, ColorConvTable::RANGE_TV))
            {
                for (int i=0;i<paletteNumber;i++)
                {
                    DWORD argb = ColorConvTable::A8Y8U8V8_To_ARGB_TV_BT601(m_Palette[i].T, m_Palette[i].Y
                        , m_Palette[i].Cb, m_Palette[i].Cr);
                    m_Colors[m_Palette[i].entry_id] = argb;
                }
            }
            else if (FULL_TYPE(cur_type,cur_range)==
                FULL_TYPE(ColorConvTable::BT601, ColorConvTable::RANGE_PC))
            {
                for (int i=0;i<paletteNumber;i++)
                {
                    DWORD argb = ColorConvTable::A8Y8U8V8_To_ARGB_PC_BT601(m_Palette[i].T, m_Palette[i].Y
                        , m_Palette[i].Cb, m_Palette[i].Cr);
                    m_Colors[m_Palette[i].entry_id] = argb;
                }
            }
            else
            {
                XY_LOG_ERROR("Not supported");
                ASSERT(0);
                return;
            }
            break;
        default:
            XY_LOG_ERROR("Not supported");
            ASSERT(0);
            return;
        }
    }
}
STDMETHODIMP XySubRenderProviderWrapper::RequestFrame( IXySubRenderFrame**subRenderFrame, REFERENCE_TIME now  )
{
    ASSERT(m_consumer);
    double fps;
    CheckPointer(subRenderFrame, E_POINTER);
    *subRenderFrame = NULL;

    HRESULT hr = m_consumer->XyGetDouble(DirectVobSubXyOptions::DOUBLE_FPS, &fps);
    if (FAILED(hr))
    {
        XY_LOG_ERROR("Failed to get fps. "<<XY_LOG_VAR_2_STR(hr));
        return hr;
    }

    CRect output_rect, subtitle_target_rect;
    CSize original_video_size;
    bool use_dst_alpha = false;
    ASSERT(m_consumer);
    hr = m_consumer->XyGetSize(DirectVobSubXyOptions::SIZE_ORIGINAL_VIDEO, &original_video_size);
    ASSERT(SUCCEEDED(hr));
    hr = m_consumer->XyGetBool(DirectVobSubXyOptions::BOOL_SUB_FRAME_USE_DST_ALPHA, &use_dst_alpha);

    if (m_original_video_size!=original_video_size
        || m_use_dst_alpha!=use_dst_alpha)
    {
        if (m_use_dst_alpha==use_dst_alpha)
        {
            XY_LOG_WARN("Original video size changed from "<<m_original_video_size<<" to "<<original_video_size);
        }
        else
        {
            XY_LOG_INFO("'Use dst alpha' option changed from "<<m_use_dst_alpha<<" to "<<use_dst_alpha);
        }
        Invalidate();
        m_original_video_size = original_video_size;
        m_use_dst_alpha = use_dst_alpha;
    }
    if(!m_pSubPic)
    {
        if (!m_allocator)
        {
            ResetAllocator();
        }
    }

    POSITION pos = m_provider->GetStartPosition(now, fps);
    if (!pos)
    {
        return S_FALSE;
    }
    REFERENCE_TIME start = m_provider->GetStart(pos, fps);
    REFERENCE_TIME stop = m_provider->GetStop(pos, fps); //fixme: have to get start stop twice
    if (!(start <= now && now < stop))
    {
        return S_FALSE;
    }

    hr = Render( now, pos, fps );
    if (FAILED(hr))
    {
        return hr;
    }
    if (m_xy_sub_render_frame)
    {
        *subRenderFrame = m_xy_sub_render_frame;
        (*subRenderFrame)->AddRef();
    }

    return hr;
}
HRESULT XySubRenderProviderWrapper2::CombineBitmap(REFERENCE_TIME now)
{
    static int s_combined_bitmap_id = 0x10000000;//fixme: important! Uncombined bitmap id MUST < 0x10000000.

    XY_LOG_TRACE(now);
    HRESULT hr = NOERROR;
    if (m_xy_sub_render_frame)
    {
        m_subpic = NULL;
        hr = m_allocator->AllocDynamicEx(&m_subpic);
        if(FAILED(hr) || !m_subpic) {
            XY_LOG_FATAL("Failed to allocate subpic. "<<XY_LOG_VAR_2_STR(hr));
            return hr;
        }

        int count = 0;
        hr = m_xy_sub_render_frame->GetBitmapCount(&count);
        ASSERT(SUCCEEDED(hr));
        if (count==1)
        {
            return S_OK;
        }
        SubPicDesc spd;
        hr = m_subpic->Lock(spd);
        if (FAILED(hr))
        {
            XY_LOG_ERROR("Failed to lock spd. "<<XY_LOG_VAR_2_STR(hr));
            return hr;
        }
        DWORD color = 0x00000000;
        hr = m_subpic->ClearDirtyRect(color);
        if(FAILED(hr))
        {
            XY_LOG_ERROR("Failed to clear dirty rect. "<<XY_LOG_VAR_2_STR(hr));
            return hr;
        }
        CRect dirty_rect;
        for (int i=0;i<count;i++)
        {
            POINT pos;
            SIZE size;
            LPCVOID pixels;
            int pitch;
            hr = m_xy_sub_render_frame->GetBitmap(i, NULL, &pos, &size, &pixels, &pitch );
            if (FAILED(hr))
            {
                XY_LOG_ERROR("Failed to get bitmap. "<<XY_LOG_VAR_2_STR(hr));
                return hr;
            }
            ASSERT(SUCCEEDED(hr));
            dirty_rect |= CRect(pos, size);
            XyBitmap::BltPack(spd, pos, size, pixels, pitch);
        }
        dirty_rect &= m_subtitle_target_rect;
        hr = m_subpic->Unlock(&dirty_rect);
        if (FAILED(hr))
        {
            XY_LOG_ERROR("Failed to unlock. "<<XY_LOG_VAR_2_STR(dirty_rect)<<XY_LOG_VAR_2_STR(hr));
            return hr;
        }
        hr = m_subpic->GetDirtyRect(&dirty_rect);
        ASSERT(SUCCEEDED(hr));
        CMemSubPic * mem_subpic = dynamic_cast<CMemSubPic*>((ISubPicEx *)m_subpic);
        ASSERT(mem_subpic);

        m_xy_sub_render_frame = DEBUG_NEW XySubRenderFrameWrapper(mem_subpic, m_output_rect, m_subtitle_target_rect
            , s_combined_bitmap_id++, &hr);
        return hr;
    }
    return hr;
}
STDMETHODIMP XySubRenderProviderWrapper2::RequestFrame( IXySubRenderFrame**subRenderFrame, REFERENCE_TIME now )
{
    ASSERT(m_consumer);
    double fps;
    CheckPointer(subRenderFrame, E_POINTER);
    *subRenderFrame = NULL;

    HRESULT hr = m_consumer->XyGetDouble(DirectVobSubXyOptions::DOUBLE_FPS, &fps);
    if (FAILED(hr))
    {
        XY_LOG_ERROR("Failed to get fps. "<<XY_LOG_VAR_2_STR(hr));
        return hr;
    }
    m_fps = fps;//fix me: invalidate

    CRect output_rect, subtitle_target_rect;
    CSize original_video_size;
    bool use_dst_alpha = false;
    bool combine_bitmap = false;
    bool render_to_original_video_size = false;

    ASSERT(m_consumer);
    hr = m_consumer->XyGetRect(DirectVobSubXyOptions::RECT_VIDEO_OUTPUT, &output_rect);
    ASSERT(SUCCEEDED(hr));
    hr = m_consumer->XyGetRect(DirectVobSubXyOptions::RECT_SUBTITLE_TARGET, &subtitle_target_rect);
    ASSERT(SUCCEEDED(hr));
    ASSERT(output_rect.Width()<=subtitle_target_rect.Width() && output_rect.Height()<=subtitle_target_rect.Height());
    hr = m_consumer->XyGetSize(DirectVobSubXyOptions::SIZE_LAYOUT_WITH, &original_video_size);
    ASSERT(SUCCEEDED(hr));
    hr = m_consumer->XyGetInt(DirectVobSubXyOptions::INT_MAX_BITMAP_COUNT2, &m_max_bitmap_count2);
    ASSERT(SUCCEEDED(hr));
    hr = m_consumer->XyGetBool(DirectVobSubXyOptions::BOOL_SUB_FRAME_USE_DST_ALPHA, &use_dst_alpha);
    hr = m_consumer->XyGetBool(DirectVobSubXyOptions::BOOL_RENDER_TO_ORIGINAL_VIDEO_SIZE, &render_to_original_video_size);

    if (render_to_original_video_size)
    {
        output_rect = CRect(CPoint(), original_video_size);
        subtitle_target_rect = output_rect;
    }

    m_render_to_original_video_size = render_to_original_video_size;

    bool should_invalidate = false;
    bool should_invalidate_allocator = false;
    if (m_original_video_size!=original_video_size
        || m_use_dst_alpha!=use_dst_alpha
        || m_output_rect!=output_rect
        || m_subtitle_target_rect!=subtitle_target_rect)
    {
        should_invalidate = true;
        should_invalidate_allocator = (m_subtitle_target_rect!=subtitle_target_rect)==TRUE;

        m_original_video_size  = original_video_size;
        m_use_dst_alpha        = use_dst_alpha;
        m_output_rect          = output_rect;
        m_subtitle_target_rect = subtitle_target_rect;
    }

    if (m_xy_sub_render_frame)
    {
        int count = 0;
        hr = m_xy_sub_render_frame->GetBitmapCount(&count);
        should_invalidate = (count>m_max_bitmap_count2);
    }
    if (should_invalidate)
    {
        XY_LOG_INFO("Output rects or max_bitmap_count or alpha type changed.");
        Invalidate();
    }
    if (should_invalidate_allocator)
    {
        CSize max_size(m_subtitle_target_rect.right, m_subtitle_target_rect.bottom);

        m_allocator = DEBUG_NEW CPooledSubPicAllocator(MSP_RGB32, max_size,2);
        ASSERT(m_allocator);

        m_allocator->SetCurSize(max_size);
        m_allocator->SetCurVidRect(CRect(CPoint(0,0),max_size));
    }

    POSITION pos = m_provider->GetStartPosition(now, fps);
    if (!pos)
    {
        XY_LOG_TRACE("No subtitles at "<<XY_LOG_VAR_2_STR(now));
        return S_FALSE;
    }
    REFERENCE_TIME start = m_provider->GetStart(pos, fps);
    REFERENCE_TIME stop = m_provider->GetStop(pos, fps); //fixme: have to get start stop twice
    if (!(start <= now && now < stop))
    {
        XY_LOG_TRACE("No subtitles at "<<XY_LOG_VAR_2_STR(now));
        return S_FALSE;
    }

    hr = Render( now, pos );
    if (FAILED(hr))
    {
        return hr;
    }
    if (m_xy_sub_render_frame)
    {
        *subRenderFrame = m_xy_sub_render_frame;
        (*subRenderFrame)->AddRef();
    }
    return hr;
}
HRESULT XySubRenderProviderWrapper::Render( REFERENCE_TIME now, POSITION pos, double fps )
{
    if(m_pSubPic && m_pSubPic->GetStart() <= now && now < m_pSubPic->GetStop())
    {
        return S_OK;
    }
    HRESULT hr = E_FAIL;

    //should always re-alloc one for the old be in used by the consumer
    m_pSubPic = NULL;
    ASSERT(m_allocator);
    if(FAILED(m_allocator->AllocDynamicEx(&m_pSubPic))) {
        XY_LOG_ERROR("Failed to allocate subpic");
        return E_FAIL;
    }
    ASSERT(m_pSubPic);

    if(FAILED(m_provider->Lock())) {
        return hr;
    }

    CMemSubPic * mem_subpic = dynamic_cast<CMemSubPic*>((ISubPicEx *)m_pSubPic);
    ASSERT(mem_subpic);
    SubPicDesc spd;
    if(SUCCEEDED(m_pSubPic->Lock(spd)))
    {
        CAtlList<CRect> rectList;
        DWORD color = 0xFF000000;
        if(SUCCEEDED(m_pSubPic->ClearDirtyRect(color)))
        {
            hr = m_provider->RenderEx(spd, now, fps, rectList);

            if (!m_provider->IsAnimated(pos))
            {
                REFERENCE_TIME start = m_provider->GetStart(pos, fps);
                REFERENCE_TIME stop = m_provider->GetStop(pos, fps);
                XY_LOG_TRACE(XY_LOG_VAR_2_STR(start)<<XY_LOG_VAR_2_STR(stop));
                m_pSubPic->SetStart(start);
                m_pSubPic->SetStop(stop);
            }
            else
            {
                m_pSubPic->SetStart(now);
                m_pSubPic->SetStop(now+1);
            }
        }
        else
        {
            rectList.AddHead(CRect(CPoint(0,0),m_original_video_size));
            XY_LOG_ERROR("Failed to clear subpic!");
        }
        hr = m_pSubPic->UnlockEx(&rectList);
        ASSERT(SUCCEEDED(hr));
        if (FAILED(hr))
        {
            XY_LOG_ERROR("Failed to unlock subpic. "<<XY_LOG_VAR_2_STR(hr));
        }
        CRect dirty_rect;
        hr = m_pSubPic->GetDirtyRect(&dirty_rect);
        ASSERT(SUCCEEDED(hr));
        if (!dirty_rect.IsRectEmpty())
        {
            if (!m_use_dst_alpha)
            {
                hr = mem_subpic->FlipAlphaValue(dirty_rect);//fixme: mem_subpic.type is now MSP_RGBA_F, not MSP_RGBA
                ASSERT(SUCCEEDED(hr));
                if (FAILED(hr))
                {
                    XY_LOG_ERROR("Failed. "<<XY_LOG_VAR_2_STR(hr));
                    return hr;
                }
            }
        }
        else
        {
            hr = S_FALSE;
        }
    }

    m_provider->Unlock();
    if (hr == S_OK)
    {
        CRect video_rect(CPoint(0,0), m_original_video_size);
        m_xy_sub_render_frame = DEBUG_NEW XySubRenderFrameWrapper(mem_subpic, video_rect, video_rect, now, &hr);
    }
    else
    {
        m_xy_sub_render_frame = NULL;
    }
    return hr;
}
STDMETHODIMP HdmvSubtitleProviderImpl::RequestFrame( IXySubRenderFrame**subRenderFrame, REFERENCE_TIME now )
{
    CheckPointer(subRenderFrame, E_POINTER);
    *subRenderFrame = NULL;

    HRESULT hr = NOERROR;

    POSITION pos;
    CSize MaxTextureSize, VideoSize;
    CPoint VideoTopLeft;

    pos = m_pSub->GetStartPosition(now);

    if (!pos)
    {
        return S_FALSE;
    }

    bool use_dst_alpha = false;
    hr = m_consumer->XyGetBool(DirectVobSubXyOptions::BOOL_SUB_FRAME_USE_DST_ALPHA, &use_dst_alpha);
    if (m_use_dst_alpha!=use_dst_alpha)
    {
        XY_LOG_INFO("Alpha type changed from "<<m_use_dst_alpha<<" to "<<use_dst_alpha);
        Invalidate(-1);
        m_use_dst_alpha = use_dst_alpha;
    }

    hr = m_pSub->GetTextureSize(pos, MaxTextureSize, VideoSize, VideoTopLeft);
    if (SUCCEEDED(hr))
    {
        ASSERT(MaxTextureSize==VideoSize && VideoTopLeft==CPoint(0,0));
        if (!(MaxTextureSize==VideoSize && VideoTopLeft==CPoint(0,0)))
        {
            XY_LOG_ERROR("We don't know how to deal with this sizes."
                <<XY_LOG_VAR_2_STR(MaxTextureSize)<<XY_LOG_VAR_2_STR(VideoSize)
                <<XY_LOG_VAR_2_STR(VideoTopLeft));
            return E_FAIL;
        }
    }
    else
    {
        XY_LOG_ERROR("Failed to get sizes info");
        return hr;
    }
    if (!m_allocator || m_cur_output_size!=MaxTextureSize)
    {
        m_cur_output_size = MaxTextureSize;
        if (m_cur_output_size.cx!=0 && m_cur_output_size.cy!=0)
        {
            hr = ResetAllocator();
            ASSERT(SUCCEEDED(hr));
        }
        else
        {
            XY_LOG_WARN("Invalid output size "<<m_cur_output_size);
            return S_FALSE;
        }
    }

    hr = Render( now, pos );
    if (SUCCEEDED(hr) && m_xy_sub_render_frame)
    {
        *subRenderFrame = m_xy_sub_render_frame;
        (*subRenderFrame)->AddRef();
    }

    return hr;
}
HRESULT HdmvSubtitleProviderImpl::Render( REFERENCE_TIME now, POSITION pos )
{
    REFERENCE_TIME start = m_pSub->GetStart(pos);
    REFERENCE_TIME stop = m_pSub->GetStop(pos);

    if (!(start <= now && now < stop))
    {
        return S_FALSE;
    }

    if(m_pSubPic && m_pSubPic->GetStart() <= now && now < m_pSubPic->GetStop())
    {
        return S_OK;
    }

    //should always re-alloc one for the old be in used by the consumer
    m_pSubPic = NULL;
    ASSERT(m_allocator);
    if(FAILED(m_allocator->AllocDynamicEx(&m_pSubPic))) {
        XY_LOG_ERROR("Failed to allocate subpic");
        return E_FAIL;
    }

    ASSERT(m_pSubPic);

    HRESULT hr = E_FAIL;

    CMemSubPic * mem_subpic = dynamic_cast<CMemSubPic*>((ISubPicEx *)m_pSubPic);
    ASSERT(mem_subpic);
    SubPicDesc spd;
    if(SUCCEEDED(m_pSubPic->Lock(spd)))
    {
        CRect dirty_rect;
        DWORD color = 0xFF000000;
        if(SUCCEEDED(m_pSubPic->ClearDirtyRect(color)))
        {
            m_pSub->Render(spd, now, dirty_rect);

            TRACE_SUB_PROVIDER(XY_LOG_VAR_2_STR(start)<<XY_LOG_VAR_2_STR(stop));

            m_pSubPic->SetStart(start);
            m_pSubPic->SetStop(stop);
        }
        hr = m_pSubPic->Unlock(&dirty_rect);
        ASSERT(SUCCEEDED(hr));
        if (FAILED(hr))
        {
            XY_LOG_ERROR("Failed to unlock subtitle."
                <<XY_LOG_VAR_2_STR(hr)<<XY_LOG_VAR_2_STR(dirty_rect));
        }
        if (!dirty_rect.IsRectEmpty())
        {
            hr = m_pSubPic->GetDirtyRect(&dirty_rect);
            ASSERT(SUCCEEDED(hr));
            if (!m_use_dst_alpha)
            {
                hr = mem_subpic->FlipAlphaValue(dirty_rect);//fixme: mem_subpic.type is now MSP_RGBA_F, not MSP_RGBA
                ASSERT(SUCCEEDED(hr));
                if (FAILED(hr))
                {
                    XY_LOG_ERROR("Failed. "<<XY_LOG_VAR_2_STR(hr));
                    return hr;
                }
            }
            hr = S_OK;
        }
        else
        {
            hr = S_FALSE;
        }
    }
    if (hr == S_OK)
    {
        CRect video_rect(CPoint(0,0), m_cur_output_size);
        m_xy_sub_render_frame = DEBUG_NEW XySubRenderFrameWrapper(mem_subpic, video_rect, video_rect, now, &hr);
    }
    else
    {
        m_xy_sub_render_frame = NULL;
    }
    return hr;
}