winegstreamer: Get rid of the mp3 decoder.

In the unlikely event that we are hotplugging not from an IAsyncReader, we
already have the ACM wrapper and l3codeca.acm available to do the same thing.

Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2020-01-28 23:36:51 -06:00 committed by Alexandre Julliard
parent 4588f10f8d
commit d263c4a366
8 changed files with 2 additions and 724 deletions

View File

@ -10,14 +10,12 @@ C_SRCS = \
filter.c \
gst_cbs.c \
gstdemux.c \
gsttffilter.c \
main.c \
mediatype.c \
mfplat.c \
pin.c \
qualitycontrol.c \
seeking.c \
transform.c
seeking.c
IDL_SRCS = mfplat.idl

View File

@ -188,19 +188,6 @@ GstFlowReturn got_data_sink_wrapper(GstPad *pad, GstObject *parent, GstBuffer *b
return cbdata.u.got_data_sink_data.ret;
}
GstFlowReturn got_data_wrapper(GstPad *pad, GstObject *parent, GstBuffer *buf)
{
struct cb_data cbdata = { GOT_DATA };
cbdata.u.got_data_data.pad = pad;
cbdata.u.got_data_data.parent = parent;
cbdata.u.got_data_data.buf = buf;
call_cb(&cbdata);
return cbdata.u.got_data_data.ret;
}
void removed_decoded_pad_wrapper(GstElement *bin, GstPad *pad, gpointer user)
{
struct cb_data cbdata = { REMOVED_DECODED_PAD };
@ -249,17 +236,6 @@ void release_sample_wrapper(gpointer data)
call_cb(&cbdata);
}
void Gstreamer_transform_pad_added_wrapper(GstElement *filter, GstPad *pad, gpointer user)
{
struct cb_data cbdata = { TRANSFORM_PAD_ADDED };
cbdata.u.transform_pad_added_data.filter = filter;
cbdata.u.transform_pad_added_data.pad = pad;
cbdata.u.transform_pad_added_data.user = user;
call_cb(&cbdata);
}
gboolean query_sink_wrapper(GstPad *pad, GstObject *parent, GstQuery *query)
{
struct cb_data cbdata = { QUERY_SINK };

View File

@ -39,12 +39,10 @@ enum CB_TYPE {
EVENT_SRC,
EVENT_SINK,
GOT_DATA_SINK,
GOT_DATA,
REMOVED_DECODED_PAD,
AUTOPLUG_BLACKLIST,
UNKNOWN_TYPE,
RELEASE_SAMPLE,
TRANSFORM_PAD_ADDED,
QUERY_SINK
};
@ -105,12 +103,6 @@ struct cb_data {
GstBuffer *buf;
GstFlowReturn ret;
} got_data_sink_data;
struct got_data_data {
GstPad *pad;
GstObject *parent;
GstBuffer *buf;
GstFlowReturn ret;
} got_data_data;
struct removed_decoded_pad_data {
GstElement *bin;
GstPad *pad;
@ -133,11 +125,6 @@ struct cb_data {
struct release_sample_data {
gpointer data;
} release_sample_data;
struct transform_pad_added_data {
GstElement *filter;
GstPad *pad;
gpointer user;
} transform_pad_added_data;
struct query_sink_data {
GstPad *pad;
GstObject *parent;

View File

@ -19,6 +19,5 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
DEFINE_GUID(CLSID_Gstreamer_Mp3, 0x728dcf55, 0x128f, 0x4dd1, 0xad, 0x22, 0xbe, 0xcf, 0xa6, 0x6c, 0xe7, 0xaa);
DEFINE_GUID(CLSID_Gstreamer_Splitter, 0xf9d8d64e, 0xa144, 0x47dc, 0x8e, 0xe0, 0xf5, 0x34, 0x98, 0x37, 0x2c, 0x29);
DEFINE_GUID(WINESUBTYPE_Gstreamer, 0xffffffff, 0x128f, 0x4dd1, 0xad, 0x22, 0xbe, 0xcf, 0xa6, 0x6c, 0xe7, 0xaa);

View File

@ -37,20 +37,13 @@
IUnknown * CALLBACK avi_splitter_create(IUnknown *outer, HRESULT *phr) DECLSPEC_HIDDEN;
IUnknown * CALLBACK mpeg_splitter_create(IUnknown *outer, HRESULT *phr) DECLSPEC_HIDDEN;
IUnknown * CALLBACK Gstreamer_Mp3_create(IUnknown *pUnkOuter, HRESULT *phr);
IUnknown * CALLBACK Gstreamer_Splitter_create(IUnknown *pUnkOuter, HRESULT *phr);
IUnknown * CALLBACK wave_parser_create(IUnknown *outer, HRESULT *phr) DECLSPEC_HIDDEN;
BOOL init_gstreamer(void) DECLSPEC_HIDDEN;
GstFlowReturn got_data(GstPad *pad, GstObject *parent, GstBuffer *buf) DECLSPEC_HIDDEN;
GstFlowReturn request_buffer(GstPad *pad, guint64 ofs, guint size, GstCaps *caps, GstBuffer **buf) DECLSPEC_HIDDEN;
void Gstreamer_transform_pad_added(GstElement *filter, GstPad *pad, gpointer user) DECLSPEC_HIDDEN;
void start_dispatch_thread(void) DECLSPEC_HIDDEN;
extern const char *media_quark_string DECLSPEC_HIDDEN;
extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) DECLSPEC_HIDDEN;
extern HRESULT mfplat_can_unload_now(void) DECLSPEC_HIDDEN;

View File

@ -97,7 +97,7 @@ static inline struct gstdemux *impl_from_strmbase_filter(struct strmbase_filter
return CONTAINING_RECORD(iface, struct gstdemux, filter);
}
const char* media_quark_string = "media-sample";
static const char *media_quark_string = "media-sample";
static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
static const IMediaSeekingVtbl GST_Seeking_Vtbl;
@ -2313,12 +2313,6 @@ void CALLBACK perform_cb(TP_CALLBACK_INSTANCE *instance, void *user)
cbdata->u.got_data_sink_data.ret = got_data_sink(data->pad, data->parent, data->buf);
break;
}
case GOT_DATA:
{
struct got_data_data *data = &cbdata->u.got_data_data;
cbdata->u.got_data_data.ret = got_data(data->pad, data->parent, data->buf);
break;
}
case REMOVED_DECODED_PAD:
{
struct removed_decoded_pad_data *data = &cbdata->u.removed_decoded_pad_data;
@ -2344,12 +2338,6 @@ void CALLBACK perform_cb(TP_CALLBACK_INSTANCE *instance, void *user)
release_sample(data->data);
break;
}
case TRANSFORM_PAD_ADDED:
{
struct transform_pad_added_data *data = &cbdata->u.transform_pad_added_data;
Gstreamer_transform_pad_added(data->filter, data->pad, data->user);
break;
}
case QUERY_SINK:
{
struct query_sink_data *data = &cbdata->u.query_sink_data;

View File

@ -1,628 +0,0 @@
/*
* GStreamer wrapper filter
*
* Copyright 2010 Maarten Lankhorst for CodeWeavers
* Copyright 2010 Aric Stewart for CodeWeavers
*
* This library 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.
*
* This library 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 this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
#include "config.h"
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/audio/audio.h>
#include "gst_private.h"
#include "gst_guids.h"
#include "gst_cbs.h"
#include "uuids.h"
#include "mmreg.h"
#include "windef.h"
#include "winbase.h"
#include "dshow.h"
#include "strmif.h"
#include "vfwmsgs.h"
#include "dvdmedia.h"
#include "ks.h"
#include "ksmedia.h"
#include "msacm.h"
#include <assert.h>
#include "wine/unicode.h"
#include "wine/debug.h"
#include "initguid.h"
DEFINE_GUID(WMMEDIASUBTYPE_MP3, 0x00000055, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
WINE_DEFAULT_DEBUG_CHANNEL(gstreamer);
struct typeinfo {
GstCaps *caps;
const char *type;
};
static gboolean match_element(GstPluginFeature *feature, gpointer gdata)
{
struct typeinfo *data = (struct typeinfo*)gdata;
GstElementFactory *factory;
const GList *list;
if (!GST_IS_ELEMENT_FACTORY(feature))
return FALSE;
factory = GST_ELEMENT_FACTORY(feature);
if (!strstr(gst_element_factory_get_klass(factory), data->type))
return FALSE;
for (list = gst_element_factory_get_static_pad_templates(factory); list; list = list->next) {
GstStaticPadTemplate *pad = (GstStaticPadTemplate*)list->data;
GstCaps *caps;
gboolean ret;
if (pad->direction != GST_PAD_SINK)
continue;
caps = gst_static_caps_get(&pad->static_caps);
ret = gst_caps_is_always_compatible(caps, data->caps);
gst_caps_unref(caps);
if (ret)
return TRUE;
}
return FALSE;
}
static const char *Gstreamer_FindMatch(const char *strcaps)
{
struct typeinfo data;
GList *list, *copy;
guint bestrank = 0;
GstElementFactory *bestfactory = NULL;
GstCaps *caps = gst_caps_from_string(strcaps);
TRACE("%s\n", strcaps);
data.caps = caps;
data.type = "Decoder";
copy = gst_registry_feature_filter(gst_registry_get(), match_element, 0, &data);
for (list = copy; list; list = list->next) {
GstElementFactory *factory = (GstElementFactory*)list->data;
guint rank;
rank = gst_plugin_feature_get_rank(GST_PLUGIN_FEATURE(factory));
if (rank > bestrank || !bestrank) {
bestrank = rank;
bestfactory = factory;
}
}
gst_caps_unref(caps);
g_list_free(copy);
if (!bestfactory) {
ERR("Could not find plugin for %s\n", strcaps);
return NULL;
}
return gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(bestfactory));
}
typedef struct GstTfImpl {
TransformFilter tf;
const char *gstreamer_name;
GstElement *filter;
GstPad *my_src, *my_sink, *their_src, *their_sink;
LONG cbBuffer;
} GstTfImpl;
static HRESULT WINAPI Gstreamer_transform_ProcessBegin(TransformFilter *iface)
{
GstTfImpl *This = (GstTfImpl*)iface;
int ret;
mark_wine_thread();
ret = gst_element_set_state(This->filter, GST_STATE_PLAYING);
TRACE("Returned: %i\n", ret);
return S_OK;
}
static HRESULT WINAPI Gstreamer_transform_DecideBufferSize(TransformFilter *tf, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest)
{
GstTfImpl *This = (GstTfImpl*)tf;
ALLOCATOR_PROPERTIES actual;
TRACE("%p, %p, %p\n", This, pAlloc, ppropInputRequest);
if (!ppropInputRequest->cbAlign)
ppropInputRequest->cbAlign = 1;
ppropInputRequest->cbBuffer = This->cbBuffer;
if (ppropInputRequest->cBuffers < 2)
ppropInputRequest->cBuffers = 2;
return IMemAllocator_SetProperties(pAlloc, ppropInputRequest, &actual);
}
GstFlowReturn got_data(GstPad *pad, GstObject *parent, GstBuffer *buf)
{
GstTfImpl *This = gst_pad_get_element_private(pad);
IMediaSample *sample = (IMediaSample *) gst_mini_object_get_qdata(GST_MINI_OBJECT(buf), g_quark_from_static_string(media_quark_string));
REFERENCE_TIME tStart, tStop;
HRESULT hr;
TRACE("%p, %p\n", pad, buf);
if(!sample){
GstMapInfo info;
BYTE *ptr;
gst_buffer_map(buf, &info, GST_MAP_READ);
hr = BaseOutputPinImpl_GetDeliveryBuffer(&This->tf.source, &sample, NULL, NULL, 0);
if (FAILED(hr)) {
ERR("Could not get output buffer: %08x\n", hr);
return GST_FLOW_FLUSHING;
}
IMediaSample_SetActualDataLength(sample, info.size);
IMediaSample_GetPointer(sample, &ptr);
memcpy(ptr, info.data, info.size);
gst_buffer_unmap(buf, &info);
}
if (GST_BUFFER_PTS_IS_VALID(buf) &&
GST_BUFFER_DURATION_IS_VALID(buf)) {
tStart = buf->pts / 100;
tStop = tStart + buf->duration / 100;
IMediaSample_SetTime(sample, &tStart, &tStop);
}
else
IMediaSample_SetTime(sample, NULL, NULL);
if (GST_BUFFER_OFFSET_IS_VALID(buf) &&
GST_BUFFER_OFFSET_END_IS_VALID(buf)) {
tStart = buf->offset / 100;
tStop = buf->offset_end / 100;
IMediaSample_SetMediaTime(sample, &tStart, &tStop);
}
else
IMediaSample_SetMediaTime(sample, NULL, NULL);
IMediaSample_SetDiscontinuity(sample, GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DISCONT));
IMediaSample_SetPreroll(sample, GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_LIVE));
IMediaSample_SetSyncPoint(sample, !GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DELTA_UNIT));
IMediaSample_SetActualDataLength(sample, gst_buffer_get_size(buf));
hr = IMemInputPin_Receive(This->tf.source.pMemInputPin, sample);
IMediaSample_Release(sample);
gst_buffer_unref(buf);
if (FAILED(hr))
return GST_FLOW_FLUSHING;
return GST_FLOW_OK;
}
static HRESULT WINAPI Gstreamer_transform_ProcessData(TransformFilter *iface, IMediaSample *sample)
{
GstTfImpl *This = (GstTfImpl*)iface;
REFERENCE_TIME tStart, tStop;
BYTE *data;
GstBuffer *buf;
HRESULT hr;
DWORD bufsize;
int ret;
TRACE("%p, %p\n", This, sample);
mark_wine_thread();
IMediaSample_GetPointer(sample, &data);
IMediaSample_AddRef(sample);
bufsize = IMediaSample_GetActualDataLength(sample);
buf = gst_buffer_new_wrapped_full(0, data, bufsize, 0, bufsize, sample, release_sample_wrapper);
if (!buf) {
IMediaSample_Release(sample);
return S_OK;
}
IMediaSample_AddRef(sample);
gst_mini_object_set_qdata(GST_MINI_OBJECT(buf), g_quark_from_static_string(media_quark_string), sample, release_sample_wrapper);
buf->duration = buf->pts = -1;
hr = IMediaSample_GetTime(sample, &tStart, &tStop);
if (SUCCEEDED(hr)) {
buf->pts = tStart * 100;
if (hr == S_OK)
buf->duration = (tStop - tStart)*100;
}
if (IMediaSample_GetMediaTime(sample, &tStart, &tStop) == S_OK) {
buf->offset = tStart * 100;
buf->offset_end = tStop * 100;
}
if (IMediaSample_IsDiscontinuity(sample) == S_OK)
GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_DISCONT);
if (IMediaSample_IsPreroll(sample) == S_OK)
GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_LIVE);
if (IMediaSample_IsSyncPoint(sample) != S_OK)
GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_DELTA_UNIT);
ret = gst_pad_push(This->my_src, buf);
if (ret)
WARN("Sending returned: %i\n", ret);
if (ret == GST_FLOW_FLUSHING)
return VFW_E_WRONG_STATE;
return S_OK;
}
static HRESULT WINAPI Gstreamer_transform_ProcessEnd(TransformFilter *iface)
{
GstTfImpl *This = (GstTfImpl*)iface;
int ret;
mark_wine_thread();
ret = gst_element_set_state(This->filter, GST_STATE_READY);
TRACE("Returned: %i\n", ret);
return S_OK;
}
void Gstreamer_transform_pad_added(GstElement *filter, GstPad *pad, gpointer user)
{
GstTfImpl *This = (GstTfImpl*)user;
int ret;
TRACE("%p %p %p\n", This, filter, pad);
if (!GST_PAD_IS_SRC(pad))
return;
ret = gst_pad_link(pad, This->my_sink);
if (ret < 0)
WARN("Failed to link with %i\n", ret);
This->their_src = pad;
}
static HRESULT Gstreamer_transform_ConnectInput(GstTfImpl *This, const AM_MEDIA_TYPE *amt, GstCaps *capsin, GstCaps *capsout)
{
GstIterator *it;
BOOL done = FALSE, found = FALSE;
int ret;
TRACE("%p %p %p %p\n", This, amt, capsin, capsout);
mark_wine_thread();
This->filter = gst_element_factory_make(This->gstreamer_name, NULL);
if (!This->filter) {
ERR("Could not make %s filter\n", This->gstreamer_name);
return E_FAIL;
}
This->my_src = gst_pad_new("yuvsrc", GST_PAD_SRC);
gst_pad_set_element_private (This->my_src, This);
gst_pad_set_active(This->my_src, 1);
This->my_sink = gst_pad_new("yuvsink", GST_PAD_SINK);
gst_pad_set_chain_function(This->my_sink, got_data_wrapper);
gst_pad_set_element_private (This->my_sink, This);
gst_pad_set_active(This->my_sink, 1);
it = gst_element_iterate_sink_pads(This->filter);
while (!done) {
GValue item = {0};
switch (gst_iterator_next(it, &item)) {
case GST_ITERATOR_RESYNC:
gst_iterator_resync (it);
break;
case GST_ITERATOR_OK:
This->their_sink = g_value_get_object(&item);
gst_object_ref(This->their_sink);
g_value_reset(&item);
case GST_ITERATOR_ERROR:
case GST_ITERATOR_DONE:
done = TRUE;
break;
}
}
gst_iterator_free(it);
if (!This->their_sink) {
ERR("Could not find sink on filter %s\n", This->gstreamer_name);
return E_FAIL;
}
it = gst_element_iterate_src_pads(This->filter);
gst_iterator_resync(it);
done = FALSE;
while (!done) {
GValue item = {0};
switch (gst_iterator_next(it, &item)) {
case GST_ITERATOR_RESYNC:
gst_iterator_resync (it);
break;
case GST_ITERATOR_OK:
This->their_src = g_value_get_object(&item);
gst_object_ref(This->their_src);
g_value_reset(&item);
case GST_ITERATOR_ERROR:
case GST_ITERATOR_DONE:
done = TRUE;
break;
}
}
gst_iterator_free(it);
found = !!This->their_src;
if (!found)
g_signal_connect(This->filter, "pad-added", G_CALLBACK(Gstreamer_transform_pad_added_wrapper), This);
ret = gst_pad_link(This->my_src, This->their_sink);
if (ret < 0) {
WARN("Failed to link with %i\n", ret);
return E_FAIL;
}
ret = gst_pad_set_caps(This->my_src, capsin);
if (ret < 0) {
WARN("Failed to set caps on own source with %i\n", ret);
return E_FAIL;
}
if (found)
Gstreamer_transform_pad_added(This->filter, This->their_src, This);
if (!gst_pad_is_linked(This->my_sink))
return E_FAIL;
ret = gst_pad_set_caps(This->my_sink, capsout);
if (ret < 0) {
WARN("Failed to set caps on own sink with %i\n", ret);
return E_FAIL;
}
TRACE("Connected\n");
return S_OK;
}
static HRESULT WINAPI Gstreamer_transform_Cleanup(TransformFilter *tf, PIN_DIRECTION dir)
{
GstTfImpl *This = (GstTfImpl*)tf;
TRACE("%p 0x%x\n", This, dir);
mark_wine_thread();
if (dir == PINDIR_INPUT)
{
if (This->filter) {
gst_element_set_state(This->filter, GST_STATE_NULL);
gst_object_unref(This->filter);
}
This->filter = NULL;
if (This->my_src) {
gst_pad_unlink(This->my_src, This->their_sink);
gst_object_unref(This->my_src);
gst_object_unref(This->their_sink);
}
if (This->my_sink) {
gst_pad_unlink(This->their_src, This->my_sink);
gst_object_unref(This->my_sink);
gst_object_unref(This->their_src);
}
This->my_sink = This->my_src = This->their_sink = This->their_src = NULL;
}
return S_OK;
}
static HRESULT WINAPI Gstreamer_transform_EndOfStream(TransformFilter *iface)
{
GstTfImpl *This = (GstTfImpl*)iface;
TRACE("%p\n", This);
mark_wine_thread();
gst_pad_push_event(This->my_src, gst_event_new_eos());
return S_OK;
}
static HRESULT WINAPI Gstreamer_transform_BeginFlush(TransformFilter *iface)
{
GstTfImpl *This = (GstTfImpl*)iface;
TRACE("%p\n", This);
mark_wine_thread();
gst_pad_push_event(This->my_src, gst_event_new_flush_start());
return S_OK;
}
static HRESULT WINAPI Gstreamer_transform_EndFlush(TransformFilter *iface)
{
GstTfImpl *This = (GstTfImpl*)iface;
TRACE("%p\n", This);
mark_wine_thread();
gst_pad_push_event(This->my_src, gst_event_new_flush_stop(TRUE));
return S_OK;
}
static HRESULT WINAPI Gstreamer_transform_NewSegment(TransformFilter *iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
{
GstTfImpl *This = (GstTfImpl*)iface;
const GstSegment segment = { GST_SEGMENT_FLAG_NONE, 1.0, dRate, GST_FORMAT_TIME, 0, 0, 0, tStop <= tStart ? -1 : tStop * 100, 0, tStart*100, -1 };
TRACE("%p\n", This);
mark_wine_thread();
gst_pad_push_event(This->my_src, gst_event_new_segment(&segment));
return S_OK;
}
static HRESULT WINAPI Gstreamer_transform_QOS(TransformFilter *iface, IBaseFilter *sender, Quality qm)
{
GstTfImpl *This = (GstTfImpl*)iface;
REFERENCE_TIME late = qm.Late;
TRACE("%p %p { 0x%x %u %s %s }\n", This, sender,
qm.Type, qm.Proportion,
wine_dbgstr_longlong(qm.Late),
wine_dbgstr_longlong(qm.TimeStamp));
mark_wine_thread();
if (qm.Late < 0 && -qm.Late > qm.TimeStamp)
late = -qm.TimeStamp;
gst_pad_push_event(This->my_sink, gst_event_new_qos(late <= 0 ? GST_QOS_TYPE_OVERFLOW : GST_QOS_TYPE_UNDERFLOW, 1000. / qm.Proportion, late * 100, qm.TimeStamp * 100));
return TransformFilterImpl_Notify(iface, sender, qm);
}
static HRESULT Gstreamer_transform_create(IUnknown *outer, const CLSID *clsid,
const char *name, const TransformFilterFuncTable *vtbl, void **obj)
{
GstTfImpl *This;
if (FAILED(strmbase_transform_create(sizeof(GstTfImpl), outer, clsid, vtbl, (IBaseFilter **)&This)))
return E_OUTOFMEMORY;
This->gstreamer_name = name;
*obj = &This->tf.filter.IUnknown_inner;
TRACE("returning %p\n", This);
return S_OK;
}
static HRESULT WINAPI Gstreamer_Mp3_QueryConnect(TransformFilter *iface, const AM_MEDIA_TYPE *amt)
{
GstTfImpl *This = (GstTfImpl*)iface;
TRACE("%p %p\n", This, amt);
if ( (!IsEqualGUID(&amt->majortype, &MEDIATYPE_Audio) &&
!IsEqualGUID(&amt->majortype, &MEDIATYPE_Stream)) ||
(!IsEqualGUID(&amt->subtype, &MEDIASUBTYPE_MPEG1AudioPayload) &&
!IsEqualGUID(&amt->subtype, &WMMEDIASUBTYPE_MP3))
|| !IsEqualGUID(&amt->formattype, &FORMAT_WaveFormatEx)){
return S_FALSE;
}
return S_OK;
}
static HRESULT mp3_decoder_connect_sink(TransformFilter *tf, const AM_MEDIA_TYPE *amt)
{
GstTfImpl *This = (GstTfImpl*)tf;
GstCaps *capsin, *capsout;
AM_MEDIA_TYPE *outpmt = &This->tf.pmt;
WAVEFORMATEX *wfx, *wfxin;
HRESULT hr;
int layer;
mark_wine_thread();
if (Gstreamer_Mp3_QueryConnect(&This->tf, amt) == S_FALSE || !amt->pbFormat)
return VFW_E_TYPE_NOT_ACCEPTED;
wfxin = (WAVEFORMATEX*)amt->pbFormat;
switch (wfxin->wFormatTag) {
case WAVE_FORMAT_MPEGLAYER3:
layer = 3;
break;
case WAVE_FORMAT_MPEG: {
MPEG1WAVEFORMAT *mpgformat = (MPEG1WAVEFORMAT*)wfxin;
layer = mpgformat->fwHeadLayer;
break;
}
default:
FIXME("Unhandled tag %x\n", wfxin->wFormatTag);
return E_FAIL;
}
FreeMediaType(outpmt);
CopyMediaType(outpmt, amt);
outpmt->subtype = MEDIASUBTYPE_PCM;
outpmt->formattype = FORMAT_WaveFormatEx;
outpmt->cbFormat = sizeof(*wfx);
CoTaskMemFree(outpmt->pbFormat);
wfx = CoTaskMemAlloc(outpmt->cbFormat);
outpmt->pbFormat = (BYTE*)wfx;
wfx->wFormatTag = WAVE_FORMAT_PCM;
wfx->wBitsPerSample = 16;
wfx->nSamplesPerSec = wfxin->nSamplesPerSec;
wfx->nChannels = wfxin->nChannels;
wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
wfx->cbSize = 0;
wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
capsin = gst_caps_new_simple("audio/mpeg",
"mpegversion", G_TYPE_INT, 1,
"layer", G_TYPE_INT, layer,
"rate", G_TYPE_INT, wfx->nSamplesPerSec,
"channels", G_TYPE_INT, wfx->nChannels,
NULL);
capsout = gst_caps_new_simple("audio/x-raw",
"format", G_TYPE_STRING, "S16LE",
"rate", G_TYPE_INT, wfx->nSamplesPerSec,
"channels", G_TYPE_INT, wfx->nChannels,
NULL);
hr = Gstreamer_transform_ConnectInput(This, amt, capsin, capsout);
gst_caps_unref(capsin);
gst_caps_unref(capsout);
This->cbBuffer = wfx->nAvgBytesPerSec / 4;
return hr;
}
static const TransformFilterFuncTable Gstreamer_Mp3_vtbl = {
.pfnDecideBufferSize = Gstreamer_transform_DecideBufferSize,
.pfnStartStreaming = Gstreamer_transform_ProcessBegin,
.pfnReceive = Gstreamer_transform_ProcessData,
.pfnStopStreaming = Gstreamer_transform_ProcessEnd,
.pfnCheckInputType = Gstreamer_Mp3_QueryConnect,
.transform_connect_sink = mp3_decoder_connect_sink,
.pfnBreakConnect = Gstreamer_transform_Cleanup,
.pfnEndOfStream = Gstreamer_transform_EndOfStream,
.pfnBeginFlush = Gstreamer_transform_BeginFlush,
.pfnEndFlush = Gstreamer_transform_EndFlush,
.pfnNewSegment = Gstreamer_transform_NewSegment,
.pfnNotify = Gstreamer_transform_QOS,
};
IUnknown * CALLBACK Gstreamer_Mp3_create(IUnknown *punkouter, HRESULT *phr)
{
const char *plugin;
IUnknown *obj = NULL;
TRACE("%p %p\n", punkouter, phr);
if (!init_gstreamer())
{
*phr = E_FAIL;
return NULL;
}
mark_wine_thread();
plugin = Gstreamer_FindMatch("audio/mpeg, mpegversion=(int) 1");
if (!plugin)
{
*phr = E_FAIL;
return NULL;
}
*phr = Gstreamer_transform_create(punkouter, &CLSID_Gstreamer_Mp3, plugin, &Gstreamer_Mp3_vtbl, (LPVOID*)&obj);
TRACE("returning %p\n", obj);
return obj;
}

View File

@ -38,8 +38,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(gstreamer);
static const WCHAR wGstreamer_Splitter[] =
{'G','S','t','r','e','a','m','e','r',' ','s','p','l','i','t','t','e','r',' ','f','i','l','t','e','r',0};
static const WCHAR wGstreamer_Mp3[] =
{'G','S','t','r','e','a','m','e','r',' ','M','p','3',' ','f','i','l','t','e','r',0};
static const WCHAR wave_parserW[] =
{'W','a','v','e',' ','P','a','r','s','e','r',0};
static const WCHAR avi_splitterW[] =
@ -94,32 +92,6 @@ static const AMOVIESETUP_FILTER amfSplitter =
amfSplitPin
};
AMOVIESETUP_PIN amfMp3Pin[] =
{ { wNull,
FALSE, FALSE, FALSE, FALSE,
&GUID_NULL,
NULL,
1,
amfMTaudio
},
{
wNull,
FALSE, TRUE, FALSE, FALSE,
&GUID_NULL,
NULL,
1,
amfMTaudio
},
};
AMOVIESETUP_FILTER const amfMp3 =
{ &CLSID_Gstreamer_Mp3,
wGstreamer_Mp3,
MERIT_NORMAL,
2,
amfMp3Pin
};
static const AMOVIESETUP_MEDIATYPE wave_parser_sink_type_data[] =
{
{&MEDIATYPE_Stream, &MEDIASUBTYPE_WAVE},
@ -260,13 +232,6 @@ FactoryTemplate const g_Templates[] = {
NULL,
&amfSplitter,
},
{
wGstreamer_Mp3,
&CLSID_Gstreamer_Mp3,
Gstreamer_Mp3_create,
NULL,
&amfMp3,
},
{
wave_parserW,
&CLSID_WAVEParser,