Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bf049b94 authored by Andreas Huber's avatar Andreas Huber
Browse files

Squashed commit of the following:

commit f2c38e5cf8cee3b597c744c9d6a9c0969ac8599a
Author: Andreas Huber <andih@google.com>
Date:   Mon Jan 28 16:33:07 2013 -0800

    Proper support for video format selection/negotiation.

    Change-Id: I7db86cef939d63b8064be1c74de9ad78e85d45d9

commit 488023b7bad086692ffe942114fa3cc0e59a16c0
Author: Andreas Huber <andih@google.com>
Date:   Mon Jan 28 11:21:23 2013 -0800

    Sink now notifies clients once it is disconnected.

    Change-Id: I2f0a458ef1ec30dda1272ad5a013fee4ee70edc9

commit 783932e40dd904aa531c263ad51280d9ca814dcb
Author: Andreas Huber <andih@google.com>
Date:   Tue Dec 18 15:03:40 2012 -0800

    Alternative DirectRenderer implementation.

    Change-Id: I307beb913d7a61cb938bcb02696cc2e82d2b8b07

commit 1935cc9a87824aea71fc8ebe2162f62ec634ce5a
Author: Andreas Huber <andih@google.com>
Date:   Tue Dec 18 10:24:27 2012 -0800

    Experimenting with wifi sink timing.

    Change-Id: I059bae9762cf11777666988a8b4ab2012b5807be

commit a859ee1eadd6a1d6a080667917e8b102c3770d61
Author: Andreas Huber <andih@google.com>
Date:   Thu Nov 15 11:16:30 2012 -0800

    wfd sink update.

    Change-Id: I026dfc580be92aa40dbbe7c1bc061fadf3b08be8

Change-Id: I191d3d7015869ca99254d813d074328fb5b2f479
parent 61eae44c
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -534,6 +534,16 @@ status_t ATSParser::Stream::parse(
        mBuffer->setRange(0, 0);
        mExpectedContinuityCounter = -1;

#if 0
        // Uncomment this if you'd rather see no corruption whatsoever on
        // screen and suspend updates until we come across another IDR frame.

        if (mStreamType == STREAMTYPE_H264) {
            ALOGI("clearing video queue");
            mQueue->clear(true /* clearFormat */);
        }
#endif

        return OK;
    }

+2 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@ LOCAL_SRC_FILES:= \
        ANetworkSession.cpp             \
        Parameters.cpp                  \
        ParsedMessage.cpp               \
        sink/DirectRenderer.cpp         \
        sink/LinearRegression.cpp       \
        sink/RTPSink.cpp                \
        sink/TunnelRenderer.cpp         \
@@ -18,6 +19,7 @@ LOCAL_SRC_FILES:= \
        source/TSPacketizer.cpp         \
        source/WifiDisplaySource.cpp    \
        TimeSeries.cpp                  \
        VideoFormats.cpp                \

LOCAL_C_INCLUDES:= \
        $(TOP)/frameworks/av/media/libstagefright \
