Forum
Tipps
News
Menu-Icon

DirectShow: IMediaSample, was mach ich bloß mit Dir?!

Hallo,

ich bastel gerade einen DirectShow-Filter auf der Grundlage eines CTransformFilter. Der Filter war, bevor ich ihn auseinander genommen habe, dafür zuständig ein Video zu invertieren, d.h. getrennt R-,G- und B-Werte zu invertieren. Dafür erschien es mir auch sehr logisch, dass ein Videoframe (vom Typ IMediaSample*) erstmal in seine RGB-Werte zerlegt wird. Das sah in etwa so aus:

HRESULT CDirectShowFilter::DoTransformation(IMediaSample *pIn, IMediaSample *pOut)
{
...
BYTE *pOutData;
pOut->GetPointer(&pOutData);
...
BYTE *prgbOut = (BYTE*) pOutData;
...
}

Das Array von pOut wird also nach int8 gecastet.

Ich für meinen Teil brauche aber keine Farbkonvertierung, sondern möchte nur einzelne Pixel an andere Stellen schieben. Dafür würde es mir vollkommen reichen etwas in dieser Art zu tun:
HRESULT CDirectShowFilter::DoTransformation(IMediaSample *pIn, IMediaSample *pOut)
{
...
pOut[0] = pin[10];
...
}

Abgesehen davon, dass dann aber absolut nicht passiert, geht dann auch die Rechenzeit extrem hoch.

Was für einen Typ hat also IMediaSample? Ich hatte gehofft eine einfache int24-Variable mit den RGB-Werten vorzufinden, aber dem scheint nicht so.
Ich hatte mir vorgestellt das ein weisser Pixel zB so aussieht:
pOut[0] = 0xFFFFFF;Aber wenn ich das versuche, meckert der Compiler von wegen, IMediaSample und int passt nicht.

Vielleicht hat sich schon mal jmd damit beschäftigt und weiss eine Antwort?

Gruß Spawn

