blob: 782aa14e73f3f42d2d3121e74011a150b47e4b7a [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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 %
cristyde984cd2013-12-01 14:49:27 +000016% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000017% July 1999 %
18% %
19% %
Cristy7ce65e72015-12-12 18:03:16 -050020% Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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*/
cristy4c08aed2011-07-01 19:47:50 +000041#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"
cristy18c6c272011-09-23 14:40:37 +000063#include "MagickCore/utility-private.h"
cristy3ed852e2009-09-05 21:47:34 +000064
65/*
66 Forward declarations.
67*/
68static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +000069 WriteMPEGImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +000070
71/*
72%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73% %
74% %
75% %
cristyaded3262009-10-24 22:47:02 +000076% 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%
cristybb503372010-05-27 20:51:26 +000087% size_t IsAVI(const unsigned char *magick,const size_t length)
cristyaded3262009-10-24 22:47:02 +000088%
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% %
cristy3ed852e2009-09-05 21:47:34 +0000110% 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);
cristye1c94d92015-06-28 12:16:33 +0000185 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000186 if (image_info->debug != MagickFalse)
187 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
188 image_info->filename);
189 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000190 assert(exception->signature == MagickCoreSignature);
cristy9950d572011-10-01 18:22:35 +0000191 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000192 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);
cristy9950d572011-10-01 18:22:35 +0000204 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000205 (void) InvokeDelegate(read_info,image,"mpeg:decode",(char *) NULL,exception);
206 image=DestroyImage(image);
cristy151b66d2015-04-15 10:50:31 +0000207 (void) FormatLocaleString(read_info->filename,MagickPathExtent,"%s.%s",
cristy3ed852e2009-09-05 21:47:34 +0000208 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%
cristybb503372010-05-27 20:51:26 +0000235% size_t RegisterMPEGImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000236%
237*/
cristybb503372010-05-27 20:51:26 +0000238ModuleExport size_t RegisterMPEGImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000239{
240 MagickInfo
241 *entry;
242
dirk06b627a2015-04-06 18:59:17 +0000243 entry=AcquireMagickInfo("MPEG","AVI","Microsoft Audio/Visual Interleaved");
cristyaded3262009-10-24 22:47:02 +0000244 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
cristyf34a1452009-10-24 22:29:27 +0000245 entry->magick=(IsImageFormatHandler *) IsAVI;
dirk08e9a112015-02-22 01:51:41 +0000246 entry->flags^=CoderBlobSupportFlag;
cristyf34a1452009-10-24 22:29:27 +0000247 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000248 entry=AcquireMagickInfo("MPEG","MKV","Multimedia Container");
cristya3d81422015-04-03 13:00:33 +0000249 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
250 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
251 entry->magick=(IsImageFormatHandler *) IsMPEG;
252 entry->flags^=CoderBlobSupportFlag;
cristya3d81422015-04-03 13:00:33 +0000253 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000254 entry=AcquireMagickInfo("MPEG","MOV","MPEG Video Stream");
cristy3ed852e2009-09-05 21:47:34 +0000255 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
256 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
257 entry->magick=(IsImageFormatHandler *) IsMPEG;
dirk08e9a112015-02-22 01:51:41 +0000258 entry->flags^=CoderBlobSupportFlag;
cristy3ed852e2009-09-05 21:47:34 +0000259 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000260 entry=AcquireMagickInfo("MPEG","MPEG","MPEG Video Stream");
cristy3ed852e2009-09-05 21:47:34 +0000261 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
262 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
263 entry->magick=(IsImageFormatHandler *) IsMPEG;
dirk08e9a112015-02-22 01:51:41 +0000264 entry->flags^=CoderBlobSupportFlag;
cristy3ed852e2009-09-05 21:47:34 +0000265 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000266 entry=AcquireMagickInfo("MPEG","MPG","MPEG Video Stream");
cristy3ed852e2009-09-05 21:47:34 +0000267 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
268 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
269 entry->magick=(IsImageFormatHandler *) IsMPEG;
dirk08e9a112015-02-22 01:51:41 +0000270 entry->flags^=CoderBlobSupportFlag;
cristy3ed852e2009-09-05 21:47:34 +0000271 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000272 entry=AcquireMagickInfo("MPEG","MP4","MPEG-4 Video Stream");
cristy3ed852e2009-09-05 21:47:34 +0000273 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
274 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
275 entry->magick=(IsImageFormatHandler *) IsMPEG;
dirk08e9a112015-02-22 01:51:41 +0000276 entry->flags^=CoderBlobSupportFlag;
cristy3ed852e2009-09-05 21:47:34 +0000277 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000278 entry=AcquireMagickInfo("MPEG","M2V","MPEG Video Stream");
cristy3ed852e2009-09-05 21:47:34 +0000279 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
280 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
281 entry->magick=(IsImageFormatHandler *) IsMPEG;
dirk08e9a112015-02-22 01:51:41 +0000282 entry->flags^=CoderBlobSupportFlag;
cristy3ed852e2009-09-05 21:47:34 +0000283 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000284 entry=AcquireMagickInfo("MPEG","M4V","Raw MPEG-4 Video");
cristy3ed852e2009-09-05 21:47:34 +0000285 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
286 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
287 entry->magick=(IsImageFormatHandler *) IsMPEG;
dirk08e9a112015-02-22 01:51:41 +0000288 entry->flags^=CoderBlobSupportFlag;
cristy3ed852e2009-09-05 21:47:34 +0000289 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000290 entry=AcquireMagickInfo("MPEG","WMV","Windows Media Video");
cristy3ed852e2009-09-05 21:47:34 +0000291 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
292 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
293 entry->magick=(IsImageFormatHandler *) IsMPEG;
dirk08e9a112015-02-22 01:51:41 +0000294 entry->flags^=CoderBlobSupportFlag;
cristy3ed852e2009-09-05 21:47:34 +0000295 (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");
cristya3d81422015-04-03 13:00:33 +0000321 (void) UnregisterMagickInfo("MOV");
cristy3ed852e2009-09-05 21:47:34 +0000322 (void) UnregisterMagickInfo("M4V");
323 (void) UnregisterMagickInfo("M2V");
324 (void) UnregisterMagickInfo("MP4");
325 (void) UnregisterMagickInfo("MPG");
326 (void) UnregisterMagickInfo("MPEG");
cristya3d81422015-04-03 13:00:33 +0000327 (void) UnregisterMagickInfo("MKV");
cristyf34a1452009-10-24 22:29:27 +0000328 (void) UnregisterMagickInfo("AVI");
cristy3ed852e2009-09-05 21:47:34 +0000329}
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,
cristy1e178e72011-08-28 19:44:34 +0000349% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000350%
351% A description of each parameter follows.
352%
353% o image_info: the image info.
354%
355% o image: The image.
356%
cristy1e178e72011-08-28 19:44:34 +0000357% o exception: return any errors or warnings in this structure.
358%
cristy3ed852e2009-09-05 21:47:34 +0000359*/
cristy3ed852e2009-09-05 21:47:34 +0000360static 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);
cristyf201ba62015-07-05 13:54:28 +0000392 if ((status != MagickFalse) && (attributes.st_size > 0))
cristy3ed852e2009-09-05 21:47:34 +0000393 return(MagickTrue);
394 /*
395 Copy source file to destination.
396 */
cristy18c6c272011-09-23 14:40:37 +0000397 destination_file=open_utf8(destination,O_WRONLY | O_BINARY | O_CREAT,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000398 if (destination_file == -1)
399 return(MagickFalse);
cristy18c6c272011-09-23 14:40:37 +0000400 source_file=open_utf8(source,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000401 if (source_file == -1)
402 {
403 (void) close(destination_file);
404 return(MagickFalse);
405 }
406 quantum=(size_t) MagickMaxBufferExtent;
cristyf201ba62015-07-05 13:54:28 +0000407 if ((fstat(source_file,&attributes) == 0) && (attributes.st_size > 0))
cristy3ed852e2009-09-05 21:47:34 +0000408 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,
cristy1e178e72011-08-28 19:44:34 +0000435 Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000436{
437#define WriteMPEGIntermediateFormat "jpg"
438
439 char
cristy151b66d2015-04-15 10:50:31 +0000440 basename[MagickPathExtent],
441 filename[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +0000442
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
cristybb503372010-05-27 20:51:26 +0000461 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000462 i;
463
464 size_t
cristyaff6d802011-04-26 01:46:31 +0000465 count,
466 length,
467 scene;
cristy3ed852e2009-09-05 21:47:34 +0000468
469 unsigned char
470 *blob;
471
cristy3ed852e2009-09-05 21:47:34 +0000472 /*
473 Open output image file.
474 */
475 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000476 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000477 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000478 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000479 if (image->debug != MagickFalse)
480 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +0000481 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000482 assert(exception->signature == MagickCoreSignature);
cristy1e178e72011-08-28 19:44:34 +0000483 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000484 if (status == MagickFalse)
485 return(status);
486 (void) CloseBlob(image);
487 /*
cristye9ae8112009-09-21 16:17:49 +0000488 Write intermediate files.
cristy3ed852e2009-09-05 21:47:34 +0000489 */
cristy1e178e72011-08-28 19:44:34 +0000490 coalesce_image=CoalesceImages(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000491 if (coalesce_image == (Image *) NULL)
492 return(MagickFalse);
493 file=AcquireUniqueFileResource(basename);
494 if (file != -1)
495 file=close(file)-1;
cristy151b66d2015-04-15 10:50:31 +0000496 (void) FormatLocaleString(coalesce_image->filename,MagickPathExtent,"%s",
cristy3ed852e2009-09-05 21:47:34 +0000497 basename);
498 count=0;
499 write_info=CloneImageInfo(image_info);
cristy386d8ba2015-02-25 02:45:59 +0000500 *write_info->magick='\0';
cristy3ed852e2009-09-05 21:47:34 +0000501 for (p=coalesce_image; p != (Image *) NULL; p=GetNextImageInList(p))
502 {
503 char
cristy151b66d2015-04-15 10:50:31 +0000504 previous_image[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +0000505
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);
cristybb503372010-05-27 20:51:26 +0000510 for (i=0; i < (ssize_t) MagickMax((1.0*delay+1.0)/3.0,1.0); i++)
cristy3ed852e2009-09-05 21:47:34 +0000511 {
512 p->scene=count;
513 count++;
514 status=MagickFalse;
515 switch (i)
516 {
517 case 0:
518 {
519 Image
520 *frame;
521
cristy151b66d2015-04-15 10:50:31 +0000522 (void) FormatLocaleString(p->filename,MagickPathExtent,"%s%.20g.%s",
cristye8c25f92010-06-03 00:53:06 +0000523 basename,(double) p->scene,WriteMPEGIntermediateFormat);
cristy151b66d2015-04-15 10:50:31 +0000524 (void) FormatLocaleString(filename,MagickPathExtent,"%s%.20g.%s",
cristye8c25f92010-06-03 00:53:06 +0000525 basename,(double) p->scene,WriteMPEGIntermediateFormat);
cristy151b66d2015-04-15 10:50:31 +0000526 (void) FormatLocaleString(previous_image,MagickPathExtent,
cristye8c25f92010-06-03 00:53:06 +0000527 "%s%.20g.%s",basename,(double) p->scene,
cristyf2faecf2010-05-28 19:19:36 +0000528 WriteMPEGIntermediateFormat);
cristy1e178e72011-08-28 19:44:34 +0000529 frame=CloneImage(p,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +0000530 if (frame == (Image *) NULL)
531 break;
cristy1e178e72011-08-28 19:44:34 +0000532 status=WriteImage(write_info,frame,exception);
cristy3ed852e2009-09-05 21:47:34 +0000533 frame=DestroyImage(frame);
534 break;
535 }
536 case 1:
537 {
538 blob=(unsigned char *) FileToBlob(previous_image,~0UL,&length,
cristy1e178e72011-08-28 19:44:34 +0000539 exception);
cristy3ed852e2009-09-05 21:47:34 +0000540 }
541 default:
542 {
cristy151b66d2015-04-15 10:50:31 +0000543 (void) FormatLocaleString(filename,MagickPathExtent,"%s%.20g.%s",
cristye8c25f92010-06-03 00:53:06 +0000544 basename,(double) p->scene,WriteMPEGIntermediateFormat);
cristy3ed852e2009-09-05 21:47:34 +0000545 if (length > 0)
cristy1e178e72011-08-28 19:44:34 +0000546 status=BlobToFile(filename,blob,length,exception);
cristy3ed852e2009-09-05 21:47:34 +0000547 break;
548 }
549 }
550 if (image->debug != MagickFalse)
551 {
552 if (status != MagickFalse)
553 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +0000554 "%.20g. Wrote %s file for scene %.20g:",(double) i,
555 WriteMPEGIntermediateFormat,(double) p->scene);
cristy3ed852e2009-09-05 21:47:34 +0000556 else
557 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +0000558 "%.20g. Failed to write %s file for scene %.20g:",(double) i,
559 WriteMPEGIntermediateFormat,(double) p->scene);
560 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s",filename);
cristy3ed852e2009-09-05 21:47:34 +0000561 }
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,
cristy151b66d2015-04-15 10:50:31 +0000573 MagickPathExtent);
574 (void) CopyMagickString(coalesce_image->filename,basename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000575 GetPathComponent(image_info->filename,ExtensionPath,coalesce_image->magick);
576 if (*coalesce_image->magick == '\0')
cristy151b66d2015-04-15 10:50:31 +0000577 (void) CopyMagickString(coalesce_image->magick,image->magick,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000578 status=InvokeDelegate(write_info,coalesce_image,(char *) NULL,"mpeg:encode",
cristy1e178e72011-08-28 19:44:34 +0000579 exception);
cristy151b66d2015-04-15 10:50:31 +0000580 (void) FormatLocaleString(write_info->filename,MagickPathExtent,"%s.%s",
cristy3ed852e2009-09-05 21:47:34 +0000581 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);
cristybb503372010-05-27 20:51:26 +0000592 for (i=0; i < (ssize_t) MagickMax((1.0*delay+1.0)/3.0,1.0); i++)
cristy3ed852e2009-09-05 21:47:34 +0000593 {
cristy151b66d2015-04-15 10:50:31 +0000594 (void) FormatLocaleString(p->filename,MagickPathExtent,"%s%.20g.%s",
cristye8c25f92010-06-03 00:53:06 +0000595 basename,(double) count++,WriteMPEGIntermediateFormat);
cristy3ed852e2009-09-05 21:47:34 +0000596 (void) RelinquishUniqueFileResource(p->filename);
597 }
cristy151b66d2015-04-15 10:50:31 +0000598 (void) CopyMagickString(p->filename,image_info->filename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000599 }
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}