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(double 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 ServerRequestAlternativeByteHandler* serverRequestAlternativeByteHandler,
00123 void* serverRequestAlternativeByteHandlerClientData) {
00124 if (fIndexFile != NULL) {
00125 ClientTrickPlayState* client = lookupClient(clientSessionId);
00126 if (client != NULL && client->areChangingScale()) {
00127
00128 client->updateStateOnPlayChange(True);
00129 OnDemandServerMediaSubsession::pauseStream(clientSessionId, streamToken);
00130
00131
00132 client->updateStateOnScaleChange();
00133 }
00134 }
00135
00136
00137 OnDemandServerMediaSubsession::startStream(clientSessionId, streamToken,
00138 rtcpRRHandler, rtcpRRHandlerClientData,
00139 rtpSeqNum, rtpTimestamp,
00140 serverRequestAlternativeByteHandler, serverRequestAlternativeByteHandlerClientData);
00141 }
00142
00143 void MPEG2TransportFileServerMediaSubsession
00144 ::pauseStream(unsigned clientSessionId, void* streamToken) {
00145 if (fIndexFile != NULL) {
00146 ClientTrickPlayState* client = lookupClient(clientSessionId);
00147 if (client != NULL) {
00148 client->updateStateOnPlayChange(False);
00149 }
00150 }
00151
00152
00153 OnDemandServerMediaSubsession::pauseStream(clientSessionId, streamToken);
00154 }
00155
00156 void MPEG2TransportFileServerMediaSubsession
00157 ::seekStream(unsigned clientSessionId, void* streamToken, double seekNPT) {
00158 if (fIndexFile != NULL) {
00159 ClientTrickPlayState* client = lookupClient(clientSessionId);
00160 if (client != NULL) {
00161 client->updateStateFromNPT(seekNPT);
00162 }
00163 }
00164
00165
00166 OnDemandServerMediaSubsession::seekStream(clientSessionId, streamToken, seekNPT);
00167 }
00168
00169 void MPEG2TransportFileServerMediaSubsession
00170 ::setStreamScale(unsigned clientSessionId, void* streamToken, float scale) {
00171 if (fIndexFile != NULL) {
00172 ClientTrickPlayState* client = lookupClient(clientSessionId);
00173 if (client != NULL) {
00174 client->setNextScale(scale);
00175 }
00176 }
00177
00178
00179 OnDemandServerMediaSubsession::setStreamScale(clientSessionId, streamToken, scale);
00180 }
00181
00182 void MPEG2TransportFileServerMediaSubsession
00183 ::deleteStream(unsigned clientSessionId, void*& streamToken) {
00184 if (fIndexFile != NULL) {
00185 ClientTrickPlayState* client = lookupClient(clientSessionId);
00186 if (client != NULL) {
00187 client->updateStateOnPlayChange(False);
00188 }
00189 }
00190
00191
00192 OnDemandServerMediaSubsession::deleteStream(clientSessionId, streamToken);
00193 }
00194
00195 FramedSource* MPEG2TransportFileServerMediaSubsession
00196 ::createNewStreamSource(unsigned clientSessionId, unsigned& estBitrate) {
00197 estBitrate = 5000;
00198
00199
00200 unsigned const inputDataChunkSize
00201 = TRANSPORT_PACKETS_PER_NETWORK_PACKET*TRANSPORT_PACKET_SIZE;
00202 ByteStreamFileSource* fileSource
00203 = ByteStreamFileSource::createNew(envir(), fFileName, inputDataChunkSize);
00204 if (fileSource == NULL) return NULL;
00205 fFileSize = fileSource->fileSize();
00206
00207
00208 MPEG2TransportStreamFramer* framer
00209 = MPEG2TransportStreamFramer::createNew(envir(), fileSource);
00210
00211 if (fIndexFile != NULL) {
00212
00213 ClientTrickPlayState* client = lookupClient(clientSessionId);
00214 if (client == NULL) {
00215 client = new ClientTrickPlayState(fIndexFile);
00216 fClientSessionHashTable->Add((char const*)clientSessionId, client);
00217 }
00218 client->setSource(framer);
00219 }
00220
00221 return framer;
00222 }
00223
00224 RTPSink* MPEG2TransportFileServerMediaSubsession
00225 ::createNewRTPSink(Groupsock* rtpGroupsock,
00226 unsigned char ,
00227 FramedSource* ) {
00228 return SimpleRTPSink::createNew(envir(), rtpGroupsock,
00229 33, 90000, "video", "MP2T",
00230 1, True, False );
00231 }
00232
00233 void MPEG2TransportFileServerMediaSubsession::testScaleFactor(float& scale) {
00234 if (fIndexFile != NULL && fDuration > 0.0) {
00235
00236 int iScale = scale < 0.0 ? (int)(scale - 0.5f) : (int)(scale + 0.5f);
00237 if (iScale == 0) iScale = 1;
00238 scale = (float)iScale;
00239 } else {
00240 scale = 1.0f;
00241 }
00242 }
00243
00244 float MPEG2TransportFileServerMediaSubsession::duration() const {
00245 return fDuration;
00246 }
00247
00248 ClientTrickPlayState* MPEG2TransportFileServerMediaSubsession
00249 ::lookupClient(unsigned clientSessionId) {
00250 return (ClientTrickPlayState*)(fClientSessionHashTable->Lookup((char const*)clientSessionId));
00251 }
00252
00253
00255
00256 ClientTrickPlayState::ClientTrickPlayState(MPEG2TransportStreamIndexFile* indexFile)
00257 : fIndexFile(indexFile),
00258 fOriginalTransportStreamSource(NULL),
00259 fTrickModeFilter(NULL), fTrickPlaySource(NULL),
00260 fFramer(NULL),
00261 fScale(1.0f), fNextScale(1.0f), fNPT(0.0f),
00262 fTSRecordNum(0), fIxRecordNum(0) {
00263 }
00264
00265 void ClientTrickPlayState::updateStateFromNPT(double npt) {
00266 fNPT = (float)npt;
00267
00268 unsigned long tsRecordNum, ixRecordNum;
00269 fIndexFile->lookupTSPacketNumFromNPT(fNPT, tsRecordNum, ixRecordNum);
00270
00271 updateTSRecordNum();
00272 if (tsRecordNum != fTSRecordNum) {
00273 fTSRecordNum = tsRecordNum;
00274 fIxRecordNum = ixRecordNum;
00275
00276
00277 reseekOriginalTransportStreamSource();
00278
00279
00280
00281
00282 fFramer->clearPIDStatusTable();
00283 }
00284 }
00285
00286 void ClientTrickPlayState::updateStateOnScaleChange() {
00287 fScale = fNextScale;
00288
00289
00290
00291 if (fTrickPlaySource != NULL) {
00292 fTrickModeFilter->forgetInputSource();
00293
00294 Medium::close(fTrickPlaySource);
00295 fTrickPlaySource = NULL;
00296 fTrickModeFilter = NULL;
00297 }
00298 if (fNextScale != 1.0f) {
00299
00300 UsageEnvironment& env = fIndexFile->envir();
00301 fTrickModeFilter = MPEG2TransportStreamTrickModeFilter
00302 ::createNew(env, fOriginalTransportStreamSource, fIndexFile, int(fNextScale));
00303 fTrickModeFilter->seekTo(fTSRecordNum, fIxRecordNum);
00304
00305
00306 fTrickPlaySource = MPEG2TransportStreamFromESSource::createNew(env);
00307 fTrickPlaySource->addNewVideoSource(fTrickModeFilter, VIDEO_MPEG_VERSION);
00308
00309 fFramer->changeInputSource(fTrickPlaySource);
00310 } else {
00311
00312 reseekOriginalTransportStreamSource();
00313 fFramer->changeInputSource(fOriginalTransportStreamSource);
00314 }
00315 }
00316
00317 void ClientTrickPlayState::updateStateOnPlayChange(Boolean reverseToPreviousVSH) {
00318 updateTSRecordNum();
00319 if (fTrickPlaySource == NULL) {
00320
00321
00322 fIndexFile->lookupPCRFromTSPacketNum(fTSRecordNum, reverseToPreviousVSH, fNPT, fIxRecordNum);
00323 } else {
00324
00325
00326 fIxRecordNum = fTrickModeFilter->nextIndexRecordNum();
00327 if ((long)fIxRecordNum < 0) fIxRecordNum = 0;
00328 unsigned long transportRecordNum;
00329 float pcr;
00330 u_int8_t offset, size, recordType;
00331 if (fIndexFile->readIndexRecordValues(fIxRecordNum, transportRecordNum,
00332 offset, size, pcr, recordType)) {
00333 fTSRecordNum = transportRecordNum;
00334 fNPT = pcr;
00335 }
00336 }
00337 }
00338
00339 void ClientTrickPlayState::setSource(MPEG2TransportStreamFramer* framer) {
00340 fFramer = framer;
00341 fOriginalTransportStreamSource = (ByteStreamFileSource*)(framer->inputSource());
00342 }
00343
00344 void ClientTrickPlayState::updateTSRecordNum(){
00345 if (fFramer != NULL) fTSRecordNum += fFramer->tsPacketCount();
00346 }
00347
00348 void ClientTrickPlayState::reseekOriginalTransportStreamSource() {
00349 u_int64_t tsRecordNum64 = (u_int64_t)fTSRecordNum;
00350 fOriginalTransportStreamSource->seekToByteAbsolute(tsRecordNum64*TRANSPORT_PACKET_SIZE);
00351 }