quartz: Add a libavformat based MPEG demuxer.

Henri Verbeet hverbeet at codeweavers.com
Mon Mar 23 03:42:27 CDT 2009


---
 configure.ac            |   21 +
 dlls/quartz/mpegsplit.c | 1097 +++++++++++++++++++++--------------------------
 2 files changed, 514 insertions(+), 604 deletions(-)

diff --git a/configure.ac b/configure.ac
index 3c2463c..a31f831 100644
--- a/configure.ac
+++ b/configure.ac
@@ -23,6 +23,8 @@ AC_ARG_WITH(alsa,      AS_HELP_STRING([--without-alsa],[do not use the Alsa soun
             [if test "x$withval" = "xno"; then ac_cv_header_sys_asoundlib_h=no; ac_cv_header_alsa_asoundlib_h=no; fi])
 AC_ARG_WITH(audioio,   AS_HELP_STRING([--without-audioio],[do not use the AudioIO sound support]),
             [if test "x$withval" = "xno"; then ac_cv_header_libaudioio_h=no; fi])
+AC_ARG_WITH(avformat,  AS_HELP_STRING([--without-avformat], [do not use avformat (MPEG demuxer support)]))
+AC_ARG_WITH(avutil,    AS_HELP_STRING([--without-avutil], [do not use avutil (MPEG demuxer support)]))
 AC_ARG_WITH(capi,      AS_HELP_STRING([--without-capi],[do not use CAPI (ISDN support)]),
             [if test "x$withval" = "xno"; then ac_cv_header_capi20_h=no; ac_cv_header_linux_capi_h=no; fi])
 AC_ARG_WITH(cms,       AS_HELP_STRING([--without-cms],[do not use CMS (color management support)]),
@@ -997,6 +999,25 @@ fi
 WINE_NOTICE_WITH(gnutls,[test "x$ac_cv_lib_soname_gnutls" = "x"],
                  [libgnutls ${notice_platform}development files not found, no schannel support.])
 
+dnl **** Check for libavutil
+if test "x$with_avutil" != "xno"
+then
+    AC_CHECK_HEADER(libavutil/avutil.h,
+        [WINE_CHECK_SONAME(avutil,avutil_version)])
+fi
+WINE_NOTICE_WITH(avutil,[test "x$ac_cv_lib_soname_avutil" = "x"],
+    [libavutil ${notice_platform}development files not found, no MPEG demuxer support.])
+
+dnl **** Check for libavformat
+if test "x$with_avformat" != "xno"
+then
+    AC_CHECK_HEADER(libavformat/avformat.h,
+        [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <libavformat/avformat.h>]], [[typeof(av_read_frame) *pfunc;]])],
+            [WINE_CHECK_SONAME(avformat,avformat_version)])])
+fi
+WINE_NOTICE_WITH(avformat,[test "x$ac_cv_lib_soname_avformat" = "x"],
+    [libavformat ${notice_platform}development files not found, no MPEG demuxer support.])
+
 dnl **** Check which curses lib to use ***
 CURSESLIBS=""
 if test "$ac_cv_header_ncurses_h" = "yes"
diff --git a/dlls/quartz/mpegsplit.c b/dlls/quartz/mpegsplit.c
index a97a8c9..1efdb1a 100644
--- a/dlls/quartz/mpegsplit.c
+++ b/dlls/quartz/mpegsplit.c
@@ -5,6 +5,7 @@
  * Copyright 2004-2005 Christian Costa
  * Copyright 2007 Chris Robinson
  * Copyright 2008 Maarten Lankhorst
+ * Copyright 2009 Henri Verbeet for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -21,754 +22,576 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#include <assert.h>
-#include <math.h>
+#include "config.h"
+#include "wine/port.h"
 
+#if defined SONAME_LIBAVFORMAT && defined SONAME_LIBAVUTIL
+#include <libavformat/avformat.h>
+#endif
+
+#include "wine/debug.h"
+#include "wine/library.h"
 #include "quartz_private.h"
 #include "control_private.h"
 #include "pin.h"
-
-#include "uuids.h"
 #include "mmreg.h"
-#include "mmsystem.h"
-
-#include "winternl.h"
-
-#include "wine/unicode.h"
-#include "wine/debug.h"
-
 #include "parser.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
 
-#define SEQUENCE_HEADER_CODE     0xB3
-#define PACK_START_CODE          0xBA
+#if defined SONAME_LIBAVFORMAT && defined SONAME_LIBAVUTIL
+
+static void *libavformat_handle;
+static void *libavutil_handle;
+#define MAKE_FUNCPTR(f) static typeof(f) * p##f
+MAKE_FUNCPTR(av_close_input_file);
+MAKE_FUNCPTR(av_find_stream_info);
+MAKE_FUNCPTR(av_free);
+MAKE_FUNCPTR(av_malloc);
+MAKE_FUNCPTR(av_open_input_file);
+MAKE_FUNCPTR(av_read_frame);
+MAKE_FUNCPTR(av_register_all);
+MAKE_FUNCPTR(av_seek_frame);
+MAKE_FUNCPTR(register_protocol);
+#undef MAKE_FUNCPTR
 
-#define SYSTEM_START_CODE        0xBB
-#define AUDIO_ELEMENTARY_STREAM  0xC0
-#define VIDEO_ELEMENTARY_STREAM  0xE0
-
-#define MPEG_SYSTEM_HEADER 3
-#define MPEG_VIDEO_HEADER 2
-#define MPEG_AUDIO_HEADER 1
-#define MPEG_NO_HEADER 0
-
-#define SEEK_INTERVAL (ULONGLONG)(10 * 10000000) /* Add an entry every 10 seconds */
-
-struct seek_entry {
-    ULONGLONG bytepos;
-    ULONGLONG timepos;
-};
+static const WCHAR wszAudioStream[] = {'A','u','d','i','o',0};
+static const WCHAR wszVideoStream[] = {'V','i','d','e','o',0};
 
-typedef struct MPEGSplitterImpl
+struct quartz_context
 {
-    ParserImpl Parser;
-    LONGLONG EndOfFile;
-    LONGLONG duration;
-    LONGLONG position;
-    DWORD begin_offset;
-    BYTE header[4];
-
-    /* Whether we just seeked (or started playing) */
-    BOOL seek;
-
-    /* Seeking cache */
-    ULONG seek_entries;
-    struct seek_entry *seektable;
-} MPEGSplitterImpl;
+    PullPin *pin;
+    LONGLONG pos;
+    LONGLONG len;
+};
 
-static int MPEGSplitter_head_check(const BYTE *header)
+static int quartz_open(URLContext *ctx, const char *url, int flags)
 {
-    /* If this is a possible start code, check for a system or video header */
-    if (header[0] == 0 && header[1] == 0 && header[2] == 1)
-    {
-        /* Check if we got a system or elementary stream start code */
-        if (header[3] == PACK_START_CODE ||
-            header[3] == VIDEO_ELEMENTARY_STREAM ||
-            header[3] == AUDIO_ELEMENTARY_STREAM)
-            return MPEG_SYSTEM_HEADER;
-
-        /* Check for a MPEG video sequence start code */
-        if (header[3] == SEQUENCE_HEADER_CODE)
-            return MPEG_VIDEO_HEADER;
-    }
+    struct quartz_context *qc;
+    LONGLONG avail;
 
-    /* This should give a good guess if we have an MPEG audio header */
-    if(header[0] == 0xff && ((header[1]>>5)&0x7) == 0x7 &&
-       ((header[1]>>1)&0x3) != 0 && ((header[2]>>4)&0xf) != 0xf &&
-       ((header[2]>>2)&0x3) != 0x3)
-        return MPEG_AUDIO_HEADER;
+    TRACE("ctx %p, url %s, flags %#x\n", ctx, url, flags);
 
-    /* Nothing yet.. */
-    return MPEG_NO_HEADER;
-}
+    qc = pav_malloc(sizeof(*qc));
+    if (!qc) return AVERROR(ENOMEM);
+    ctx->priv_data = qc;
 
