summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/wifi-display/rtp/RTPAssembler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/wifi-display/rtp/RTPAssembler.cpp')
-rw-r--r--media/libstagefright/wifi-display/rtp/RTPAssembler.cpp328
1 files changed, 328 insertions, 0 deletions
diff --git a/media/libstagefright/wifi-display/rtp/RTPAssembler.cpp b/media/libstagefright/wifi-display/rtp/RTPAssembler.cpp
new file mode 100644
index 0000000..7a96081
--- /dev/null
+++ b/media/libstagefright/wifi-display/rtp/RTPAssembler.cpp
@@ -0,0 +1,328 @@
+/*
+ * 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 "RTPAssembler"
+#include <utils/Log.h>
+
+#include "RTPAssembler.h"
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/MediaErrors.h>
+
+namespace android {
+
+RTPReceiver::Assembler::Assembler(const sp<AMessage> &notify)
+ : mNotify(notify) {
+}
+
+void RTPReceiver::Assembler::postAccessUnit(
+ const sp<ABuffer> &accessUnit, bool followsDiscontinuity) {
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", RTPReceiver::kWhatAccessUnit);
+ notify->setBuffer("accessUnit", accessUnit);
+ notify->setInt32("followsDiscontinuity", followsDiscontinuity);
+ notify->post();
+}
+////////////////////////////////////////////////////////////////////////////////
+
+RTPReceiver::TSAssembler::TSAssembler(const sp<AMessage> &notify)
+ : Assembler(notify),
+ mSawDiscontinuity(false) {
+}
+
+void RTPReceiver::TSAssembler::signalDiscontinuity() {
+ mSawDiscontinuity = true;
+}
+
+status_t RTPReceiver::TSAssembler::processPacket(const sp<ABuffer> &packet) {
+ int32_t rtpTime;
+ CHECK(packet->meta()->findInt32("rtp-time", &rtpTime));
+
+ packet->meta()->setInt64("timeUs", (rtpTime * 100ll) / 9);
+
+ postAccessUnit(packet, mSawDiscontinuity);
+
+ if (mSawDiscontinuity) {
+ mSawDiscontinuity = false;
+ }
+
+ return OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+RTPReceiver::H264Assembler::H264Assembler(const sp<AMessage> &notify)
+ : Assembler(notify),
+ mState(0),
+ mIndicator(0),
+ mNALType(0),
+ mAccessUnitRTPTime(0) {
+}
+
+void RTPReceiver::H264Assembler::signalDiscontinuity() {
+ reset();
+}
+
+status_t RTPReceiver::H264Assembler::processPacket(const sp<ABuffer> &packet) {
+ status_t err = internalProcessPacket(packet);
+
+ if (err != OK) {
+ reset();
+ }
+
+ return err;
+}
+
+status_t RTPReceiver::H264Assembler::internalProcessPacket(
+ const sp<ABuffer> &packet) {
+ const uint8_t *data = packet->data();
+ size_t size = packet->size();
+
+ switch (mState) {
+ case 0:
+ {
+ if (size < 1 || (data[0] & 0x80)) {
+ ALOGV("Malformed H264 RTP packet (empty or F-bit set)");
+ return ERROR_MALFORMED;
+ }
+
+ unsigned nalType = data[0] & 0x1f;
+ if (nalType >= 1 && nalType <= 23) {
+ addSingleNALUnit(packet);
+ ALOGV("added single NAL packet");
+ } else if (nalType == 28) {
+ // FU-A
+ unsigned indicator = data[0];
+ CHECK((indicator & 0x1f) == 28);
+
+ if (size < 2) {
+ ALOGV("Malformed H264 FU-A packet (single byte)");
+ return ERROR_MALFORMED;
+ }
+
+ if (!(data[1] & 0x80)) {
+ ALOGV("Malformed H264 FU-A packet (no start bit)");
+ return ERROR_MALFORMED;
+ }
+
+ mIndicator = data[0];
+ mNALType = data[1] & 0x1f;
+ uint32_t nri = (data[0] >> 5) & 3;
+
+ clearAccumulator();
+
+ uint8_t byte = mNALType | (nri << 5);
+ appendToAccumulator(&byte, 1);
+ appendToAccumulator(data + 2, size - 2);
+
+ int32_t rtpTime;
+ CHECK(packet->meta()->findInt32("rtp-time", &rtpTime));
+ mAccumulator->meta()->setInt32("rtp-time", rtpTime);
+
+ if (data[1] & 0x40) {
+ // Huh? End bit also set on the first buffer.
+ addSingleNALUnit(mAccumulator);
+ clearAccumulator();
+
+ ALOGV("added FU-A");
+ break;
+ }
+
+ mState = 1;
+ } else if (nalType == 24) {
+ // STAP-A
+
+ status_t err = addSingleTimeAggregationPacket(packet);
+ if (err != OK) {
+ return err;
+ }
+ } else {
+ ALOGV("Malformed H264 packet (unknown type %d)", nalType);
+ return ERROR_UNSUPPORTED;
+ }
+ break;
+ }
+
+ case 1:
+ {
+ if (size < 2
+ || data[0] != mIndicator
+ || (data[1] & 0x1f) != mNALType
+ || (data[1] & 0x80)) {
+ ALOGV("Malformed H264 FU-A packet (indicator, "
+ "type or start bit mismatch)");
+
+ return ERROR_MALFORMED;
+ }
+
+ appendToAccumulator(data + 2, size - 2);
+
+ if (data[1] & 0x40) {
+ addSingleNALUnit(mAccumulator);
+
+ clearAccumulator();
+ mState = 0;
+
+ ALOGV("added FU-A");
+ }
+ break;
+ }
+
+ default:
+ TRESPASS();
+ }
+
+ int32_t marker;
+ CHECK(packet->meta()->findInt32("M", &marker));
+
+ if (marker) {
+ flushAccessUnit();
+ }
+
+ return OK;
+}
+
+void RTPReceiver::H264Assembler::reset() {
+ mNALUnits.clear();
+
+ clearAccumulator();
+ mState = 0;
+}
+
+void RTPReceiver::H264Assembler::clearAccumulator() {
+ if (mAccumulator != NULL) {
+ // XXX Too expensive.
+ mAccumulator.clear();
+ }
+}
+
+void RTPReceiver::H264Assembler::appendToAccumulator(
+ const void *data, size_t size) {
+ if (mAccumulator == NULL) {
+ mAccumulator = new ABuffer(size);
+ memcpy(mAccumulator->data(), data, size);
+ return;
+ }
+
+ if (mAccumulator->size() + size > mAccumulator->capacity()) {
+ sp<ABuffer> buf = new ABuffer(mAccumulator->size() + size);
+ memcpy(buf->data(), mAccumulator->data(), mAccumulator->size());
+ buf->setRange(0, mAccumulator->size());
+
+ int32_t rtpTime;
+ if (mAccumulator->meta()->findInt32("rtp-time", &rtpTime)) {
+ buf->meta()->setInt32("rtp-time", rtpTime);
+ }
+
+ mAccumulator = buf;
+ }
+
+ memcpy(mAccumulator->data() + mAccumulator->size(), data, size);
+ mAccumulator->setRange(0, mAccumulator->size() + size);
+}
+
+void RTPReceiver::H264Assembler::addSingleNALUnit(const sp<ABuffer> &packet) {
+ if (mNALUnits.empty()) {
+ int32_t rtpTime;
+ CHECK(packet->meta()->findInt32("rtp-time", &rtpTime));
+
+ mAccessUnitRTPTime = rtpTime;
+ }
+
+ mNALUnits.push_back(packet);
+}
+
+void RTPReceiver::H264Assembler::flushAccessUnit() {
+ if (mNALUnits.empty()) {
+ return;
+ }
+
+ size_t totalSize = 0;
+ for (List<sp<ABuffer> >::iterator it = mNALUnits.begin();
+ it != mNALUnits.end(); ++it) {
+ totalSize += 4 + (*it)->size();
+ }
+
+ sp<ABuffer> accessUnit = new ABuffer(totalSize);
+ size_t offset = 0;
+ for (List<sp<ABuffer> >::iterator it = mNALUnits.begin();
+ it != mNALUnits.end(); ++it) {
+ const sp<ABuffer> nalUnit = *it;
+
+ memcpy(accessUnit->data() + offset, "\x00\x00\x00\x01", 4);
+
+ memcpy(accessUnit->data() + offset + 4,
+ nalUnit->data(),
+ nalUnit->size());
+
+ offset += 4 + nalUnit->size();
+ }
+
+ mNALUnits.clear();
+
+ accessUnit->meta()->setInt64("timeUs", mAccessUnitRTPTime * 100ll / 9ll);
+ postAccessUnit(accessUnit, false /* followsDiscontinuity */);
+}
+
+status_t RTPReceiver::H264Assembler::addSingleTimeAggregationPacket(
+ const sp<ABuffer> &packet) {
+ const uint8_t *data = packet->data();
+ size_t size = packet->size();
+
+ if (size < 3) {
+ ALOGV("Malformed H264 STAP-A packet (too small)");
+ return ERROR_MALFORMED;
+ }
+
+ int32_t rtpTime;
+ CHECK(packet->meta()->findInt32("rtp-time", &rtpTime));
+
+ ++data;
+ --size;
+ while (size >= 2) {
+ size_t nalSize = (data[0] << 8) | data[1];
+
+ if (size < nalSize + 2) {
+ ALOGV("Malformed H264 STAP-A packet (incomplete NAL unit)");
+ return ERROR_MALFORMED;
+ }
+
+ sp<ABuffer> unit = new ABuffer(nalSize);
+ memcpy(unit->data(), &data[2], nalSize);
+
+ unit->meta()->setInt32("rtp-time", rtpTime);
+
+ addSingleNALUnit(unit);
+
+ data += 2 + nalSize;
+ size -= 2 + nalSize;
+ }
+
+ if (size != 0) {
+ ALOGV("Unexpected padding at end of STAP-A packet.");
+ }
+
+ ALOGV("added STAP-A");
+
+ return OK;
+}
+
+} // namespace android
+