00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "MPEG2TransportFileServerMediaSubsession.hh"
00023 #include "SimpleRTPSink.hh"
00024 #include "ByteStreamFileSource.hh"
00025 #include "MPEG2TransportStreamTrickModeFilter.hh"
00026 #include "MPEG2TransportStreamFromESSource.hh"
00027 #include "MPEG2TransportStreamFramer.hh"
00028
00029
00030
00031 #define VIDEO_MPEG_VERSION 2
00032
00034
00035
00036
00037
00038 class ClientTrickPlayState {
00039 public:
00040 ClientTrickPlayState(MPEG2TransportStreamIndexFile* indexFile);
00041
00042
00043 void updateStateFromNPT(float npt);
00044 void updateStateOnScaleChange();
00045 void updateStateOnPlayChange(Boolean reverseToPreviousVSH);
00046
00047 void handleStreamDeletion();
00048 void setSource(MPEG2TransportStreamFramer* framer);
00049
00050 void setNextScale(float nextScale) { fNextScale = nextScale; }
00051 Boolean areChangingScale() const { return fNextScale != fScale; }
00052
00053 private:
00054 void updateTSRecordNum();
00055 void reseekOriginalTransportStreamSource();
00056
00057 private:
00058 MPEG2TransportStreamIndexFile* fIndexFile;
00059 ByteStreamFileSource* fOriginalTransportStreamSource;
00060 MPEG2TransportStreamTrickModeFilter* fTrickModeFilter;
00061 MPEG2TransportStreamFromESSource* fTrickPlaySource;
00062 MPEG2TransportStreamFramer* fFramer;
00063 float fScale, fNextScale, fNPT;
00064 unsigned long fTSRecordNum, fIxRecordNum;
00065 };
00066
00067
00069
00070 MPEG2TransportFileServerMediaSubsession*
00071 MPEG2TransportFileServerMediaSubsession::createNew(UsageEnvironment& env,
00072 char const* fileName,
00073 char const* indexFileName,
00074 Boolean reuseFirstSource) {
00075 if (indexFileName != NULL && reuseFirstSource) {
00076
00077 env << "MPEG2TransportFileServerMediaSubsession::createNew(): ignoring the index file name, because \"reuseFirstSource\" is set\n";
00078 indexFileName = NULL;
00079 }
00080 MPEG2TransportStreamIndexFile* indexFile = MPEG2TransportStreamIndexFile::createNew(env, indexFileName);
00081 return new MPEG2TransportFileServerMediaSubsession(env, fileName, indexFile,
00082 reuseFirstSource);
00083 }
00084
00085 MPEG2TransportFileServerMediaSubsession
00086 ::MPEG2TransportFileServerMediaSubsession(UsageEnvironment& env,
00087 char const* fileName,
00088 MPEG2TransportStreamIndexFile* indexFile,
00089 Boolean reuseFirstSource)
00090 : FileServerMediaSubsession(env, fileName, reuseFirstSource),
00091 fIndexFile(indexFile), fDuration(0.0), fClientSessionHashTable(NULL) {
00092 if (fIndexFile != NULL) {
00093 fDuration = fIndexFile->getPlayingDuration();
00094 fClientSessionHashTable = HashTable::create(ONE_WORD_HASH_KEYS);
00095 }
00096 }
00097
00098 MPEG2TransportFileServerMediaSubsession
00099 ::~MPEG2TransportFileServerMediaSubsession() {
00100 if (fIndexFile != NULL) {
00101 Medium::close(fIndexFile);
00102
00103
00104 while (1) {
00105 ClientTrickPlayState* client
00106 = (ClientTrickPlayState*)(fClientSessionHashTable->RemoveNext());
00107 if (client == NULL) break;
00108 delete client;
00109 }
00110 delete fClientSessionHashTable;
00111 }
00112 }
00113
00114 #define TRANSPORT_PACKET_SIZE 188
00115 #define TRANSPORT_PACKETS_PER_NETWORK_PACKET 7
00116
00117
00118 void MPEG2TransportFileServerMediaSubsession
00119 ::startStream(unsigned clientSessionId, void* streamToken, TaskFunc* rtcpRRHandler,
00120 void* rtcpRRHandlerClientData, unsigned short& rtpSeqNum,
00121 unsigned& rtpTimestamp) {
00122 if (fIndexFile != NULL) {
00123 ClientTrickPlayState* client = lookupClient(clientSessionId);
00124 if (client != NULL && client->areChangingScale()) {
00125
00126 client->updateStateOnPlayChange(True);
00127 OnDemandServerMediaSubsession::pauseStream(clientSessionId, streamToken);
00128
00129
00130 client->updateStateOnScaleChange();
00131 }
00132 }
00133
00134
00135 OnDemandServerMediaSubsession::startStream(clientSessionId, streamToken,
00136 rtcpRRHandler, rtcpRRHandlerClientData,
00137 rtpSeqNum, rtpTimestamp);
00138 }
00139
00140 void MPEG2TransportFileServerMediaSubsession
00141 ::pauseStream(unsigned clientSessionId, void* streamToken) {
00142 if (fIndexFile != NULL) {
00143 ClientTrickPlayState* client = lookupClient(clientSessionId);
00144 if (client != NULL) {
00145 client->updateStateOnPlayChange(False);
00146 }
00147 }
00148
00149
00150 OnDemandServerMediaSubsession::pauseStream(clientSessionId, streamToken);
00151 }
00152
00153 void MPEG2TransportFileServerMediaSubsession
00154 ::seekStream(unsigned clientSessionId, void* streamToken, float seekNPT) {
00155 if (fIndexFile != NULL) {
00156 ClientTrickPlayState* client = lookupClient(clientSessionId);
00157 if (client != NULL) {
00158 client->updateStateFromNPT(seekNPT);
00159 }
00160 }
00161
00162
00163 OnDemandServerMediaSubsession::seekStream(clientSessionId, streamToken, seekNPT);
00164 }
00165
00166 void MPEG2TransportFileServerMediaSubsession
00167 ::setStreamScale(unsigned clientSessionId, void* streamToken, float scale) {
00168 if (fIndexFile != NULL) {
00169 ClientTrickPlayState* client = lookupClient(clientSessionId);
00170 if (client != NULL) {
00171 client->setNextScale(scale);
00172 }
00173 }
00174
00175
00176 OnDemandServerMediaSubsession::setStreamScale(clientSessionId, streamToken, scale);
00177 }
00178
00179 void MPEG2TransportFileServerMediaSubsession
00180 ::deleteStream(unsigned clientSessionId, void*& streamToken) {
00181 if (fIndexFile != NULL) {
00182 ClientTrickPlayState* client = lookupClient(clientSessionId);
00183 if (client != NULL) {
00184 client->updateStateOnPlayChange(False);
00185 }
00186 }
00187
00188
00189 OnDemandServerMediaSubsession::deleteStream(clientSessionId, streamToken);
00190 }
00191
00192 FramedSource* MPEG2TransportFileServerMediaSubsession
00193 ::createNewStreamSource(unsigned clientSessionId, unsigned& estBitrate) {
00194 estBitrate = 5000;
00195
00196
00197 unsigned const inputDataChunkSize
00198 = TRANSPORT_PACKETS_PER_NETWORK_PACKET*TRANSPORT_PACKET_SIZE;
00199 ByteStreamFileSource* fileSource
00200 = ByteStreamFileSource::createNew(envir(), fFileName, inputDataChunkSize);
00201 if (fileSource == NULL) return NULL;
00202 fFileSize = fileSource->fileSize();
00203
00204
00205 MPEG2TransportStreamFramer* framer
00206 = MPEG2TransportStreamFramer::createNew(envir(), fileSource);
00207
00208 if (fIndexFile != NULL) {
00209
00210 ClientTrickPlayState* client = lookupClient(clientSessionId);
00211 if (client == NULL) {
00212 client = new ClientTrickPlayState(fIndexFile);
00213 fClientSessionHashTable->Add((char const*)clientSessionId, client);
00214 }
00215 client->setSource(framer);
00216 }
00217
00218 return framer;
00219 }
00220
00221 RTPSink* MPEG2TransportFileServerMediaSubsession
00222 ::createNewRTPSink(Groupsock* rtpGroupsock,
00223 unsigned char ,
00224 FramedSource* ) {
00225 return SimpleRTPSink::createNew(envir(), rtpGroupsock,
00226 33, 90000, "video", "MP2T",
00227 1, True, False );
00228 }
00229
00230 void MPEG2TransportFileServerMediaSubsession::testScaleFactor(float& scale) {
00231 if (fIndexFile != NULL && fDuration > 0.0) {
00232
00233 int iScale = scale < 0.0 ? (int)(scale - 0.5f) : (int)(scale + 0.5f);
00234 if (iScale == 0) iScale = 1;
00235 scale = (float)iScale;
00236 } else {
00237 scale = 1.0f;
00238 }
00239 }
00240
00241 float MPEG2TransportFileServerMediaSubsession::duration() const {
00242 return fDuration;
00243 }
00244
00245 ClientTrickPlayState* MPEG2TransportFileServerMediaSubsession
00246 ::lookupClient(unsigned clientSessionId) {
00247 return (ClientTrickPlayState*)(fClientSessionHashTable->Lookup((char const*)clientSessionId));
00248 }
00249
00250
00252
00253 ClientTrickPlayState::ClientTrickPlayState(MPEG2TransportStreamIndexFile* indexFile)
00254 : fIndexFile(indexFile),
00255 fOriginalTransportStreamSource(NULL),
00256 fTrickModeFilter(NULL), fTrickPlaySource(NULL),
00257 fFramer(NULL),
00258 fScale(1.0f), fNextScale(1.0f), fNPT(0.0f),
00259 fTSRecordNum(0), fIxRecordNum(0) {
00260 }
00261
00262 void ClientTrickPlayState::updateStateFromNPT(float npt) {
00263 fNPT = npt;
00264
00265 unsigned long tsRecordNum, ixRecordNum;
00266 fIndexFile->lookupTSPacketNumFromNPT(fNPT, tsRecordNum, ixRecordNum);
00267
00268 updateTSRecordNum();
00269 if (tsRecordNum != fTSRecordNum) {
00270 fTSRecordNum = tsRecordNum;
00271 fIxRecordNum = ixRecordNum;
00272
00273
00274 reseekOriginalTransportStreamSource();
00275
00276
00277
00278
00279 fFramer->clearPIDStatusTable();
00280 }
00281 }
00282
00283 void ClientTrickPlayState::updateStateOnScaleChange() {
00284 fScale = fNextScale;
00285
00286
00287
00288 if (fTrickPlaySource != NULL) {
00289 fTrickModeFilter->forgetInputSource();
00290
00291 Medium::close(fTrickPlaySource);
00292 fTrickPlaySource = NULL;
00293 fTrickModeFilter = NULL;
00294 }
00295 if (fNextScale != 1.0f) {
00296
00297 UsageEnvironment& env = fIndexFile->envir();
00298 fTrickModeFilter = MPEG2TransportStreamTrickModeFilter
00299 ::createNew(env, fOriginalTransportStreamSource, fIndexFile, int(fNextScale));
00300 fTrickModeFilter->seekTo(fTSRecordNum, fIxRecordNum);
00301
00302
00303 fTrickPlaySource = MPEG2TransportStreamFromESSource::createNew(env);
00304 fTrickPlaySource->addNewVideoSource(fTrickModeFilter, VIDEO_MPEG_VERSION);
00305
00306 fFramer->changeInputSource(fTrickPlaySource);
00307 } else {
00308
00309 reseekOriginalTransportStreamSource();
00310 fFramer->changeInputSource(fOriginalTransportStreamSource);
00311 }
00312 }
00313
00314 void ClientTrickPlayState::updateStateOnPlayChange(Boolean reverseToPreviousVSH) {
00315 updateTSRecordNum();
00316 if (fTrickPlaySource == NULL) {
00317
00318
00319 fIndexFile->lookupPCRFromTSPacketNum(fTSRecordNum, reverseToPreviousVSH, fNPT, fIxRecordNum);
00320 } else {
00321
00322
00323 fIxRecordNum = fTrickModeFilter->nextIndexRecordNum();
00324 if ((long)fIxRecordNum < 0) fIxRecordNum = 0;
00325 unsigned long transportRecordNum;
00326 float pcr;
00327 u_int8_t offset, size, recordType;
00328 if (fIndexFile->readIndexRecordValues(fIxRecordNum, transportRecordNum,
00329 offset, size, pcr, recordType)) {
00330 fTSRecordNum = transportRecordNum;
00331 fNPT = pcr;
00332 }
00333 }
00334 }
00335
00336 void ClientTrickPlayState::setSource(MPEG2TransportStreamFramer* framer) {
00337 fFramer = framer;
00338 fOriginalTransportStreamSource = (ByteStreamFileSource*)(framer->inputSource());
00339 }
00340
00341 void ClientTrickPlayState::updateTSRecordNum(){
00342 if (fFramer != NULL) fTSRecordNum += fFramer->tsPacketCount();
00343 }
00344
00345 void ClientTrickPlayState::reseekOriginalTransportStreamSource() {
00346 u_int64_t tsRecordNum64 = (u_int64_t)fTSRecordNum;
00347 fOriginalTransportStreamSource->seekToByteAbsolute(tsRecordNum64*TRANSPORT_PACKET_SIZE);
00348 }