Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

grap image and font failed? #26

Open
w136111526 opened this issue Nov 12, 2020 · 3 comments
Open

grap image and font failed? #26

w136111526 opened this issue Nov 12, 2020 · 3 comments

Comments

@w136111526
Copy link

Hello, I use your player to play the video and display text, before the call of the Present window, like to grab a composite image, why not grab it, how can I modify my code:

RECT srcRect = { 0, 0, m_sourceSize.cx, m_sourceSize.cy };
CRect screenPosition = GetScreenPosition();
CRect target(POINT{}, screenPosition.Size());

#ifdef 0
const auto blt = GetVideoProcessBltParams(
target,
m_ProcAmpValues,
m_NFilterValues,
m_DFilterValues);
const auto sample = GetVideoSample(m_sourceSize, target, m_pMainStream);

hr = m_pDXVAVPD->VideoProcessBlt(m_pD3DRT,
    &blt,
    &sample,
    SUB_STREAM_COUNT + 1,
    NULL);
if (FAILED(hr))
{
    TRACE("VideoProcessBlt failed with error 0x%x.\n", hr);
}

#else
m_pD3DD9->Clear(
0,
NULL,
D3DCLEAR_TARGET,
D3DCOLOR_XRGB(0, 0, 0),
1.0f,
0);

hr = m_pD3DD9->StretchRect(
    m_pMainStream,
    &srcRect,
    m_pD3DRT,
    &target,
    D3DTEXF_NONE);
if (FAILED(hr))
{
    TRACE("StretchRect failed with error 0x%x.\n", hr);
}

#endif

std::string subtitle = "这个一个测试文字";
if (!subtitle.empty())
{
	RECT srcRect = { 0, 0, m_sourceSize.cx, m_sourceSize.cy };
	CRect screenPosition = GetScreenPosition();
	CRect target(POINT{}, screenPosition.Size());

	//const auto& convertedSubtitle = CA2T(subtitle.c_str(), CP_UTF8);
	HRESULT hr = m_pD3DD9->BeginScene();
	if (SUCCEEDED(hr))
	{
		DrawSubtitleText(m_pD3DD9, target.Width(), target.Height(),
			CA2W(subtitle.c_str(), GetDocument()->isUnicodeSubtitles() ? CP_UTF8 : CP_ACP));

		m_pD3DD9->EndScene();
	}
}
//grab dest image
{
	IDirect3DSurface9 *pBackBuffer;

	HRESULT hr = m_pD3DD9->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer);
	D3DSURFACE_DESC desc;
	D3DLOCKED_RECT lr;
	pBackBuffer->GetDesc(&desc);
	pBackBuffer->LockRect(&lr, NULL, D3DLOCK_NOSYSLOCK);
	int width = desc.Width;
	int height = desc.Height;
	int nPitch = lr.Pitch;
	unsigned char* data = (unsigned char*)lr.pBits;
	pBackBuffer->UnlockRect();

	if (SUCCEEDED(hr))
		pBackBuffer->Release();
}

hr = m_pD3DD9->Present(&target, &screenPosition, GetSafeHwnd(), NULL);
if (FAILED(hr))
{
    TRACE("Present failed with error 0x%x.\n", hr);
}
@aliakseis
Copy link
Owner

Hi,
The combination of https://gist.github.com/karlgluck/8467971 and https://www.programmersought.com/article/15961657580/ worked for me:

