Skip to content

Commit 0074f52

Browse files
committed
dshow: capture NV12
refers to GH-369
1 parent 0c0a403 commit 0074f52

File tree

1 file changed

+58
-21
lines changed

1 file changed

+58
-21
lines changed

src/video_capture/DirectShowGrabber.cpp

+58-21
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,15 @@
3838
EXTERN_C const CLSID CLSID_NullRenderer;
3939
EXTERN_C const CLSID CLSID_SampleGrabber;
4040

41+
typedef void (*convert_t)(int width, int height, const unsigned char *in,
42+
unsigned char *out);
43+
4144
using namespace std;
4245

4346
static void DeleteMediaType(AM_MEDIA_TYPE *mediaType);
4447
static const CHAR * GetSubtypeName(const GUID *pSubtype);
4548
static codec_t get_ug_codec(const GUID *pSubtype);
49+
static convert_t get_conversion(const GUID *pSubtype);
4650
static codec_t get_ug_from_subtype_name(const char *subtype_name);
4751
static void vidcap_dshow_probe(device_info **available_cards, int *count, void (**deleter)(void *));
4852

@@ -74,6 +78,7 @@ struct vidcap_dshow_state {
7478
int modeNumber;
7579
struct video_desc desc;
7680
bool convert_YUYV_RGB; ///< @todo check - currently newer set
81+
convert_t convert;
7782

7883
struct video_frame *frame;
7984
long grabBufferLen;
@@ -143,8 +148,10 @@ class SampleGrabberCallback : public ISampleGrabberCB {
143148
if (len <= 0) return S_OK;
144149

145150
EnterCriticalSection(&s->returnBufferCS);
146-
if (s->grabBufferLen != len) {
147-
s->grabBuffer = (BYTE *) realloc((void *) s->grabBuffer, len * sizeof(BYTE));
151+
const long req_len = vc_get_datalen(
152+
s->desc.width, s->desc.height, s->desc.color_spec);
153+
if (s->grabBufferLen != req_len) {
154+
s->grabBuffer = (BYTE *) realloc((void *) s->grabBuffer, req_len);
148155
if (s->grabBuffer == NULL) {
149156
s->grabBufferLen = 0;
150157
return S_OK;
@@ -156,7 +163,9 @@ class SampleGrabberCallback : public ISampleGrabberCB {
156163
// Apparently DirectShow uses bottom-to-top line ordering so we want make
157164
// it top-to-bottom
158165
int linesize = vc_get_linesize(s->desc.width, s->desc.color_spec);
159-
if (s->desc.color_spec == BGR) {
166+
if (s->convert != nullptr) {
167+
s->convert(s->desc.width, s->desc.height, buffer, s->grabBuffer);
168+
} else if (s->desc.color_spec == BGR) {
160169
for(unsigned int i = 0; i < s->desc.height; ++i) {
161170
memcpy((char *) s->grabBuffer + i * linesize,
162171
(char *) buffer + (s->desc.height - i - 1) * linesize,
@@ -1006,6 +1015,7 @@ static int vidcap_dshow_init(struct vidcap_params *params, void **state) {
10061015
}
10071016
res = s->streamConfig->SetFormat(mediaType);
10081017
HANDLE_ERR(res, "Cannot set capture format");
1018+
s->convert = get_conversion(&mediaType->subtype);
10091019
DeleteMediaType(mediaType);
10101020

10111021
if (s->convert_YUYV_RGB) {
@@ -1215,6 +1225,25 @@ static void DeleteMediaType(AM_MEDIA_TYPE *pmt) {
12151225
CoTaskMemFree((PVOID)pmt);
12161226
}
12171227

1228+
void
1229+
nv12_to_uyvy(int width, int height, const unsigned char *in, unsigned char *out)
1230+
{
1231+
const int uyvy_linesize = vc_get_linesize(width, UYVY);
1232+
for (int y = 0; y < height; ++y) {
1233+
const unsigned char *src_y = in + width * y;
1234+
const unsigned char *src_cbcr = in + width * height;
1235+
unsigned char *dst = out + y * uyvy_linesize;
1236+
1237+
OPTIMIZED_FOR(int x = 0; x < width / 2; ++x)
1238+
{
1239+
*dst++ = *src_cbcr++;
1240+
*dst++ = *src_y++;
1241+
*dst++ = *src_cbcr++;
1242+
*dst++ = *src_y++;
1243+
}
1244+
}
1245+
}
1246+
12181247
static GUID GUID_R210 = {0x30313272, 0x0000, 0x10, {0x80,0x0,0x0,0xAA,0x0,0x38,0x9B,0x71}};
12191248
static GUID GUID_v210 = {0x30313276, 0x0000, 0x10, {0x80,0x0,0x0,0xAA,0x0,0x38,0x9B,0x71}};
12201249
static GUID GUID_V210 = {0x30313256, 0x0000, 0x10, {0x80,0x0,0x0,0xAA,0x0,0x38,0x9B,0x71}};
@@ -1225,32 +1254,40 @@ static const struct {
12251254
const GUID *pSubtype;
12261255
const CHAR *pName;
12271256
codec_t ug_codec;
1257+
convert_t convert;
12281258
} BitCountMap[] = {
1229-
{&MEDIASUBTYPE_RGB1, "RGB Monochrome", VC_NONE},
1230-
{ &MEDIASUBTYPE_RGB4, "RGB VGA", VC_NONE},
1231-
{ &MEDIASUBTYPE_RGB8, "RGB 8", VC_NONE},
1232-
{ &MEDIASUBTYPE_RGB565, "RGB 565 (16 bit)", VC_NONE},
1233-
{ &MEDIASUBTYPE_RGB555, "RGB 555 (16 bit)", VC_NONE},
1234-
{ &MEDIASUBTYPE_RGB24, "RGB 24", BGR },
1235-
{ &MEDIASUBTYPE_RGB32, "RGB 32", RGBA },
1236-
{ &MEDIASUBTYPE_ARGB32, "ARGB 32", VC_NONE},
1237-
{ &MEDIASUBTYPE_Overlay, "Overlay", VC_NONE},
1238-
{ &GUID_I420, "I420", VC_NONE},
1239-
{ &MEDIASUBTYPE_YUY2, "YUY2", YUYV },
1240-
{ &GUID_R210, "r210", VC_NONE},
1241-
{ &GUID_v210, "v210", v210 },
1242-
{ &GUID_V210, "V210", v210 },
1243-
{ &MEDIASUBTYPE_UYVY, "UYVY", UYVY },
1244-
{ &GUID_HDYC, "HDYC", UYVY },
1245-
{ &MEDIASUBTYPE_MJPG, "MJPG", MJPG },
1246-
{ &GUID_NULL, "UNKNOWN", VC_NONE},
1259+
{&MEDIASUBTYPE_RGB1, "RGB Monochrome", VC_NONE, nullptr },
1260+
{ &MEDIASUBTYPE_RGB4, "RGB VGA", VC_NONE, nullptr },
1261+
{ &MEDIASUBTYPE_RGB8, "RGB 8", VC_NONE, nullptr },
1262+
{ &MEDIASUBTYPE_RGB565, "RGB 565 (16 bit)", VC_NONE, nullptr },
1263+
{ &MEDIASUBTYPE_RGB555, "RGB 555 (16 bit)", VC_NONE, nullptr },
1264+
{ &MEDIASUBTYPE_RGB24, "RGB 24", BGR, nullptr },
1265+
{ &MEDIASUBTYPE_RGB32, "RGB 32", RGBA, nullptr },
1266+
{ &MEDIASUBTYPE_ARGB32, "ARGB 32", VC_NONE, nullptr },
1267+
{ &MEDIASUBTYPE_Overlay, "Overlay", VC_NONE, nullptr },
1268+
{ &GUID_I420, "I420", VC_NONE, nullptr },
1269+
{ &MEDIASUBTYPE_YUY2, "YUY2", YUYV, nullptr },
1270+
{ &GUID_R210, "r210", VC_NONE, nullptr },
1271+
{ &GUID_v210, "v210", v210, nullptr },
1272+
{ &GUID_V210, "V210", v210, nullptr },
1273+
{ &MEDIASUBTYPE_UYVY, "UYVY", UYVY, nullptr },
1274+
{ &GUID_HDYC, "HDYC", UYVY, nullptr },
1275+
{ &MEDIASUBTYPE_MJPG, "MJPG", MJPG, nullptr },
1276+
{ &MEDIASUBTYPE_NV12, "NV12", UYVY, nv12_to_uyvy},
1277+
{ &GUID_NULL, "UNKNOWN", VC_NONE, nullptr },
12471278
};
12481279

12491280
static codec_t get_ug_codec(const GUID *pSubtype)
12501281
{
12511282
return BitCountMap[LocateSubtype(pSubtype)].ug_codec;
12521283
}
12531284

1285+
static convert_t
1286+
get_conversion(const GUID *pSubtype)
1287+
{
1288+
return BitCountMap[LocateSubtype(pSubtype)].convert;
1289+
}
1290+
12541291
static codec_t get_ug_from_subtype_name(const char *subtype_name) {
12551292
for (unsigned int i = 0; i < sizeof BitCountMap / sizeof BitCountMap[0]; ++i) {
12561293
if (strcmp(BitCountMap[i].pName, subtype_name) == 0) {

0 commit comments

Comments
 (0)