Bild-Seitenverhältnis

In diesem Thema werden zwei verwandte Konzepte beschrieben: bildbezogenes Seitenverhältnis und Pixel-Seitenverhältnis. Anschließend wird beschrieben, wie diese Konzepte mithilfe von Microsoft Media Foundation ausgedrückt werden.

Bild-Seitenverhältnis

Das Seitenverhältnis des Bilds definiert die Form des angezeigten Videobilds. Bild-Seitenverhältnis wird X:Y notiert, wobei X:Y das Verhältnis von Bildbreite zu Bildhöhe ist. Die meisten Videostandards verwenden das Seitenverhältnis 4:3 oder 16:9. Das Seitenverhältnis 16:9 wird häufig als Widescreen bezeichnet. Für Den Film wird häufig ein Seitenverhältnis von 1:85:1 oder 1:66:1 verwendet. Bild-Seitenverhältnis wird auch als Anzeige-Seitenverhältnis (DAR) bezeichnet.

Diagramm mit den Seitenverhältnis 4:3 und 16:9

Manchmal hat das Videobild nicht die gleiche Form wie der Anzeigebereich. Beispielsweise könnte ein 4:3-Video auf einem Widescreen-Fernsehgerät (16×9) angezeigt werden. In Computervideos kann das Video in einem Fenster mit einer beliebigen Größe angezeigt werden. In diesem Fall gibt es drei Möglichkeiten, das Bild so zu erstellen, dass es in den Anzeigebereich passt:

  • Strecken Sie das Bild entlang einer Achse, um es an den Anzeigebereich zu passen.
  • Skalieren Sie das Bild so, dass es an den Anzeigebereich passt, und halten Sie dabei das ursprüngliche Seitenverhältnis des Bilds bei.
  • Zuschneiden des Bilds.

Das Strecken des Bilds an den Anzeigebereich ist fast immer falsch, da das richtige Bildbild-Seitenverhältnis nicht beibehalten wird.

Letterboxing

Das Skalieren eines Widescreenbilds an eine 4:3-Anzeige wird als Letterboxing bezeichnet, wie im nächsten Diagramm dargestellt. Die resultierenden winkelförmigen Bereiche am oberen und unteren Rand des Bilds werden in der Regel mit Schwarz gefüllt, obwohl andere Farben verwendet werden können.

Diagramm, das den richtigen Weg zum Letterbox-Text zeigt

Der umgekehrte Fall, das Skalieren eines 4:3-Bilds für eine Widescreenanzeige, wird manchmal als Pillarboxing bezeichnet. Der Begriff Letterbox wird jedoch auch allgemein verwendet, um ein Videobild so zu skalieren, dass es an einen bestimmten Anzeigebereich passt.

Diagramm mit Pillarboxing

Schwenken und Scannen

Schwenken und Scannen ist eine Technik, bei der ein Widescreenbild auf einen rechteckigen Bereich 4×3 zugeschnitten wird, um es auf einem 4:3-Anzeigegerät anzuzeigen. Das resultierende Bild füllt die gesamte Anzeige, ohne dass schwarze Letterboxbereiche erforderlich sind, aber Teile des originalen Bilds werden aus dem Bild zugeschnitten. Der bereich, der zugeschnitten wird, kann sich von Frame zu Frame bewegen, wenn sich der für Sie interessierende Bereich verschiebt. Der Begriff "Schwenken" in Schwenken und Scannen bezieht sich auf den Schwenkeffekt, der durch das Verschieben des Schwenk- und Scanbereichs verursacht wird.

Diagramm, das Schwenken und Scannen zeigt

Pixel-Seitenverhältnis

Das Pixel-Seitenverhältnis (PAR) misst die Form eines Pixels.

Wenn ein digitales Bild erfasst wird, wird das Bild sowohl vertikal als auch horizontal entnommen, was zu einem rechteckigen Array von quantisierten Stichproben führt, das als Pixel oder Ziern bezeichnet wird. Die Form des Samplingrasters bestimmt die Form der Pixel im digitalisierten Bild.

Im Folgenden finden Sie ein Beispiel, in dem kleine Zahlen verwendet werden, um die Mathematik einfach zu halten. Angenommen, das ursprüngliche Bild ist quadratisch (d. h. das Seitenverhältnis des Bilds ist 1:1). und angenommen, das Samplingraster enthält 12 Elemente, die in einem 4×3-Raster angeordnet sind. Die Form jedes resultierenden Pixels ist größer als breit. Insbesondere ist die Form jedes Pixels 3×4. Pixel, die nicht quadratisch sind, werden als nicht quadratische Pixel bezeichnet.

Diagramm, das ein Raster für die Stichprobenentnahme ohne Quadrat zeigt

Das Pixel-Seitenverhältnis gilt auch für das Anzeigegerät. Die physische Form des Anzeigegeräts und die physische Pixelauflösung (über und nach unten) bestimmen das PAR des Anzeigegeräts. Computermonitore verwenden in der Regel Quadratpixel. Wenn das Bild PAR und das Anzeige-PAR nicht übereinstimmen, muss das Bild in einer Dimension skaliert werden, entweder vertikal oder horizontal, um ordnungsgemäß angezeigt zu werden. Die folgende Formel bezieht sich auf PAR, das Anzeigeverhältnis (DAR) und die Bildgröße in Pixel:

DAR = (Bildbreite in Pixel / Bildhöhe in Pixel) × PAR

Beachten Sie, dass Bildbreite und Bildhöhe in dieser Formel auf das Bild im Arbeitsspeicher verweisen, nicht auf das angezeigte Bild.

Hier sehen Sie ein beispiel aus der realen Welt: Das analoge NTSC-M-Video enthält 480 Scanzeilen im aktiven Bildbereich. ITU-R Rec. BT.601 gibt eine horizontale Samplingrate von 704 sichtbaren Pixeln pro Zeile an, die ein digitales Bild mit 704 x 480 Pixel ergibt. Das beabsichtigte Bildbild-Seitenverhältnis ist 4:3 und ergibt einen PAR-Anteil von 10:11.

  • DAR: 4:3
  • Breite in Pixel: 704
  • Höhe in Pixel: 480
  • PAR: 10/11

4/3 = (704/420) x (10/11)

Um dieses Bild ordnungsgemäß auf einem Anzeigegerät mit quadratischen Pixeln anzuzeigen, müssen Sie entweder die Breite um 10/11 oder die Höhe um 11/10 skalieren.

Arbeiten mit Seitenverhältnis

Die richtige Form eines Videoframes wird durch das Pixel-Seitenverhältnis (PAR) und den Anzeigebereich definiert.

  • Der PAR definiert die Form der Pixel in einem Bild. Quadratische Pixel haben ein Seitenverhältnis von 1:1. Jedes andere Seitenverhältnis beschreibt ein nicht quadratisches Pixel. Beispielsweise verwendet NTSC-Fernsehsendungen einen 10:11 PAR. Wenn Sie das Video auf einem Computermonitor präsentieren, hat die Anzeige quadratische Pixel (1:1 PAR). Das PAR des Quellinhalts wird im MF _ MT PIXEL _ ASPECT _ _ RATIO-Attribut für den Medientyp angegeben.
  • Der Anzeigebereich ist der Bereich des Videobilds, das angezeigt werden soll. Es gibt zwei relevante Anzeigebereiche, die im Medientyp angegeben werden können:
    • Schwenk-und-Scan-Öffnung. Die Schwenk-und-Scan-Öffnung ist ein 4×3-Videobereich, der im Schwenk-/Scanmodus angezeigt werden soll. Es wird verwendet, um Breitbildschirminhalte auf einer 4×3-Anzeige ohne Letterboxing anzuzeigen. Die Schwenk- und Scan-Öffnung wird im MF _ MT PAN SCAN _ _ _ APERTURE-Attribut angegeben und sollte nur verwendet werden, wenn das MF MT PAN SCAN _ _ _ _ ENABLED-Attribut TRUE ist.
    • Blende anzeigen. Diese Öffnung ist in einigen Videostandards definiert. Alles außerhalb der Anzeigeblende ist der überscannte Bereich und sollte nicht angezeigt werden. NtSC-Fernsehsendungen sind z. B. 720×480 Pixel mit einer Anzeigeperleer von 704×480. Die Anzeigeblende wird im MF _ MT MINIMUM _ DISPLAY _ _ APERTURE-Attribut angegeben. Falls vorhanden, sollte sie verwendet werden, wenn der Schwenk- und Scanmodus FALSE ist.

Wenn der Schwenk- und Can-Modus FALSE ist und keine Anzeigeblende definiert ist, sollte der gesamte Videoframe angezeigt werden. Tatsächlich ist dies bei den meisten Videoinhalten der Fall, bei dem es sich nicht um Fernseh- und DVD-Videos handelt. Das Seitenverhältnis des gesamten Bilds wird als (Anzeigebereichsbreitenhöhe / ) × PAR berechnet.

Codebeispiele

Suchen des Anzeigebereichs

Der folgende Code zeigt, wie sie den Anzeigebereich vom Medientyp erhalten.

MFVideoArea MakeArea(float x, float y, DWORD width, DWORD height);

HRESULT GetVideoDisplayArea(IMFMediaType *pType, MFVideoArea *pArea)
{
    HRESULT hr = S_OK;
    BOOL bPanScan = FALSE;
    UINT32 width = 0, height = 0;

    bPanScan = MFGetAttributeUINT32(pType, MF_MT_PAN_SCAN_ENABLED, FALSE);

    // In pan-and-scan mode, try to get the pan-and-scan region.
    if (bPanScan)
    {
        hr = pType->GetBlob(MF_MT_PAN_SCAN_APERTURE, (UINT8*)pArea, 
            sizeof(MFVideoArea), NULL);
    }

    // If not in pan-and-scan mode, or the pan-and-scan region is not set, 
    // get the minimimum display aperture.

    if (!bPanScan || hr == MF_E_ATTRIBUTENOTFOUND)
    {
        hr = pType->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE, (UINT8*)pArea, 
            sizeof(MFVideoArea), NULL);

        if (hr == MF_E_ATTRIBUTENOTFOUND)
        {
            // Minimum display aperture is not set.

            // For backward compatibility with some components, 
            // check for a geometric aperture. 

            hr = pType->GetBlob(MF_MT_GEOMETRIC_APERTURE, (UINT8*)pArea, 
                sizeof(MFVideoArea), NULL);
        }

        // Default: Use the entire video area.

        if (hr == MF_E_ATTRIBUTENOTFOUND)
        {
            hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &width, &height);

            if (SUCCEEDED(hr))
            {
                *pArea = MakeArea(0.0, 0.0, width, height);
            }
        }
    }
    return hr;
}
MFOffset MakeOffset(float v)
{
    MFOffset offset;
    offset.value = short(v);
    offset.fract = WORD(65536 * (v-offset.value));
    return offset;
}
MFVideoArea MakeArea(float x, float y, DWORD width, DWORD height)
{
    MFVideoArea area;
    area.OffsetX = MakeOffset(x);
    area.OffsetY = MakeOffset(y);
    area.Area.cx = width;
    area.Area.cy = height;
    return area;
}

Konvertieren zwischen Pixel-Seitenverhältnis

Der folgende Code zeigt, wie ein Rechteck von einem Pixel-Seitenverhältnis (PAR) in ein anderes konvertiert wird, während das Seitenverhältnis des Bilds beibehalten wird.

//-----------------------------------------------------------------------------
// Converts a rectangle from one pixel aspect ratio (PAR) to another PAR.
// Returns the corrected rectangle.
//
// For example, a 720 x 486 rect with a PAR of 9:10, when converted to 1x1 PAR,
// must be stretched to 720 x 540.
//-----------------------------------------------------------------------------

RECT CorrectAspectRatio(const RECT& src, const MFRatio& srcPAR, const MFRatio& destPAR)
{
    // Start with a rectangle the same size as src, but offset to (0,0).
    RECT rc = {0, 0, src.right - src.left, src.bottom - src.top};

    // If the source and destination have the same PAR, there is nothing to do.
    // Otherwise, adjust the image size, in two steps:
    //  1. Transform from source PAR to 1:1
    //  2. Transform from 1:1 to destination PAR.

    if ((srcPAR.Numerator != destPAR.Numerator) || 
        (srcPAR.Denominator != destPAR.Denominator))
    {
        // Correct for the source's PAR.

        if (srcPAR.Numerator > srcPAR.Denominator)
        {
            // The source has "wide" pixels, so stretch the width.
            rc.right = MulDiv(rc.right, srcPAR.Numerator, srcPAR.Denominator);
        }
        else if (srcPAR.Numerator < srcPAR.Denominator)
        {
            // The source has "tall" pixels, so stretch the height.
            rc.bottom = MulDiv(rc.bottom, srcPAR.Denominator, srcPAR.Numerator);
        }
        // else: PAR is 1:1, which is a no-op.

        // Next, correct for the target's PAR. This is the inverse operation of 
        // the previous.

        if (destPAR.Numerator > destPAR.Denominator)
        {
            // The destination has "wide" pixels, so stretch the height.
            rc.bottom = MulDiv(rc.bottom, destPAR.Numerator, destPAR.Denominator);
        }
        else if (destPAR.Numerator < destPAR.Denominator)
        {
            // The destination has "tall" pixels, so stretch the width.
            rc.right = MulDiv(rc.right, destPAR.Denominator, destPAR.Numerator);
        }
        // else: PAR is 1:1, which is a no-op.
    }
    return rc;
}

Berechnen des Letterbox-Bereichs

Der folgende Code berechnet den Letterboxbereich bei einem Quell- und Zielrechteck. Es wird davon ausgegangen, dass beide Rechtecke den gleichen Par aufweisen.

RECT LetterBoxRect(const RECT& rcSrc, const RECT& rcDst)
{
    // Compute source/destination ratios.
    int iSrcWidth  = rcSrc.right - rcSrc.left;
    int iSrcHeight = rcSrc.bottom - rcSrc.top;

    int iDstWidth  = rcDst.right - rcDst.left;
    int iDstHeight = rcDst.bottom - rcDst.top;

    int iDstLBWidth;
    int iDstLBHeight;

    if (MulDiv(iSrcWidth, iDstHeight, iSrcHeight) <= iDstWidth) 
    {
        // Column letterboxing ("pillar box")
        iDstLBWidth  = MulDiv(iDstHeight, iSrcWidth, iSrcHeight);
        iDstLBHeight = iDstHeight;
    }
    else 
    {
        // Row letterboxing.
        iDstLBWidth  = iDstWidth;
        iDstLBHeight = MulDiv(iDstWidth, iSrcHeight, iSrcWidth);
    }

    // Create a centered rectangle within the current destination rect

    LONG left = rcDst.left + ((iDstWidth - iDstLBWidth) / 2);
    LONG top = rcDst.top + ((iDstHeight - iDstLBHeight) / 2);

    RECT rc;
    SetRect(&rc, left, top, left + iDstLBWidth, top + iDstLBHeight);
    return rc;
}

Medientypen

Videomedientypen

MF _ MT _ MINIMUM _ DISPLAY _ APERTURE

MF _ MT _ PAN _ SCAN _ APERTURE

MF _ MT PAN SCAN _ _ _ AKTIVIERT

MF _ MT _ PIXEL _ ASPECT _ RATIO