2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % M M PPPP EEEEE GGGG %
8 % M M M PPPP EEE G GG %
13 % Read/Write MPEG Image Format %
20 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
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. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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"
68 static MagickBooleanType
69 WriteMPEGImage(const ImageInfo *,Image *,ExceptionInfo *);
72 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
82 % IsAVI() returns MagickTrue if the image format type, identified by the
83 % magick string, is Audio/Video Interleaved file format.
85 % The format of the IsAVI method is:
87 % size_t IsAVI(const unsigned char *magick,const size_t length)
89 % A description of each parameter follows:
91 % o magick: compare image format pattern against these bytes.
93 % o length: Specifies the length of the magick string.
96 static MagickBooleanType IsAVI(const unsigned char *magick,const size_t length)
100 if (memcmp(magick,"RIFF",4) == 0)
106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
116 % IsMPEG() returns MagickTrue if the image format type, identified by the
117 % magick string, is MPEG.
119 % The format of the IsMPEG method is:
121 % MagickBooleanType IsMPEG(const unsigned char *magick,const size_t length)
123 % A description of each parameter follows:
125 % o magick: compare image format pattern against these bytes.
127 % o length: Specifies the length of the magick string.
130 static MagickBooleanType IsMPEG(const unsigned char *magick,const size_t length)
134 if (memcmp(magick,"\000\000\001\263",4) == 0)
140 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
144 % R e a d M P E G I m a g e %
148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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.
154 % The format of the ReadMPEGImage method is:
156 % Image *ReadMPEGImage(const ImageInfo *image_info,
157 % ExceptionInfo *exception)
159 % A description of each parameter follows:
161 % o image_info: the image info.
163 % o exception: return any errors or warnings in this structure.
166 static Image *ReadMPEGImage(const ImageInfo *image_info,
167 ExceptionInfo *exception)
169 #define ReadMPEGIntermediateFormat "pam"
184 assert(image_info != (const ImageInfo *) NULL);
185 assert(image_info->signature == MagickSignature);
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 == MagickSignature);
191 image=AcquireImage(image_info,exception);
192 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
193 if (status == MagickFalse)
195 image=DestroyImageList(image);
196 return((Image *) NULL);
198 (void) CloseBlob(image);
199 (void) DestroyImageList(image);
201 Convert MPEG to PAM with delegate.
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,MaxTextExtent,"%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);
216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
220 % R e g i s t e r M P E G I m a g e %
224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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.
233 % The format of the RegisterMPEGImage method is:
235 % size_t RegisterMPEGImage(void)
238 ModuleExport size_t RegisterMPEGImage(void)
243 entry=SetMagickInfo("AVI");
244 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
245 entry->magick=(IsImageFormatHandler *) IsAVI;
246 entry->blob_support=MagickFalse;
247 entry->description=ConstantString("Microsoft Audio/Visual Interleaved");
248 entry->module=ConstantString("MPEG");
249 (void) RegisterMagickInfo(entry);
250 entry=SetMagickInfo("MOV");
251 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
252 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
253 entry->magick=(IsImageFormatHandler *) IsMPEG;
254 entry->blob_support=MagickFalse;
255 entry->description=ConstantString("MPEG Video Stream");
256 entry->module=ConstantString("MPEG");
257 (void) RegisterMagickInfo(entry);
258 entry=SetMagickInfo("MPEG");
259 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
260 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
261 entry->magick=(IsImageFormatHandler *) IsMPEG;
262 entry->blob_support=MagickFalse;
263 entry->description=ConstantString("MPEG Video Stream");
264 entry->module=ConstantString("MPEG");
265 (void) RegisterMagickInfo(entry);
266 entry=SetMagickInfo("MPG");
267 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
268 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
269 entry->magick=(IsImageFormatHandler *) IsMPEG;
270 entry->blob_support=MagickFalse;
271 entry->description=ConstantString("MPEG Video Stream");
272 entry->module=ConstantString("MPEG");
273 (void) RegisterMagickInfo(entry);
274 entry=SetMagickInfo("MP4");
275 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
276 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
277 entry->magick=(IsImageFormatHandler *) IsMPEG;
278 entry->blob_support=MagickFalse;
279 entry->description=ConstantString("MPEG-4 Video Stream");
280 entry->module=ConstantString("MPEG");
281 (void) RegisterMagickInfo(entry);
282 entry=SetMagickInfo("M2V");
283 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
284 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
285 entry->magick=(IsImageFormatHandler *) IsMPEG;
286 entry->blob_support=MagickFalse;
287 entry->description=ConstantString("MPEG Video Stream");
288 entry->module=ConstantString("MPEG");
289 (void) RegisterMagickInfo(entry);
290 entry=SetMagickInfo("M4V");
291 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
292 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
293 entry->magick=(IsImageFormatHandler *) IsMPEG;
294 entry->blob_support=MagickFalse;
295 entry->description=ConstantString("Raw MPEG-4 Video");
296 entry->module=ConstantString("MPEG");
297 (void) RegisterMagickInfo(entry);
298 entry=SetMagickInfo("WMV");
299 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
300 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
301 entry->magick=(IsImageFormatHandler *) IsMPEG;
302 entry->blob_support=MagickFalse;
303 entry->description=ConstantString("Windows Media Video");
304 entry->module=ConstantString("MPEG");
305 (void) RegisterMagickInfo(entry);
306 return(MagickImageCoderSignature);
310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
314 % U n r e g i s t e r M P E G I m a g e %
318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
320 % UnregisterMPEGImage() removes format registrations made by the
321 % BIM module from the list of supported formats.
323 % The format of the UnregisterBIMImage method is:
325 % UnregisterMPEGImage(void)
328 ModuleExport void UnregisterMPEGImage(void)
330 (void) UnregisterMagickInfo("WMV");
331 (void) UnregisterMagickInfo("M4V");
332 (void) UnregisterMagickInfo("M2V");
333 (void) UnregisterMagickInfo("MP4");
334 (void) UnregisterMagickInfo("MPG");
335 (void) UnregisterMagickInfo("MPEG");
336 (void) UnregisterMagickInfo("MOV");
337 (void) UnregisterMagickInfo("AVI");
341 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
345 % W r i t e M P E G I m a g e %
349 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
351 % WriteMPEGImage() writes an image to a file in MPEG video stream format.
352 % Lawrence Livermore National Laboratory (LLNL) contributed code to adjust
353 % the MPEG parameters to correspond to the compression quality setting.
355 % The format of the WriteMPEGImage method is:
357 % MagickBooleanType WriteMPEGImage(const ImageInfo *image_info,
358 % Image *image,ExceptionInfo *exception)
360 % A description of each parameter follows.
362 % o image_info: the image info.
364 % o image: The image.
366 % o exception: return any errors or warnings in this structure.
370 static inline double MagickMax(const double x,const double y)
377 static inline double MagickMin(const double x,const double y)
384 static MagickBooleanType CopyDelegateFile(const char *source,
385 const char *destination)
411 Return if destination file already exists and is not empty.
413 assert(source != (const char *) NULL);
414 assert(destination != (char *) NULL);
415 status=GetPathAttributes(destination,&attributes);
416 if ((status != MagickFalse) && (attributes.st_size != 0))
419 Copy source file to destination.
421 destination_file=open_utf8(destination,O_WRONLY | O_BINARY | O_CREAT,S_MODE);
422 if (destination_file == -1)
424 source_file=open_utf8(source,O_RDONLY | O_BINARY,0);
425 if (source_file == -1)
427 (void) close(destination_file);
430 quantum=(size_t) MagickMaxBufferExtent;
431 if ((fstat(source_file,&attributes) == 0) && (attributes.st_size != 0))
432 quantum=(size_t) MagickMin((double) attributes.st_size,
433 MagickMaxBufferExtent);
434 buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
435 if (buffer == (unsigned char *) NULL)
437 (void) close(source_file);
438 (void) close(destination_file);
442 for (i=0; ; i+=count)
444 count=(ssize_t) read(source_file,buffer,quantum);
447 length=(size_t) count;
448 count=(ssize_t) write(destination_file,buffer,length);
449 if ((size_t) count != length)
452 (void) close(destination_file);
453 (void) close(source_file);
454 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
455 return(i != 0 ? MagickTrue : MagickFalse);
458 static MagickBooleanType WriteMPEGImage(const ImageInfo *image_info,
459 Image *image,ExceptionInfo *exception)
461 #define WriteMPEGIntermediateFormat "jpg"
464 basename[MaxTextExtent],
465 filename[MaxTextExtent];
497 Open output image file.
499 assert(image_info != (const ImageInfo *) NULL);
500 assert(image_info->signature == MagickSignature);
501 assert(image != (Image *) NULL);
502 assert(image->signature == MagickSignature);
503 if (image->debug != MagickFalse)
504 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
505 assert(exception != (ExceptionInfo *) NULL);
506 assert(exception->signature == MagickSignature);
507 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
508 if (status == MagickFalse)
510 (void) CloseBlob(image);
512 Write intermediate files.
514 coalesce_image=CoalesceImages(image,exception);
515 if (coalesce_image == (Image *) NULL)
517 file=AcquireUniqueFileResource(basename);
520 (void) FormatLocaleString(coalesce_image->filename,MaxTextExtent,"%s",
523 write_info=CloneImageInfo(image_info);
524 for (p=coalesce_image; p != (Image *) NULL; p=GetNextImageInList(p))
527 previous_image[MaxTextExtent];
529 blob=(unsigned char *) NULL;
532 delay=100.0*p->delay/MagickMax(1.0*p->ticks_per_second,1.0);
533 for (i=0; i < (ssize_t) MagickMax((1.0*delay+1.0)/3.0,1.0); i++)
545 (void) FormatLocaleString(p->filename,MaxTextExtent,"%s%.20g.%s",
546 basename,(double) p->scene,WriteMPEGIntermediateFormat);
547 (void) FormatLocaleString(filename,MaxTextExtent,"%s%.20g.%s",
548 basename,(double) p->scene,WriteMPEGIntermediateFormat);
549 (void) FormatLocaleString(previous_image,MaxTextExtent,
550 "%s%.20g.%s",basename,(double) p->scene,
551 WriteMPEGIntermediateFormat);
552 frame=CloneImage(p,0,0,MagickTrue,exception);
553 if (frame == (Image *) NULL)
555 status=WriteImage(write_info,frame,exception);
556 frame=DestroyImage(frame);
561 blob=(unsigned char *) FileToBlob(previous_image,~0UL,&length,
566 (void) FormatLocaleString(filename,MaxTextExtent,"%s%.20g.%s",
567 basename,(double) p->scene,WriteMPEGIntermediateFormat);
569 status=BlobToFile(filename,blob,length,exception);
573 if (image->debug != MagickFalse)
575 if (status != MagickFalse)
576 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
577 "%.20g. Wrote %s file for scene %.20g:",(double) i,
578 WriteMPEGIntermediateFormat,(double) p->scene);
580 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
581 "%.20g. Failed to write %s file for scene %.20g:",(double) i,
582 WriteMPEGIntermediateFormat,(double) p->scene);
583 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s",filename);
587 if (blob != (unsigned char *) NULL)
588 blob=(unsigned char *) RelinquishMagickMemory(blob);
589 if (status == MagickFalse)
593 Convert JPEG to MPEG.
595 (void) CopyMagickString(coalesce_image->magick_filename,basename,
597 (void) CopyMagickString(coalesce_image->filename,basename,MaxTextExtent);
598 GetPathComponent(image_info->filename,ExtensionPath,coalesce_image->magick);
599 if (*coalesce_image->magick == '\0')
600 (void) CopyMagickString(coalesce_image->magick,image->magick,MaxTextExtent);
601 status=InvokeDelegate(write_info,coalesce_image,(char *) NULL,"mpeg:encode",
603 (void) FormatLocaleString(write_info->filename,MaxTextExtent,"%s.%s",
604 write_info->unique,coalesce_image->magick);
605 status=CopyDelegateFile(write_info->filename,image->filename);
606 (void) RelinquishUniqueFileResource(write_info->filename);
607 write_info=DestroyImageInfo(write_info);
609 Relinquish resources.
612 for (p=coalesce_image; p != (Image *) NULL; p=GetNextImageInList(p))
614 delay=100.0*p->delay/MagickMax(1.0*p->ticks_per_second,1.0);
615 for (i=0; i < (ssize_t) MagickMax((1.0*delay+1.0)/3.0,1.0); i++)
617 (void) FormatLocaleString(p->filename,MaxTextExtent,"%s%.20g.%s",
618 basename,(double) count++,WriteMPEGIntermediateFormat);
619 (void) RelinquishUniqueFileResource(p->filename);
621 (void) CopyMagickString(p->filename,image_info->filename,MaxTextExtent);
623 (void) RelinquishUniqueFileResource(basename);
624 coalesce_image=DestroyImageList(coalesce_image);
625 if (image->debug != MagickFalse)
626 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit");