DirectShow capture support

Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
Ramiro Polla 2011-05-21 14:24:50 +02:00 committed by Michael Niedermayer
parent f8c49d02b0
commit 95eb2e3a38
11 changed files with 1820 additions and 2 deletions

4
configure vendored
View File

@ -1463,6 +1463,8 @@ w64_demuxer_deps="wav_demuxer"
alsa_indev_deps="alsa_asoundlib_h snd_pcm_htimestamp"
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"
dshow_indev_deps="IBaseFilter"
dshow_indev_extralibs="-lpsapi -lole32 -lstrmiids -luuid"
dv1394_indev_deps="dv1394 dv_demuxer"
fbdev_indev_deps="linux_fb_h"
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
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_header dev/bktr/ioctl_meteor.h &&
check_header dev/bktr/ioctl_bt848.h; } ||

View File

@ -13,6 +13,9 @@ OBJS-$(CONFIG_ALSA_INDEV) += alsa-audio-common.o \
OBJS-$(CONFIG_ALSA_OUTDEV) += alsa-audio-common.o \
alsa-audio-enc.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_FBDEV_INDEV) += fbdev.o
OBJS-$(CONFIG_JACK_INDEV) += jack_audio.o

View File

@ -41,6 +41,7 @@ void avdevice_register_all(void)
/* devices */
REGISTER_INOUTDEV (ALSA, alsa);
REGISTER_INDEV (BKTR, bktr);
REGISTER_INDEV (DSHOW, dshow);
REGISTER_INDEV (DV1394, dv1394);
REGISTER_INDEV (FBDEV, fbdev);
REGISTER_INDEV (JACK, jack);

646
libavdevice/dshow.c Normal file
View 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, &AMPROPSETID_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
View 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
View 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
}

View 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)

View 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
View 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
View 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);
}

View File

@ -29,8 +29,6 @@
* Remove this when MinGW incorporates them. */
#define HWND_MESSAGE ((HWND)-3)
#define BI_RGB 0
/* End of missing MinGW defines */
struct vfw_ctx {