mirror of https://github.com/FFmpeg/FFmpeg.git
parent
f8c49d02b0
commit
95eb2e3a38
11 changed files with 1820 additions and 2 deletions
@ -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, |
||||
}; |
@ -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); |
@ -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 |
||||
} |
@ -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) |
@ -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) |
@ -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) |
@ -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); |
||||
} |
Loading…
Reference in new issue