Add even more of the source

This should be about everything needed to build so far?
This commit is contained in:
Darren VanBuren 2017-03-07 17:14:16 -08:00
parent af3619d4fa
commit 849723c9cf
547 changed files with 149239 additions and 0 deletions

View file

@ -0,0 +1,222 @@
/*
*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include <fcntl.h>
#ifndef __MacOSX__
#include "getopt.h"
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "QTRTPFile.h"
//extern char *optarg;
//extern int optind;
int main(int argc, char *argv[]) {
// Temporary vars
int ch;
struct timeval tp;
// General vars
bool Debug = false, DeepDebug = false;
const char *IPAddress;
const char *BasePort;
const char *MovieFilename;
int s;
QTRTPFile *RTPFile;
int CurPort;
Float64 StartTime;
extern int optind;
//
// Read our command line options
while( (ch = getopt(argc, argv, "dD")) != -1 ) {
switch( ch ) {
case 'd':
Debug = true;
break;
case 'D':
Debug = true;
DeepDebug = true;
break;
}
}
argc -= optind;
argv += optind;
//
// Validate our arguments.
if( argc < 4 ) {
qtss_printf("usage: QTBroadcaster <ip address> <baseport> <filename> <track#n> <track#n+1> ..\n");
exit(1);
}
IPAddress = *argv++; argc--;
BasePort = *argv++; argc--;
MovieFilename = *argv++; argc--;
//
// Open the movie.
RTPFile = new QTRTPFile(Debug, DeepDebug);
switch( RTPFile->Initialize(MovieFilename) ) {
case QTRTPFile::errNoError:
break;
case QTRTPFile::errFileNotFound:
qtss_printf("Error! File not found \"%s\"!\n", MovieFilename);
exit(1);
case QTRTPFile::errNoHintTracks:
qtss_printf("Error! No hint tracks \"%s\"!\n", MovieFilename);
exit(1);
case QTRTPFile::errInvalidQuickTimeFile:
qtss_printf("Error! Invalid movie file \"%s\"!\n", MovieFilename);
exit(1);
case QTRTPFile::errInternalError:
qtss_printf("Error! Internal error opening movie file \"%s\"!\n", MovieFilename);
exit(1);
case QTRTPFile::errTrackIDNotFound:
case QTRTPFile::errCallAgain:
//noops
break;
}
//
// Add the tracks that we're interested in.
CurPort = atoi(BasePort);
while(argc--) {
switch( RTPFile->AddTrack(atoi(*argv)) ) {
case QTRTPFile::errNoError:
case QTRTPFile::errTrackIDNotFound:
case QTRTPFile::errCallAgain:
break;
case QTRTPFile::errFileNotFound:
case QTRTPFile::errNoHintTracks:
case QTRTPFile::errInvalidQuickTimeFile:
case QTRTPFile::errInternalError:
qtss_printf("Error! Invalid movie file \"%s\"!\n", MovieFilename);
exit(1);
}
RTPFile->SetTrackCookies(atoi(*argv), NULL, (UInt32 )CurPort);
CurPort += 2;
(void)RTPFile->GetSeekTimestamp(atoi(*argv));
argv++;
}
//
// Create our socket to broadcast to.
s = socket(AF_INET, SOCK_DGRAM, 0);
if( s == -1 ) {
qtss_printf("Error! Couldn't create socket!\n");
exit(1);
}
//
// Seek to the beginning of the movie.
if( RTPFile->Seek(0.0) != QTRTPFile::errNoError ) {
qtss_printf("Error! Couldn't seek to time 0.0!\n");
exit(1);
}
//
// Send packets..
gettimeofday(&tp, NULL);
StartTime = tp.tv_sec + ((Float64)tp.tv_usec / 1000000);
while(1) {
// General vars
char *Packet;
int PacketLength;
//int Cookie;
Float64 SleepTime;
struct sockaddr_in sin;
//
// Get the next packet.
Float64 TransmitTime = RTPFile->GetNextPacket(&Packet, &PacketLength);
if( Packet == NULL )
break;
//
// Wait until it is time to send the packet.
gettimeofday(&tp, NULL);
SleepTime = tp.tv_sec + ((Float64)tp.tv_usec / 1000000);
SleepTime = (StartTime + TransmitTime) - SleepTime;
if( SleepTime > 0.0 ) {
qtss_printf("Sleeping for %.2f seconds (TransmitTime=%.2f).\n", SleepTime, TransmitTime);
usleep((unsigned int)(SleepTime * 1000000));
}
//
// Send the packet.
memset(&sin, 0, sizeof(struct sockaddr_in));
sin.sin_family = AF_INET;
UInt32 value = RTPFile->GetLastPacketTrack()->Cookie2;
in_port_t cookievalue = value;
sin.sin_port = htons( cookievalue );
sin.sin_addr.s_addr = inet_addr(IPAddress);
sendto(s, Packet, PacketLength, 0, (struct sockaddr *)&sin, sizeof(struct sockaddr));
}
//
// Close the socket.
close(s);
//
// Close our RTP file.
delete RTPFile;
return 0;
}

View file

@ -0,0 +1,129 @@
/*
*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <time.h>
#ifndef __MacOSX__
#include "getopt.h"
#include <unistd.h>
#endif
#include "QTFile.h"
#include "QTTrack.h"
#include "QTHintTrack.h"
int main(int argc, char *argv[]) {
// Temporary vars
int ch;
// General vars
QTTrack *Track;
bool Debug = false, DeepDebug = false;
extern int optind;
//
// Read our command line options
while( (ch = getopt(argc, argv, "dD")) != -1 ) {
switch( ch ) {
case 'd':
Debug = true;
break;
case 'D':
Debug = true;
DeepDebug = true;
break;
}
}
argc -= optind;
argv += optind;
//
// Validate our arguments.
if( argc != 1 ) {
qtss_printf("usage: QTFileInfo [-d] [-D] <filename>\n");
exit(1);
}
//
// Open the movie.
QTFile file(Debug, DeepDebug);
file.Open(*argv);
if(Debug) file.DumpAtomTOC();
//
// Print out some information.
qtss_printf("-- Movie %s \n", *argv);
qtss_printf(" Duration : %f\n", file.GetDurationInSeconds());
Track = NULL;
while( file.NextTrack(&Track, Track) ) {
// Temporary vars
QTHintTrack *HintTrack;
time_t unixCreationTime = (time_t)Track->GetCreationTime() + (time_t)QT_TIME_TO_LOCAL_TIME;
time_t unixModificationTime = (time_t)Track->GetModificationTime() + (time_t)QT_TIME_TO_LOCAL_TIME;
char buffer[kTimeStrSize];
struct tm timeResult;
//
// Initialize the track and dump it.
if( Track->Initialize() != QTTrack::errNoError ) {
qtss_printf("!!! Failed to initialize track !!!\n");
continue;
}
if(DeepDebug) Track->DumpTrack();
//
// Dump some info.
qtss_printf("-- Track #%02"_S32BITARG_" ---------------------------\n", Track->GetTrackID());
qtss_printf(" Name : %s\n", Track->GetTrackName());
qtss_printf(" Created on : %s", qtss_asctime(qtss_gmtime(&unixCreationTime, &timeResult), buffer, sizeof(buffer) ));
qtss_printf(" Modified on : %s", qtss_asctime(qtss_gmtime(&unixModificationTime, &timeResult), buffer, sizeof(buffer) ));
//
// Dump hint information is possible.
if( file.IsHintTrack(Track) ) {
HintTrack = (QTHintTrack *)Track;
qtss_printf(" Total RTP bytes : %"_64BITARG_"u\n", HintTrack->GetTotalRTPBytes());
qtss_printf(" Total RTP packets : %"_64BITARG_"u\n", HintTrack->GetTotalRTPPackets());
qtss_printf(" Average bitrate : %.2f Kbps\n", file.GetDurationInSeconds() == 0 ? 0.0 : ((HintTrack->GetTotalRTPBytes() << 3) / file.GetDurationInSeconds()) / 1024);
qtss_printf(" Average packet size: %"_64BITARG_"u\n", HintTrack->GetTotalRTPPackets() == 0 ? 0 : HintTrack->GetTotalRTPBytes() / HintTrack->GetTotalRTPPackets());
UInt32 UDPIPHeaderSize = (56 * HintTrack->GetTotalRTPPackets());
UInt32 RTPUDPIPHeaderSize = ((56+12) * HintTrack->GetTotalRTPPackets());
qtss_printf(" Percentage of stream wasted on UDP/IP headers : %.2f\n", HintTrack->GetTotalRTPBytes() == 0 ? 0 : (float)UDPIPHeaderSize / (float)(HintTrack->GetTotalRTPBytes() + UDPIPHeaderSize) * 100);
qtss_printf(" Percentage of stream wasted on RTP/UDP/IP headers: %.2f\n", HintTrack->GetTotalRTPBytes() == 0 ? 0 : (float)RTPUDPIPHeaderSize / (float)(HintTrack->GetTotalRTPBytes() + RTPUDPIPHeaderSize) * 100);
}
}
return 0;
}

View file

@ -0,0 +1,44 @@
/*
*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include "QTFile.h"
int main(int /*argc*/, char *argv[]) {
// Validate
if( argv[1] == NULL )
{
qtss_printf("usage: QTFileTest <filename>\n");
exit(1);
}
QTFile file(true, true);
file.Open(argv[1]);
file.DumpAtomTOC();
return 0;
}

View file

@ -0,0 +1,368 @@
/*
*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include <fcntl.h>
#ifndef __MacOSX__
#include "getopt.h"
#include <unistd.h>
#endif
#include "OS.h"
#include "QTRTPFile.h"
int main(int argc, char *argv[]) {
// Temporary vars
int ch = '\0';
// General vars
int fd = -1;
const char *MovieFilename;
QTRTPFile *RTPFile = NULL;
bool Debug = false, DeepDebug = false;
bool silent = false;
bool trackCache= false;
bool everytrack= false;
bool hintOnly = false;
bool keyFramesOnly = false;
extern int optind;
QTRTPFile::RTPTrackListEntry *trackListEntry = NULL;
//
// Read our command line options
while( (ch = getopt(argc, argv, "dDhsetk")) != -1 ) {
switch( ch ) {
case 'e':
everytrack = true;
break;
case 's':
silent = true;
break;
case 't':
trackCache = true;
break;
case 'h':
hintOnly = true;
break;
case 'd':
Debug = true;
break;
case 'D':
Debug = true;
DeepDebug = true;
break;
case 'k':
keyFramesOnly = true;
break;
}
}
argc -= optind;
argv += optind;
//
// Validate our arguments.
if( argc < 1 ) {
qtss_printf("usage: QTRTPFileTest <filename> <track#n> <track#n+1> ..\n");
qtss_printf("usage: -s no packet printfs\n");
qtss_printf("usage: -e test every hint track\n");
qtss_printf("usage: -k list only packets belonging to key frames. Specify a single video track with this option\n");
qtss_printf("usage: -t write packets to track.cache file\n");
qtss_printf("usage: -h show hinted (.unopt, .opt)\n");
exit(1);
}
MovieFilename = *argv++;
argc--;
if (!hintOnly)
qtss_printf("****************** QTRTPFileTest ******************\n");
//
// Open the movie.
RTPFile = new QTRTPFile(Debug, DeepDebug);
switch( RTPFile->Initialize(MovieFilename) ) {
case QTRTPFile::errNoError:
case QTRTPFile::errNoHintTracks:
break;
case QTRTPFile::errFileNotFound:
qtss_printf("Error! File not found \"%s\"!\n", MovieFilename);
exit(1);
case QTRTPFile::errInvalidQuickTimeFile:
qtss_printf("Error! Invalid movie file \"%s\"!\n", MovieFilename);
exit(1);
case QTRTPFile::errInternalError:
qtss_printf("Error! Internal error opening movie file \"%s\"!\n", MovieFilename);
exit(1);
case QTRTPFile::errTrackIDNotFound:
case QTRTPFile::errCallAgain:
//noops
break;
}
//
// Get the SDP file and print it out.
char *SDPFile;
int SDPFileLength;
{
//
// Get the file
SDPFile = RTPFile->GetSDPFile(&SDPFileLength);
if( SDPFile == NULL ) {
qtss_printf("Error! Could not get SDP file!\n");
exit(1);
}
if (!hintOnly)
{
write(1, SDPFile, SDPFileLength);
write(1, "\n", 1);
}
}
//
// Open our file to write the packets out to.
if (trackCache)
{
fd = open("track.cache", O_CREAT | O_TRUNC | O_WRONLY, 0664);
if( fd == -1 ) {
qtss_printf("Error! Could not create output file!\n");
exit(1);
}
}
if (everytrack || hintOnly)
{
int trackcount = 0;
int hinttracks[20];
memset(&hinttracks,0,sizeof(hinttracks));
bool found = false;
char *trackPtr = SDPFile;
while (true)
{
trackPtr = ::strstr(trackPtr,"trackID=");
if (trackPtr != NULL)
{ trackPtr+= ::strlen("trackID=");
sscanf(trackPtr, "%d",&hinttracks[trackcount]);
trackcount++;
found = true;
}
else
break;
}
while (trackcount)
{
switch( RTPFile->AddTrack(hinttracks[trackcount -1]) ) {
case QTRTPFile::errNoError:
case QTRTPFile::errNoHintTracks:
break;
case QTRTPFile::errFileNotFound:
case QTRTPFile::errInvalidQuickTimeFile:
case QTRTPFile::errInternalError:
qtss_printf("Error! Invalid movie file \"%s\"!\n", MovieFilename);
exit(1);
case QTRTPFile::errTrackIDNotFound:
case QTRTPFile::errCallAgain:
//noops
break;
}
RTPFile->SetTrackCookies(hinttracks[trackcount], (char *)hinttracks[trackcount], 0);
(void)RTPFile->GetSeekTimestamp(hinttracks[trackcount]);
trackcount --;
}
}
else
{
//
// Add the tracks that we're interested in.
while(argc--) {
switch( RTPFile->AddTrack(atoi(*argv)) ) {
case QTRTPFile::errNoError:
case QTRTPFile::errNoHintTracks:
case QTRTPFile::errTrackIDNotFound:
case QTRTPFile::errCallAgain:
break;
case QTRTPFile::errFileNotFound:
case QTRTPFile::errInvalidQuickTimeFile:
case QTRTPFile::errInternalError:
qtss_printf("Error! Invalid movie file \"%s\"!\n", MovieFilename);
exit(1);
}
RTPFile->FindTrackEntry(atoi(*argv), &trackListEntry);
RTPFile->SetTrackCookies(atoi(*argv), (char *)atoi(*argv), 0);
(void)RTPFile->GetSeekTimestamp(atoi(*argv));
argv++;
}
}
//
// Display some stats about the movie.
if (!hintOnly)
qtss_printf("Total RTP bytes of all added tracks: %"_64BITARG_"u\n", RTPFile->GetAddedTracksRTPBytes());
//
// Seek to the beginning of the movie.
if( RTPFile->Seek(0.0) != QTRTPFile::errNoError ) {
qtss_printf("Error! Couldn't seek to time 0.0!\n");
exit(1);
}
//
// Suck down packets..
UInt32 NumberOfPackets = 0;
Float64 TotalInterpacketDelay = 0.0,
LastPacketTime = 0.0;
SInt64 startTime = 0;
SInt64 durationTime = 0;
SInt64 packetCount = 0;
while(1)
{
// Temporary vars
UInt16 tempInt16;
// General vars
char *Packet;
int PacketLength;
//SInt32 Cookie;
UInt32 RTPTimestamp;
UInt16 RTPSequenceNumber;
int maxHintPackets = 100; // cheat assume this many packets is good enough to assume entire file is the same at these packets
//
// Get the next packet.
startTime = OS::Milliseconds();
if (keyFramesOnly)
RTPFile->SetTrackQualityLevel(trackListEntry, QTRTPFile::kKeyFramesOnly);
Float64 TransmitTime = RTPFile->GetNextPacket(&Packet, &PacketLength);
SInt64 thisDuration = OS::Milliseconds() - startTime;
durationTime += thisDuration;
packetCount++;
if( Packet == NULL )
break;
if (hintOnly)
{ if (--maxHintPackets == 0 )
break;
continue;
}
memcpy(&RTPSequenceNumber, Packet + 2, 2);
RTPSequenceNumber = ntohs(RTPSequenceNumber);
memcpy(&RTPTimestamp, Packet + 4, 4);
RTPTimestamp = ntohl(RTPTimestamp);
if (!hintOnly)
if (!silent)
qtss_printf("TransmitTime = %.2f; SEQ = %u; TS = %"_U32BITARG_"\n", TransmitTime, RTPSequenceNumber, RTPTimestamp);
if (trackCache)
{
//
// Write out the packet header.
write(fd, (char *)&TransmitTime, 8); // transmitTime
tempInt16 = PacketLength;
write(fd, (char *)&tempInt16, 2); // packetLength
tempInt16 = 0;
write(fd, (char *)&tempInt16, 2); // padding1
//
// Write out the packet.
write(fd, Packet, PacketLength);
}
//
// Compute the Inter-packet delay and keep track of it.
if( TransmitTime >= LastPacketTime ) {
TotalInterpacketDelay += TransmitTime - LastPacketTime;
LastPacketTime = TransmitTime;
NumberOfPackets++;
}
}
//
// Compute and display the Inter-packet delay.
if( (!hintOnly) && NumberOfPackets > 0 )
{
qtss_printf("QTRTPFileTest: Total GetNextPacket durationTime = %"_U32BITARG_"ms packetCount= %"_U32BITARG_"\n",(UInt32)durationTime,(UInt32)packetCount);
qtss_printf("QTRTPFileTest: Average Inter-packet delay: %"_64BITARG_"uus\n", (UInt64)((TotalInterpacketDelay / NumberOfPackets) * 1000 * 1000));
}
SInt32 hintType = RTPFile->GetMovieHintType(); // this can only be reliably called after playing all the packets.
if (!hintOnly)
{
if (hintType < 0)
qtss_printf("QTRTPFileTest: HintType=Optimized\n");
else if (hintType > 0)
qtss_printf("QTRTPFileTest: HintType=Unoptimized\n");
else
qtss_printf("QTRTPFileTest: HintType=Unknown\n");
}
else
{
if (hintType < 0)
qtss_printf("%s.opt\n",MovieFilename);
else if (hintType > 0)
qtss_printf("%s.unopt\n",MovieFilename);
else
qtss_printf("%s\n",MovieFilename);
}
if (trackCache)
{ //
// Close the output file.
close(fd);
}
//
// Close our RTP file.
delete RTPFile;
return 0;
}

View file

@ -0,0 +1,218 @@
/*
*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include <time.h>
#include <fcntl.h>
#ifndef __MacOSX__
#include "getopt.h"
#include <unistd.h>
#endif
#include "QTFile.h"
#include "QTTrack.h"
#include "QTHintTrack.h"
int main(int argc, char *argv[]) {
// Temporary vars
int ch;
UInt16 tempInt16;
UInt32 tempInt32;
Float32 tempFloat32;
Float64 tempFloat64;
// General vars
int fd;
const char *MovieFilename;
int TrackNumber;
QTTrack *Track;
QTHintTrack *HintTrack;
bool Debug = false, DeepDebug = false;
UInt16 NumPackets;
extern int optind;
//
// Read our command line options
while( (ch = getopt(argc, argv, "dD")) != -1 ) {
switch( ch ) {
case 'd':
Debug = true;
break;
case 'D':
Debug = true;
DeepDebug = true;
break;
}
}
argc -= optind;
argv += optind;
//
// Validate our arguments.
if( argc != 2 ) {
qtss_printf("usage: QTRTPGen [-d] [-D] <filename> <track number>\n");
exit(1);
}
MovieFilename = *argv++;
TrackNumber = atoi(*argv++);
//
// Open the movie.
QTFile file(Debug, DeepDebug);
file.Open(MovieFilename);
//
// Find the specified track and dump out information about its' samples.
if( !file.FindTrack(TrackNumber, &Track) ) {
qtss_printf("Error! Could not find track number %d in file \"%s\"!",
TrackNumber, MovieFilename);
exit(1);
}
//
// Make sure that this is a hint track.
if( !file.IsHintTrack(Track) ) {
qtss_printf("Error! Track number %d is not a hint track!\n", TrackNumber);
exit(1);
}
HintTrack = (QTHintTrack *)Track;
//
// Initialize this track.
HintTrack->Initialize();
//
// Dump some information about this track.
{
time_t unixCreationTime = (time_t)HintTrack->GetCreationTime() + (time_t)QT_TIME_TO_LOCAL_TIME;
time_t unixModificationTime = (time_t)HintTrack->GetModificationTime() + (time_t)QT_TIME_TO_LOCAL_TIME;
char buffer[kTimeStrSize];
struct tm timeResult;
qtss_printf("-- Track #%02"_S32BITARG_" ---------------------------\n", HintTrack->GetTrackID());
qtss_printf(" Name : %s\n", HintTrack->GetTrackName());
qtss_printf(" Created on : %s", qtss_asctime(qtss_gmtime(&unixCreationTime, &timeResult),buffer, sizeof(buffer)));
qtss_printf(" Modified on : %s", qtss_asctime(qtss_gmtime(&unixModificationTime, &timeResult),buffer, sizeof(buffer)));
qtss_printf(" Total RTP bytes : %"_64BITARG_"u\n", HintTrack->GetTotalRTPBytes());
qtss_printf(" Total RTP packets : %"_64BITARG_"u\n", HintTrack->GetTotalRTPPackets());
qtss_printf(" Average bitrate : %.2f Kbps\n",(float) ((HintTrack->GetTotalRTPBytes() << 3) / file.GetDurationInSeconds()) / 1024);
qtss_printf(" Average packet size: %"_64BITARG_"u\n", HintTrack->GetTotalRTPBytes() / HintTrack->GetTotalRTPPackets());
UInt32 UDPIPHeaderSize = (56 * HintTrack->GetTotalRTPPackets());
UInt32 RTPUDPIPHeaderSize = ((56+12) * HintTrack->GetTotalRTPPackets());
qtss_printf(" Percentage of stream wasted on UDP/IP headers : %.2f\n", (float)UDPIPHeaderSize / (float)(HintTrack->GetTotalRTPBytes() + UDPIPHeaderSize) * 100);
qtss_printf(" Percentage of stream wasted on RTP/UDP/IP headers: %.2f\n", (float)RTPUDPIPHeaderSize / (float)(HintTrack->GetTotalRTPBytes() + RTPUDPIPHeaderSize) * 100);
qtss_printf("\n");
qtss_printf("\n");
}
//
// Open our file to write the packets out to.
fd = open("track.cache", O_CREAT | O_TRUNC | O_WRONLY, 0666);
if( fd == -1 ) {
qtss_printf("Error! Could not create output file!\n");
exit(1);
}
//
// Write out the header.
tempInt16 = 1;
write(fd, (char *)&tempInt16, 2); // isCompletelyWritten
tempInt16 = 0;
write(fd, (char *)&tempInt16, 2); // padding1
tempFloat64 = file.GetDurationInSeconds();
write(fd, (char *)&tempFloat64, 8); // movieLength
tempInt32 = HintTrack->GetRTPTimescale();
write(fd, (char *)&tempInt32, 4); // rtpTimescale
tempInt16 = HintTrack->GetRTPSequenceNumberRandomOffset();
write(fd, (char *)&tempInt16, 2); // seqNumRandomOffset
tempInt16 = 0;
write(fd, (char *)&tempInt16, 2); // padding2
tempFloat32 = HintTrack->GetTotalRTPBytes() / file.GetDurationInSeconds();
write(fd, (char *)&tempFloat32, 4); // dataRate
//
// Go through all of the samples in this track, printing out their offsets
// and sizes.
qtss_printf("Sample # NPkts\n");
qtss_printf("-------- -----\n");
UInt32 curSample = 1;
QTHintTrack_HintTrackControlBlock HCB;
while( HintTrack->GetNumPackets(curSample, &NumPackets) == QTTrack::errNoError ) {
//
// Generate all of the packets.
qtss_printf("Generating %u packet(s) in sample #%"_U32BITARG_"..\n", NumPackets, curSample);
for( UInt16 curPacket = 1; curPacket <= NumPackets; curPacket++ ) {
// General vars
#define MAX_PACKET_LEN 2048
char Packet[MAX_PACKET_LEN];
UInt32 PacketLength;
Float64 TransmitTime;
//
// Generate this packet.
PacketLength = MAX_PACKET_LEN;
HintTrack->GetPacket(curSample, curPacket,
Packet, &PacketLength,
&TransmitTime, false, false, 0,&HCB);
//
// Write out the packet header.
write(fd, (char *)&TransmitTime, 8); // transmitTime
tempInt16 = PacketLength;
write(fd, (char *)&tempInt16, 2); // packetLength
tempInt16 = 0;
write(fd, (char *)&tempInt16, 2); // padding1
//
// Write out the packet.
write(fd, Packet, PacketLength);
}
//
// Next sample.
curSample++;
}
//
// Close the output file.
close(fd);
return 0;
}

View file

@ -0,0 +1,148 @@
/*
*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <fcntl.h>
#ifndef __MacOSX__
#include "getopt.h"
#include <unistd.h>
#endif
#include "QTRTPFile.h"
int main(int argc, char *argv[]) {
// Temporary vars
int ch;
// General vars
const char *MovieFilename;
const char *OutputFilename = NULL;
QTRTPFile *RTPFile;
bool Debug = false, DeepDebug = false;
extern char* optarg;
extern int optind;
//
// Read our command line options
while( (ch = getopt(argc, argv, "dD")) != -1 ) {
switch( ch ) {
case 'd':
Debug = true;
break;
case 'D':
Debug = true;
DeepDebug = true;
break;
case 'f':
OutputFilename = optarg;
break;
}
}
argc -= optind;
argv += optind;
//
// Validate our arguments.
if( argc < 1 ) {
qtss_printf("usage: QTSDPGen <filename[s]>\n");
exit(1);
}
//MovieFilename = *argv++;
while ((MovieFilename = *argv++) != NULL)
{
//
// Open the movie.
RTPFile = new QTRTPFile();
if( RTPFile->Initialize(MovieFilename) != QTRTPFile::errNoError ) {
qtss_printf("Error! Could not open movie file \"%s\"!\n", MovieFilename);
continue;
//exit(1);
}
//
// Get the SDP file and write it out.
{
// General vars
char *SDPFile;
int SDPFileLength;
int fdsdp;
char SDPFilename[255 + 1];
//
// Get the file
SDPFile = RTPFile->GetSDPFile(&SDPFileLength);
if( SDPFile == NULL ) {
qtss_printf("Error! Could not get SDP file!\n");
continue;
//exit(1);
}
//
// Create our SDP file and write out the data
if( OutputFilename == NULL ) {
fdsdp = STDOUT_FILENO;
} else {
qtss_sprintf(SDPFilename, "%s.sdp", MovieFilename);
fdsdp = open(SDPFilename, O_CREAT | O_TRUNC | O_WRONLY, 0664);
if( fdsdp == -1 ) {
qtss_printf("Error! Could not create SDP file \"%s\"!\n", SDPFilename);
continue;
//exit(1);
}
}
qtss_printf("\n--%s--\n", MovieFilename);
write(fdsdp, SDPFile, SDPFileLength);
qtss_printf("\n");
if( OutputFilename != NULL )
close(fdsdp);
}
//
// Close our RTP file.
delete RTPFile;
}
return 0;
}

View file

@ -0,0 +1,156 @@
/*
*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include <time.h>
#ifndef __MacOSX__
#include "getopt.h"
#include <unistd.h>
#endif
#include "QTFile.h"
#include "QTTrack.h"
int main(int argc, char *argv[]) {
// Temporary vars
int ch;
// General vars
const char *MovieFilename;
int TrackNumber;
QTTrack *Track;
bool Debug = false, DeepDebug = false,
DumpHTML = false;
UInt64 Offset;
UInt32 Size, MediaTime;
extern int optind;
//
// Read our command line options
while( (ch = getopt(argc, argv, "dDH")) != -1 ) {
switch( ch ) {
case 'd':
Debug = true;
break;
case 'D':
Debug = true;
DeepDebug = true;
break;
case 'H':
DumpHTML = true;
break;
}
}
argc -= optind;
argv += optind;
//
// Validate our arguments.
if( argc != 2 ) {
qtss_printf("usage: QTSampleLister [-d] [-D] [-H] <filename> <track number>\n");
exit(1);
}
MovieFilename = *argv++;
TrackNumber = atoi(*argv++);
//
// Open the movie.
QTFile file(Debug, DeepDebug);
file.Open(MovieFilename);
//
// Find the specified track and dump out information about its' samples.
if( !file.FindTrack(TrackNumber, &Track) ) {
qtss_printf("Error! Could not find track number %d in file \"%s\"!",
TrackNumber, MovieFilename);
exit(1);
}
//
// Initialize the track.
if( Track->Initialize() != QTTrack::errNoError){
qtss_printf("Error! Failed to initialize track %d in file \"%s\"!\n",
TrackNumber, MovieFilename);
exit(1);
}
//
// Dump some information about this track.
if( !DumpHTML ) {
time_t unixCreationTime = (time_t)Track->GetCreationTime() + (time_t)QT_TIME_TO_LOCAL_TIME;
time_t unixModificationTime = (time_t)Track->GetModificationTime() + (time_t)QT_TIME_TO_LOCAL_TIME;
char buffer[kTimeStrSize];
struct tm timeResult;
qtss_printf("-- Track #%02"_S32BITARG_" ---------------------------\n", Track->GetTrackID());
qtss_printf(" Name : %s\n", Track->GetTrackName());
qtss_printf(" Created on : %s", qtss_asctime(qtss_gmtime(&unixCreationTime, &timeResult),buffer, sizeof(buffer)));
qtss_printf(" Modified on : %s", qtss_asctime(qtss_gmtime(&unixModificationTime, &timeResult),buffer, sizeof(buffer)));
qtss_printf("\n");
qtss_printf("\n");
}
//
// Go through all of the samples in this track, printing out their offsets
// and sizes.
if( !DumpHTML ) {
qtss_printf("Sample # Media Time DataOffset SampleSize\n");
qtss_printf("-------- ---------- ---------- ----------\n");
}
UInt32 curSample = 1;
QTAtom_stsc_SampleTableControlBlock stsc;
QTAtom_stts_SampleTableControlBlock stts;
while( Track->GetSampleInfo(curSample, &Size, &Offset, NULL, &stsc) ) {
//
// Get some additional information about this sample.
Track->GetSampleMediaTime(curSample, &MediaTime, &stts);
//
// Dump out the sample.
if( DumpHTML )
qtss_printf("<FONT COLOR=black>%010"_64BITARG_"u: track=%02"_U32BITARG_"; size=%"_U32BITARG_"</FONT><BR>\n",Offset, Track->GetTrackID(), Size);
else
qtss_printf("%8"_U32BITARG_" - %10"_U32BITARG_" %10"_64BITARG_"u %10"_U32BITARG_"\n", curSample, MediaTime, Offset, Size);
// Next sample.
curSample++;
}
return 0;
}

View file

@ -0,0 +1,168 @@
/*
*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*
*/
/*
*/
#include <stdio.h>
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include <time.h>
#ifndef __MacOSX__
#include "getopt.h"
#include <unistd.h>
#endif
#include "QTFile.h"
#include "QTTrack.h"
#include "QTHintTrack.h"
int main(int argc, char *argv[]) {
// Temporary vars
int ch;
// General vars
const char *MovieFilename;
int TrackNumber;
QTTrack *Track;
QTHintTrack *HintTrack;
bool Debug = false, DeepDebug = false;
char *Table = NULL;
extern char* optarg;
extern int optind;
//
// Read our command line options
while( (ch = getopt(argc, argv, "dDT:")) != -1 ) {
switch( ch ) {
case 'd':
Debug = true;
break;
case 'D':
Debug = true;
DeepDebug = true;
break;
case 'T':
Table = strdup(optarg);
break;
}
}
argc -= optind;
argv += optind;
//
// Validate our arguments.
if( argc != 2 ) {
qtss_printf("usage: QTTrackInfo [-d] [-D] [-T <table name>]<filename> <track number>\n");
exit(1);
}
MovieFilename = *argv++;
TrackNumber = atoi(*argv++);
//
// Open the movie.
QTFile file(Debug, DeepDebug);
file.Open(MovieFilename);
//
// Find the specified track and dump out information about its' samples.
if( !file.FindTrack(TrackNumber, &Track) ) {
qtss_printf("Error! Could not find track number %d in file \"%s\"!",
TrackNumber, MovieFilename);
exit(1);
}
//
// Initialize the track.
if( Track->Initialize() != QTTrack::errNoError ) {
qtss_printf("Error! Failed to initialize track %d in file \"%s\"!\n",
TrackNumber, MovieFilename);
exit(1);
}
//
// Dump some information about this track.
{
time_t unixCreationTime = (time_t)Track->GetCreationTime() + (time_t)QT_TIME_TO_LOCAL_TIME;
time_t unixModificationTime = (time_t)Track->GetModificationTime() + (time_t)QT_TIME_TO_LOCAL_TIME;
char buffer[kTimeStrSize];
struct tm timeResult;
qtss_printf("-- Track #%02"_S32BITARG_" ---------------------------\n", Track->GetTrackID());
qtss_printf(" Name : %s\n", Track->GetTrackName());
qtss_printf(" Created on : %s", qtss_asctime(qtss_gmtime(&unixCreationTime, &timeResult),buffer, sizeof(buffer)));
qtss_printf(" Modified on : %s", qtss_asctime(qtss_gmtime(&unixModificationTime, &timeResult),buffer, sizeof(buffer)));
//
// Dump hint information is possible.
if( file.IsHintTrack(Track) ) {
HintTrack = (QTHintTrack *)Track;
qtss_printf(" Total RTP bytes : %"_64BITARG_"u\n", HintTrack->GetTotalRTPBytes());
qtss_printf(" Total RTP packets : %"_64BITARG_"u\n", HintTrack->GetTotalRTPPackets());
qtss_printf(" Average bitrate : %.2f Kbps\n", ((HintTrack->GetTotalRTPBytes() << 3) / file.GetDurationInSeconds()) / 1024);
qtss_printf(" Average packet size: %"_64BITARG_"u\n", HintTrack->GetTotalRTPBytes() / HintTrack->GetTotalRTPPackets());
UInt32 UDPIPHeaderSize = (UInt32) (56 * HintTrack->GetTotalRTPPackets());
UInt32 RTPUDPIPHeaderSize = (UInt32) ((56+12) * HintTrack->GetTotalRTPPackets());
qtss_printf(" Percentage of stream wasted on UDP/IP headers : %.2f\n", (float)UDPIPHeaderSize / (float)(HintTrack->GetTotalRTPBytes() + UDPIPHeaderSize) * 100);
qtss_printf(" Percentage of stream wasted on RTP/UDP/IP headers: %.2f\n", (float)RTPUDPIPHeaderSize / (float)(HintTrack->GetTotalRTPBytes() + RTPUDPIPHeaderSize) * 100);
}
qtss_printf("\n");
qtss_printf("\n");
}
//
// Dump all of the entries in the specified table (if we were given one).
// Go through all of the samples in this track, printing out their offsets
// and sizes.
if( Table != NULL ) {
if( (strcmp(Table, "stco") == 0) || (strcmp(Table, "co64") == 0) ) {
Track->DumpChunkOffsetTable();
} else if( strcmp(Table, "stsc") == 0 ) {
Track->DumpSampleToChunkTable();
} else if( strcmp(Table, "stsz") == 0 ) {
Track->DumpSampleSizeTable();
} else if( strcmp(Table, "stts") == 0 ) {
Track->DumpTimeToSampleTable();
} else if( strcmp(Table, "ctts") == 0 ) {
Track->DumpCompTimeToSampleTable();
}
}
return 0;
}

