Add even more of the source
This should be about everything needed to build so far?
This commit is contained in:
parent
af3619d4fa
commit
849723c9cf
547 changed files with 149239 additions and 0 deletions
222
QTFileTools/QTBroadcaster.tproj/QTBroadcaster.cpp
Normal file
222
QTFileTools/QTBroadcaster.tproj/QTBroadcaster.cpp
Normal 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;
|
||||
}
|
129
QTFileTools/QTFileInfo.tproj/QTFileInfo.cpp
Normal file
129
QTFileTools/QTFileInfo.tproj/QTFileInfo.cpp
Normal 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;
|
||||
}
|
44
QTFileTools/QTFileTest.tproj/QTFileTest.cpp
Normal file
44
QTFileTools/QTFileTest.tproj/QTFileTest.cpp
Normal 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;
|
||||
}
|
368
QTFileTools/QTRTPFileTest.tproj/QTRTPFileTest.cpp
Normal file
368
QTFileTools/QTRTPFileTest.tproj/QTRTPFileTest.cpp
Normal 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;
|
||||
}
|
218
QTFileTools/QTRTPGen.tproj/QTRTPGen.cpp
Normal file
218
QTFileTools/QTRTPGen.tproj/QTRTPGen.cpp
Normal 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;
|
||||
}
|
148
QTFileTools/QTSDPGen.tproj/QTSDPGen.cpp
Normal file
148
QTFileTools/QTSDPGen.tproj/QTSDPGen.cpp
Normal 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;
|
||||
}
|
||||
|
156
QTFileTools/QTSampleLister.tproj/QTSampleLister.cpp
Normal file
156
QTFileTools/QTSampleLister.tproj/QTSampleLister.cpp
Normal 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;
|
||||
}
|
168
QTFileTools/QTTrackInfo.tproj/QTTrackInfo.cpp
Normal file
168
QTFileTools/QTTrackInfo.tproj/QTTrackInfo.cpp
Normal 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;
|
||||
}
|
91
QTFileTools/RTPFileGen.tproj/RTPFileDefs.h
Normal file
91
QTFileTools/RTPFileGen.tproj/RTPFileDefs.h
Normal 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__
|
322
QTFileTools/RTPFileGen.tproj/RTPFileGen.cpp
Normal file
322
QTFileTools/RTPFileGen.tproj/RTPFileGen.cpp
Normal 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, ©Buffer[0], kBlockSize);
|
||||
if (theErr <= 0)
|
||||
break;
|
||||
|
||||
int lenWritten = ::write(theOutFile, ©Buffer[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;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue