Home > fcn > DIVA_GUI_toolbox > MakeQTMovie.m

MakeQTMovie

PURPOSE ^

function MakeQTMovie(cmd, arg, arg2)

SYNOPSIS ^

function MakeQTMovie(cmd,arg, arg2)

DESCRIPTION ^

 function MakeQTMovie(cmd, arg, arg2)
 Create a QuickTime movie from a bunch of figures (and an optional sound).

 Syntax: MakeQTMovie cmd [arg]
 The following commands are supported:
    addfigure - Add snapshot of current figure to movie
     addaxes - Add snapshot of current axes to movie
    addmatrix data - Add a matrix to movie (convert to jpeg with imwrite)
    addmatrixsc data - Add a matrix to movie (convert to jpeg with imwrite)
        (automatically scales image data)
    addsound data [sr] - Add sound to movie (only monaural for now)
        (third argument is the sound's sample rate.)
    cleanup - Remove the temporary files
    demo - Create a demonstration movie
     finish - Finish movie, write out QT file
    framerate fps - Set movies frame rate [Default is 10 fps]
    quality # - Set JPEG quality (between 0 and 1)
     size [# #] - Set plot size to [width height]
     start filename - Start creating a movie with this name
 The start command must be called first to provide a movie name.
 The finish command must be called last to write out the movie
 data. All other commands can be called in any order.  Only one
 movie can be created at a time.

 This code is published as Interval Technical Report #1999-066
 The latest copy can be found at 
    http://web.interval.com/papers/1999-066/
 (c) Copyright Malcolm Slaney, Interval Research, March 1999.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function MakeQTMovie(cmd,arg, arg2)
0002 % function MakeQTMovie(cmd, arg, arg2)
0003 % Create a QuickTime movie from a bunch of figures (and an optional sound).
0004 %
0005 % Syntax: MakeQTMovie cmd [arg]
0006 % The following commands are supported:
0007 %    addfigure - Add snapshot of current figure to movie
0008 %     addaxes - Add snapshot of current axes to movie
0009 %    addmatrix data - Add a matrix to movie (convert to jpeg with imwrite)
0010 %    addmatrixsc data - Add a matrix to movie (convert to jpeg with imwrite)
0011 %        (automatically scales image data)
0012 %    addsound data [sr] - Add sound to movie (only monaural for now)
0013 %        (third argument is the sound's sample rate.)
0014 %    cleanup - Remove the temporary files
0015 %    demo - Create a demonstration movie
0016 %     finish - Finish movie, write out QT file
0017 %    framerate fps - Set movies frame rate [Default is 10 fps]
0018 %    quality # - Set JPEG quality (between 0 and 1)
0019 %     size [# #] - Set plot size to [width height]
0020 %     start filename - Start creating a movie with this name
0021 % The start command must be called first to provide a movie name.
0022 % The finish command must be called last to write out the movie
0023 % data. All other commands can be called in any order.  Only one
0024 % movie can be created at a time.
0025 %
0026 % This code is published as Interval Technical Report #1999-066
0027 % The latest copy can be found at
0028 %    http://web.interval.com/papers/1999-066/
0029 % (c) Copyright Malcolm Slaney, Interval Research, March 1999.
0030 
0031 % This is experimental software and is being provided to Licensee
0032 % 'AS IS.'  Although the software has been tested on Macintosh, SGI,
0033 % Linux, and Windows machines, Interval makes no warranties relating
0034 % to the software's performance on these or any other platforms.
0035 %
0036 % Disclaimer
0037 % THIS SOFTWARE IS BEING PROVIDED TO YOU 'AS IS.'  INTERVAL MAKES
0038 % NO EXPRESS, IMPLIED OR STATUTORY WARRANTY OF ANY KIND FOR THE
0039 % SOFTWARE INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY OF
0040 % PERFORMANCE, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
0041 % IN NO EVENT WILL INTERVAL BE LIABLE TO LICENSEE OR ANY THIRD
0042 % PARTY FOR ANY DAMAGES, INCLUDING LOST PROFITS OR OTHER INCIDENTAL
0043 % OR CONSEQUENTIAL DAMAGES, EVEN IF INTERVAL HAS BEEN ADVISED OF
0044 % THE POSSIBLITY THEREOF.
0045 %
0046 %   This software program is owned by Interval Research
0047 % Corporation, but may be used, reproduced, modified and
0048 % distributed by Licensee.  Licensee agrees that any copies of the
0049 % software program will contain the same proprietary notices and
0050 % warranty disclaimers which appear in this software program.
0051 
0052 % This program uses the Matlab imwrite routine to convert each image
0053 % frame into JPEG.  After first reserving 8 bytes for a header that points
0054 % to the movie description, all the compressed images and the sound are
0055 % added to the movie file.  When the 'finish' method is called then the
0056 % first 8 bytes of the header are rewritten to indicate the size of the
0057 % movie data, and then the movie header ('moov structure') is written
0058 % to the output file.
0059 %
0060 % This routine creates files according to the QuickTime file format as
0061 % described in the appendix of
0062 %    "Quicktime (Inside MacIntosh)," Apple Computer Incorporated,
0063 %    Addison-Wesley Pub Co; ISBN: 0201622017, April 1993.
0064 % I appreciate help that I received from Lee Fyock (MathWorks) and Aaron
0065 % Hertzmann (Interval) in debugging and testing this work.
0066 
0067 % Changes:
0068 % July 5, 1999 - Removed stss atom since it upset PC version of QuickTime
0069 % November 11, 1999 - Fixed quality bug in addmatrix.  Added addmatrixsc.
0070 % March 7, 2000 - by Jordan Rosenthal (jr@ece.gatech.edu), Added truecolor
0071 %    capability when running in Matlab 5.3 changed some help comments, fixed
0072 %    some bugs, vectorized some code.
0073 % April 7, 2000 - by Malcolm.  Cleaned up axis/figure code and fixed(?) SGI
0074 %    playback problems.  Added user data atom to give version information.
0075 %    Fixed sound format problems.
0076 % April 10, 2000 - by Malcolm. Fixed problem with SGI (at least) and B&W
0077 %    addmatrix.
0078 
0079 if nargin < 1
0080     fprintf('Syntax: MakeQTMovie cmd [arg]\n')
0081     fprintf('The following commands are supported:\n');
0082     fprintf('    addfigure - Add snapshot of current figure to movie\n')
0083     fprintf('    addaxes - Add snapshot of current axes to movie\n')
0084     fprintf('    addmatrix data - Add a matrix to movie ');
0085             fprintf('(convert to jpeg)\n')
0086     fprintf('    addmatrixsc data - Add a matrix to movie ');
0087             fprintf('(scale and convert to jpeg)\n')
0088     fprintf('    addsound data - Add sound samples ');
0089             fprintf('(with optional rate)\n')
0090     fprintf('    demo - Show this program in action\n');
0091     fprintf('    finish - Finish movie, write out QT file\n');
0092     fprintf('    framerate # - Set movie frame rate ');
0093             fprintf('(default is 10fps)\n');
0094     fprintf('    quality # - Set JPEG quality (between 0 and 1)\n');
0095     fprintf('    size [# #] - Set plot size to [width height]\n');
0096     fprintf('    start filename - Start making a movie with ');
0097             fprintf('this name\n');
0098     return;
0099 end
0100 
0101 global MakeQTMovieStatus
0102 MakeDefaultQTMovieStatus;        % Needed first time, ignored otherwise
0103 
0104 if(~isfield(MakeQTMovieStatus,'imageTmp'))
0105     MakeQTMovieStatus.imageTmp='tmp.jpg';
0106 end
0107 
0108 switch lower(cmd)
0109 case {'addframe','addplot','addfigure','addaxes'}
0110     switch lower(cmd)
0111     case {'addframe','addfigure'}
0112         hObj = gcf;        % Add the entire figure (with all axes)
0113     otherwise
0114         hObj = gca;        % Add what's inside the current axis
0115     end
0116     frame = getframe(hObj);
0117     [I,map] = frame2im(frame);
0118     if ImageSizeChanged(size(I)) > 0
0119         return;
0120     end
0121     if isempty(map)
0122                     % RGB image
0123           imwrite(I,MakeQTMovieStatus.imageTmp, 'jpg', 'Quality', ...
0124          MakeQTMovieStatus.spatialQual*100);
0125     else
0126                     % Indexed image
0127         writejpg_map(MakeQTMovieStatus.imageTmp, I, map);
0128     end
0129     [pos, len] = AddFileToMovie;
0130     if(~isfield(MakeQTMovieStatus,'frameNumber'))
0131         MakeQTMovieStatus.frameNumber=0;
0132     end 
0133     n = MakeQTMovieStatus.frameNumber + 1;
0134     MakeQTMovieStatus.frameNumber = n;
0135     MakeQTMovieStatus.frameStarts(n) = pos;
0136     MakeQTMovieStatus.frameLengths(n) = len;
0137    
0138 %% Allow images to be added by doing:
0139 %%    MakeQTMovie('addimage', '/path/to/file.jpg');
0140 %% This case adapted from addmatrix.  Thanks to
0141 %% Stephen Eglen <stephen@cogsci.ed.ac.uk> for this idea.
0142 case 'addimage'
0143     if nargin < 2
0144         fprintf('MakeQTMovie error: Need to specify a filename with ');
0145         fprintf('the image command.\n');
0146         return;
0147     end
0148 
0149         %% Check to see that the image is the correct size.  Do
0150         %% this by reading in the image and then checking its size.
0151     %% tim - temporary image.
0152         tim = imread(arg); tim_size = size(tim);
0153     
0154     fprintf('Image %s size %d %d\n', arg, tim_size(1), tim_size(2));
0155      if ImageSizeChanged(tim_size) > 0
0156          return;
0157      end
0158     [pos, len] = AddFileToMovie(arg);
0159     n = MakeQTMovieStatus.frameNumber + 1;
0160     MakeQTMovieStatus.frameNumber = n;
0161     MakeQTMovieStatus.frameStarts(n) = pos;
0162     MakeQTMovieStatus.frameLengths(n) = len;
0163 
0164 case 'addmatrix'
0165     if nargin < 2
0166         fprintf('MakeQTMovie error: Need to specify a matrix with ');
0167         fprintf('the addmatrix command.\n');
0168         return;
0169     end
0170     if ImageSizeChanged(size(arg)) > 0
0171         return;
0172     end
0173                     % Work around a bug, at least on the
0174                     % SGIs, which causes JPEGs to be
0175                     % written which can't be read with the
0176                     % SGI QT.  Turn the B&W image into a
0177                     % color matrix.
0178     if ndims(arg) < 3
0179         arg(:,:,2) = arg;
0180         arg(:,:,3) = arg(:,:,1);
0181     end
0182     imwrite(arg, MakeQTMovieStatus.imageTmp, 'jpg', 'Quality', ...
0183         MakeQTMovieStatus.spatialQual*100);
0184     [pos, len] = AddFileToMovie;
0185     n = MakeQTMovieStatus.frameNumber + 1;
0186     MakeQTMovieStatus.frameNumber = n;
0187     MakeQTMovieStatus.frameStarts(n) = pos;
0188     MakeQTMovieStatus.frameLengths(n) = len;
0189     
0190 case 'addmatrixsc'
0191     if nargin < 2
0192         fprintf('MakeQTMovie error: Need to specify a matrix with ');
0193         fprintf('the addmatrix command.\n');
0194         return;
0195     end
0196     if ImageSizeChanged(size(arg)) > 0
0197         return;
0198     end
0199     arg = arg - min(min(arg));
0200     arg = arg / max(max(arg));
0201                     % Work around a bug, at least on the
0202                     % SGIs, which causes JPEGs to be
0203                     % written which can't be read with the
0204                     % SGI QT.  Turn the B&W image into a
0205                     % color matrix.
0206     if ndims(arg) < 3
0207         arg(:,:,2) = arg;
0208         arg(:,:,3) = arg(:,:,1);
0209     end
0210     imwrite(arg, MakeQTMovieStatus.imageTmp, 'jpg', 'Quality', ...
0211         MakeQTMovieStatus.spatialQual*100);
0212     [pos, len] = AddFileToMovie;
0213     n = MakeQTMovieStatus.frameNumber + 1;
0214     MakeQTMovieStatus.frameNumber = n;
0215     MakeQTMovieStatus.frameStarts(n) = pos;
0216     MakeQTMovieStatus.frameLengths(n) = len;
0217 
0218 case 'addsound'
0219     if nargin < 2
0220         fprintf('MakeQTMovie error: Need to specify a sound array ');
0221         fprintf('with the addsound command.\n');
0222         return;
0223     end
0224                     % Do stereo someday???
0225     OpenMovieFile
0226     MakeQTMovieStatus.soundLength = length(arg);
0227     arg = round(arg/max(max(abs(arg)))*32765);
0228     negs = find(arg<0);
0229     arg(negs) = arg(negs) + 65536;
0230 
0231     sound = mb16(arg);
0232     MakeQTMovieStatus.soundStart = ftell(MakeQTMovieStatus.movieFp);
0233     MakeQTMovieStatus.soundLen = length(sound);
0234     fwrite(MakeQTMovieStatus.movieFp, sound, 'uchar');
0235     if nargin < 3
0236         arg2 = 22050;
0237     end
0238     MakeQTMovieStatus.soundRate = arg2;
0239     
0240 case 'cleanup'
0241     if isstruct(MakeQTMovieStatus)
0242         if(isfield(MakeQTMovieStatus,'moveFp')),
0243         if ~isempty(MakeQTMovieStatus.movieFp)
0244             fclose(MakeQTMovieStatus.movieFp);
0245             MakeQTMovieStatus.movieFp = [];
0246         end
0247         else
0248             MakeQTMovieStatus.movieFp=[];
0249         end 
0250         
0251         if(isfield(MakeQTMovieStatus,'imageTmp'))
0252         if ~isempty(MakeQTMovieStatus.imageTmp) & ...
0253            exist(MakeQTMovieStatus.imageTmp,'file') > 0
0254             delete(MakeQTMovieStatus.imageTmp);
0255             MakeQTMovieStatus.imageTmp = [];
0256         end
0257         else
0258             MakeQTMovieStatus.imageTmp=[];
0259         end
0260     end
0261     MakeQTMovieStatus = [];
0262 
0263 case 'debug'
0264     fprintf('Current Movie Data:\n');
0265     fprintf('    %d frames at %d fps\n', MakeQTMovieStatus.frameNumber, ...
0266                     MakeQTMovieStatus.frameRate);
0267     starts = MakeQTMovieStatus.frameStarts;
0268     if length(starts) > 10, starts = starts(1:10);, end;
0269     lens = MakeQTMovieStatus.frameLengths;
0270     if length(lens) > 10, lens = lens(1:10);, end;
0271     fprintf('         Start: %6d      Size: %6d\n', [starts; lens]);
0272     fprintf('    Movie Image Size: %dx%d\n', ...
0273         MakeQTMovieStatus.imageSize(2), ...);
0274         MakeQTMovieStatus.imageSize(1));
0275     if length(MakeQTMovieStatus.soundStart) > 0  
0276         fprintf('    Sound: %d samples at %d Hz sampling rate ', ...
0277             MakeQTMovieStatus.soundLength, ...
0278             MakeQTMovieStatus.soundRate);
0279         fprintf('at %d.\n', MakeQTMovieStatus.soundStart);
0280     else
0281         fprintf('    Sound: No sound track\n');
0282     end
0283     fprintf('    Temporary files for images: %s\n', ...
0284         MakeQTMovieStatus.imageTmp);
0285     fprintf('    Final movie name: %s\n', MakeQTMovieStatus.movieName);
0286     fprintf('    Compression Quality: %g\n', ...
0287         MakeQTMovieStatus.spatialQual);
0288 
0289 
0290 case 'demo'
0291     clf
0292     fps = 10;
0293     movieLength = 10;
0294     sr = 22050;
0295     fn = 'test.mov';
0296     fprintf('Creating the movie %s.\n', fn);
0297     MakeQTMovie('start',fn);
0298     MakeQTMovie('size', [160 120]);
0299     MakeQTMovie('quality', 1.0);
0300     theSound = [];
0301     for i=1:movieLength
0302         plot(sin((1:100)/4+i));
0303         MakeQTMovie('addaxes');
0304         theSound = [theSound sin(440/sr*2*pi*(2^(i/12))*(1:sr/fps))];
0305     end
0306     MakeQTMovie('framerate', fps);
0307     MakeQTMovie('addsound', theSound, sr);
0308     MakeQTMovie('finish');
0309 
0310 case {'finish','close'}
0311     AddQTHeader;
0312     MakeQTMovie('cleanup')            % Remove temporary files
0313 
0314 case 'framerate'
0315     if nargin < 2
0316         fprintf('MakeQTMovie error: Need to specify the ');
0317         fprintf('frames/second with the framerate command.\n');
0318         return;
0319     end
0320     MakeQTMovieStatus.frameRate = arg;
0321 
0322 case 'help'
0323     MakeQTMovie                % To get help message.
0324 
0325 case 'size'
0326                         % Size is off by one on the
0327                         % Mac.
0328     if nargin < 2
0329         fprintf('MakeQTMovie error: Need to specify a vector with ');
0330         fprintf('the size command.\n');
0331         return;
0332     end
0333     if length(arg) ~= 2
0334         error('MakeQTMovie: Error, must supply 2 element size.');
0335     end
0336     oldUnits = get(gcf,'units');
0337     set(gcf,'units','pixels');
0338     cursize = get(gcf, 'position');
0339     cursize(3) = arg(1);
0340     cursize(4) = arg(2);
0341     set(gcf, 'position', cursize);
0342     set(gcf,'units',oldUnits);
0343     %MakeQTMovieStatus.imageSize=arg;
0344 case 'start'
0345     if nargin < 2
0346         fprintf('MakeQTMovie error: Need to specify a file name ');
0347         fprintf('with start command.\n');
0348         return;
0349     end
0350     MakeQTMovie('cleanup');
0351     MakeDefaultQTMovieStatus;
0352     MakeQTMovieStatus.movieName = arg;
0353     
0354 case 'test'
0355     clf
0356     MakeQTMovieStatus = [];
0357     MakeQTMovie('start','test.mov');
0358      MakeQTMovie('size', [320 240]);
0359     MakeQTMovie('quality', 1.0);
0360     subplot(2,2,1);
0361     for i=1:10
0362         plot(sin((1:100)/4+i));
0363         MakeQTMovie('addfigure');
0364     end
0365     MakeQTMovie('framerate', 10);
0366     MakeQTMovie('addsound', sin(1:5000), 22050);
0367     MakeQTMovie('debug');
0368     MakeQTMovie('finish');
0369     
0370 case 'quality'
0371     if nargin < 2
0372         fprintf('MakeQTMovie error: Need to specify a quality ');
0373         fprintf('(between 0-1) with the quality command.\n');
0374         return;
0375     end
0376     MakeQTMovieStatus.spatialQual = arg;
0377 
0378 otherwise
0379     fprintf('MakeQTMovie: Unknown method %s.\n', cmd);
0380 end
0381 
0382 %%%%%%%%%%%%%%%  MakeDefaultQTMovieStatus %%%%%%%%%%%%%%%%%
0383 % Make the default movie status structure.
0384 function MakeDefaultQTMovieStatus
0385 global MakeQTMovieStatus
0386 if isempty(MakeQTMovieStatus)
0387    MakeQTMovieStatus = struct(...
0388       'frameRate', 10, ...    % frames per second
0389       'frameStarts', [], ...  % Starting byte position
0390       'frameLengths', [], ...
0391       'timeScale', 10, ...    % How much faster does time run?
0392       'soundRate', 22050, ... % Sound Sample Rate
0393       'soundStart', [], ...    % Starting byte position
0394       'soundLength', 0, ...
0395       'soundChannels', 1, ...    % Number of channels
0396       'frameNumber', 0, ...
0397       'movieFp', [], ...        % File pointer 
0398       'imageTmp', tempname, ...
0399       'movieName', 'output.mov', ...
0400       'imageSize', [0 0], ...
0401       'trackNumber', 0, ...
0402       'timeScaleExpansion', 100, ...
0403       'spatialQual', 1.0);    % Between 0.0 and 1.0
0404 end
0405 
0406 
0407 %%%%%%%%%%%%%%%  ImageSizeChanged %%%%%%%%%%%%%%%%%
0408 % Check to see if the image size has changed.  This m-file can't
0409 % deal with that, so we'll return an error.
0410 function err = ImageSizeChanged(newsize)
0411 global MakeQTMovieStatus
0412 
0413 newsize = newsize(1:2);            % Don't care about RGB info, if present
0414 if(isfield(MakeQTMovieStatus,'imageSize'))
0415     oldsize = MakeQTMovieStatus.imageSize;
0416 else
0417     oldsize=newsize;
0418     MakeQTMovieStatus.imageSize=oldsize;
0419 end
0420 err = 0;
0421 
0422 if sum(oldsize) == 0
0423     MakeQTMovieStatus.imageSize = newsize;
0424 else
0425     if sum(newsize ~= oldsize) > 0
0426         fprintf('MakeQTMovie Error: New image size');
0427         fprintf('(%dx%d) doesn''t match old size (%dx%d)\n', ...
0428             newsize(1), newsize(2), oldsize(1), oldsize(2));
0429         fprintf('   Can''t add this image to the movie.\n');
0430         err = 1;
0431     end
0432 end
0433 
0434 %%%%%%%%%%%%%%%  AddFileToMovie %%%%%%%%%%%%%%%%%
0435 % OK, we've saved out an image file.  Now add it to the end of the movie
0436 % file we are creating.
0437 % We'll copy the JPEG file in 16kbyte chunks to the end of the movie file.
0438 % Keep track of the start and end byte position in the file so we can put
0439 % the right information into the QT header.
0440 function [pos, len] = AddFileToMovie(imageTmp)
0441 global MakeQTMovieStatus
0442 OpenMovieFile
0443 if nargin < 1
0444     imageTmp = MakeQTMovieStatus.imageTmp;
0445 end
0446 fp = fopen(imageTmp, 'rb');
0447 if fp < 0
0448     error('Could not reopen QT image temporary file.');
0449 end
0450 
0451 len = 0;
0452 pos = ftell(MakeQTMovieStatus.movieFp);
0453 while 1
0454     data = fread(fp, 1024*16, 'uchar');
0455     if isempty(data)
0456         break;
0457     end
0458     cnt = fwrite(MakeQTMovieStatus.movieFp, data, 'uchar');
0459     len = len + cnt;
0460 end
0461 fclose(fp);
0462 
0463 %%%%%%%%%%%%%%%  AddQTHeader %%%%%%%%%%%%%%%%%
0464 % Go back and write the atom information that allows
0465 % QuickTime to skip the image and sound data and find
0466 % its movie description information.
0467 function AddQTHeader()
0468 global MakeQTMovieStatus
0469 
0470 pos = ftell(MakeQTMovieStatus.movieFp);
0471 header = moov_atom;
0472 cnt = fwrite(MakeQTMovieStatus.movieFp, header, 'uchar');
0473 fseek(MakeQTMovieStatus.movieFp, 0, -1);
0474 cnt = fwrite(MakeQTMovieStatus.movieFp, mb32(pos), 'uchar');
0475 fclose(MakeQTMovieStatus.movieFp);
0476 MakeQTMovieStatus.movieFp = [];
0477 
0478 %%%%%%%%%%%%%%%  OpenMovieFile %%%%%%%%%%%%%%%%%
0479 % Open a new movie file.  Write out the initial QT header.  We'll fill in
0480 % the correct length later.
0481 function OpenMovieFile
0482 global MakeQTMovieStatus
0483 if(isfield(MakeQTMovieStatus,'movieFp')),
0484     if isempty(MakeQTMovieStatus.movieFp)
0485         fp = fopen(MakeQTMovieStatus.movieName, 'wb');
0486         if fp < 0
0487             error('Could not open QT movie output file.');
0488         end
0489         MakeQTMovieStatus.movieFp = fp;
0490         cnt = fwrite(fp, [mb32(0) mbstring('mdat')], 'uchar');
0491     end
0492 else
0493     fp = fopen(MakeQTMovieStatus.movieName,'wb');
0494     if(fp<0)
0495             error('Could not open QT movie output file.');
0496     end
0497     MakeQTMovieStatus.movieFp=fp;
0498     cnt=fwrite(fp,[mb32(0) mbstring('mdat')], 'uchar');
0499 end
0500 
0501 %%%%%%%%%%%%%%%  writejpg_map %%%%%%%%%%%%%%%%%
0502 % Like the imwrite routine, but first pass the image data through the indicated
0503 % RGB map.
0504 function writejpg_map(name,I,map)
0505 global MakeQTMovieStatus
0506 
0507 [y,x] = size(I);
0508 
0509 % Force values to be valid indexes.  This fixes a bug that occasionally
0510 % occurs in frame2im in Matlab 5.2 which incorrectly produces values of I
0511 % equal to zero.
0512 I = max(1,min(I,size(map,1)));
0513 
0514 rgb = zeros(y, x, 3);
0515 t = zeros(y,x);
0516 t(:) = map(I(:),1)*255; rgb(:,:,1) = t;
0517 t(:) = map(I(:),2)*255; rgb(:,:,2) = t;
0518 t(:) = map(I(:),3)*255; rgb(:,:,3) = t;
0519 
0520 imwrite(uint8(rgb),name,'jpeg','Quality',MakeQTMovieStatus.spatialQual*100);
0521 
0522 %%%%%%%%%%%%%%%  SetAtomSize %%%%%%%%%%%%%%%%%
0523 % Fill in the size of the atom
0524 function y=SetAtomSize(x)
0525 y = x;
0526 y(1:4) = mb32(length(x));
0527 
0528 %%%%%%%%%%%%%%%  mb32 %%%%%%%%%%%%%%%%%
0529 % Make a vector from a 32 bit integer
0530 function y = mb32(x)                
0531 if size(x,1) > size(x,2)
0532     x = x';
0533 end
0534 
0535 y = [bitand(bitshift(x,-24),255); ...
0536      bitand(bitshift(x,-16),255); ...
0537      bitand(bitshift(x, -8),255); ...
0538      bitand(x,              255)];
0539 y = y(:)';
0540 
0541 %%%%%%%%%%%%%%%  mb16 %%%%%%%%%%%%%%%%%
0542 % Make a vector from a 16 bit integer
0543 function y = mb16(x)
0544 if size(x,1) > size(x,2)
0545     x = x';
0546 end
0547 
0548 y = [bitand(bitshift(x, -8),255); ...
0549      bitand(x,              255)];
0550 y = y(:)';
0551 
0552 %%%%%%%%%%%%%%%  mb8 %%%%%%%%%%%%%%%%%
0553 % Make a vector from a 8 bit integer
0554 function y = mb8(x)
0555 if size(x,1) > size(x,2)
0556     x = x';
0557 end
0558 
0559 y = [bitand(x,              255)];
0560 y = y(:)';
0561 
0562 %
0563 % The following routines all create atoms necessary
0564 % to describe a QuickTime Movie. The basic idea is to
0565 % fill in the necessary data, all converted to 8 bit
0566 % characters, then fix it up later with SetAtomSize so
0567 % that it has the correct header.  (This is easier than
0568 % counting by hand.)
0569 
0570 %%%%%%%%%%%%%%%  mbstring %%%%%%%%%%%%%%%%%
0571 % Make a vector from a character string
0572 function y = mbstring(s)
0573 y = double(s);
0574 
0575 
0576 %%%%%%%%%%%%%%%  dinf_atom %%%%%%%%%%%%%%%%%
0577 function y = dinf_atom()
0578 y = SetAtomSize([mb32(0) mbstring('dinf') dref_atom]);
0579 
0580 %%%%%%%%%%%%%%%  dref_atom %%%%%%%%%%%%%%%%%
0581 function y = dref_atom()
0582 y = SetAtomSize([mb32(0) mbstring('dref') mb32(0) mb32(1) ...
0583         mb32(12) mbstring('alis') mb32(1)]);
0584 
0585 %%%%%%%%%%%%%%%  edts_atom %%%%%%%%%%%%%%%%%
0586 function y = edts_atom(add_sound_p)
0587 global MakeQTMovieStatus
0588 fixed1 = bitshift(1,16);            % Fixed point 1
0589 if add_sound_p > 0
0590     duration = MakeQTMovieStatus.soundLength / ...
0591             MakeQTMovieStatus.soundRate * ...
0592             MakeQTMovieStatus.timeScale;
0593 else
0594     duration = MakeQTMovieStatus.frameNumber / ...
0595             MakeQTMovieStatus.frameRate * ...
0596             MakeQTMovieStatus.timeScale;
0597 end
0598 duration = ceil(duration);
0599 
0600 y = [mb32(0) ...                % Atom Size
0601      mbstring('edts') ...            % Atom Name
0602      SetAtomSize([mb32(0) ...            % Atom Size
0603           mbstring('elst') ...        % Atom Name
0604           mb32(0) ...            % Version/Flags
0605           mb32(1) ...            % Number of entries
0606           mb32(duration) ...        % Length of this track
0607           mb32(0) ...            % Time
0608           mb32(fixed1)])];        % Rate
0609 y = SetAtomSize(y);
0610 
0611 %%%%%%%%%%%%%%%  hdlr_atom %%%%%%%%%%%%%%%%%
0612 function y = hdlr_atom(component_type, sub_type)
0613 if strcmp(sub_type, 'vide')
0614     type_string = 'Apple Video Media Handler';
0615 elseif strcmp(sub_type, 'alis')
0616     type_string = 'Apple Alias Data Handler';
0617 elseif strcmp(sub_type, 'soun')
0618     type_string = 'Apple Sound Media Handler';
0619 end
0620 
0621 y = [mb32(0) ...                % Atom Size
0622      mbstring('hdlr') ...            % Atom Name
0623      mb32(0) ...                % Version and Flags
0624      mbstring(component_type) ...        % Component Name
0625      mbstring(sub_type) ...            % Sub Type Name
0626      mbstring('appl') ...            % Component manufacturer
0627      mb32(0) ...                % Component flags
0628      mb32(0) ...                % Component flag mask
0629      mb8(length(type_string)) ...        % Type Name byte count
0630      mbstring(type_string)];            % Type Name
0631 y = SetAtomSize(y);
0632 
0633 %%%%%%%%%%%%%%%  mdhd_atom %%%%%%%%%%%%%%%%%
0634 function y = mdhd_atom(add_sound_p)
0635 global MakeQTMovieStatus
0636 
0637 if add_sound_p
0638     data = [mb32(MakeQTMovieStatus.soundRate)  ...
0639         mb32(MakeQTMovieStatus.soundLength)];
0640 else
0641     data = [mb32(MakeQTMovieStatus.frameRate * ...
0642             MakeQTMovieStatus.timeScaleExpansion)  ...
0643         mb32(MakeQTMovieStatus.frameNumber * ...
0644             MakeQTMovieStatus.timeScaleExpansion)];
0645 end
0646 
0647 y = [mb32(0) mbstring('mdhd') ...        % Atom Header
0648      mb32(0) ...
0649      mb32(round(now*3600*24)) ...        % Creation time
0650      mb32(round(now*3600*24)) ...        % Modification time
0651      data ...
0652      mb16(0) mb16(0)];
0653 y = SetAtomSize(y);
0654  
0655 %%%%%%%%%%%%%%%  mdia_atom %%%%%%%%%%%%%%%%%
0656 function y = mdia_atom(add_sound_p)
0657 global MakeQTMovieStatus
0658  
0659 if add_sound_p
0660     hdlr = hdlr_atom('mhlr', 'soun');
0661 else
0662     hdlr = hdlr_atom('mhlr', 'vide');
0663 end
0664 
0665 y = [mb32(0) mbstring('mdia') ...        % Atom Header
0666      mdhd_atom(add_sound_p) ...
0667      hdlr ...                    % Handler Atom
0668      minf_atom(add_sound_p)];
0669 y = SetAtomSize(y);
0670 
0671 
0672 %%%%%%%%%%%%%%%  minf_atom %%%%%%%%%%%%%%%%%
0673 function y = minf_atom(add_sound_p)
0674 global MakeQTMovieStatus
0675  
0676 if add_sound_p
0677     data = smhd_atom;
0678 else
0679     data = vmhd_atom;
0680 end
0681 
0682 y = [mb32(0) mbstring('minf') ...        % Atom Header
0683      data ...
0684      hdlr_atom('dhlr','alis') ...
0685      dinf_atom ...
0686      stbl_atom(add_sound_p)];
0687 y = SetAtomSize(y);
0688 
0689 %%%%%%%%%%%%%%%  moov_atom %%%%%%%%%%%%%%%%%
0690 function y=moov_atom
0691 global MakeQTMovieStatus
0692 if(~isfield(MakeQTMovieStatus,'timeScaleExpansion'))
0693     MakeQTMovieStatus.timeScaleExpansion=100;
0694 end
0695 MakeQTMovieStatus.timeScale = MakeQTMovieStatus.frameRate * ...
0696                 MakeQTMovieStatus.timeScaleExpansion;
0697 
0698 if(~isfield(MakeQTMovieStatus,'soundLength'))
0699     MakeQTMovieStatus.soundLength=0;
0700 end
0701 if MakeQTMovieStatus.soundLength > 0
0702     sound = trak_atom(1);
0703 else
0704     sound = [];
0705 end
0706 
0707 y = [mb32(0) mbstring('moov') ...
0708      mvhd_atom udat_atom sound trak_atom(0) ];
0709 y = SetAtomSize(y);
0710 
0711 %%%%%%%%%%%%%%%  mvhd_atom %%%%%%%%%%%%%%%%%
0712 function y=mvhd_atom
0713 global MakeQTMovieStatus
0714 
0715 fixed1 = bitshift(1,16);            % Fixed point 1
0716 frac1 = bitshift(1,30);                % Fractional 1
0717 
0718 if(~isfield(MakeQTMovieStatus,'soundStart'))
0719     MakeQTMovieStatus.soundStart=0;
0720 end
0721 
0722 if length(MakeQTMovieStatus.soundStart) > 0        
0723     NumberOfTracks = 2;
0724 else
0725     NumberOfTracks = 1;
0726 end
0727 
0728 if(~isfield(MakeQTMovieStatus,'soundRate'))
0729     MakeQTMovieStatus.soundRate=22050;
0730 end
0731 
0732                     % Need to make sure its longer
0733                     % of movie and sound lengths
0734 MovieDuration = max(MakeQTMovieStatus.frameNumber / ...
0735             MakeQTMovieStatus.frameRate, ...
0736             MakeQTMovieStatus.soundLength / ...
0737             MakeQTMovieStatus.soundRate);
0738 MovieDuration = ceil(MovieDuration * MakeQTMovieStatus.timeScale);
0739 
0740 y = [mb32(0) ...            % Size
0741      mbstring('mvhd') ...        % Movie Data
0742      mb32(0) ...            % Version and Flags
0743      mb32(0) ...            % Creation Time (unknown)
0744      mb32(0) ...            % Modification Time (unknown)
0745      mb32(MakeQTMovieStatus.timeScale) ...    % Movie's Time Scale
0746      mb32(MovieDuration) ...        % Movie Duration 
0747      mb32(fixed1) ...            % Preferred Rate
0748      mb16(255) ...            % Preferred Volume
0749      mb16(0) ...            % Fill
0750      mb32(0) ...            % Fill
0751      mb32(0) ...            % Fill
0752      mb32(fixed1) mb32(0) mb32(0) ...    % Transformation matrix (identity)
0753      mb32(0) mb32(fixed1) mb32(0) ...
0754      mb32(0) mb32(0) mb32(frac1) ...
0755      mb32(0) ...            % Preview Time
0756      mb32(0) ...            % Preview Duration
0757      mb32(0) ...            % Poster Time
0758      mb32(0) ...            % Selection Time
0759      mb32(0) ...            % Selection Duration
0760      mb32(0) ...            % Current Time
0761      mb32(NumberOfTracks)];        % Video and/or Sound?
0762 
0763 y = SetAtomSize(y);
0764 
0765 %%%%%%%%%%%%%%%  raw_image_description %%%%%%%%%%%%%%%%%
0766 function y = raw_image_description()
0767 global MakeQTMovieStatus
0768 
0769 fixed1 = bitshift(1,16);            % Fixed point 1
0770 codec = [12 'Photo - JPEG                   '];
0771 
0772 y = [mb32(0) mbstring('jpeg') ...        % Atom Header
0773      mb32(0) mb16(0) mb16(0) mb16(0) mb16(1) ...
0774      mbstring('appl') ...
0775      mb32(1023) ...                % Temporal Quality (perfect)
0776      mb32(floor(1023*MakeQTMovieStatus.spatialQual)) ...
0777      mb16(MakeQTMovieStatus.imageSize(2)) ...
0778      mb16(MakeQTMovieStatus.imageSize(1)) ...
0779      mb32(fixed1 * 72) mb32(fixed1 * 72) ...
0780      mb32(0) ...
0781      mb16(0) ...
0782      mbstring(codec) ...
0783      mb16(24) mb16(65535)];
0784 y = SetAtomSize(y);
0785 
0786 
0787 %%%%%%%%%%%%%%%  raw_sound_description %%%%%%%%%%%%%%%%%
0788 function y = raw_sound_description()
0789 global MakeQTMovieStatus
0790 
0791 if(~isfield(MakeQTMovieStatus,'soundChannels'))
0792     MakeQTMovieStatus.soundChannels=1;
0793 end
0794 
0795 y = [mb32(0) mbstring('twos') ...        % Atom Header
0796      mb32(0) mb16(0) mb16(0) mb16(0) mb16(0) ...
0797      mb32(0) ...
0798      mb16(MakeQTMovieStatus.soundChannels) ...
0799      mb16(16) ...                % 16 bits per sample
0800      mb16(0) mb16(0) ...
0801      mb32(round(MakeQTMovieStatus.soundRate*65536))];
0802 y = SetAtomSize(y);
0803 
0804 
0805 %%%%%%%%%%%%%%%  smhd_atom %%%%%%%%%%%%%%%%%
0806 function y = smhd_atom()
0807 y = SetAtomSize([mb32(0) mbstring('smhd') mb32(0) mb16(0) mb16(0)]);
0808 
0809 %%%%%%%%%%%%%%%  stbl_atom %%%%%%%%%%%%%%%%%
0810 % Removed the stss atom since it seems to upset the PC version of QT
0811 % and it is empty so it doesn't add anything.
0812 % Malcolm - July 5, 1999
0813 function y = stbl_atom(add_sound_p)
0814 y = [mb32(0) mbstring('stbl') ...        % Atom Header
0815      stsd_atom(add_sound_p) ...
0816      stts_atom(add_sound_p) ...
0817      stsc_atom(add_sound_p) ...
0818      stsz_atom(add_sound_p) ...
0819      stco_atom(add_sound_p)];
0820 y = SetAtomSize(y);
0821 
0822 %%%%%%%%%%%%%%%  stco_atom %%%%%%%%%%%%%%%%%
0823 function y = stco_atom(add_sound_p)
0824 global MakeQTMovieStatus
0825 if add_sound_p
0826     y = [mb32(0) mbstring('stco') mb32(0) mb32(1) ...
0827          mb32(MakeQTMovieStatus.soundStart)];
0828 else
0829     y = [mb32(0) mbstring('stco') mb32(0) ...
0830          mb32(MakeQTMovieStatus.frameNumber) ...
0831          mb32(MakeQTMovieStatus.frameStarts)];
0832 end
0833 y = SetAtomSize(y);
0834 
0835 %%%%%%%%%%%%%%%  stsc_atom %%%%%%%%%%%%%%%%%
0836 function y = stsc_atom(add_sound_p)
0837 global MakeQTMovieStatus
0838 if add_sound_p
0839     samplesperchunk = MakeQTMovieStatus.soundLength;
0840 else
0841     samplesperchunk = 1;
0842 end
0843 
0844 y = [mb32(0) mbstring('stsc') mb32(0) mb32(1)  ...
0845      mb32(1) mb32(samplesperchunk) mb32(1)];
0846 y = SetAtomSize(y);
0847 
0848 %%%%%%%%%%%%%%%  stsd_atom %%%%%%%%%%%%%%%%%
0849 function y = stsd_atom(add_sound_p)
0850 if add_sound_p
0851     desc = raw_sound_description;
0852 else
0853     desc = raw_image_description;
0854 end
0855 
0856 y = [mb32(0) mbstring('stsd') mb32(0) mb32(1) desc];
0857 y = SetAtomSize(y);
0858 
0859 %%%%%%%%%%%%%%%  stss_atom %%%%%%%%%%%%%%%%%
0860 function y = stss_atom()
0861 y = SetAtomSize([mb32(0) mbstring('stss') mb32(0) mb32(0)]);
0862 
0863 %%%%%%%%%%%%%%%  stsz_atom %%%%%%%%%%%%%%%%%
0864 function y = stsz_atom(add_sound_p)
0865 global MakeQTMovieStatus
0866 if add_sound_p
0867     y = [mb32(0) mbstring('stsz') mb32(0) mb32(2) ...
0868          mb32(MakeQTMovieStatus.soundLength)];
0869 else
0870     y = [mb32(0) mbstring('stsz') mb32(0) mb32(0) ...
0871          mb32(MakeQTMovieStatus.frameNumber) ...
0872          mb32(MakeQTMovieStatus.frameLengths)];
0873 end
0874 y = SetAtomSize(y);
0875 
0876 %%%%%%%%%%%%%%%  stts_atom %%%%%%%%%%%%%%%%%
0877 function y = stts_atom(add_sound_p)
0878 global MakeQTMovieStatus
0879 if add_sound_p
0880     count_duration = [mb32(MakeQTMovieStatus.soundLength) mb32(1)];
0881 else
0882     count_duration = [mb32(MakeQTMovieStatus.frameNumber) ...
0883         mb32(MakeQTMovieStatus.timeScaleExpansion)];
0884 end
0885 
0886 y = SetAtomSize([mb32(0) mbstring('stts') mb32(0) mb32(1) count_duration]);
0887 
0888 %%%%%%%%%%%%%%%  trak_atom %%%%%%%%%%%%%%%%%
0889 function y = trak_atom(add_sound_p)
0890 global MakeQTMovieStatus
0891 
0892 y = [mb32(0) mbstring('trak') ...        % Atom Header
0893     tkhd_atom(add_sound_p) ...        % Track header
0894     edts_atom(add_sound_p) ...        % Edit List
0895     mdia_atom(add_sound_p)];
0896 y = SetAtomSize(y);
0897 
0898 %%%%%%%%%%%%%%%  tkhd_atom %%%%%%%%%%%%%%%%%
0899 function y = tkhd_atom(add_sound_p)
0900 global MakeQTMovieStatus
0901 
0902 fixed1 = bitshift(1,16);            % Fixed point 1
0903 frac1 = bitshift(1,30);                % Fractional 1 (CHECK THIS)
0904 
0905 if add_sound_p > 0
0906     duration = MakeQTMovieStatus.soundLength / ...
0907             MakeQTMovieStatus.soundRate * ...
0908             MakeQTMovieStatus.timeScale;
0909 else
0910     duration = MakeQTMovieStatus.frameNumber / ...
0911             MakeQTMovieStatus.frameRate * ...
0912             MakeQTMovieStatus.timeScale;
0913 end
0914 duration = ceil(duration);
0915 
0916 if(~isfield(MakeQTMovieStatus,'trackNumber'))
0917     MakeQTMovieStatus.trackNumber=0;
0918 end
0919 
0920 y = [mb32(0) mbstring('tkhd') ...    % Atom Header
0921      mb32(15) ...            % Version and flags
0922      mb32(round(now*3600*24)) ...    % Creation time
0923      mb32(round(now*3600*24)) ...    % Modification time
0924      mb32(MakeQTMovieStatus.trackNumber) ...
0925      mb32(0) ...
0926      mb32(duration) ...            % Track duration
0927      mb32(0) mb32(0) ...        % Offset and priority
0928      mb16(0) mb16(0) mb16(255) mb16(0) ...    % Layer, Group, Volume, fill
0929      mb32(fixed1) mb32(0) mb32(0) ...    % Transformation matrix (identity)
0930      mb32(0) mb32(fixed1) mb32(0) ...
0931      mb32(0) mb32(0) mb32(frac1)];
0932 
0933 if add_sound_p
0934     y = [y mb32(0) mb32(0)];    % Zeros for sound
0935 else
0936     if(~isfield(MakeQTMovieStatus,'imageSize'))
0937         MakeQTMovieStatus.imageSize=[0 0];
0938     end
0939     y = [y mb32(fliplr(MakeQTMovieStatus.imageSize)*fixed1)];
0940 end
0941 y= SetAtomSize(y);
0942 
0943 MakeQTMovieStatus.trackNumber = MakeQTMovieStatus.trackNumber + 1;
0944 
0945 %%%%%%%%%%%%%%%  udat_atom %%%%%%%%%%%%%%%%%
0946 function y = udat_atom()
0947 atfmt = [64 double('fmt')];
0948 atday = [64 double('day')];
0949 
0950 VersionString = 'Matlab MakeQTMovie version April 7, 2000';
0951 
0952 y = [mb32(0) mbstring('udta') ...
0953     SetAtomSize([mb32(0) atfmt mbstring(['Created ' VersionString])]) ...
0954     SetAtomSize([mb32(0) atday '  ' date])];
0955 y = SetAtomSize(y);
0956 
0957 
0958 %%%%%%%%%%%%%%%  vmhd_atom %%%%%%%%%%%%%%%%%
0959 function y = vmhd_atom()
0960 
0961 y = SetAtomSize([mb32(0) mbstring('vmhd') mb32(0) ...
0962     mb16(64) ...            % Graphics Mode
0963     mb16(0) mb16(0) mb16(0)]);        % Op Color

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