00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <inttypes.h>
00030 #include <string.h>
00031 
00032 #ifdef __MINGW32__
00033 #define fseeko(x, y, z) fseeko64(x, y, z)
00034 #define ftello(x)       ftello64(x)
00035 #elif defined(_WIN32)
00036 #define fseeko(x, y, z) _fseeki64(x, y, z)
00037 #define ftello(x)       _ftelli64(x)
00038 #endif
00039 
00040 #define BE_16(x) ((((uint8_t*)(x))[0] <<  8) | ((uint8_t*)(x))[1])
00041 
00042 #define BE_32(x) ((((uint8_t*)(x))[0] << 24) |  \
00043                   (((uint8_t*)(x))[1] << 16) |  \
00044                   (((uint8_t*)(x))[2] <<  8) |  \
00045                    ((uint8_t*)(x))[3])
00046 
00047 #define BE_64(x) (((uint64_t)(((uint8_t*)(x))[0]) << 56) |  \
00048                   ((uint64_t)(((uint8_t*)(x))[1]) << 48) |  \
00049                   ((uint64_t)(((uint8_t*)(x))[2]) << 40) |  \
00050                   ((uint64_t)(((uint8_t*)(x))[3]) << 32) |  \
00051                   ((uint64_t)(((uint8_t*)(x))[4]) << 24) |  \
00052                   ((uint64_t)(((uint8_t*)(x))[5]) << 16) |  \
00053                   ((uint64_t)(((uint8_t*)(x))[6]) <<  8) |  \
00054                   ((uint64_t)( (uint8_t*)(x))[7]))
00055 
00056 #define BE_FOURCC(ch0, ch1, ch2, ch3)           \
00057     ( (uint32_t)(unsigned char)(ch3)        |   \
00058      ((uint32_t)(unsigned char)(ch2) <<  8) |   \
00059      ((uint32_t)(unsigned char)(ch1) << 16) |   \
00060      ((uint32_t)(unsigned char)(ch0) << 24) )
00061 
00062 #define QT_ATOM BE_FOURCC
00063 
00064 #define FREE_ATOM QT_ATOM('f', 'r', 'e', 'e')
00065 #define JUNK_ATOM QT_ATOM('j', 'u', 'n', 'k')
00066 #define MDAT_ATOM QT_ATOM('m', 'd', 'a', 't')
00067 #define MOOV_ATOM QT_ATOM('m', 'o', 'o', 'v')
00068 #define PNOT_ATOM QT_ATOM('p', 'n', 'o', 't')
00069 #define SKIP_ATOM QT_ATOM('s', 'k', 'i', 'p')
00070 #define WIDE_ATOM QT_ATOM('w', 'i', 'd', 'e')
00071 #define PICT_ATOM QT_ATOM('P', 'I', 'C', 'T')
00072 #define FTYP_ATOM QT_ATOM('f', 't', 'y', 'p')
00073 #define UUID_ATOM QT_ATOM('u', 'u', 'i', 'd')
00074 
00075 #define CMOV_ATOM QT_ATOM('c', 'm', 'o', 'v')
00076 #define STCO_ATOM QT_ATOM('s', 't', 'c', 'o')
00077 #define CO64_ATOM QT_ATOM('c', 'o', '6', '4')
00078 
00079 #define ATOM_PREAMBLE_SIZE    8
00080 #define COPY_BUFFER_SIZE   1024
00081 
00082 int main(int argc, char *argv[])
00083 {
00084     FILE *infile  = NULL;
00085     FILE *outfile = NULL;
00086     unsigned char atom_bytes[ATOM_PREAMBLE_SIZE];
00087     uint32_t atom_type   = 0;
00088     uint64_t atom_size   = 0;
00089     uint64_t atom_offset = 0;
00090     uint64_t last_offset;
00091     unsigned char *moov_atom = NULL;
00092     unsigned char *ftyp_atom = NULL;
00093     uint64_t moov_atom_size;
00094     uint64_t ftyp_atom_size = 0;
00095     uint64_t i, j;
00096     uint32_t offset_count;
00097     uint64_t current_offset;
00098     uint64_t start_offset = 0;
00099     unsigned char copy_buffer[COPY_BUFFER_SIZE];
00100     int bytes_to_copy;
00101 
00102     if (argc != 3) {
00103         printf("Usage: qt-faststart <infile.mov> <outfile.mov>\n");
00104         return 0;
00105     }
00106 
00107     if (!strcmp(argv[1], argv[2])) {
00108         fprintf(stderr, "input and output files need to be different\n");
00109         return 1;
00110     }
00111 
00112     infile = fopen(argv[1], "rb");
00113     if (!infile) {
00114         perror(argv[1]);
00115         goto error_out;
00116     }
00117 
00118     
00119 
00120     while (!feof(infile)) {
00121         if (fread(atom_bytes, ATOM_PREAMBLE_SIZE, 1, infile) != 1) {
00122             break;
00123         }
00124         atom_size = (uint32_t) BE_32(&atom_bytes[0]);
00125         atom_type = BE_32(&atom_bytes[4]);
00126 
00127         
00128         if (atom_type == FTYP_ATOM) {
00129             ftyp_atom_size = atom_size;
00130             free(ftyp_atom);
00131             ftyp_atom = malloc(ftyp_atom_size);
00132             if (!ftyp_atom) {
00133                 printf("could not allocate %"PRIu64" bytes for ftyp atom\n",
00134                        atom_size);
00135                 goto error_out;
00136             }
00137             fseeko(infile, -ATOM_PREAMBLE_SIZE, SEEK_CUR);
00138             if (fread(ftyp_atom, atom_size, 1, infile) != 1) {
00139                 perror(argv[1]);
00140                 goto error_out;
00141             }
00142             start_offset = ftello(infile);
00143         } else {
00144             
00145             if (atom_size == 1) {
00146                 if (fread(atom_bytes, ATOM_PREAMBLE_SIZE, 1, infile) != 1) {
00147                     break;
00148                 }
00149                 atom_size = BE_64(&atom_bytes[0]);
00150                 fseeko(infile, atom_size - ATOM_PREAMBLE_SIZE * 2, SEEK_CUR);
00151             } else {
00152                 fseeko(infile, atom_size - ATOM_PREAMBLE_SIZE, SEEK_CUR);
00153             }
00154         }
00155         printf("%c%c%c%c %10"PRIu64" %"PRIu64"\n",
00156                (atom_type >> 24) & 255,
00157                (atom_type >> 16) & 255,
00158                (atom_type >>  8) & 255,
00159                (atom_type >>  0) & 255,
00160                atom_offset,
00161                atom_size);
00162         if ((atom_type != FREE_ATOM) &&
00163             (atom_type != JUNK_ATOM) &&
00164             (atom_type != MDAT_ATOM) &&
00165             (atom_type != MOOV_ATOM) &&
00166             (atom_type != PNOT_ATOM) &&
00167             (atom_type != SKIP_ATOM) &&
00168             (atom_type != WIDE_ATOM) &&
00169             (atom_type != PICT_ATOM) &&
00170             (atom_type != UUID_ATOM) &&
00171             (atom_type != FTYP_ATOM)) {
00172             printf("encountered non-QT top-level atom (is this a QuickTime file?)\n");
00173             break;
00174         }
00175         atom_offset += atom_size;
00176 
00177         
00178 
00179 
00180         if (atom_size < 8)
00181             break;
00182     }
00183 
00184     if (atom_type != MOOV_ATOM) {
00185         printf("last atom in file was not a moov atom\n");
00186         free(ftyp_atom);
00187         fclose(infile);
00188         return 0;
00189     }
00190 
00191     
00192 
00193     fseeko(infile, -atom_size, SEEK_END);
00194     last_offset    = ftello(infile);
00195     moov_atom_size = atom_size;
00196     moov_atom      = malloc(moov_atom_size);
00197     if (!moov_atom) {
00198         printf("could not allocate %"PRIu64" bytes for moov atom\n", atom_size);
00199         goto error_out;
00200     }
00201     if (fread(moov_atom, atom_size, 1, infile) != 1) {
00202         perror(argv[1]);
00203         goto error_out;
00204     }
00205 
00206     
00207 
00208     if (BE_32(&moov_atom[12]) == CMOV_ATOM) {
00209         printf("this utility does not support compressed moov atoms yet\n");
00210         goto error_out;
00211     }
00212 
00213     
00214     fclose(infile);
00215     infile = NULL;
00216 
00217     
00218     for (i = 4; i < moov_atom_size - 4; i++) {
00219         atom_type = BE_32(&moov_atom[i]);
00220         if (atom_type == STCO_ATOM) {
00221             printf(" patching stco atom...\n");
00222             atom_size = BE_32(&moov_atom[i - 4]);
00223             if (i + atom_size - 4 > moov_atom_size) {
00224                 printf(" bad atom size\n");
00225                 goto error_out;
00226             }
00227             offset_count = BE_32(&moov_atom[i + 8]);
00228             for (j = 0; j < offset_count; j++) {
00229                 current_offset  = BE_32(&moov_atom[i + 12 + j * 4]);
00230                 current_offset += moov_atom_size;
00231                 moov_atom[i + 12 + j * 4 + 0] = (current_offset >> 24) & 0xFF;
00232                 moov_atom[i + 12 + j * 4 + 1] = (current_offset >> 16) & 0xFF;
00233                 moov_atom[i + 12 + j * 4 + 2] = (current_offset >>  8) & 0xFF;
00234                 moov_atom[i + 12 + j * 4 + 3] = (current_offset >>  0) & 0xFF;
00235             }
00236             i += atom_size - 4;
00237         } else if (atom_type == CO64_ATOM) {
00238             printf(" patching co64 atom...\n");
00239             atom_size = BE_32(&moov_atom[i - 4]);
00240             if (i + atom_size - 4 > moov_atom_size) {
00241                 printf(" bad atom size\n");
00242                 goto error_out;
00243             }
00244             offset_count = BE_32(&moov_atom[i + 8]);
00245             for (j = 0; j < offset_count; j++) {
00246                 current_offset  = BE_64(&moov_atom[i + 12 + j * 8]);
00247                 current_offset += moov_atom_size;
00248                 moov_atom[i + 12 + j * 8 + 0] = (current_offset >> 56) & 0xFF;
00249                 moov_atom[i + 12 + j * 8 + 1] = (current_offset >> 48) & 0xFF;
00250                 moov_atom[i + 12 + j * 8 + 2] = (current_offset >> 40) & 0xFF;
00251                 moov_atom[i + 12 + j * 8 + 3] = (current_offset >> 32) & 0xFF;
00252                 moov_atom[i + 12 + j * 8 + 4] = (current_offset >> 24) & 0xFF;
00253                 moov_atom[i + 12 + j * 8 + 5] = (current_offset >> 16) & 0xFF;
00254                 moov_atom[i + 12 + j * 8 + 6] = (current_offset >>  8) & 0xFF;
00255                 moov_atom[i + 12 + j * 8 + 7] = (current_offset >>  0) & 0xFF;
00256             }
00257             i += atom_size - 4;
00258         }
00259     }
00260 
00261     
00262     infile = fopen(argv[1], "rb");
00263     if (!infile) {
00264         perror(argv[1]);
00265         goto error_out;
00266     }
00267 
00268     if (start_offset > 0) { 
00269         fseeko(infile, start_offset, SEEK_SET);
00270         last_offset -= start_offset;
00271     }
00272 
00273     outfile = fopen(argv[2], "wb");
00274     if (!outfile) {
00275         perror(argv[2]);
00276         goto error_out;
00277     }
00278 
00279     
00280     if (ftyp_atom_size > 0) {
00281         printf(" writing ftyp atom...\n");
00282         if (fwrite(ftyp_atom, ftyp_atom_size, 1, outfile) != 1) {
00283             perror(argv[2]);
00284             goto error_out;
00285         }
00286     }
00287 
00288     
00289     printf(" writing moov atom...\n");
00290     if (fwrite(moov_atom, moov_atom_size, 1, outfile) != 1) {
00291         perror(argv[2]);
00292         goto error_out;
00293     }
00294 
00295     
00296     printf(" copying rest of file...\n");
00297     while (last_offset) {
00298         if (last_offset > COPY_BUFFER_SIZE)
00299             bytes_to_copy = COPY_BUFFER_SIZE;
00300         else
00301             bytes_to_copy = last_offset;
00302 
00303         if (fread(copy_buffer, bytes_to_copy, 1, infile) != 1) {
00304             perror(argv[1]);
00305             goto error_out;
00306         }
00307         if (fwrite(copy_buffer, bytes_to_copy, 1, outfile) != 1) {
00308             perror(argv[2]);
00309             goto error_out;
00310         }
00311         last_offset -= bytes_to_copy;
00312     }
00313 
00314     fclose(infile);
00315     fclose(outfile);
00316     free(moov_atom);
00317     free(ftyp_atom);
00318 
00319     return 0;
00320 
00321 error_out:
00322     if (infile)
00323         fclose(infile);
00324     if (outfile)
00325         fclose(outfile);
00326     free(moov_atom);
00327     free(ftyp_atom);
00328     return 1;
00329 }