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); } }
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 }