forked from FFmpeg/FFmpeg
DirectShow capture support
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
parent
f8c49d02b0
commit
95eb2e3a38
11 changed files with 1820 additions and 2 deletions
4
configure
vendored
4
configure
vendored
|
@ -1463,6 +1463,8 @@ w64_demuxer_deps="wav_demuxer"
|
||||||
alsa_indev_deps="alsa_asoundlib_h snd_pcm_htimestamp"
|
alsa_indev_deps="alsa_asoundlib_h snd_pcm_htimestamp"
|
||||||
alsa_outdev_deps="alsa_asoundlib_h"
|
alsa_outdev_deps="alsa_asoundlib_h"
|
||||||
bktr_indev_deps_any="dev_bktr_ioctl_bt848_h machine_ioctl_bt848_h dev_video_bktr_ioctl_bt848_h dev_ic_bt8xx_h"
|
bktr_indev_deps_any="dev_bktr_ioctl_bt848_h machine_ioctl_bt848_h dev_video_bktr_ioctl_bt848_h dev_ic_bt8xx_h"
|
||||||
|
dshow_indev_deps="IBaseFilter"
|
||||||
|
dshow_indev_extralibs="-lpsapi -lole32 -lstrmiids -luuid"
|
||||||
dv1394_indev_deps="dv1394 dv_demuxer"
|
dv1394_indev_deps="dv1394 dv_demuxer"
|
||||||
fbdev_indev_deps="linux_fb_h"
|
fbdev_indev_deps="linux_fb_h"
|
||||||
jack_indev_deps="jack_jack_h sem_timedwait"
|
jack_indev_deps="jack_jack_h sem_timedwait"
|
||||||
|
@ -2979,6 +2981,8 @@ check_func_headers "windows.h vfw.h" capCreateCaptureWindow "$vfwcap_indev_extra
|
||||||
# w32api 3.12 had it defined wrong
|
# w32api 3.12 had it defined wrong
|
||||||
check_cpp_condition vfw.h "WM_CAP_DRIVER_CONNECT > WM_USER" && enable vfwcap_defines
|
check_cpp_condition vfw.h "WM_CAP_DRIVER_CONNECT > WM_USER" && enable vfwcap_defines
|
||||||
|
|
||||||
|
check_type "dshow.h" IBaseFilter
|
||||||
|
|
||||||
# check for ioctl_meteor.h, ioctl_bt848.h and alternatives
|
# check for ioctl_meteor.h, ioctl_bt848.h and alternatives
|
||||||
{ check_header dev/bktr/ioctl_meteor.h &&
|
{ check_header dev/bktr/ioctl_meteor.h &&
|
||||||
check_header dev/bktr/ioctl_bt848.h; } ||
|
check_header dev/bktr/ioctl_bt848.h; } ||
|
||||||
|
|
|
@ -13,6 +13,9 @@ OBJS-$(CONFIG_ALSA_INDEV) += alsa-audio-common.o \
|
||||||
OBJS-$(CONFIG_ALSA_OUTDEV) += alsa-audio-common.o \
|
OBJS-$(CONFIG_ALSA_OUTDEV) += alsa-audio-common.o \
|
||||||
alsa-audio-enc.o
|
alsa-audio-enc.o
|
||||||
OBJS-$(CONFIG_BKTR_INDEV) += bktr.o
|
OBJS-$(CONFIG_BKTR_INDEV) += bktr.o
|
||||||
|
OBJS-$(CONFIG_DSHOW_INDEV) += dshow.o dshow_enummediatypes.o \
|
||||||
|
dshow_enumpins.o dshow_filter.o \
|
||||||
|
dshow_pin.o dshow_common.o
|
||||||
OBJS-$(CONFIG_DV1394_INDEV) += dv1394.o
|
OBJS-$(CONFIG_DV1394_INDEV) += dv1394.o
|
||||||
OBJS-$(CONFIG_FBDEV_INDEV) += fbdev.o
|
OBJS-$(CONFIG_FBDEV_INDEV) += fbdev.o
|
||||||
OBJS-$(CONFIG_JACK_INDEV) += jack_audio.o
|
OBJS-$(CONFIG_JACK_INDEV) += jack_audio.o
|
||||||
|
|
|
@ -41,6 +41,7 @@ void avdevice_register_all(void)
|
||||||
/* devices */
|
/* devices */
|
||||||
REGISTER_INOUTDEV (ALSA, alsa);
|
REGISTER_INOUTDEV (ALSA, alsa);
|
||||||
REGISTER_INDEV (BKTR, bktr);
|
REGISTER_INDEV (BKTR, bktr);
|
||||||
|
REGISTER_INDEV (DSHOW, dshow);
|
||||||
REGISTER_INDEV (DV1394, dv1394);
|
REGISTER_INDEV (DV1394, dv1394);
|
||||||
REGISTER_INDEV (FBDEV, fbdev);
|
REGISTER_INDEV (FBDEV, fbdev);
|
||||||
REGISTER_INDEV (JACK, jack);
|
REGISTER_INDEV (JACK, jack);
|
||||||
|
|
646
libavdevice/dshow.c
Normal file
646
libavdevice/dshow.c
Normal file
|
@ -0,0 +1,646 @@
|
||||||
|
/*
|
||||||
|
* Directshow capture interface
|
||||||
|
* Copyright (c) 2010 Ramiro Polla
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libavformat/avformat.h"
|
||||||
|
#include "libavformat/timefilter.h"
|
||||||
|
|
||||||
|
#include "dshow.h"
|
||||||
|
|
||||||
|
struct dshow_ctx {
|
||||||
|
IGraphBuilder *graph;
|
||||||
|
|
||||||
|
char *device_name[2];
|
||||||
|
|
||||||
|
IBaseFilter *device_filter[2];
|
||||||
|
IPin *device_pin[2];
|
||||||
|
libAVFilter *capture_filter[2];
|
||||||
|
libAVPin *capture_pin[2];
|
||||||
|
|
||||||
|
HANDLE mutex;
|
||||||
|
HANDLE event;
|
||||||
|
AVPacketList *pktl;
|
||||||
|
|
||||||
|
unsigned int curbufsize;
|
||||||
|
unsigned int video_frame_num;
|
||||||
|
|
||||||
|
IMediaControl *control;
|
||||||
|
|
||||||
|
TimeFilter *timefilter;
|
||||||
|
};
|
||||||
|
|
||||||
|
static enum PixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
|
||||||
|
{
|
||||||
|
switch(biCompression) {
|
||||||
|
case MKTAG('U', 'Y', 'V', 'Y'):
|
||||||
|
return PIX_FMT_UYVY422;
|
||||||
|
case MKTAG('Y', 'U', 'Y', '2'):
|
||||||
|
return PIX_FMT_YUYV422;
|
||||||
|
case MKTAG('I', '4', '2', '0'):
|
||||||
|
return PIX_FMT_YUV420P;
|
||||||
|
case BI_RGB:
|
||||||
|
switch(biBitCount) { /* 1-8 are untested */
|
||||||
|
case 1:
|
||||||
|
return PIX_FMT_MONOWHITE;
|
||||||
|
case 4:
|
||||||
|
return PIX_FMT_RGB4;
|
||||||
|
case 8:
|
||||||
|
return PIX_FMT_RGB8;
|
||||||
|
case 16:
|
||||||
|
return PIX_FMT_RGB555;
|
||||||
|
case 24:
|
||||||
|
return PIX_FMT_BGR24;
|
||||||
|
case 32:
|
||||||
|
return PIX_FMT_RGB32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PIX_FMT_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum CodecID dshow_codecid(DWORD biCompression)
|
||||||
|
{
|
||||||
|
switch(biCompression) {
|
||||||
|
case MKTAG('d', 'v', 's', 'd'):
|
||||||
|
return CODEC_ID_DVVIDEO;
|
||||||
|
case MKTAG('M', 'J', 'P', 'G'):
|
||||||
|
case MKTAG('m', 'j', 'p', 'g'):
|
||||||
|
return CODEC_ID_MJPEG;
|
||||||
|
}
|
||||||
|
return CODEC_ID_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dshow_read_close(AVFormatContext *s)
|
||||||
|
{
|
||||||
|
struct dshow_ctx *ctx = s->priv_data;
|
||||||
|
AVPacketList *pktl;
|
||||||
|
|
||||||
|
if (ctx->control) {
|
||||||
|
IMediaControl_Stop(ctx->control);
|
||||||
|
IMediaControl_Release(ctx->control);
|
||||||
|
}
|
||||||
|
if (ctx->graph)
|
||||||
|
IGraphBuilder_Release(ctx->graph);
|
||||||
|
|
||||||
|
/* FIXME remove filters from graph */
|
||||||
|
/* FIXME disconnect pins */
|
||||||
|
if (ctx->capture_pin[VideoDevice])
|
||||||
|
libAVPin_Release(ctx->capture_pin[VideoDevice]);
|
||||||
|
if (ctx->capture_pin[AudioDevice])
|
||||||
|
libAVPin_Release(ctx->capture_pin[AudioDevice]);
|
||||||
|
if (ctx->capture_filter[VideoDevice])
|
||||||
|
libAVFilter_Release(ctx->capture_filter[VideoDevice]);
|
||||||
|
if (ctx->capture_filter[AudioDevice])
|
||||||
|
libAVFilter_Release(ctx->capture_filter[AudioDevice]);
|
||||||
|
|
||||||
|
if (ctx->device_pin[VideoDevice])
|
||||||
|
IPin_Release(ctx->device_pin[VideoDevice]);
|
||||||
|
if (ctx->device_pin[AudioDevice])
|
||||||
|
IPin_Release(ctx->device_pin[AudioDevice]);
|
||||||
|
if (ctx->device_filter[VideoDevice])
|
||||||
|
IBaseFilter_Release(ctx->device_filter[VideoDevice]);
|
||||||
|
if (ctx->device_filter[AudioDevice])
|
||||||
|
IBaseFilter_Release(ctx->device_filter[AudioDevice]);
|
||||||
|
|
||||||
|
if (ctx->device_name[0])
|
||||||
|
av_free(ctx->device_name[0]);
|
||||||
|
if (ctx->device_name[1])
|
||||||
|
av_free(ctx->device_name[1]);
|
||||||
|
|
||||||
|
if(ctx->mutex)
|
||||||
|
CloseHandle(ctx->mutex);
|
||||||
|
if(ctx->event)
|
||||||
|
CloseHandle(ctx->event);
|
||||||
|
|
||||||
|
pktl = ctx->pktl;
|
||||||
|
while (pktl) {
|
||||||
|
AVPacketList *next = pktl->next;
|
||||||
|
av_destruct_packet(&pktl->pkt);
|
||||||
|
av_free(pktl);
|
||||||
|
pktl = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *dup_wchar_to_utf8(wchar_t *w)
|
||||||
|
{
|
||||||
|
char *s = NULL;
|
||||||
|
int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
|
||||||
|
s = av_malloc(l);
|
||||||
|
if (s)
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int shall_we_drop(AVFormatContext *s)
|
||||||
|
{
|
||||||
|
struct dshow_ctx *ctx = s->priv_data;
|
||||||
|
const uint8_t dropscore[] = {62, 75, 87, 100};
|
||||||
|
const int ndropscores = FF_ARRAY_ELEMS(dropscore);
|
||||||
|
unsigned int buffer_fullness = (ctx->curbufsize*100)/s->max_picture_buffer;
|
||||||
|
|
||||||
|
if(dropscore[++ctx->video_frame_num%ndropscores] <= buffer_fullness) {
|
||||||
|
av_log(s, AV_LOG_ERROR,
|
||||||
|
"real-time buffer %d%% full! frame dropped!\n", buffer_fullness);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
callback(void *priv_data, int index, uint8_t *buf, int buf_size, int64_t time)
|
||||||
|
{
|
||||||
|
AVFormatContext *s = priv_data;
|
||||||
|
struct dshow_ctx *ctx = s->priv_data;
|
||||||
|
AVPacketList **ppktl, *pktl_next;
|
||||||
|
|
||||||
|
// dump_videohdr(s, vdhdr);
|
||||||
|
|
||||||
|
if(shall_we_drop(s))
|
||||||
|
return;
|
||||||
|
|
||||||
|
WaitForSingleObject(ctx->mutex, INFINITE);
|
||||||
|
|
||||||
|
pktl_next = av_mallocz(sizeof(AVPacketList));
|
||||||
|
if(!pktl_next)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if(av_new_packet(&pktl_next->pkt, buf_size) < 0) {
|
||||||
|
av_free(pktl_next);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
pktl_next->pkt.stream_index = index;
|
||||||
|
pktl_next->pkt.pts = time;
|
||||||
|
memcpy(pktl_next->pkt.data, buf, buf_size);
|
||||||
|
|
||||||
|
for(ppktl = &ctx->pktl ; *ppktl ; ppktl = &(*ppktl)->next);
|
||||||
|
*ppktl = pktl_next;
|
||||||
|
|
||||||
|
ctx->curbufsize += buf_size;
|
||||||
|
|
||||||
|
SetEvent(ctx->event);
|
||||||
|
ReleaseMutex(ctx->mutex);
|
||||||
|
|
||||||
|
return;
|
||||||
|
fail:
|
||||||
|
ReleaseMutex(ctx->mutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
|
||||||
|
enum dshowDeviceType devtype)
|
||||||
|
{
|
||||||
|
struct dshow_ctx *ctx = avctx->priv_data;
|
||||||
|
IBaseFilter *device_filter = NULL;
|
||||||
|
IEnumMoniker *classenum = NULL;
|
||||||
|
IGraphBuilder *graph = ctx->graph;
|
||||||
|
IEnumPins *pins = 0;
|
||||||
|
IMoniker *m = NULL;
|
||||||
|
IPin *device_pin = NULL;
|
||||||
|
libAVPin *capture_pin = NULL;
|
||||||
|
libAVFilter *capture_filter = NULL;
|
||||||
|
const char *device_name = ctx->device_name[devtype];
|
||||||
|
int ret = AVERROR(EIO);
|
||||||
|
IPin *pin;
|
||||||
|
int r, i;
|
||||||
|
|
||||||
|
const GUID *device_guid[2] = { &CLSID_VideoInputDeviceCategory,
|
||||||
|
&CLSID_AudioInputDeviceCategory };
|
||||||
|
const GUID *mediatype[2] = { &MEDIATYPE_Video, &MEDIATYPE_Audio };
|
||||||
|
const char *devtypename = (devtype == VideoDevice) ? "video" : "audio";
|
||||||
|
const wchar_t *filter_name[2] = { L"Audio capture filter", L"Video capture filter" };
|
||||||
|
|
||||||
|
r = ICreateDevEnum_CreateClassEnumerator(devenum, device_guid[devtype],
|
||||||
|
(IEnumMoniker **) &classenum, 0);
|
||||||
|
if (r != S_OK) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Could not enumerate %s devices.\n",
|
||||||
|
devtypename);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (IEnumMoniker_Next(classenum, 1, &m, NULL) == S_OK && !device_filter) {
|
||||||
|
IPropertyBag *bag = NULL;
|
||||||
|
char *buf = NULL;
|
||||||
|
VARIANT var;
|
||||||
|
|
||||||
|
r = IMoniker_BindToStorage(m, 0, 0, &IID_IPropertyBag, (void *) &bag);
|
||||||
|
if (r != S_OK)
|
||||||
|
goto fail1;
|
||||||
|
|
||||||
|
var.vt = VT_BSTR;
|
||||||
|
r = IPropertyBag_Read(bag, L"FriendlyName", &var, NULL);
|
||||||
|
if (r != S_OK)
|
||||||
|
goto fail1;
|
||||||
|
|
||||||
|
buf = dup_wchar_to_utf8(var.bstrVal);
|
||||||
|
|
||||||
|
if (strcmp(device_name, buf))
|
||||||
|
goto fail1;
|
||||||
|
|
||||||
|
IMoniker_BindToObject(m, 0, 0, &IID_IBaseFilter, (void *) &device_filter);
|
||||||
|
|
||||||
|
fail1:
|
||||||
|
if (buf)
|
||||||
|
av_free(buf);
|
||||||
|
if (bag)
|
||||||
|
IPropertyBag_Release(bag);
|
||||||
|
IMoniker_Release(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!device_filter) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Could not find %s device.\n",
|
||||||
|
devtypename);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
ctx->device_filter [devtype] = device_filter;
|
||||||
|
|
||||||
|
r = IGraphBuilder_AddFilter(graph, device_filter, NULL);
|
||||||
|
if (r != S_OK) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Could not add device filter to graph.\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = IBaseFilter_EnumPins(device_filter, &pins);
|
||||||
|
if (r != S_OK) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Could not enumerate pins.\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (IEnumPins_Next(pins, 1, &pin, NULL) == S_OK && !device_pin) {
|
||||||
|
IKsPropertySet *p = NULL;
|
||||||
|
IEnumMediaTypes *types;
|
||||||
|
PIN_INFO info = {0};
|
||||||
|
AM_MEDIA_TYPE *type;
|
||||||
|
GUID category;
|
||||||
|
DWORD r2;
|
||||||
|
|
||||||
|
IPin_QueryPinInfo(pin, &info);
|
||||||
|
IBaseFilter_Release(info.pFilter);
|
||||||
|
|
||||||
|
if (info.dir != PINDIR_OUTPUT)
|
||||||
|
goto next;
|
||||||
|
if (IPin_QueryInterface(pin, &IID_IKsPropertySet, (void **) &p) != S_OK)
|
||||||
|
goto next;
|
||||||
|
if (IKsPropertySet_Get(p, &ROPSETID_Pin, AMPROPERTY_PIN_CATEGORY,
|
||||||
|
NULL, 0, &category, sizeof(GUID), &r2) != S_OK)
|
||||||
|
goto next;
|
||||||
|
if (!IsEqualGUID(&category, &PIN_CATEGORY_CAPTURE))
|
||||||
|
goto next;
|
||||||
|
|
||||||
|
if (IPin_EnumMediaTypes(pin, &types) != S_OK)
|
||||||
|
goto next;
|
||||||
|
|
||||||
|
IEnumMediaTypes_Reset(types);
|
||||||
|
while (IEnumMediaTypes_Next(types, 1, &type, NULL) == S_OK && !device_pin) {
|
||||||
|
if (IsEqualGUID(&type->majortype, mediatype[devtype])) {
|
||||||
|
device_pin = pin;
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
CoTaskMemFree(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
next:
|
||||||
|
if (types)
|
||||||
|
IEnumMediaTypes_Release(types);
|
||||||
|
if (p)
|
||||||
|
IKsPropertySet_Release(p);
|
||||||
|
if (device_pin != pin)
|
||||||
|
IPin_Release(pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!device_pin) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR,
|
||||||
|
"Could not find output pin from %s capture device.\n", devtypename);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
ctx->device_pin[devtype] = device_pin;
|
||||||
|
|
||||||
|
capture_filter = libAVFilter_Create(avctx, callback, devtype);
|
||||||
|
if (!capture_filter) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Could not create grabber filter.\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
ctx->capture_filter[devtype] = capture_filter;
|
||||||
|
|
||||||
|
r = IGraphBuilder_AddFilter(graph, (IBaseFilter *) capture_filter,
|
||||||
|
filter_name[devtype]);
|
||||||
|
if (r != S_OK) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Could not add capture filter to graph\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
libAVPin_AddRef(capture_filter->pin);
|
||||||
|
capture_pin = capture_filter->pin;
|
||||||
|
ctx->capture_pin[devtype] = capture_pin;
|
||||||
|
|
||||||
|
r = IGraphBuilder_ConnectDirect(graph, device_pin, (IPin *) capture_pin, NULL);
|
||||||
|
if (r != S_OK) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Could not connect pins\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (pins)
|
||||||
|
IEnumPins_Release(pins);
|
||||||
|
if (classenum)
|
||||||
|
IEnumMoniker_Release(classenum);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum CodecID waveform_codec_id(enum AVSampleFormat sample_fmt)
|
||||||
|
{
|
||||||
|
switch (sample_fmt) {
|
||||||
|
case AV_SAMPLE_FMT_U8: return CODEC_ID_PCM_U8;
|
||||||
|
case AV_SAMPLE_FMT_S16: return CODEC_ID_PCM_S16LE;
|
||||||
|
case AV_SAMPLE_FMT_S32: return CODEC_ID_PCM_S32LE;
|
||||||
|
default: return CODEC_ID_NONE; /* Should never happen. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum SampleFormat sample_fmt_bits_per_sample(int bits)
|
||||||
|
{
|
||||||
|
switch (bits) {
|
||||||
|
case 8: return AV_SAMPLE_FMT_U8;
|
||||||
|
case 16: return AV_SAMPLE_FMT_S16;
|
||||||
|
case 32: return AV_SAMPLE_FMT_S32;
|
||||||
|
default: return AV_SAMPLE_FMT_NONE; /* Should never happen. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dshow_add_device(AVFormatContext *avctx, AVFormatParameters *ap,
|
||||||
|
enum dshowDeviceType devtype)
|
||||||
|
{
|
||||||
|
struct dshow_ctx *ctx = avctx->priv_data;
|
||||||
|
AM_MEDIA_TYPE type;
|
||||||
|
AVCodecContext *codec;
|
||||||
|
AVStream *st;
|
||||||
|
int ret = AVERROR(EIO);
|
||||||
|
|
||||||
|
st = av_new_stream(avctx, devtype);
|
||||||
|
if (!st) {
|
||||||
|
ret = AVERROR(ENOMEM);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->capture_filter[devtype]->stream_index = st->index;
|
||||||
|
|
||||||
|
libAVPin_ConnectionMediaType(ctx->capture_pin[devtype], &type);
|
||||||
|
|
||||||
|
codec = st->codec;
|
||||||
|
if (devtype == VideoDevice) {
|
||||||
|
BITMAPINFOHEADER *bih = NULL;
|
||||||
|
|
||||||
|
if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo)) {
|
||||||
|
VIDEOINFOHEADER *v = (void *) type.pbFormat;
|
||||||
|
bih = &v->bmiHeader;
|
||||||
|
} else if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo2)) {
|
||||||
|
VIDEOINFOHEADER2 *v = (void *) type.pbFormat;
|
||||||
|
bih = &v->bmiHeader;
|
||||||
|
}
|
||||||
|
if (!bih) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
codec->time_base = ap->time_base;
|
||||||
|
codec->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||||
|
codec->width = bih->biWidth;
|
||||||
|
codec->height = bih->biHeight;
|
||||||
|
codec->pix_fmt = dshow_pixfmt(bih->biCompression, bih->biBitCount);
|
||||||
|
if (codec->pix_fmt == PIX_FMT_NONE) {
|
||||||
|
codec->codec_id = dshow_codecid(bih->biCompression);
|
||||||
|
if (codec->codec_id == CODEC_ID_NONE) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Unknown compression type. "
|
||||||
|
"Please report verbose (-v 9) debug information.\n");
|
||||||
|
dshow_read_close(avctx);
|
||||||
|
return AVERROR_PATCHWELCOME;
|
||||||
|
}
|
||||||
|
codec->bits_per_coded_sample = bih->biBitCount;
|
||||||
|
} else {
|
||||||
|
codec->codec_id = CODEC_ID_RAWVIDEO;
|
||||||
|
if (bih->biCompression == BI_RGB) {
|
||||||
|
codec->bits_per_coded_sample = bih->biBitCount;
|
||||||
|
codec->extradata = av_malloc(9 + FF_INPUT_BUFFER_PADDING_SIZE);
|
||||||
|
if (codec->extradata) {
|
||||||
|
codec->extradata_size = 9;
|
||||||
|
memcpy(codec->extradata, "BottomUp", 9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
WAVEFORMATEX *fx = NULL;
|
||||||
|
|
||||||
|
if (IsEqualGUID(&type.formattype, &FORMAT_WaveFormatEx)) {
|
||||||
|
fx = (void *) type.pbFormat;
|
||||||
|
}
|
||||||
|
if (!fx) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
codec->codec_type = CODEC_TYPE_AUDIO;
|
||||||
|
codec->sample_fmt = sample_fmt_bits_per_sample(fx->wBitsPerSample);
|
||||||
|
codec->codec_id = waveform_codec_id(codec->sample_fmt);
|
||||||
|
codec->sample_rate = fx->nSamplesPerSec;
|
||||||
|
codec->channels = fx->nChannels;
|
||||||
|
}
|
||||||
|
|
||||||
|
av_set_pts_info(st, 64, 1, 10000000);
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_device_name(AVFormatContext *avctx)
|
||||||
|
{
|
||||||
|
struct dshow_ctx *ctx = avctx->priv_data;
|
||||||
|
char **device_name = ctx->device_name;
|
||||||
|
char *name = av_strdup(avctx->filename);
|
||||||
|
char *tmp = name;
|
||||||
|
int ret = 1;
|
||||||
|
char *type;
|
||||||
|
|
||||||
|
while ((type = strtok(tmp, "="))) {
|
||||||
|
char *token = strtok(NULL, ":");
|
||||||
|
tmp = NULL;
|
||||||
|
|
||||||
|
if (!strcmp(type, "video")) {
|
||||||
|
device_name[0] = token;
|
||||||
|
} else if (!strcmp(type, "audio")) {
|
||||||
|
device_name[1] = token;
|
||||||
|
} else {
|
||||||
|
device_name[0] = NULL;
|
||||||
|
device_name[1] = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!device_name[0] && !device_name[1]) {
|
||||||
|
ret = 0;
|
||||||
|
} else {
|
||||||
|
if (device_name[0])
|
||||||
|
device_name[0] = av_strdup(device_name[0]);
|
||||||
|
if (device_name[1])
|
||||||
|
device_name[1] = av_strdup(device_name[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
av_free(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dshow_read_header(AVFormatContext *avctx, AVFormatParameters *ap)
|
||||||
|
{
|
||||||
|
struct dshow_ctx *ctx = avctx->priv_data;
|
||||||
|
IGraphBuilder *graph = NULL;
|
||||||
|
ICreateDevEnum *devenum = NULL;
|
||||||
|
IMediaControl *control = NULL;
|
||||||
|
int ret = AVERROR(EIO);
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (!parse_device_name(avctx)) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Malformed dshow input string.\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
CoInitialize(0);
|
||||||
|
|
||||||
|
r = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
|
||||||
|
&IID_IGraphBuilder, (void **) &graph);
|
||||||
|
if (r != S_OK) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Could not create capture graph.\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
ctx->graph = graph;
|
||||||
|
|
||||||
|
r = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
|
||||||
|
&IID_ICreateDevEnum, (void **) &devenum);
|
||||||
|
if (r != S_OK) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Could not enumerate system devices.\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->device_name[VideoDevice]) {
|
||||||
|
ret = dshow_open_device(avctx, devenum, VideoDevice);
|
||||||
|
if (ret < 0)
|
||||||
|
goto error;
|
||||||
|
ret = dshow_add_device(avctx, ap, VideoDevice);
|
||||||
|
if (ret < 0)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (ctx->device_name[AudioDevice]) {
|
||||||
|
ret = dshow_open_device(avctx, devenum, AudioDevice);
|
||||||
|
if (ret < 0)
|
||||||
|
goto error;
|
||||||
|
ret = dshow_add_device(avctx, ap, AudioDevice);
|
||||||
|
if (ret < 0)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->mutex = CreateMutex(NULL, 0, NULL);
|
||||||
|
if (!ctx->mutex) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Could not create Mutex\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
ctx->event = CreateEvent(NULL, 1, 0, NULL);
|
||||||
|
if (!ctx->event) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Could not create Event\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = IGraphBuilder_QueryInterface(graph, &IID_IMediaControl, (void **) &control);
|
||||||
|
if (r != S_OK) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Could not get media control.\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
ctx->control = control;
|
||||||
|
|
||||||
|
r = IMediaControl_Run(control);
|
||||||
|
if (r == S_FALSE) {
|
||||||
|
OAFilterState pfs;
|
||||||
|
r = IMediaControl_GetState(control, 0, &pfs);
|
||||||
|
}
|
||||||
|
if (r != S_OK) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Could not run filter\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
dshow_read_close(avctx);
|
||||||
|
|
||||||
|
if (devenum)
|
||||||
|
ICreateDevEnum_Release(devenum);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dshow_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||||
|
{
|
||||||
|
struct dshow_ctx *ctx = s->priv_data;
|
||||||
|
AVPacketList *pktl = NULL;
|
||||||
|
|
||||||
|
while (!pktl) {
|
||||||
|
WaitForSingleObject(ctx->mutex, INFINITE);
|
||||||
|
pktl = ctx->pktl;
|
||||||
|
if (ctx->pktl) {
|
||||||
|
*pkt = ctx->pktl->pkt;
|
||||||
|
ctx->pktl = ctx->pktl->next;
|
||||||
|
av_free(pktl);
|
||||||
|
}
|
||||||
|
ResetEvent(ctx->event);
|
||||||
|
ReleaseMutex(ctx->mutex);
|
||||||
|
if (!pktl) {
|
||||||
|
if (s->flags & AVFMT_FLAG_NONBLOCK) {
|
||||||
|
return AVERROR(EAGAIN);
|
||||||
|
} else {
|
||||||
|
WaitForSingleObject(ctx->event, INFINITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->curbufsize -= pkt->size;
|
||||||
|
|
||||||
|
return pkt->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVInputFormat dshow_demuxer = {
|
||||||
|
"dshow",
|
||||||
|
NULL_IF_CONFIG_SMALL("DirectShow capture"),
|
||||||
|
sizeof(struct dshow_ctx),
|
||||||
|
NULL,
|
||||||
|
dshow_read_header,
|
||||||
|
dshow_read_packet,
|
||||||
|
dshow_read_close,
|
||||||
|
.flags = AVFMT_NOFILE,
|
||||||
|
};
|
266
libavdevice/dshow.h
Normal file
266
libavdevice/dshow.h
Normal file
|
@ -0,0 +1,266 @@
|
||||||
|
/*
|
||||||
|
* DirectShow capture interface
|
||||||
|
* Copyright (c) 2010 Ramiro Polla
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DSHOWDEBUG 0
|
||||||
|
|
||||||
|
#include "libavformat/avformat.h"
|
||||||
|
|
||||||
|
#define COBJMACROS
|
||||||
|
#include <windows.h>
|
||||||
|
#include <dshow.h>
|
||||||
|
#include <dvdmedia.h>
|
||||||
|
|
||||||
|
long ff_copy_dshow_media_type(AM_MEDIA_TYPE *dst, const AM_MEDIA_TYPE *src);
|
||||||
|
void ff_print_AM_MEDIA_TYPE(const AM_MEDIA_TYPE *type);
|
||||||
|
void ff_printGUID(const GUID *g);
|
||||||
|
|
||||||
|
#if DSHOWDEBUG
|
||||||
|
extern const AVClass *ff_dshow_context_class_ptr;
|
||||||
|
#define dshowdebug(...) av_log(&ff_dshow_context_class_ptr, AV_LOG_DEBUG, __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define dshowdebug(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void nothing(void *foo)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GUIDoffset {
|
||||||
|
const GUID *iid;
|
||||||
|
int offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum dshowDeviceType {
|
||||||
|
VideoDevice = 0,
|
||||||
|
AudioDevice = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DECLARE_QUERYINTERFACE(class, ...) \
|
||||||
|
long WINAPI \
|
||||||
|
class##_QueryInterface(class *this, const GUID *riid, void **ppvObject) \
|
||||||
|
{ \
|
||||||
|
struct GUIDoffset ifaces[] = __VA_ARGS__; \
|
||||||
|
int i; \
|
||||||
|
dshowdebug(AV_STRINGIFY(class)"_QueryInterface(%p, %p, %p)\n", this, riid, ppvObject); \
|
||||||
|
ff_printGUID(riid); \
|
||||||
|
if (!ppvObject) \
|
||||||
|
return E_POINTER; \
|
||||||
|
for (i = 0; i < sizeof(ifaces)/sizeof(ifaces[0]); i++) { \
|
||||||
|
if (IsEqualGUID(riid, ifaces[i].iid)) { \
|
||||||
|
void *obj = (void *) ((uint8_t *) this + ifaces[i].offset); \
|
||||||
|
class##_AddRef(this); \
|
||||||
|
dshowdebug("\tfound %d with offset %d\n", i, ifaces[i].offset); \
|
||||||
|
*ppvObject = (void *) obj; \
|
||||||
|
return S_OK; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
dshowdebug("\tE_NOINTERFACE\n"); \
|
||||||
|
*ppvObject = NULL; \
|
||||||
|
return E_NOINTERFACE; \
|
||||||
|
}
|
||||||
|
#define DECLARE_ADDREF(class) \
|
||||||
|
unsigned long WINAPI \
|
||||||
|
class##_AddRef(class *this) \
|
||||||
|
{ \
|
||||||
|
dshowdebug(AV_STRINGIFY(class)"_AddRef(%p)\t%ld\n", this, this->ref+1); \
|
||||||
|
return InterlockedIncrement(&this->ref); \
|
||||||
|
}
|
||||||
|
#define DECLARE_RELEASE(class) \
|
||||||
|
unsigned long WINAPI \
|
||||||
|
class##_Release(class *this) \
|
||||||
|
{ \
|
||||||
|
long ref = InterlockedDecrement(&this->ref); \
|
||||||
|
dshowdebug(AV_STRINGIFY(class)"_Release(%p)\t%ld\n", this, ref); \
|
||||||
|
if (!ref) \
|
||||||
|
class##_Destroy(this); \
|
||||||
|
return ref; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DECLARE_DESTROY(class, func) \
|
||||||
|
void class##_Destroy(class *this) \
|
||||||
|
{ \
|
||||||
|
dshowdebug(AV_STRINGIFY(class)"_Destroy(%p)\n", this); \
|
||||||
|
func(this); \
|
||||||
|
if (this) { \
|
||||||
|
if (this->vtbl) \
|
||||||
|
CoTaskMemFree(this->vtbl); \
|
||||||
|
CoTaskMemFree(this); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
#define DECLARE_CREATE(class, setup, ...) \
|
||||||
|
class *class##_Create(__VA_ARGS__) \
|
||||||
|
{ \
|
||||||
|
class *this = CoTaskMemAlloc(sizeof(class)); \
|
||||||
|
void *vtbl = CoTaskMemAlloc(sizeof(*this->vtbl)); \
|
||||||
|
dshowdebug(AV_STRINGIFY(class)"_Create(%p)\n", this); \
|
||||||
|
if (!this || !vtbl) \
|
||||||
|
goto fail; \
|
||||||
|
ZeroMemory(this, sizeof(class)); \
|
||||||
|
ZeroMemory(vtbl, sizeof(*this->vtbl)); \
|
||||||
|
this->ref = 1; \
|
||||||
|
this->vtbl = vtbl; \
|
||||||
|
if (!setup) \
|
||||||
|
goto fail; \
|
||||||
|
dshowdebug("created "AV_STRINGIFY(class)" %p\n", this); \
|
||||||
|
return this; \
|
||||||
|
fail: \
|
||||||
|
class##_Destroy(this); \
|
||||||
|
dshowdebug("could not create "AV_STRINGIFY(class)"\n"); \
|
||||||
|
return NULL; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SETVTBL(vtbl, class, fn) \
|
||||||
|
do { (vtbl)->fn = (void *) class##_##fn; } while(0)
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Forward Declarations
|
||||||
|
****************************************************************************/
|
||||||
|
typedef struct libAVPin libAVPin;
|
||||||
|
typedef struct libAVMemInputPin libAVMemInputPin;
|
||||||
|
typedef struct libAVEnumPins libAVEnumPins;
|
||||||
|
typedef struct libAVEnumMediaTypes libAVEnumMediaTypes;
|
||||||
|
typedef struct libAVFilter libAVFilter;
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* libAVPin
|
||||||
|
****************************************************************************/
|
||||||
|
struct libAVPin {
|
||||||
|
IPinVtbl *vtbl;
|
||||||
|
long ref;
|
||||||
|
libAVFilter *filter;
|
||||||
|
IPin *connectedto;
|
||||||
|
AM_MEDIA_TYPE type;
|
||||||
|
IMemInputPinVtbl *imemvtbl;
|
||||||
|
};
|
||||||
|
|
||||||
|
long WINAPI libAVPin_QueryInterface (libAVPin *, const GUID *, void **);
|
||||||
|
unsigned long WINAPI libAVPin_AddRef (libAVPin *);
|
||||||
|
unsigned long WINAPI libAVPin_Release (libAVPin *);
|
||||||
|
long WINAPI libAVPin_Connect (libAVPin *, IPin *, const AM_MEDIA_TYPE *);
|
||||||
|
long WINAPI libAVPin_ReceiveConnection (libAVPin *, IPin *, const AM_MEDIA_TYPE *);
|
||||||
|
long WINAPI libAVPin_Disconnect (libAVPin *);
|
||||||
|
long WINAPI libAVPin_ConnectedTo (libAVPin *, IPin **);
|
||||||
|
long WINAPI libAVPin_ConnectionMediaType (libAVPin *, AM_MEDIA_TYPE *);
|
||||||
|
long WINAPI libAVPin_QueryPinInfo (libAVPin *, PIN_INFO *);
|
||||||
|
long WINAPI libAVPin_QueryDirection (libAVPin *, PIN_DIRECTION *);
|
||||||
|
long WINAPI libAVPin_QueryId (libAVPin *, wchar_t **);
|
||||||
|
long WINAPI libAVPin_QueryAccept (libAVPin *, const AM_MEDIA_TYPE *);
|
||||||
|
long WINAPI libAVPin_EnumMediaTypes (libAVPin *, IEnumMediaTypes **);
|
||||||
|
long WINAPI libAVPin_QueryInternalConnections(libAVPin *, IPin **, unsigned long *);
|
||||||
|
long WINAPI libAVPin_EndOfStream (libAVPin *);
|
||||||
|
long WINAPI libAVPin_BeginFlush (libAVPin *);
|
||||||
|
long WINAPI libAVPin_EndFlush (libAVPin *);
|
||||||
|
long WINAPI libAVPin_NewSegment (libAVPin *, REFERENCE_TIME, REFERENCE_TIME, double);
|
||||||
|
|
||||||
|
long WINAPI libAVMemInputPin_QueryInterface (libAVMemInputPin *, const GUID *, void **);
|
||||||
|
unsigned long WINAPI libAVMemInputPin_AddRef (libAVMemInputPin *);
|
||||||
|
unsigned long WINAPI libAVMemInputPin_Release (libAVMemInputPin *);
|
||||||
|
long WINAPI libAVMemInputPin_GetAllocator (libAVMemInputPin *, IMemAllocator **);
|
||||||
|
long WINAPI libAVMemInputPin_NotifyAllocator (libAVMemInputPin *, IMemAllocator *, WINBOOL);
|
||||||
|
long WINAPI libAVMemInputPin_GetAllocatorRequirements(libAVMemInputPin *, ALLOCATOR_PROPERTIES *);
|
||||||
|
long WINAPI libAVMemInputPin_Receive (libAVMemInputPin *, IMediaSample *);
|
||||||
|
long WINAPI libAVMemInputPin_ReceiveMultiple (libAVMemInputPin *, IMediaSample **, long, long *);
|
||||||
|
long WINAPI libAVMemInputPin_ReceiveCanBlock (libAVMemInputPin *);
|
||||||
|
|
||||||
|
void libAVPin_Destroy(libAVPin *);
|
||||||
|
libAVPin *libAVPin_Create (libAVFilter *filter);
|
||||||
|
|
||||||
|
void libAVMemInputPin_Destroy(libAVMemInputPin *);
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* libAVEnumPins
|
||||||
|
****************************************************************************/
|
||||||
|
struct libAVEnumPins {
|
||||||
|
IEnumPinsVtbl *vtbl;
|
||||||
|
long ref;
|
||||||
|
int pos;
|
||||||
|
libAVPin *pin;
|
||||||
|
libAVFilter *filter;
|
||||||
|
};
|
||||||
|
|
||||||
|
long WINAPI libAVEnumPins_QueryInterface(libAVEnumPins *, const GUID *, void **);
|
||||||
|
unsigned long WINAPI libAVEnumPins_AddRef (libAVEnumPins *);
|
||||||
|
unsigned long WINAPI libAVEnumPins_Release (libAVEnumPins *);
|
||||||
|
long WINAPI libAVEnumPins_Next (libAVEnumPins *, unsigned long, IPin **, unsigned long *);
|
||||||
|
long WINAPI libAVEnumPins_Skip (libAVEnumPins *, unsigned long);
|
||||||
|
long WINAPI libAVEnumPins_Reset (libAVEnumPins *);
|
||||||
|
long WINAPI libAVEnumPins_Clone (libAVEnumPins *, libAVEnumPins **);
|
||||||
|
|
||||||
|
void libAVEnumPins_Destroy(libAVEnumPins *);
|
||||||
|
libAVEnumPins *libAVEnumPins_Create (libAVPin *pin, libAVFilter *filter);
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* libAVEnumMediaTypes
|
||||||
|
****************************************************************************/
|
||||||
|
struct libAVEnumMediaTypes {
|
||||||
|
IEnumPinsVtbl *vtbl;
|
||||||
|
long ref;
|
||||||
|
int pos;
|
||||||
|
AM_MEDIA_TYPE type;
|
||||||
|
};
|
||||||
|
|
||||||
|
long WINAPI libAVEnumMediaTypes_QueryInterface(libAVEnumMediaTypes *, const GUID *, void **);
|
||||||
|
unsigned long WINAPI libAVEnumMediaTypes_AddRef (libAVEnumMediaTypes *);
|
||||||
|
unsigned long WINAPI libAVEnumMediaTypes_Release (libAVEnumMediaTypes *);
|
||||||
|
long WINAPI libAVEnumMediaTypes_Next (libAVEnumMediaTypes *, unsigned long, AM_MEDIA_TYPE **, unsigned long *);
|
||||||
|
long WINAPI libAVEnumMediaTypes_Skip (libAVEnumMediaTypes *, unsigned long);
|
||||||
|
long WINAPI libAVEnumMediaTypes_Reset (libAVEnumMediaTypes *);
|
||||||
|
long WINAPI libAVEnumMediaTypes_Clone (libAVEnumMediaTypes *, libAVEnumMediaTypes **);
|
||||||
|
|
||||||
|
void libAVEnumMediaTypes_Destroy(libAVEnumMediaTypes *);
|
||||||
|
libAVEnumMediaTypes *libAVEnumMediaTypes_Create(const AM_MEDIA_TYPE *type);
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* libAVFilter
|
||||||
|
****************************************************************************/
|
||||||
|
struct libAVFilter {
|
||||||
|
IBaseFilterVtbl *vtbl;
|
||||||
|
long ref;
|
||||||
|
const wchar_t *name;
|
||||||
|
libAVPin *pin;
|
||||||
|
FILTER_INFO info;
|
||||||
|
FILTER_STATE state;
|
||||||
|
IReferenceClock *clock;
|
||||||
|
enum dshowDeviceType type;
|
||||||
|
void *priv_data;
|
||||||
|
int stream_index;
|
||||||
|
int64_t start_time;
|
||||||
|
void (*callback)(void *priv_data, int index, uint8_t *buf, int buf_size, int64_t time);
|
||||||
|
};
|
||||||
|
|
||||||
|
long WINAPI libAVFilter_QueryInterface (libAVFilter *, const GUID *, void **);
|
||||||
|
unsigned long WINAPI libAVFilter_AddRef (libAVFilter *);
|
||||||
|
unsigned long WINAPI libAVFilter_Release (libAVFilter *);
|
||||||
|
long WINAPI libAVFilter_GetClassID (libAVFilter *, CLSID *);
|
||||||
|
long WINAPI libAVFilter_Stop (libAVFilter *);
|
||||||
|
long WINAPI libAVFilter_Pause (libAVFilter *);
|
||||||
|
long WINAPI libAVFilter_Run (libAVFilter *, REFERENCE_TIME);
|
||||||
|
long WINAPI libAVFilter_GetState (libAVFilter *, DWORD, FILTER_STATE *);
|
||||||
|
long WINAPI libAVFilter_SetSyncSource (libAVFilter *, IReferenceClock *);
|
||||||
|
long WINAPI libAVFilter_GetSyncSource (libAVFilter *, IReferenceClock **);
|
||||||
|
long WINAPI libAVFilter_EnumPins (libAVFilter *, IEnumPins **);
|
||||||
|
long WINAPI libAVFilter_FindPin (libAVFilter *, const wchar_t *, IPin **);
|
||||||
|
long WINAPI libAVFilter_QueryFilterInfo(libAVFilter *, FILTER_INFO *);
|
||||||
|
long WINAPI libAVFilter_JoinFilterGraph(libAVFilter *, IFilterGraph *, const wchar_t *);
|
||||||
|
long WINAPI libAVFilter_QueryVendorInfo(libAVFilter *, wchar_t **);
|
||||||
|
|
||||||
|
void libAVFilter_Destroy(libAVFilter *);
|
||||||
|
libAVFilter *libAVFilter_Create (void *, void *, enum dshowDeviceType);
|
141
libavdevice/dshow_common.c
Normal file
141
libavdevice/dshow_common.c
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
/*
|
||||||
|
* Directshow capture interface
|
||||||
|
* Copyright (c) 2010 Ramiro Polla
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dshow.h"
|
||||||
|
|
||||||
|
long ff_copy_dshow_media_type(AM_MEDIA_TYPE *dst, const AM_MEDIA_TYPE *src)
|
||||||
|
{
|
||||||
|
uint8_t *pbFormat = NULL;
|
||||||
|
|
||||||
|
if (src->cbFormat) {
|
||||||
|
pbFormat = CoTaskMemAlloc(src->cbFormat);
|
||||||
|
if (!pbFormat)
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
memcpy(pbFormat, src->pbFormat, src->cbFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
*dst = *src;
|
||||||
|
dst->pUnk = NULL;
|
||||||
|
dst->pbFormat = pbFormat;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ff_printGUID(const GUID *g)
|
||||||
|
{
|
||||||
|
#if DSHOWDEBUG
|
||||||
|
const uint32_t *d = (const uint32_t *) &g->Data1;
|
||||||
|
const uint16_t *w = (const uint16_t *) &g->Data2;
|
||||||
|
const uint8_t *c = (const uint8_t *) &g->Data4;
|
||||||
|
|
||||||
|
dshowdebug("0x%08x 0x%04x 0x%04x %02x%02x%02x%02x%02x%02x%02x%02x",
|
||||||
|
d[0], w[0], w[1],
|
||||||
|
c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *dshow_context_to_name(void *ptr)
|
||||||
|
{
|
||||||
|
return "dshow";
|
||||||
|
}
|
||||||
|
static const AVClass ff_dshow_context_class = { "DirectShow", dshow_context_to_name };
|
||||||
|
const AVClass *ff_dshow_context_class_ptr = &ff_dshow_context_class;
|
||||||
|
|
||||||
|
#define dstruct(pctx, sname, var, type) \
|
||||||
|
dshowdebug(" "#var":\t%"type"\n", sname->var)
|
||||||
|
|
||||||
|
#if DSHOWDEBUG
|
||||||
|
static void dump_bih(void *s, BITMAPINFOHEADER *bih)
|
||||||
|
{
|
||||||
|
dshowdebug(" BITMAPINFOHEADER\n");
|
||||||
|
dstruct(s, bih, biSize, "lu");
|
||||||
|
dstruct(s, bih, biWidth, "ld");
|
||||||
|
dstruct(s, bih, biHeight, "ld");
|
||||||
|
dstruct(s, bih, biPlanes, "d");
|
||||||
|
dstruct(s, bih, biBitCount, "d");
|
||||||
|
dstruct(s, bih, biCompression, "lu");
|
||||||
|
dshowdebug(" biCompression:\t\"%.4s\"\n",
|
||||||
|
(char*) &bih->biCompression);
|
||||||
|
dstruct(s, bih, biSizeImage, "lu");
|
||||||
|
dstruct(s, bih, biXPelsPerMeter, "lu");
|
||||||
|
dstruct(s, bih, biYPelsPerMeter, "lu");
|
||||||
|
dstruct(s, bih, biClrUsed, "lu");
|
||||||
|
dstruct(s, bih, biClrImportant, "lu");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void ff_print_AM_MEDIA_TYPE(const AM_MEDIA_TYPE *type)
|
||||||
|
{
|
||||||
|
#if DSHOWDEBUG
|
||||||
|
dshowdebug(" majortype\t");
|
||||||
|
ff_printGUID(&type->majortype);
|
||||||
|
dshowdebug("\n");
|
||||||
|
dshowdebug(" subtype\t");
|
||||||
|
ff_printGUID(&type->subtype);
|
||||||
|
dshowdebug("\n");
|
||||||
|
dshowdebug(" bFixedSizeSamples\t%d\n", type->bFixedSizeSamples);
|
||||||
|
dshowdebug(" bTemporalCompression\t%d\n", type->bTemporalCompression);
|
||||||
|
dshowdebug(" lSampleSize\t%lu\n", type->lSampleSize);
|
||||||
|
dshowdebug(" formattype\t");
|
||||||
|
ff_printGUID(&type->formattype);
|
||||||
|
dshowdebug("\n");
|
||||||
|
dshowdebug(" pUnk\t%p\n", type->pUnk);
|
||||||
|
dshowdebug(" cbFormat\t%lu\n", type->cbFormat);
|
||||||
|
dshowdebug(" pbFormat\t%p\n", type->pbFormat);
|
||||||
|
|
||||||
|
if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo)) {
|
||||||
|
VIDEOINFOHEADER *v = (void *) type->pbFormat;
|
||||||
|
dshowdebug(" rcSource: left %ld top %ld right %ld bottom %ld\n",
|
||||||
|
v->rcSource.left, v->rcSource.top, v->rcSource.right, v->rcSource.bottom);
|
||||||
|
dshowdebug(" rcTarget: left %ld top %ld right %ld bottom %ld\n",
|
||||||
|
v->rcTarget.left, v->rcTarget.top, v->rcTarget.right, v->rcTarget.bottom);
|
||||||
|
dshowdebug(" dwBitRate: %lu\n", v->dwBitRate);
|
||||||
|
dshowdebug(" dwBitErrorRate: %lu\n", v->dwBitErrorRate);
|
||||||
|
dshowdebug(" AvgTimePerFrame: %"PRId64"\n", v->AvgTimePerFrame);
|
||||||
|
dump_bih(NULL, &v->bmiHeader);
|
||||||
|
} else if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo2)) {
|
||||||
|
VIDEOINFOHEADER2 *v = (void *) type->pbFormat;
|
||||||
|
dshowdebug(" rcSource: left %ld top %ld right %ld bottom %ld\n",
|
||||||
|
v->rcSource.left, v->rcSource.top, v->rcSource.right, v->rcSource.bottom);
|
||||||
|
dshowdebug(" rcTarget: left %ld top %ld right %ld bottom %ld\n",
|
||||||
|
v->rcTarget.left, v->rcTarget.top, v->rcTarget.right, v->rcTarget.bottom);
|
||||||
|
dshowdebug(" dwBitRate: %lu\n", v->dwBitRate);
|
||||||
|
dshowdebug(" dwBitErrorRate: %lu\n", v->dwBitErrorRate);
|
||||||
|
dshowdebug(" AvgTimePerFrame: %"PRId64"\n", v->AvgTimePerFrame);
|
||||||
|
dshowdebug(" dwInterlaceFlags: %lu\n", v->dwInterlaceFlags);
|
||||||
|
dshowdebug(" dwCopyProtectFlags: %lu\n", v->dwCopyProtectFlags);
|
||||||
|
dshowdebug(" dwPictAspectRatioX: %lu\n", v->dwPictAspectRatioX);
|
||||||
|
dshowdebug(" dwPictAspectRatioY: %lu\n", v->dwPictAspectRatioY);
|
||||||
|
// dshowdebug(" dwReserved1: %lu\n", v->u.dwReserved1); /* mingw-w64 is buggy and doesn't name unnamed unions */
|
||||||
|
dshowdebug(" dwReserved2: %lu\n", v->dwReserved2);
|
||||||
|
dump_bih(NULL, &v->bmiHeader);
|
||||||
|
} else if (IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx)) {
|
||||||
|
WAVEFORMATEX *fx = (void *) type->pbFormat;
|
||||||
|
dshowdebug(" wFormatTag: %u\n", fx->wFormatTag);
|
||||||
|
dshowdebug(" nChannels: %u\n", fx->nChannels);
|
||||||
|
dshowdebug(" nSamplesPerSec: %lu\n", fx->nSamplesPerSec);
|
||||||
|
dshowdebug(" nAvgBytesPerSec: %lu\n", fx->nAvgBytesPerSec);
|
||||||
|
dshowdebug(" nBlockAlign: %u\n", fx->nBlockAlign);
|
||||||
|
dshowdebug(" wBitsPerSample: %u\n", fx->wBitsPerSample);
|
||||||
|
dshowdebug(" cbSize: %u\n", fx->cbSize);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
103
libavdevice/dshow_enummediatypes.c
Normal file
103
libavdevice/dshow_enummediatypes.c
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* DirectShow capture interface
|
||||||
|
* Copyright (c) 2010 Ramiro Polla
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dshow.h"
|
||||||
|
|
||||||
|
DECLARE_QUERYINTERFACE(libAVEnumMediaTypes,
|
||||||
|
{ {&IID_IUnknown,0}, {&IID_IEnumPins,0} })
|
||||||
|
DECLARE_ADDREF(libAVEnumMediaTypes)
|
||||||
|
DECLARE_RELEASE(libAVEnumMediaTypes)
|
||||||
|
|
||||||
|
long WINAPI
|
||||||
|
libAVEnumMediaTypes_Next(libAVEnumMediaTypes *this, unsigned long n,
|
||||||
|
AM_MEDIA_TYPE **types, unsigned long *fetched)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
dshowdebug("libAVEnumMediaTypes_Next(%p)\n", this);
|
||||||
|
if (!types)
|
||||||
|
return E_POINTER;
|
||||||
|
if (!this->pos && n == 1) {
|
||||||
|
if (!IsEqualGUID(&this->type.majortype, &GUID_NULL)) {
|
||||||
|
AM_MEDIA_TYPE *type = av_malloc(sizeof(AM_MEDIA_TYPE));
|
||||||
|
ff_copy_dshow_media_type(type, &this->type);
|
||||||
|
*types = type;
|
||||||
|
count = 1;
|
||||||
|
}
|
||||||
|
this->pos = 1;
|
||||||
|
}
|
||||||
|
if (fetched)
|
||||||
|
*fetched = count;
|
||||||
|
if (!count)
|
||||||
|
return S_FALSE;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVEnumMediaTypes_Skip(libAVEnumMediaTypes *this, unsigned long n)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVEnumMediaTypes_Skip(%p)\n", this);
|
||||||
|
if (n) /* Any skip will always fall outside of the only valid type. */
|
||||||
|
return S_FALSE;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVEnumMediaTypes_Reset(libAVEnumMediaTypes *this)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVEnumMediaTypes_Reset(%p)\n", this);
|
||||||
|
this->pos = 0;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVEnumMediaTypes_Clone(libAVEnumMediaTypes *this, libAVEnumMediaTypes **enums)
|
||||||
|
{
|
||||||
|
libAVEnumMediaTypes *new;
|
||||||
|
dshowdebug("libAVEnumMediaTypes_Clone(%p)\n", this);
|
||||||
|
if (!enums)
|
||||||
|
return E_POINTER;
|
||||||
|
new = libAVEnumMediaTypes_Create(&this->type);
|
||||||
|
if (!new)
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
new->pos = this->pos;
|
||||||
|
*enums = new;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
libAVEnumMediaTypes_Setup(libAVEnumMediaTypes *this, const AM_MEDIA_TYPE *type)
|
||||||
|
{
|
||||||
|
IEnumPinsVtbl *vtbl = this->vtbl;
|
||||||
|
SETVTBL(vtbl, libAVEnumMediaTypes, QueryInterface);
|
||||||
|
SETVTBL(vtbl, libAVEnumMediaTypes, AddRef);
|
||||||
|
SETVTBL(vtbl, libAVEnumMediaTypes, Release);
|
||||||
|
SETVTBL(vtbl, libAVEnumMediaTypes, Next);
|
||||||
|
SETVTBL(vtbl, libAVEnumMediaTypes, Skip);
|
||||||
|
SETVTBL(vtbl, libAVEnumMediaTypes, Reset);
|
||||||
|
SETVTBL(vtbl, libAVEnumMediaTypes, Clone);
|
||||||
|
|
||||||
|
if (!type) {
|
||||||
|
this->type.majortype = GUID_NULL;
|
||||||
|
} else {
|
||||||
|
ff_copy_dshow_media_type(&this->type, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
DECLARE_CREATE(libAVEnumMediaTypes, libAVEnumMediaTypes_Setup(this, type), const AM_MEDIA_TYPE *type)
|
||||||
|
DECLARE_DESTROY(libAVEnumMediaTypes, nothing)
|
99
libavdevice/dshow_enumpins.c
Normal file
99
libavdevice/dshow_enumpins.c
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
* DirectShow capture interface
|
||||||
|
* Copyright (c) 2010 Ramiro Polla
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dshow.h"
|
||||||
|
|
||||||
|
DECLARE_QUERYINTERFACE(libAVEnumPins,
|
||||||
|
{ {&IID_IUnknown,0}, {&IID_IEnumPins,0} })
|
||||||
|
DECLARE_ADDREF(libAVEnumPins)
|
||||||
|
DECLARE_RELEASE(libAVEnumPins)
|
||||||
|
|
||||||
|
long WINAPI
|
||||||
|
libAVEnumPins_Next(libAVEnumPins *this, unsigned long n, IPin **pins,
|
||||||
|
unsigned long *fetched)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
dshowdebug("libAVEnumPins_Next(%p)\n", this);
|
||||||
|
if (!pins)
|
||||||
|
return E_POINTER;
|
||||||
|
if (!this->pos && n == 1) {
|
||||||
|
libAVPin_AddRef(this->pin);
|
||||||
|
*pins = (IPin *) this->pin;
|
||||||
|
count = 1;
|
||||||
|
this->pos = 1;
|
||||||
|
}
|
||||||
|
if (fetched)
|
||||||
|
*fetched = count;
|
||||||
|
if (!count)
|
||||||
|
return S_FALSE;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVEnumPins_Skip(libAVEnumPins *this, unsigned long n)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVEnumPins_Skip(%p)\n", this);
|
||||||
|
if (n) /* Any skip will always fall outside of the only valid pin. */
|
||||||
|
return S_FALSE;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVEnumPins_Reset(libAVEnumPins *this)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVEnumPins_Reset(%p)\n", this);
|
||||||
|
this->pos = 0;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVEnumPins_Clone(libAVEnumPins *this, libAVEnumPins **pins)
|
||||||
|
{
|
||||||
|
libAVEnumPins *new;
|
||||||
|
dshowdebug("libAVEnumPins_Clone(%p)\n", this);
|
||||||
|
if (!pins)
|
||||||
|
return E_POINTER;
|
||||||
|
new = libAVEnumPins_Create(this->pin, this->filter);
|
||||||
|
if (!new)
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
new->pos = this->pos;
|
||||||
|
*pins = new;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
libAVEnumPins_Setup(libAVEnumPins *this, libAVPin *pin, libAVFilter *filter)
|
||||||
|
{
|
||||||
|
IEnumPinsVtbl *vtbl = this->vtbl;
|
||||||
|
SETVTBL(vtbl, libAVEnumPins, QueryInterface);
|
||||||
|
SETVTBL(vtbl, libAVEnumPins, AddRef);
|
||||||
|
SETVTBL(vtbl, libAVEnumPins, Release);
|
||||||
|
SETVTBL(vtbl, libAVEnumPins, Next);
|
||||||
|
SETVTBL(vtbl, libAVEnumPins, Skip);
|
||||||
|
SETVTBL(vtbl, libAVEnumPins, Reset);
|
||||||
|
SETVTBL(vtbl, libAVEnumPins, Clone);
|
||||||
|
|
||||||
|
this->pin = pin;
|
||||||
|
this->filter = filter;
|
||||||
|
libAVFilter_AddRef(this->filter);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
DECLARE_CREATE(libAVEnumPins, libAVEnumPins_Setup(this, pin, filter),
|
||||||
|
libAVPin *pin, libAVFilter *filter)
|
||||||
|
DECLARE_DESTROY(libAVEnumPins, nothing)
|
196
libavdevice/dshow_filter.c
Normal file
196
libavdevice/dshow_filter.c
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
/*
|
||||||
|
* DirectShow capture interface
|
||||||
|
* Copyright (c) 2010 Ramiro Polla
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dshow.h"
|
||||||
|
|
||||||
|
DECLARE_QUERYINTERFACE(libAVFilter,
|
||||||
|
{ {&IID_IUnknown,0}, {&IID_IBaseFilter,0} })
|
||||||
|
DECLARE_ADDREF(libAVFilter)
|
||||||
|
DECLARE_RELEASE(libAVFilter)
|
||||||
|
|
||||||
|
long WINAPI
|
||||||
|
libAVFilter_GetClassID(libAVFilter *this, CLSID *id)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVFilter_GetClassID(%p)\n", this);
|
||||||
|
/* I'm not creating a ClassID just for this. */
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVFilter_Stop(libAVFilter *this)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVFilter_Stop(%p)\n", this);
|
||||||
|
this->state = State_Stopped;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVFilter_Pause(libAVFilter *this)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVFilter_Pause(%p)\n", this);
|
||||||
|
this->state = State_Paused;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVFilter_Run(libAVFilter *this, REFERENCE_TIME start)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVFilter_Run(%p) %"PRId64"\n", this, start);
|
||||||
|
this->state = State_Running;
|
||||||
|
this->start_time = start;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVFilter_GetState(libAVFilter *this, DWORD ms, FILTER_STATE *state)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVFilter_GetState(%p)\n", this);
|
||||||
|
if (!state)
|
||||||
|
return E_POINTER;
|
||||||
|
*state = this->state;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVFilter_SetSyncSource(libAVFilter *this, IReferenceClock *clock)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVFilter_SetSyncSource(%p)\n", this);
|
||||||
|
|
||||||
|
if (this->clock != clock) {
|
||||||
|
if (this->clock)
|
||||||
|
IReferenceClock_Release(this->clock);
|
||||||
|
this->clock = clock;
|
||||||
|
if (clock)
|
||||||
|
IReferenceClock_AddRef(clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVFilter_GetSyncSource(libAVFilter *this, IReferenceClock **clock)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVFilter_GetSyncSource(%p)\n", this);
|
||||||
|
|
||||||
|
if (!clock)
|
||||||
|
return E_POINTER;
|
||||||
|
if (this->clock)
|
||||||
|
IReferenceClock_AddRef(this->clock);
|
||||||
|
*clock = this->clock;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVFilter_EnumPins(libAVFilter *this, IEnumPins **enumpin)
|
||||||
|
{
|
||||||
|
libAVEnumPins *new;
|
||||||
|
dshowdebug("libAVFilter_EnumPins(%p)\n", this);
|
||||||
|
|
||||||
|
if (!enumpin)
|
||||||
|
return E_POINTER;
|
||||||
|
new = libAVEnumPins_Create(this->pin, this);
|
||||||
|
if (!new)
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
|
||||||
|
*enumpin = (IEnumPins *) new;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVFilter_FindPin(libAVFilter *this, const wchar_t *id, IPin **pin)
|
||||||
|
{
|
||||||
|
libAVPin *found = NULL;
|
||||||
|
dshowdebug("libAVFilter_FindPin(%p)\n", this);
|
||||||
|
|
||||||
|
if (!id || !pin)
|
||||||
|
return E_POINTER;
|
||||||
|
if (!wcscmp(id, L"In")) {
|
||||||
|
found = this->pin;
|
||||||
|
libAVPin_AddRef(found);
|
||||||
|
}
|
||||||
|
*pin = (IPin *) found;
|
||||||
|
if (!found)
|
||||||
|
return VFW_E_NOT_FOUND;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVFilter_QueryFilterInfo(libAVFilter *this, FILTER_INFO *info)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVFilter_QueryFilterInfo(%p)\n", this);
|
||||||
|
|
||||||
|
if (!info)
|
||||||
|
return E_POINTER;
|
||||||
|
if (this->info.pGraph)
|
||||||
|
IFilterGraph_AddRef(this->info.pGraph);
|
||||||
|
*info = this->info;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVFilter_JoinFilterGraph(libAVFilter *this, IFilterGraph *graph,
|
||||||
|
const wchar_t *name)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVFilter_JoinFilterGraph(%p)\n", this);
|
||||||
|
|
||||||
|
this->info.pGraph = graph;
|
||||||
|
if (name)
|
||||||
|
wcscpy(this->info.achName, name);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVFilter_QueryVendorInfo(libAVFilter *this, wchar_t **info)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVFilter_QueryVendorInfo(%p)\n", this);
|
||||||
|
|
||||||
|
if (!info)
|
||||||
|
return E_POINTER;
|
||||||
|
*info = wcsdup(L"libAV");
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
libAVFilter_Setup(libAVFilter *this, void *priv_data, void *callback,
|
||||||
|
enum dshowDeviceType type)
|
||||||
|
{
|
||||||
|
IBaseFilterVtbl *vtbl = this->vtbl;
|
||||||
|
SETVTBL(vtbl, libAVFilter, QueryInterface);
|
||||||
|
SETVTBL(vtbl, libAVFilter, AddRef);
|
||||||
|
SETVTBL(vtbl, libAVFilter, Release);
|
||||||
|
SETVTBL(vtbl, libAVFilter, GetClassID);
|
||||||
|
SETVTBL(vtbl, libAVFilter, Stop);
|
||||||
|
SETVTBL(vtbl, libAVFilter, Pause);
|
||||||
|
SETVTBL(vtbl, libAVFilter, Run);
|
||||||
|
SETVTBL(vtbl, libAVFilter, GetState);
|
||||||
|
SETVTBL(vtbl, libAVFilter, SetSyncSource);
|
||||||
|
SETVTBL(vtbl, libAVFilter, GetSyncSource);
|
||||||
|
SETVTBL(vtbl, libAVFilter, EnumPins);
|
||||||
|
SETVTBL(vtbl, libAVFilter, FindPin);
|
||||||
|
SETVTBL(vtbl, libAVFilter, QueryFilterInfo);
|
||||||
|
SETVTBL(vtbl, libAVFilter, JoinFilterGraph);
|
||||||
|
SETVTBL(vtbl, libAVFilter, QueryVendorInfo);
|
||||||
|
|
||||||
|
this->pin = libAVPin_Create(this);
|
||||||
|
|
||||||
|
this->priv_data = priv_data;
|
||||||
|
this->callback = callback;
|
||||||
|
this->type = type;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
DECLARE_CREATE(libAVFilter, libAVFilter_Setup(this, priv_data, callback, type),
|
||||||
|
void *priv_data, void *callback, enum dshowDeviceType type)
|
||||||
|
DECLARE_DESTROY(libAVFilter, nothing)
|
361
libavdevice/dshow_pin.c
Normal file
361
libavdevice/dshow_pin.c
Normal file
|
@ -0,0 +1,361 @@
|
||||||
|
/*
|
||||||
|
* DirectShow capture interface
|
||||||
|
* Copyright (c) 2010 Ramiro Polla
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dshow.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#define imemoffset offsetof(libAVPin, imemvtbl)
|
||||||
|
|
||||||
|
DECLARE_QUERYINTERFACE(libAVPin,
|
||||||
|
{ {&IID_IUnknown,0}, {&IID_IPin,0}, {&IID_IMemInputPin,imemoffset} })
|
||||||
|
DECLARE_ADDREF(libAVPin)
|
||||||
|
DECLARE_RELEASE(libAVPin)
|
||||||
|
|
||||||
|
long WINAPI
|
||||||
|
libAVPin_Connect(libAVPin *this, IPin *pin, const AM_MEDIA_TYPE *type)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVPin_Connect(%p, %p, %p)\n", this, pin, type);
|
||||||
|
/* Input pins receive connections. */
|
||||||
|
return S_FALSE;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVPin_ReceiveConnection(libAVPin *this, IPin *pin,
|
||||||
|
const AM_MEDIA_TYPE *type)
|
||||||
|
{
|
||||||
|
enum dshowDeviceType devtype = this->filter->type;
|
||||||
|
dshowdebug("libAVPin_ReceiveConnection(%p)\n", this);
|
||||||
|
|
||||||
|
if (!pin)
|
||||||
|
return E_POINTER;
|
||||||
|
if (this->connectedto)
|
||||||
|
return VFW_E_ALREADY_CONNECTED;
|
||||||
|
|
||||||
|
ff_print_AM_MEDIA_TYPE(type);
|
||||||
|
if (devtype == VideoDevice) {
|
||||||
|
if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video))
|
||||||
|
return VFW_E_TYPE_NOT_ACCEPTED;
|
||||||
|
} else {
|
||||||
|
if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Audio))
|
||||||
|
return VFW_E_TYPE_NOT_ACCEPTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPin_AddRef(pin);
|
||||||
|
this->connectedto = pin;
|
||||||
|
|
||||||
|
ff_copy_dshow_media_type(&this->type, type);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVPin_Disconnect(libAVPin *this)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVPin_Disconnect(%p)\n", this);
|
||||||
|
|
||||||
|
if (this->filter->state != State_Stopped)
|
||||||
|
return VFW_E_NOT_STOPPED;
|
||||||
|
if (!this->connectedto)
|
||||||
|
return S_FALSE;
|
||||||
|
this->connectedto = NULL;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVPin_ConnectedTo(libAVPin *this, IPin **pin)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVPin_ConnectedTo(%p)\n", this);
|
||||||
|
|
||||||
|
if (!pin)
|
||||||
|
return E_POINTER;
|
||||||
|
if (!this->connectedto)
|
||||||
|
return VFW_E_NOT_CONNECTED;
|
||||||
|
IPin_AddRef(this->connectedto);
|
||||||
|
*pin = this->connectedto;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVPin_ConnectionMediaType(libAVPin *this, AM_MEDIA_TYPE *type)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVPin_ConnectionMediaType(%p)\n", this);
|
||||||
|
|
||||||
|
if (!type)
|
||||||
|
return E_POINTER;
|
||||||
|
if (!this->connectedto)
|
||||||
|
return VFW_E_NOT_CONNECTED;
|
||||||
|
|
||||||
|
return ff_copy_dshow_media_type(type, &this->type);
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVPin_QueryPinInfo(libAVPin *this, PIN_INFO *info)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVPin_QueryPinInfo(%p)\n", this);
|
||||||
|
|
||||||
|
if (!info)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
if (this->filter)
|
||||||
|
libAVFilter_AddRef(this->filter);
|
||||||
|
|
||||||
|
info->pFilter = (IBaseFilter *) this->filter;
|
||||||
|
info->dir = PINDIR_INPUT;
|
||||||
|
wcscpy(info->achName, L"Capture");
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVPin_QueryDirection(libAVPin *this, PIN_DIRECTION *dir)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVPin_QueryDirection(%p)\n", this);
|
||||||
|
if (!dir)
|
||||||
|
return E_POINTER;
|
||||||
|
*dir = PINDIR_INPUT;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVPin_QueryId(libAVPin *this, wchar_t **id)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVPin_QueryId(%p)\n", this);
|
||||||
|
|
||||||
|
if (!id)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
*id = wcsdup(L"libAV Pin");
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVPin_QueryAccept(libAVPin *this, const AM_MEDIA_TYPE *type)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVPin_QueryAccept(%p)\n", this);
|
||||||
|
return S_FALSE;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVPin_EnumMediaTypes(libAVPin *this, IEnumMediaTypes **enumtypes)
|
||||||
|
{
|
||||||
|
const AM_MEDIA_TYPE *type = NULL;
|
||||||
|
libAVEnumMediaTypes *new;
|
||||||
|
dshowdebug("libAVPin_EnumMediaTypes(%p)\n", this);
|
||||||
|
|
||||||
|
if (!enumtypes)
|
||||||
|
return E_POINTER;
|
||||||
|
new = libAVEnumMediaTypes_Create(type);
|
||||||
|
if (!new)
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
|
||||||
|
*enumtypes = (IEnumMediaTypes *) new;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVPin_QueryInternalConnections(libAVPin *this, IPin **pin,
|
||||||
|
unsigned long *npin)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVPin_QueryInternalConnections(%p)\n", this);
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVPin_EndOfStream(libAVPin *this)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVPin_EndOfStream(%p)\n", this);
|
||||||
|
/* I don't care. */
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVPin_BeginFlush(libAVPin *this)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVPin_BeginFlush(%p)\n", this);
|
||||||
|
/* I don't care. */
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVPin_EndFlush(libAVPin *this)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVPin_EndFlush(%p)\n", this);
|
||||||
|
/* I don't care. */
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVPin_NewSegment(libAVPin *this, REFERENCE_TIME start, REFERENCE_TIME stop,
|
||||||
|
double rate)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVPin_NewSegment(%p)\n", this);
|
||||||
|
/* I don't care. */
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
libAVPin_Setup(libAVPin *this, libAVFilter *filter)
|
||||||
|
{
|
||||||
|
IPinVtbl *vtbl = this->vtbl;
|
||||||
|
IMemInputPinVtbl *imemvtbl;
|
||||||
|
|
||||||
|
if (!filter)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
imemvtbl = av_malloc(sizeof(IMemInputPinVtbl));
|
||||||
|
if (!imemvtbl)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
SETVTBL(imemvtbl, libAVMemInputPin, QueryInterface);
|
||||||
|
SETVTBL(imemvtbl, libAVMemInputPin, AddRef);
|
||||||
|
SETVTBL(imemvtbl, libAVMemInputPin, Release);
|
||||||
|
SETVTBL(imemvtbl, libAVMemInputPin, GetAllocator);
|
||||||
|
SETVTBL(imemvtbl, libAVMemInputPin, NotifyAllocator);
|
||||||
|
SETVTBL(imemvtbl, libAVMemInputPin, GetAllocatorRequirements);
|
||||||
|
SETVTBL(imemvtbl, libAVMemInputPin, Receive);
|
||||||
|
SETVTBL(imemvtbl, libAVMemInputPin, ReceiveMultiple);
|
||||||
|
SETVTBL(imemvtbl, libAVMemInputPin, ReceiveCanBlock);
|
||||||
|
|
||||||
|
this->imemvtbl = imemvtbl;
|
||||||
|
|
||||||
|
SETVTBL(vtbl, libAVPin, QueryInterface);
|
||||||
|
SETVTBL(vtbl, libAVPin, AddRef);
|
||||||
|
SETVTBL(vtbl, libAVPin, Release);
|
||||||
|
SETVTBL(vtbl, libAVPin, Connect);
|
||||||
|
SETVTBL(vtbl, libAVPin, ReceiveConnection);
|
||||||
|
SETVTBL(vtbl, libAVPin, Disconnect);
|
||||||
|
SETVTBL(vtbl, libAVPin, ConnectedTo);
|
||||||
|
SETVTBL(vtbl, libAVPin, ConnectionMediaType);
|
||||||
|
SETVTBL(vtbl, libAVPin, QueryPinInfo);
|
||||||
|
SETVTBL(vtbl, libAVPin, QueryDirection);
|
||||||
|
SETVTBL(vtbl, libAVPin, QueryId);
|
||||||
|
SETVTBL(vtbl, libAVPin, QueryAccept);
|
||||||
|
SETVTBL(vtbl, libAVPin, EnumMediaTypes);
|
||||||
|
SETVTBL(vtbl, libAVPin, QueryInternalConnections);
|
||||||
|
SETVTBL(vtbl, libAVPin, EndOfStream);
|
||||||
|
SETVTBL(vtbl, libAVPin, BeginFlush);
|
||||||
|
SETVTBL(vtbl, libAVPin, EndFlush);
|
||||||
|
SETVTBL(vtbl, libAVPin, NewSegment);
|
||||||
|
|
||||||
|
this->filter = filter;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
DECLARE_CREATE(libAVPin, libAVPin_Setup(this, filter), libAVFilter *filter)
|
||||||
|
DECLARE_DESTROY(libAVPin, nothing)
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* libAVMemInputPin
|
||||||
|
****************************************************************************/
|
||||||
|
long WINAPI
|
||||||
|
libAVMemInputPin_QueryInterface(libAVMemInputPin *this, const GUID *riid,
|
||||||
|
void **ppvObject)
|
||||||
|
{
|
||||||
|
libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
|
||||||
|
dshowdebug("libAVMemInputPin_QueryInterface(%p)\n", this);
|
||||||
|
return libAVPin_QueryInterface(pin, riid, ppvObject);
|
||||||
|
}
|
||||||
|
unsigned long WINAPI
|
||||||
|
libAVMemInputPin_AddRef(libAVMemInputPin *this)
|
||||||
|
{
|
||||||
|
libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
|
||||||
|
dshowdebug("libAVMemInputPin_AddRef(%p)\n", this);
|
||||||
|
return libAVPin_AddRef(pin);
|
||||||
|
}
|
||||||
|
unsigned long WINAPI
|
||||||
|
libAVMemInputPin_Release(libAVMemInputPin *this)
|
||||||
|
{
|
||||||
|
libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
|
||||||
|
dshowdebug("libAVMemInputPin_Release(%p)\n", this);
|
||||||
|
return libAVPin_Release(pin);
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVMemInputPin_GetAllocator(libAVMemInputPin *this, IMemAllocator **alloc)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVMemInputPin_GetAllocator(%p)\n", this);
|
||||||
|
return VFW_E_NO_ALLOCATOR;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVMemInputPin_NotifyAllocator(libAVMemInputPin *this, IMemAllocator *alloc,
|
||||||
|
WINBOOL rdwr)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVMemInputPin_NotifyAllocator(%p)\n", this);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVMemInputPin_GetAllocatorRequirements(libAVMemInputPin *this,
|
||||||
|
ALLOCATOR_PROPERTIES *props)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVMemInputPin_GetAllocatorRequirements(%p)\n", this);
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVMemInputPin_Receive(libAVMemInputPin *this, IMediaSample *sample)
|
||||||
|
{
|
||||||
|
libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
|
||||||
|
enum dshowDeviceType devtype = pin->filter->type;
|
||||||
|
void *priv_data;
|
||||||
|
uint8_t *buf;
|
||||||
|
int buf_size;
|
||||||
|
int index;
|
||||||
|
int64_t curtime;
|
||||||
|
|
||||||
|
dshowdebug("libAVMemInputPin_Receive(%p)\n", this);
|
||||||
|
|
||||||
|
if (!sample)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
if (devtype == VideoDevice) {
|
||||||
|
/* PTS from video devices is unreliable. */
|
||||||
|
IReferenceClock *clock = pin->filter->clock;
|
||||||
|
IReferenceClock_GetTime(clock, &curtime);
|
||||||
|
} else {
|
||||||
|
int64_t dummy;
|
||||||
|
IMediaSample_GetTime(sample, &curtime, &dummy);
|
||||||
|
curtime += pin->filter->start_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf_size = IMediaSample_GetActualDataLength(sample);
|
||||||
|
IMediaSample_GetPointer(sample, &buf);
|
||||||
|
priv_data = pin->filter->priv_data;
|
||||||
|
index = pin->filter->stream_index;
|
||||||
|
|
||||||
|
pin->filter->callback(priv_data, index, buf, buf_size, curtime);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVMemInputPin_ReceiveMultiple(libAVMemInputPin *this,
|
||||||
|
IMediaSample **samples, long n, long *nproc)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
dshowdebug("libAVMemInputPin_ReceiveMultiple(%p)\n", this);
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
libAVMemInputPin_Receive(this, samples[i]);
|
||||||
|
|
||||||
|
*nproc = n;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
long WINAPI
|
||||||
|
libAVMemInputPin_ReceiveCanBlock(libAVMemInputPin *this)
|
||||||
|
{
|
||||||
|
dshowdebug("libAVMemInputPin_ReceiveCanBlock(%p)\n", this);
|
||||||
|
/* I swear I will not block. */
|
||||||
|
return S_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
libAVMemInputPin_Destroy(libAVMemInputPin *this)
|
||||||
|
{
|
||||||
|
libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
|
||||||
|
dshowdebug("libAVMemInputPin_Destroy(%p)\n", this);
|
||||||
|
return libAVPin_Destroy(pin);
|
||||||
|
}
|
|
@ -29,8 +29,6 @@
|
||||||
* Remove this when MinGW incorporates them. */
|
* Remove this when MinGW incorporates them. */
|
||||||
#define HWND_MESSAGE ((HWND)-3)
|
#define HWND_MESSAGE ((HWND)-3)
|
||||||
|
|
||||||
#define BI_RGB 0
|
|
||||||
|
|
||||||
/* End of missing MinGW defines */
|
/* End of missing MinGW defines */
|
||||||
|
|
||||||
struct vfw_ctx {
|
struct vfw_ctx {
|
||||||
|
|
Loading…
Add table
Reference in a new issue