"Fossies" - the Fresh Open Source Software Archive

Member "quicktime4linux-2.3/recover.c" (9 Jan 2007, 10710 Bytes) of package /linux/privat/old/quicktime4linux-2.3-src.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 #include "funcprotos.h"
    2 #include "quicktime.h"
    3 
    4 #include <stdio.h>
    5 #include <stdlib.h>
    6 #include <string.h>
    7 #include <sys/stat.h>
    8 #include <sys/time.h>
    9 #include <stdint.h>
   10 
   11 
   12 
   13 
   14 /*
   15 
   16 Face it kids, Linux crashes.  Regardless of how good the free software
   17 model is, you still need to run on unreliable hardware and to get any
   18 hardware support at all you need to compete with McRosoft on features. 
   19 Ever since RedHat started trying to copy McRosoft's every move,
   20 reliability has been fickle at best.
   21 
   22 The X server crashes, the filesystem crashes, the network crashes, the
   23 sound driver crashes, the video driver crashes.  Signal handlers only
   24 handle application failures but most of the crashes are complete system
   25 lockups.   
   26 
   27 This utility should read through a truncated movie file and put a
   28 header on it, no matter what immitated McRosoft feature caused the
   29 crash.  It only handles JPEG encoded with jpeg-6b and MJPEG encoded
   30 with the BUZ driver with PCM audio.
   31 
   32 */
   33 
   34 
   35 
   36 
   37 
   38 
   39 
   40 #define FSEEK fseeko64
   41 
   42 
   43 #define WIDTH 720
   44 #define HEIGHT 480
   45 #define FRAMERATE (double)30000/1001
   46 #define CHANNELS 2
   47 #define SAMPLERATE 48000
   48 #define BITS 24
   49 #define TEMP_FILE "/tmp/temp.mov"
   50 #define VCODEC QUICKTIME_MJPA
   51 //#define VCODEC QUICKTIME_JPEG
   52 
   53 
   54 
   55 
   56 
   57 #define SEARCH_FRAGMENT (int64_t)0x100000
   58 //#define SEARCH_PAD 8
   59 #define SEARCH_PAD 16
   60 
   61 
   62 #define GOT_NOTHING 0
   63 #define IN_FIELD1   1
   64 #define GOT_FIELD1  2
   65 #define IN_FIELD2   3
   66 #define GOT_FIELD2  4
   67 #define GOT_AUDIO   5
   68 #define GOT_IMAGE_START 6
   69 #define GOT_IMAGE_END   7
   70 
   71 // Table utilities
   72 #define NEW_TABLE(ptr, size, allocation) \
   73 { \
   74     (ptr) = 0; \
   75     (size) = 0; \
   76     (allocation) = 0; \
   77 }
   78 
   79 #define APPEND_TABLE(ptr, size, allocation, value) \
   80 { \
   81     if((allocation) <= (size)) \
   82     { \
   83         if(!(allocation)) \
   84             (allocation) = 1024; \
   85         else \
   86             (allocation) *= 2; \
   87         int64_t *new_table = calloc(1, sizeof(int64_t) * (allocation)); \
   88         memcpy(new_table, (ptr), sizeof(int64_t) * (size)); \
   89         free((ptr)); \
   90         (ptr) = new_table; \
   91     } \
   92     (ptr)[(size)] = (value); \
   93     (size)++; \
   94 }
   95 
   96 
   97 
   98 int main(int argc, char *argv[])
   99 {
  100     FILE *in;
  101     FILE *temp;
  102     quicktime_t *out;
  103     int64_t current_byte, ftell_byte;
  104     int64_t jpeg_end;
  105     int64_t audio_start = 0, audio_end = 0;
  106     unsigned char *search_buffer = calloc(1, SEARCH_FRAGMENT);
  107     unsigned char *copy_buffer = 0;
  108     int i;
  109     int64_t file_size;
  110     struct stat status;
  111     unsigned char data[8];
  112     struct stat ostat;
  113     int fields = 1;
  114     time_t current_time = time(0);
  115     time_t prev_time = 0;
  116     int jpeg_header_offset;
  117     int64_t field1_offset = 0;
  118     int64_t field2_offset = 0;
  119     int64_t image_start = 0;
  120     int64_t image_end = 0;
  121     int update_time = 0;
  122     int state = GOT_NOTHING;
  123     char *in_path;
  124     int audio_frame;
  125     int total_samples;
  126     int field;
  127 
  128 // Value taken from Cinelerra preferences
  129     int audio_chunk = 131072;
  130 
  131 
  132     int64_t *start_table;
  133     int start_size;
  134     int start_allocation;
  135     int64_t *end_table;
  136     int end_size;
  137     int end_allocation;
  138     int64_t *field_table;
  139     int64_t field_size;
  140     int64_t field_allocation;
  141 
  142 // Dump codec settings
  143     printf("Codec settings:\n"
  144         "   WIDTH=%d HEIGHT=%d\n"
  145         "   FRAMERATE=%.2f\n"
  146         "   CHANNELS=%d\n"
  147         "   SAMPLERATE=%d\n"
  148         "   BITS=%d\n"
  149         "   audio chunk=%d\n"
  150         "   VCODEC=\"%s\"\n",
  151         WIDTH,
  152         HEIGHT,
  153         FRAMERATE,
  154         CHANNELS,
  155         SAMPLERATE,
  156         BITS,
  157         audio_chunk,
  158         VCODEC);
  159 
  160     if(argc < 2)
  161     {
  162         printf("Recover JPEG and PCM audio in a corrupted movie.\n"
  163             "Usage: recover [options] <input>\n"
  164             "Options:\n"
  165             " -b samples     number of samples in an audio chunk (%d)\n"
  166             "\n",
  167             audio_chunk);
  168         exit(1);
  169     }
  170 
  171     for(i = 1; i < argc; i++)
  172     {
  173         if(!strcmp(argv[i], "-b"))
  174         {
  175             if(i + 1 < argc)
  176             {
  177                 audio_chunk = atol(argv[i + 1]);
  178                 i++;
  179                 if(audio_chunk <= 0)
  180                 {
  181                     printf("Sample count for -b is out of range.\n");
  182                     exit(1);
  183                 }
  184             }
  185             else
  186             {
  187                 printf("-b needs a sample count.\n");
  188                 exit(1);
  189             }
  190         }
  191         else
  192         {
  193             in_path = argv[i];
  194         }
  195     }
  196 
  197 
  198 
  199 
  200     in = fopen(in_path, "rb+");
  201     out = quicktime_open(TEMP_FILE, 0, 1);
  202 
  203     if(!in)
  204     {
  205         perror("open input");
  206         exit(1);
  207     }
  208     if(!out)
  209     {
  210         perror("open temp");
  211         exit(1);
  212     }
  213 
  214     quicktime_set_audio(out, 
  215         CHANNELS, 
  216         SAMPLERATE, 
  217         BITS, 
  218         QUICKTIME_TWOS);
  219     quicktime_set_video(out, 
  220         1, 
  221         WIDTH, 
  222         HEIGHT, 
  223         FRAMERATE, 
  224         VCODEC);
  225     audio_start = (int64_t)0x10;
  226     ftell_byte = 0;
  227 
  228     if(fstat(fileno(in), &status))
  229         perror("get_file_length fstat:");
  230     file_size = status.st_size;
  231 
  232 
  233     NEW_TABLE(start_table, start_size, start_allocation)
  234     NEW_TABLE(end_table, end_size, end_allocation)
  235     NEW_TABLE(field_table, field_size, field_allocation)
  236 
  237 
  238 // Get the field count
  239     if(!memcmp(VCODEC, QUICKTIME_MJPA, 4))
  240     {
  241         fields = 2;
  242     }
  243     else
  244     {
  245         fields = 1;
  246     }
  247 
  248     audio_frame = BITS * CHANNELS / 8;
  249 
  250 // Tabulate the start and end of all the JPEG images.
  251 // This search is intended to be as simple as possible, reserving more
  252 // complicated operations for a table pass.
  253 printf("Pass 1 video only.\n");
  254     while(ftell_byte < file_size)
  255     {
  256         current_byte = ftell_byte;
  257         fread(search_buffer, SEARCH_FRAGMENT, 1, in);
  258         ftell_byte = current_byte + SEARCH_FRAGMENT - SEARCH_PAD;
  259         FSEEK(in, ftell_byte, SEEK_SET);
  260 
  261         for(i = 0; i < SEARCH_FRAGMENT - SEARCH_PAD; i++)
  262         {
  263 // Search for image start
  264             if(state == GOT_NOTHING)
  265             {
  266                 if(search_buffer[i] == 0xff &&
  267                     search_buffer[i + 1] == 0xd8 &&
  268                     search_buffer[i + 2] == 0xff &&
  269                     search_buffer[i + 3] == 0xe1 &&
  270                     search_buffer[i + 10] == 'm' &&
  271                     search_buffer[i + 11] == 'j' &&
  272                     search_buffer[i + 12] == 'p' &&
  273                     search_buffer[i + 13] == 'g')
  274                 {
  275                     state = GOT_IMAGE_START;
  276                     image_start = current_byte + i;
  277 
  278 // Determine the field
  279                     if(fields == 2)
  280                     {
  281 // Next field offset is nonzero in first field
  282                         if(search_buffer[i + 22] != 0 ||
  283                             search_buffer[i + 23] != 0 ||
  284                             search_buffer[i + 24] != 0 ||
  285                             search_buffer[i + 25] != 0)
  286                         {
  287                             field = 0;
  288                         }
  289                         else
  290                         {
  291                             field = 1;
  292                         }
  293                         APPEND_TABLE(field_table, field_size, field_allocation, field)
  294                     }
  295                 }
  296                 else
  297                 if(search_buffer[i] == 0xff &&
  298                     search_buffer[i + 1] == 0xd8 &&
  299                     search_buffer[i + 2] == 0xff &&
  300                     search_buffer[i + 3] == 0xe0 &&
  301                     search_buffer[i + 6] == 'J' &&
  302                     search_buffer[i + 7] == 'F' &&
  303                     search_buffer[i + 8] == 'I' &&
  304                     search_buffer[i + 9] == 'F')
  305                 {
  306                     state = GOT_IMAGE_START;
  307                     image_start = current_byte + i;
  308                 }
  309             }
  310             else
  311 // Search for image end
  312             if(state == GOT_IMAGE_START)
  313             {
  314                 if(search_buffer[i] == 0xff &&
  315                     search_buffer[i + 1] == 0xd9)
  316                 {
  317 // ffd9 sometimes occurs inside the mjpg tag
  318                     if(current_byte + i - image_start > 0x2a)
  319                     {
  320                         state = GOT_NOTHING;
  321 // Put it in the table
  322                         image_end = current_byte + i + 2;
  323 
  324 // An image may have been lost due to encoding errors but we can't do anything
  325 // because the audio may by misaligned.  Use the extract utility to get the audio.
  326                         if(image_end - image_start > audio_chunk * audio_frame)
  327                         {
  328                             printf("Possibly lost image between %llx and %llx\n", 
  329                                 image_start,
  330                                 image_end);
  331 // Put in fake image
  332 /*
  333  *                          APPEND_TABLE(start_table, start_size, start_allocation, image_start)
  334  *                          APPEND_TABLE(end_table, end_size, end_allocation, image_start + 1024)
  335  *                          APPEND_TABLE(start_table, start_size, start_allocation, image_end - 1024)
  336  *                          APPEND_TABLE(end_table, end_size, end_allocation, image_end)
  337  */
  338                         }
  339 
  340                         APPEND_TABLE(start_table, start_size, start_allocation, image_start)
  341                         APPEND_TABLE(end_table, end_size, end_allocation, image_end)
  342 
  343 //printf("%d %llx - %llx\n", start_size, image_start, image_end - image_start);
  344 
  345 if(!(start_size % 100))
  346 {
  347 printf("Got %d frames. %d%%\r", 
  348 start_size, 
  349 current_byte * (int64_t)100 / file_size);
  350 fflush(stdout);
  351 }
  352                     }
  353                 }
  354             }
  355         }
  356     }
  357 
  358 
  359 
  360 
  361 // With the image table complete, 
  362 // write chunk table from the gaps in the image table
  363 printf("Pass 2 audio table.\n");
  364     total_samples = 0;
  365     for(i = 1; i < start_size; i++)
  366     {
  367         int64_t next_image_start = start_table[i];
  368         int64_t prev_image_end = end_table[i - 1];
  369 
  370 // Got a chunk
  371         if(next_image_start - prev_image_end >= audio_chunk * audio_frame)
  372         {
  373             long samples = (next_image_start - prev_image_end) / audio_frame;
  374             quicktime_atom_t chunk_atom;
  375 
  376             quicktime_set_position(out, prev_image_end);
  377             quicktime_write_chunk_header(out, 
  378                 out->atracks[0].track, 
  379                 &chunk_atom);
  380             quicktime_set_position(out, next_image_start);
  381             quicktime_write_chunk_footer(out,
  382                 out->atracks[0].track, 
  383                 out->atracks[0].current_chunk, 
  384                 &chunk_atom,
  385                 samples);
  386 /*
  387  *          quicktime_update_tables(out, 
  388  *                      out->atracks[0].track, 
  389  *                      prev_image_end, 
  390  *                      out->atracks[0].current_chunk, 
  391  *                      out->atracks[0].current_position, 
  392  *                      samples, 
  393  *                      0);
  394  */
  395             out->atracks[0].current_position += samples;
  396             out->atracks[0].current_chunk++;
  397             total_samples += samples;
  398         }
  399     }
  400 
  401 
  402 
  403 
  404 
  405 // Put image table in movie
  406 printf("Got %d frames %d samples total.\n", start_size, total_samples);
  407     for(i = 0; i < start_size - fields; i += fields)
  408     {
  409 // Got a field out of order.  Skip just 1 image instead of 2.
  410         if(fields == 2 && field_table[i] != 0)
  411         {
  412             printf("Got field out of order at 0x%llx\n", start_table[i]);
  413             i--;
  414         }
  415         else
  416         {
  417             quicktime_atom_t chunk_atom;
  418             quicktime_set_position(out, start_table[i]);
  419             quicktime_write_chunk_header(out, 
  420                 out->vtracks[0].track,
  421                 &chunk_atom);
  422             quicktime_set_position(out, end_table[i + fields - 1]);
  423             quicktime_write_chunk_footer(out,
  424                 out->vtracks[0].track, 
  425                 out->vtracks[0].current_chunk, 
  426                 &chunk_atom,
  427                 1);
  428 /*
  429  *          quicktime_update_tables(out,
  430  *                      out->vtracks[0].track,
  431  *                      start_table[i],
  432  *                      out->vtracks[0].current_chunk,
  433  *                      out->vtracks[0].current_position,
  434  *                      1,
  435  *                      end_table[i + fields - 1] - start_table[i]);
  436  */
  437             out->vtracks[0].current_position++;
  438             out->vtracks[0].current_chunk++;
  439         }
  440     }
  441 
  442 
  443 
  444 
  445 
  446 
  447 
  448 // Force header out at beginning of temp file
  449     quicktime_set_position(out, 0x10);
  450     quicktime_close(out);
  451 
  452 // Transfer header
  453     FSEEK(in, 0x8, SEEK_SET);
  454 
  455     data[0] = (ftell_byte & 0xff00000000000000LL) >> 56;
  456     data[1] = (ftell_byte & 0xff000000000000LL) >> 48;
  457     data[2] = (ftell_byte & 0xff0000000000LL) >> 40;
  458     data[3] = (ftell_byte & 0xff00000000LL) >> 32;
  459     data[4] = (ftell_byte & 0xff000000LL) >> 24;
  460     data[5] = (ftell_byte & 0xff0000LL) >> 16;
  461     data[6] = (ftell_byte & 0xff00LL) >> 8;
  462     data[7] = ftell_byte & 0xff;
  463     fwrite(data, 8, 1, in);
  464 
  465     FSEEK(in, ftell_byte, SEEK_SET);
  466     stat(TEMP_FILE, &ostat);
  467 
  468     temp = fopen(TEMP_FILE, "rb");
  469     FSEEK(temp, 0x10, SEEK_SET);
  470     copy_buffer = calloc(1, ostat.st_size);
  471     fread(copy_buffer, ostat.st_size, 1, temp);
  472     fclose(temp);
  473     fwrite(copy_buffer, ostat.st_size, 1, in);
  474 
  475     fclose(in);
  476 }
  477 
  478 
  479 
  480