-static const WCHAR wszAudioStream[] = {'A','u','d','i','o',0};
-static const WCHAR wszVideoStream[] = {'V','i','d','e','o',0};
+    qc->pos = 0;
+    qc->pin = NULL;
+    sscanf(url, "quartz://%p", &qc->pin);
 
-static const DWORD freqs[10] = { 44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000,  8000, 0 };
+    TRACE("pin %p\n", qc->pin);
 
-static const DWORD tabsel_123[2][3][16] = {
-    { {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,},
-      {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,},
-      {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,} },
+    IAsyncReader_Length(qc->pin->pReader, &qc->len, &avail);
 
-    { {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,},
-      {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,},
-      {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,} }
-};
+    return 0;
+}
 
-static HRESULT parse_header(BYTE *header, LONGLONG *plen, LONGLONG *pduration)
+static int quartz_read(URLContext *ctx, unsigned char *data, int data_size)
 {
-    LONGLONG duration;
-
-    int bitrate_index, freq_index, lsf = 1, mpeg1, layer, padding, bitrate, length;
-
-    if (!(header[0] == 0xff && ((header[1]>>5)&0x7) == 0x7 &&
-       ((header[1]>>1)&0x3) != 0 && ((header[2]>>4)&0xf) != 0xf &&
-       ((header[2]>>2)&0x3) != 0x3))
-    {
-        FIXME("Not a valid header: %02x:%02x\n", header[0], header[1]);
-        return E_INVALIDARG;
-    }
+    struct quartz_context *qc = ctx->priv_data;
+    HRESULT hr;
 
-    mpeg1 = (header[1]>>4)&0x1;
-    if (mpeg1)
-        lsf = ((header[1]>>3)&0x1)^1;
+    TRACE("ctx %p, data %p, data_size %d\n", ctx, data, data_size);
 
-    layer = 4-((header[1]>>1)&0x3);
-    bitrate_index = ((header[2]>>4)&0xf);
-    freq_index = ((header[2]>>2)&0x3) + (mpeg1?(lsf*3):6);
-    padding = ((header[2]>>1)&0x1);
+    if (data_size > qc->len - qc->pos) data_size = qc->len - qc->pos;
 
-    bitrate = tabsel_123[lsf][layer-1][bitrate_index] * 1000;
-    if (!bitrate || layer != 3)
+    hr = IAsyncReader_SyncRead(qc->pin->pReader, qc->pos, data_size, data);
+    if (FAILED(hr))
     {
-        FIXME("Not a valid header: %02x:%02x:%02x:%02x\n", header[0], header[1], header[2], header[3]);
-        return E_INVALIDARG;
+        ERR("Failed to read data.\n");
+        return AVERROR(EIO);
     }
 
+    TRACE("read %d bytes @ pos %s, len %s\n", data_size,
+            wine_dbgstr_longlong(qc->pos), wine_dbgstr_longlong(qc->len));
 
-    if (layer == 3 || layer == 2)
-        length = 144 * bitrate / freqs[freq_index] + padding;
-    else
-        length = 4 * (12 * bitrate / freqs[freq_index] + padding);
+    qc->pos += data_size;
 
-    duration = (ULONGLONG)10000000 * (ULONGLONG)(length) / (ULONGLONG)(bitrate/8);
-    *plen = length;
-    if (pduration)
-        *pduration += duration;
-    return S_OK;
+    return data_size;
 }
 
-static HRESULT FillBuffer(MPEGSplitterImpl *This, IMediaSample *pCurrentSample)
+static int64_t quartz_seek(URLContext *ctx, int64_t pos, int whence)
 {
-    Parser_OutputPin * pOutputPin = (Parser_OutputPin*)This->Parser.ppPins[1];
-    LONGLONG length = 0;
-    LONGLONG pos = BYTES_FROM_MEDIATIME(This->Parser.pInputPin->rtNext);
-    LONGLONG time = This->position;
-    HRESULT hr;
-    BYTE *fbuf = NULL;
-    DWORD len = IMediaSample_GetActualDataLength(pCurrentSample);
+    struct quartz_context *qc = ctx->priv_data;
 
-    TRACE("Source length: %u\n", len);
-    IMediaSample_GetPointer(pCurrentSample, &fbuf);
+    TRACE("ctx %p, pos %s, whence %#x\n", ctx, wine_dbgstr_longlong(pos), whence);
 
-    /* Find the next valid header.. it <SHOULD> be right here */
-    assert(parse_header(fbuf, &length, &This->position) == S_OK);
-    assert(length == len || length + 4 == len);
-    IMediaSample_SetActualDataLength(pCurrentSample, length);
-
-    /* Queue the next sample */
-    if (length + 4 == len)
+    switch(whence)
     {
-        PullPin *pin = This->Parser.pInputPin;
-        LONGLONG stop = BYTES_FROM_MEDIATIME(pin->rtStop);
+        case SEEK_SET:
+            return qc->pos = pos;
 
-        hr = S_OK;
-        memcpy(This->header, fbuf + length, 4);
-        while (FAILED(hr = parse_header(This->header, &length, NULL)))
-        {
-            memmove(This->header, This->header+1, 3);
-            if (pos + 4 >= stop)
-                break;
-            IAsyncReader_SyncRead(pin->pReader, ++pos, 1, This->header + 3);
-        }
-        pin->rtNext = MEDIATIME_FROM_BYTES(pos);
-
-        if (SUCCEEDED(hr))
-        {
-            /* Remove 4 for the last header, which should hopefully work */
-            IMediaSample *sample = NULL;
-            LONGLONG rtSampleStart = pin->rtNext - MEDIATIME_FROM_BYTES(4);
-            LONGLONG rtSampleStop = rtSampleStart + MEDIATIME_FROM_BYTES(length + 4);
-
-            hr = IMemAllocator_GetBuffer(pin->pAlloc, &sample, NULL, NULL, 0);
+        case SEEK_CUR:
+            return qc->pos += pos;
 
-            if (rtSampleStop > pin->rtStop)
-                rtSampleStop = MEDIATIME_FROM_BYTES(ALIGNUP(BYTES_FROM_MEDIATIME(pin->rtStop), pin->cbAlign));
+        case SEEK_END:
+            return qc->pos = qc->len - pos;
 
-            IMediaSample_SetTime(sample, &rtSampleStart, &rtSampleStop);
-            IMediaSample_SetPreroll(sample, 0);
-            IMediaSample_SetDiscontinuity(sample, 0);
-            IMediaSample_SetSyncPoint(sample, 1);
-            pin->rtCurrent = rtSampleStart;
-            pin->rtNext = rtSampleStop;
+        case AVSEEK_SIZE:
+            return qc->len;
 
-            if (SUCCEEDED(hr))
-                hr = IAsyncReader_Request(pin->pReader, sample, 0);
-            if (FAILED(hr))
-                FIXME("o_Ox%08x\n", hr);
-        }
+        default:
+            FIXME("Unhandled whence %#x\n", whence);
+            return -1;
     }
-    /* If not, we're presumably at the end of file */
-
-    TRACE("Media time : %u.%03u\n", (DWORD)(This->position/10000000), (DWORD)((This->position/10000)%1000));
+}
 
