void ClientTrickPlayState::updateStateOnScaleChange() { fScale = fNextScale; // Change our source objects to reflect the change in scale: // First, close the existing trick play source (if any): if (fTrickPlaySource != NULL) { fTrickModeFilter->forgetInputSource(); // so that the underlying Transport Stream source doesn't get deleted by: Medium::close(fTrickPlaySource); fTrickPlaySource = NULL; fTrickModeFilter = NULL; } if (fNextScale != 1.0f) { // Create a new trick play filter from the original Transport Stream source: UsageEnvironment &env = fIndexFile->envir(); // alias fTrickModeFilter = MPEG2TransportStreamTrickModeFilter ::createNew(env, fOriginalTransportStreamSource, fIndexFile, int(fNextScale)); fTrickModeFilter->seekTo(fTSRecordNum, fIxRecordNum); // And generate a Transport Stream from this: fTrickPlaySource = MPEG2TransportStreamFromESSource::createNew(env); fTrickPlaySource->addNewVideoSource(fTrickModeFilter, fIndexFile->mpegVersion()); fFramer->changeInputSource(fTrickPlaySource); } else { // Switch back to the original Transport Stream source: reseekOriginalTransportStreamSource(); fFramer->changeInputSource(fOriginalTransportStreamSource); } }
void MPEG2TransportStreamTrickModeFilter ::afterGettingFrame(void* clientData, unsigned frameSize, unsigned /*numTruncatedBytes*/, struct timeval presentationTime, unsigned /*durationInMicroseconds*/) { MPEG2TransportStreamTrickModeFilter* filter = (MPEG2TransportStreamTrickModeFilter*)clientData; filter->afterGettingFrame1(frameSize); }
void ClientTrickPlayState::updateStateOnPlayChange(Boolean reverseToPreviousVSH) { updateTSRecordNum(); if (fTrickPlaySource == NULL) { // We were in regular (1x) play. Use the index file to look up the // index record number and npt from the current transport number: fIndexFile->lookupPCRFromTSPacketNum(fTSRecordNum, reverseToPreviousVSH, fNPT, fIxRecordNum); } else { // We were in trick mode, and so already have the index record number. // Get the transport record number and npt from this: fIxRecordNum = fTrickModeFilter->nextIndexRecordNum(); if ((long)fIxRecordNum < 0) fIxRecordNum = 0; // we were at the start of the file unsigned long transportRecordNum; float pcr; u_int8_t offset, size, recordType; // all dummy if (fIndexFile->readIndexRecordValues(fIxRecordNum, transportRecordNum, offset, size, pcr, recordType)) { fTSRecordNum = transportRecordNum; fNPT = pcr; } } }
void MPEG2TransportStreamTrickModeFilter::onSourceClosure(void* clientData) { MPEG2TransportStreamTrickModeFilter* filter = (MPEG2TransportStreamTrickModeFilter*)clientData; filter->onSourceClosure1(); }
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 }