void ClientTrickPlayState::updateStateFromNPT(double npt, double streamDuration) { fNPT = (float)npt; // Map "fNPT" to the corresponding Transport Stream and Index record numbers: unsigned long tsRecordNum, ixRecordNum; fIndexFile->lookupTSPacketNumFromNPT(fNPT, tsRecordNum, ixRecordNum); updateTSRecordNum(); if (tsRecordNum != fTSRecordNum) { fTSRecordNum = tsRecordNum; fIxRecordNum = ixRecordNum; // Seek the source to the new record number: reseekOriginalTransportStreamSource(); // Note: We assume that we're asked to seek only in normal // (i.e., non trick play) mode, so we don't seek within the trick // play source (if any). fFramer->clearPIDStatusTable(); } unsigned long numTSRecordsToStream = 0; if (streamDuration > 0.0) { // Use the index file to figure out how many Transport Packets we get to stream: unsigned long toTSRecordNum, toIxRecordNum; float toNPT = (float)(fNPT + streamDuration); fIndexFile->lookupTSPacketNumFromNPT(toNPT, toTSRecordNum, toIxRecordNum); if (toTSRecordNum > tsRecordNum) // sanity check { numTSRecordsToStream = toTSRecordNum - tsRecordNum; } } fFramer->setNumTSPacketsToStream(numTSRecordsToStream); }
void ClientTrickPlayState::updateStateFromNPT(double npt) { fNPT = (float)npt; // Map "fNPT" to the corresponding Transport Stream and Index record numbers: unsigned long tsRecordNum, ixRecordNum; fIndexFile->lookupTSPacketNumFromNPT(fNPT, tsRecordNum, ixRecordNum); updateTSRecordNum(); if (tsRecordNum != fTSRecordNum) { fTSRecordNum = tsRecordNum; fIxRecordNum = ixRecordNum; // Seek the source to the new record number: reseekOriginalTransportStreamSource(); // Note: We assume that we're asked to seek only in normal // (i.e., non trick play) mode, so we don't seek within the trick // play source (if any). fFramer->clearPIDStatusTable(); } }
int main(int argc, char const** argv) { // Begin by setting up our usage environment: TaskScheduler* scheduler = BasicTaskScheduler::createNew(); env = BasicUsageEnvironment::createNew(*scheduler); // Parse the command line: programName = argv[0]; if (argc != 5) usage(); char const* inputFileName = argv[1]; // Check whether the input file name ends with ".ts": int len = strlen(inputFileName); if (len < 4 || strcmp(&inputFileName[len-3], ".ts") != 0) { *env << "ERROR: input file name \"" << inputFileName << "\" does not end with \".ts\"\n"; usage(); } // Parse the <start-time> and <scale> parameters: float startTime; if (sscanf(argv[2], "%f", &startTime) != 1 || startTime < 0.0f) usage(); int scale; if (sscanf(argv[3], "%d", &scale) != 1 || scale == 0) usage(); // Open the input file (as a 'byte stream file source'): FramedSource* input = ByteStreamFileSource::createNew(*env, inputFileName, TRANSPORT_PACKET_SIZE); if (input == NULL) { *env << "Failed to open input file \"" << inputFileName << "\" (does it exist?)\n"; exit(1); } // Check whether the corresponding index file exists. // The index file name is the same as the input file name, except with suffix ".tsx": char* indexFileName = new char[len+2]; // allow for trailing x\0 sprintf(indexFileName, "%sx", inputFileName); MPEG2TransportStreamIndexFile* indexFile = MPEG2TransportStreamIndexFile::createNew(*env, indexFileName); if (indexFile == NULL) { *env << "Failed to open index file \"" << indexFileName << "\" (does it exist?)\n"; exit(1); } // Create a filter that generates trick mode data from the input and index files: MPEG2TransportStreamTrickModeFilter* trickModeFilter = MPEG2TransportStreamTrickModeFilter::createNew(*env, input, indexFile, scale); if (startTime > 0.0f) { // Seek the input Transport Stream and Index files to the specified start time: unsigned long tsRecordNumber, indexRecordNumber; indexFile->lookupTSPacketNumFromNPT(startTime, tsRecordNumber, indexRecordNumber); if (!trickModeFilter->seekTo(tsRecordNumber, indexRecordNumber)) { // TARFU! *env << "Failed to seek trick mode filter to ts #" << (unsigned)tsRecordNumber << ", ix #" << (unsigned)indexRecordNumber << "(for time " << startTime << ")\n"; exit(1); } } // Generate a new Transport Stream from the Trick Mode filter: MPEG2TransportStreamFromESSource* newTransportStream = MPEG2TransportStreamFromESSource::createNew(*env); newTransportStream->addNewVideoSource(trickModeFilter, indexFile->mpegVersion()); // Open the output file (for writing), as a 'file sink': char const* outputFileName = argv[4]; MediaSink* output = FileSink::createNew(*env, outputFileName); if (output == NULL) { *env << "Failed to open output file \"" << outputFileName << "\"\n"; exit(1); } // Start playing, to generate the output file: *env << "Writing output file \"" << outputFileName << "\" (start time " << startTime << ", scale " << scale << ")..."; output->startPlaying(*newTransportStream, afterPlaying, NULL); env->taskScheduler().doEventLoop(); // does not return return 0; // only to prevent compiler warning }