Und PS: Sorry mal wieder wegen des langen, unverständlichen Posts  :-[
« Letzte Änderung: 03.06.05, 18:27:14 von Spawn »

Antworten zu DirectShow: IMediaSample, was mach ich bloß mit Dir?!:

Hat dir diese Antwort geholfen?

Danke ButtonHilfreiche Antwort Button

Ja, sorry. Das habe ich aber auch schon versucht. Das Problem ist, dass dort nirgendwo steht, wie ich mir das Format IMediaSample nun vorstellen muss. Ist es nun wie oben vermutet eine 24bit RGB-Anordnung, oder 32bit mit Alpha-Kanal oder ganz was anderes Verrücktes? Diesen Punkt habe ich nirgends gefunden.

Dennoch danke Spawn

Wenn man in C++ eine Operation schreiben will muss man auch mit C++ umgehen können oder?

Deshalb hier mal zum ankreuzen

Ähm kurze Frage :

[ ] Du kannst mit C++ Umgehen
[ ] Du weißt was ein Interface ist
[ ] Du weißt was ein Pointer ist
[ ] Du kennst den Unterschied zwischen einem Void-Pointer und einem 'Typisierten'-Pointer

Wenn du alle diese Boxen mit einem Kreuz füllen kannst, kann ich dir in 'endlicher' (< 5 Zeilen) Zeit erklären wie du die Daten aus einem MediaSample-Objekt über das IMediaSample Interface bekommst und diese vom Input-Pin an den Output-Pin liefern kannst.

MfG

###

Hat dir diese Antwort geholfen?

Danke ButtonHilfreiche Antwort Button

[X] Du kannst mit C++ Umgehen
[X] Du weißt was ein Interface ist
[X] Du weißt was ein Pointer ist
[X] Du kennst den Unterschied zwischen einem Void-Pointer und einem 'Typisierten'-Pointer

So here we go... ;D

Ich wage zu behaupten die Kreuze ruhigen Gewissens gesetzt zu haben. Das Ding ist einfach das: Ich habe es schon geschafft, Daten vom Input zum Output zu bekommen. Aber das nur mit Hilfe eines abgeänderten Source-Codes von einem anderen Filter (s.o.). Mir fehlen also eindeutig Hintergründe, die mir erklären, mit was ich da eigentlich rumhantiere. Mit hin- und herprobieren und immer schön Beispiel-Code suchen lassen sich meine "Wünsche" auch (wenn auch etwas zeitaufwendiger) realisieren, aber wie gesagt: Ich weiss nicht so recht, was dahinter steckt.
Sogesehen, wäre ich Dir also sehr dankbar, wenn Du mir sagst, wie Du es machst (oder vorstellst).

Gruß Spawn

[X] Du kannst mit C++ Umgehen
[X] Du weißt was ein Interface ist
[X] Du weißt was ein Pointer ist
[X] Du kennst den Unterschied zwischen einem Void-Pointer und einem 'Typisierten'-Pointer

HRESULT CDirectShowFilter::DoTransformation(IMediaSample *pIn, IMediaSample *pOut)
{
...
pOut[0] = 0xFFFFFF;
...}
:o:o:o

Irgendetwas widerspricht sich bei den beiden Quotes da oben gar fürchterlich!

Hat dir diese Antwort geholfen?

Danke ButtonHilfreiche Antwort Button

Ja, ist schon richtig. Ich war wie gesagt am rumprobieren, habe einfach mal ohne groß nachzudenken versucht, bissel rumzuspielen. Das dieser Code-Schnipsel totaler Stuß ist, ist mir auch klar. Damit wollte ich nur sagen, dass ich auf der Suche nach einer Lösung war, die eine Veränderung eines Pixels des Videostroms so einfach gewährleistet.

HRESULT CDirectShowFilter::DoTransformation(IMediaSample *pIn, IMediaSample *pOut)
{
...
BYTE *pOutData;
pOut->GetPointer(&pOutData);
...
BYTE *prgbOut = (BYTE*) pOutData;
...
}

Hat dir diese Antwort geholfen?

Danke ButtonHilfreiche Antwort Button

Ist schon wieder ausgebaut. Möchtest Du jetzt noch die restlichen 10% von meinen Posts quoten?

Ist schon wieder ausgebaut. Möchtest Du jetzt noch die restlichen 10% von meinen Posts quoten?

Du meinst, Du hast das einzige Stückchen, das in Deinem Posting richtig aussah, wieder ausgebaut ???

Hat dir diese Antwort geholfen?

Danke ButtonHilfreiche Antwort Button

Nein, nur den Teil:

BYTE *prgbOut = (BYTE*) pOutData;Zumal der relativ überflüssig war.
Dachte, das war es, was Du kritisieren wolltest. Konnte es allerdings aus dem Post nicht ganz rausdeuten, bissel zu wenig Text von Dir.
Nein, nur den Teil:
BYTE *prgbOut = (BYTE*) pOutData;Zumal der relativ überflüssig war.

Vielleicht überflüssig aber zumindest sagen die beiden Variablen jeweils doch wohl ziemlich deutlich, was sie den bedeuten bzw. worauf sie zeigen. Offensichtlich hast Du es mit dem, was (IMediaSample).getPointer() zurückgibt mit einem Pointer auf die Daten dieses Samples zu tun, also genau das, was Du haben möchtest. Würde ich jedenfalls mal ganz stark vermuten aber ### klärt Dich da bald bestimmt ganz genau auf ;-)



Hat dir diese Antwort geholfen?

Danke ButtonHilfreiche Antwort Button

Das ist schon richtig und dass ich die Daten mit pOutData interpretieren und verändern kann, habe ich ja auch gemerkt. Dadurch, dass diese aber vom Typ Byte ist, habe ich es immer nur mit R-,G- und B-Werten getrennt von einander zu tun.

Wenn ich also zB im Video das Pixel an der Stelle 0 an die Stelle 1 schieben will, muss ich sagen:

pOutData[3] = pInData[0];
pOutData[4] = pInData[1];
pOutData[5] = pInData[2];

Ich hatte auch schon versucht, pInData (und Out) einen Int24-Wertebereich zu verpassen, da konnte der Pointer aber nicht übergeben werden.
Und eben dieses würde ich aber gern irgendwie schaffen, so dass ich nciht ständig 3 Operationen (plus wahrscheinlich das ganze rumcasten) brauche um einen Pixel zu verschieben.

Naja, vielleicht kann ### ja wirklich mal noch n paar Worte dazu sagen, ich glaube, das bringt so nix.... :-[
« Letzte Änderung: 07.06.05, 16:12:32 von Spawn »

So jetzt antworte ich auch mal  ;D

in der Transform Methode bekommst du 2 MediaSamples.
also hier etwas code zur Veranschaulichung :

HRESULT CDShowCSCFilter::Transform(IMediaSample *pIn, IMediaSample *pOut)
{
// Copy the sample data
BYTE* pSourceBuffer = 0;
BYTE* pDestBuffer = 0;
        long lSourceSize = pIn->GetActualDataLength();
        long lDestSize = pOut->GetActualDataLength();
GUID src_fmt = m_pInput->CurrentMediaType().subtype;
GUID dest_fmt = m_pOutput->CurrentMediaType().subtype;
        pIn->GetPointer(&pSourceBuffer);
        pOut->GetPointer(&pDestBuffer);

       // hier machen wir jetzt die Transformation
       DoTransform*( pSourceBuffer, pDestBuffer, lSourceSize );
       ...
       return S_OK;
}

Hier jetzt mal ein paar Beispiele :

In diesem Beispiel flippen wir ein Bild um die Horizontale und Vertikale :

void DoTransformFlipRGB32(void* pSourceBuffer, void*pDestBuffer, long lSourceSize )
{
     // Da wir wissen, dass das quell bild immer 4 byte benutzt um einen pixel darzustellen machen wir jetzt eine Struktur mit dessen layout
     struct RGB32 { BYTE r; BYTE g; BYTE b; BYTE v; }

   
     RGB32* pSrc = (RGB32*) pSourceBuffer; // wir kennen das Layout, deshalb casten wir den void pointer stumpf nach RGB32 (haha Java Programmierer ;-P)
     RGB32* pSrc = (RGB32*) pDestBuffer;
     for( int i = 0; i < lSourceSize / 4; ++i )
     {
         pDest[i] = pSrc[lSourceSize - i - 1];
     }
}


Negativ-Bild erzeugen ... (also pDest.f = (255 - pSrc.f)

void DoTransformFlipRGB32(void* pSourceBuffer, void*pDestBuffer, long lSourceSize )
{
    // Um den Algorithmus zu vereinfachen können wir einfach jedes Pixel als BYTE interpretieren
    // und so jedes BYTE 'invertieren'

   
     BYTE* pSrc = (BYTE*) pSourceBuffer;
     for( int i = 0; i < lSourceSize; ++i )
     {
         pDest[i] = (255 - pSrc[i]);
     }
}


Diese Funktion transformiert ein RGB32 in ein RGB24 Bild.
void DoTransformRGB32_RGB24(void* pSourceBuffer, void*pDestBuffer, long lSourceSize )
{
     // Da wir wissen, dass das quell bild immer 4 byte benutzt um einen pixel darzustellen machen wir jetzt eine Struktur mit dessen layout
     struct RGB32 { BYTE r; BYTE g; BYTE b; BYTE v; }
     // Da wir wissen, dass das Zielbild immer 3 byte benutzt um einen pixel darzustellen machen wir jetzt eine Struktur mit dessen layout
     struct RGB24 { BYTE r; BYTE g; BYTE b; }
   
     RGB32* pSrc = (RGB32*) pSourceBuffer; // wir kennen das Layout, deshalb casten wir den void pointer stumpf nach RGB32 (haha Java Programmierer ;-P)
     RGB24* pSrc = (RGB24*) pDestBuffer;
     for( int i = 0; i < lSourceSize / 4; ++i )
     {
         pDest[i].r = pSrc[i].r;
         pDest[i].g = pSrc[i].g;
         pDest[i].b = pSrc[i].b;
     }
}

Wie man hier im Beispie sieht benutzen wir type-casts um ein Farbraum Transformation durchzuführen.

Für höhere Beispiele müssten wir jetzt aber doch mehr Informationen aus dem Medientyp des IMediaSamples benutzen, z.B. die Höhe und Breite. Weiter benutzen alle Beispiele hier als Eingabe-Typ RGB32 und nur einmal als Ausgabe RGB24 ... .
Diese Vorraussetzungen muss man natürlich in CheckInput und CheckTransform erzwingen ...

hf

###

Hat dir diese Antwort geholfen?

Danke ButtonHilfreiche Antwort Button

Ich danke Dir! Dieser schicke Abriss hat mir sehr geholfen das ganze etwas tiefgreifender zu verstehen. Inzwischen läuft auch alles entschieden fixer.

Eine Frage noch: Prinzipiell kann ich statt RGB32 doch auch UINT32 nehmen, oder?

ähm, ja ....

((sizeof( RGB32 ) == sizeof( UINT32 )) && (sizeof( RGB32 ) == 4)) == true

Du musst dann eben nur die 'bit-shift', oder 'or' operationen selbst machen ... .

Hier ein Beispiel, dass das Bild kopiert und alles Blau aus dem Bild herausnimmt :
void DoTransformGB32(void* pSourceBuffer, void*pDestBuffer, long lSourceSize )
{
     UINT* pSrc = (UINT*) pSourceBuffer;
     UINT* pDest = (UINT*) pDestBuffer;
     for( int i = 0; i < lSourceSize / 4; ++i )
     {
         pDest[i] = (pSrc[i] & 0xFFFF00FF);

/* wäre sonst :
         pDest[i].r = pSrc[i].r;
         pDest[i].g = pSrc[i].g;
         pDest[i].b = = 0;
*/
     }
}

PS: Dieser Code ist ungetestet, da er aus dem Gedächtnis geschrieben wurde und nur zur Verdeutlichung gedacht ist (die Beispiele oben haben nen bug ...)

« Borland C++ Builder Einsteigerbuch?Stundenumrechnung »
 

Schnelle Hilfe: Hier nach ähnlichen Fragen und passenden Tipps suchen!

Fremdwörter? Erklärungen im Lexikon!
Type 1 Schriften
Type 1 ist ein Schriftformat, das die Schrift-Beschreibung in Form von PostScript-Befehlen speichert. PostScript-Schriften werden mithilfe von PostScript-Operationen besc...

Quellcode
Ein Quellcode, auch als Quelltext bekannt, bezeichnet den unkompilierten Programm-Code einer Software. Quell- oder Programm-Code ist der auch für Menschen lesbare Co...

Unicode
Unicode ist ein international anerkannter Standard, der als universeller Zeichencode ("Universal Code") dient und durch das Unicode-Konsortium entwickelt und verwaltet wi...