View file

@ -0,0 +1,91 @@
/*
*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*
*/
/*
This file defines a good file format to use for storing RTP streams.
It is optimized for linear reads through the file, but also allows for
seeking using a "Block Map", similar to a QuickTime sample table but more
compressed.
RTP PACKET FILE FORMAT DEFINITION:
1 RTPFileHeader
__ SDP DATA __
1 RTPFileTrackInfo per track
__ BLOCK MAP__
packet, packet, packet
Each packet is:
1 RTPFilePacket, followed by data
No partial packets allowed between blocks, blocks should finish with a pad packet
*/
#ifndef __RTP_FILE_DEFS__
#define __RTP_FILE_DEFS__
#include "OSHeaders.h"
#define RTP_FILE_CURRENT_VERSION 0
typedef struct RTPFileHeader
{
UInt32 fVersion; // Version 0
Float64 fMovieDuration;
UInt32 fSDPLen;
UInt32 fNumTracks;
UInt32 fMaxTrackID;
UInt32 fBlockMapSize;
UInt32 fDataStartPos;
} RTPFileHeader;
typedef struct RTPFileTrackInfo
{
UInt32 fID;
UInt32 fTimescale;
UInt64 fBytesInTrack;
Float64 fDuration;
} RTPFileTrackInfo;
typedef struct RTPFilePacket
{
UInt16 fTrackID;
UInt16 fPacketLength;
Float64 fTransmitTime;
} RTPFilePacket;
static const UInt32 kBlockSize = 32768;
static const UInt32 kBlockMask = 0xFFF8000;
static const UInt16 kPaddingBit = 0x8000;
#endif //__RTP_FILE_DEFS__

View file

@ -0,0 +1,322 @@
/*
*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*
*/
#include <stdlib.h>
#include "SafeStdLib.h"
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifndef __MacOSX__
#include "getopt.h"
#include <unistd.h>
#endif
#include "RTPFileDefs.h"
#include "QTRTPFile.h"
#include "QTHintTrack.h"
#include "OSHeaders.h"
class QTRTPGenFile : public QTRTPFile
{
public:
QTRTPGenFile() : QTRTPFile() {}
virtual ~QTRTPGenFile() {}
// Accessors
UInt32 GetNumHintTracks() { return fNumHintTracks; }
RTPTrackListEntry* GetFirstTrack() { return fFirstTrack; }
};
UInt8* WriteTempFile(QTRTPFile* inQTRTPFile, int inTempFile, UInt32* outNumBlocks);
int main(int argc, char *argv[])
{
if (argc <= 1)
{
qtss_printf("Usage: rtpfilegen *hintedqtfilename*\n");
exit(0);
}
char* theFileName = argv[1];
QTRTPFile::Initialize();
// Init our qt file
QTRTPGenFile theFile;
QTRTPFile::ErrorCode initErr = theFile.Initialize(theFileName);
switch (initErr)
{
case QTRTPFile::errFileNotFound:
qtss_printf("Movie file not found\n"); exit(0);
case QTRTPFile::errInvalidQuickTimeFile:
qtss_printf("File is not a hinted quicktime file\n"); exit(0);
case QTRTPFile::errNoHintTracks:
qtss_printf("File has no hint tracks\n"); exit(0);
case QTRTPFile::errInternalError:
qtss_printf("Internal error\n"); exit(0);
case QTRTPFile::errNoError:
case QTRTPFile::errTrackIDNotFound:
case QTRTPFile::errCallAgain:
//noops
break;
}
// Open our output file
char* outputFileName = new char[::strlen(theFileName) + 5];
::strcpy(outputFileName, theFileName);
::strcat(outputFileName, ".rtp");
int theOutFile = open(outputFileName, O_WRONLY | O_CREAT | O_TRUNC);
if (theOutFile == -1)
{ qtss_printf("Failed to open output file at %s.\n", outputFileName); exit(0); }
// Open a temp file
char* tempFileName = new char[::strlen(theFileName) + 6];
::strcpy(tempFileName, theFileName);
::strcat(tempFileName, ".temp");
int theTempFile = open(tempFileName, O_WRONLY | O_CREAT | O_TRUNC);
if (theTempFile == -1)
{ qtss_printf("Failed to open temp file at %s.\n", tempFileName); exit(0); }
// Setup all our tracks
UInt32 theMaxTrackID = 0; // These variables are needed to write the file header
UInt32 theNumTracks = 0;
QTRTPFile::RTPTrackListEntry* curTrack = theFile.GetFirstTrack();
while (curTrack != NULL)
{
if (theMaxTrackID < curTrack->TrackID)
theMaxTrackID = curTrack->TrackID;
theNumTracks++;
(void)theFile.AddTrack(curTrack->TrackID);
// Make the cookie be the track ID, so we know what the track ID is when
// we are retreiving packets
theFile.SetTrackCookies(curTrack->TrackID, (void*) NULL, curTrack->TrackID);
curTrack = curTrack->NextTrack;
}
// Seek to time 0
(void)theFile.Seek(0);
// Write status
qtss_printf("Generating RTP packets to temp file at %s...\n", tempFileName);
// Write out all the packets to the temp file
UInt32 theNumBlocks = 0;
UInt8* theBlockArray = WriteTempFile(&theFile, theTempFile, &theNumBlocks);
::close(theTempFile);
// Write status
qtss_printf("Generating RTP file at %s. Copying packets...\n", outputFileName);
// Get SDP
int theSDPLen = 0;
char* theSDPFile = theFile.GetSDPFile(&theSDPLen);
// Write file header
RTPFileHeader theHeader;
theHeader.fSDPLen = theSDPLen;
theHeader.fNumTracks = theFile.GetNumHintTracks();
theHeader.fMaxTrackID = theMaxTrackID;
theHeader.fBlockMapSize = theNumBlocks;
theHeader.fDataStartPos = theNumBlocks + theSDPLen + sizeof(RTPFileHeader) +
(sizeof(RTPFileTrackInfo) * theNumTracks);
theHeader.fMovieDuration = theFile.GetMovieDuration();
int theErr = ::write(theOutFile, &theHeader, sizeof(theHeader));
if (theErr != sizeof(theHeader))
{ qtss_printf("Write operation failed on output file\n"); exit(0); }
// Write the SDP data
theErr = ::write(theOutFile, theSDPFile, theSDPLen);
if (theErr != theSDPLen)
{ qtss_printf("Write operation failed on output file\n"); exit(0); }
// Write track info
curTrack = theFile.GetFirstTrack();
while (curTrack != NULL)
{
RTPFileTrackInfo theTrackInfo;
theTrackInfo.fID = curTrack->TrackID;
theTrackInfo.fTimescale = curTrack->HintTrack->GetRTPTimescale();
theTrackInfo.fBytesInTrack = curTrack->HintTrack->GetTotalRTPBytes();
theTrackInfo.fDuration = curTrack->HintTrack->GetDurationInSeconds();
theErr = ::write(theOutFile, &theTrackInfo, sizeof(theTrackInfo));
if (theErr != sizeof(theTrackInfo))
{ qtss_printf("Write operation failed on output file\n"); exit(0); }
curTrack = curTrack->NextTrack;
}
// Write the block map
UInt32 numWritten = ::write(theOutFile, theBlockArray, theNumBlocks);
if (numWritten != theNumBlocks)
{ qtss_printf("Write operation failed on output file\n"); exit(0); }
//Copy the temp file into the out file
theTempFile = open(tempFileName, O_RDONLY);
if (theTempFile == -1)
{ qtss_printf("Failed to open temp file for reading at %s.\n", tempFileName); exit(0); }
while (true)
{
char copyBuffer[kBlockSize];
// Read a block out of the temp file
theErr = ::read(theTempFile, &copyBuffer[0], kBlockSize);
if (theErr <= 0)
break;
int lenWritten = ::write(theOutFile, &copyBuffer[0], theErr);
if (theErr != lenWritten)
{ qtss_printf("Write operation failed on output file\n"); exit(0); }
}
qtss_printf("RTP file generation complete\n");
// Delete the temp file
(void)::unlink(tempFileName);
// close the output file
::close(theOutFile);
// We're done!
}
// Returns the complete block map
UInt8* WriteTempFile(QTRTPFile* inQTRTPFile, int inTempFile, UInt32* outNumBlocks)
{
int theErr = -1;
UInt32 theNumPackets = 0;
// Write all packets to the temp file. Pad out blocks appropriately
UInt32 offsetInBlock = 0;
// As we write out packets, build our block map
UInt8* theBlockMap = new UInt8[1024];
UInt32 curBlockMapSize = 1024;
UInt32 curBlockMapIndex = 0;
Float64 theLastBlockTime = 0;
while (true)
{
RTPFilePacket thePacketHeader;
char* thePacketData = NULL;
int thePacketLength = 0;
thePacketHeader.fTransmitTime = inQTRTPFile->GetNextPacket(&thePacketData, &thePacketLength);
if (thePacketData == NULL)
// We're done with all tracks
break;
thePacketHeader.fPacketLength = thePacketLength;
thePacketHeader.fTrackID = inQTRTPFile->GetLastPacketTrack()->Cookie2;
// Make sure there is enough room in the current block for this
// packet plus a header for the next packet. If not, move onto the next block
if ((offsetInBlock + thePacketHeader.fPacketLength + (2 * sizeof(RTPFilePacket))) > kBlockSize)
{
// Write out a pad packet
RTPFilePacket pad;
pad.fTrackID |= kPaddingBit;
theErr = ::write(inTempFile, &pad, sizeof(pad));
if (theErr < (int) sizeof(pad))
{ qtss_printf("Write operation failed on temp file\n"); exit(0); }
offsetInBlock += sizeof(pad);
SInt32 spaceRemaining = kBlockSize - offsetInBlock;
Assert(spaceRemaining >= 0);
// Fill out the rest of this block with crap
char* dumpBuf = new char[spaceRemaining];
::memset(dumpBuf, 0xFF, spaceRemaining);//Fill with FFs so we can debug easier
theErr = ::write(inTempFile, dumpBuf, spaceRemaining);
if (theErr < spaceRemaining)
{ qtss_printf("Write operation failed on temp file\n"); exit(0); }
delete [] dumpBuf;
offsetInBlock = 0;
}
// If this is the first packet in a block, we should mark the time in the
// Write the packet header and the packet data
if (offsetInBlock == 0)
{
// What is the offset between the first packet in the last block and this block?
Float64 theOffset = thePacketHeader.fTransmitTime - theLastBlockTime;
if (theOffset < 0)
theOffset = 0; //This may happen with the stupid negative times
theLastBlockTime = thePacketHeader.fTransmitTime;
if (theLastBlockTime < 0)
theLastBlockTime = 0; //This may happen with the stupid negative times
Assert(theOffset < 255);
theBlockMap[curBlockMapIndex] = (UInt8)theOffset;
// We may need to reallocate the block array
curBlockMapIndex++;
if (curBlockMapIndex == curBlockMapSize)
{
UInt8* newBlockArray = new UInt8[curBlockMapSize * 2];
::memcpy(newBlockArray, theBlockMap, curBlockMapSize);
curBlockMapSize *= 2;
delete [] theBlockMap;
theBlockMap = newBlockArray;
}
}
theNumPackets++;
theErr = ::write(inTempFile, &thePacketHeader, sizeof(thePacketHeader));
if (theErr < (int) sizeof(thePacketHeader))
{ qtss_printf("Write operation failed on temp file\n"); exit(0); }
theErr = ::write(inTempFile, thePacketData, thePacketLength);
if (theErr < thePacketLength)
{ qtss_printf("Write operation failed on temp file\n"); exit(0); }
// update our block offset
offsetInBlock += thePacketLength + sizeof(thePacketHeader);
}
qtss_printf("Finished writing packets. Wrote %"_U32BITARG_" packets to temp file.\n", theNumPackets);
*outNumBlocks = curBlockMapIndex-1;
return theBlockMap;
}