void SaveFrameToJpg(AVFrame *frame, const char* fname)
{
    AVFormatContext *ofmtCtx = NULL;
    AVCodec *codec = NULL;
    AVCodecContext *codecCtx = NULL;
    AVStream *stream = NULL;
    int ret;
 
    /* allocate the output media context */
    avformat_alloc_output_context2(&ofmtCtx, NULL, NULL, fname);
    if (!ofmtCtx) {
        return;
    }
 
    codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG);
    if (!codec) {
        return;
    }
 
    stream = avformat_new_stream(ofmtCtx, NULL);
    if (!stream) {
        return;
    }
 
    codecCtx = avcodec_alloc_context3(codec);
    if (!codecCtx) {
        return;
    }
 
    codecCtx->pix_fmt = AV_PIX_FMT_YUVJ420P;
    codecCtx->bit_rate = 400000;
    codecCtx->width = frame->width;
    codecCtx->height = frame->height;
    codecCtx->time_base.num = 1;
    codecCtx->time_base.den = 25;
 
    /* open the codec */
    ret = avcodec_open2(codecCtx, codec, NULL);
    if (ret < 0) {
        return;
    }
 
    /* open the output file, if needed */
    ret = avio_open(&ofmtCtx->pb, "aa.jpg", AVIO_FLAG_WRITE);
    if (ret < 0) {
        return;
    }
 
    /* Write the stream header, if any. */
    ret = avformat_write_header(ofmtCtx, NULL);
    if (ret < 0) {
        return;
    }
 
    AVPacket avpkt = { 0 };
    int got_packet = 0;
 
    av_init_packet(&avpkt);
 
    /* encode the image */
    ret = avcodec_send_frame(codecCtx, frame);
    if (ret < 0) {
        return;
    }
 
    ret = avcodec_receive_packet(codecCtx, &avpkt);
    if (ret < 0) {
        return;
    }
 
    av_write_frame(ofmtCtx, &avpkt);
 
    /* Write the trailer, if any. The trailer must be written before you
    * close the CodecContexts open when you wrote the header; otherwise
    * av_write_trailer() may try to use memory that was freed on
    * av_codec_close(). */
    av_write_trailer(ofmtCtx);
 
    /* Close the output file. */
    avio_closep(&ofmtCtx->pb);
 
    avcodec_free_context(&codecCtx);
 
    /* free the stream */
    avformat_free_context(ofmtCtx);
}
    //grab dest image
    {
        // https://gist.github.com/karlgluck/8467971
        // Get the buffer's description and make an offscreen surface in system memory.
        // We need to do this because the backbuffer is in video memory and can't be locked
        // unless the device was created with a special flag (D3DPRESENTFLAG_LOCKABLE_BACKBUFFER).
        // Unfortunately, a video-memory buffer CAN be locked with LockRect.  The effect is
        // that it crashes your app when you try to read or write to it.
        D3DLOCKED_RECT d3dlr;
        D3DSURFACE_DESC desc;
        CComPtr<IDirect3DSurface9> offscreen_surface;
        m_pD3DRT->GetDesc(&desc); // backbuffer
        m_pD3DD9->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format,
            D3DPOOL_SYSTEMMEM, &offscreen_surface, NULL);

        // Copy from video memory to system memory
        m_pD3DD9->GetRenderTargetData(m_pD3DRT, offscreen_surface);

        D3DLOCKED_RECT lr;
        ZeroMemory(&lr, sizeof(D3DLOCKED_RECT));
        hr = offscreen_surface->LockRect(&lr, 0, D3DLOCK_READONLY);
        if (FAILED(hr))
        {
            //printf("Cannot lock rect!");
        }

        if (lr.pBits)
        {
            uint8_t *dst_data[4] = { 0 };
            int dst_linesize[4];
            uint8_t *src_data[4] = { 0 };
            int src_linesize[4];
            struct SwsContext *sws_ctx = NULL;
            AVFrame *frame = NULL;
            int ret;

            sws_ctx = sws_getContext(target.Width(), target.Height(), AV_PIX_FMT_BGRA,
                target.Width(), target.Height(), AV_PIX_FMT_YUV420P,
                SWS_BILINEAR, NULL, NULL, NULL);

            if ((ret = av_image_alloc(dst_data, dst_linesize,
                target.Width(), target.Height(), AV_PIX_FMT_YUV420P, 1)) < 0)
            {
                //fprintf(stderr, "Could not allocate destination image\n");
                //return E_FAIL;
            }

            frame = av_frame_alloc();

            frame->format = AV_PIX_FMT_YUVJ420P;
            frame->width = target.Width();
            frame->height = target.Height();

            src_data[0] = (uint8_t*)lr.pBits;
            src_linesize[0] = lr.Pitch;

            sws_scale(sws_ctx, src_data,
                src_linesize, 0, target.Height(), dst_data, dst_linesize);

            frame->data[0] = dst_data[0];
            frame->data[1] = dst_data[1];
            frame->data[2] = dst_data[2];
            frame->linesize[0] = dst_linesize[0];
            frame->linesize[1] = dst_linesize[1];
            frame->linesize[2] = dst_linesize[2];

            SaveFrameToJpg(frame, "/temp/frame.jpg");

            av_freep(&dst_data[0]);
            av_frame_free(&frame);
            sws_freeContext(sws_ctx);
        }

        hr = offscreen_surface->UnlockRect();
        if (FAILED(hr))
        {
            //printf("Cannot unlock rect!");
        }

    }

@w136111526
Copy link
Author

Thank you very much, but there is one small problem. My input source is an image of 1920 * 1080, but the target client is not this size. Can you grab the original 1080p image。

@aliakseis
Copy link
Owner

In this case, I would rather generate a bitmap with the frame image from m_pMainStream, then draw text etc. on that bitmap with the help of Gdiplus::Graphics. There is an example of Gdiplus::Graphics usage with bitmaps in DrawSubtitleText...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants