blob: be6689d4891ca460fd402274b144a8c0d1369d92 [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% %
Cristyf6ff9ea2016-12-05 09:53:35 -050020% Copyright 1999-2017 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% %
Cristyf19d4142017-04-24 11:34:30 -040026% https://www.imagemagick.org/script/license.php %
cristy3ed852e2009-09-05 21:47:34 +000027% %
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
Cristyb066eae2017-01-20 09:15:54 -0500243 entry=AcquireMagickInfo("MPEG","3GP","Media Container");
244 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
245 entry->flags^=CoderBlobSupportFlag;
246 entry->flags|=CoderSeekableStreamFlag;
247 (void) RegisterMagickInfo(entry);
248 entry=AcquireMagickInfo("MPEG","3G2","Media Container");
249 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
250 entry->flags^=CoderBlobSupportFlag;
251 entry->flags|=CoderSeekableStreamFlag;
252 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000253 entry=AcquireMagickInfo("MPEG","AVI","Microsoft Audio/Visual Interleaved");
cristyaded3262009-10-24 22:47:02 +0000254 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
cristyf34a1452009-10-24 22:29:27 +0000255 entry->magick=(IsImageFormatHandler *) IsAVI;
dirk08e9a112015-02-22 01:51:41 +0000256 entry->flags^=CoderBlobSupportFlag;
cristyf34a1452009-10-24 22:29:27 +0000257 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000258 entry=AcquireMagickInfo("MPEG","MKV","Multimedia Container");
cristya3d81422015-04-03 13:00:33 +0000259 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
260 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
261 entry->magick=(IsImageFormatHandler *) IsMPEG;
262 entry->flags^=CoderBlobSupportFlag;
cristya3d81422015-04-03 13:00:33 +0000263 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000264 entry=AcquireMagickInfo("MPEG","MOV","MPEG Video Stream");
cristy3ed852e2009-09-05 21:47:34 +0000265 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
266 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
267 entry->magick=(IsImageFormatHandler *) IsMPEG;
dirk08e9a112015-02-22 01:51:41 +0000268 entry->flags^=CoderBlobSupportFlag;
cristy3ed852e2009-09-05 21:47:34 +0000269 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000270 entry=AcquireMagickInfo("MPEG","MPEG","MPEG Video Stream");
cristy3ed852e2009-09-05 21:47:34 +0000271 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
272 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
273 entry->magick=(IsImageFormatHandler *) IsMPEG;
dirk08e9a112015-02-22 01:51:41 +0000274 entry->flags^=CoderBlobSupportFlag;
cristy3ed852e2009-09-05 21:47:34 +0000275 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000276 entry=AcquireMagickInfo("MPEG","MPG","MPEG Video Stream");
cristy3ed852e2009-09-05 21:47:34 +0000277 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
278 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
279 entry->magick=(IsImageFormatHandler *) IsMPEG;
dirk08e9a112015-02-22 01:51:41 +0000280 entry->flags^=CoderBlobSupportFlag;
cristy3ed852e2009-09-05 21:47:34 +0000281 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000282 entry=AcquireMagickInfo("MPEG","MP4","MPEG-4 Video Stream");
cristy3ed852e2009-09-05 21:47:34 +0000283 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
284 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
285 entry->magick=(IsImageFormatHandler *) IsMPEG;
dirk08e9a112015-02-22 01:51:41 +0000286 entry->flags^=CoderBlobSupportFlag;
cristy3ed852e2009-09-05 21:47:34 +0000287 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000288 entry=AcquireMagickInfo("MPEG","M2V","MPEG Video Stream");
cristy3ed852e2009-09-05 21:47:34 +0000289 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
290 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
291 entry->magick=(IsImageFormatHandler *) IsMPEG;
dirk08e9a112015-02-22 01:51:41 +0000292 entry->flags^=CoderBlobSupportFlag;
cristy3ed852e2009-09-05 21:47:34 +0000293 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000294 entry=AcquireMagickInfo("MPEG","M4V","Raw MPEG-4 Video");
cristy3ed852e2009-09-05 21:47:34 +0000295 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
296 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
297 entry->magick=(IsImageFormatHandler *) IsMPEG;
dirk08e9a112015-02-22 01:51:41 +0000298 entry->flags^=CoderBlobSupportFlag;
cristy3ed852e2009-09-05 21:47:34 +0000299 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +0000300 entry=AcquireMagickInfo("MPEG","WMV","Windows Media Video");
cristy3ed852e2009-09-05 21:47:34 +0000301 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
302 entry->encoder=(EncodeImageHandler *) WriteMPEGImage;
303 entry->magick=(IsImageFormatHandler *) IsMPEG;
dirk08e9a112015-02-22 01:51:41 +0000304 entry->flags^=CoderBlobSupportFlag;
cristy3ed852e2009-09-05 21:47:34 +0000305 (void) RegisterMagickInfo(entry);
306 return(MagickImageCoderSignature);
307}
308
309/*
310%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
311% %
312% %
313% %
314% U n r e g i s t e r M P E G I m a g e %
315% %
316% %
317% %
318%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
319%
320% UnregisterMPEGImage() removes format registrations made by the
321% BIM module from the list of supported formats.
322%
323% The format of the UnregisterBIMImage method is:
324%
325% UnregisterMPEGImage(void)
326%
327*/
328ModuleExport void UnregisterMPEGImage(void)
329{
330 (void) UnregisterMagickInfo("WMV");
cristya3d81422015-04-03 13:00:33 +0000331 (void) UnregisterMagickInfo("MOV");
cristy3ed852e2009-09-05 21:47:34 +0000332 (void) UnregisterMagickInfo("M4V");
333 (void) UnregisterMagickInfo("M2V");
334 (void) UnregisterMagickInfo("MP4");
335 (void) UnregisterMagickInfo("MPG");
336 (void) UnregisterMagickInfo("MPEG");
cristya3d81422015-04-03 13:00:33 +0000337 (void) UnregisterMagickInfo("MKV");
cristyf34a1452009-10-24 22:29:27 +0000338 (void) UnregisterMagickInfo("AVI");
Cristyb066eae2017-01-20 09:15:54 -0500339 (void) UnregisterMagickInfo("3G2");
340 (void) UnregisterMagickInfo("3GP");
cristy3ed852e2009-09-05 21:47:34 +0000341}
342
343/*
344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
345% %
346% %
347% %
348% W r i t e M P E G I m a g e %
349% %
350% %
351% %
352%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
353%
354% WriteMPEGImage() writes an image to a file in MPEG video stream format.
355% Lawrence Livermore National Laboratory (LLNL) contributed code to adjust
356% the MPEG parameters to correspond to the compression quality setting.
357%
358% The format of the WriteMPEGImage method is:
359%
360% MagickBooleanType WriteMPEGImage(const ImageInfo *image_info,
cristy1e178e72011-08-28 19:44:34 +0000361% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000362%
363% A description of each parameter follows.
364%
365% o image_info: the image info.
366%
367% o image: The image.
368%
cristy1e178e72011-08-28 19:44:34 +0000369% o exception: return any errors or warnings in this structure.
370%
cristy3ed852e2009-09-05 21:47:34 +0000371*/
cristy3ed852e2009-09-05 21:47:34 +0000372static MagickBooleanType CopyDelegateFile(const char *source,
373 const char *destination)
374{
375 int
376 destination_file,
377 source_file;
378
379 MagickBooleanType
380 status;
381
382 register size_t
383 i;
384
385 size_t
386 length,
387 quantum;
388
389 ssize_t
390 count;
391
392 struct stat
393 attributes;
394
395 unsigned char
396 *buffer;
397
398 /*
399 Return if destination file already exists and is not empty.
400 */
401 assert(source != (const char *) NULL);
402 assert(destination != (char *) NULL);
403 status=GetPathAttributes(destination,&attributes);
cristyf201ba62015-07-05 13:54:28 +0000404 if ((status != MagickFalse) && (attributes.st_size > 0))
cristy3ed852e2009-09-05 21:47:34 +0000405 return(MagickTrue);
406 /*
407 Copy source file to destination.
408 */
cristy18c6c272011-09-23 14:40:37 +0000409 destination_file=open_utf8(destination,O_WRONLY | O_BINARY | O_CREAT,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000410 if (destination_file == -1)
411 return(MagickFalse);
cristy18c6c272011-09-23 14:40:37 +0000412 source_file=open_utf8(source,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000413 if (source_file == -1)
414 {
415 (void) close(destination_file);
416 return(MagickFalse);
417 }
418 quantum=(size_t) MagickMaxBufferExtent;
cristyf201ba62015-07-05 13:54:28 +0000419 if ((fstat(source_file,&attributes) == 0) && (attributes.st_size > 0))
cristy3ed852e2009-09-05 21:47:34 +0000420 quantum=(size_t) MagickMin((double) attributes.st_size,
421 MagickMaxBufferExtent);
422 buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
423 if (buffer == (unsigned char *) NULL)
424 {
425 (void) close(source_file);
426 (void) close(destination_file);
427 return(MagickFalse);
428 }
429 length=0;
430 for (i=0; ; i+=count)
431 {
432 count=(ssize_t) read(source_file,buffer,quantum);
433 if (count <= 0)
434 break;
435 length=(size_t) count;
436 count=(ssize_t) write(destination_file,buffer,length);
437 if ((size_t) count != length)
438 break;
439 }
440 (void) close(destination_file);
441 (void) close(source_file);
442 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
443 return(i != 0 ? MagickTrue : MagickFalse);
444}
445
446static MagickBooleanType WriteMPEGImage(const ImageInfo *image_info,
cristy1e178e72011-08-28 19:44:34 +0000447 Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000448{
449#define WriteMPEGIntermediateFormat "jpg"
450
451 char
cristy151b66d2015-04-15 10:50:31 +0000452 basename[MagickPathExtent],
453 filename[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +0000454
455 double
456 delay;
457
458 Image
459 *coalesce_image;
460
461 ImageInfo
462 *write_info;
463
464 int
465 file;
466
467 MagickBooleanType
468 status;
469
470 register Image
471 *p;
472
cristybb503372010-05-27 20:51:26 +0000473 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000474 i;
475
476 size_t
cristyaff6d802011-04-26 01:46:31 +0000477 count,
478 length,
479 scene;
cristy3ed852e2009-09-05 21:47:34 +0000480
481 unsigned char
482 *blob;
483
cristy3ed852e2009-09-05 21:47:34 +0000484 /*
485 Open output image file.
486 */
487 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000488 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000489 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000490 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000491 if (image->debug != MagickFalse)
492 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +0000493 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000494 assert(exception->signature == MagickCoreSignature);
cristy1e178e72011-08-28 19:44:34 +0000495 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000496 if (status == MagickFalse)
497 return(status);
498 (void) CloseBlob(image);
499 /*
cristye9ae8112009-09-21 16:17:49 +0000500 Write intermediate files.
cristy3ed852e2009-09-05 21:47:34 +0000501 */
cristy1e178e72011-08-28 19:44:34 +0000502 coalesce_image=CoalesceImages(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000503 if (coalesce_image == (Image *) NULL)
504 return(MagickFalse);
505 file=AcquireUniqueFileResource(basename);
506 if (file != -1)
507 file=close(file)-1;
cristy151b66d2015-04-15 10:50:31 +0000508 (void) FormatLocaleString(coalesce_image->filename,MagickPathExtent,"%s",
cristy3ed852e2009-09-05 21:47:34 +0000509 basename);
510 count=0;
511 write_info=CloneImageInfo(image_info);
cristy386d8ba2015-02-25 02:45:59 +0000512 *write_info->magick='\0';
cristy3ed852e2009-09-05 21:47:34 +0000513 for (p=coalesce_image; p != (Image *) NULL; p=GetNextImageInList(p))
514 {
515 char
cristy151b66d2015-04-15 10:50:31 +0000516 previous_image[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +0000517
518 blob=(unsigned char *) NULL;
519 length=0;
520 scene=p->scene;
521 delay=100.0*p->delay/MagickMax(1.0*p->ticks_per_second,1.0);
cristybb503372010-05-27 20:51:26 +0000522 for (i=0; i < (ssize_t) MagickMax((1.0*delay+1.0)/3.0,1.0); i++)
cristy3ed852e2009-09-05 21:47:34 +0000523 {
524 p->scene=count;
525 count++;
526 status=MagickFalse;
527 switch (i)
528 {
529 case 0:
530 {
531 Image
532 *frame;
533
cristy151b66d2015-04-15 10:50:31 +0000534 (void) FormatLocaleString(p->filename,MagickPathExtent,"%s%.20g.%s",
cristye8c25f92010-06-03 00:53:06 +0000535 basename,(double) p->scene,WriteMPEGIntermediateFormat);
cristy151b66d2015-04-15 10:50:31 +0000536 (void) FormatLocaleString(filename,MagickPathExtent,"%s%.20g.%s",
cristye8c25f92010-06-03 00:53:06 +0000537 basename,(double) p->scene,WriteMPEGIntermediateFormat);
cristy151b66d2015-04-15 10:50:31 +0000538 (void) FormatLocaleString(previous_image,MagickPathExtent,
cristye8c25f92010-06-03 00:53:06 +0000539 "%s%.20g.%s",basename,(double) p->scene,
cristyf2faecf2010-05-28 19:19:36 +0000540 WriteMPEGIntermediateFormat);
cristy1e178e72011-08-28 19:44:34 +0000541 frame=CloneImage(p,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +0000542 if (frame == (Image *) NULL)
543 break;
cristy1e178e72011-08-28 19:44:34 +0000544 status=WriteImage(write_info,frame,exception);
cristy3ed852e2009-09-05 21:47:34 +0000545 frame=DestroyImage(frame);
546 break;
547 }
548 case 1:
549 {
550 blob=(unsigned char *) FileToBlob(previous_image,~0UL,&length,
cristy1e178e72011-08-28 19:44:34 +0000551 exception);
cristy3ed852e2009-09-05 21:47:34 +0000552 }
553 default:
554 {
cristy151b66d2015-04-15 10:50:31 +0000555 (void) FormatLocaleString(filename,MagickPathExtent,"%s%.20g.%s",
cristye8c25f92010-06-03 00:53:06 +0000556 basename,(double) p->scene,WriteMPEGIntermediateFormat);
cristy3ed852e2009-09-05 21:47:34 +0000557 if (length > 0)
cristy1e178e72011-08-28 19:44:34 +0000558 status=BlobToFile(filename,blob,length,exception);
cristy3ed852e2009-09-05 21:47:34 +0000559 break;
560 }
561 }
562 if (image->debug != MagickFalse)
563 {
564 if (status != MagickFalse)
565 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +0000566 "%.20g. Wrote %s file for scene %.20g:",(double) i,
567 WriteMPEGIntermediateFormat,(double) p->scene);
cristy3ed852e2009-09-05 21:47:34 +0000568 else
569 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +0000570 "%.20g. Failed to write %s file for scene %.20g:",(double) i,
571 WriteMPEGIntermediateFormat,(double) p->scene);
572 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s",filename);
cristy3ed852e2009-09-05 21:47:34 +0000573 }
574 }
575 p->scene=scene;
576 if (blob != (unsigned char *) NULL)
577 blob=(unsigned char *) RelinquishMagickMemory(blob);
578 if (status == MagickFalse)
579 break;
580 }
581 /*
582 Convert JPEG to MPEG.
583 */
584 (void) CopyMagickString(coalesce_image->magick_filename,basename,
cristy151b66d2015-04-15 10:50:31 +0000585 MagickPathExtent);
586 (void) CopyMagickString(coalesce_image->filename,basename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000587 GetPathComponent(image_info->filename,ExtensionPath,coalesce_image->magick);
588 if (*coalesce_image->magick == '\0')
cristy151b66d2015-04-15 10:50:31 +0000589 (void) CopyMagickString(coalesce_image->magick,image->magick,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000590 status=InvokeDelegate(write_info,coalesce_image,(char *) NULL,"mpeg:encode",
cristy1e178e72011-08-28 19:44:34 +0000591 exception);
cristy151b66d2015-04-15 10:50:31 +0000592 (void) FormatLocaleString(write_info->filename,MagickPathExtent,"%s.%s",
cristy3ed852e2009-09-05 21:47:34 +0000593 write_info->unique,coalesce_image->magick);
594 status=CopyDelegateFile(write_info->filename,image->filename);
595 (void) RelinquishUniqueFileResource(write_info->filename);
596 write_info=DestroyImageInfo(write_info);
597 /*
598 Relinquish resources.
599 */
600 count=0;
601 for (p=coalesce_image; p != (Image *) NULL; p=GetNextImageInList(p))
602 {
603 delay=100.0*p->delay/MagickMax(1.0*p->ticks_per_second,1.0);
cristybb503372010-05-27 20:51:26 +0000604 for (i=0; i < (ssize_t) MagickMax((1.0*delay+1.0)/3.0,1.0); i++)
cristy3ed852e2009-09-05 21:47:34 +0000605 {
cristy151b66d2015-04-15 10:50:31 +0000606 (void) FormatLocaleString(p->filename,MagickPathExtent,"%s%.20g.%s",
cristye8c25f92010-06-03 00:53:06 +0000607 basename,(double) count++,WriteMPEGIntermediateFormat);
cristy3ed852e2009-09-05 21:47:34 +0000608 (void) RelinquishUniqueFileResource(p->filename);
609 }
cristy151b66d2015-04-15 10:50:31 +0000610 (void) CopyMagickString(p->filename,image_info->filename,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000611 }
612 (void) RelinquishUniqueFileResource(basename);
613 coalesce_image=DestroyImageList(coalesce_image);
614 if (image->debug != MagickFalse)
615 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit");
616 return(status);
617}