-    IMediaSample_SetTime(pCurrentSample, &time, &This->position);
+static int quartz_close(URLContext *ctx)
+{
+    struct quartz_context *qc = ctx->priv_data;
 
-    hr = OutputPin_SendSample(&pOutputPin->pin, pCurrentSample);
+    TRACE("ctx %p\n", ctx);
 
-    if (hr != S_OK)
-    {
-        if (hr != S_FALSE)
-            TRACE("Error sending sample (%x)\n", hr);
-        else
-            TRACE("S_FALSE (%d), holding\n", IMediaSample_GetActualDataLength(pCurrentSample));
-    }
+    pav_free(qc);
 
-    return hr;
+    return 0;
 }
 
+static URLProtocol quartz_prot =
+{
+    "quartz",
+    quartz_open,
+    quartz_read,
+    NULL,
+    quartz_seek,
+    quartz_close,
+};
 
-static HRESULT MPEGSplitter_process_sample(LPVOID iface)
+struct MPEGSplitterImpl
 {
-    MPEGSplitterImpl *This = iface;
-    BYTE *pbSrcStream;
-    DWORD cbSrcStream = 0;
-    REFERENCE_TIME tStart, tStop, tAviStart = This->position;
-    Parser_OutputPin * pOutputPin;
-    IMediaSample *pSample;
-    DWORD_PTR cookie;
-    HRESULT hr;
+    ParserImpl Parser;
 
-    hr = IAsyncReader_WaitForNext(This->Parser.pInputPin->pReader, 10000, &pSample, &cookie);
-    if (FAILED(hr))
-    {
-        ERR("Processing error: %x\n", hr);
-        if (hr == VFW_E_TIMEOUT)
-        {
-            assert(!pSample);
-            return S_OK;
-        }
-        return hr;
-    }
+    LONGLONG duration;
+    LONGLONG position;
+    BOOL discontinuity;
 
-    pOutputPin = (Parser_OutputPin*)This->Parser.ppPins[1];
+    AVFormatContext *format_ctx;
+    AVPacket packet;
+    BOOL packet_held;
+};
 
-    hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
-    if (SUCCEEDED(hr))
-    {
-        cbSrcStream = IMediaSample_GetActualDataLength(pSample);
-        hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
-    }
+static HRESULT MPEGSplitter_process_sample(LPVOID iface)
+{
+    struct MPEGSplitterImpl *This = iface;
+    PullPin *input_pin = This->Parser.pInputPin;
+    Parser_OutputPin *output_pin;
+    REFERENCE_TIME sample_start, sample_stop;
+    IMediaSample *dst_sample;
+    AVRational time_base;
+    BYTE *dst_sample_data;
+    LONG dst_sample_size;
+    HRESULT hr;
+    int ret;
 
-    /* Flush occurring */
-    if (cbSrcStream == 0)
+    if (This->packet_held)
     {
-        FIXME(".. Why do I need you?\n");
-        IMediaSample_Release(pSample);
-        return S_OK;
+        TRACE("Using held packet\n");
+        This->packet_held = FALSE;
+        ret = 0;
     }
-
-    /* trace removed for performance reasons */
-    /* TRACE("(%p), %llu -> %llu\n", pSample, tStart, tStop); */
-
-    /* Now, try to find a new header */
-    hr = FillBuffer(This, pSample);
-    IMediaSample_Release(pSample);
-    if (hr != S_OK)
+    else
     {
-        WARN("Failed with hres: %08x!\n", hr);
-
-        /* Unset progression if denied! */
-        if (hr == VFW_E_WRONG_STATE || hr == S_FALSE)
-        {
-            memcpy(This->header, pbSrcStream, 4);
-            This->Parser.pInputPin->rtCurrent = tStart;
-            This->position = tAviStart;
-        }
+        ret = pav_read_frame(This->format_ctx, &This->packet);
     }
 
-    if (BYTES_FROM_MEDIATIME(tStop) >= This->EndOfFile || This->position >= This->Parser.mediaSeeking.llStop)
+    if (ret < 0 || (This->position >= This->Parser.mediaSeeking.llStop && This->Parser.mediaSeeking.llStop != -1))
     {
         unsigned int i;
 
-        TRACE("End of file reached\n");
+        if (ret < 0) ERR("Failed to read a frame, %d\n", ret);
+        else av_free_packet(&This->packet);
 
-        for (i = 0; i < This->Parser.cStreams; i++)
+        for (i = 0; i < This->Parser.cStreams; ++i)
         {
-            IPin* ppin;
+            IPin *pin;
 
-            hr = IPin_ConnectedTo(This->Parser.ppPins[i+1], &ppin);
+            hr = IPin_ConnectedTo(This->Parser.ppPins[i + 1], &pin);
             if (SUCCEEDED(hr))
             {
-                hr = IPin_EndOfStream(ppin);
-                IPin_Release(ppin);
+                hr = IPin_EndOfStream(pin);
+                IPin_Release(pin);
             }
-            if (FAILED(hr))
-                WARN("Error sending EndOfStream to pin %u (%x)\n", i, hr);
+            if (FAILED(hr)) ERR("Error %#x sending EndOfStream to pin %u\n", hr, i);
         }
 
         /* Force the pullpin thread to stop */
-        hr = S_FALSE;
-    }
-
-    return hr;
-}
-
-
-static HRESULT MPEGSplitter_query_accept(LPVOID iface, const AM_MEDIA_TYPE *pmt)
-{
-    if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Stream))
         return S_FALSE;
+    }
 
-    if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_MPEG1Audio))
-        return S_OK;
-
-    if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_MPEG1Video))
-        FIXME("MPEG-1 video streams not yet supported.\n");
-    else if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_MPEG1System))
-        FIXME("MPEG-1 system streams not yet supported.\n");
-    else if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_MPEG1VideoCD))
-        FIXME("MPEG-1 VideoCD streams not yet supported.\n");
+    output_pin = (Parser_OutputPin *)This->Parser.ppPins[This->packet.stream_index + 1];
+    time_base = This->format_ctx->streams[This->packet.stream_index]->time_base;
 
-    return S_FALSE;
-}
+    hr = OutputPin_GetDeliveryBuffer(&output_pin->pin, &dst_sample, NULL, NULL, 0);
+    if (FAILED(hr))
+    {
+        ERR("Unable to get delivery buffer, %#x\n", hr);
+        goto fail;
+    }
 
+    dst_sample_size = IMediaSample_GetSize(dst_sample);
+    if (dst_sample_size < This->packet.size)
+    {
+        ERR("Sample size is too small %d < %d\n", dst_sample_size, This->packet.size);
+        hr = E_FAIL;
+        goto fail;
+    }
 
