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

Commit d9aa7b4d authored by Andreas Huber's avatar Andreas Huber Committed by Android (Google) Code Review
Browse files

Merge "Better transport stream timestamp handling." into jb-mr1-dev

parents c910b7ac 28e17ed7
Loading
Loading
Loading
Loading
+196 −101
Original line number Diff line number Diff line
@@ -70,6 +70,9 @@ struct WifiDisplaySource::PlaybackSession::Track : public RefBase {
    status_t start();
    status_t stop();

    void queueAccessUnit(const sp<ABuffer> &accessUnit);
    sp<ABuffer> dequeueAccessUnit();

protected:
    virtual ~Track();

@@ -82,6 +85,7 @@ private:
    bool mStarted;
    ssize_t mPacketizerTrackIndex;
    bool mIsAudio;
    List<sp<ABuffer> > mQueuedAccessUnits;

    static bool IsAudioFormat(const sp<AMessage> &format);

@@ -182,6 +186,24 @@ status_t WifiDisplaySource::PlaybackSession::Track::stop() {
    return err;
}

void WifiDisplaySource::PlaybackSession::Track::queueAccessUnit(
        const sp<ABuffer> &accessUnit) {
    mQueuedAccessUnits.push_back(accessUnit);
}

sp<ABuffer> WifiDisplaySource::PlaybackSession::Track::dequeueAccessUnit() {
    if (mQueuedAccessUnits.empty()) {
        return NULL;
    }

    sp<ABuffer> accessUnit = *mQueuedAccessUnits.begin();
    CHECK(accessUnit != NULL);

    mQueuedAccessUnits.erase(mQueuedAccessUnits.begin());

    return accessUnit;
}

////////////////////////////////////////////////////////////////////////////////

WifiDisplaySource::PlaybackSession::PlaybackSession(
@@ -198,6 +220,7 @@ WifiDisplaySource::PlaybackSession::PlaybackSession(
      mTSQueue(new ABuffer(12 + kMaxNumTSPacketsPerRTPPacket * 188)),
      mPrevTimeUs(-1ll),
      mTransportMode(TRANSPORT_UDP),
      mAllTracksHavePacketizerIndex(false),
      mRTPChannel(0),
      mRTCPChannel(0),
      mRTPPort(0),
@@ -675,129 +698,49 @@ void WifiDisplaySource::PlaybackSession::onMessageReceived(
            if (what == Converter::kWhatAccessUnit) {
                const sp<Track> &track = mTracks.valueFor(trackIndex);

                uint32_t flags = 0;

                ssize_t packetizerTrackIndex = track->packetizerTrackIndex();
                if (packetizerTrackIndex < 0) {
                    flags = TSPacketizer::EMIT_PAT_AND_PMT;

                if (packetizerTrackIndex < 0) {
                    packetizerTrackIndex =
                        mPacketizer->addTrack(track->getFormat());

                    if (packetizerTrackIndex >= 0) {
                        track->setPacketizerTrackIndex(packetizerTrackIndex);
                    }
                }
                    CHECK_GE(packetizerTrackIndex, 0);

                if (packetizerTrackIndex >= 0) {
                    sp<ABuffer> accessUnit;
                    CHECK(msg->findBuffer("accessUnit", &accessUnit));

                    bool isHDCPEncrypted = false;
                    uint64_t inputCTR;
                    uint8_t HDCP_private_data[16];
                    if (mHDCP != NULL && !track->isAudio()) {
                        isHDCPEncrypted = true;
                    track->setPacketizerTrackIndex(packetizerTrackIndex);

                        status_t err = mHDCP->encrypt(
                                accessUnit->data(), accessUnit->size(),
                                trackIndex  /* streamCTR */,
                                &inputCTR,
                                accessUnit->data());
                    if (allTracksHavePacketizerIndex()) {
                        status_t err = packetizeQueuedAccessUnits();

                        if (err != OK) {
                            ALOGI("Failed to HDCP-encrypt media data (err %d)",
                                  err);

                            // Inform WifiDisplaySource of our premature death
                            // (wish).
                            sp<AMessage> notify = mNotify->dup();
                            notify->setInt32("what", kWhatSessionDead);
                            notify->post();

                            break;
                        }

                        HDCP_private_data[0] = 0x00;

                        HDCP_private_data[1] =
                            (((trackIndex >> 30) & 3) << 1) | 1;

                        HDCP_private_data[2] = (trackIndex >> 22) & 0xff;

                        HDCP_private_data[3] =
                            (((trackIndex >> 15) & 0x7f) << 1) | 1;

                        HDCP_private_data[4] = (trackIndex >> 7) & 0xff;

                        HDCP_private_data[5] =
                            ((trackIndex & 0x7f) << 1) | 1;

                        HDCP_private_data[6] = 0x00;

                        HDCP_private_data[7] =
                            (((inputCTR >> 60) & 0x0f) << 1) | 1;

                        HDCP_private_data[8] = (inputCTR >> 52) & 0xff;

                        HDCP_private_data[9] =
                            (((inputCTR >> 45) & 0x7f) << 1) | 1;

                        HDCP_private_data[10] = (inputCTR >> 37) & 0xff;

                        HDCP_private_data[11] =
                            (((inputCTR >> 30) & 0x7f) << 1) | 1;

                        HDCP_private_data[12] = (inputCTR >> 22) & 0xff;

                        HDCP_private_data[13] =
                            (((inputCTR >> 15) & 0x7f) << 1) | 1;

                        HDCP_private_data[14] = (inputCTR >> 7) & 0xff;

                        HDCP_private_data[15] =
                            ((inputCTR & 0x7f) << 1) | 1;

                        flags |= TSPacketizer::IS_ENCRYPTED;
                    }

                    int64_t timeUs;
                    CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));

                    if (mPrevTimeUs < 0ll || mPrevTimeUs + 100000ll >= timeUs) {
                        flags |= TSPacketizer::EMIT_PCR;
                        mPrevTimeUs = timeUs;
                }

                    sp<ABuffer> packets;
                    mPacketizer->packetize(
                            packetizerTrackIndex, accessUnit, &packets, flags,
                            isHDCPEncrypted ? NULL : HDCP_private_data,
                            isHDCPEncrypted ? 0 : sizeof(HDCP_private_data));

                    for (size_t offset = 0;
                            offset < packets->size(); offset += 188) {
                        bool lastTSPacket = (offset + 188 >= packets->size());

                        // We're only going to flush video, audio packets are
                        // much more frequent and would waste all that space
                        // available in a full sized UDP packet.
                        bool flush =
                            lastTSPacket
                                && ((ssize_t)trackIndex == mVideoTrackIndex);
                sp<ABuffer> accessUnit;
                CHECK(msg->findBuffer("accessUnit", &accessUnit));

                        appendTSData(
                                packets->data() + offset,
                                188,
                                true /* timeDiscontinuity */,
                                flush);
                if (!allTracksHavePacketizerIndex()) {
                    track->queueAccessUnit(accessUnit);
                    break;
                }

#if LOG_TRANSPORT_STREAM
                    if (mLogFile != NULL) {
                        fwrite(packets->data(), 1, packets->size(), mLogFile);
                    }
#endif
                status_t err = packetizeAccessUnit(trackIndex, accessUnit);

                if (err != OK) {
                    // Inform WifiDisplaySource of our premature death
                    // (wish).
                    sp<AMessage> notify = mNotify->dup();
                    notify->setInt32("what", kWhatSessionDead);
                    notify->post();
                }
                break;
            } else if (what == Converter::kWhatEOS) {
                CHECK_EQ(what, Converter::kWhatEOS);

@@ -1338,5 +1281,157 @@ status_t WifiDisplaySource::PlaybackSession::sendPacket(
    return mNetSession->sendRequest(sessionID, data, size);
}

bool WifiDisplaySource::PlaybackSession::allTracksHavePacketizerIndex() {
    if (mAllTracksHavePacketizerIndex) {
        return true;
    }

    for (size_t i = 0; i < mTracks.size(); ++i) {
        if (mTracks.valueAt(i)->packetizerTrackIndex() < 0) {
            return false;
        }
    }

    mAllTracksHavePacketizerIndex = true;

    return true;
}

status_t WifiDisplaySource::PlaybackSession::packetizeAccessUnit(
        size_t trackIndex, const sp<ABuffer> &accessUnit) {
    const sp<Track> &track = mTracks.valueFor(trackIndex);

    uint32_t flags = 0;

    bool isHDCPEncrypted = false;
    uint64_t inputCTR;
    uint8_t HDCP_private_data[16];
    if (mHDCP != NULL && !track->isAudio()) {
        isHDCPEncrypted = true;

        status_t err = mHDCP->encrypt(
                accessUnit->data(), accessUnit->size(),
                trackIndex  /* streamCTR */,
                &inputCTR,
                accessUnit->data());

        if (err != OK) {
            ALOGE("Failed to HDCP-encrypt media data (err %d)",
                  err);

            return err;
        }

        HDCP_private_data[0] = 0x00;

        HDCP_private_data[1] =
            (((trackIndex >> 30) & 3) << 1) | 1;

        HDCP_private_data[2] = (trackIndex >> 22) & 0xff;

        HDCP_private_data[3] =
            (((trackIndex >> 15) & 0x7f) << 1) | 1;

        HDCP_private_data[4] = (trackIndex >> 7) & 0xff;

        HDCP_private_data[5] =
            ((trackIndex & 0x7f) << 1) | 1;

        HDCP_private_data[6] = 0x00;

        HDCP_private_data[7] =
            (((inputCTR >> 60) & 0x0f) << 1) | 1;

        HDCP_private_data[8] = (inputCTR >> 52) & 0xff;

        HDCP_private_data[9] =
            (((inputCTR >> 45) & 0x7f) << 1) | 1;

        HDCP_private_data[10] = (inputCTR >> 37) & 0xff;

        HDCP_private_data[11] =
            (((inputCTR >> 30) & 0x7f) << 1) | 1;

        HDCP_private_data[12] = (inputCTR >> 22) & 0xff;

        HDCP_private_data[13] =
            (((inputCTR >> 15) & 0x7f) << 1) | 1;

        HDCP_private_data[14] = (inputCTR >> 7) & 0xff;

        HDCP_private_data[15] =
            ((inputCTR & 0x7f) << 1) | 1;

        flags |= TSPacketizer::IS_ENCRYPTED;
    }

    int64_t timeUs = ALooper::GetNowUs();
    if (mPrevTimeUs < 0ll || mPrevTimeUs + 100000ll <= timeUs) {
        flags |= TSPacketizer::EMIT_PCR;
        flags |= TSPacketizer::EMIT_PAT_AND_PMT;

        mPrevTimeUs = timeUs;
    }

    sp<ABuffer> packets;
    mPacketizer->packetize(
            track->packetizerTrackIndex(), accessUnit, &packets, flags,
            isHDCPEncrypted ? NULL : HDCP_private_data,
            isHDCPEncrypted ? 0 : sizeof(HDCP_private_data));

    for (size_t offset = 0;
            offset < packets->size(); offset += 188) {
        bool lastTSPacket = (offset + 188 >= packets->size());

        // We're only going to flush video, audio packets are
        // much more frequent and would waste all that space
        // available in a full sized UDP packet.
        bool flush =
            lastTSPacket
                && ((ssize_t)trackIndex == mVideoTrackIndex);

        appendTSData(
                packets->data() + offset,
                188,
                true /* timeDiscontinuity */,
                flush);
    }

#if LOG_TRANSPORT_STREAM
    if (mLogFile != NULL) {
        fwrite(packets->data(), 1, packets->size(), mLogFile);
    }
#endif

    return OK;
}

status_t WifiDisplaySource::PlaybackSession::packetizeQueuedAccessUnits() {
    for (;;) {
        bool gotMoreData = false;
        for (size_t i = 0; i < mTracks.size(); ++i) {
            size_t trackIndex = mTracks.keyAt(i);
            const sp<Track> &track = mTracks.valueAt(i);

            sp<ABuffer> accessUnit = track->dequeueAccessUnit();
            if (accessUnit != NULL) {
                status_t err = packetizeAccessUnit(trackIndex, accessUnit);

                if (err != OK) {
                    return err;
                }

                gotMoreData = true;
            }
        }

        if (!gotMoreData) {
            break;
        }
    }

    return OK;
}

}  // namespace android
+9 −0
Original line number Diff line number Diff line
@@ -123,6 +123,8 @@ private:

    AString mClientIP;

    bool mAllTracksHavePacketizerIndex;

    // in TCP mode
    int32_t mRTPChannel;
    int32_t mRTCPChannel;
@@ -196,6 +198,13 @@ private:
    status_t onFinishPlay();
    status_t onFinishPlay2();

    bool allTracksHavePacketizerIndex();

    status_t packetizeAccessUnit(
            size_t trackIndex, const sp<ABuffer> &accessUnit);

    status_t packetizeQueuedAccessUnits();

    DISALLOW_EVIL_CONSTRUCTORS(PlaybackSession);
};

+4 −8
Original line number Diff line number Diff line
@@ -283,15 +283,15 @@ status_t TSPacketizer::packetize(
        const uint8_t *PES_private_data, size_t PES_private_data_len) {
    sp<ABuffer> accessUnit = _accessUnit;

    int64_t timeUs;
    CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));

    packets->clear();

    if (trackIndex >= mTracks.size()) {
        return -ERANGE;
    }

    int64_t timeUs;
    CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));

    const sp<Track> &track = mTracks.itemAt(trackIndex);

    if (track->isH264() && !(flags & IS_ENCRYPTED)) {
@@ -531,11 +531,7 @@ status_t TSPacketizer::packetize(
        // reserved = b111111
        // program_clock_reference_extension = b?????????

#if 0
        int64_t nowUs = ALooper::GetNowUs();
#else
        int64_t nowUs = timeUs;
#endif

        uint64_t PCR = nowUs * 27;  // PCR based on a 27MHz clock
        uint64_t PCR_base = PCR / 300;
@@ -560,7 +556,7 @@ status_t TSPacketizer::packetize(
        packetDataStart += 188;
    }

    uint32_t PTS = (timeUs * 9ll) / 100ll;
    uint64_t PTS = (timeUs * 9ll) / 100ll;

    bool padding = (PES_packet_length < (188 - 10));

+1 −2
Original line number Diff line number Diff line
@@ -876,7 +876,6 @@ status_t WifiDisplaySource::onSetupRequest(
        } else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) {
            // No RTCP.
            clientRtcp = -1;
            clientRtcp = clientRtp + 1;  // XXX
        } else {
            badRequest = true;
        }
@@ -889,7 +888,7 @@ status_t WifiDisplaySource::onSetupRequest(
    // The older LG dongles doesn't specify client_port=xxx apparently.
    } else if (transport == "RTP/AVP/UDP;unicast") {
        clientRtp = 19000;
        clientRtcp = clientRtp + 1;
        clientRtcp = -1;
#endif
    } else {
        sendErrorResponse(sessionID, "461 Unsupported Transport", cseq);