Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

jinx

Frischling

  • »jinx« ist der Autor dieses Themas
  • Private Nachricht senden

1

08.09.2011, 00:22

MP3 aus Speicher abspielen

Hi,
ich benutze zum Abspielen von MP3s den WMASF Reader. Das funktioniert auch alles soweit ganz gut, wenn man die mp3 direkt aus einer Datei (über IFileSourceFilter) lädt.
Allerdings würde ich sie lieber direkt aus dem Speicher abspielen und steh da etwas auf dem Schlauch. Eigentlich dachte ich, dass das ja nicht die Welt sein kann, es ändert sich ja quasi nur die Quelle; die Daten sind ja identisch.
Allerdings scheint es nicht ganz so trivial zu sein. :)

Also bisher läuft es ca so ab, was, wie gesagt, für Dateien auch funktioniert.

C-/C++-Quelltext

1
2
3
4
5
6
7
CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IFilterGraph, (void**)&pGraph);
CoCreateInstance(CLSID_WMAsfReader, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void**)&pReader);
pGraph->QueryInterface(IID_IGraphBuilder, (void **)&pBuilder);
pBuilder->AddFilter(pReader, L"ASF Reader");
pReader->QueryInterface(IID_IFileSourceFilter, (void **)&pFS);
// Load and retrieve pin
pBuilder->Render(pin)


Also ich weiß, dass das selbe quasi mit Renderfile zu erreichen ist, aber ich hatte gleich Render benutzt, da ich ja wie gesagt, keine Files rendern wollte.
Das das nun mit dem IFileSourceFilter aus dem Speicher nicht mehr geht, liegt ja irgendwie auf der Hand.

Ich kann mir auch vorstellen, dass Musik aus dem Speicher laden bestimmt irgendwie anders (ggf mit anderen Bibliotheken) besser und eleganter geht, aber mittlerweile ist das eine prinzipielle Frage geworden. Es muss ja irgendwie gehen, dass man als Quelle statt einer Datei einen Speicherbereich angeben kann. Das das bei mir hier nicht funktioniert, wurmt mich halt irgendwie.
Ich suche also keine andere Lösung für das Musik-aus-Speicher-Problem, sondern Rat, wie man das in DShow direkt selbst umsetzen könnte. Ich bin für jede Hilfe/Anregung dankbar.

Im Netz hatte ich noch den Hinweis gefunden, dass man sich ein IServiceProvider aus dem Reader querien kann und über denen einen WMDRMReader und dann über QI einen WMAdvancedReader2 zurückgeben lassen kann. Dieser kann direkt IStreams laden.
Das scheiterte allerdings daran, dass ich bei mir hier keinen DRMReader erzeugen konnte.
Da ich mich allerdings erst seit kurzem mit DShow beschäftige, kann das (also auch das oben) natürlich alles mist sein und bevor ich mich nun weiter in irgendwelchen Sackgassen verrenne, wollte ich einfach mal nachfragen, ob hier jemand mehr Erfahrung damit hat und mir bei dem Problem vielleicht helfen könnte.

Vielen Dank schonmal!

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

2

08.09.2011, 12:25

Es gibt Klassen namens "CMemStream" und "CMemReader" im Windows SDK (DirectShow-Teil).
Diese erlauben das Lesen aus einem Speicherbereich. Sollte auch Beispiele dazu geben.

jinx

Frischling

  • »jinx« ist der Autor dieses Themas
  • Private Nachricht senden

3

08.09.2011, 12:49

Hi,

ah ja, ich erinnere mich. So bin ich eigentlich auf den ASFReader gekommen. Sorry, das hab ich gestern vergessen, hab da schon so viel ausprobiert. ;-)
Also das hab ich so auch probiert:

C-/C++-Quelltext

1
2
3
4
pStream->Init((BYTE*)pData, dwFileSize, INFINITE);
pReader = new CMemReader(pStream, &MT, &r);
pBuilder->AddFilter(pReader, L"SourceFilter");
pBuilder->Render(pReader->GetPin(0));


Der letzte Aufruf bricht dann mit
pBuilder->Render caused DirectX error VFW_E_NO_TRANSPORT!
Description: Pins cannot connect due to not supporting the same transport.

ab.

Hab danach auch schon Stunden gegooglet, und so auch irgendwie auf den ASFReader gekommen,
aber viel geholfen hatte es noch nicht. Ich guck gleich aber gerne noch einmal durch das SDK.
Weiß da hier vielleicht noch jemand weiter?

LG

jinx

Frischling

  • »jinx« ist der Autor dieses Themas
  • Private Nachricht senden

4

08.09.2011, 14:01

Ich muss den Mediatype ja, wenn ich es richtig verstanden hab, selbst setzen... da hab ich mir für MP3 folgendes herausgefunden, was der CMemReader dann auch lädt:

C-/C++-Quelltext

1
2
3
4
5
6
  pmt->SetType(&MEDIATYPE_Audio);
  pmt->subtype = FOURCCMap(WAVE_FORMAT_MPEGLAYER3);
  pmt->SetFormatType(&FORMAT_WaveFormatEx);
  pmt->SetFormat((BYTE*)&mp3format, sizeof(MPEGLAYER3WAVEFORMAT));
  pmt->bFixedSizeSamples = FALSE;
  pmt->bTemporalCompression = FALSE;

Das Waveformat wird halt vorher noch gesetzt.

Mit diesem MT wirft der builder den Fehler oben aus.
Wenn man es mit dem Reader nun strikt nach dem Beispiel aus dem SDK mit MEDIATYPE_Stream macht, kommt stattdessen:
pBuilder->Render caused DirectX error VFW_E_CANNOT_RENDER!
No combination of filters could be found to render the stream.


Ist da schlicht der MT falsch? Renderfile brauch ja auch keine extra filter, setzt ja aber den MT auch selbst.
Bzw. welchen subtype in Kombination mit Stream soll man für MP3s verwenden, falls der oben falsch ist bzw man Stream verwenden muss?
Ideen? ;)

LG

jinx

Frischling

  • »jinx« ist der Autor dieses Themas
  • Private Nachricht senden

5

08.09.2011, 22:30

Es funktioniert jetzt.
Ich poste hier mal meine Lösung, falls das mal irgendwer sucht.
Grundsätzlich geht es einfach über den MemReader, sofern man den MediaType richtig setzt.
Keine Ahnung warum es am Anfang nicht ging, aber irgendwie haben die ganzen direct show posts im netz eher verwirrt... ;)
Wahrscheinlich lag es am MediaType.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
IFilterGraph*   pGraph;
IGraphBuilder*  pBuilder;
CMediaType  mt;
CMemStream* pStream;
CMemReader* pReader;

mt.majortype    = MEDIATYPE_Stream;
mt.subtype      = MEDIASUBTYPE_MPEG1Audio;

hResult = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IFilterGraph, (void**)&pGraph);
hResult = pGraph->QueryInterface(IID_IGraphBuilder, (void**)&pBuilder);
pStream = new CMemStream;
pStream->Init((BYTE*)pData, dwSize, INFINITE);
pReader = new CMemReader(pStream, &mt, &r);
hResult = pGraph->AddFilter(pReader, NULL);
hResult = pBuilder->Render(pReader->GetPin(0));


Danke erstmal für die offenen Ohren...
... das Auskotzen hat ja offensichtlich geholfen. 8)

LG

Werbeanzeige