status_t MediaCodecList::includeXMLFile(const char **attrs) { const char *href = NULL; size_t i = 0; while (attrs[i] != NULL) { if (!strcmp(attrs[i], "href")) { if (attrs[i + 1] == NULL) { return -EINVAL; } href = attrs[i + 1]; ++i; } else { return -EINVAL; } ++i; } // For security reasons and for simplicity, file names can only contain // [a-zA-Z0-9_.] and must start with media_codecs_ and end with .xml for (i = 0; href[i] != '\0'; i++) { if (href[i] == '.' || href[i] == '_' || (href[i] >= '0' && href[i] <= '9') || (href[i] >= 'A' && href[i] <= 'Z') || (href[i] >= 'a' && href[i] <= 'z')) { continue; } ALOGE("invalid include file name: %s", href); return -EINVAL; } AString filename = href; if (!filename.startsWith("media_codecs_") || !filename.endsWith(".xml")) { ALOGE("invalid include file name: %s", href); return -EINVAL; } filename.insert(mHrefBase, 0); parseXMLFile(filename.c_str()); return mInitCheck; }
void profileCodecs( const Vector<sp<MediaCodecInfo>> &infos, CodecSettings *global_results, KeyedVector<AString, CodecSettings> *encoder_results, KeyedVector<AString, CodecSettings> *decoder_results, bool forceToMeasure) { KeyedVector<AString, sp<MediaCodecInfo::Capabilities>> codecsNeedMeasure; AString supportMultipleSecureCodecs = "true"; size_t maxEncoderInputBuffers = 0; for (size_t i = 0; i < infos.size(); ++i) { const sp<MediaCodecInfo> info = infos[i]; AString name = info->getCodecName(); if (name.startsWith("OMX.google.") || // TODO: reenable below codecs once fixed name == "OMX.Intel.VideoDecoder.VP9.hybrid") { continue; } Vector<AString> mimes; info->getSupportedMimes(&mimes); for (size_t i = 0; i < mimes.size(); ++i) { const sp<MediaCodecInfo::Capabilities> &caps = info->getCapabilitiesFor(mimes[i].c_str()); if (!forceToMeasure && (caps->getDetails()->contains("max-supported-instances") || caps->getDetails()->contains("max-concurrent-instances"))) { continue; } size_t max = doProfileCodecs(info->isEncoder(), name, mimes[i], caps); if (max > 0) { CodecSettings settings; char maxStr[32]; sprintf(maxStr, "%zu", max); settings.add("max-supported-instances", maxStr); AString key = name; key.append(" "); key.append(mimes[i]); if (info->isEncoder()) { encoder_results->add(key, settings); } else { decoder_results->add(key, settings); } if (name.endsWith(".secure")) { if (max <= 1) { supportMultipleSecureCodecs = "false"; } } if (info->isEncoder() && mimes[i].startsWith("video/")) { size_t encoderInputBuffers = doProfileEncoderInputBuffers(name, mimes[i], caps); if (encoderInputBuffers > maxEncoderInputBuffers) { maxEncoderInputBuffers = encoderInputBuffers; } } } } } if (maxEncoderInputBuffers > 0) { char tmp[32]; sprintf(tmp, "%zu", maxEncoderInputBuffers); global_results->add(kMaxEncoderInputBuffers, tmp); } global_results->add(kPolicySupportsMultipleSecureCodecs, supportMultipleSecureCodecs); }
status_t WifiDisplaySource::onSetupRequest( int32_t sessionID, int32_t cseq, const sp<ParsedMessage> &data) { CHECK_EQ(sessionID, mClientSessionID); if (mClientInfo.mPlaybackSessionID != -1) { // We only support a single playback session per client. // This is due to the reversed keep-alive design in the wfd specs... sendErrorResponse(sessionID, "400 Bad Request", cseq); return ERROR_MALFORMED; } AString transport; if (!data->findString("transport", &transport)) { sendErrorResponse(sessionID, "400 Bad Request", cseq); return ERROR_MALFORMED; } RTPSender::TransportMode rtpMode = RTPSender::TRANSPORT_UDP; int clientRtp, clientRtcp; if (transport.startsWith("RTP/AVP/TCP;")) { AString interleaved; if (ParsedMessage::GetAttribute( transport.c_str(), "interleaved", &interleaved) && sscanf(interleaved.c_str(), "%d-%d", &clientRtp, &clientRtcp) == 2) { rtpMode = RTPSender::TRANSPORT_TCP_INTERLEAVED; } else { bool badRequest = false; AString clientPort; if (!ParsedMessage::GetAttribute( transport.c_str(), "client_port", &clientPort)) { badRequest = true; } else if (sscanf(clientPort.c_str(), "%d-%d", &clientRtp, &clientRtcp) == 2) { } else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) { // No RTCP. clientRtcp = -1; } else { badRequest = true; } if (badRequest) { sendErrorResponse(sessionID, "400 Bad Request", cseq); return ERROR_MALFORMED; } rtpMode = RTPSender::TRANSPORT_TCP; } } else if (transport.startsWith("RTP/AVP;unicast;") || transport.startsWith("RTP/AVP/UDP;unicast;")) { bool badRequest = false; AString clientPort; if (!ParsedMessage::GetAttribute( transport.c_str(), "client_port", &clientPort)) { badRequest = true; } else if (sscanf(clientPort.c_str(), "%d-%d", &clientRtp, &clientRtcp) == 2) { } else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) { // No RTCP. clientRtcp = -1; } else { badRequest = true; } if (badRequest) { sendErrorResponse(sessionID, "400 Bad Request", cseq); return ERROR_MALFORMED; } #if 1 // The older LG dongles doesn't specify client_port=xxx apparently. } else if (transport == "RTP/AVP/UDP;unicast") { clientRtp = 19000; clientRtcp = -1; #endif } else { sendErrorResponse(sessionID, "461 Unsupported Transport", cseq); return ERROR_UNSUPPORTED; } int32_t playbackSessionID = makeUniquePlaybackSessionID(); sp<AMessage> notify = new AMessage(kWhatPlaybackSessionNotify, this); notify->setInt32("playbackSessionID", playbackSessionID); notify->setInt32("sessionID", sessionID); sp<PlaybackSession> playbackSession = new PlaybackSession( mOpPackageName, mNetSession, notify, mInterfaceAddr, mHDCP, mMediaPath.c_str()); looper()->registerHandler(playbackSession); AString uri; data->getRequestField(1, &uri); if (strncasecmp("rtsp://", uri.c_str(), 7)) { sendErrorResponse(sessionID, "400 Bad Request", cseq); return ERROR_MALFORMED; } if (!(uri.startsWith("rtsp://") && uri.endsWith("/wfd1.0/streamid=0"))) { sendErrorResponse(sessionID, "404 Not found", cseq); return ERROR_MALFORMED; } RTPSender::TransportMode rtcpMode = RTPSender::TRANSPORT_UDP; if (clientRtcp < 0) { rtcpMode = RTPSender::TRANSPORT_NONE; } status_t err = playbackSession->init( mClientInfo.mRemoteIP.c_str(), clientRtp, rtpMode, clientRtcp, rtcpMode, mSinkSupportsAudio, mUsingPCMAudio, mSinkSupportsVideo, mChosenVideoResolutionType, mChosenVideoResolutionIndex, mChosenVideoProfile, mChosenVideoLevel); if (err != OK) { looper()->unregisterHandler(playbackSession->id()); playbackSession.clear(); } switch (err) { case OK: break; case -ENOENT: sendErrorResponse(sessionID, "404 Not Found", cseq); return err; default: sendErrorResponse(sessionID, "403 Forbidden", cseq); return err; } mClientInfo.mPlaybackSessionID = playbackSessionID; mClientInfo.mPlaybackSession = playbackSession; AString response = "RTSP/1.0 200 OK\r\n"; AppendCommonResponse(&response, cseq, playbackSessionID); if (rtpMode == RTPSender::TRANSPORT_TCP_INTERLEAVED) { response.append( AStringPrintf( "Transport: RTP/AVP/TCP;interleaved=%d-%d;", clientRtp, clientRtcp)); } else { int32_t serverRtp = playbackSession->getRTPPort(); AString transportString = "UDP"; if (rtpMode == RTPSender::TRANSPORT_TCP) { transportString = "TCP"; } if (clientRtcp >= 0) { response.append( AStringPrintf( "Transport: RTP/AVP/%s;unicast;client_port=%d-%d;" "server_port=%d-%d\r\n", transportString.c_str(), clientRtp, clientRtcp, serverRtp, serverRtp + 1)); } else { response.append( AStringPrintf( "Transport: RTP/AVP/%s;unicast;client_port=%d;" "server_port=%d\r\n", transportString.c_str(), clientRtp, serverRtp)); } } response.append("\r\n"); err = mNetSession->sendRequest(sessionID, response.c_str()); if (err != OK) { return err; } mState = AWAITING_CLIENT_PLAY; scheduleReaper(); scheduleKeepAlive(sessionID); return OK; }