HTTPLiveSource.cpp revision 404fced9bfa8fa423ee210a271ca051ffd1bec13
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17//#define LOG_NDEBUG 0 18#define LOG_TAG "HTTPLiveSource" 19#include <utils/Log.h> 20 21#include "HTTPLiveSource.h" 22 23#include "AnotherPacketSource.h" 24#include "LiveDataSource.h" 25#include "LiveSession.h" 26 27#include <media/IMediaHTTPService.h> 28#include <media/stagefright/foundation/ABuffer.h> 29#include <media/stagefright/foundation/ADebug.h> 30#include <media/stagefright/foundation/AMessage.h> 31#include <media/stagefright/MediaErrors.h> 32#include <media/stagefright/MetaData.h> 33 34namespace android { 35 36NuPlayer::HTTPLiveSource::HTTPLiveSource( 37 const sp<AMessage> ¬ify, 38 const sp<IMediaHTTPService> &httpService, 39 const char *url, 40 const KeyedVector<String8, String8> *headers) 41 : Source(notify), 42 mHTTPService(httpService), 43 mURL(url), 44 mFlags(0), 45 mFinalResult(OK), 46 mOffset(0), 47 mFetchSubtitleDataGeneration(0) { 48 if (headers) { 49 mExtraHeaders = *headers; 50 51 ssize_t index = 52 mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log")); 53 54 if (index >= 0) { 55 mFlags |= kFlagIncognito; 56 57 mExtraHeaders.removeItemsAt(index); 58 } 59 } 60} 61 62NuPlayer::HTTPLiveSource::~HTTPLiveSource() { 63 if (mLiveSession != NULL) { 64 mLiveSession->disconnect(); 65 mLiveSession.clear(); 66 67 mLiveLooper->stop(); 68 mLiveLooper.clear(); 69 } 70} 71 72void NuPlayer::HTTPLiveSource::prepareAsync() { 73 mLiveLooper = new ALooper; 74 mLiveLooper->setName("http live"); 75 mLiveLooper->start(); 76 77 sp<AMessage> notify = new AMessage(kWhatSessionNotify, id()); 78 79 mLiveSession = new LiveSession( 80 notify, 81 (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0, 82 mHTTPService); 83 84 mLiveLooper->registerHandler(mLiveSession); 85 86 mLiveSession->connectAsync( 87 mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders); 88} 89 90void NuPlayer::HTTPLiveSource::start() { 91} 92 93sp<AMessage> NuPlayer::HTTPLiveSource::getFormat(bool audio) { 94 sp<AMessage> format; 95 status_t err = mLiveSession->getStreamFormat( 96 audio ? LiveSession::STREAMTYPE_AUDIO 97 : LiveSession::STREAMTYPE_VIDEO, 98 &format); 99 100 if (err != OK) { 101 return NULL; 102 } 103 104 return format; 105} 106 107status_t NuPlayer::HTTPLiveSource::feedMoreTSData() { 108 return OK; 109} 110 111status_t NuPlayer::HTTPLiveSource::dequeueAccessUnit( 112 bool audio, sp<ABuffer> *accessUnit) { 113 return mLiveSession->dequeueAccessUnit( 114 audio ? LiveSession::STREAMTYPE_AUDIO 115 : LiveSession::STREAMTYPE_VIDEO, 116 accessUnit); 117} 118 119status_t NuPlayer::HTTPLiveSource::getDuration(int64_t *durationUs) { 120 return mLiveSession->getDuration(durationUs); 121} 122 123size_t NuPlayer::HTTPLiveSource::getTrackCount() const { 124 return mLiveSession->getTrackCount(); 125} 126 127sp<AMessage> NuPlayer::HTTPLiveSource::getTrackInfo(size_t trackIndex) const { 128 return mLiveSession->getTrackInfo(trackIndex); 129} 130 131status_t NuPlayer::HTTPLiveSource::selectTrack(size_t trackIndex, bool select) { 132 status_t err = mLiveSession->selectTrack(trackIndex, select); 133 134 if (err == OK) { 135 mFetchSubtitleDataGeneration++; 136 if (select) { 137 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id()); 138 msg->setInt32("generation", mFetchSubtitleDataGeneration); 139 msg->post(); 140 } 141 } 142 143 // LiveSession::selectTrack returns BAD_VALUE when selecting the currently 144 // selected track, or unselecting a non-selected track. In this case it's an 145 // no-op so we return OK. 146 return (err == OK || err == BAD_VALUE) ? (status_t)OK : err; 147} 148 149status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs) { 150 return mLiveSession->seekTo(seekTimeUs); 151} 152 153void NuPlayer::HTTPLiveSource::onMessageReceived(const sp<AMessage> &msg) { 154 switch (msg->what()) { 155 case kWhatSessionNotify: 156 { 157 onSessionNotify(msg); 158 break; 159 } 160 161 case kWhatFetchSubtitleData: 162 { 163 int32_t generation; 164 CHECK(msg->findInt32("generation", &generation)); 165 166 if (generation != mFetchSubtitleDataGeneration) { 167 // stale 168 break; 169 } 170 171 sp<ABuffer> buffer; 172 if (mLiveSession->dequeueAccessUnit( 173 LiveSession::STREAMTYPE_SUBTITLES, &buffer) == OK) { 174 sp<AMessage> notify = dupNotify(); 175 notify->setInt32("what", kWhatSubtitleData); 176 notify->setBuffer("buffer", buffer); 177 notify->post(); 178 179 int64_t timeUs, baseUs, durationUs, delayUs; 180 CHECK(buffer->meta()->findInt64("baseUs", &baseUs)); 181 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 182 CHECK(buffer->meta()->findInt64("durationUs", &durationUs)); 183 delayUs = baseUs + timeUs - ALooper::GetNowUs(); 184 185 msg->post(delayUs > 0ll ? delayUs : 0ll); 186 } else { 187 // try again in 1 second 188 msg->post(1000000ll); 189 } 190 191 break; 192 } 193 194 default: 195 Source::onMessageReceived(msg); 196 break; 197 } 198} 199 200void NuPlayer::HTTPLiveSource::onSessionNotify(const sp<AMessage> &msg) { 201 int32_t what; 202 CHECK(msg->findInt32("what", &what)); 203 204 switch (what) { 205 case LiveSession::kWhatPrepared: 206 { 207 // notify the current size here if we have it, otherwise report an initial size of (0,0) 208 sp<AMessage> format = getFormat(false /* audio */); 209 int32_t width; 210 int32_t height; 211 if (format != NULL && 212 format->findInt32("width", &width) && format->findInt32("height", &height)) { 213 notifyVideoSizeChanged(width, height); 214 } else { 215 notifyVideoSizeChanged(0, 0); 216 } 217 218 uint32_t flags = FLAG_CAN_PAUSE; 219 if (mLiveSession->isSeekable()) { 220 flags |= FLAG_CAN_SEEK; 221 flags |= FLAG_CAN_SEEK_BACKWARD; 222 flags |= FLAG_CAN_SEEK_FORWARD; 223 } 224 225 if (mLiveSession->hasDynamicDuration()) { 226 flags |= FLAG_DYNAMIC_DURATION; 227 } 228 229 notifyFlagsChanged(flags); 230 231 notifyPrepared(); 232 break; 233 } 234 235 case LiveSession::kWhatPreparationFailed: 236 { 237 status_t err; 238 CHECK(msg->findInt32("err", &err)); 239 240 notifyPrepared(err); 241 break; 242 } 243 244 case LiveSession::kWhatStreamsChanged: 245 { 246 uint32_t changedMask; 247 CHECK(msg->findInt32( 248 "changedMask", (int32_t *)&changedMask)); 249 250 bool audio = changedMask & LiveSession::STREAMTYPE_AUDIO; 251 bool video = changedMask & LiveSession::STREAMTYPE_VIDEO; 252 253 sp<AMessage> reply; 254 CHECK(msg->findMessage("reply", &reply)); 255 256 sp<AMessage> notify = dupNotify(); 257 notify->setInt32("what", kWhatQueueDecoderShutdown); 258 notify->setInt32("audio", audio); 259 notify->setInt32("video", video); 260 notify->setMessage("reply", reply); 261 notify->post(); 262 break; 263 } 264 265 case LiveSession::kWhatError: 266 { 267 break; 268 } 269 270 default: 271 TRESPASS(); 272 } 273} 274 275} // namespace android 276 277