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