status_t M3UParser::parse(const void *_data, size_t size) { int32_t lineNo = 0; sp<AMessage> itemMeta; const char *data = (const char *)_data; size_t offset = 0; while (offset < size) { size_t offsetLF = offset; while (offsetLF < size && data[offsetLF] != '\n') { ++offsetLF; } if (offsetLF >= size) { break; } AString line; if (offsetLF > offset && data[offsetLF - 1] == '\r') { line.setTo(&data[offset], offsetLF - offset - 1); } else { line.setTo(&data[offset], offsetLF - offset); } // LOGI("#%s#", line.c_str()); if (line.empty()) { offset = offsetLF + 1; continue; } if (lineNo == 0 && line == "#EXTM3U") { mIsExtM3U = true; } if (mIsExtM3U) { status_t err = OK; if (line.startsWith("#EXT-X-TARGETDURATION")) { if (mIsVariantPlaylist) { return ERROR_MALFORMED; } err = parseMetaData(line, &mMeta, "target-duration"); } else if (line.startsWith("#EXT-X-MEDIA-SEQUENCE")) { if (mIsVariantPlaylist) { return ERROR_MALFORMED; } err = parseMetaData(line, &mMeta, "media-sequence"); } else if (line.startsWith("#EXT-X-ENDLIST")) { mIsComplete = true; } else if (line.startsWith("#EXTINF")) { if (mIsVariantPlaylist) { return ERROR_MALFORMED; } err = parseMetaData(line, &itemMeta, "duration"); } else if (line.startsWith("#EXT-X-DISCONTINUITY")) { if (mIsVariantPlaylist) { return ERROR_MALFORMED; } if (itemMeta == NULL) { itemMeta = new AMessage; } itemMeta->setInt32("discontinuity", true); } else if (line.startsWith("#EXT-X-STREAM-INF")) { if (mMeta != NULL) { return ERROR_MALFORMED; } mIsVariantPlaylist = true; err = parseStreamInf(line, &itemMeta); } if (err != OK) { return err; } } if (!line.startsWith("#")) { if (!mIsVariantPlaylist) { int32_t durationSecs; if (itemMeta == NULL || !itemMeta->findInt32("duration", &durationSecs)) { return ERROR_MALFORMED; } } mItems.push(); Item *item = &mItems.editItemAt(mItems.size() - 1); CHECK(MakeURL(mBaseURI.c_str(), line.c_str(), &item->mURI)); item->mMeta = itemMeta; itemMeta.clear(); } offset = offsetLF + 1; ++lineNo; } return OK; }
bool ASessionDescription::parse(const void *data, size_t size) { mTracks.clear(); mFormats.clear(); mTracks.push(Attribs()); mFormats.push(AString("[root]")); AString desc((const char *)data, size); size_t i = 0; for (;;) { ssize_t eolPos = desc.find("\n", i); if (eolPos < 0) { break; } AString line; if ((size_t)eolPos > i && desc.c_str()[eolPos - 1] == '\r') { // We accept both '\n' and '\r\n' line endings, if it's // the latter, strip the '\r' as well. line.setTo(desc, i, eolPos - i - 1); } else { line.setTo(desc, i, eolPos - i); } if (line.empty()) { i = eolPos + 1; continue; } if (line.size() < 2 || line.c_str()[1] != '=') { return false; } ALOGI("%s", line.c_str()); switch (line.c_str()[0]) { case 'v': { if (strcmp(line.c_str(), "v=0")) { return false; } break; } case 'a': case 'b': { AString key, value; ssize_t colonPos = line.find(":", 2); if (colonPos < 0) { key = line; } else { key.setTo(line, 0, colonPos); if (key == "a=fmtp" || key == "a=rtpmap" || key == "a=framesize") { ssize_t spacePos = line.find(" ", colonPos + 1); if (spacePos < 0) { return false; } key.setTo(line, 0, spacePos); colonPos = spacePos; } value.setTo(line, colonPos + 1, line.size() - colonPos - 1); } key.trim(); value.trim(); ALOGV("adding '%s' => '%s'", key.c_str(), value.c_str()); mTracks.editItemAt(mTracks.size() - 1).add(key, value); break; } case 'm': { ALOGV("new section '%s'", AString(line, 2, line.size() - 2).c_str()); mTracks.push(Attribs()); mFormats.push(AString(line, 2, line.size() - 2)); break; } default: { AString key, value; ssize_t equalPos = line.find("="); key = AString(line, 0, equalPos + 1); value = AString(line, equalPos + 1, line.size() - equalPos - 1); key.trim(); value.trim(); ALOGV("adding '%s' => '%s'", key.c_str(), value.c_str()); mTracks.editItemAt(mTracks.size() - 1).add(key, value); break; } } i = eolPos + 1; } return true; }
int main(int argc, char **argv) { using namespace android; //负责打开Binder驱动,建立线程池,让其进程里面的所有线程都能通过Binder通信 http://blog.csdn.net/pi9nc/article/details/9749325 //每个线程都有一个IPCThreadState实例登记在Linux线程的上下文附属数据中,主要负责Binder的读取,写入和请求处理框架 ProcessState::self()->startThreadPool(); //基类DataSource提供了一些分离器 DataSource::RegisterDefaultSniffers(); AString connectToHost; int32_t connectToPort = -1; AString uri; AString listenOnAddr; int32_t listenOnPort = -1; int res; //解析参数 while ((res = getopt(argc, argv, "hc:l:u:")) >= 0) { switch (res) { //建立连接,设置默认端口 case 'c': { const char *colonPos = strrchr(optarg, ':'); if (colonPos == NULL) { connectToHost = optarg; connectToPort = WifiDisplaySource::kWifiDisplayDefaultPort; //kWifiDisplayDefaultPort = 7236; } else { connectToHost.setTo(optarg, colonPos - optarg); char *end; connectToPort = strtol(colonPos + 1, &end, 10); if (*end != '\0' || end == colonPos + 1 || connectToPort < 1 || connectToPort > 65535) { fprintf(stderr, "Illegal port specified.\n"); exit(1); } } break; } case 'u': { uri = optarg; break; } case 'l': { const char *colonPos = strrchr(optarg, ':'); if (colonPos == NULL) { listenOnAddr = optarg; listenOnPort = WifiDisplaySource::kWifiDisplayDefaultPort; //kWifiDisplayDefaultPort = 7236; } else { listenOnAddr.setTo(optarg, colonPos - optarg); char *end; listenOnPort = strtol(colonPos + 1, &end, 10); if (*end != '\0' || end == colonPos + 1 || listenOnPort < 1 || listenOnPort > 65535) { fprintf(stderr, "Illegal port specified.\n"); exit(1); } } break; } case '?': case 'h': default: usage(argv[0]); exit(1); } } if (connectToPort >= 0 && listenOnPort >= 0) { fprintf(stderr, "You can connect to a source or create one, " "but not both at the same time.\n"); exit(1); } if (listenOnPort >= 0) { createSource(listenOnAddr, listenOnPort); exit(0); } if (connectToPort < 0 && uri.empty()) { fprintf(stderr, "You need to select either source host or uri.\n"); exit(1); } if (connectToPort >= 0 && !uri.empty()) { fprintf(stderr, "You need to either connect to a wfd host or an rtsp url, " "not both.\n"); exit(1); } sp<ANetworkSession> session = new ANetworkSession; session->start(); //strong pointer,而wp则是weak pointer的意思 sp<ALooper> looper = new ALooper; sp<WifiDisplaySink> sink = new WifiDisplaySink(session); looper->registerHandler(sink); if (connectToPort >= 0) { sink->start(connectToHost.c_str(), connectToPort); } else { sink->start(uri.c_str()); } looper->start(true /* runOnCallingThread */); return 0; }
bool ASessionDescription::parse(const void *data, size_t size) { mTracks.clear(); mFormats.clear(); mTracks.push(Attribs()); mFormats.push(AString("[root]")); AString desc((const char *)data, size); #ifndef ANDROID_DEFAULT_CODE int rtpmapNum = 0; bool unsupported = false; #endif // #ifndef ANDROID_DEFAULT_CODE size_t i = 0; for (;;) { #ifndef ANDROID_DEFAULT_CODE if (i >= desc.size()) { break; } #endif // #ifndef ANDROID_DEFAULT_CODE ssize_t eolPos = desc.find("\n", i); if (eolPos < 0) { #ifndef ANDROID_DEFAULT_CODE eolPos = desc.size(); #else break; #endif // #ifndef ANDROID_DEFAULT_CODE } AString line; if ((size_t)eolPos > i && desc.c_str()[eolPos - 1] == '\r') { // We accept both '\n' and '\r\n' line endings, if it's // the latter, strip the '\r' as well. line.setTo(desc, i, eolPos - i - 1); } else { line.setTo(desc, i, eolPos - i); } if (line.empty()) { i = eolPos + 1; continue; } if (line.size() < 2 || line.c_str()[1] != '=') { return false; } #ifndef ANDROID_DEFAULT_CODE if (unsupported && line.c_str()[0] != 'm') { LOGI("skip %s in unsupported media description", line.c_str()); i = eolPos + 1; continue; } else #endif // #ifndef ANDROID_DEFAULT_CODE LOGI("%s", line.c_str()); switch (line.c_str()[0]) { case 'v': { if (strcmp(line.c_str(), "v=0")) { return false; } break; } case 'a': case 'b': { AString key, value; ssize_t colonPos = line.find(":", 2); if (colonPos < 0) { key = line; } else { key.setTo(line, 0, colonPos); if (key == "a=fmtp" || key == "a=rtpmap" || key == "a=framesize") { ssize_t spacePos = line.find(" ", colonPos + 1); if (spacePos < 0) { return false; } #ifndef ANDROID_DEFAULT_CODE if (key == "a=rtpmap") { if (rtpmapNum > 0) { mTracks.pop(); mFormats.pop(); unsupported = true; LOGW("ASessionDescription: multiple rtpmap" " for one media is not supported yet"); break; } else { rtpmapNum++; } } #endif // #ifndef ANDROID_DEFAULT_CODE key.setTo(line, 0, spacePos); colonPos = spacePos; } value.setTo(line, colonPos + 1, line.size() - colonPos - 1); } key.trim(); value.trim(); LOGV("adding '%s' => '%s'", key.c_str(), value.c_str()); mTracks.editItemAt(mTracks.size() - 1).add(key, value); break; } case 'm': { LOGV("new section '%s'", AString(line, 2, line.size() - 2).c_str()); #ifndef ANDROID_DEFAULT_CODE rtpmapNum = 0; unsupported = false; #endif // #ifndef ANDROID_DEFAULT_CODE mTracks.push(Attribs()); mFormats.push(AString(line, 2, line.size() - 2)); break; } default: { AString key, value; ssize_t equalPos = line.find("="); key = AString(line, 0, equalPos + 1); value = AString(line, equalPos + 1, line.size() - equalPos - 1); key.trim(); value.trim(); LOGV("adding '%s' => '%s'", key.c_str(), value.c_str()); mTracks.editItemAt(mTracks.size() - 1).add(key, value); break; } } i = eolPos + 1; } return true; }
int main(int argc, char **argv) { using namespace android; ProcessState::self()->startThreadPool(); DataSource::RegisterDefaultSniffers(); AString connectToHost; int32_t connectToPort = -1; AString uri; AString listenOnAddr; int32_t listenOnPort = -1; AString path; ///M: @{ int isFastSetup = 0; ///@} int res; while ((res = getopt(argc, argv, "hpic:b:l:t:f:r:u:e:s:d")) >= 0) { switch (res) { case 'b': { const char *colonPos = strrchr(optarg, ':'); if (colonPos == NULL) { connectToHost = optarg; connectToPort = WFD_UIBC_SERVER_PORT; } else { connectToHost.setTo(optarg, colonPos - optarg); char *end; connectToPort = strtol(colonPos + 1, &end, 10); if (*end != '\0' || end == colonPos + 1 || connectToPort < 1 || connectToPort > 65535) { fprintf(stderr, "Illegal port specified.\n"); exit(1); } } connectUibc(connectToHost.c_str(), connectToPort); exit(1); break; } case 't': { isFastSetup = 1; } case 'f': { path = optarg; break; } case 'u': { uri = optarg; break; } case 'l': { const char *colonPos = strrchr(optarg, ':'); if (colonPos == NULL) { listenOnAddr = optarg; listenOnPort = WifiDisplaySource::kWifiDisplayDefaultPort; } else { listenOnAddr.setTo(optarg, colonPos - optarg); char *end; listenOnPort = strtol(colonPos + 1, &end, 10); if (*end != '\0' || end == colonPos + 1 || listenOnPort < 1 || listenOnPort > 65535) { fprintf(stderr, "Illegal port specified.\n"); exit(1); } } break; } case 'r': { enableFastRtpRemoteDisplay(optarg); exit(0); break; } case 'e': { enableDisableRemoteDisplay(optarg); exit(0); break; } case 'd': { enableDisableRemoteDisplay(NULL); exit(0); break; } case 's': { setStreamMode(optarg); exit(0); break; } case '?': case 'h': default: testUibcCmd(argv[1]); usage(argv[0]); exit(1); } } if (listenOnPort >= 0) { if (path.empty()) { createSource(listenOnAddr, listenOnPort); } else { createFileSource(listenOnAddr, listenOnPort, path.c_str()); } exit(0); } usage(argv[0]); return 0; }