• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • Examples
  • File List
  • Globals

libavdevice/dshow.c

Go to the documentation of this file.
00001 /*
00002  * Directshow capture interface
00003  * Copyright (c) 2010 Ramiro Polla
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00022 #include "libavformat/timefilter.h"
00023 
00024 #include "avdevice.h"
00025 #include "dshow.h"
00026 
00027 struct dshow_ctx {
00028     IGraphBuilder *graph;
00029 
00030     char *device_name[2];
00031 
00032     IBaseFilter *device_filter[2];
00033     IPin        *device_pin[2];
00034     libAVFilter *capture_filter[2];
00035     libAVPin    *capture_pin[2];
00036 
00037     HANDLE mutex;
00038     HANDLE event;
00039     AVPacketList *pktl;
00040 
00041     unsigned int curbufsize;
00042     unsigned int video_frame_num;
00043 
00044     IMediaControl *control;
00045 
00046     TimeFilter *timefilter;
00047 };
00048 
00049 static enum PixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
00050 {
00051     switch(biCompression) {
00052     case MKTAG('U', 'Y', 'V', 'Y'):
00053         return PIX_FMT_UYVY422;
00054     case MKTAG('Y', 'U', 'Y', '2'):
00055         return PIX_FMT_YUYV422;
00056     case MKTAG('I', '4', '2', '0'):
00057         return PIX_FMT_YUV420P;
00058     case BI_RGB:
00059         switch(biBitCount) { /* 1-8 are untested */
00060             case 1:
00061                 return PIX_FMT_MONOWHITE;
00062             case 4:
00063                 return PIX_FMT_RGB4;
00064             case 8:
00065                 return PIX_FMT_RGB8;
00066             case 16:
00067                 return PIX_FMT_RGB555;
00068             case 24:
00069                 return PIX_FMT_BGR24;
00070             case 32:
00071                 return PIX_FMT_RGB32;
00072         }
00073     }
00074     return PIX_FMT_NONE;
00075 }
00076 
00077 static enum CodecID dshow_codecid(DWORD biCompression)
00078 {
00079     switch(biCompression) {
00080     case MKTAG('d', 'v', 's', 'd'):
00081         return CODEC_ID_DVVIDEO;
00082     case MKTAG('M', 'J', 'P', 'G'):
00083     case MKTAG('m', 'j', 'p', 'g'):
00084         return CODEC_ID_MJPEG;
00085     }
00086     return CODEC_ID_NONE;
00087 }
00088 
00089 static int
00090 dshow_read_close(AVFormatContext *s)
00091 {
00092     struct dshow_ctx *ctx = s->priv_data;
00093     AVPacketList *pktl;
00094 
00095     if (ctx->control) {
00096         IMediaControl_Stop(ctx->control);
00097         IMediaControl_Release(ctx->control);
00098     }
00099     if (ctx->graph)
00100         IGraphBuilder_Release(ctx->graph);
00101 
00102     /* FIXME remove filters from graph */
00103     /* FIXME disconnect pins */
00104     if (ctx->capture_pin[VideoDevice])
00105         libAVPin_Release(ctx->capture_pin[VideoDevice]);
00106     if (ctx->capture_pin[AudioDevice])
00107         libAVPin_Release(ctx->capture_pin[AudioDevice]);
00108     if (ctx->capture_filter[VideoDevice])
00109         libAVFilter_Release(ctx->capture_filter[VideoDevice]);
00110     if (ctx->capture_filter[AudioDevice])
00111         libAVFilter_Release(ctx->capture_filter[AudioDevice]);
00112 
00113     if (ctx->device_pin[VideoDevice])
00114         IPin_Release(ctx->device_pin[VideoDevice]);
00115     if (ctx->device_pin[AudioDevice])
00116         IPin_Release(ctx->device_pin[AudioDevice]);
00117     if (ctx->device_filter[VideoDevice])
00118         IBaseFilter_Release(ctx->device_filter[VideoDevice]);
00119     if (ctx->device_filter[AudioDevice])
00120         IBaseFilter_Release(ctx->device_filter[AudioDevice]);
00121 
00122     if (ctx->device_name[0])
00123         av_free(ctx->device_name[0]);
00124     if (ctx->device_name[1])
00125         av_free(ctx->device_name[1]);
00126 
00127     if(ctx->mutex)
00128         CloseHandle(ctx->mutex);
00129     if(ctx->event)
00130         CloseHandle(ctx->event);
00131 
00132     pktl = ctx->pktl;
00133     while (pktl) {
00134         AVPacketList *next = pktl->next;
00135         av_destruct_packet(&pktl->pkt);
00136         av_free(pktl);
00137         pktl = next;
00138     }
00139 
00140     return 0;
00141 }
00142 
00143 static char *dup_wchar_to_utf8(wchar_t *w)
00144 {
00145     char *s = NULL;
00146     int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
00147     s = av_malloc(l);
00148     if (s)
00149         WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
00150     return s;
00151 }
00152 
00153 static int shall_we_drop(AVFormatContext *s)
00154 {
00155     struct dshow_ctx *ctx = s->priv_data;
00156     const uint8_t dropscore[] = {62, 75, 87, 100};
00157     const int ndropscores = FF_ARRAY_ELEMS(dropscore);
00158     unsigned int buffer_fullness = (ctx->curbufsize*100)/s->max_picture_buffer;
00159 
00160     if(dropscore[++ctx->video_frame_num%ndropscores] <= buffer_fullness) {
00161         av_log(s, AV_LOG_ERROR,
00162               "real-time buffer %d%% full! frame dropped!\n", buffer_fullness);
00163         return 1;
00164     }
00165 
00166     return 0;
00167 }
00168 
00169 static void
00170 callback(void *priv_data, int index, uint8_t *buf, int buf_size, int64_t time)
00171 {
00172     AVFormatContext *s = priv_data;
00173     struct dshow_ctx *ctx = s->priv_data;
00174     AVPacketList **ppktl, *pktl_next;
00175 
00176 //    dump_videohdr(s, vdhdr);
00177 
00178     if(shall_we_drop(s))
00179         return;
00180 
00181     WaitForSingleObject(ctx->mutex, INFINITE);
00182 
00183     pktl_next = av_mallocz(sizeof(AVPacketList));
00184     if(!pktl_next)
00185         goto fail;
00186 
00187     if(av_new_packet(&pktl_next->pkt, buf_size) < 0) {
00188         av_free(pktl_next);
00189         goto fail;
00190     }
00191 
00192     pktl_next->pkt.stream_index = index;
00193     pktl_next->pkt.pts = time;
00194     memcpy(pktl_next->pkt.data, buf, buf_size);
00195 
00196     for(ppktl = &ctx->pktl ; *ppktl ; ppktl = &(*ppktl)->next);
00197     *ppktl = pktl_next;
00198 
00199     ctx->curbufsize += buf_size;
00200 
00201     SetEvent(ctx->event);
00202     ReleaseMutex(ctx->mutex);
00203 
00204     return;
00205 fail:
00206     ReleaseMutex(ctx->mutex);
00207     return;
00208 }
00209 
00210 static int
00211 dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
00212                   enum dshowDeviceType devtype)
00213 {
00214     struct dshow_ctx *ctx = avctx->priv_data;
00215     IBaseFilter *device_filter = NULL;
00216     IEnumMoniker *classenum = NULL;
00217     IGraphBuilder *graph = ctx->graph;
00218     IEnumPins *pins = 0;
00219     IMoniker *m = NULL;
00220     IPin *device_pin = NULL;
00221     libAVPin *capture_pin = NULL;
00222     libAVFilter *capture_filter = NULL;
00223     const char *device_name = ctx->device_name[devtype];
00224     int ret = AVERROR(EIO);
00225     IPin *pin;
00226     int r, i;
00227 
00228     const GUID *device_guid[2] = { &CLSID_VideoInputDeviceCategory,
00229                                    &CLSID_AudioInputDeviceCategory };
00230     const GUID *mediatype[2] = { &MEDIATYPE_Video, &MEDIATYPE_Audio };
00231     const char *devtypename = (devtype == VideoDevice) ? "video" : "audio";
00232     const wchar_t *filter_name[2] = { L"Audio capture filter", L"Video capture filter" };
00233 
00234     r = ICreateDevEnum_CreateClassEnumerator(devenum, device_guid[devtype],
00235                                              (IEnumMoniker **) &classenum, 0);
00236     if (r != S_OK) {
00237         av_log(avctx, AV_LOG_ERROR, "Could not enumerate %s devices.\n",
00238                devtypename);
00239         goto error;
00240     }
00241 
00242     while (IEnumMoniker_Next(classenum, 1, &m, NULL) == S_OK && !device_filter) {
00243         IPropertyBag *bag = NULL;
00244         char *buf = NULL;
00245         VARIANT var;
00246 
00247         r = IMoniker_BindToStorage(m, 0, 0, &IID_IPropertyBag, (void *) &bag);
00248         if (r != S_OK)
00249             goto fail1;
00250 
00251         var.vt = VT_BSTR;
00252         r = IPropertyBag_Read(bag, L"FriendlyName", &var, NULL);
00253         if (r != S_OK)
00254             goto fail1;
00255 
00256         buf = dup_wchar_to_utf8(var.bstrVal);
00257 
00258         if (strcmp(device_name, buf))
00259             goto fail1;
00260 
00261         IMoniker_BindToObject(m, 0, 0, &IID_IBaseFilter, (void *) &device_filter);
00262 
00263 fail1:
00264         if (buf)
00265             av_free(buf);
00266         if (bag)
00267             IPropertyBag_Release(bag);
00268         IMoniker_Release(m);
00269     }
00270 
00271     if (!device_filter) {
00272         av_log(avctx, AV_LOG_ERROR, "Could not find %s device.\n",
00273                devtypename);
00274         goto error;
00275     }
00276     ctx->device_filter [devtype] = device_filter;
00277 
00278     r = IGraphBuilder_AddFilter(graph, device_filter, NULL);
00279     if (r != S_OK) {
00280         av_log(avctx, AV_LOG_ERROR, "Could not add device filter to graph.\n");
00281         goto error;
00282     }
00283 
00284     r = IBaseFilter_EnumPins(device_filter, &pins);
00285     if (r != S_OK) {
00286         av_log(avctx, AV_LOG_ERROR, "Could not enumerate pins.\n");
00287         goto error;
00288     }
00289 
00290     i = 0;
00291     while (IEnumPins_Next(pins, 1, &pin, NULL) == S_OK && !device_pin) {
00292         IKsPropertySet *p = NULL;
00293         IEnumMediaTypes *types;
00294         PIN_INFO info = {0};
00295         AM_MEDIA_TYPE *type;
00296         GUID category;
00297         DWORD r2;
00298 
00299         IPin_QueryPinInfo(pin, &info);
00300         IBaseFilter_Release(info.pFilter);
00301 
00302         if (info.dir != PINDIR_OUTPUT)
00303             goto next;
00304         if (IPin_QueryInterface(pin, &IID_IKsPropertySet, (void **) &p) != S_OK)
00305             goto next;
00306         if (IKsPropertySet_Get(p, &AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY,
00307                                NULL, 0, &category, sizeof(GUID), &r2) != S_OK)
00308             goto next;
00309         if (!IsEqualGUID(&category, &PIN_CATEGORY_CAPTURE))
00310             goto next;
00311 
00312         if (IPin_EnumMediaTypes(pin, &types) != S_OK)
00313             goto next;
00314 
00315         IEnumMediaTypes_Reset(types);
00316         while (IEnumMediaTypes_Next(types, 1, &type, NULL) == S_OK && !device_pin) {
00317             if (IsEqualGUID(&type->majortype, mediatype[devtype])) {
00318                 device_pin = pin;
00319                 goto next;
00320             }
00321             CoTaskMemFree(type);
00322         }
00323 
00324 next:
00325         if (types)
00326             IEnumMediaTypes_Release(types);
00327         if (p)
00328             IKsPropertySet_Release(p);
00329         if (device_pin != pin)
00330             IPin_Release(pin);
00331     }
00332 
00333     if (!device_pin) {
00334         av_log(avctx, AV_LOG_ERROR,
00335                "Could not find output pin from %s capture device.\n", devtypename);
00336         goto error;
00337     }
00338     ctx->device_pin[devtype] = device_pin;
00339 
00340     capture_filter = libAVFilter_Create(avctx, callback, devtype);
00341     if (!capture_filter) {
00342         av_log(avctx, AV_LOG_ERROR, "Could not create grabber filter.\n");
00343         goto error;
00344     }
00345     ctx->capture_filter[devtype] = capture_filter;
00346 
00347     r = IGraphBuilder_AddFilter(graph, (IBaseFilter *) capture_filter,
00348                                 filter_name[devtype]);
00349     if (r != S_OK) {
00350         av_log(avctx, AV_LOG_ERROR, "Could not add capture filter to graph\n");
00351         goto error;
00352     }
00353 
00354     libAVPin_AddRef(capture_filter->pin);
00355     capture_pin = capture_filter->pin;
00356     ctx->capture_pin[devtype] = capture_pin;
00357 
00358     r = IGraphBuilder_ConnectDirect(graph, device_pin, (IPin *) capture_pin, NULL);
00359     if (r != S_OK) {
00360         av_log(avctx, AV_LOG_ERROR, "Could not connect pins\n");
00361         goto error;
00362     }
00363 
00364     ret = 0;
00365 
00366 error:
00367     if (pins)
00368         IEnumPins_Release(pins);
00369     if (classenum)
00370         IEnumMoniker_Release(classenum);
00371 
00372     return ret;
00373 }
00374 
00375 static enum CodecID waveform_codec_id(enum AVSampleFormat sample_fmt)
00376 {
00377     switch (sample_fmt) {
00378     case AV_SAMPLE_FMT_U8:  return CODEC_ID_PCM_U8;
00379     case AV_SAMPLE_FMT_S16: return CODEC_ID_PCM_S16LE;
00380     case AV_SAMPLE_FMT_S32: return CODEC_ID_PCM_S32LE;
00381     default:                return CODEC_ID_NONE; /* Should never happen. */
00382     }
00383 }
00384 
00385 static enum SampleFormat sample_fmt_bits_per_sample(int bits)
00386 {
00387     switch (bits) {
00388     case 8:  return AV_SAMPLE_FMT_U8;
00389     case 16: return AV_SAMPLE_FMT_S16;
00390     case 32: return AV_SAMPLE_FMT_S32;
00391     default: return AV_SAMPLE_FMT_NONE; /* Should never happen. */
00392     }
00393 }
00394 
00395 static int
00396 dshow_add_device(AVFormatContext *avctx, AVFormatParameters *ap,
00397                  enum dshowDeviceType devtype)
00398 {
00399     struct dshow_ctx *ctx = avctx->priv_data;
00400     AM_MEDIA_TYPE type;
00401     AVCodecContext *codec;
00402     AVStream *st;
00403     int ret = AVERROR(EIO);
00404 
00405     st = av_new_stream(avctx, devtype);
00406     if (!st) {
00407         ret = AVERROR(ENOMEM);
00408         goto error;
00409     }
00410 
00411     ctx->capture_filter[devtype]->stream_index = st->index;
00412 
00413     libAVPin_ConnectionMediaType(ctx->capture_pin[devtype], &type);
00414 
00415     codec = st->codec;
00416     if (devtype == VideoDevice) {
00417         BITMAPINFOHEADER *bih = NULL;
00418 
00419         if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo)) {
00420             VIDEOINFOHEADER *v = (void *) type.pbFormat;
00421             bih = &v->bmiHeader;
00422         } else if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo2)) {
00423             VIDEOINFOHEADER2 *v = (void *) type.pbFormat;
00424             bih = &v->bmiHeader;
00425         }
00426         if (!bih) {
00427             av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n");
00428             goto error;
00429         }
00430 
00431         codec->time_base  = ap->time_base;
00432         codec->codec_type = AVMEDIA_TYPE_VIDEO;
00433         codec->width      = bih->biWidth;
00434         codec->height     = bih->biHeight;
00435         codec->pix_fmt    = dshow_pixfmt(bih->biCompression, bih->biBitCount);
00436         if (codec->pix_fmt == PIX_FMT_NONE) {
00437             codec->codec_id = dshow_codecid(bih->biCompression);
00438             if (codec->codec_id == CODEC_ID_NONE) {
00439                 av_log(avctx, AV_LOG_ERROR, "Unknown compression type. "
00440                                  "Please report verbose (-v 9) debug information.\n");
00441                 dshow_read_close(avctx);
00442                 return AVERROR_PATCHWELCOME;
00443             }
00444             codec->bits_per_coded_sample = bih->biBitCount;
00445         } else {
00446             codec->codec_id = CODEC_ID_RAWVIDEO;
00447             if (bih->biCompression == BI_RGB) {
00448                 codec->bits_per_coded_sample = bih->biBitCount;
00449                 codec->extradata = av_malloc(9 + FF_INPUT_BUFFER_PADDING_SIZE);
00450                 if (codec->extradata) {
00451                     codec->extradata_size = 9;
00452                     memcpy(codec->extradata, "BottomUp", 9);
00453                 }
00454             }
00455         }
00456     } else {
00457         WAVEFORMATEX *fx = NULL;
00458 
00459         if (IsEqualGUID(&type.formattype, &FORMAT_WaveFormatEx)) {
00460             fx = (void *) type.pbFormat;
00461         }
00462         if (!fx) {
00463             av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n");
00464             goto error;
00465         }
00466 
00467         codec->codec_type  = AVMEDIA_TYPE_AUDIO;
00468         codec->sample_fmt  = sample_fmt_bits_per_sample(fx->wBitsPerSample);
00469         codec->codec_id    = waveform_codec_id(codec->sample_fmt);
00470         codec->sample_rate = fx->nSamplesPerSec;
00471         codec->channels    = fx->nChannels;
00472     }
00473 
00474     av_set_pts_info(st, 64, 1, 10000000);
00475 
00476     ret = 0;
00477 
00478 error:
00479     return ret;
00480 }
00481 
00482 static int parse_device_name(AVFormatContext *avctx)
00483 {
00484     struct dshow_ctx *ctx = avctx->priv_data;
00485     char **device_name = ctx->device_name;
00486     char *name = av_strdup(avctx->filename);
00487     char *tmp = name;
00488     int ret = 1;
00489     char *type;
00490 
00491     while ((type = strtok(tmp, "="))) {
00492         char *token = strtok(NULL, ":");
00493         tmp = NULL;
00494 
00495         if        (!strcmp(type, "video")) {
00496             device_name[0] = token;
00497         } else if (!strcmp(type, "audio")) {
00498             device_name[1] = token;
00499         } else {
00500             device_name[0] = NULL;
00501             device_name[1] = NULL;
00502             break;
00503         }
00504     }
00505 
00506     if (!device_name[0] && !device_name[1]) {
00507         ret = 0;
00508     } else {
00509         if (device_name[0])
00510             device_name[0] = av_strdup(device_name[0]);
00511         if (device_name[1])
00512             device_name[1] = av_strdup(device_name[1]);
00513     }
00514 
00515     av_free(name);
00516     return ret;
00517 }
00518 
00519 static int dshow_read_header(AVFormatContext *avctx, AVFormatParameters *ap)
00520 {
00521     struct dshow_ctx *ctx = avctx->priv_data;
00522     IGraphBuilder *graph = NULL;
00523     ICreateDevEnum *devenum = NULL;
00524     IMediaControl *control = NULL;
00525     int ret = AVERROR(EIO);
00526     int r;
00527 
00528     if (!parse_device_name(avctx)) {
00529         av_log(avctx, AV_LOG_ERROR, "Malformed dshow input string.\n");
00530         goto error;
00531     }
00532 
00533     CoInitialize(0);
00534 
00535     r = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
00536                          &IID_IGraphBuilder, (void **) &graph);
00537     if (r != S_OK) {
00538         av_log(avctx, AV_LOG_ERROR, "Could not create capture graph.\n");
00539         goto error;
00540     }
00541     ctx->graph = graph;
00542 
00543     r = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
00544                          &IID_ICreateDevEnum, (void **) &devenum);
00545     if (r != S_OK) {
00546         av_log(avctx, AV_LOG_ERROR, "Could not enumerate system devices.\n");
00547         goto error;
00548     }
00549 
00550     if (ctx->device_name[VideoDevice]) {
00551         ret = dshow_open_device(avctx, devenum, VideoDevice);
00552         if (ret < 0)
00553             goto error;
00554         ret = dshow_add_device(avctx, ap, VideoDevice);
00555         if (ret < 0)
00556             goto error;
00557     }
00558     if (ctx->device_name[AudioDevice]) {
00559         ret = dshow_open_device(avctx, devenum, AudioDevice);
00560         if (ret < 0)
00561             goto error;
00562         ret = dshow_add_device(avctx, ap, AudioDevice);
00563         if (ret < 0)
00564             goto error;
00565     }
00566 
00567     ctx->mutex = CreateMutex(NULL, 0, NULL);
00568     if (!ctx->mutex) {
00569         av_log(avctx, AV_LOG_ERROR, "Could not create Mutex\n");
00570         goto error;
00571     }
00572     ctx->event = CreateEvent(NULL, 1, 0, NULL);
00573     if (!ctx->event) {
00574         av_log(avctx, AV_LOG_ERROR, "Could not create Event\n");
00575         goto error;
00576     }
00577 
00578     r = IGraphBuilder_QueryInterface(graph, &IID_IMediaControl, (void **) &control);
00579     if (r != S_OK) {
00580         av_log(avctx, AV_LOG_ERROR, "Could not get media control.\n");
00581         goto error;
00582     }
00583     ctx->control = control;
00584 
00585     r = IMediaControl_Run(control);
00586     if (r == S_FALSE) {
00587         OAFilterState pfs;
00588         r = IMediaControl_GetState(control, 0, &pfs);
00589     }
00590     if (r != S_OK) {
00591         av_log(avctx, AV_LOG_ERROR, "Could not run filter\n");
00592         goto error;
00593     }
00594 
00595     ret = 0;
00596 
00597 error:
00598 
00599     if (ret < 0)
00600         dshow_read_close(avctx);
00601 
00602     if (devenum)
00603         ICreateDevEnum_Release(devenum);
00604 
00605     return ret;
00606 }
00607 
00608 static int dshow_read_packet(AVFormatContext *s, AVPacket *pkt)
00609 {
00610     struct dshow_ctx *ctx = s->priv_data;
00611     AVPacketList *pktl = NULL;
00612 
00613     while (!pktl) {
00614         WaitForSingleObject(ctx->mutex, INFINITE);
00615         pktl = ctx->pktl;
00616         if (ctx->pktl) {
00617             *pkt = ctx->pktl->pkt;
00618             ctx->pktl = ctx->pktl->next;
00619             av_free(pktl);
00620         }
00621         ResetEvent(ctx->event);
00622         ReleaseMutex(ctx->mutex);
00623         if (!pktl) {
00624             if (s->flags & AVFMT_FLAG_NONBLOCK) {
00625                 return AVERROR(EAGAIN);
00626             } else {
00627                 WaitForSingleObject(ctx->event, INFINITE);
00628             }
00629         }
00630     }
00631 
00632     ctx->curbufsize -= pkt->size;
00633 
00634     return pkt->size;
00635 }
00636 
00637 AVInputFormat ff_dshow_demuxer = {
00638     "dshow",
00639     NULL_IF_CONFIG_SMALL("DirectShow capture"),
00640     sizeof(struct dshow_ctx),
00641     NULL,
00642     dshow_read_header,
00643     dshow_read_packet,
00644     dshow_read_close,
00645     .flags = AVFMT_NOFILE,
00646 };

Generated on Wed Apr 11 2012 07:31:35 for FFmpeg by  doxygen 1.7.1