Home > fcn > DIVA_GUI_toolbox > ReadQTMovie.m

ReadQTMovie

PURPOSE ^

im = ReadQTMovie(cmd, arg)

SYNOPSIS ^

function im = ReadQTMovie(cmd, arg)

DESCRIPTION ^

 im = ReadQTMovie(cmd, arg)
 Read images and sound from a QuickTime movie.
 Syntax: im = ReadQTMovie(cmd, arg)
        The following commands are supported:
        start filename - Open the indicated file and parse
               its contents.  Must be called first.
        getframe num - Return the image indicated by this
               frame number.   Returns an empty matrix if this frame
        does not exist.
     getsound - Get all the sound for this movie
      getsoundsr - Get the sample rate for the sound in this movie
        close - Close this movie.
 Note: This code can only read movies compressed with the JPEG image
 format.  Motion JPEG and the other more advanced codecs are NOT supported.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 % im = ReadQTMovie(cmd, arg)
0002 % Read images and sound from a QuickTime movie.
0003 % Syntax: im = ReadQTMovie(cmd, arg)
0004 %        The following commands are supported:
0005 %        start filename - Open the indicated file and parse
0006 %               its contents.  Must be called first.
0007 %        getframe num - Return the image indicated by this
0008 %               frame number.   Returns an empty matrix if this frame
0009 %        does not exist.
0010 %     getsound - Get all the sound for this movie
0011 %      getsoundsr - Get the sample rate for the sound in this movie
0012 %        close - Close this movie.
0013 % Note: This code can only read movies compressed with the JPEG image
0014 % format.  Motion JPEG and the other more advanced codecs are NOT supported.
0015 
0016 % Malcolm Slaney - Interval Research Corporation - August 13, 1999
0017 % (c) Copyright Malcolm Slaney, Interval Research, March 1999.
0018 
0019 % This is experimental software and is being provided to Licensee
0020 % 'AS IS.'  Although the software has been tested on Macintosh, SGI,
0021 % Linux, and Windows machines, Interval makes no warranties relating
0022 % to the software's performance on these or any other platforms.
0023 %
0024 % Disclaimer
0025 % THIS SOFTWARE IS BEING PROVIDED TO YOU 'AS IS.'  INTERVAL MAKES
0026 % NO EXPRESS, IMPLIED OR STATUTORY WARRANTY OF ANY KIND FOR THE
0027 % SOFTWARE INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY OF
0028 % PERFORMANCE, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
0029 % IN NO EVENT WILL INTERVAL BE LIABLE TO LICENSEE OR ANY THIRD
0030 % PARTY FOR ANY DAMAGES, INCLUDING LOST PROFITS OR OTHER INCIDENTAL
0031 % OR CONSEQUENTIAL DAMAGES, EVEN IF INTERVAL HAS BEEN ADVISED OF
0032 % THE POSSIBLITY THEREOF.
0033 %
0034 %   This software program is owned by Interval Research
0035 % Corporation, but may be used, reproduced, modified and
0036 % distributed by Licensee.  Licensee agrees that any copies of the
0037 % software program will contain the same proprietary notices and
0038 % warranty disclaimers which appear in this software program.
0039 %
0040 
0041 % The QuickTime movie format is documented in the appendix to the Inside
0042 % Macintosh: QuickTime book or at this URL
0043 %http://developer.apple.com/techpubs/quicktime/qtdevdocs/REF/refFileFormat96.htm
0044 %
0045 % Note, only a single track of audio and video is supported.  This
0046 % QuickTime movies can get arbitrarily complicated, with masks and all sorts
0047 % of random media in them.  This routine only reads the simplest kind of
0048 % movies, and does not give access to the detailed timing information.
0049 
0050 function im = ReadQTMovie(cmd, arg)
0051 global movieStatus;
0052 
0053 if nargin < 1
0054     ReadQTMovie('help')
0055     return;
0056 end
0057 
0058 if exist('movieStatus') ~= 1 | isempty(movieStatus)
0059     % disp('Creating new movieStatus variable');
0060     movieStatus = struct('sound_stco', [], ...
0061                 'sound_stsc', [], ...
0062                 'sound_stsz', [], ...
0063                 'sound_stts', [], ...
0064                 'video_stco', [], ...
0065                 'video_stsc', [], ...
0066                 'video_stsz', [], ...
0067                 'video_stts', [], ...
0068                 'frame_pos', [], ...
0069                 'frame_desc', [], ...
0070                 'handler', 'none', ...
0071                 'timeScale', [], ...
0072                 'name', [], ...
0073                 'videoDescription', [], ...
0074                 'soundDescription', [], ...
0075                 'fp', -1 ...
0076                 );
0077 end
0078 
0079 switch lower(cmd)
0080 case 'help'
0081     fprintf('Syntax: im = ReadQTMovie(cmd, arg)\n');
0082     fprintf('The following commands are supported:\n');
0083     fprintf('    start filename - Open the indicated file and parse\n');
0084     fprintf('        its contents.  Must be called first.\n');
0085     fprintf('    getframe num - Return the image indicated by this\n');
0086     fprintf('        frame number \n');
0087     fprintf('    getsound - Get all the movie''s sound.\n');
0088     fprintf('    getsamplerate - Get the sound''s sample rate.\n');
0089     fprintf('    describe - Show debugging information.\n');
0090     fprintf('    close - Close this movie.\n');
0091 
0092 case 'close'
0093     if movieStatus.fp >= 0
0094         try
0095             fclose(movieStatus.fp),
0096         catch
0097         end
0098     end
0099     movieStatus.fp = -1;
0100     movieStatus = [];
0101     
0102 case {'start','name'}
0103     if movieStatus.fp >= 0
0104         try
0105             fclose(movieStatus.fp),
0106         catch
0107         end
0108     end
0109 
0110     name = arg;
0111     movieStatus.name = name;
0112     fp = fopen(name, 'rb', 'b');        % Big-endian file reading
0113     if fp < 0
0114         error('Can not open file name.');
0115     end
0116     movieStatus.fp = fp;
0117     movieStatus.sound_stco = [];
0118     movieStatus.sound_stsc = [];
0119     movieStatus.sound_stsz = [];
0120     movieStatus.sound_stts = [];
0121     movieStatus.video_stco = [];
0122     movieStatus.video_stsc = [];
0123     movieStatus.video_stsz = [];
0124     movieStatus.video_stts = [];
0125     movieStatus.videoDescription = [];
0126     movieStatus.soundDescription = [];
0127     movieStatus.frame_pos = [];
0128     movieStatus.frame_desc = [];
0129 
0130     while ParseAtom(fp) > 0
0131         ;
0132     end
0133     FindVideoFrames;
0134     im = movieStatus;
0135 case {'findframe','getframe'}
0136     if nargin < 2
0137         error('Missing frame number in ReadQTMovie(''findframe'',#)')'
0138     end
0139     num = arg;
0140 
0141     if num < 1 | num > length(movieStatus.frame_pos)
0142         im = [];
0143         return;
0144     end
0145 
0146     desc_index =  movieStatus.frame_desc(num)+1;
0147     if length(movieStatus.videoDescription) > 1
0148         vs = movieStatus.videoDescription(desc_index);
0149     else
0150         vs = movieStatus.videoDescription;
0151     end
0152     switch vs.type
0153     case 'jpeg',
0154         ;                % OK, go for it.
0155 %    case 'mjpa',                % Just for testing
0156 %        ;
0157     otherwise,
0158         error(['Can not decode a ' vs.type ' field of video.']);
0159     end
0160 
0161     im = GrabFrameFromMovie(movieStatus.fp, movieStatus.frame_pos(num), ...
0162         movieStatus.video_stsz(num));
0163 
0164                         % Read the raw compressed
0165                         % image data from the QT
0166                         % file.
0167 case 'getcompressedframe',
0168     if nargin < 2
0169         error('Missing frame number in ReadQTMovie(''findframe'',#)')'
0170     end
0171     num = arg;
0172 
0173     if num < 1 | num > length(movieStatus.frame_pos)
0174         im = [];
0175         return;
0176     end
0177 
0178     desc_index =  movieStatus.frame_desc(num)+1;
0179     if length(movieStatus.videoDescription) > 1
0180         vs = movieStatus.videoDescription(desc_index);
0181     else
0182         vs = movieStatus.videoDescription;
0183     end
0184 
0185     fseek(movieStatus.fp, movieStatus.frame_pos(num), 'bof');
0186     im = fread(movieStatus.fp, movieStatus.video_stsz(num), 'uchar');
0187 
0188 case 'getsound',
0189     if nargin < 2
0190         im = FindSound;
0191     else
0192         im = FindSound(arg(1), arg(2));
0193     end
0194 case 'getsoundsr',
0195     im = [];
0196     if HaveSoundTrack
0197         for i=1:length(movieStatus.soundDescription)
0198             sr = movieStatus.soundDescription(i).sample_rate;
0199             if ~isempty(sr)
0200                 im = sr;
0201                 break
0202             end
0203         end
0204     end
0205 case {'info','describe'},
0206     fprintf('Movie information for %s:\n', movieStatus.name);
0207     fprintf('\tTime Scale: %d ticks per second\n', movieStatus.timeScale);
0208     fprintf('\tVideo information:\n');
0209     fprintf('\t\tNumber of frames: %d\n', length(movieStatus.video_stsz));
0210     fprintf('\t\tNumber of chunk offset atoms (stco): %d\n', ...
0211         length(movieStatus.video_stco));
0212     fprintf('\t\tNumber of sample to chunk atoms (stsc): %d\n', ...
0213         length(movieStatus.video_stsc));
0214     for i=1:min(4,size(movieStatus.video_stsc,2));
0215         fprintf('\t\t\tfirst sample %d, %d samples/chunk, type %d\n',...
0216             movieStatus.video_stsc(1,i), ...
0217             movieStatus.video_stsc(2,i), ...
0218             movieStatus.video_stsc(3,i));
0219     end
0220     fprintf('\t\tNumber of sample size atoms (stsz): %d\n', ...
0221         length(movieStatus.video_stsz));
0222     fprintf('\t\t\t');
0223     for i=1:min(8,length(movieStatus.video_stsz))
0224         if i > 1
0225             fprintf(', ');
0226         end
0227         fprintf('%d', movieStatus.video_stsz(i));
0228     end
0229     fprintf('\n');
0230     fprintf('\t\tNumber of sample to time atoms (stts): %d\n', ...
0231         length(movieStatus.video_stts));
0232     for i=1:min(3,size(movieStatus.video_stts,2))
0233         fprintf('\t\t\t%d frames separated by %d ticks', ...
0234             movieStatus.video_stts(1,i), ...
0235             movieStatus.video_stts(2,i));
0236         fprintf(' (%g ms)\n', ...
0237             movieStatus.video_stts(2,i)/movieStatus.timeScale*1000);
0238     end
0239     for i=1:length(movieStatus.videoDescription)
0240         if ~isempty(movieStatus.videoDescription(i).type)
0241             fprintf('\t\tTrack %d Format: %s\n', i-1, ...
0242                 movieStatus.videoDescription(i).type);
0243             fprintf('\t\t\t%d x %d, tqual is %d, squal is %d.\n',...
0244                 movieStatus.videoDescription(i).width, ...
0245                 movieStatus.videoDescription(i).height, ...
0246                 movieStatus.videoDescription(i).tqual, ...
0247                 movieStatus.videoDescription(i).squal);
0248         end
0249     end
0250 
0251     fprintf('\tSound information:\n');
0252     fprintf('\t\tNumber of chunk offset atoms (stco): %d\n', ...
0253         length(movieStatus.sound_stco));
0254     fprintf('\t\tNumber of sample to chunk atoms (stsc): %d\n', ...
0255         length(movieStatus.sound_stsc));
0256     for i=1:min(4,size(movieStatus.sound_stsc,2));
0257         fprintf('\t\t\tfirst sample %d, %d samples/chunk, type %d\n',...
0258             movieStatus.sound_stsc(1,i), ...
0259             movieStatus.sound_stsc(2,i), ...
0260             movieStatus.sound_stsc(3,i));
0261     end
0262     fprintf('\t\tNumber of sample size atoms (stsz): %d\n', ...
0263         length(movieStatus.sound_stsz));
0264     fprintf('\t\t\t');
0265     for i=1:min(8,length(movieStatus.sound_stsz))
0266         if i > 1
0267             fprintf(', ');
0268         end
0269         fprintf('%d', movieStatus.sound_stsz(i));
0270     end
0271     fprintf('\n');
0272     fprintf('\t\tNumber of sample to time atoms (stts): %d\n', ...
0273         length(movieStatus.sound_stts));
0274     for i=1:min(3,size(movieStatus.sound_stts,2))
0275         fprintf('\t\t\t%d frames separated by %d ticks', ...
0276             movieStatus.sound_stts(1,i), ...
0277             movieStatus.sound_stts(2,i));
0278         fprintf(' (%g ms)\n', ...
0279             movieStatus.sound_stts(2,i)/movieStatus.timeScale*1000);
0280 
0281     end
0282     for i=1:length(movieStatus.soundDescription)
0283         if ~isempty(movieStatus.soundDescription(i).type)
0284             fprintf('\t\tTrack %d Format: %s\n', i-1, ...
0285                 movieStatus.soundDescription(i).type);
0286             fprintf('\t\t\t%d channel, %d bits/sample, %d Hz\n',...
0287                 movieStatus.soundDescription(i).channels, ...
0288                 movieStatus.soundDescription(i).bits, ...
0289                 movieStatus.soundDescription(i).sample_rate);
0290                 
0291         end
0292     end
0293 
0294 otherwise
0295     error('Unknown command to ReadQTMovie')
0296 end
0297 
0298 
0299 
0300 
0301 %%%%%%%%%%%%%%%  FindVideoFrames  %%%%%%%%%%%%%%%%%
0302 % Go through the structures we've read in and find all the video
0303 % frames.  Mostly this means figuring out where each frame of video
0304 % starts in the file.
0305 function FindVideoFrames
0306 global movieStatus
0307 pos = [];
0308 description_index = [];
0309 current_stsc_index = 1;
0310 current_frame = 1;
0311                         % For each chunk of data
0312                         % (as indicated by chunk offset
0313                         % list.)
0314 for c=1:length(movieStatus.video_stco)
0315                         % Where does this chunk of
0316                         % data sit in the file?
0317     chunk_pos = movieStatus.video_stco(c);
0318                         % Check to see whether we move
0319                         % to the next stsc record
0320                         % (which tells us how many
0321                         % samples per chunk and their
0322                         % description index.)
0323     if current_stsc_index < size(movieStatus.video_stsc,2)
0324         if c >= movieStatus.video_stsc(1,current_stsc_index+1)
0325             current_stsc_index = current_stsc_index+1;
0326         end
0327     end
0328                         % OK, now we know how many
0329                         % samples we have in the
0330                         % current chunk.
0331     frames_per_chunk = movieStatus.video_stsc(2,current_stsc_index);
0332                         % Get the sizes of the samples
0333                         % for this chunk
0334     sizes = movieStatus.video_stsz(current_frame: ...
0335             (current_frame+frames_per_chunk-1))';
0336                         
0337                         % Now create a list of
0338                         % starting positions.  If there
0339                         % is only one, then it is
0340                         % easy.  Otherwise, we need
0341                         % to sum the sizes and add to
0342                         % the start.
0343     if frames_per_chunk > 1
0344         pos = [pos chunk_pos chunk_pos+cumsum(sizes(1:end-1))];
0345     else
0346         pos = [pos chunk_pos];
0347     end
0348                         % OK, we've processed
0349                         % another "frames_per_chunk"
0350                         % samples by doing this
0351                         % chunk.
0352     current_frame = current_frame + frames_per_chunk;
0353                         % Also keep track of which
0354                         % sample description
0355                         % corresponds to each frame.
0356     description_index = [description_index ones(1,length(sizes)) * ...
0357             movieStatus.video_stsc(3,current_stsc_index)];
0358 end
0359 movieStatus.frame_pos = pos;
0360 movieStatus.frame_desc = description_index;
0361 
0362 %%%%%%%%%%%%%%%  FindSound  %%%%%%%%%%%%%%%%%
0363 function sound = FindSound(firstSample, lastSample)
0364 global movieStatus
0365 current_stsc_index = 1;                % Sample to Chunk Index
0366 totalLength = 0;                % Total length of sound
0367 chunk_pos = zeros(1,length(movieStatus.sound_stco));
0368 chunk_desc = chunk_pos;
0369 chunk_frames = chunk_pos;
0370 
0371                         % Get the sizes of the samples
0372 if length(movieStatus.sound_stsz) > 1
0373     warning('Got an stsz atom I don''t know what to do with.\n');
0374 end
0375 sizes = movieStatus.sound_stsz(1);
0376 
0377                         % For each chunk of data
0378                         % (as indicated by chunk offset
0379                         % list.)
0380 for c=1:length(movieStatus.sound_stco)
0381                         % Where does this chunk of
0382                         % data sit in the file?
0383     chunk_pos(c) = movieStatus.sound_stco(c);
0384                         % Check to see whether we move
0385                         % to the next stsc record
0386                         % (which tells us how many
0387                         % samples per chunk and their
0388                         % description index.)
0389     if current_stsc_index < size(movieStatus.sound_stsc,2)
0390         if c >= movieStatus.sound_stsc(1,current_stsc_index+1)
0391             current_stsc_index = current_stsc_index+1;
0392         end
0393     end
0394                         % OK, now we know how many
0395                         % samples we have in the
0396                         % current chunk.
0397     chunk_frames(c) = movieStatus.sound_stsc(2,current_stsc_index);
0398 
0399     chunk_desc(c) = movieStatus.sound_stsc(3,current_stsc_index)+1;
0400                         % Massive hack.  Quicktime
0401                         % does something when the
0402                         % stsc specifies a sound
0403                         % description that doesn't
0404                         % exist.  I have seen this,
0405                         % but I don't know what Apple
0406                         % does.  I just set the
0407                         % number back to what I
0408                         % have.
0409     if (chunk_desc(c) > length(movieStatus.soundDescription))
0410         chunk_desc(c) = length(movieStatus.soundDescription);
0411         disp('Adjusting sound description id in FindSound.');
0412     end
0413 
0414     ch = movieStatus.soundDescription(chunk_desc(c)).channels;
0415     if c == 1
0416         channels = ch;
0417     elseif channels ~= ch
0418         er = fprintf('Channel count changed %d to %d at chunk %d.\n',...
0419             channels, ch, c);
0420         error(er);
0421     end
0422     totalLength = totalLength + sizes*chunk_frames(c);
0423 end
0424                         
0425 if nargin < 1
0426     firstSample = 0;
0427 end
0428 if nargin < 2
0429     lastSample = totalLength;
0430 end
0431 fprintf('Getting sound from sample %d to %d from %d total samples.\n', ...
0432     firstSample, lastSample, totalLength);
0433     
0434 sound = zeros(lastSample-firstSample+1, channels);
0435 inputPos = 1;
0436 outputPos = 1;
0437 for c=1:length(chunk_desc)
0438     desc = chunk_desc(c);
0439     inputCnt = sizes * chunk_frames(c);
0440     if inputPos+inputCnt-1 >= firstSample & inputPos <= lastSample
0441 
0442         skip = max(0, firstSample - inputPos);
0443         outputCnt = min(inputCnt-skip, size(sound,1) - outputPos + 1);
0444         % fprintf('Chunk %d, skipping %d samples and grabbing %d.\n',...
0445         %     c, skip, outputCnt);
0446         % fprintf(' inputPos is %d, outputPos is %d.\n', ...
0447          %    inputPos, outputPos);
0448         fseek(movieStatus.fp, chunk_pos(c), 'bof');
0449         switch movieStatus.soundDescription(desc).type
0450         case 'raw ',
0451             chunk = fread(movieStatus.fp,inputCnt*channels,'uchar');
0452             chunk = (chunk-128)/128;
0453         case 'twos',
0454             chunk = fread(movieStatus.fp,inputCnt*channels,'int16');
0455             chunk = chunk/32768;
0456         otherwise,
0457             error('Unknown sound format');
0458         end
0459         chunk = reshape(chunk, channels, inputCnt)';
0460         chunkEnd = outputPos+outputCnt-1;
0461         if chunkEnd > size(sound,1)
0462             error('Internal Error: chunkEnd got too big.');
0463         end
0464         sound(outputPos:chunkEnd,:) = chunk(skip+1:skip+outputCnt,:);
0465         outputPos = outputPos + outputCnt;
0466     end
0467     inputPos = inputPos + inputCnt;
0468 end
0469         
0470 
0471 %%%%%%%%%%%%%%%  GrabFrameFromMovie %%%%%%%%%%%%%%%%%
0472 function im = GrabFrameFromMovie(fp, pos, framelen)
0473 global movieStatus
0474 
0475 imageTmp = tempname;
0476 tempfp = fopen(imageTmp, 'wb');
0477 if tempfp < 0
0478     error ('Could not open temporary file for grabbing QT movie frame.');
0479 end
0480 
0481 fseek(fp, pos, 'bof');
0482 lensofar = 0;
0483 while lensofar < framelen
0484     data = fread(fp, min(1024*16, framelen-lensofar), 'uchar');
0485     if isempty(data)
0486         break;
0487     end
0488     cnt = fwrite(tempfp, data, 'uchar');
0489     lensofar = lensofar + cnt;
0490 end
0491 fclose(tempfp);
0492 im = imread(imageTmp);
0493 delete(imageTmp);
0494 
0495 %%%%%%%%%%%%%%%  HaveVideoTrack %%%%%%%%%%%%%%%%%
0496 function res = HaveVideoTrack()
0497 global movieStatus
0498 res = ~isempty(movieStatus.video_stco) & ~isempty(movieStatus.video_stsc) & ...
0499         ~isempty(movieStatus.video_stsz);
0500 
0501 %%%%%%%%%%%%%%%  HaveSoundTrack %%%%%%%%%%%%%%%%%
0502 function res = HaveSoundTrack()
0503 global movieStatus
0504 res = ~isempty(movieStatus.sound_stco) & ~isempty(movieStatus.sound_stsc) & ...
0505         ~isempty(movieStatus.sound_stsz);
0506 
0507 
0508 
0509     
0510 
0511 %%%%%%%%%%%%%%%  DuplicateTrack (error message) %%%%%%%%%%%%%%%%%
0512 function DuplicateTrack(mode, atom)
0513 fprintf('Found duplicate %s track in QuickTime movie (%s atom).\n',mode,atom);
0514 error('Unable to process duplicate tracks.');
0515             
0516 
0517 %%%%%%%%%%%%%%%  ParseAtom (just one) %%%%%%%%%%%%%%%%%
0518 function size = ParseAtom(fp)
0519 global movieStatus
0520 size = Read32Bits(fp);
0521 type = Read4ByteString(fp);
0522 place = 8;
0523 
0524 if isempty(size)
0525     size = 0;
0526     return;
0527 end
0528 
0529 % fprintf('Parsing a %s atom with size of %d.\n', type, size);
0530 switch type
0531 case 'dref',
0532     Read32Bits(fp, 2);
0533     place = place + 8;
0534     while place < size
0535         place = place + ParseAtom(fp);
0536     end
0537 case {'edts','mdia','minf','moov','stbl'},
0538     while place < size
0539         place = place + ParseAtom(fp);
0540     end
0541 case 'trak',
0542     while place < size
0543         place = place + ParseAtom(fp);
0544     end
0545     
0546 % http://developer.apple.com/techpubs/quicktime/qtdevdocs/REF/
0547 %    refFileFormat96.1b.htm#29160
0548 case 'hdlr',
0549     Read32Bits(fp);
0550     type = Read4ByteString(fp);
0551     sub = Read4ByteString(fp);
0552     place = place + 12;
0553     % fprintf('Got a %s hdlr\n', type);
0554     if strcmp(type, 'mhlr')
0555         movieStatus.handler = sub;
0556     end
0557 case 'mvhd',
0558     Read32Bits(fp, 3);
0559     movieStatus.timeScale = Read32Bits(fp);
0560     place = place + 16;
0561 % http://developer.apple.com/techpubs/quicktime/qtdevdocs/REF/
0562 %     refFileFormat96.2d.htm
0563 case 'stco',
0564     Read32Bits(fp);
0565     count = Read32Bits(fp);
0566     place = place + 8;
0567     % fprintf('Processing %s, got %d stco\n', movieStatus.handler,...
0568     %     count);
0569     switch movieStatus.handler
0570     case 'soun', 
0571         if isempty(movieStatus.sound_stco)
0572             movieStatus.sound_stco = Read32Bits(fp, count);
0573         else
0574             DuplicateTrack('sound','stco');
0575         end
0576     case 'vide', 
0577         if isempty(movieStatus.video_stco)
0578             movieStatus.video_stco = Read32Bits(fp, count);
0579         else
0580             DuplicateTrack('video','stco');
0581         end
0582     end
0583     place = place + 4 * count;
0584 % http://developer.apple.com/techpubs/quicktime/qtdevdocs/REF/
0585 %    refFileFormat96.2b.htm
0586 % This chunk contains the following three items for each sequence of chunks
0587 %    First Chunk Number
0588 %    Number of Samples per Chunk
0589 %    Chunk Tag Number
0590 % When we look for a chunk, we have to count through the entries in this
0591 % table until we've found the right chunk.
0592 case 'stsc',
0593     Read32Bits(fp);
0594     count = Read32Bits(fp);
0595     place = place + 8;
0596     % fprintf('Processing %s, got %d stsc\n', movieStatus.handler,...
0597     %     count);
0598     data = Read32Bits(fp, count*3);
0599     switch movieStatus.handler
0600     case 'soun', 
0601         if isempty(movieStatus.sound_stsc)
0602             movieStatus.sound_stsc = reshape(data,3,count);
0603         else
0604             DuplicateTrack('sound','stsc');
0605         end
0606     case 'vide', 
0607         if isempty(movieStatus.video_stsc)
0608             movieStatus.video_stsc = reshape(data,3,count);
0609         else
0610             DuplicateTrack('video','stsc');
0611         end
0612     end
0613     place = place + 4 * 3 * count;
0614 % http://developer.apple.com/techpubs/quicktime/qtdevdocs/REF/
0615 %    refFileFormat96.28.htm
0616 case 'stsd',
0617     Read32Bits(fp);
0618     count = Read32Bits(fp);
0619     place = place + 8;
0620     for i=1:count
0621         place = place + ParseSampleDescription(fp);
0622     end
0623 case 'stts',
0624     Read32Bits(fp);
0625     count = Read32Bits(fp);
0626     place = place + 8;
0627     data = Read32Bits(fp, count*2);
0628     place = place + 2*count*4;
0629     switch movieStatus.handler
0630     case 'soun', 
0631         if isempty(movieStatus.sound_stts)
0632             movieStatus.sound_stts = reshape(data,2,count);
0633         else
0634             DuplicateTrack('sound','stts');
0635         end
0636     case 'vide', 
0637         if isempty(movieStatus.video_stts)
0638             movieStatus.video_stts = reshape(data,2,count);
0639         else
0640             DuplicateTrack('video','stts');
0641         end
0642     end
0643 
0644 % Size of each sample of data.  Should be one entry for each video frame and
0645 % probably just one entry for all the sound.
0646 % http://developer.apple.com/techpubs/quicktime/qtdevdocs/REF/
0647 %     refFileFormat96.2c.htm
0648 case 'stsz',
0649     flags = Read32Bits(fp);
0650     sizedata = Read32Bits(fp);
0651     count = Read32Bits(fp);
0652     place = place + 12;
0653     if sizedata > 0
0654         data = sizedata;
0655     else
0656         % fprintf('Processing %s, got %d stsz\n', ...
0657         %     movieStatus.handler,  count);
0658         data = Read32Bits(fp, count);
0659         place = place + 4 * count;
0660     end
0661     switch movieStatus.handler
0662     case 'soun', 
0663         if isempty(movieStatus.sound_stsz)
0664             movieStatus.sound_stsz = data;
0665         else
0666             DuplicateTrack('sound','stsz');
0667         end
0668     case 'vide', 
0669         if isempty(movieStatus.video_stsz)
0670             movieStatus.video_stsz = data;
0671         else
0672             DuplicateTrack('video','stsz');
0673         end
0674     end
0675 case {'dinf','elst','mdat','raw ','rpza', 'jpeg', 'rle ','smhd', ...
0676     'stgs', 'stss', 'tkhd', 'vmhd'}
0677                 % Ignore this.. no further information
0678 otherwise,
0679     % fprintf(' Ignoring a %s atom with size of %d.\n', type, size);
0680 end
0681 if size-place < 0
0682     error('got out of sync while reading QT movie.');
0683 end
0684 fseek(fp, size-place, 'cof');
0685 
0686 
0687 
0688 %%%%%%%%%%%%%%%  ParseSampleDescription (just one) %%%%%%%%%%%%%%%%%
0689 % The generic sample description atoms are described at:
0690 % http://developer.apple.com/techpubs/quicktime/qtdevdocs/REF/
0691 %    refFileFormat96.28.htm#pgfId=1169
0692 function size = ParseSampleDescription(fp)
0693 global movieStatus
0694 size = Read32Bits(fp);
0695 type = Read4ByteString(fp);
0696 place = 8;
0697 
0698 if isempty(size)
0699     size = 0;
0700     return;
0701 end
0702 
0703 Read16Bits(fp, 3);
0704 reference_index = Read16Bits(fp)+1;
0705 place = place + 8;
0706 
0707 switch movieStatus.handler
0708 case 'soun',
0709     Read32Bits(fp);            % Version/Revision
0710     Read32Bits(fp);            % Vendor
0711     num_channels = Read16Bits(fp);
0712     num_bits = Read16Bits(fp);
0713     compress_packet = Read32Bits(fp);
0714     sample_rate = Read32Bits(fp)/65536.0;
0715     place = place + 20;
0716 
0717     if(isempty(movieStatus.soundDescription))
0718         movieStatus.soundDescription = ...
0719             repmat(struct('type',[],'channels',[],'bits',[],'sample_rate',[]),1,1);
0720     else
0721         movieStatus.soundDescription(end+1)=movieStatus.soundDescription(end);
0722     end
0723     movieStatus.soundDescription(reference_index).type = type;
0724     movieStatus.soundDescription(reference_index).channels = num_channels;
0725     movieStatus.soundDescription(reference_index).bits = num_bits;
0726     movieStatus.soundDescription(reference_index).sample_rate = sample_rate;
0727 %         struct('type', type, ...
0728 %             'channels', num_channels, ...
0729 %             'bits', num_bits, ...
0730 %             'sample_rate', sample_rate);
0731 
0732 case 'vide',
0733     Read32Bits(fp);            % Version/Revision
0734     Read32Bits(fp);            % Vendor
0735     tqual = Read32Bits(fp);        % Temporal Quality
0736     squal = Read32Bits(fp);        % Spatial Quality
0737     width = Read16Bits(fp);        % Width of source image
0738     height = Read16Bits(fp);    % Height of source image
0739     hres = Read16Bits(fp);
0740     vres = Read16Bits(fp);
0741     Read32Bits(fp);            % Data size (ignored)
0742     fcount = Read16Bits(fp);    % Frames per sample (usually 1)
0743     place = place + 30;
0744 
0745     if(isempty(movieStatus.videoDescription))
0746         movieStatus.videoDescription = ...
0747             repmat(struct('type',[],'tqual',[],'squal',[],...
0748                           'width',[],'height',[]),1,1);
0749     else
0750         movieStatus.videoDescription(end+1)=movieStatus.videoDescription(end);
0751     end
0752     movieStatus.videoDescription(reference_index).type = type;
0753     movieStatus.videoDescription(reference_index).tqual = tqual;
0754     movieStatus.videoDescription(reference_index).squal = squal;
0755     movieStatus.videoDescription(reference_index).width = width;
0756     movieStatus.videoDescription(reference_index).height = height;
0757 
0758 %     movieStatus.videoDescription(reference_index) = ...
0759 %         struct('type', type, ...
0760 %             'tqual', tqual, ...
0761 %             'squal', squal, ...
0762 %             'width', width, ...
0763 %             'height', height);
0764 end
0765 if size-place < 0
0766     error('got out of sync while reading QT sample description.');
0767 end
0768 fseek(fp, size-place, 'cof');
0769 
0770 
0771 
0772 
0773 
0774 %%%%%%%%%%%%%%%  Read32Bits  %%%%%%%%%%%%%%%%%
0775 function i = Read32Bits(fp, count)
0776 if nargin < 2
0777     count = 1;
0778 end
0779 i = fread(fp, count, 'int32');
0780 
0781 %%%%%%%%%%%%%%%  Read16Bits  %%%%%%%%%%%%%%%%%
0782 function i = Read16Bits(fp, count)
0783 if nargin < 2
0784     count = 1;
0785 end
0786 i = fread(fp, count, 'int16');
0787 
0788 function i = Read4ByteString(fp)
0789 i = char(fread(fp, 4, 'int8')');

Generated on Tue 27-Mar-2007 12:06:24 by m2html © 2003