Home | History | Annotate | Download | only in coders
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %                        M   M  PPPP   EEEEE   GGGG                           %
      7 %                        MM MM  P   P  E      G                               %
      8 %                        M M M  PPPP   EEE    G  GG                           %
      9 %                        M   M  P      E      G   G                           %
     10 %                        M   M  P      EEEEE   GGGG                           %
     11 %                                                                             %
     12 %                                                                             %
     13 %                       Read/Write MPEG Image Format                          %
     14 %                                                                             %
     15 %                              Software Design                                %
     16 %                                   Cristy                                    %
     17 %                                 July 1999                                   %
     18 %                                                                             %
     19 %                                                                             %
     20 %  Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization      %
     21 %  dedicated to making software imaging solutions freely available.           %
     22 %                                                                             %
     23 %  You may not use this file except in compliance with the License.  You may  %
     24 %  obtain a copy of the License at                                            %
     25 %                                                                             %
     26 %    https://imagemagick.org/script/license.php                               %
     27 %                                                                             %
     28 %  Unless required by applicable law or agreed to in writing, software        %
     29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
     30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
     31 %  See the License for the specific language governing permissions and        %
     32 %  limitations under the License.                                             %
     33 %                                                                             %
     34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     35 %
     36 %
     37 */
     38 /*
     39   Include declarations.
     40 */
     41 #include "MagickCore/studio.h"
     42 #include "MagickCore/blob.h"
     43 #include "MagickCore/blob-private.h"
     44 #include "MagickCore/constitute.h"
     45 #include "MagickCore/delegate.h"
     46 #include "MagickCore/exception.h"
     47 #include "MagickCore/exception-private.h"
     48 #include "MagickCore/geometry.h"
     49 #include "MagickCore/image.h"
     50 #include "MagickCore/image-private.h"
     51 #include "MagickCore/layer.h"
     52 #include "MagickCore/list.h"
     53 #include "MagickCore/log.h"
     54 #include "MagickCore/magick.h"
     55 #include "MagickCore/memory_.h"
     56 #include "MagickCore/resource_.h"
     57 #include "MagickCore/quantum-private.h"
     58 #include "MagickCore/static.h"
     59 #include "MagickCore/string_.h"
     60 #include "MagickCore/module.h"
     61 #include "MagickCore/transform.h"
     62 #include "MagickCore/utility.h"
     63 #include "MagickCore/utility-private.h"
     64 
     65 /*
     67   Forward declarations.
     68 */
     69 static MagickBooleanType
     70   WriteMPEGImage(const ImageInfo *,Image *,ExceptionInfo *);
     71 
     72 /*
     74 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     75 %                                                                             %
     76 %                                                                             %
     77 %                                                                             %
     78 %   I s A V I                                                                 %
     79 %                                                                             %
     80 %                                                                             %
     81 %                                                                             %
     82 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     83 %
     84 %  IsAVI() returns MagickTrue if the image format type, identified by the
     85 %  magick string, is Audio/Video Interleaved file format.
     86 %
     87 %  The format of the IsAVI method is:
     88 %
     89 %      size_t IsAVI(const unsigned char *magick,const size_t length)
     90 %
     91 %  A description of each parameter follows:
     92 %
     93 %    o magick: compare image format pattern against these bytes.
     94 %
     95 %    o length: Specifies the length of the magick string.
     96 %
     97 */
     98 static MagickBooleanType IsAVI(const unsigned char *magick,const size_t length)
     99 {
    100   if (length < 4)
    101     return(MagickFalse);
    102   if (memcmp(magick,"RIFF",4) == 0)
    103     return(MagickTrue);
    104   return(MagickFalse);
    105 }
    106 
    107 /*
    109 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    110 %                                                                             %
    111 %                                                                             %
    112 %                                                                             %
    113 %   I s M P E G                                                               %
    114 %                                                                             %
    115 %                                                                             %
    116 %                                                                             %
    117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    118 %
    119 %  IsMPEG() returns MagickTrue if the image format type, identified by the
    120 %  magick string, is MPEG.
    121 %
    122 %  The format of the IsMPEG method is:
    123 %
    124 %      MagickBooleanType IsMPEG(const unsigned char *magick,const size_t length)
    125 %
    126 %  A description of each parameter follows:
    127 %
    128 %    o magick: compare image format pattern against these bytes.
    129 %
    130 %    o length: Specifies the length of the magick string.
    131 %
    132 */
    133 static MagickBooleanType IsMPEG(const unsigned char *magick,const size_t length)
    134 {
    135   if (length < 4)
    136     return(MagickFalse);
    137   if (memcmp(magick,"\000\000\001\263",4) == 0)
    138     return(MagickTrue);
    139   return(MagickFalse);
    140 }
    141 
    142 /*
    144 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    145 %                                                                             %
    146 %                                                                             %
    147 %                                                                             %
    148 %   R e a d M P E G I m a g e                                                 %
    149 %                                                                             %
    150 %                                                                             %
    151 %                                                                             %
    152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    153 %
    154 %  ReadMPEGImage() reads an binary file in the MPEG video stream format
    155 %  and returns it.  It allocates the memory necessary for the new Image
    156 %  structure and returns a pointer to the new image.
    157 %
    158 %  The format of the ReadMPEGImage method is:
    159 %
    160 %      Image *ReadMPEGImage(const ImageInfo *image_info,
    161 %        ExceptionInfo *exception)
    162 %
    163 %  A description of each parameter follows:
    164 %
    165 %    o image_info: the image info.
    166 %
    167 %    o exception: return any errors or warnings in this structure.
    168 %
    169 */
    170 static Image *ReadMPEGImage(const ImageInfo *image_info,
    171   ExceptionInfo *exception)
    172 {
    173 #define ReadMPEGIntermediateFormat "pam"
    174 
    175   Image
    176     *image,
    177     *images,
    178     *next;
    179 
    180   ImageInfo
    181     *read_info;
    182 
    183   MagickBooleanType
    184     status;
    185 
    186   /*
    187     Open image file.
    188   */
    189   assert(image_info != (const ImageInfo *) NULL);
    190   assert(image_info->signature == MagickCoreSignature);
    191   if (image_info->debug != MagickFalse)
    192     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
    193       image_info->filename);
    194   assert(exception != (ExceptionInfo *) NULL);
    195   assert(exception->signature == MagickCoreSignature);
    196   image=AcquireImage(image_info,exception);
    197   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
    198   if (status == MagickFalse)
    199     {
    200       image=DestroyImageList(image);
    201       return((Image *) NULL);
    202     }
    203   (void) CloseBlob(image);
    204   (void) DestroyImageList(image);
    205   /*
    206     Convert MPEG to PAM with delegate.
    207   */
    208   images=(Image *) NULL;
    209   read_info=CloneImageInfo(image_info);
    210   image=AcquireImage(image_info,exception);
    211   status=InvokeDelegate(read_info,image,"mpeg:decode",(char *) NULL,exception);
    212   if (status != MagickFalse)
    213     {
    214       (void) FormatLocaleString(read_info->filename,MagickPathExtent,"%s.%s",
    215         read_info->unique,ReadMPEGIntermediateFormat);
    216       *read_info->magick='\0';
    217       images=ReadImage(read_info,exception);
    218       if (images != (Image *) NULL)
    219         for (next=images; next != (Image *) NULL; next=next->next)
    220         {
    221           (void) CopyMagickString(next->filename,image->filename,
    222             MagickPathExtent);
    223           (void) CopyMagickString(next->magick,image->magick,MagickPathExtent);
    224         }
    225       (void) RelinquishUniqueFileResource(read_info->filename);
    226     }
    227   read_info=DestroyImageInfo(read_info);
    228   image=DestroyImage(image);
    229   return(images);
    230 }
    231 
    232 /*
    234 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    235 %                                                                             %
    236 %                                                                             %
    237 %                                                                             %
    238 %   R e g i s t e r M P E G I m a g e                                         %
    239 %                                                                             %
    240 %                                                                             %
    241 %                                                                             %
    242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    243 %
    244 %  RegisterMPEGImage() adds attributes for the MPEG image format to
    245 %  the list of supported formats.  The attributes include the image format
    246 %  tag, a method to read and/or write the format, whether the format
    247 %  supports the saving of more than one frame to the same file or blob,
    248 %  whether the format supports native in-memory I/O, and a brief
    249 %  description of the format.
    250 %
    251 %  The format of the RegisterMPEGImage method is:
    252 %
    253 %      size_t RegisterMPEGImage(void)
    254 %
    255 */
    256 ModuleExport size_t RegisterMPEGImage(void)
    257 {
    258   MagickInfo
    259     *entry;
    260 
    261   entry=AcquireMagickInfo("MPEG","3GP","Media Container");
    262   entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
    263   entry->flags^=CoderBlobSupportFlag;
    264   entry->flags|=CoderSeekableStreamFlag;
    265   (void) RegisterMagickInfo(entry);
    266   entry=AcquireMagickInfo("MPEG","3G2","Media Container");
    267   entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
    268   entry->flags^=CoderBlobSupportFlag;
    269   entry->flags|=CoderSeekableStreamFlag;
    270   (void) RegisterMagickInfo(entry);
    271   entry=AcquireMagickInfo("MPEG","AVI","Microsoft Audio/Visual Interleaved");
    272   entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
    273   entry->magick=(IsImageFormatHandler *) IsAVI;
    274   entry->flags^=CoderBlobSupportFlag;
    275   (void) RegisterMagickInfo(entry);
    276   entry=AcquireMagickInfo("MPEG","MKV","Multimedia Container");
    277   entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
    278   entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
    279   entry->magick=(IsImageFormatHandler *) IsMPEG;
    280   entry->flags^=CoderBlobSupportFlag;
    281   (void) RegisterMagickInfo(entry);
    282   entry=AcquireMagickInfo("MPEG","MOV","MPEG Video Stream");
    283   entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
    284   entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
    285   entry->magick=(IsImageFormatHandler *) IsMPEG;
    286   entry->flags^=CoderBlobSupportFlag;
    287   (void) RegisterMagickInfo(entry);
    288   entry=AcquireMagickInfo("MPEG","MPEG","MPEG Video Stream");
    289   entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
    290   entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
    291   entry->magick=(IsImageFormatHandler *) IsMPEG;
    292   entry->flags^=CoderBlobSupportFlag;
    293   (void) RegisterMagickInfo(entry);
    294   entry=AcquireMagickInfo("MPEG","MPG","MPEG Video Stream");
    295   entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
    296   entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
    297   entry->magick=(IsImageFormatHandler *) IsMPEG;
    298   entry->flags^=CoderBlobSupportFlag;
    299   (void) RegisterMagickInfo(entry);
    300   entry=AcquireMagickInfo("MPEG","MP4","MPEG-4 Video Stream");
    301   entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
    302   entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
    303   entry->magick=(IsImageFormatHandler *) IsMPEG;
    304   entry->flags^=CoderBlobSupportFlag;
    305   (void) RegisterMagickInfo(entry);
    306   entry=AcquireMagickInfo("MPEG","M2V","MPEG Video Stream");
    307   entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
    308   entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
    309   entry->magick=(IsImageFormatHandler *) IsMPEG;
    310   entry->flags^=CoderBlobSupportFlag;
    311   (void) RegisterMagickInfo(entry);
    312   entry=AcquireMagickInfo("MPEG","M4V","Raw MPEG-4 Video");
    313   entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
    314   entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
    315   entry->magick=(IsImageFormatHandler *) IsMPEG;
    316   entry->flags^=CoderBlobSupportFlag;
    317   (void) RegisterMagickInfo(entry);
    318   entry=AcquireMagickInfo("MPEG","WMV","Windows Media Video");
    319   entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
    320   entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
    321   entry->magick=(IsImageFormatHandler *) IsMPEG;
    322   entry->flags^=CoderBlobSupportFlag;
    323   (void) RegisterMagickInfo(entry);
    324   return(MagickImageCoderSignature);
    325 }
    326 
    327 /*
    329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    330 %                                                                             %
    331 %                                                                             %
    332 %                                                                             %
    333 %   U n r e g i s t e r M P E G I m a g e                                     %
    334 %                                                                             %
    335 %                                                                             %
    336 %                                                                             %
    337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    338 %
    339 %  UnregisterMPEGImage() removes format registrations made by the
    340 %  BIM module from the list of supported formats.
    341 %
    342 %  The format of the UnregisterBIMImage method is:
    343 %
    344 %      UnregisterMPEGImage(void)
    345 %
    346 */
    347 ModuleExport void UnregisterMPEGImage(void)
    348 {
    349   (void) UnregisterMagickInfo("WMV");
    350   (void) UnregisterMagickInfo("MOV");
    351   (void) UnregisterMagickInfo("M4V");
    352   (void) UnregisterMagickInfo("M2V");
    353   (void) UnregisterMagickInfo("MP4");
    354   (void) UnregisterMagickInfo("MPG");
    355   (void) UnregisterMagickInfo("MPEG");
    356   (void) UnregisterMagickInfo("MKV");
    357   (void) UnregisterMagickInfo("AVI");
    358   (void) UnregisterMagickInfo("3G2");
    359   (void) UnregisterMagickInfo("3GP");
    360 }
    361 
    362 /*
    364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    365 %                                                                             %
    366 %                                                                             %
    367 %                                                                             %
    368 %   W r i t e M P E G I m a g e                                               %
    369 %                                                                             %
    370 %                                                                             %
    371 %                                                                             %
    372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    373 %
    374 %  WriteMPEGImage() writes an image to a file in MPEG video stream format.
    375 %  Lawrence Livermore National Laboratory (LLNL) contributed code to adjust
    376 %  the MPEG parameters to correspond to the compression quality setting.
    377 %
    378 %  The format of the WriteMPEGImage method is:
    379 %
    380 %      MagickBooleanType WriteMPEGImage(const ImageInfo *image_info,
    381 %        Image *image,ExceptionInfo *exception)
    382 %
    383 %  A description of each parameter follows.
    384 %
    385 %    o image_info: the image info.
    386 %
    387 %    o image:  The image.
    388 %
    389 %    o exception: return any errors or warnings in this structure.
    390 %
    391 */
    392 static MagickBooleanType CopyDelegateFile(const char *source,
    393   const char *destination)
    394 {
    395   int
    396     destination_file,
    397     source_file;
    398 
    399   MagickBooleanType
    400     status;
    401 
    402   register size_t
    403     i;
    404 
    405   size_t
    406     length,
    407     quantum;
    408 
    409   ssize_t
    410     count;
    411 
    412   struct stat
    413     attributes;
    414 
    415   unsigned char
    416     *buffer;
    417 
    418   /*
    419     Return if destination file already exists and is not empty.
    420   */
    421   assert(source != (const char *) NULL);
    422   assert(destination != (char *) NULL);
    423   status=GetPathAttributes(destination,&attributes);
    424   if ((status != MagickFalse) && (attributes.st_size > 0))
    425     return(MagickTrue);
    426   /*
    427     Copy source file to destination.
    428   */
    429   destination_file=open_utf8(destination,O_WRONLY | O_BINARY | O_CREAT,S_MODE);
    430   if (destination_file == -1)
    431     return(MagickFalse);
    432   source_file=open_utf8(source,O_RDONLY | O_BINARY,0);
    433   if (source_file == -1)
    434     {
    435       (void) close(destination_file);
    436       return(MagickFalse);
    437     }
    438   quantum=(size_t) MagickMaxBufferExtent;
    439   if ((fstat(source_file,&attributes) == 0) && (attributes.st_size > 0))
    440     quantum=(size_t) MagickMin((double) attributes.st_size,
    441       MagickMaxBufferExtent);
    442   buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
    443   if (buffer == (unsigned char *) NULL)
    444     {
    445       (void) close(source_file);
    446       (void) close(destination_file);
    447       return(MagickFalse);
    448     }
    449   length=0;
    450   for (i=0; ; i+=count)
    451   {
    452     count=(ssize_t) read(source_file,buffer,quantum);
    453     if (count <= 0)
    454       break;
    455     length=(size_t) count;
    456     count=(ssize_t) write(destination_file,buffer,length);
    457     if ((size_t) count != length)
    458       break;
    459   }
    460   (void) close(destination_file);
    461   (void) close(source_file);
    462   buffer=(unsigned char *) RelinquishMagickMemory(buffer);
    463   return(i != 0 ? MagickTrue : MagickFalse);
    464 }
    465 
    466 static MagickBooleanType WriteMPEGImage(const ImageInfo *image_info,
    467   Image *image,ExceptionInfo *exception)
    468 {
    469 #define WriteMPEGIntermediateFormat "jpg"
    470 
    471   char
    472     basename[MagickPathExtent],
    473     filename[MagickPathExtent];
    474 
    475   double
    476     delay;
    477 
    478   Image
    479     *coalesce_image;
    480 
    481   ImageInfo
    482     *write_info;
    483 
    484   int
    485     file;
    486 
    487   MagickBooleanType
    488     status;
    489 
    490   register Image
    491     *p;
    492 
    493   register ssize_t
    494     i;
    495 
    496   size_t
    497     count,
    498     length,
    499     scene;
    500 
    501   unsigned char
    502     *blob;
    503 
    504   /*
    505     Open output image file.
    506   */
    507   assert(image_info != (const ImageInfo *) NULL);
    508   assert(image_info->signature == MagickCoreSignature);
    509   assert(image != (Image *) NULL);
    510   assert(image->signature == MagickCoreSignature);
    511   if (image->debug != MagickFalse)
    512     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    513   assert(exception != (ExceptionInfo *) NULL);
    514   assert(exception->signature == MagickCoreSignature);
    515   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
    516   if (status == MagickFalse)
    517     return(status);
    518   (void) CloseBlob(image);
    519   /*
    520     Write intermediate files.
    521   */
    522   coalesce_image=CoalesceImages(image,exception);
    523   if (coalesce_image == (Image *) NULL)
    524     return(MagickFalse);
    525   file=AcquireUniqueFileResource(basename);
    526   if (file != -1)
    527     file=close(file)-1;
    528   (void) FormatLocaleString(coalesce_image->filename,MagickPathExtent,"%s",
    529     basename);
    530   count=0;
    531   write_info=CloneImageInfo(image_info);
    532   *write_info->magick='\0';
    533   for (p=coalesce_image; p != (Image *) NULL; p=GetNextImageInList(p))
    534   {
    535     char
    536       previous_image[MagickPathExtent];
    537 
    538     blob=(unsigned char *) NULL;
    539     length=0;
    540     scene=p->scene;
    541     delay=100.0*p->delay/MagickMax(1.0*p->ticks_per_second,1.0);
    542     for (i=0; i < (ssize_t) MagickMax((1.0*delay+1.0)/3.0,1.0); i++)
    543     {
    544       p->scene=count;
    545       count++;
    546       status=MagickFalse;
    547       switch (i)
    548       {
    549         case 0:
    550         {
    551           Image
    552             *frame;
    553 
    554           (void) FormatLocaleString(p->filename,MagickPathExtent,"%s%.20g.%s",
    555             basename,(double) p->scene,WriteMPEGIntermediateFormat);
    556           (void) FormatLocaleString(filename,MagickPathExtent,"%s%.20g.%s",
    557             basename,(double) p->scene,WriteMPEGIntermediateFormat);
    558           (void) FormatLocaleString(previous_image,MagickPathExtent,
    559             "%s%.20g.%s",basename,(double) p->scene,
    560             WriteMPEGIntermediateFormat);
    561           frame=CloneImage(p,0,0,MagickTrue,exception);
    562           if (frame == (Image *) NULL)
    563             break;
    564           status=WriteImage(write_info,frame,exception);
    565           frame=DestroyImage(frame);
    566           break;
    567         }
    568         case 1:
    569         {
    570           blob=(unsigned char *) FileToBlob(previous_image,~0UL,&length,
    571             exception);
    572         }
    573         default:
    574         {
    575           (void) FormatLocaleString(filename,MagickPathExtent,"%s%.20g.%s",
    576             basename,(double) p->scene,WriteMPEGIntermediateFormat);
    577           if (length > 0)
    578             status=BlobToFile(filename,blob,length,exception);
    579           break;
    580         }
    581       }
    582       if (image->debug != MagickFalse)
    583         {
    584           if (status != MagickFalse)
    585             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
    586               "%.20g. Wrote %s file for scene %.20g:",(double) i,
    587               WriteMPEGIntermediateFormat,(double) p->scene);
    588           else
    589             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
    590               "%.20g. Failed to write %s file for scene %.20g:",(double) i,
    591               WriteMPEGIntermediateFormat,(double) p->scene);
    592           (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s",filename);
    593         }
    594     }
    595     p->scene=scene;
    596     if (blob != (unsigned char *) NULL)
    597       blob=(unsigned char *) RelinquishMagickMemory(blob);
    598     if (status == MagickFalse)
    599       break;
    600   }
    601   /*
    602     Convert JPEG to MPEG.
    603   */
    604   (void) CopyMagickString(coalesce_image->magick_filename,basename,
    605     MagickPathExtent);
    606   (void) CopyMagickString(coalesce_image->filename,basename,MagickPathExtent);
    607   GetPathComponent(image_info->filename,ExtensionPath,coalesce_image->magick);
    608   if (*coalesce_image->magick == '\0')
    609     (void) CopyMagickString(coalesce_image->magick,image->magick,
    610       MagickPathExtent);
    611   status=InvokeDelegate(write_info,coalesce_image,(char *) NULL,"mpeg:encode",
    612     exception);
    613   (void) FormatLocaleString(write_info->filename,MagickPathExtent,"%s.%s",
    614     write_info->unique,coalesce_image->magick);
    615   status=CopyDelegateFile(write_info->filename,image->filename);
    616   (void) RelinquishUniqueFileResource(write_info->filename);
    617   write_info=DestroyImageInfo(write_info);
    618   /*
    619     Relinquish resources.
    620   */
    621   count=0;
    622   for (p=coalesce_image; p != (Image *) NULL; p=GetNextImageInList(p))
    623   {
    624     delay=100.0*p->delay/MagickMax(1.0*p->ticks_per_second,1.0);
    625     for (i=0; i < (ssize_t) MagickMax((1.0*delay+1.0)/3.0,1.0); i++)
    626     {
    627       (void) FormatLocaleString(p->filename,MagickPathExtent,"%s%.20g.%s",
    628         basename,(double) count++,WriteMPEGIntermediateFormat);
    629       (void) RelinquishUniqueFileResource(p->filename);
    630     }
    631     (void) CopyMagickString(p->filename,image_info->filename,MagickPathExtent);
    632   }
    633   (void) RelinquishUniqueFileResource(basename);
    634   coalesce_image=DestroyImageList(coalesce_image);
    635   if (image->debug != MagickFalse)
    636     (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit");
    637   return(status);
    638 }
    639