+370 −0
Original line number Diff line number Diff line
/*
 * Copyright 2013, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "VideoFormats"
#include <utils/Log.h>

#include "VideoFormats.h"

#include <media/stagefright/foundation/ADebug.h>

namespace android {

VideoFormats::VideoFormats() {
    for (size_t i = 0; i < kNumResolutionTypes; ++i) {
        mResolutionEnabled[i] = 0;
    }

    setNativeResolution(RESOLUTION_CEA, 0);  // default to 640x480 p60
}

void VideoFormats::setNativeResolution(ResolutionType type, size_t index) {
    CHECK_LT(type, kNumResolutionTypes);
    CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL));

    mNativeType = type;
    mNativeIndex = index;

    setResolutionEnabled(type, index);
}

void VideoFormats::getNativeResolution(
        ResolutionType *type, size_t *index) const {
    *type = mNativeType;
    *index = mNativeIndex;
}

void VideoFormats::disableAll() {
    for (size_t i = 0; i < kNumResolutionTypes; ++i) {
        mResolutionEnabled[i] = 0;
    }
}

void VideoFormats::enableAll() {
    for (size_t i = 0; i < kNumResolutionTypes; ++i) {
        mResolutionEnabled[i] = 0xffffffff;
    }
}

void VideoFormats::setResolutionEnabled(
        ResolutionType type, size_t index, bool enabled) {
    CHECK_LT(type, kNumResolutionTypes);
    CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL));

    if (enabled) {
        mResolutionEnabled[type] |= (1ul << index);
    } else {
        mResolutionEnabled[type] &= ~(1ul << index);
    }
}

bool VideoFormats::isResolutionEnabled(
        ResolutionType type, size_t index) const {
    CHECK_LT(type, kNumResolutionTypes);
    CHECK(GetConfiguration(type, index, NULL, NULL, NULL, NULL));

    return mResolutionEnabled[type] & (1ul << index);
}

// static
bool VideoFormats::GetConfiguration(
        ResolutionType type,
        size_t index,
        size_t *width, size_t *height, size_t *framesPerSecond,
        bool *interlaced) {
    CHECK_LT(type, kNumResolutionTypes);

    if (index >= 32) {
        return false;
    }

    static const struct config_t {
        size_t width, height, framesPerSecond;
        bool interlaced;
    } kConfigs[kNumResolutionTypes][32] = {
        {
            // CEA Resolutions
            { 640, 480, 60, false },
            { 720, 480, 60, false },
            { 720, 480, 60, true },
            { 720, 576, 50, false },
            { 720, 576, 50, true },
            { 1280, 720, 30, false },
            { 1280, 720, 60, false },
            { 1920, 1080, 30, false },
            { 1920, 1080, 60, false },
            { 1920, 1080, 60, true },
            { 1280, 720, 25, false },
            { 1280, 720, 50, false },
            { 1920, 1080, 25, false },
            { 1920, 1080, 50, false },
            { 1920, 1080, 50, true },
            { 1280, 720, 24, false },
            { 1920, 1080, 24, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
        },
        {
            // VESA Resolutions
            { 800, 600, 30, false },
            { 800, 600, 60, false },
            { 1024, 768, 30, false },
            { 1024, 768, 60, false },
            { 1152, 864, 30, false },
            { 1152, 864, 60, false },
            { 1280, 768, 30, false },
            { 1280, 768, 60, false },
            { 1280, 800, 30, false },
            { 1280, 800, 60, false },
            { 1360, 768, 30, false },
            { 1360, 768, 60, false },
            { 1366, 768, 30, false },
            { 1366, 768, 60, false },
            { 1280, 1024, 30, false },
            { 1280, 1024, 60, false },
            { 1400, 1050, 30, false },
            { 1400, 1050, 60, false },
            { 1440, 900, 30, false },
            { 1440, 900, 60, false },
            { 1600, 900, 30, false },
            { 1600, 900, 60, false },
            { 1600, 1200, 30, false },
            { 1600, 1200, 60, false },
            { 1680, 1024, 30, false },
            { 1680, 1024, 60, false },
            { 1680, 1050, 30, false },
            { 1680, 1050, 60, false },
            { 1920, 1200, 30, false },
            { 1920, 1200, 60, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
        },
        {
            // HH Resolutions
            { 800, 480, 30, false },
            { 800, 480, 60, false },
            { 854, 480, 30, false },
            { 854, 480, 60, false },
            { 864, 480, 30, false },
            { 864, 480, 60, false },
            { 640, 360, 30, false },
            { 640, 360, 60, false },
            { 960, 540, 30, false },
            { 960, 540, 60, false },
            { 848, 480, 30, false },
            { 848, 480, 60, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
            { 0, 0, 0, false },
        }
    };

    const config_t *config = &kConfigs[type][index];

    if (config->width == 0) {
        return false;
    }

    if (width) {
        *width = config->width;
    }

    if (height) {
        *height = config->height;
    }

    if (framesPerSecond) {
        *framesPerSecond = config->framesPerSecond;
    }

    if (interlaced) {
        *interlaced = config->interlaced;
    }

    return true;
}

bool VideoFormats::parseFormatSpec(const char *spec) {
    CHECK_EQ(kNumResolutionTypes, 3);

    unsigned native, dummy;

    if (sscanf(
            spec,
            "%02x %02x %02x %02x %08X %08X %08X",
            &native,
            &dummy,
            &dummy,
            &dummy,
            &mResolutionEnabled[0],
            &mResolutionEnabled[1],
            &mResolutionEnabled[2]) != 7) {
        return false;
    }

    mNativeIndex = native >> 3;
    mNativeType = (ResolutionType)(native & 7);

    if (mNativeType >= kNumResolutionTypes) {
        return false;
    }

    return GetConfiguration(mNativeType, mNativeIndex, NULL, NULL, NULL, NULL);
}

AString VideoFormats::getFormatSpec() const {
    CHECK_EQ(kNumResolutionTypes, 3);

    // wfd_video_formats:
    // 1 byte "native"
    // 1 byte "preferred-display-mode-supported" 0 or 1
    // one or more avc codec structures
    //   1 byte profile
    //   1 byte level
    //   4 byte CEA mask
    //   4 byte VESA mask
    //   4 byte HH mask
    //   1 byte latency
    //   2 byte min-slice-slice
    //   2 byte slice-enc-params
    //   1 byte framerate-control-support
    //   max-hres (none or 2 byte)
    //   max-vres (none or 2 byte)

    return StringPrintf(
            "%02x 00 02 02 %08x %08x %08x 00 0000 0000 00 none none",
            (mNativeIndex << 3) | mNativeType,
            mResolutionEnabled[0],
            mResolutionEnabled[1],
            mResolutionEnabled[2]);
}

// static
bool VideoFormats::PickBestFormat(
        const VideoFormats &sinkSupported,
        const VideoFormats &sourceSupported,
        ResolutionType *chosenType,
        size_t *chosenIndex) {
    ResolutionType nativeType;
    size_t nativeIndex;
    sinkSupported.getNativeResolution(&nativeType, &nativeIndex);
    if (sinkSupported.isResolutionEnabled(nativeType, nativeIndex)) {
        if (sourceSupported.isResolutionEnabled(nativeType, nativeIndex)) {
            ALOGI("Choosing sink's native resolution");
            *chosenType = nativeType;
            *chosenIndex = nativeIndex;
            return true;
        }
    } else {
        ALOGW("Sink advertised native resolution that it doesn't "
              "actually support... ignoring");
    }

    sourceSupported.getNativeResolution(&nativeType, &nativeIndex);
    if (sourceSupported.isResolutionEnabled(nativeType, nativeIndex)) {
        if (sinkSupported.isResolutionEnabled(nativeType, nativeIndex)) {
            ALOGI("Choosing source's native resolution");
            *chosenType = nativeType;
            *chosenIndex = nativeIndex;
            return true;
        }
    } else {
        ALOGW("Source advertised native resolution that it doesn't "
              "actually support... ignoring");
    }

    bool first = true;
    uint32_t bestScore = 0;
    size_t bestType = 0;
    size_t bestIndex = 0;
    for (size_t i = 0; i < kNumResolutionTypes; ++i) {
        for (size_t j = 0; j < 32; ++j) {
            size_t width, height, framesPerSecond;
            bool interlaced;
            if (!GetConfiguration(
                        (ResolutionType)i,
                        j,
                        &width, &height, &framesPerSecond, &interlaced)) {
                break;
            }

            if (!sinkSupported.isResolutionEnabled((ResolutionType)i, j)
                    || !sourceSupported.isResolutionEnabled(
                        (ResolutionType)i, j)) {
                continue;
            }

            ALOGV("type %u, index %u, %u x %u %c%u supported",
                  i, j, width, height, interlaced ? 'i' : 'p', framesPerSecond);

            uint32_t score = width * height * framesPerSecond;
            if (!interlaced) {
                score *= 2;
            }

            if (first || score > bestScore) {
                bestScore = score;
                bestType = i;
                bestIndex = j;

                first = false;
            }
        }
    }

    if (first) {
        return false;
    }

    *chosenType = (ResolutionType)bestType;
    *chosenIndex = bestIndex;

    return true;
}

}  // namespace android
+83 −0
Original line number Diff line number Diff line
/*
 * Copyright 2013, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef VIDEO_FORMATS_H_

#define VIDEO_FORMATS_H_

#include <media/stagefright/foundation/ABase.h>

#include <stdint.h>

namespace android {

struct AString;

// This class encapsulates that video resolution capabilities of a wfd source
// or sink as outlined in the wfd specs. Currently three sets of resolutions
// are specified, each of which supports up to 32 resolutions.
// In addition to its capabilities each sink/source also publishes its
// "native" resolution, presumably one that is preferred among all others
// because it wouldn't require any scaling and directly corresponds to the
// display capabilities/pixels.
struct VideoFormats {
    VideoFormats();

    enum ResolutionType {
        RESOLUTION_CEA,
        RESOLUTION_VESA,
        RESOLUTION_HH,
        kNumResolutionTypes,
    };

    void setNativeResolution(ResolutionType type, size_t index);
    void getNativeResolution(ResolutionType *type, size_t *index) const;

    void disableAll();
    void enableAll();

    void setResolutionEnabled(
            ResolutionType type, size_t index, bool enabled = true);

    bool isResolutionEnabled(ResolutionType type, size_t index) const;

    static bool GetConfiguration(
            ResolutionType type, size_t index,
            size_t *width, size_t *height, size_t *framesPerSecond,
            bool *interlaced);

    bool parseFormatSpec(const char *spec);
    AString getFormatSpec() const;

    static bool PickBestFormat(
            const VideoFormats &sinkSupported,
            const VideoFormats &sourceSupported,
            ResolutionType *chosenType,
            size_t *chosenIndex);

private:
    ResolutionType mNativeType;
    size_t mNativeIndex;

    uint32_t mResolutionEnabled[kNumResolutionTypes];

    DISALLOW_EVIL_CONSTRUCTORS(VideoFormats);
};

}  // namespace android

#endif  // VIDEO_FORMATS_H_
+14 −3
Original line number Diff line number Diff line
@@ -21,7 +21,14 @@
#include "RTPSink.h"

#include "ANetworkSession.h"

#if USE_TUNNEL_RENDERER
#include "TunnelRenderer.h"
#define RENDERER_CLASS TunnelRenderer
#else
#include "DirectRenderer.h"
#define RENDERER_CLASS DirectRenderer
#endif

#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -238,9 +245,11 @@ void RTPSink::Source::addReportBlock(

RTPSink::RTPSink(
        const sp<ANetworkSession> &netSession,
        const sp<IGraphicBufferProducer> &bufferProducer)
        const sp<IGraphicBufferProducer> &bufferProducer,
        const sp<AMessage> &notify)
    : mNetSession(netSession),
      mSurfaceTex(bufferProducer),
      mNotify(notify),
      mRTPPort(0),
      mRTPSessionID(0),
      mRTCPSessionID(0),
@@ -470,6 +479,7 @@ status_t RTPSink::parseRTP(const sp<ABuffer> &buffer) {
    uint32_t rtpTime = U32_AT(&data[4]);
    uint16_t seqNo = U16_AT(&data[2]);

#if 0
    int64_t arrivalTimeUs;
    CHECK(buffer->meta()->findInt64("arrivalTimeUs", &arrivalTimeUs));

@@ -500,6 +510,7 @@ status_t RTPSink::parseRTP(const sp<ABuffer> &buffer) {
            ALOGI("packet was %.2f ms late", latenessMs);
        }
    }
#endif

    sp<AMessage> meta = buffer->meta();
    meta->setInt32("ssrc", srcId);
@@ -515,12 +526,12 @@ status_t RTPSink::parseRTP(const sp<ABuffer> &buffer) {
            sp<AMessage> notifyLost = new AMessage(kWhatPacketLost, id());
            notifyLost->setInt32("ssrc", srcId);

            mRenderer = new TunnelRenderer(notifyLost, mSurfaceTex);
            mRenderer = new RENDERER_CLASS(notifyLost, mSurfaceTex);
            looper()->registerHandler(mRenderer);
        }

        sp<AMessage> queueBufferMsg =
            new AMessage(TunnelRenderer::kWhatQueueBuffer, mRenderer->id());
            new AMessage(RENDERER_CLASS::kWhatQueueBuffer, mRenderer->id());

        sp<Source> source = new Source(seqNo, buffer, queueBufferMsg);
        mSources.add(srcId, source);
Loading