2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % M M PPPP EEEEE GGGG %
8 % M M M PPPP EEE G GG %
13 % Read/Write MPEG Image Format %
20 % Copyright 1999-2010 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 "magick/studio.h"
42 #include "magick/blob.h"
43 #include "magick/blob-private.h"
44 #include "magick/constitute.h"
45 #include "magick/delegate.h"
46 #include "magick/exception.h"
47 #include "magick/exception-private.h"
48 #include "magick/geometry.h"
49 #include "magick/image.h"
50 #include "magick/image-private.h"
51 #include "magick/layer.h"
52 #include "magick/list.h"
53 #include "magick/log.h"
54 #include "magick/magick.h"
55 #include "magick/memory_.h"
56 #include "magick/resource_.h"
57 #include "magick/quantum-private.h"
58 #include "magick/static.h"
59 #include "magick/string_.h"
60 #include "magick/module.h"
61 #include "magick/transform.h"
62 #include "magick/utility.h"
67 static MagickBooleanType
68 WriteMPEGImage(const ImageInfo *image_info,Image *image);
71 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81 % IsAVI() returns MagickTrue if the image format type, identified by the
82 % magick string, is Audio/Video Interleaved file format.
84 % The format of the IsAVI method is:
86 % size_t IsAVI(const unsigned char *magick,const size_t length)
88 % A description of each parameter follows:
90 % o magick: compare image format pattern against these bytes.
92 % o length: Specifies the length of the magick string.
95 static MagickBooleanType IsAVI(const unsigned char *magick,const size_t length)
99 if (memcmp(magick,"RIFF",4) == 0)
105 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
115 % IsMPEG() returns MagickTrue if the image format type, identified by the
116 % magick string, is MPEG.
118 % The format of the IsMPEG method is:
120 % MagickBooleanType IsMPEG(const unsigned char *magick,const size_t length)
122 % A description of each parameter follows:
124 % o magick: compare image format pattern against these bytes.
126 % o length: Specifies the length of the magick string.
129 static MagickBooleanType IsMPEG(const unsigned char *magick,const size_t length)
133 if (memcmp(magick,"\000\000\001\263",4) == 0)
139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143 % R e a d M P E G I m a g e %
147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
149 % ReadMPEGImage() reads an binary file in the MPEG video stream format
150 % and returns it. It allocates the memory necessary for the new Image
151 % structure and returns a pointer to the new image.
153 % The format of the ReadMPEGImage method is:
155 % Image *ReadMPEGImage(const ImageInfo *image_info,
156 % ExceptionInfo *exception)
158 % A description of each parameter follows:
160 % o image_info: the image info.
162 % o exception: return any errors or warnings in this structure.
165 static Image *ReadMPEGImage(const ImageInfo *image_info,
166 ExceptionInfo *exception)
168 #define ReadMPEGIntermediateFormat "pam"
183 assert(image_info != (const ImageInfo *) NULL);
184 assert(image_info->signature == MagickSignature);
185 if (image_info->debug != MagickFalse)
186 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
187 image_info->filename);
188 assert(exception != (ExceptionInfo *) NULL);
189 assert(exception->signature == MagickSignature);
190 image=AcquireImage(image_info);
191 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
192 if (status == MagickFalse)
194 image=DestroyImageList(image);
195 return((Image *) NULL);
197 (void) CloseBlob(image);
198 (void) DestroyImageList(image);
200 Convert MPEG to PAM with delegate.
202 read_info=CloneImageInfo(image_info);
203 image=AcquireImage(image_info);
204 (void) InvokeDelegate(read_info,image,"mpeg:decode",(char *) NULL,exception);
205 image=DestroyImage(image);
206 (void) FormatMagickString(read_info->filename,MaxTextExtent,"%s.%s",
207 read_info->unique,ReadMPEGIntermediateFormat);
208 images=ReadImage(read_info,exception);
209 (void) RelinquishUniqueFileResource(read_info->filename);
210 read_info=DestroyImageInfo(read_info);
215 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
219 % R e g i s t e r M P E G I m a g e %
223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
225 % RegisterMPEGImage() adds attributes for the MPEG image format to
226 % the list of supported formats. The attributes include the image format
227 % tag, a method to read and/or write the format, whether the format
228 % supports the saving of more than one frame to the same file or blob,
229 % whether the format supports native in-memory I/O, and a brief
230 % description of the format.
232 % The format of the RegisterMPEGImage method is:
234 % size_t RegisterMPEGImage(void)
237 ModuleExport size_t RegisterMPEGImage(void)
242 entry=SetMagickInfo("AVI");
243 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
244 entry->magick=(IsImageFormatHandler *) IsAVI;
245 entry->blob_support=MagickFalse;
246 entry->description=ConstantString("Microsoft Audio/Visual Interleaved");
247 entry->module=ConstantString("MPEG");
248 (void) RegisterMagickInfo(entry);
249 entry=SetMagickInfo("MOV");
250 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
251 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
252 entry->magick=(IsImageFormatHandler *) IsMPEG;
253 entry->blob_support=MagickFalse;
254 entry->description=ConstantString("MPEG Video Stream");
255 entry->module=ConstantString("MPEG");
256 (void) RegisterMagickInfo(entry);
257 entry=SetMagickInfo("MPEG");
258 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
259 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
260 entry->magick=(IsImageFormatHandler *) IsMPEG;
261 entry->blob_support=MagickFalse;
262 entry->description=ConstantString("MPEG Video Stream");
263 entry->module=ConstantString("MPEG");
264 (void) RegisterMagickInfo(entry);
265 entry=SetMagickInfo("MPG");
266 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
267 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
268 entry->magick=(IsImageFormatHandler *) IsMPEG;
269 entry->blob_support=MagickFalse;
270 entry->description=ConstantString("MPEG Video Stream");
271 entry->module=ConstantString("MPEG");
272 (void) RegisterMagickInfo(entry);
273 entry=SetMagickInfo("MP4");
274 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
275 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
276 entry->magick=(IsImageFormatHandler *) IsMPEG;
277 entry->blob_support=MagickFalse;
278 entry->description=ConstantString("MPEG-4 Video Stream");
279 entry->module=ConstantString("MPEG");
280 (void) RegisterMagickInfo(entry);
281 entry=SetMagickInfo("M2V");
282 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
283 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
284 entry->magick=(IsImageFormatHandler *) IsMPEG;
285 entry->blob_support=MagickFalse;
286 entry->description=ConstantString("MPEG Video Stream");
287 entry->module=ConstantString("MPEG");
288 (void) RegisterMagickInfo(entry);
289 entry=SetMagickInfo("M4V");
290 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
291 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
292 entry->magick=(IsImageFormatHandler *) IsMPEG;
293 entry->blob_support=MagickFalse;
294 entry->description=ConstantString("Raw MPEG-4 Video");
295 entry->module=ConstantString("MPEG");
296 (void) RegisterMagickInfo(entry);
297 entry=SetMagickInfo("WMV");
298 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
299 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
300 entry->magick=(IsImageFormatHandler *) IsMPEG;
301 entry->blob_support=MagickFalse;
302 entry->description=ConstantString("Windows Media Video");
303 entry->module=ConstantString("MPEG");
304 (void) RegisterMagickInfo(entry);
305 return(MagickImageCoderSignature);
309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
313 % U n r e g i s t e r M P E G I m a g e %
317 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
319 % UnregisterMPEGImage() removes format registrations made by the
320 % BIM module from the list of supported formats.
322 % The format of the UnregisterBIMImage method is:
324 % UnregisterMPEGImage(void)
327 ModuleExport void UnregisterMPEGImage(void)
329 (void) UnregisterMagickInfo("WMV");
330 (void) UnregisterMagickInfo("M4V");
331 (void) UnregisterMagickInfo("M2V");
332 (void) UnregisterMagickInfo("MP4");
333 (void) UnregisterMagickInfo("MPG");
334 (void) UnregisterMagickInfo("MPEG");
335 (void) UnregisterMagickInfo("MOV");
336 (void) UnregisterMagickInfo("AVI");
340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
344 % W r i t e M P E G I m a g e %
348 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
350 % WriteMPEGImage() writes an image to a file in MPEG video stream format.
351 % Lawrence Livermore National Laboratory (LLNL) contributed code to adjust
352 % the MPEG parameters to correspond to the compression quality setting.
354 % The format of the WriteMPEGImage method is:
356 % MagickBooleanType WriteMPEGImage(const ImageInfo *image_info,
359 % A description of each parameter follows.
361 % o image_info: the image info.
363 % o image: The image.
367 static inline double MagickMax(const double x,const double y)
374 static inline double MagickMin(const double x,const double y)
381 static MagickBooleanType CopyDelegateFile(const char *source,
382 const char *destination)
408 Return if destination file already exists and is not empty.
410 assert(source != (const char *) NULL);
411 assert(destination != (char *) NULL);
412 status=GetPathAttributes(destination,&attributes);
413 if ((status != MagickFalse) && (attributes.st_size != 0))
416 Copy source file to destination.
418 destination_file=open(destination,O_WRONLY | O_BINARY | O_CREAT,S_MODE);
419 if (destination_file == -1)
421 source_file=open(source,O_RDONLY | O_BINARY);
422 if (source_file == -1)
424 (void) close(destination_file);
427 quantum=(size_t) MagickMaxBufferExtent;
428 if ((fstat(source_file,&attributes) == 0) && (attributes.st_size != 0))
429 quantum=(size_t) MagickMin((double) attributes.st_size,
430 MagickMaxBufferExtent);
431 buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
432 if (buffer == (unsigned char *) NULL)
434 (void) close(source_file);
435 (void) close(destination_file);
439 for (i=0; ; i+=count)
441 count=(ssize_t) read(source_file,buffer,quantum);
444 length=(size_t) count;
445 count=(ssize_t) write(destination_file,buffer,length);
446 if ((size_t) count != length)
449 (void) close(destination_file);
450 (void) close(source_file);
451 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
452 return(i != 0 ? MagickTrue : MagickFalse);
455 static MagickBooleanType WriteMPEGImage(const ImageInfo *image_info,
458 #define WriteMPEGIntermediateFormat "jpg"
461 basename[MaxTextExtent],
462 filename[MaxTextExtent];
496 Open output image file.
498 assert(image_info != (const ImageInfo *) NULL);
499 assert(image_info->signature == MagickSignature);
500 assert(image != (Image *) NULL);
501 assert(image->signature == MagickSignature);
502 if (image->debug != MagickFalse)
503 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
504 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
505 if (status == MagickFalse)
507 (void) CloseBlob(image);
509 Write intermediate files.
511 coalesce_image=CoalesceImages(image,&image->exception);
512 if (coalesce_image == (Image *) NULL)
514 file=AcquireUniqueFileResource(basename);
517 (void) FormatMagickString(coalesce_image->filename,MaxTextExtent,"%s",
520 write_info=CloneImageInfo(image_info);
521 for (p=coalesce_image; p != (Image *) NULL; p=GetNextImageInList(p))
524 previous_image[MaxTextExtent];
526 blob=(unsigned char *) NULL;
529 delay=100.0*p->delay/MagickMax(1.0*p->ticks_per_second,1.0);
530 for (i=0; i < (ssize_t) MagickMax((1.0*delay+1.0)/3.0,1.0); i++)
542 (void) FormatMagickString(p->filename,MaxTextExtent,"%s%lu.%s",
543 basename,p->scene,WriteMPEGIntermediateFormat);
544 (void) FormatMagickString(filename,MaxTextExtent,"%s%lu.%s",
545 basename,p->scene,WriteMPEGIntermediateFormat);
546 (void) FormatMagickString(previous_image,MaxTextExtent,
547 "%s%lu.%s",basename,p->scene,WriteMPEGIntermediateFormat);
548 frame=CloneImage(p,0,0,MagickTrue,&p->exception);
549 if (frame == (Image *) NULL)
551 status=WriteImage(write_info,frame);
552 frame=DestroyImage(frame);
557 blob=(unsigned char *) FileToBlob(previous_image,~0UL,&length,
562 (void) FormatMagickString(filename,MaxTextExtent,"%s%lu.%s",
563 basename,p->scene,WriteMPEGIntermediateFormat);
565 status=BlobToFile(filename,blob,length,&image->exception);
569 if (image->debug != MagickFalse)
571 if (status != MagickFalse)
572 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
573 "%lu. Wrote %s file for scene %lu:",i,WriteMPEGIntermediateFormat,
576 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
577 "%lu. Failed to write %s file for scene %lu:",i,
578 WriteMPEGIntermediateFormat,p->scene);
579 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s",
584 if (blob != (unsigned char *) NULL)
585 blob=(unsigned char *) RelinquishMagickMemory(blob);
586 if (status == MagickFalse)
590 Convert JPEG to MPEG.
592 (void) CopyMagickString(coalesce_image->magick_filename,basename,
594 (void) CopyMagickString(coalesce_image->filename,basename,MaxTextExtent);
595 GetPathComponent(image_info->filename,ExtensionPath,coalesce_image->magick);
596 if (*coalesce_image->magick == '\0')
597 (void) CopyMagickString(coalesce_image->magick,image->magick,MaxTextExtent);
598 status=InvokeDelegate(write_info,coalesce_image,(char *) NULL,"mpeg:encode",
600 (void) FormatMagickString(write_info->filename,MaxTextExtent,"%s.%s",
601 write_info->unique,coalesce_image->magick);
602 status=CopyDelegateFile(write_info->filename,image->filename);
603 (void) RelinquishUniqueFileResource(write_info->filename);
604 write_info=DestroyImageInfo(write_info);
606 Relinquish resources.
609 for (p=coalesce_image; p != (Image *) NULL; p=GetNextImageInList(p))
611 delay=100.0*p->delay/MagickMax(1.0*p->ticks_per_second,1.0);
612 for (i=0; i < (ssize_t) MagickMax((1.0*delay+1.0)/3.0,1.0); i++)
614 (void) FormatMagickString(p->filename,MaxTextExtent,"%s%lu.%s",
615 basename,count++,WriteMPEGIntermediateFormat);
616 (void) RelinquishUniqueFileResource(p->filename);
618 (void) CopyMagickString(p->filename,image_info->filename,MaxTextExtent);
620 (void) RelinquishUniqueFileResource(basename);
621 coalesce_image=DestroyImageList(coalesce_image);
622 if (image->debug != MagickFalse)
623 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit");