Add Microsoft DirectDraw screencast producer
This commit is contained in:
parent
2ec0624c6b
commit
79ff1fe75d
|
@ -0,0 +1,36 @@
|
||||||
|
/* Copyright (C) 2015 Mamadou DIOP.
|
||||||
|
* Copyright (C) 2015 Doubango Telecom.
|
||||||
|
*
|
||||||
|
* This file is part of Open Source Doubango Framework.
|
||||||
|
*
|
||||||
|
* DOUBANGO is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* DOUBANGO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with DOUBANGO.
|
||||||
|
*/
|
||||||
|
#ifndef TINYDAV_PRODUCER_SCREENCAST_D3D9_H
|
||||||
|
#define TINYDAV_PRODUCER_SCREENCAST_D3D9_H
|
||||||
|
|
||||||
|
#include "tinydav_config.h"
|
||||||
|
|
||||||
|
#if TDAV_UNDER_WINDOWS && !TDAV_UNDER_WINDOWS_RT
|
||||||
|
|
||||||
|
#include "tinymedia/tmedia_producer.h"
|
||||||
|
|
||||||
|
TDAV_BEGIN_DECLS
|
||||||
|
|
||||||
|
TINYDAV_GEXTERN const tmedia_producer_plugin_def_t *tdav_producer_screencast_d3d9_plugin_def_t;
|
||||||
|
|
||||||
|
TDAV_END_DECLS
|
||||||
|
|
||||||
|
#endif /* TDAV_UNDER_WINDOWS && !TDAV_UNDER_WINDOWS_RT */
|
||||||
|
|
||||||
|
#endif /* TINYDAV_PRODUCER_SCREENCAST_D3D9_H */
|
|
@ -0,0 +1,37 @@
|
||||||
|
/* Copyright (C) 2015 Mamadou DIOP.
|
||||||
|
* Copyright (C) 2015 Doubango Telecom.
|
||||||
|
*
|
||||||
|
* This file is part of Open Source Doubango Framework.
|
||||||
|
*
|
||||||
|
* DOUBANGO is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* DOUBANGO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with DOUBANGO.
|
||||||
|
*/
|
||||||
|
#ifndef TINYDAV_PRODUCER_SCREENCAST_DDRAW_H
|
||||||
|
#define TINYDAV_PRODUCER_SCREENCAST_DDRAW_H
|
||||||
|
|
||||||
|
#include "tinydav_config.h"
|
||||||
|
|
||||||
|
#if TDAV_UNDER_WINDOWS && !TDAV_UNDER_WINDOWS_RT
|
||||||
|
|
||||||
|
#include "tinymedia/tmedia_producer.h"
|
||||||
|
|
||||||
|
TDAV_BEGIN_DECLS
|
||||||
|
|
||||||
|
tsk_bool_t tdav_producer_screencast_ddraw_plugin_is_supported();
|
||||||
|
TINYDAV_GEXTERN const tmedia_producer_plugin_def_t *tdav_producer_screencast_ddraw_plugin_def_t;
|
||||||
|
|
||||||
|
TDAV_END_DECLS
|
||||||
|
|
||||||
|
#endif /* TDAV_UNDER_WINDOWS && !TDAV_UNDER_WINDOWS_RT */
|
||||||
|
|
||||||
|
#endif /* TINYDAV_PRODUCER_SCREENCAST_DDRAW_H */
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright (C) 2014 Mamadou DIOP.
|
/* Copyright (C) 2014-2015 Mamadou DIOP.
|
||||||
*
|
*
|
||||||
* This file is part of Open Source Doubango Framework.
|
* This file is part of Open Source Doubango Framework.
|
||||||
*
|
*
|
||||||
|
|
|
@ -114,6 +114,7 @@ static const tsk_size_t __codec_plugins_all_count = sizeof(__codec_plugins_all)/
|
||||||
#include "tinydav/audio/waveapi/tdav_producer_waveapi.h"
|
#include "tinydav/audio/waveapi/tdav_producer_waveapi.h"
|
||||||
#include "tinydav/audio/directsound/tdav_producer_dsound.h"
|
#include "tinydav/audio/directsound/tdav_producer_dsound.h"
|
||||||
#include "tinydav/video/gdi/tdav_producer_screencast_gdi.h"
|
#include "tinydav/video/gdi/tdav_producer_screencast_gdi.h"
|
||||||
|
#include "tinydav/video/directx/tdav_producer_screencast_ddraw.h"
|
||||||
#include "tinydav/video/v4linux/tdav_producer_video_v4l2.h"
|
#include "tinydav/video/v4linux/tdav_producer_video_v4l2.h"
|
||||||
#include "tinydav/audio/coreaudio/tdav_producer_audioqueue.h"
|
#include "tinydav/audio/coreaudio/tdav_producer_audioqueue.h"
|
||||||
#include "tinydav/audio/coreaudio/tdav_producer_audiounit.h"
|
#include "tinydav/audio/coreaudio/tdav_producer_audiounit.h"
|
||||||
|
@ -411,6 +412,11 @@ int tdav_init()
|
||||||
#elif HAVE_WASAPI // WASAPI
|
#elif HAVE_WASAPI // WASAPI
|
||||||
tmedia_producer_plugin_register(tdav_producer_wasapi_plugin_def_t);
|
tmedia_producer_plugin_register(tdav_producer_wasapi_plugin_def_t);
|
||||||
#endif
|
#endif
|
||||||
|
#if TDAV_UNDER_WINDOWS && !TDAV_UNDER_WINDOWS_RT // Windows DirectDraw (DirectX)
|
||||||
|
if (tdav_producer_screencast_ddraw_plugin_is_supported()) {
|
||||||
|
tmedia_producer_plugin_register(tdav_producer_screencast_ddraw_plugin_def_t);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#if TDAV_UNDER_WINDOWS && !TDAV_UNDER_WINDOWS_RT // Windows GDI
|
#if TDAV_UNDER_WINDOWS && !TDAV_UNDER_WINDOWS_RT // Windows GDI
|
||||||
tmedia_producer_plugin_register(tdav_producer_screencast_gdi_plugin_def_t);
|
tmedia_producer_plugin_register(tdav_producer_screencast_gdi_plugin_def_t);
|
||||||
#endif
|
#endif
|
||||||
|
@ -680,6 +686,9 @@ int tdav_deinit()
|
||||||
#if HAVE_WASAPI // WASAPI
|
#if HAVE_WASAPI // WASAPI
|
||||||
tmedia_producer_plugin_unregister(tdav_producer_wasapi_plugin_def_t);
|
tmedia_producer_plugin_unregister(tdav_producer_wasapi_plugin_def_t);
|
||||||
#endif
|
#endif
|
||||||
|
#if TDAV_UNDER_WINDOWS && !TDAV_UNDER_WINDOWS_RT // Windows DirectDraw (DirectX)
|
||||||
|
tmedia_producer_plugin_unregister(tdav_producer_screencast_ddraw_plugin_def_t);
|
||||||
|
#endif
|
||||||
#if TDAV_UNDER_WINDOWS && !TDAV_UNDER_WINDOWS_RT // Windows GDI
|
#if TDAV_UNDER_WINDOWS && !TDAV_UNDER_WINDOWS_RT // Windows GDI
|
||||||
tmedia_producer_plugin_unregister(tdav_producer_screencast_gdi_plugin_def_t);
|
tmedia_producer_plugin_unregister(tdav_producer_screencast_gdi_plugin_def_t);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,179 @@
|
||||||
|
/* Copyright (C) 2015 Mamadou DIOP.
|
||||||
|
* Copyright (C) 2015 Doubango Telecom.
|
||||||
|
*
|
||||||
|
* This file is part of Open Source Doubango Framework.
|
||||||
|
*
|
||||||
|
* DOUBANGO is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* DOUBANGO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with DOUBANGO.
|
||||||
|
*/
|
||||||
|
#include "tinydav/video/directx/tdav_producer_screencast_d3d9.h"
|
||||||
|
|
||||||
|
#if TDAV_UNDER_WINDOWS && !TDAV_UNDER_WINDOWS_RT
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#if TDAV_UNDER_WINDOWS_CE
|
||||||
|
# include <D3dm.h>
|
||||||
|
#else
|
||||||
|
# include <d3d9.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# if TDAV_UNDER_WINDOWS_CE
|
||||||
|
# pragma comment(lib, "D3dm")
|
||||||
|
# pragma comment(lib, "D3dmguid")
|
||||||
|
# else
|
||||||
|
# pragma comment(lib, "d3d9")
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "tsk_thread.h"
|
||||||
|
#include "tsk_memory.h"
|
||||||
|
#include "tsk_safeobj.h"
|
||||||
|
#include "tsk_timer.h"
|
||||||
|
#include "tsk_time.h"
|
||||||
|
#include "tsk_string.h"
|
||||||
|
#include "tsk_debug.h"
|
||||||
|
|
||||||
|
#define D3D9_DEBUG_INFO(FMT, ...) TSK_DEBUG_INFO("[D3D9 Producer] " FMT, ##__VA_ARGS__)
|
||||||
|
#define D3D9_DEBUG_WARN(FMT, ...) TSK_DEBUG_WARN("[D3D9 Producer] " FMT, ##__VA_ARGS__)
|
||||||
|
#define D3D9_DEBUG_ERROR(FMT, ...) TSK_DEBUG_ERROR("[D3D9 Producer] " FMT, ##__VA_ARGS__)
|
||||||
|
#define D3D9_DEBUG_FATAL(FMT, ...) TSK_DEBUG_FATAL("[D3D9 Producer] " FMT, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
typedef struct tdav_producer_screencast_d3d9_s
|
||||||
|
{
|
||||||
|
TMEDIA_DECLARE_PRODUCER;
|
||||||
|
|
||||||
|
HWND hwnd_preview;
|
||||||
|
HWND hwnd_src;
|
||||||
|
|
||||||
|
tsk_thread_handle_t* tid[1];
|
||||||
|
|
||||||
|
void* p_buff_src; // must use VirtualAlloc()
|
||||||
|
tsk_size_t n_buff_src;
|
||||||
|
void* p_buff_neg; // must use VirtualAlloc()
|
||||||
|
tsk_size_t n_buff_neg;
|
||||||
|
|
||||||
|
tsk_bool_t b_started;
|
||||||
|
tsk_bool_t b_paused;
|
||||||
|
tsk_bool_t b_muted;
|
||||||
|
|
||||||
|
RECT rcScreen;
|
||||||
|
|
||||||
|
TSK_DECLARE_SAFEOBJ;
|
||||||
|
}
|
||||||
|
tdav_producer_screencast_d3d9_t;
|
||||||
|
|
||||||
|
/* ============ Media Producer Interface ================= */
|
||||||
|
static int _tdav_producer_screencast_d3d9_set(tmedia_producer_t *p_self, const tmedia_param_t* pc_param)
|
||||||
|
{
|
||||||
|
D3D9_DEBUG_ERROR("Not implemented");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int _tdav_producer_screencast_d3d9_prepare(tmedia_producer_t* p_self, const tmedia_codec_t* pc_codec)
|
||||||
|
{
|
||||||
|
D3D9_DEBUG_ERROR("Not implemented");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _tdav_producer_screencast_d3d9_start(tmedia_producer_t* p_self)
|
||||||
|
{
|
||||||
|
D3D9_DEBUG_ERROR("Not implemented");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _tdav_producer_screencast_d3d9_pause(tmedia_producer_t* p_self)
|
||||||
|
{
|
||||||
|
D3D9_DEBUG_ERROR("Not implemented");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _tdav_producer_screencast_d3d9_stop(tmedia_producer_t* p_self)
|
||||||
|
{
|
||||||
|
D3D9_DEBUG_ERROR("Not implemented");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// d3d9 screencast producer object definition
|
||||||
|
//
|
||||||
|
/* constructor */
|
||||||
|
static tsk_object_t* _tdav_producer_screencast_d3d9_ctor(tsk_object_t *self, va_list * app)
|
||||||
|
{
|
||||||
|
tdav_producer_screencast_d3d9_t *p_d3d9 = (tdav_producer_screencast_d3d9_t *)self;
|
||||||
|
if (p_d3d9) {
|
||||||
|
/* init base */
|
||||||
|
tmedia_producer_init(TMEDIA_PRODUCER(p_d3d9));
|
||||||
|
TMEDIA_PRODUCER(p_d3d9)->video.chroma = tmedia_chroma_bgr24; // RGB24 on x86 (little endians) stored as BGR24
|
||||||
|
/* init self with default values*/
|
||||||
|
TMEDIA_PRODUCER(p_d3d9)->video.fps = 15;
|
||||||
|
TMEDIA_PRODUCER(p_d3d9)->video.width = 352;
|
||||||
|
TMEDIA_PRODUCER(p_d3d9)->video.height = 288;
|
||||||
|
|
||||||
|
tsk_safeobj_init(p_d3d9);
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
/* destructor */
|
||||||
|
static tsk_object_t* _tdav_producer_screencast_d3d9_dtor(tsk_object_t * self)
|
||||||
|
{
|
||||||
|
tdav_producer_screencast_d3d9_t *p_d3d9 = (tdav_producer_screencast_d3d9_t *)self;
|
||||||
|
if (p_d3d9) {
|
||||||
|
/* stop */
|
||||||
|
if (p_d3d9->b_started) {
|
||||||
|
_tdav_producer_screencast_d3d9_stop((tmedia_producer_t*)p_d3d9);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* deinit base */
|
||||||
|
tmedia_producer_deinit(TMEDIA_PRODUCER(p_d3d9));
|
||||||
|
/* deinit self */
|
||||||
|
if (p_d3d9->p_buff_neg) {
|
||||||
|
VirtualFree(p_d3d9->p_buff_neg, 0, MEM_RELEASE);
|
||||||
|
p_d3d9->p_buff_neg = NULL;
|
||||||
|
}
|
||||||
|
if (p_d3d9->p_buff_src) {
|
||||||
|
VirtualFree(p_d3d9->p_buff_src, 0, MEM_RELEASE);
|
||||||
|
p_d3d9->p_buff_src = NULL;
|
||||||
|
}
|
||||||
|
tsk_safeobj_deinit(p_d3d9);
|
||||||
|
|
||||||
|
TSK_DEBUG_INFO("*** d3d9 Screencast producer destroyed ***");
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
/* object definition */
|
||||||
|
static const tsk_object_def_t tdav_producer_screencast_d3d9_def_s =
|
||||||
|
{
|
||||||
|
sizeof(tdav_producer_screencast_d3d9_t),
|
||||||
|
_tdav_producer_screencast_d3d9_ctor,
|
||||||
|
_tdav_producer_screencast_d3d9_dtor,
|
||||||
|
tsk_null,
|
||||||
|
};
|
||||||
|
/* plugin definition*/
|
||||||
|
static const tmedia_producer_plugin_def_t tdav_producer_screencast_d3d9_plugin_def_s =
|
||||||
|
{
|
||||||
|
&tdav_producer_screencast_d3d9_def_s,
|
||||||
|
tmedia_bfcp_video,
|
||||||
|
"Microsoft Direct3D screencast producer",
|
||||||
|
|
||||||
|
_tdav_producer_screencast_d3d9_set,
|
||||||
|
_tdav_producer_screencast_d3d9_prepare,
|
||||||
|
_tdav_producer_screencast_d3d9_start,
|
||||||
|
_tdav_producer_screencast_d3d9_pause,
|
||||||
|
_tdav_producer_screencast_d3d9_stop
|
||||||
|
};
|
||||||
|
const tmedia_producer_plugin_def_t *tdav_producer_screencast_d3d9_plugin_def_t = &tdav_producer_screencast_d3d9_plugin_def_s;
|
||||||
|
|
||||||
|
#endif /* TDAV_UNDER_WINDOWS && !TDAV_UNDER_WINDOWS_RT */
|
|
@ -0,0 +1,598 @@
|
||||||
|
/* Copyright (C) 2015 Mamadou DIOP.
|
||||||
|
* Copyright (C) 2015 Doubango Telecom.
|
||||||
|
*
|
||||||
|
* This file is part of Open Source Doubango Framework.
|
||||||
|
*
|
||||||
|
* DOUBANGO is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* DOUBANGO is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with DOUBANGO.
|
||||||
|
*/
|
||||||
|
#include "tinydav/video/directx/tdav_producer_screencast_ddraw.h"
|
||||||
|
|
||||||
|
#if TDAV_UNDER_WINDOWS && !TDAV_UNDER_WINDOWS_RT
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <ddraw.h>
|
||||||
|
|
||||||
|
#include "tsk_thread.h"
|
||||||
|
#include "tsk_memory.h"
|
||||||
|
#include "tsk_safeobj.h"
|
||||||
|
#include "tsk_timer.h"
|
||||||
|
#include "tsk_time.h"
|
||||||
|
#include "tsk_string.h"
|
||||||
|
#include "tsk_debug.h"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# pragma comment(lib, "Ddraw")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(DDRAW_HIGH_PRIO_MEMCPY)
|
||||||
|
# define DDRAW_HIGH_PRIO_MEMCPY 0
|
||||||
|
#endif /* DDRAW_HIGH_PRIO_MEMCPY */
|
||||||
|
|
||||||
|
#if !defined(DDRAW_PREVIEW)
|
||||||
|
# if TDAV_UNDER_WINDOWS_CE && (BUILD_TYPE_GE || SIN_CITY)
|
||||||
|
# define DDRAW_PREVIEW 0 // Do not waste time displaying the preview on "WEC7 + (GE | SINCITY)"
|
||||||
|
# else
|
||||||
|
# define DDRAW_PREVIEW 1
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DDRAW_DEBUG_INFO(FMT, ...) TSK_DEBUG_INFO("[DDRAW Producer] " FMT, ##__VA_ARGS__)
|
||||||
|
#define DDRAW_DEBUG_WARN(FMT, ...) TSK_DEBUG_WARN("[DDRAW Producer] " FMT, ##__VA_ARGS__)
|
||||||
|
#define DDRAW_DEBUG_ERROR(FMT, ...) TSK_DEBUG_ERROR("[DDRAW Producer] " FMT, ##__VA_ARGS__)
|
||||||
|
#define DDRAW_DEBUG_FATAL(FMT, ...) TSK_DEBUG_FATAL("[DDRAW Producer] " FMT, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
#define DDRAW_SAFE_RELEASE(pp) if ((pp) && *(pp)) (*(pp))->Release(), *(pp) = NULL
|
||||||
|
#define DDRAW_CHECK_HR(x) { HRESULT __hr__ = (x); if (FAILED(__hr__)) { DDRAW_DEBUG_ERROR("Operation Failed (%08x)", __hr__); goto bail; } }
|
||||||
|
|
||||||
|
typedef struct tdav_producer_screencast_ddraw_s
|
||||||
|
{
|
||||||
|
TMEDIA_DECLARE_PRODUCER;
|
||||||
|
|
||||||
|
HWND hwnd_preview;
|
||||||
|
HWND hwnd_src;
|
||||||
|
#if DDRAW_PREVIEW
|
||||||
|
BITMAPINFO bi_preview;
|
||||||
|
#endif /* DDRAW_PREVIEW */
|
||||||
|
|
||||||
|
IDirectDraw* p_dd;
|
||||||
|
IDirectDrawSurface* p_surf_primary;
|
||||||
|
|
||||||
|
tsk_thread_handle_t* tid[1];
|
||||||
|
|
||||||
|
void* p_buff_neg; // must use VirtualAlloc()
|
||||||
|
tsk_size_t n_buff_neg;
|
||||||
|
tsk_size_t n_buff_rgb_bitscount;
|
||||||
|
|
||||||
|
tsk_bool_t b_started;
|
||||||
|
tsk_bool_t b_paused;
|
||||||
|
tsk_bool_t b_muted;
|
||||||
|
|
||||||
|
TSK_DECLARE_SAFEOBJ;
|
||||||
|
}
|
||||||
|
tdav_producer_screencast_ddraw_t;
|
||||||
|
|
||||||
|
static tmedia_chroma_t _tdav_producer_screencast_get_chroma(const DDPIXELFORMAT* pixelFormat);
|
||||||
|
static void* TSK_STDCALL _tdav_producer_screencast_record_thread(void *arg);
|
||||||
|
static int _tdav_producer_screencast_grab(tdav_producer_screencast_ddraw_t* p_self);
|
||||||
|
|
||||||
|
// public function used to check that we can use DDRAW plugin before loading it
|
||||||
|
tsk_bool_t tdav_producer_screencast_ddraw_plugin_is_supported()
|
||||||
|
{
|
||||||
|
static tsk_bool_t __checked = tsk_false; // static guard to avoid checking more than once
|
||||||
|
static tsk_bool_t __supported = tsk_false;
|
||||||
|
|
||||||
|
HRESULT hr = DD_OK;
|
||||||
|
DDSURFACEDESC ddsd;
|
||||||
|
DDPIXELFORMAT DDPixelFormat;
|
||||||
|
LPDIRECTDRAWSURFACE lpDDS = NULL;
|
||||||
|
LPDIRECTDRAW lpDD = NULL;
|
||||||
|
|
||||||
|
if (__checked) {
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
|
||||||
|
__checked = tsk_true;
|
||||||
|
|
||||||
|
DDRAW_CHECK_HR(hr = DirectDrawCreate(NULL, &lpDD, NULL));
|
||||||
|
DDRAW_CHECK_HR(hr = lpDD->SetCooperativeLevel(NULL, DDSCL_NORMAL));
|
||||||
|
|
||||||
|
ZeroMemory(&ddsd, sizeof(ddsd));
|
||||||
|
ddsd.dwSize = sizeof(ddsd);
|
||||||
|
ddsd.dwFlags = DDSD_CAPS;
|
||||||
|
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
|
||||||
|
|
||||||
|
DDRAW_CHECK_HR(hr = lpDD->CreateSurface(&ddsd, &lpDDS, NULL));
|
||||||
|
|
||||||
|
ZeroMemory(&DDPixelFormat, sizeof(DDPixelFormat));
|
||||||
|
DDPixelFormat.dwSize = sizeof(DDPixelFormat);
|
||||||
|
DDRAW_CHECK_HR(hr = lpDDS->GetPixelFormat(&DDPixelFormat));
|
||||||
|
DDRAW_DEBUG_INFO("dwRGBBitCount:%d, dwRBitMask:%x, dwGBitMask:%x, dwBBitMask:%x, dwRGBAlphaBitMask:%x",
|
||||||
|
DDPixelFormat.dwRGBBitCount, DDPixelFormat.dwRBitMask, DDPixelFormat.dwGBitMask, DDPixelFormat.dwBBitMask, DDPixelFormat.dwRGBAlphaBitMask);
|
||||||
|
if (_tdav_producer_screencast_get_chroma(&DDPixelFormat) == tmedia_chroma_none) {
|
||||||
|
DDRAW_CHECK_HR(hr = DDERR_INVALIDCAPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
__supported = SUCCEEDED(hr);
|
||||||
|
|
||||||
|
bail:
|
||||||
|
DDRAW_SAFE_RELEASE(&lpDDS);
|
||||||
|
DDRAW_SAFE_RELEASE(&lpDD);
|
||||||
|
return __supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============ Media Producer Interface ================= */
|
||||||
|
static int _tdav_producer_screencast_ddraw_set(tmedia_producer_t *p_self, const tmedia_param_t* pc_param)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
tdav_producer_screencast_ddraw_t* p_ddraw = (tdav_producer_screencast_ddraw_t*)p_self;
|
||||||
|
|
||||||
|
if (!p_ddraw || !pc_param) {
|
||||||
|
DDRAW_DEBUG_ERROR("Invalid parameter");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pc_param->value_type == tmedia_pvt_int64) {
|
||||||
|
if (tsk_striequals(pc_param->key, "local-hwnd") || tsk_striequals(pc_param->key, "preview-hwnd")) {
|
||||||
|
p_ddraw->hwnd_preview = (HWND)*((int64_t*)pc_param->value);
|
||||||
|
}
|
||||||
|
else if (tsk_striequals(pc_param->key, "src-hwnd")) {
|
||||||
|
p_ddraw->hwnd_src = (HWND)*((int64_t*)pc_param->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pc_param->value_type == tmedia_pvt_int32) {
|
||||||
|
if (tsk_striequals(pc_param->key, "mute")) {
|
||||||
|
p_ddraw->b_muted = (TSK_TO_INT32((uint8_t*)pc_param->value) != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int _tdav_producer_screencast_ddraw_prepare(tmedia_producer_t* p_self, const tmedia_codec_t* pc_codec)
|
||||||
|
{
|
||||||
|
tdav_producer_screencast_ddraw_t* p_ddraw = (tdav_producer_screencast_ddraw_t*)p_self;
|
||||||
|
int ret = 0;
|
||||||
|
HRESULT hr = DD_OK;
|
||||||
|
tsk_size_t n_buff_neg_new;
|
||||||
|
#if 0
|
||||||
|
DDPIXELFORMAT DDPixelFormat;
|
||||||
|
#endif
|
||||||
|
DDSURFACEDESC ddsd;
|
||||||
|
|
||||||
|
if (!p_ddraw || !pc_codec) {
|
||||||
|
DDRAW_DEBUG_ERROR("Invalid parameter");
|
||||||
|
DDRAW_CHECK_HR(hr = E_INVALIDARG);
|
||||||
|
}
|
||||||
|
|
||||||
|
tsk_safeobj_lock(p_ddraw);
|
||||||
|
|
||||||
|
// check support for DirectDraw again
|
||||||
|
if (!tdav_producer_screencast_ddraw_plugin_is_supported()) {
|
||||||
|
DDRAW_CHECK_HR(hr = E_FAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
TMEDIA_PRODUCER(p_ddraw)->video.fps = TMEDIA_CODEC_VIDEO(pc_codec)->out.fps;
|
||||||
|
TMEDIA_PRODUCER(p_ddraw)->video.width = TMEDIA_CODEC_VIDEO(pc_codec)->out.width;
|
||||||
|
TMEDIA_PRODUCER(p_ddraw)->video.height = TMEDIA_CODEC_VIDEO(pc_codec)->out.height;
|
||||||
|
|
||||||
|
// Hack the codec to avoid flipping
|
||||||
|
TMEDIA_CODEC_VIDEO(pc_codec)->out.flip = tsk_false;
|
||||||
|
|
||||||
|
DDRAW_DEBUG_INFO("Prepare with fps:%d, width:%d; height:%d", TMEDIA_PRODUCER(p_ddraw)->video.fps, TMEDIA_PRODUCER(p_ddraw)->video.width, TMEDIA_PRODUCER(p_ddraw)->video.height);
|
||||||
|
|
||||||
|
if (!p_ddraw->p_dd) {
|
||||||
|
DDRAW_CHECK_HR(hr = DirectDrawCreate(NULL, &p_ddraw->p_dd, NULL));
|
||||||
|
}
|
||||||
|
DDRAW_CHECK_HR(hr = p_ddraw->p_dd->SetCooperativeLevel(NULL, DDSCL_NORMAL));
|
||||||
|
|
||||||
|
if (!p_ddraw->p_surf_primary) {
|
||||||
|
ZeroMemory(&ddsd, sizeof(ddsd));
|
||||||
|
ddsd.dwSize = sizeof(ddsd);
|
||||||
|
ddsd.dwFlags = DDSD_CAPS;
|
||||||
|
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
|
||||||
|
|
||||||
|
DDRAW_CHECK_HR(hr = p_ddraw->p_dd->CreateSurface(&ddsd, &p_ddraw->p_surf_primary, NULL));
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
ZeroMemory(&DDPixelFormat, sizeof(DDPixelFormat));
|
||||||
|
DDPixelFormat.dwSize = sizeof(DDPixelFormat);
|
||||||
|
DDRAW_CHECK_HR(hr = DDRAW_VTBL(p_ddraw->p_surf_primary)->GetPixelFormat(p_ddraw->p_surf_primary, &DDPixelFormat));
|
||||||
|
DDRAW_DEBUG_INFO("dwRGBBitCount:%d, dwRBitMask:%x, dwGBitMask:%x, dwBBitMask:%x, dwRGBAlphaBitMask:%x",
|
||||||
|
DDPixelFormat.dwRGBBitCount, DDPixelFormat.dwRBitMask, DDPixelFormat.dwGBitMask, DDPixelFormat.dwBBitMask, DDPixelFormat.dwRGBAlphaBitMask);
|
||||||
|
if ((TMEDIA_PRODUCER(p_ddraw)->video.chroma = _tdav_producer_screencast_get_chroma(&DDPixelFormat)) == tmedia_chroma_none) {
|
||||||
|
DDRAW_CHECK_HR(hr = DDERR_INVALIDCAPS);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ZeroMemory(&ddsd, sizeof(ddsd));
|
||||||
|
ddsd.dwSize = sizeof(ddsd);
|
||||||
|
ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_PITCH | DDSD_PIXELFORMAT;
|
||||||
|
DDRAW_CHECK_HR(hr = p_ddraw->p_surf_primary->GetSurfaceDesc(&ddsd));
|
||||||
|
DDRAW_DEBUG_INFO("Prepare with neg. width:%d, height:%d, pitch=%ld", ddsd.dwWidth, ddsd.dwHeight, ddsd.lPitch);
|
||||||
|
TMEDIA_PRODUCER(p_ddraw)->video.width = ddsd.dwWidth;
|
||||||
|
TMEDIA_PRODUCER(p_ddraw)->video.height = ddsd.dwHeight;
|
||||||
|
p_ddraw->n_buff_rgb_bitscount = ddsd.ddpfPixelFormat.dwRGBBitCount;
|
||||||
|
DDRAW_DEBUG_INFO("Prepare with dwRGBBitCount:%d, dwRBitMask:%x, dwGBitMask:%x, dwBBitMask:%x, dwRGBAlphaBitMask:%x",
|
||||||
|
ddsd.ddpfPixelFormat.dwRGBBitCount, ddsd.ddpfPixelFormat.dwRBitMask, ddsd.ddpfPixelFormat.dwGBitMask, ddsd.ddpfPixelFormat.dwBBitMask, ddsd.ddpfPixelFormat.dwRGBAlphaBitMask);
|
||||||
|
if ((TMEDIA_PRODUCER(p_ddraw)->video.chroma = _tdav_producer_screencast_get_chroma(&ddsd.ddpfPixelFormat)) == tmedia_chroma_none) {
|
||||||
|
DDRAW_CHECK_HR(hr = DDERR_INVALIDCAPS);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
n_buff_neg_new = (ddsd.dwWidth * ddsd.dwHeight * (ddsd.ddpfPixelFormat.dwRGBBitCount >> 3));
|
||||||
|
if (p_ddraw->n_buff_neg < n_buff_neg_new) {
|
||||||
|
if (p_ddraw->p_buff_neg) VirtualFree(p_ddraw->p_buff_neg, 0, MEM_RELEASE);
|
||||||
|
if (!(p_ddraw->p_buff_neg = VirtualAlloc(NULL, n_buff_neg_new, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE))) {
|
||||||
|
p_ddraw->n_buff_neg = 0;
|
||||||
|
DDRAW_CHECK_HR(hr = DDERR_OUTOFMEMORY);
|
||||||
|
}
|
||||||
|
p_ddraw->n_buff_neg = n_buff_neg_new;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BitmapInfo for preview
|
||||||
|
#if DDRAW_PREVIEW
|
||||||
|
ZeroMemory(&p_ddraw->bi_preview, sizeof(p_ddraw->bi_preview));
|
||||||
|
p_ddraw->bi_preview.bmiHeader.biSize = (DWORD)sizeof(BITMAPINFOHEADER);
|
||||||
|
p_ddraw->bi_preview.bmiHeader.biCompression = BI_RGB;
|
||||||
|
p_ddraw->bi_preview.bmiHeader.biPlanes = 1;
|
||||||
|
p_ddraw->bi_preview.bmiHeader.biWidth = ddsd.dwWidth;
|
||||||
|
p_ddraw->bi_preview.bmiHeader.biHeight = ddsd.dwHeight;
|
||||||
|
p_ddraw->bi_preview.bmiHeader.biBitCount = (WORD)ddsd.ddpfPixelFormat.dwRGBBitCount;
|
||||||
|
p_ddraw->bi_preview.bmiHeader.biSizeImage = (p_ddraw->bi_preview.bmiHeader.biWidth * p_ddraw->bi_preview.bmiHeader.biHeight * (p_ddraw->bi_preview.bmiHeader.biBitCount >> 3));
|
||||||
|
#endif /* DDRAW_PREVIEW */
|
||||||
|
|
||||||
|
bail:
|
||||||
|
tsk_safeobj_unlock(p_ddraw);
|
||||||
|
return SUCCEEDED(hr) ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _tdav_producer_screencast_ddraw_start(tmedia_producer_t* p_self)
|
||||||
|
{
|
||||||
|
tdav_producer_screencast_ddraw_t* p_ddraw = (tdav_producer_screencast_ddraw_t*)p_self;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!p_ddraw) {
|
||||||
|
DDRAW_DEBUG_ERROR("Invalid parameter");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tsk_safeobj_lock(p_ddraw);
|
||||||
|
|
||||||
|
p_ddraw->b_paused = tsk_false;
|
||||||
|
|
||||||
|
if (p_ddraw->b_started) {
|
||||||
|
DDRAW_DEBUG_INFO("Already started");
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_ddraw->b_started = tsk_true;
|
||||||
|
|
||||||
|
tsk_thread_create(&p_ddraw->tid[0], _tdav_producer_screencast_record_thread, p_ddraw);
|
||||||
|
#if DDRAW_HIGH_PRIO_MEMCPY
|
||||||
|
if (p_ddraw->tid[0]) {
|
||||||
|
tsk_thread_set_priority(p_ddraw->tid[0], TSK_THREAD_PRIORITY_TIME_CRITICAL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bail:
|
||||||
|
if (ret) {
|
||||||
|
p_ddraw->b_started = tsk_false;
|
||||||
|
}
|
||||||
|
tsk_safeobj_unlock(p_ddraw);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _tdav_producer_screencast_ddraw_pause(tmedia_producer_t* p_self)
|
||||||
|
{
|
||||||
|
tdav_producer_screencast_ddraw_t* p_ddraw = (tdav_producer_screencast_ddraw_t*)p_self;
|
||||||
|
|
||||||
|
if (!p_ddraw) {
|
||||||
|
DDRAW_DEBUG_ERROR("Invalid parameter");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tsk_safeobj_lock(p_ddraw);
|
||||||
|
|
||||||
|
p_ddraw->b_paused = tsk_true;
|
||||||
|
goto bail;
|
||||||
|
|
||||||
|
bail:
|
||||||
|
tsk_safeobj_unlock(p_ddraw);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _tdav_producer_screencast_ddraw_stop(tmedia_producer_t* p_self)
|
||||||
|
{
|
||||||
|
tdav_producer_screencast_ddraw_t* p_ddraw = (tdav_producer_screencast_ddraw_t*)p_self;
|
||||||
|
|
||||||
|
if (!p_ddraw) {
|
||||||
|
DDRAW_DEBUG_ERROR("Invalid parameter");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tsk_safeobj_lock(p_ddraw);
|
||||||
|
|
||||||
|
if (!p_ddraw->b_started) {
|
||||||
|
DDRAW_DEBUG_INFO("Already stopped");
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_ddraw->b_started = tsk_false;
|
||||||
|
p_ddraw->b_paused = tsk_false;
|
||||||
|
|
||||||
|
// stop thread
|
||||||
|
if (p_ddraw->tid[0]) {
|
||||||
|
tsk_thread_join(&(p_ddraw->tid[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
bail:
|
||||||
|
tsk_safeobj_unlock(p_ddraw);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _tdav_producer_screencast_grab(tdav_producer_screencast_ddraw_t* p_self)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
DDSURFACEDESC ddsd;
|
||||||
|
DWORD nSizeWithoutPadding, nRowLengthInBytes;
|
||||||
|
tmedia_producer_t* p_base = TMEDIA_PRODUCER(p_self);
|
||||||
|
LPVOID lpBuffToSend;
|
||||||
|
|
||||||
|
if (!p_self) {
|
||||||
|
DDRAW_CHECK_HR(hr = E_INVALIDARG);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!p_self->b_started) {
|
||||||
|
#if defined(E_ILLEGAL_METHOD_CALL)
|
||||||
|
DDRAW_CHECK_HR(hr = E_ILLEGAL_METHOD_CALL);
|
||||||
|
#else
|
||||||
|
DDRAW_CHECK_HR(hr = E_FAIL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_self->p_surf_primary->IsLost() == DDERR_SURFACELOST) {
|
||||||
|
DDRAW_CHECK_HR(hr = p_self->p_surf_primary->Restore());
|
||||||
|
}
|
||||||
|
|
||||||
|
ddsd.dwSize = sizeof(ddsd);
|
||||||
|
ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_PITCH | DDSD_PIXELFORMAT;
|
||||||
|
DDRAW_CHECK_HR(hr = p_self->p_surf_primary->Lock(NULL, &ddsd, DDLOCK_READONLY, NULL));
|
||||||
|
// make sure surface size and number of bits per pixel haven't changed
|
||||||
|
if (TMEDIA_PRODUCER(p_self)->video.width != ddsd.dwWidth || TMEDIA_PRODUCER(p_self)->video.height != ddsd.dwHeight || p_self->n_buff_rgb_bitscount != ddsd.ddpfPixelFormat.dwRGBBitCount) {
|
||||||
|
tsk_size_t n_buff_neg_new;
|
||||||
|
tmedia_chroma_t chroma_new;
|
||||||
|
DDRAW_DEBUG_WARN("surface has changed: width %d<>%d or height %d<>%d or rgb_bits_count %d<>%d",
|
||||||
|
p_base->video.width, ddsd.dwWidth,
|
||||||
|
p_base->video.height, ddsd.dwHeight,
|
||||||
|
p_self->n_buff_rgb_bitscount, ddsd.ddpfPixelFormat.dwRGBBitCount);
|
||||||
|
if ((chroma_new = _tdav_producer_screencast_get_chroma(&ddsd.ddpfPixelFormat)) == tmedia_chroma_none) {
|
||||||
|
DDRAW_CHECK_HR(hr = DDERR_INVALIDCAPS);
|
||||||
|
}
|
||||||
|
n_buff_neg_new = (ddsd.dwWidth * ddsd.dwHeight * (ddsd.ddpfPixelFormat.dwRGBBitCount >> 3));
|
||||||
|
if (p_self->n_buff_neg < n_buff_neg_new) {
|
||||||
|
if (p_self->p_buff_neg) VirtualFree(p_self->p_buff_neg, 0, MEM_RELEASE);
|
||||||
|
if (!(p_self->p_buff_neg = VirtualAlloc(NULL, n_buff_neg_new, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE))) {
|
||||||
|
p_self->n_buff_neg = 0;
|
||||||
|
p_self->p_surf_primary->Unlock(NULL); // unlock before going to bail
|
||||||
|
DDRAW_CHECK_HR(hr = DDERR_OUTOFMEMORY);
|
||||||
|
}
|
||||||
|
p_self->n_buff_neg = n_buff_neg_new;
|
||||||
|
}
|
||||||
|
p_base->video.width = ddsd.dwWidth;
|
||||||
|
p_base->video.height = ddsd.dwHeight;
|
||||||
|
p_base->video.chroma = chroma_new;
|
||||||
|
p_self->n_buff_rgb_bitscount = ddsd.ddpfPixelFormat.dwRGBBitCount;
|
||||||
|
// preview
|
||||||
|
#if DDRAW_PREVIEW
|
||||||
|
p_self->bi_preview.bmiHeader.biWidth = ddsd.dwWidth;
|
||||||
|
p_self->bi_preview.bmiHeader.biHeight = ddsd.dwHeight;
|
||||||
|
p_self->bi_preview.bmiHeader.biBitCount = (WORD)ddsd.ddpfPixelFormat.dwRGBBitCount;
|
||||||
|
p_self->bi_preview.bmiHeader.biSizeImage = (p_self->bi_preview.bmiHeader.biWidth * p_self->bi_preview.bmiHeader.biHeight * (p_self->bi_preview.bmiHeader.biBitCount >> 3));
|
||||||
|
#endif /* DDRAW_PREVIEW */
|
||||||
|
}
|
||||||
|
nRowLengthInBytes = ddsd.dwWidth * (ddsd.ddpfPixelFormat.dwRGBBitCount >> 3);
|
||||||
|
nSizeWithoutPadding = ddsd.dwHeight * nRowLengthInBytes;
|
||||||
|
|
||||||
|
// init lpBuffToSend
|
||||||
|
if (ddsd.lPitch == nRowLengthInBytes) {
|
||||||
|
// no padding
|
||||||
|
lpBuffToSend = ddsd.lpSurface;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// with padding
|
||||||
|
UINT8 *pSurfBuff = (UINT8 *)ddsd.lpSurface, *pNegBuff = (UINT8 *)p_self->p_buff_neg;
|
||||||
|
DWORD y;
|
||||||
|
for (y = 0; y < ddsd.dwHeight; ++y) {
|
||||||
|
CopyMemory(pNegBuff, pSurfBuff, nRowLengthInBytes);
|
||||||
|
pSurfBuff += ddsd.lPitch;
|
||||||
|
pNegBuff += nRowLengthInBytes;
|
||||||
|
}
|
||||||
|
lpBuffToSend = p_self->p_buff_neg;
|
||||||
|
}
|
||||||
|
// display preview
|
||||||
|
#if DDRAW_PREVIEW
|
||||||
|
if (p_self->hwnd_preview) {
|
||||||
|
HWND hWnd; // copy for thread-safeness
|
||||||
|
HDC hDC = GetDC((hWnd = p_self->hwnd_preview));
|
||||||
|
if (hDC) {
|
||||||
|
RECT rcPreview;
|
||||||
|
if (GetWindowRect(hWnd, &rcPreview)) {
|
||||||
|
LONG nPreviewWidth = (rcPreview.right - rcPreview.left);
|
||||||
|
LONG nPreviewHeight = (rcPreview.bottom - rcPreview.top);
|
||||||
|
StretchDIBits(
|
||||||
|
hDC,
|
||||||
|
0, 0, nPreviewWidth, nPreviewHeight,
|
||||||
|
0, 0, p_self->bi_preview.bmiHeader.biWidth, p_self->bi_preview.bmiHeader.biHeight,
|
||||||
|
lpBuffToSend,
|
||||||
|
&p_self->bi_preview,
|
||||||
|
DIB_RGB_COLORS,
|
||||||
|
SRCCOPY);
|
||||||
|
}
|
||||||
|
ReleaseDC(hWnd, hDC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* DDRAW_PREVIEW */
|
||||||
|
// Encode, encrypt and send data
|
||||||
|
p_base->enc_cb.callback(p_base->enc_cb.callback_data, lpBuffToSend, nSizeWithoutPadding);
|
||||||
|
|
||||||
|
DDRAW_CHECK_HR(hr = p_self->p_surf_primary->Unlock(NULL));
|
||||||
|
|
||||||
|
bail:
|
||||||
|
if (hr == DDERR_SURFACELOST) {
|
||||||
|
/*hr = */p_self->p_surf_primary->Restore();
|
||||||
|
hr = S_OK;
|
||||||
|
}
|
||||||
|
return SUCCEEDED(hr) ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static tmedia_chroma_t _tdav_producer_screencast_get_chroma(const DDPIXELFORMAT* pixelFormat)
|
||||||
|
{
|
||||||
|
HRESULT hr = DD_OK;
|
||||||
|
if (pixelFormat->dwFlags != DDPF_RGB) {
|
||||||
|
DDRAW_DEBUG_ERROR("dwFlags(%d) != DDPF_RGB", pixelFormat->dwFlags);
|
||||||
|
DDRAW_CHECK_HR(hr = DDERR_INVALIDCAPS);
|
||||||
|
}
|
||||||
|
switch (pixelFormat->dwRGBBitCount) {
|
||||||
|
case 32: // RGB32
|
||||||
|
case 24: // RGB24
|
||||||
|
// pixels must be aligned for fast copy
|
||||||
|
if (pixelFormat->dwRBitMask != 0xff0000 || pixelFormat->dwGBitMask != 0xff00 || pixelFormat->dwBBitMask != 0xff || pixelFormat->dwRGBAlphaBitMask != 0) {
|
||||||
|
DDRAW_DEBUG_ERROR("Pixels not aligned");
|
||||||
|
}
|
||||||
|
return pixelFormat->dwRGBBitCount == 24 ? tmedia_chroma_bgr24 : tmedia_chroma_rgb32;
|
||||||
|
break;
|
||||||
|
case 16: // RGB565
|
||||||
|
// pixels must be aligned for fast copy
|
||||||
|
if (pixelFormat->dwRBitMask != 0xF800 || pixelFormat->dwGBitMask != 0x7E0 || pixelFormat->dwBBitMask != 0x1F) {
|
||||||
|
DDRAW_DEBUG_ERROR("Pixels not aligned");
|
||||||
|
}
|
||||||
|
return tmedia_chroma_rgb565le;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DDRAW_DEBUG_ERROR("dwRGBBitCount(%d) != 24 and 32", pixelFormat->dwRGBBitCount);
|
||||||
|
DDRAW_CHECK_HR(hr = DDERR_INVALIDCAPS);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bail:
|
||||||
|
return tmedia_chroma_none;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* TSK_STDCALL _tdav_producer_screencast_record_thread(void *arg)
|
||||||
|
{
|
||||||
|
tdav_producer_screencast_ddraw_t* p_ddraw = (tdav_producer_screencast_ddraw_t*)arg;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
// FPS manager
|
||||||
|
uint64_t TimeNow, TimeLastFrame = 0;
|
||||||
|
const uint64_t TimeFrameDuration = (1000 / TMEDIA_PRODUCER(p_ddraw)->video.fps);
|
||||||
|
|
||||||
|
DDRAW_DEBUG_INFO("Recorder thread -- START");
|
||||||
|
|
||||||
|
while (ret == 0 && p_ddraw->b_started) {
|
||||||
|
TimeNow = tsk_time_now();
|
||||||
|
if ((TimeNow - TimeLastFrame) > TimeFrameDuration) {
|
||||||
|
if (!p_ddraw->b_muted && !p_ddraw->b_paused) {
|
||||||
|
if (ret = _tdav_producer_screencast_grab(p_ddraw)) {
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TimeLastFrame = TimeNow;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tsk_thread_sleep(1);
|
||||||
|
#if 0
|
||||||
|
DDRAW_DEBUG_INFO("Skip frame");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
next:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
DDRAW_DEBUG_INFO("Recorder thread -- STOP");
|
||||||
|
return tsk_null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ddraw screencast producer object definition
|
||||||
|
//
|
||||||
|
/* constructor */
|
||||||
|
static tsk_object_t* _tdav_producer_screencast_ddraw_ctor(tsk_object_t *self, va_list * app)
|
||||||
|
{
|
||||||
|
tdav_producer_screencast_ddraw_t *p_ddraw = (tdav_producer_screencast_ddraw_t *)self;
|
||||||
|
if (p_ddraw) {
|
||||||
|
/* init base */
|
||||||
|
tmedia_producer_init(TMEDIA_PRODUCER(p_ddraw));
|
||||||
|
TMEDIA_PRODUCER(p_ddraw)->video.chroma = tmedia_chroma_bgr24; // RGB24 on x86 (little endians) stored as BGR24
|
||||||
|
/* init self with default values*/
|
||||||
|
TMEDIA_PRODUCER(p_ddraw)->video.fps = 15;
|
||||||
|
TMEDIA_PRODUCER(p_ddraw)->video.width = 352;
|
||||||
|
TMEDIA_PRODUCER(p_ddraw)->video.height = 288;
|
||||||
|
|
||||||
|
tsk_safeobj_init(p_ddraw);
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
/* destructor */
|
||||||
|
static tsk_object_t* _tdav_producer_screencast_ddraw_dtor(tsk_object_t * self)
|
||||||
|
{
|
||||||
|
tdav_producer_screencast_ddraw_t *p_ddraw = (tdav_producer_screencast_ddraw_t *)self;
|
||||||
|
if (p_ddraw) {
|
||||||
|
/* stop */
|
||||||
|
if (p_ddraw->b_started) {
|
||||||
|
_tdav_producer_screencast_ddraw_stop((tmedia_producer_t*)p_ddraw);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* deinit base */
|
||||||
|
tmedia_producer_deinit(TMEDIA_PRODUCER(p_ddraw));
|
||||||
|
/* deinit self */
|
||||||
|
if (p_ddraw->p_buff_neg) {
|
||||||
|
VirtualFree(p_ddraw->p_buff_neg, 0, MEM_RELEASE);
|
||||||
|
p_ddraw->p_buff_neg = NULL;
|
||||||
|
}
|
||||||
|
DDRAW_SAFE_RELEASE(&p_ddraw->p_surf_primary);
|
||||||
|
DDRAW_SAFE_RELEASE(&p_ddraw->p_dd);
|
||||||
|
tsk_safeobj_deinit(p_ddraw);
|
||||||
|
|
||||||
|
DDRAW_DEBUG_INFO("*** destroyed ***");
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
/* object definition */
|
||||||
|
static const tsk_object_def_t tdav_producer_screencast_ddraw_def_s =
|
||||||
|
{
|
||||||
|
sizeof(tdav_producer_screencast_ddraw_t),
|
||||||
|
_tdav_producer_screencast_ddraw_ctor,
|
||||||
|
_tdav_producer_screencast_ddraw_dtor,
|
||||||
|
tsk_null,
|
||||||
|
};
|
||||||
|
/* plugin definition*/
|
||||||
|
static const tmedia_producer_plugin_def_t tdav_producer_screencast_ddraw_plugin_def_s =
|
||||||
|
{
|
||||||
|
&tdav_producer_screencast_ddraw_def_s,
|
||||||
|
tmedia_bfcp_video,
|
||||||
|
"Microsoft DirectDraw screencast producer",
|
||||||
|
|
||||||
|
_tdav_producer_screencast_ddraw_set,
|
||||||
|
_tdav_producer_screencast_ddraw_prepare,
|
||||||
|
_tdav_producer_screencast_ddraw_start,
|
||||||
|
_tdav_producer_screencast_ddraw_pause,
|
||||||
|
_tdav_producer_screencast_ddraw_stop
|
||||||
|
};
|
||||||
|
const tmedia_producer_plugin_def_t *tdav_producer_screencast_ddraw_plugin_def_t = &tdav_producer_screencast_ddraw_plugin_def_s;
|
||||||
|
|
||||||
|
#endif /* TDAV_UNDER_WINDOWS && !TDAV_UNDER_WINDOWS_RT */
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright (C) 2014 Mamadou DIOP.
|
/* Copyright (C) 2014-2015 Mamadou DIOP.
|
||||||
*
|
*
|
||||||
* This file is part of Open Source Doubango Framework.
|
* This file is part of Open Source Doubango Framework.
|
||||||
*
|
*
|
||||||
|
@ -437,10 +437,12 @@ static void* TSK_STDCALL _tdav_producer_screencast_record_thread(void *arg)
|
||||||
|
|
||||||
while (ret == 0 && p_gdi->b_started) {
|
while (ret == 0 && p_gdi->b_started) {
|
||||||
TimeNow = tsk_time_now();
|
TimeNow = tsk_time_now();
|
||||||
if ((TimeNow - TimeLastFrame) > TimeFrameDuration) {
|
if ((TimeNow - TimeLastFrame) >= TimeFrameDuration) {
|
||||||
|
if (!p_gdi->b_muted && !p_gdi->b_paused) {
|
||||||
if (ret = _tdav_producer_screencast_grab(p_gdi)) {
|
if (ret = _tdav_producer_screencast_grab(p_gdi)) {
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
TimeLastFrame = TimeNow;
|
TimeLastFrame = TimeNow;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
Loading…
Reference in New Issue