summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/rtsp/MyTransmitter.h
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/rtsp/MyTransmitter.h')
-rw-r--r--media/libstagefright/rtsp/MyTransmitter.h981
1 files changed, 0 insertions, 981 deletions
diff --git a/media/libstagefright/rtsp/MyTransmitter.h b/media/libstagefright/rtsp/MyTransmitter.h
deleted file mode 100644
index 009a3b1..0000000
--- a/media/libstagefright/rtsp/MyTransmitter.h
+++ /dev/null
@@ -1,981 +0,0 @@
-/*
- * Copyright (C) 2010 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 MY_TRANSMITTER_H_
-
-#define MY_TRANSMITTER_H_
-
-#include "ARTPConnection.h"
-
-#include <arpa/inet.h>
-#include <sys/socket.h>
-
-#include <openssl/md5.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/base64.h>
-#include <media/stagefright/foundation/hexdump.h>
-
-#ifdef ANDROID
-#include "VideoSource.h"
-
-#include <media/stagefright/OMXClient.h>
-#include <media/stagefright/OMXCodec.h>
-#endif
-
-namespace android {
-
-#define TRACK_SUFFIX "trackid=1"
-#define PT 96
-#define PT_STR "96"
-
-#define USERNAME "bcast"
-#define PASSWORD "test"
-
-static int uniformRand(int limit) {
- return ((double)rand() * limit) / RAND_MAX;
-}
-
-static bool GetAttribute(const char *s, const char *key, AString *value) {
- value->clear();
-
- size_t keyLen = strlen(key);
-
- for (;;) {
- const char *colonPos = strchr(s, ';');
-
- size_t len =
- (colonPos == NULL) ? strlen(s) : colonPos - s;
-
- if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) {
- value->setTo(&s[keyLen + 1], len - keyLen - 1);
- return true;
- }
-
- if (colonPos == NULL) {
- return false;
- }
-
- s = colonPos + 1;
- }
-}
-
-struct MyTransmitter : public AHandler {
- MyTransmitter(const char *url, const sp<ALooper> &looper)
- : mServerURL(url),
- mLooper(looper),
- mConn(new ARTSPConnection),
- mConnected(false),
- mAuthType(NONE),
- mRTPSocket(-1),
- mRTCPSocket(-1),
- mSourceID(rand()),
- mSeqNo(uniformRand(65536)),
- mRTPTimeBase(rand()),
- mNumSamplesSent(0),
- mNumRTPSent(0),
- mNumRTPOctetsSent(0),
- mLastRTPTime(0),
- mLastNTPTime(0) {
- mStreamURL = mServerURL;
- mStreamURL.append("/bazong.sdp");
-
- mTrackURL = mStreamURL;
- mTrackURL.append("/");
- mTrackURL.append(TRACK_SUFFIX);
-
- mLooper->registerHandler(this);
- mLooper->registerHandler(mConn);
-
- sp<AMessage> reply = new AMessage('conn', id());
- mConn->connect(mServerURL.c_str(), reply);
-
-#ifdef ANDROID
- int width = 640;
- int height = 480;
-
- sp<MediaSource> source = new VideoSource(width, height);
-
- sp<MetaData> encMeta = new MetaData;
- encMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
- encMeta->setInt32(kKeyWidth, width);
- encMeta->setInt32(kKeyHeight, height);
-
- OMXClient client;
- client.connect();
-
- mEncoder = OMXCodec::Create(
- client.interface(), encMeta,
- true /* createEncoder */, source);
-
- mEncoder->start();
-
- MediaBuffer *buffer;
- CHECK_EQ(mEncoder->read(&buffer), (status_t)OK);
- CHECK(buffer != NULL);
-
- makeH264SPropParamSets(buffer);
-
- buffer->release();
- buffer = NULL;
-#endif
- }
-
- uint64_t ntpTime() {
- struct timeval tv;
- gettimeofday(&tv, NULL);
-
- uint64_t nowUs = tv.tv_sec * 1000000ll + tv.tv_usec;
-
- nowUs += ((70ll * 365 + 17) * 24) * 60 * 60 * 1000000ll;
-
- uint64_t hi = nowUs / 1000000ll;
- uint64_t lo = ((1ll << 32) * (nowUs % 1000000ll)) / 1000000ll;
-
- return (hi << 32) | lo;
- }
-
- void issueAnnounce() {
- AString sdp;
- sdp = "v=0\r\n";
-
- sdp.append("o=- ");
-
- uint64_t ntp = ntpTime();
- sdp.append(ntp);
- sdp.append(" ");
- sdp.append(ntp);
- sdp.append(" IN IP4 127.0.0.0\r\n");
-
- sdp.append(
- "s=Sample\r\n"
- "i=Playing around with ANNOUNCE\r\n"
- "c=IN IP4 ");
-
- struct in_addr addr;
- addr.s_addr = htonl(mServerIP);
-
- sdp.append(inet_ntoa(addr));
-
- sdp.append(
- "\r\n"
- "t=0 0\r\n"
- "a=range:npt=now-\r\n");
-
-#ifdef ANDROID
- sp<MetaData> meta = mEncoder->getFormat();
- int32_t width, height;
- CHECK(meta->findInt32(kKeyWidth, &width));
- CHECK(meta->findInt32(kKeyHeight, &height));
-
- sdp.append(
- "m=video 0 RTP/AVP " PT_STR "\r\n"
- "b=AS 320000\r\n"
- "a=rtpmap:" PT_STR " H264/90000\r\n");
-
- sdp.append("a=cliprect 0,0,");
- sdp.append(height);
- sdp.append(",");
- sdp.append(width);
- sdp.append("\r\n");
-
- sdp.append(
- "a=framesize:" PT_STR " ");
- sdp.append(width);
- sdp.append("-");
- sdp.append(height);
- sdp.append("\r\n");
-
- sdp.append(
- "a=fmtp:" PT_STR " profile-level-id=42C015;sprop-parameter-sets=");
-
- sdp.append(mSeqParamSet);
- sdp.append(",");
- sdp.append(mPicParamSet);
- sdp.append(";packetization-mode=1\r\n");
-#else
- sdp.append(
- "m=audio 0 RTP/AVP " PT_STR "\r\n"
- "a=rtpmap:" PT_STR " L8/8000/1\r\n");
-#endif
-
- sdp.append("a=control:" TRACK_SUFFIX "\r\n");
-
- AString request;
- request.append("ANNOUNCE ");
- request.append(mStreamURL);
- request.append(" RTSP/1.0\r\n");
-
- addAuthentication(&request, "ANNOUNCE", mStreamURL.c_str());
-
- request.append("Content-Type: application/sdp\r\n");
- request.append("Content-Length: ");
- request.append(sdp.size());
- request.append("\r\n");
-
- request.append("\r\n");
- request.append(sdp);
-
- sp<AMessage> reply = new AMessage('anno', id());
- mConn->sendRequest(request.c_str(), reply);
- }
-
- void H(const AString &s, AString *out) {
- out->clear();
-
- MD5_CTX m;
- MD5_Init(&m);
- MD5_Update(&m, s.c_str(), s.size());
-
- uint8_t key[16];
- MD5_Final(key, &m);
-
- for (size_t i = 0; i < 16; ++i) {
- char nibble = key[i] >> 4;
- if (nibble <= 9) {
- nibble += '0';
- } else {
- nibble += 'a' - 10;
- }
- out->append(&nibble, 1);
-
- nibble = key[i] & 0x0f;
- if (nibble <= 9) {
- nibble += '0';
- } else {
- nibble += 'a' - 10;
- }
- out->append(&nibble, 1);
- }
- }
-
- void authenticate(const sp<ARTSPResponse> &response) {
- ssize_t i = response->mHeaders.indexOfKey("www-authenticate");
- CHECK_GE(i, 0);
-
- AString value = response->mHeaders.valueAt(i);
-
- if (!strncmp(value.c_str(), "Basic", 5)) {
- mAuthType = BASIC;
- } else {
- CHECK(!strncmp(value.c_str(), "Digest", 6));
- mAuthType = DIGEST;
-
- i = value.find("nonce=");
- CHECK_GE(i, 0);
- CHECK_EQ(value.c_str()[i + 6], '\"');
- ssize_t j = value.find("\"", i + 7);
- CHECK_GE(j, 0);
-
- mNonce.setTo(value, i + 7, j - i - 7);
- }
-
- issueAnnounce();
- }
-
- void addAuthentication(
- AString *request, const char *method, const char *url) {
- if (mAuthType == NONE) {
- return;
- }
-
- if (mAuthType == BASIC) {
- request->append("Authorization: Basic YmNhc3Q6dGVzdAo=\r\n");
- return;
- }
-
- CHECK_EQ((int)mAuthType, (int)DIGEST);
-
- AString A1;
- A1.append(USERNAME);
- A1.append(":");
- A1.append("Streaming Server");
- A1.append(":");
- A1.append(PASSWORD);
-
- AString A2;
- A2.append(method);
- A2.append(":");
- A2.append(url);
-
- AString HA1, HA2;
- H(A1, &HA1);
- H(A2, &HA2);
-
- AString tmp;
- tmp.append(HA1);
- tmp.append(":");
- tmp.append(mNonce);
- tmp.append(":");
- tmp.append(HA2);
-
- AString digest;
- H(tmp, &digest);
-
- request->append("Authorization: Digest ");
- request->append("nonce=\"");
- request->append(mNonce);
- request->append("\", ");
- request->append("username=\"" USERNAME "\", ");
- request->append("uri=\"");
- request->append(url);
- request->append("\", ");
- request->append("response=\"");
- request->append(digest);
- request->append("\"");
- request->append("\r\n");
- }
-
- virtual void onMessageReceived(const sp<AMessage> &msg) {
- switch (msg->what()) {
- case 'conn':
- {
- int32_t result;
- CHECK(msg->findInt32("result", &result));
-
- LOG(INFO) << "connection request completed with result "
- << result << " (" << strerror(-result) << ")";
-
- if (result != OK) {
- (new AMessage('quit', id()))->post();
- break;
- }
-
- mConnected = true;
-
- CHECK(msg->findInt32("server-ip", (int32_t *)&mServerIP));
-
- issueAnnounce();
- break;
- }
-
- case 'anno':
- {
- int32_t result;
- CHECK(msg->findInt32("result", &result));
-
- LOG(INFO) << "ANNOUNCE completed with result "
- << result << " (" << strerror(-result) << ")";
-
- sp<RefBase> obj;
- CHECK(msg->findObject("response", &obj));
- sp<ARTSPResponse> response;
-
- if (result == OK) {
- response = static_cast<ARTSPResponse *>(obj.get());
- CHECK(response != NULL);
-
- if (response->mStatusCode == 401) {
- if (mAuthType != NONE) {
- LOG(INFO) << "FAILED to authenticate";
- (new AMessage('quit', id()))->post();
- break;
- }
-
- authenticate(response);
- break;
- }
- }
-
- if (result != OK || response->mStatusCode != 200) {
- (new AMessage('quit', id()))->post();
- break;
- }
-
- unsigned rtpPort;
- ARTPConnection::MakePortPair(&mRTPSocket, &mRTCPSocket, &rtpPort);
-
- // (new AMessage('poll', id()))->post();
-
- AString request;
- request.append("SETUP ");
- request.append(mTrackURL);
- request.append(" RTSP/1.0\r\n");
-
- addAuthentication(&request, "SETUP", mTrackURL.c_str());
-
- request.append("Transport: RTP/AVP;unicast;client_port=");
- request.append(rtpPort);
- request.append("-");
- request.append(rtpPort + 1);
- request.append(";mode=record\r\n");
- request.append("\r\n");
-
- sp<AMessage> reply = new AMessage('setu', id());
- mConn->sendRequest(request.c_str(), reply);
- break;
- }
-
-#if 0
- case 'poll':
- {
- fd_set rs;
- FD_ZERO(&rs);
- FD_SET(mRTCPSocket, &rs);
-
- struct timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 0;
-
- int res = select(mRTCPSocket + 1, &rs, NULL, NULL, &tv);
-
- if (res == 1) {
- sp<ABuffer> buffer = new ABuffer(65536);
- ssize_t n = recv(mRTCPSocket, buffer->data(), buffer->size(), 0);
-
- if (n <= 0) {
- LOG(ERROR) << "recv returned " << n;
- } else {
- LOG(INFO) << "recv returned " << n << " bytes of data.";
-
- hexdump(buffer->data(), n);
- }
- }
-
- msg->post(50000);
- break;
- }
-#endif
-
- case 'setu':
- {
- int32_t result;
- CHECK(msg->findInt32("result", &result));
-
- LOG(INFO) << "SETUP completed with result "
- << result << " (" << strerror(-result) << ")";
-
- sp<RefBase> obj;
- CHECK(msg->findObject("response", &obj));
- sp<ARTSPResponse> response;
-
- if (result == OK) {
- response = static_cast<ARTSPResponse *>(obj.get());
- CHECK(response != NULL);
- }
-
- if (result != OK || response->mStatusCode != 200) {
- (new AMessage('quit', id()))->post();
- break;
- }
-
- ssize_t i = response->mHeaders.indexOfKey("session");
- CHECK_GE(i, 0);
- mSessionID = response->mHeaders.valueAt(i);
- i = mSessionID.find(";");
- if (i >= 0) {
- // Remove options, i.e. ";timeout=90"
- mSessionID.erase(i, mSessionID.size() - i);
- }
-
- i = response->mHeaders.indexOfKey("transport");
- CHECK_GE(i, 0);
- AString transport = response->mHeaders.valueAt(i);
-
- LOG(INFO) << "transport = '" << transport << "'";
-
- AString value;
- CHECK(GetAttribute(transport.c_str(), "server_port", &value));
-
- unsigned rtpPort, rtcpPort;
- CHECK_EQ(sscanf(value.c_str(), "%u-%u", &rtpPort, &rtcpPort), 2);
-
- CHECK(GetAttribute(transport.c_str(), "source", &value));
-
- memset(mRemoteAddr.sin_zero, 0, sizeof(mRemoteAddr.sin_zero));
- mRemoteAddr.sin_family = AF_INET;
- mRemoteAddr.sin_addr.s_addr = inet_addr(value.c_str());
- mRemoteAddr.sin_port = htons(rtpPort);
-
- mRemoteRTCPAddr = mRemoteAddr;
- mRemoteRTCPAddr.sin_port = htons(rtpPort + 1);
-
- CHECK_EQ(0, connect(mRTPSocket,
- (const struct sockaddr *)&mRemoteAddr,
- sizeof(mRemoteAddr)));
-
- CHECK_EQ(0, connect(mRTCPSocket,
- (const struct sockaddr *)&mRemoteRTCPAddr,
- sizeof(mRemoteRTCPAddr)));
-
- uint32_t x = ntohl(mRemoteAddr.sin_addr.s_addr);
- LOG(INFO) << "sending data to "
- << (x >> 24)
- << "."
- << ((x >> 16) & 0xff)
- << "."
- << ((x >> 8) & 0xff)
- << "."
- << (x & 0xff)
- << ":"
- << rtpPort;
-
- AString request;
- request.append("RECORD ");
- request.append(mStreamURL);
- request.append(" RTSP/1.0\r\n");
-
- addAuthentication(&request, "RECORD", mStreamURL.c_str());
-
- request.append("Session: ");
- request.append(mSessionID);
- request.append("\r\n");
- request.append("\r\n");
-
- sp<AMessage> reply = new AMessage('reco', id());
- mConn->sendRequest(request.c_str(), reply);
- break;
- }
-
- case 'reco':
- {
- int32_t result;
- CHECK(msg->findInt32("result", &result));
-
- LOG(INFO) << "RECORD completed with result "
- << result << " (" << strerror(-result) << ")";
-
- sp<RefBase> obj;
- CHECK(msg->findObject("response", &obj));
- sp<ARTSPResponse> response;
-
- if (result == OK) {
- response = static_cast<ARTSPResponse *>(obj.get());
- CHECK(response != NULL);
- }
-
- if (result != OK) {
- (new AMessage('quit', id()))->post();
- break;
- }
-
- (new AMessage('more', id()))->post();
- (new AMessage('sr ', id()))->post();
- (new AMessage('aliv', id()))->post(30000000ll);
- break;
- }
-
- case 'aliv':
- {
- if (!mConnected) {
- break;
- }
-
- AString request;
- request.append("OPTIONS ");
- request.append(mStreamURL);
- request.append(" RTSP/1.0\r\n");
-
- addAuthentication(&request, "RECORD", mStreamURL.c_str());
-
- request.append("Session: ");
- request.append(mSessionID);
- request.append("\r\n");
- request.append("\r\n");
-
- sp<AMessage> reply = new AMessage('opts', id());
- mConn->sendRequest(request.c_str(), reply);
- break;
- }
-
- case 'opts':
- {
- int32_t result;
- CHECK(msg->findInt32("result", &result));
-
- LOG(INFO) << "OPTIONS completed with result "
- << result << " (" << strerror(-result) << ")";
-
- if (!mConnected) {
- break;
- }
-
- (new AMessage('aliv', id()))->post(30000000ll);
- break;
- }
-
- case 'more':
- {
- if (!mConnected) {
- break;
- }
-
- sp<ABuffer> buffer = new ABuffer(65536);
- uint8_t *data = buffer->data();
- data[0] = 0x80;
- data[1] = (1 << 7) | PT; // M-bit
- data[2] = (mSeqNo >> 8) & 0xff;
- data[3] = mSeqNo & 0xff;
- data[8] = mSourceID >> 24;
- data[9] = (mSourceID >> 16) & 0xff;
- data[10] = (mSourceID >> 8) & 0xff;
- data[11] = mSourceID & 0xff;
-
-#ifdef ANDROID
- MediaBuffer *mediaBuf = NULL;
- for (;;) {
- CHECK_EQ(mEncoder->read(&mediaBuf), (status_t)OK);
- if (mediaBuf->range_length() > 0) {
- break;
- }
- mediaBuf->release();
- mediaBuf = NULL;
- }
-
- int64_t timeUs;
- CHECK(mediaBuf->meta_data()->findInt64(kKeyTime, &timeUs));
-
- uint32_t rtpTime = mRTPTimeBase + (timeUs * 9 / 100ll);
-
- const uint8_t *mediaData =
- (const uint8_t *)mediaBuf->data() + mediaBuf->range_offset();
-
- CHECK(!memcmp("\x00\x00\x00\x01", mediaData, 4));
-
- CHECK_LE(mediaBuf->range_length() - 4 + 12, buffer->size());
-
- memcpy(&data[12],
- mediaData + 4, mediaBuf->range_length() - 4);
-
- buffer->setRange(0, mediaBuf->range_length() - 4 + 12);
-
- mediaBuf->release();
- mediaBuf = NULL;
-#else
- uint32_t rtpTime = mRTPTimeBase + mNumRTPSent * 128;
- memset(&data[12], 0, 128);
- buffer->setRange(0, 12 + 128);
-#endif
-
- data[4] = rtpTime >> 24;
- data[5] = (rtpTime >> 16) & 0xff;
- data[6] = (rtpTime >> 8) & 0xff;
- data[7] = rtpTime & 0xff;
-
- ssize_t n = send(
- mRTPSocket, data, buffer->size(), 0);
- if (n < 0) {
- LOG(ERROR) << "send failed (" << strerror(errno) << ")";
- }
- CHECK_EQ(n, (ssize_t)buffer->size());
-
- ++mSeqNo;
-
- ++mNumRTPSent;
- mNumRTPOctetsSent += buffer->size() - 12;
-
- mLastRTPTime = rtpTime;
- mLastNTPTime = ntpTime();
-
-#ifdef ANDROID
- if (mNumRTPSent < 60 * 25) { // 60 secs worth
- msg->post(40000);
-#else
- if (mNumRTPOctetsSent < 8000 * 60) {
- msg->post(1000000ll * 128 / 8000);
-#endif
- } else {
- LOG(INFO) << "That's enough, pausing.";
-
- AString request;
- request.append("PAUSE ");
- request.append(mStreamURL);
- request.append(" RTSP/1.0\r\n");
-
- addAuthentication(&request, "PAUSE", mStreamURL.c_str());
-
- request.append("Session: ");
- request.append(mSessionID);
- request.append("\r\n");
- request.append("\r\n");
-
- sp<AMessage> reply = new AMessage('paus', id());
- mConn->sendRequest(request.c_str(), reply);
- }
- break;
- }
-
- case 'sr ':
- {
- if (!mConnected) {
- break;
- }
-
- sp<ABuffer> buffer = new ABuffer(65536);
- buffer->setRange(0, 0);
-
- addSR(buffer);
- addSDES(buffer);
-
- uint8_t *data = buffer->data();
- ssize_t n = send(
- mRTCPSocket, data, buffer->size(), 0);
- CHECK_EQ(n, (ssize_t)buffer->size());
-
- msg->post(3000000);
- break;
- }
-
- case 'paus':
- {
- int32_t result;
- CHECK(msg->findInt32("result", &result));
-
- LOG(INFO) << "PAUSE completed with result "
- << result << " (" << strerror(-result) << ")";
-
- sp<RefBase> obj;
- CHECK(msg->findObject("response", &obj));
- sp<ARTSPResponse> response;
-
- AString request;
- request.append("TEARDOWN ");
- request.append(mStreamURL);
- request.append(" RTSP/1.0\r\n");
-
- addAuthentication(&request, "TEARDOWN", mStreamURL.c_str());
-
- request.append("Session: ");
- request.append(mSessionID);
- request.append("\r\n");
- request.append("\r\n");
-
- sp<AMessage> reply = new AMessage('tear', id());
- mConn->sendRequest(request.c_str(), reply);
- break;
- }
-
- case 'tear':
- {
- int32_t result;
- CHECK(msg->findInt32("result", &result));
-
- LOG(INFO) << "TEARDOWN completed with result "
- << result << " (" << strerror(-result) << ")";
-
- sp<RefBase> obj;
- CHECK(msg->findObject("response", &obj));
- sp<ARTSPResponse> response;
-
- if (result == OK) {
- response = static_cast<ARTSPResponse *>(obj.get());
- CHECK(response != NULL);
- }
-
- (new AMessage('quit', id()))->post();
- break;
- }
-
- case 'disc':
- {
- LOG(INFO) << "disconnect completed";
-
- mConnected = false;
- (new AMessage('quit', id()))->post();
- break;
- }
-
- case 'quit':
- {
- if (mConnected) {
- mConn->disconnect(new AMessage('disc', id()));
- break;
- }
-
- if (mRTPSocket >= 0) {
- close(mRTPSocket);
- mRTPSocket = -1;
- }
-
- if (mRTCPSocket >= 0) {
- close(mRTCPSocket);
- mRTCPSocket = -1;
- }
-
-#ifdef ANDROID
- mEncoder->stop();
- mEncoder.clear();
-#endif
-
- mLooper->stop();
- break;
- }
-
- default:
- TRESPASS();
- }
- }
-
-protected:
- virtual ~MyTransmitter() {
- }
-
-private:
- enum AuthType {
- NONE,
- BASIC,
- DIGEST
- };
-
- AString mServerURL;
- AString mTrackURL;
- AString mStreamURL;
-
- sp<ALooper> mLooper;
- sp<ARTSPConnection> mConn;
- bool mConnected;
- uint32_t mServerIP;
- AuthType mAuthType;
- AString mNonce;
- AString mSessionID;
- int mRTPSocket, mRTCPSocket;
- uint32_t mSourceID;
- uint32_t mSeqNo;
- uint32_t mRTPTimeBase;
- struct sockaddr_in mRemoteAddr;
- struct sockaddr_in mRemoteRTCPAddr;
- size_t mNumSamplesSent;
- uint32_t mNumRTPSent;
- uint32_t mNumRTPOctetsSent;
- uint32_t mLastRTPTime;
- uint64_t mLastNTPTime;
-
-#ifdef ANDROID
- sp<MediaSource> mEncoder;
- AString mSeqParamSet;
- AString mPicParamSet;
-
- void makeH264SPropParamSets(MediaBuffer *buffer) {
- static const char kStartCode[] = "\x00\x00\x00\x01";
-
- const uint8_t *data =
- (const uint8_t *)buffer->data() + buffer->range_offset();
- size_t size = buffer->range_length();
-
- CHECK_GE(size, 0u);
- CHECK(!memcmp(kStartCode, data, 4));
-
- data += 4;
- size -= 4;
-
- size_t startCodePos = 0;
- while (startCodePos + 3 < size
- && memcmp(kStartCode, &data[startCodePos], 4)) {
- ++startCodePos;
- }
-
- CHECK_LT(startCodePos + 3, size);
-
- encodeBase64(data, startCodePos, &mSeqParamSet);
-
- encodeBase64(&data[startCodePos + 4], size - startCodePos - 4,
- &mPicParamSet);
- }
-#endif
-
- void addSR(const sp<ABuffer> &buffer) {
- uint8_t *data = buffer->data() + buffer->size();
-
- data[0] = 0x80 | 0;
- data[1] = 200; // SR
- data[2] = 0;
- data[3] = 6;
- data[4] = mSourceID >> 24;
- data[5] = (mSourceID >> 16) & 0xff;
- data[6] = (mSourceID >> 8) & 0xff;
- data[7] = mSourceID & 0xff;
-
- data[8] = mLastNTPTime >> (64 - 8);
- data[9] = (mLastNTPTime >> (64 - 16)) & 0xff;
- data[10] = (mLastNTPTime >> (64 - 24)) & 0xff;
- data[11] = (mLastNTPTime >> 32) & 0xff;
- data[12] = (mLastNTPTime >> 24) & 0xff;
- data[13] = (mLastNTPTime >> 16) & 0xff;
- data[14] = (mLastNTPTime >> 8) & 0xff;
- data[15] = mLastNTPTime & 0xff;
-
- data[16] = (mLastRTPTime >> 24) & 0xff;
- data[17] = (mLastRTPTime >> 16) & 0xff;
- data[18] = (mLastRTPTime >> 8) & 0xff;
- data[19] = mLastRTPTime & 0xff;
-
- data[20] = mNumRTPSent >> 24;
- data[21] = (mNumRTPSent >> 16) & 0xff;
- data[22] = (mNumRTPSent >> 8) & 0xff;
- data[23] = mNumRTPSent & 0xff;
-
- data[24] = mNumRTPOctetsSent >> 24;
- data[25] = (mNumRTPOctetsSent >> 16) & 0xff;
- data[26] = (mNumRTPOctetsSent >> 8) & 0xff;
- data[27] = mNumRTPOctetsSent & 0xff;
-
- buffer->setRange(buffer->offset(), buffer->size() + 28);
- }
-
- void addSDES(const sp<ABuffer> &buffer) {
- uint8_t *data = buffer->data() + buffer->size();
- data[0] = 0x80 | 1;
- data[1] = 202; // SDES
- data[4] = mSourceID >> 24;
- data[5] = (mSourceID >> 16) & 0xff;
- data[6] = (mSourceID >> 8) & 0xff;
- data[7] = mSourceID & 0xff;
-
- size_t offset = 8;
-
- data[offset++] = 1; // CNAME
-
- static const char *kCNAME = "andih@laptop";
- data[offset++] = strlen(kCNAME);
-
- memcpy(&data[offset], kCNAME, strlen(kCNAME));
- offset += strlen(kCNAME);
-
- data[offset++] = 7; // NOTE
-
- static const char *kNOTE = "Hell's frozen over.";
- data[offset++] = strlen(kNOTE);
-
- memcpy(&data[offset], kNOTE, strlen(kNOTE));
- offset += strlen(kNOTE);
-
- data[offset++] = 0;
-
- if ((offset % 4) > 0) {
- size_t count = 4 - (offset % 4);
- switch (count) {
- case 3:
- data[offset++] = 0;
- case 2:
- data[offset++] = 0;
- case 1:
- data[offset++] = 0;
- }
- }
-
- size_t numWords = (offset / 4) - 1;
- data[2] = numWords >> 8;
- data[3] = numWords & 0xff;
-
- buffer->setRange(buffer->offset(), buffer->size() + offset);
- }
-
- DISALLOW_EVIL_CONSTRUCTORS(MyTransmitter);
-};
-
-} // namespace android
-
-#endif // MY_TRANSMITTER_H_