-static HRESULT MPEGSplitter_init_audio(MPEGSplitterImpl *This, const BYTE *header, PIN_INFO *ppiOutput, AM_MEDIA_TYPE *pamt)
-{
-    WAVEFORMATEX *format;
-    int bitrate_index;
-    int freq_index;
-    int mode_ext;
-    int emphasis;
-    int lsf = 1;
-    int mpeg1;
-    int layer;
-    int mode;
-
-    ZeroMemory(pamt, sizeof(*pamt));
-    ppiOutput->dir = PINDIR_OUTPUT;
-    ppiOutput->pFilter = (IBaseFilter*)This;
-    wsprintfW(ppiOutput->achName, wszAudioStream);
-
-    pamt->formattype = FORMAT_WaveFormatEx;
-    pamt->majortype = MEDIATYPE_Audio;
-    pamt->subtype = MEDIASUBTYPE_MPEG1AudioPayload;
-
-    pamt->lSampleSize = 0;
-    pamt->bFixedSizeSamples = FALSE;
-    pamt->bTemporalCompression = 0;
-
-    mpeg1 = (header[1]>>4)&0x1;
-    if (mpeg1)
-        lsf = ((header[1]>>3)&0x1)^1;
-
-    layer         = 4-((header[1]>>1)&0x3);
-    bitrate_index =   ((header[2]>>4)&0xf);
-    freq_index    =   ((header[2]>>2)&0x3) + (mpeg1?(lsf*3):6);
-    mode          =   ((header[3]>>6)&0x3);
-    mode_ext      =   ((header[3]>>4)&0x3);
-    emphasis      =   ((header[3]>>0)&0x3);
-
-    if (!bitrate_index)
+    hr = IMediaSample_GetPointer(dst_sample, &dst_sample_data);
+    if (FAILED(hr))
     {
-        /* Set to highest bitrate so samples will fit in for sure */
-        FIXME("Variable-bitrate audio not fully supported.\n");
-        bitrate_index = 15;
+        ERR("Unable to get pointer to buffer, %#x\n", hr);
+        goto fail;
     }
 
-    pamt->cbFormat = ((layer==3)? sizeof(MPEGLAYER3WAVEFORMAT) :
-                                  sizeof(MPEG1WAVEFORMAT));
-    pamt->pbFormat = CoTaskMemAlloc(pamt->cbFormat);
-    if (!pamt->pbFormat)
-        return E_OUTOFMEMORY;
-    ZeroMemory(pamt->pbFormat, pamt->cbFormat);
-    format = (WAVEFORMATEX*)pamt->pbFormat;
-
-    format->wFormatTag      = ((layer == 3) ? WAVE_FORMAT_MPEGLAYER3 :
-                                              WAVE_FORMAT_MPEG);
-    format->nChannels       = ((mode == 3) ? 1 : 2);
-    format->nSamplesPerSec  = freqs[freq_index];
-    format->nAvgBytesPerSec = tabsel_123[lsf][layer-1][bitrate_index] * 1000 / 8;
-
-    if (layer == 3)
-        format->nBlockAlign = format->nAvgBytesPerSec * 8 * 144 /
-                              (format->nSamplesPerSec<<lsf) + 1;
-    else if (layer == 2)
-        format->nBlockAlign = format->nAvgBytesPerSec * 8 * 144 /
-                              format->nSamplesPerSec + 1;
+    if (This->packet.pts != AV_NOPTS_VALUE)
+    {
+        sample_start = (This->packet.pts * time_base.num * 10000000) / (time_base.den);
+        sample_stop = ((This->packet.pts + This->packet.duration) * time_base.num * 10000000) / (time_base.den);
+    }
     else
-        format->nBlockAlign = 4 * (format->nAvgBytesPerSec * 8 * 12 / format->nSamplesPerSec + 1);
-
-    format->wBitsPerSample = 0;
+    {
+        sample_start = This->position;
+        sample_stop = sample_start + ((uint64_t)This->packet.duration * time_base.num * 10000000) / (time_base.den);
+    }
+    This->position = sample_stop;
 
-    if (layer == 3)
+    memcpy(dst_sample_data, This->packet.data, This->packet.size);
+    hr = IMediaSample_SetActualDataLength(dst_sample, This->packet.size);
+    if (FAILED(hr))
     {
-        MPEGLAYER3WAVEFORMAT *mp3format = (MPEGLAYER3WAVEFORMAT*)format;
+        ERR("Failed to set destination buffer data length, %#x\n", hr);
+        goto fail;
+    }
 
-        format->cbSize = MPEGLAYER3_WFX_EXTRA_BYTES;
+    IMediaSample_SetTime(dst_sample, &sample_start, &sample_stop);
+    IMediaSample_SetPreroll(dst_sample, FALSE);
+    IMediaSample_SetDiscontinuity(dst_sample, This->discontinuity);
+    IMediaSample_SetSyncPoint(dst_sample, TRUE);
+    input_pin->rtCurrent = sample_start;
+    input_pin->rtNext = sample_stop;
 
-        mp3format->wID = MPEGLAYER3_ID_MPEG;
-        mp3format->fdwFlags = MPEGLAYER3_FLAG_PADDING_ON;
-        mp3format->nBlockSize = format->nBlockAlign;
-        mp3format->nFramesPerBlock = 1;
+    This->discontinuity = FALSE;
 
-        /* Beware the evil magic numbers. This struct is apparently horribly
-         * under-documented, and the only references I could find had it being
-         * set to this with no real explanation. It works fine though, so I'm
-         * not complaining (yet).
-         */
-        mp3format->nCodecDelay = 1393;
+    hr = OutputPin_SendSample(&output_pin->pin, dst_sample);
+    IMediaSample_Release(dst_sample);
+    if (hr == S_FALSE || hr == VFW_E_WRONG_STATE)
+    {
+        TRACE("Holding packet\n");
+        This->packet_held = TRUE;
     }
     else
     {
-        MPEG1WAVEFORMAT *mpgformat = (MPEG1WAVEFORMAT*)format;
-
-        format->cbSize = 22;
-
-        mpgformat->fwHeadLayer   = ((layer == 1) ? ACM_MPEG_LAYER1 :
-                                    ((layer == 2) ? ACM_MPEG_LAYER2 :
-                                     ACM_MPEG_LAYER3));
-        mpgformat->dwHeadBitrate = format->nAvgBytesPerSec * 8;
-        mpgformat->fwHeadMode    = ((mode == 3) ? ACM_MPEG_SINGLECHANNEL :
-                                    ((mode == 2) ? ACM_MPEG_DUALCHANNEL :
-                                     ((mode == 1) ? ACM_MPEG_JOINTSTEREO :
-                                      ACM_MPEG_STEREO)));
-        mpgformat->fwHeadModeExt = ((mode == 1) ? 0x0F : (1<<mode_ext));
-        mpgformat->wHeadEmphasis = emphasis + 1;
-        mpgformat->fwHeadFlags   = ACM_MPEG_ID_MPEG1;
+        av_free_packet(&This->packet);
+        if (hr != S_OK)
+        {
+            WARN("Error sending sample (%x)\n", hr);
+            This->discontinuity = TRUE;
+        }
     }
-    pamt->subtype.Data1 = format->wFormatTag;
 
-    TRACE("MPEG audio stream detected:\n"
-          "\tLayer %d (%#x)\n"
-          "\tFrequency: %d\n"
-          "\tChannels: %d (%d)\n"
-          "\tBytesPerSec: %d\n",
-          layer, format->wFormatTag, format->nSamplesPerSec,
-          format->nChannels, mode, format->nAvgBytesPerSec);
-
-    dump_AM_MEDIA_TYPE(pamt);
+    return hr;
 
-    return S_OK;
+fail:
+    if (dst_sample) IMediaSample_Release(dst_sample);
+    av_free_packet(&This->packet);
+    This->discontinuity = TRUE;
+    return hr;
 }
 
+static HRESULT MPEGSplitter_query_accept(LPVOID iface, const AM_MEDIA_TYPE *pmt)
+{
+    if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Stream)) return S_FALSE;
+
+    if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_MPEG1Audio)) return S_OK;
+    if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_MPEG1Video)) return S_OK;
+    if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_MPEG1System)) return S_OK;
+
+    if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_MPEG1VideoCD))
+            FIXME("MPEG-1 VideoCD streams not yet supported.\n");
+
+    return S_FALSE;
+}
 
 static HRESULT MPEGSplitter_pre_connect(IPin *iface, IPin *pConnectPin, ALLOCATOR_PROPERTIES *props)
 {
-    PullPin *pPin = (PullPin *)iface;
-    MPEGSplitterImpl *This = (MPEGSplitterImpl*)pPin->pin.pinInfo.pFilter;
-    HRESULT hr;
-    LONGLONG pos = 0; /* in bytes */
-    BYTE header[10];
-    int streamtype = 0;
-    LONGLONG total, avail;
-    AM_MEDIA_TYPE amt;
-    PIN_INFO piOutput;
-
-    IAsyncReader_Length(pPin->pReader, &total, &avail);
-    This->EndOfFile = total;
-
-    hr = IAsyncReader_SyncRead(pPin->pReader, pos, 4, header);
-    if (SUCCEEDED(hr))
-        pos += 4;
-
-    /* Skip ID3 v2 tag, if any */
-    if (SUCCEEDED(hr) && !memcmp("ID3", header, 3))
-    do {
-        UINT length;
-        hr = IAsyncReader_SyncRead(pPin->pReader, pos, 6, header + 4);
-        if (FAILED(hr))
-            break;
-        pos += 6;
-        TRACE("Found ID3 v2.%d.%d\n", header[3], header[4]);
-        length  = (header[6] & 0x7F) << 21;
-        length += (header[7] & 0x7F) << 14;
-        length += (header[8] & 0x7F) << 7;
-        length += (header[9] & 0x7F);
-        TRACE("Length: %u\n", length);
-        pos += length;
-
-        /* Read the real header for the mpeg splitter */
-        hr = IAsyncReader_SyncRead(pPin->pReader, pos, 4, header);
-        if (SUCCEEDED(hr))
-            pos += 4;
-        TRACE("%x:%x:%x:%x\n", header[0], header[1], header[2], header[3]);
-    } while (0);
-
-    while(SUCCEEDED(hr) && !(streamtype=MPEGSplitter_head_check(header)))
+    struct MPEGSplitterImpl *This = (struct MPEGSplitterImpl *)((PullPin *)iface)->pin.pinInfo.pFilter;
+    char url[12 + sizeof(iface) * 2];
+    LONGLONG duration = -1;
+    unsigned int i;
+    int ret;
+
+    sprintf(url, "quartz://%p", iface);
+    ret = pav_open_input_file(&This->format_ctx, url, NULL, 0, NULL);
+    if (ret)
     {
-        TRACE("%x:%x:%x:%x\n", header[0], header[1], header[2], header[3]);
-        /* No valid header yet; shift by a byte and check again */
-        memmove(header, header+1, 3);
-        hr = IAsyncReader_SyncRead(pPin->pReader, pos++, 1, header + 3);
+        ERR("av_open_input_file failed %d\n", ret);
+        return E_FAIL;
+    }
+
+    ret = pav_find_stream_info(This->format_ctx);
+    if (ret < 0)
+    {
+        ERR("av_find_stream_info failed %d\n", ret);
+        pav_close_input_file(This->format_ctx);
+        This->format_ctx = NULL;
+        return E_FAIL;
     }
-    if (FAILED(hr))
-        return hr;
-    pos -= 4;
-    This->begin_offset = pos;
-    memcpy(This->header, header, 4);
 
-    This->seektable[0].bytepos = pos;
-    This->seektable[0].timepos = 0;
+    if (This->format_ctx->duration != AV_NOPTS_VALUE) duration = This->format_ctx->duration;
 
-    switch(streamtype)
+    for (i = 0; i < This->format_ctx->nb_streams; ++i)
     {
-        case MPEG_AUDIO_HEADER:
+        AVCodecContext *codec_ctx = This->format_ctx->streams[i]->codec;
+        AM_MEDIA_TYPE media_type;
+        PIN_INFO output_pin;
+
+        switch (codec_ctx->codec_type)
         {
-            LONGLONG duration = 0;
-            DWORD last_entry = 0;
+            case CODEC_TYPE_VIDEO:
+            {
+                MPEG1VIDEOINFO *format;
+                ULONG format_size = sizeof(*format);
 
-            DWORD ticks = GetTickCount();
+                format = CoTaskMemAlloc(format_size);
+                if (!format)
+                {
+                    ERR("Failed to alloc memory\n");
+                    goto fail;
+                }
 
-            hr = MPEGSplitter_init_audio(This, header, &piOutput, &amt);
-            if (SUCCEEDED(hr))
-            {
-                WAVEFORMATEX *format = (WAVEFORMATEX*)amt.pbFormat;
-
-                props->cbAlign = 1;
-                props->cbPrefix = 0;
-                /* Make the output buffer a multiple of the frame size */
-                props->cbBuffer = 0x4000 / format->nBlockAlign *
-                                 format->nBlockAlign;
-                props->cBuffers = 3;
-                hr = Parser_AddPin(&(This->Parser), &piOutput, props, &amt);
+                memset(format, 0, format_size);
+                format->dwStartTimeCode = 0;
+                format->cbSequenceHeader = 0;
+                format->hdr.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+                format->hdr.bmiHeader.biWidth = codec_ctx->width;
+                format->hdr.bmiHeader.biHeight = codec_ctx->height;
+                format->hdr.bmiHeader.biPlanes = 1;
+                format->hdr.bmiHeader.biBitCount = 24;
+                format->hdr.bmiHeader.biCompression = BI_RGB;
+                format->hdr.bmiHeader.biSizeImage = 0;
+                format->hdr.bmiHeader.biXPelsPerMeter = 0;
+                format->hdr.bmiHeader.biYPelsPerMeter = 0;
+                format->hdr.bmiHeader.biClrUsed = 0;
+                format->hdr.bmiHeader.biClrImportant = 0;
+
+                media_type.majortype = MEDIATYPE_Video;
+                media_type.subtype = MEDIASUBTYPE_MPEG1Payload;
+                media_type.bFixedSizeSamples = FALSE;
+                media_type.bTemporalCompression = TRUE;
+                media_type.lSampleSize = 0;
+                media_type.formattype = FORMAT_MPEGVideo;
+                media_type.pUnk = NULL;
+                media_type.cbFormat = format_size;
+                media_type.pbFormat = (BYTE *)format;
+
+                output_pin.dir = PINDIR_OUTPUT;
+                output_pin.pFilter = (IBaseFilter*)This;
+                wsprintfW(output_pin.achName, wszVideoStream);
+
+                Parser_AddPin(&This->Parser, &output_pin, props, &media_type);
+                break;
             }
 
-            if (FAILED(hr))
+            case CODEC_TYPE_AUDIO:
             {
-                if (amt.pbFormat)
-                    CoTaskMemFree(amt.pbFormat);
-                ERR("Could not create pin for MPEG audio stream (%x)\n", hr);
-                break;
-            }
+                int layer = codec_ctx->sub_id;
 
-            /* Check for idv1 tag, and remove it from stream if found */
-            hr = IAsyncReader_SyncRead(pPin->pReader, This->EndOfFile-128, 3, header+4);
-            if (FAILED(hr))
-                break;
-            if (!strncmp((char*)header+4, "TAG", 3))
-                This->EndOfFile -= 128;
-            This->Parser.pInputPin->rtStop = MEDIATIME_FROM_BYTES(This->EndOfFile);
-            This->Parser.pInputPin->rtStart = This->Parser.pInputPin->rtCurrent = MEDIATIME_FROM_BYTES(This->begin_offset);
+                media_type.majortype = MEDIATYPE_Audio;
+                media_type.subtype = MEDIASUBTYPE_MPEG1AudioPayload;
+                media_type.bFixedSizeSamples = FALSE;
+                media_type.bTemporalCompression = FALSE;
+                media_type.lSampleSize = 0;
+                media_type.formattype = FORMAT_WaveFormatEx;
+                media_type.pUnk = NULL;
 
-            /* http://mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm has a whole read up on audio headers */
-            while (pos + 3 < This->EndOfFile)
-            {
-                LONGLONG length = 0;
-                hr = IAsyncReader_SyncRead(pPin->pReader, pos, 4, header);
-                if (hr != S_OK)
-                    break;
-                while (parse_header(header, &length, &duration))
+                if (layer > 3)
                 {
-                    /* No valid header yet; shift by a byte and check again */
-                    memmove(header, header+1, 3);
-                    hr = IAsyncReader_SyncRead(pPin->pReader, pos++, 1, header + 3);
-                    if (hr != S_OK || This->EndOfFile - pos < 4)
-                       break;
+                    FIXME("Unhandled layer %d\n", layer);
+                    goto fail;
                 }
-                pos += length;
 
-                if (This->seektable && (duration / SEEK_INTERVAL) > last_entry)
+                if (layer == 3)
                 {
-                    if (last_entry + 1 > duration / SEEK_INTERVAL)
+                    MPEGLAYER3WAVEFORMAT *format;
+                    ULONG format_size = sizeof(*format);
+
+                    format = CoTaskMemAlloc(format_size);
+                    if (!format)
                     {
-                        ERR("Somehow skipped %d interval lengths instead of 1\n", (DWORD)(duration/SEEK_INTERVAL) - (last_entry + 1));
+                        ERR("Failed to alloc memory\n");
+                        goto fail;
                     }
-                    ++last_entry;
 
-                    TRACE("Entry: %u\n", last_entry);
-                    if (last_entry >= This->seek_entries)
+                    memset(format, 0, format_size);
+                    format->wfx.wFormatTag = WAVE_FORMAT_MPEGLAYER3;
+                    format->wfx.nChannels = codec_ctx->channels;
+                    format->wfx.nSamplesPerSec = codec_ctx->sample_rate;
+                    format->wfx.nAvgBytesPerSec = codec_ctx->bit_rate / 8;
+                    format->wfx.nBlockAlign = codec_ctx->frame_size;
+                    format->wfx.wBitsPerSample = 0;
+
+                    format->wID = MPEGLAYER3_ID_MPEG;
+                    format->fdwFlags = MPEGLAYER3_FLAG_PADDING_ON;
+                    format->nBlockSize = format->wfx.nBlockAlign;
+                    format->nFramesPerBlock = 1;
+                    format->nCodecDelay = 1393;
+                    format->wfx.cbSize = MPEGLAYER3_WFX_EXTRA_BYTES;
+
+                    media_type.cbFormat = format_size;
+                    media_type.pbFormat = (BYTE *)format;
+                    media_type.subtype.Data1 = format->wfx.wFormatTag;
+                }
+                else
+                {
+                    MPEG1WAVEFORMAT *format;
+                    ULONG format_size = sizeof(*format);
+
+                    format = CoTaskMemAlloc(format_size);
+                    if (!format)
                     {
-                        This->seek_entries += 64;
-                        This->seektable = CoTaskMemRealloc(This->seektable, (This->seek_entries)*sizeof(struct seek_entry));
+                        ERR("Failed to alloc memory\n");
+                        goto fail;
                     }
-                    This->seektable[last_entry].bytepos = pos;
-                    This->seektable[last_entry].timepos = duration;
+
+                    memset(format, 0, format_size);
+                    format->wfx.wFormatTag = WAVE_FORMAT_MPEG;
+                    format->wfx.nChannels = codec_ctx->channels;
+                    format->wfx.nSamplesPerSec = codec_ctx->sample_rate;
+                    format->wfx.nAvgBytesPerSec = codec_ctx->bit_rate / 8;
+                    format->wfx.nBlockAlign = codec_ctx->frame_size;
+                    format->fwHeadLayer = layer == 1 ? ACM_MPEG_LAYER1 : ACM_MPEG_LAYER2;
+                    format->wfx.wBitsPerSample = 0;
+                    format->dwHeadBitrate = codec_ctx->bit_rate;
+                    format->fwHeadMode = ACM_MPEG_JOINTSTEREO;
+                    format->fwHeadModeExt = 0xf;
+                    format->wHeadEmphasis = 1;
+                    format->fwHeadFlags = ACM_MPEG_ID_MPEG1;
+                    format->wfx.cbSize = 22;
+
+                    media_type.cbFormat = format_size;
+                    media_type.pbFormat = (BYTE *)format;
+                    media_type.subtype.Data1 = format->wfx.wFormatTag;
                 }
 
-                TRACE("Pos: %x%08x/%x%08x\n", (DWORD)(pos >> 32), (DWORD)pos, (DWORD)(This->EndOfFile>>32), (DWORD)This->EndOfFile);
+                output_pin.dir = PINDIR_OUTPUT;
+                output_pin.pFilter = (IBaseFilter*)This;
+                wsprintfW(output_pin.achName, wszAudioStream);
+
+                Parser_AddPin(&This->Parser, &output_pin, props, &media_type);
+                break;
             }
-            hr = S_OK;
-            TRACE("Duration: %d seconds\n", (DWORD)(duration / 10000000));
-            TRACE("Parsing took %u ms\n", GetTickCount() - ticks);
-            This->duration = duration;
-
-            This->Parser.mediaSeeking.llCurrent = 0;
-            This->Parser.mediaSeeking.llDuration = duration;
-            This->Parser.mediaSeeking.llStop = duration;
-            break;
-        }
-        case MPEG_VIDEO_HEADER:
-            FIXME("MPEG video processing not yet supported!\n");
-            hr = E_FAIL;
-            break;
-        case MPEG_SYSTEM_HEADER:
-            FIXME("MPEG system streams not yet supported!\n");
-            hr = E_FAIL;
-            break;
 
-        default:
-            break;
+            default:
+                FIXME("Unhandled codec type %#x\n", codec_ctx->codec_type);
+                goto fail;
+        }
     }
+
     This->position = 0;
+    This->duration = duration;
+    This->Parser.mediaSeeking.llCurrent = 0;
+    This->Parser.mediaSeeking.llDuration = duration;
+    This->Parser.mediaSeeking.llStop = duration;
 
-    return hr;
+    return S_OK;
+
+fail:
+    pav_close_input_file(This->format_ctx);
+    This->format_ctx = NULL;
+    return E_FAIL;
 }
 
-static HRESULT MPEGSplitter_cleanup(LPVOID iface)
+static HRESULT MPEGSplitter_cleanup(void *iface)
 {
-    MPEGSplitterImpl *This = iface;
-
-    TRACE("(%p)\n", This);
+    TRACE("iface %p\n", iface);
 
     return S_OK;
 }
 
 static HRESULT MPEGSplitter_seek(IBaseFilter *iface)
 {
-    MPEGSplitterImpl *This = (MPEGSplitterImpl*)iface;
-    PullPin *pPin = This->Parser.pInputPin;
-    LONGLONG newpos, timepos, bytepos;
-    HRESULT hr = S_OK;
-    BYTE header[4];
-
-    newpos = This->Parser.mediaSeeking.llCurrent;
+    struct MPEGSplitterImpl *This = (struct MPEGSplitterImpl *)iface;
+    LONGLONG newpos = This->Parser.mediaSeeking.llCurrent;
+    PullPin *input_pin = This->Parser.pInputPin;
+    unsigned int i;
+    int ret;
 
     if (newpos > This->duration)
     {
-        WARN("Requesting position %x%08x beyond end of stream %x%08x\n", (DWORD)(newpos>>32), (DWORD)newpos, (DWORD)(This->duration>>32), (DWORD)This->duration);
+        WARN("Requesting position %x%08x beyond end of stream %x%08x\n",
+                (DWORD)(newpos >> 32), (DWORD)newpos, (DWORD)(This->duration >> 32), (DWORD)This->duration);
         return E_INVALIDARG;
     }
 
-    if (This->position/1000000 == newpos/1000000)
+    if (This->position / 1000000 == newpos / 1000000)
     {
-        TRACE("Requesting position %x%08x same as current position %x%08x\n", (DWORD)(newpos>>32), (DWORD)newpos, (DWORD)(This->position>>32), (DWORD)This->position);
+        TRACE("Requesting position %x%08x same as current position %x%08x\n",
+                (DWORD)(newpos>>32), (DWORD)newpos, (DWORD)(This->position>>32), (DWORD)This->position);
         return S_OK;
     }
 
-    /* Position, cached */
-    bytepos = This->seektable[newpos / SEEK_INTERVAL].bytepos;
-    timepos = This->seektable[newpos / SEEK_INTERVAL].timepos;
-
-    hr = IAsyncReader_SyncRead(pPin->pReader, bytepos, 4, header);
-    while (bytepos + 3 < This->EndOfFile)
+    if (This->packet_held)
     {
-        LONGLONG length = 0;
-        hr = IAsyncReader_SyncRead(pPin->pReader, bytepos, 4, header);
-        if (hr != S_OK || timepos >= newpos)
-            break;
-
-        while (parse_header(header, &length, &timepos) && bytepos + 3 < This->EndOfFile)
-        {
-            /* No valid header yet; shift by a byte and check again */
-            memmove(header, header+1, 3);
-            hr = IAsyncReader_SyncRead(pPin->pReader, ++bytepos, 1, header + 3);
-            if (hr != S_OK)
-                break;
-         }
-         bytepos += length;
-         TRACE("Pos: %x%08x/%x%08x\n", (DWORD)(bytepos >> 32), (DWORD)bytepos, (DWORD)(This->EndOfFile>>32), (DWORD)This->EndOfFile);
+        av_free_packet(&This->packet);
+        This->packet_held = FALSE;
     }
 
-    if (SUCCEEDED(hr))
+    ret = pav_seek_frame(This->format_ctx, -1, newpos * AV_TIME_BASE, AVSEEK_FLAG_ANY);
+    if (ret < 0)
     {
-        PullPin *pin = This->Parser.pInputPin;
-        IPin *victim = NULL;
+        ERR("Failed to seek to pos %s\n", wine_dbgstr_longlong(newpos));
+        return E_FAIL;
+    }
 
-        TRACE("Moving sound to %08u bytes!\n", (DWORD)bytepos);
+    EnterCriticalSection(&input_pin->thread_lock);
 
-        EnterCriticalSection(&pin->thread_lock);
-        IPin_BeginFlush((IPin *)pin);
+    IPin_BeginFlush((IPin *)input_pin);
 
-        /* Make sure this is done while stopped, BeginFlush takes care of this */
-        EnterCriticalSection(&This->Parser.csFilter);
-        memcpy(This->header, header, 4);
-        IPin_ConnectedTo(This->Parser.ppPins[1], &victim);
-        if (victim)
-        {
-            IPin_NewSegment(victim, newpos, This->duration, pin->dRate);
-            IPin_Release(victim);
-        }
+    EnterCriticalSection(&This->Parser.csFilter);
 
-        pin->rtStart = pin->rtCurrent = MEDIATIME_FROM_BYTES(bytepos);
-        pin->rtStop = MEDIATIME_FROM_BYTES((REFERENCE_TIME)This->EndOfFile);
-        This->seek = TRUE;
-        This->position = newpos;
-        LeaveCriticalSection(&This->Parser.csFilter);
+    for (i = 0; i < This->Parser.cStreams; ++i)
+    {
+        IPin *pin;
 
-        TRACE("Done flushing\n");
-        IPin_EndFlush((IPin *)pin);
-        LeaveCriticalSection(&pin->thread_lock);
+        IPin_ConnectedTo(This->Parser.ppPins[1 + i], &pin);
+        if (pin)
+        {
+            IPin_NewSegment(pin, newpos, This->duration, input_pin->dRate);
+            IPin_Release(pin);
+        }
     }
-    return hr;
-}
 
-static HRESULT MPEGSplitter_disconnect(LPVOID iface)
-{
-    /* TODO: Find memory leaks etc */
-    return S_OK;
-}
+    This->discontinuity = TRUE;
+    This->position = newpos;
 
-static HRESULT MPEGSplitter_first_request(LPVOID iface)
-{
-    MPEGSplitterImpl *This = iface;
-    PullPin *pin = This->Parser.pInputPin;
-    HRESULT hr;
-    LONGLONG length;
-    IMediaSample *sample;
+    LeaveCriticalSection(&This->Parser.csFilter);
 
-    TRACE("Seeking? %d\n", This->seek);
-    assert(parse_header(This->header, &length, NULL) == S_OK);
+    TRACE("Done flushing\n");
+    IPin_EndFlush((IPin *)input_pin);
 
-    if (pin->rtCurrent >= pin->rtStop)
-    {
-        /* Last sample has already been queued, request nothing more */
-        FIXME("Done!\n");
-        return S_OK;
-    }
+    LeaveCriticalSection(&input_pin->thread_lock);
 
-    hr = IMemAllocator_GetBuffer(pin->pAlloc, &sample, NULL, NULL, 0);
-
-    pin->rtNext = pin->rtCurrent;
-    if (SUCCEEDED(hr))
-    {
-        LONGLONG rtSampleStart = pin->rtNext;
-        /* Add 4 for the next header, which should hopefully work */
-        LONGLONG rtSampleStop = rtSampleStart + MEDIATIME_FROM_BYTES(length + 4);
+    return S_OK;
+}
 
-        if (rtSampleStop > pin->rtStop)
-            rtSampleStop = MEDIATIME_FROM_BYTES(ALIGNUP(BYTES_FROM_MEDIATIME(pin->rtStop), pin->cbAlign));
+static HRESULT MPEGSplitter_disconnect(void *iface)
+{
+    struct MPEGSplitterImpl *This = (struct MPEGSplitterImpl *)iface;
 
-        hr = IMediaSample_SetTime(sample, &rtSampleStart, &rtSampleStop);
+    TRACE("iface %p\n", iface);
 
-        pin->rtCurrent = pin->rtNext;
-        pin->rtNext = rtSampleStop;
+    pav_close_input_file(This->format_ctx);
+    This->format_ctx = NULL;
 
-        IMediaSample_SetPreroll(sample, FALSE);
-        IMediaSample_SetDiscontinuity(sample, This->seek);
-        IMediaSample_SetSyncPoint(sample, 1);
-        This->seek = 0;
+    return S_OK;
+}
 
-        hr = IAsyncReader_Request(pin->pReader, sample, 0);
-    }
-    if (FAILED(hr))
-        ERR("Horsemen of the apocalypse came to bring error 0x%08x\n", hr);
+static HRESULT MPEGSplitter_first_request(void *iface)
+{
+    TRACE("iface %p\n", iface);
 
-    return hr;
+    return S_OK;
 }
 
 static const IBaseFilterVtbl MPEGSplitter_Vtbl =
@@ -790,41 +613,107 @@ static const IBaseFilterVtbl MPEGSplitter_Vtbl =
     Parser_QueryVendorInfo
 };
 
-HRESULT MPEGSplitter_create(IUnknown * pUnkOuter, LPVOID * ppv)
+static HRESULT init_func_ptrs()
 {
-    MPEGSplitterImpl *This;
-    HRESULT hr = E_FAIL;
+    if (libavformat_handle) return S_OK;
 
-    TRACE("(%p, %p)\n", pUnkOuter, ppv);
+    libavformat_handle = wine_dlopen(SONAME_LIBAVFORMAT, RTLD_NOW, NULL, 0);
+    if (!libavformat_handle)
+    {
+        WARN("Failed to load libavformat.\n");
+        goto fail;
+    }
 
-    *ppv = NULL;
+    libavutil_handle = wine_dlopen(SONAME_LIBAVUTIL, RTLD_NOW, NULL, 0);
+    if (!libavutil_handle)
+    {
+        WARN("Failed to load libavutil.\n");
+        goto fail;
+    }
 
-    if (pUnkOuter)
-        return CLASS_E_NOAGGREGATION;
+#define LOAD_FUNCPTR(f) \
+    if (!(p##f = wine_dlsym(libavformat_handle, #f, NULL, 0))) \
+    { \
+        ERR("Failed to load %s\n", #f); \
+        goto fail; \
+    }
 
-    This = CoTaskMemAlloc(sizeof(MPEGSplitterImpl));
-    if (!This)
-        return E_OUTOFMEMORY;
+    LOAD_FUNCPTR(av_close_input_file)
+    LOAD_FUNCPTR(av_find_stream_info)
+    LOAD_FUNCPTR(av_open_input_file)
+    LOAD_FUNCPTR(av_read_frame)
+    LOAD_FUNCPTR(av_register_all)
+    LOAD_FUNCPTR(av_seek_frame)
+    LOAD_FUNCPTR(register_protocol)
+#undef LOAD_FUNCPTR
+
+#define LOAD_FUNCPTR(f) \
+    if (!(p##f = wine_dlsym(libavutil_handle, #f, NULL, 0))) \
+    { \
+        ERR("Failed to load %s\n", #f); \
+        goto fail; \
+    }
+
+    LOAD_FUNCPTR(av_free)
+    LOAD_FUNCPTR(av_malloc)
+#undef LOAD_FUNCPTR
+
+    pav_register_all();
+    pregister_protocol(&quartz_prot);
+
+    return S_OK;
+
+fail:
+    wine_dlclose(libavformat_handle, NULL, 0);
+    libavformat_handle = NULL;
+    wine_dlclose(libavutil_handle, NULL, 0);
+    libavutil_handle = NULL;
+    return E_FAIL;
+}
+
+HRESULT MPEGSplitter_create(IUnknown *outer_unknown, void **filter)
+{
+    struct MPEGSplitterImpl *object;
+    HRESULT hr;
+
+    TRACE("outer_unknown %p, filter %p\n", outer_unknown, filter);
+
+    if (outer_unknown) return CLASS_E_NOAGGREGATION;
 
-    ZeroMemory(This, sizeof(MPEGSplitterImpl));
-    This->seektable = CoTaskMemAlloc(sizeof(struct seek_entry) * 64);
-    if (!This->seektable)
+    hr = init_func_ptrs();
+    if (FAILED(hr)) return hr;
+
+    /* Note: This memory is managed by the parser filter once created */
+    object = CoTaskMemAlloc(sizeof(*object));
+    if (!object)
     {
-        CoTaskMemFree(This);
+        ERR("Failed to allocate memory\n");
         return E_OUTOFMEMORY;
     }
-    This->seek_entries = 64;
+    ZeroMemory(object, sizeof(*object));
+
+    object->discontinuity = TRUE;
 
-    hr = Parser_Create(&(This->Parser), &MPEGSplitter_Vtbl, &CLSID_MPEG1Splitter, MPEGSplitter_process_sample, MPEGSplitter_query_accept, MPEGSplitter_pre_connect, MPEGSplitter_cleanup, MPEGSplitter_disconnect, MPEGSplitter_first_request, NULL, NULL, MPEGSplitter_seek, NULL);
+    hr = Parser_Create(&(object->Parser), &MPEGSplitter_Vtbl, &CLSID_MPEG1Splitter, MPEGSplitter_process_sample,
+            MPEGSplitter_query_accept, MPEGSplitter_pre_connect, MPEGSplitter_cleanup, MPEGSplitter_disconnect,
+            MPEGSplitter_first_request, NULL, NULL, MPEGSplitter_seek, NULL);
     if (FAILED(hr))
     {
-        CoTaskMemFree(This);
+        CoTaskMemFree(object);
         return hr;
     }
-    This->seek = 1;
 
-    /* Note: This memory is managed by the parser filter once created */
-    *ppv = This;
+    *filter = object;
 
     return hr;
 }
+
+#else
+
+HRESULT MPEGSplitter_create(IUnknown *outer_unknown, void **filter)
+{
+    WARN("No MPEG demuxing support\n");
+    return E_FAIL;
+}
+
+#endif
-- 
1.6.0.6



--------------020007090006040207030000--



More information about the wine-patches mailing list