blob: b4595c7e74546d9c6352e082ac6124df9e014e46 [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 %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy45ef08f2012-12-07 13:13:34 +000020% Copyright 1999-2013 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);
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);
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);
cristyb51dff52011-05-19 16:55:47 +0000207 (void) FormatLocaleString(read_info->filename,MaxTextExtent,"%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
cristyf34a1452009-10-24 22:29:27 +0000243 entry=SetMagickInfo("AVI");
cristyaded3262009-10-24 22:47:02 +0000244 entry->decoder=(DecodeImageHandler *) ReadMPEGImage;
cristyf34a1452009-10-24 22:29:27 +0000245 entry->magick=(IsImageFormatHandler *) IsAVI;
cristy0fc02592010-05-24 14:12:38 +0000246 entry->blob_support=MagickFalse;
cristyf34a1452009-10-24 22:29:27 +0000247 entry->description=ConstantString("Microsoft Audio/Visual Interleaved");
cristy0fc02592010-05-24 14:12:38 +0000248 entry->module=ConstantString("MPEG");
cristyf34a1452009-10-24 22:29:27 +0000249 (void) RegisterMagickInfo(entry);
cristy3ed852e2009-09-05 21:47:34 +0000250 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);
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");
331 (void) UnregisterMagickInfo("M4V");
332 (void) UnregisterMagickInfo("M2V");
333 (void) UnregisterMagickInfo("MP4");
334 (void) UnregisterMagickInfo("MPG");
335 (void) UnregisterMagickInfo("MPEG");
336 (void) UnregisterMagickInfo("MOV");
cristyf34a1452009-10-24 22:29:27 +0000337 (void) UnregisterMagickInfo("AVI");
cristy3ed852e2009-09-05 21:47:34 +0000338}
339
340/*
341%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
342% %
343% %
344% %
345% W r i t e M P E G I m a g e %
346% %
347% %
348% %
349%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
350%
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.
354%
355% The format of the WriteMPEGImage method is:
356%
357% MagickBooleanType WriteMPEGImage(const ImageInfo *image_info,
cristy1e178e72011-08-28 19:44:34 +0000358% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000359%
360% A description of each parameter follows.
361%
362% o image_info: the image info.
363%
364% o image: The image.
365%
cristy1e178e72011-08-28 19:44:34 +0000366% o exception: return any errors or warnings in this structure.
367%
cristy3ed852e2009-09-05 21:47:34 +0000368*/
369
370static inline double MagickMax(const double x,const double y)
371{
372 if (x > y)
373 return(x);
374 return(y);
375}
376
377static inline double MagickMin(const double x,const double y)
378{
379 if (x < y)
380 return(x);
381 return(y);
382}
383
384static MagickBooleanType CopyDelegateFile(const char *source,
385 const char *destination)
386{
387 int
388 destination_file,
389 source_file;
390
391 MagickBooleanType
392 status;
393
394 register size_t
395 i;
396
397 size_t
398 length,
399 quantum;
400
401 ssize_t
402 count;
403
404 struct stat
405 attributes;
406
407 unsigned char
408 *buffer;
409
410 /*
411 Return if destination file already exists and is not empty.
412 */
413 assert(source != (const char *) NULL);
414 assert(destination != (char *) NULL);
415 status=GetPathAttributes(destination,&attributes);
416 if ((status != MagickFalse) && (attributes.st_size != 0))
417 return(MagickTrue);
418 /*
419 Copy source file to destination.
420 */
cristy18c6c272011-09-23 14:40:37 +0000421 destination_file=open_utf8(destination,O_WRONLY | O_BINARY | O_CREAT,S_MODE);
cristy3ed852e2009-09-05 21:47:34 +0000422 if (destination_file == -1)
423 return(MagickFalse);
cristy18c6c272011-09-23 14:40:37 +0000424 source_file=open_utf8(source,O_RDONLY | O_BINARY,0);
cristy3ed852e2009-09-05 21:47:34 +0000425 if (source_file == -1)
426 {
427 (void) close(destination_file);
428 return(MagickFalse);
429 }
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)
436 {
437 (void) close(source_file);
438 (void) close(destination_file);
439 return(MagickFalse);
440 }
441 length=0;
442 for (i=0; ; i+=count)
443 {
444 count=(ssize_t) read(source_file,buffer,quantum);
445 if (count <= 0)
446 break;
447 length=(size_t) count;
448 count=(ssize_t) write(destination_file,buffer,length);
449 if ((size_t) count != length)
450 break;
451 }
452 (void) close(destination_file);
453 (void) close(source_file);
454 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
455 return(i != 0 ? MagickTrue : MagickFalse);
456}
457
458static MagickBooleanType WriteMPEGImage(const ImageInfo *image_info,
cristy1e178e72011-08-28 19:44:34 +0000459 Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000460{
461#define WriteMPEGIntermediateFormat "jpg"
462
463 char
464 basename[MaxTextExtent],
465 filename[MaxTextExtent];
466
467 double
468 delay;
469
470 Image
471 *coalesce_image;
472
473 ImageInfo
474 *write_info;
475
476 int
477 file;
478
479 MagickBooleanType
480 status;
481
482 register Image
483 *p;
484
cristybb503372010-05-27 20:51:26 +0000485 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000486 i;
487
488 size_t
cristyaff6d802011-04-26 01:46:31 +0000489 count,
490 length,
491 scene;
cristy3ed852e2009-09-05 21:47:34 +0000492
493 unsigned char
494 *blob;
495
cristy3ed852e2009-09-05 21:47:34 +0000496 /*
497 Open output image file.
498 */
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);
cristy3a37efd2011-08-28 20:31:03 +0000505 assert(exception != (ExceptionInfo *) NULL);
506 assert(exception->signature == MagickSignature);
cristy1e178e72011-08-28 19:44:34 +0000507 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000508 if (status == MagickFalse)
509 return(status);
510 (void) CloseBlob(image);
511 /*
cristye9ae8112009-09-21 16:17:49 +0000512 Write intermediate files.
cristy3ed852e2009-09-05 21:47:34 +0000513 */
cristy1e178e72011-08-28 19:44:34 +0000514 coalesce_image=CoalesceImages(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000515 if (coalesce_image == (Image *) NULL)
516 return(MagickFalse);
517 file=AcquireUniqueFileResource(basename);
518 if (file != -1)
519 file=close(file)-1;
cristyb51dff52011-05-19 16:55:47 +0000520 (void) FormatLocaleString(coalesce_image->filename,MaxTextExtent,"%s",
cristy3ed852e2009-09-05 21:47:34 +0000521 basename);
522 count=0;
523 write_info=CloneImageInfo(image_info);
524 for (p=coalesce_image; p != (Image *) NULL; p=GetNextImageInList(p))
525 {
526 char
527 previous_image[MaxTextExtent];
528
529 blob=(unsigned char *) NULL;
530 length=0;
531 scene=p->scene;
532 delay=100.0*p->delay/MagickMax(1.0*p->ticks_per_second,1.0);
cristybb503372010-05-27 20:51:26 +0000533 for (i=0; i < (ssize_t) MagickMax((1.0*delay+1.0)/3.0,1.0); i++)
cristy3ed852e2009-09-05 21:47:34 +0000534 {
535 p->scene=count;
536 count++;
537 status=MagickFalse;
538 switch (i)
539 {
540 case 0:
541 {
542 Image
543 *frame;
544
cristyb51dff52011-05-19 16:55:47 +0000545 (void) FormatLocaleString(p->filename,MaxTextExtent,"%s%.20g.%s",
cristye8c25f92010-06-03 00:53:06 +0000546 basename,(double) p->scene,WriteMPEGIntermediateFormat);
cristyb51dff52011-05-19 16:55:47 +0000547 (void) FormatLocaleString(filename,MaxTextExtent,"%s%.20g.%s",
cristye8c25f92010-06-03 00:53:06 +0000548 basename,(double) p->scene,WriteMPEGIntermediateFormat);
cristyb51dff52011-05-19 16:55:47 +0000549 (void) FormatLocaleString(previous_image,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +0000550 "%s%.20g.%s",basename,(double) p->scene,
cristyf2faecf2010-05-28 19:19:36 +0000551 WriteMPEGIntermediateFormat);
cristy1e178e72011-08-28 19:44:34 +0000552 frame=CloneImage(p,0,0,MagickTrue,exception);
cristy3ed852e2009-09-05 21:47:34 +0000553 if (frame == (Image *) NULL)
554 break;
cristy1e178e72011-08-28 19:44:34 +0000555 status=WriteImage(write_info,frame,exception);
cristy3ed852e2009-09-05 21:47:34 +0000556 frame=DestroyImage(frame);
557 break;
558 }
559 case 1:
560 {
561 blob=(unsigned char *) FileToBlob(previous_image,~0UL,&length,
cristy1e178e72011-08-28 19:44:34 +0000562 exception);
cristy3ed852e2009-09-05 21:47:34 +0000563 }
564 default:
565 {
cristyb51dff52011-05-19 16:55:47 +0000566 (void) FormatLocaleString(filename,MaxTextExtent,"%s%.20g.%s",
cristye8c25f92010-06-03 00:53:06 +0000567 basename,(double) p->scene,WriteMPEGIntermediateFormat);
cristy3ed852e2009-09-05 21:47:34 +0000568 if (length > 0)
cristy1e178e72011-08-28 19:44:34 +0000569 status=BlobToFile(filename,blob,length,exception);
cristy3ed852e2009-09-05 21:47:34 +0000570 break;
571 }
572 }
573 if (image->debug != MagickFalse)
574 {
575 if (status != MagickFalse)
576 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +0000577 "%.20g. Wrote %s file for scene %.20g:",(double) i,
578 WriteMPEGIntermediateFormat,(double) p->scene);
cristy3ed852e2009-09-05 21:47:34 +0000579 else
580 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
cristye8c25f92010-06-03 00:53:06 +0000581 "%.20g. Failed to write %s file for scene %.20g:",(double) i,
582 WriteMPEGIntermediateFormat,(double) p->scene);
583 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s",filename);
cristy3ed852e2009-09-05 21:47:34 +0000584 }
585 }
586 p->scene=scene;
587 if (blob != (unsigned char *) NULL)
588 blob=(unsigned char *) RelinquishMagickMemory(blob);
589 if (status == MagickFalse)
590 break;
591 }
592 /*
593 Convert JPEG to MPEG.
594 */
595 (void) CopyMagickString(coalesce_image->magick_filename,basename,
596 MaxTextExtent);
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",
cristy1e178e72011-08-28 19:44:34 +0000602 exception);
cristyb51dff52011-05-19 16:55:47 +0000603 (void) FormatLocaleString(write_info->filename,MaxTextExtent,"%s.%s",
cristy3ed852e2009-09-05 21:47:34 +0000604 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);
608 /*
609 Relinquish resources.
610 */
611 count=0;
612 for (p=coalesce_image; p != (Image *) NULL; p=GetNextImageInList(p))
613 {
614 delay=100.0*p->delay/MagickMax(1.0*p->ticks_per_second,1.0);
cristybb503372010-05-27 20:51:26 +0000615 for (i=0; i < (ssize_t) MagickMax((1.0*delay+1.0)/3.0,1.0); i++)
cristy3ed852e2009-09-05 21:47:34 +0000616 {
cristyb51dff52011-05-19 16:55:47 +0000617 (void) FormatLocaleString(p->filename,MaxTextExtent,"%s%.20g.%s",
cristye8c25f92010-06-03 00:53:06 +0000618 basename,(double) count++,WriteMPEGIntermediateFormat);
cristy3ed852e2009-09-05 21:47:34 +0000619 (void) RelinquishUniqueFileResource(p->filename);
620 }
621 (void) CopyMagickString(p->filename,image_info->filename,MaxTextExtent);
622 }
623 (void) RelinquishUniqueFileResource(basename);
624 coalesce_image=DestroyImageList(coalesce_image);
625 if (image->debug != MagickFalse)
626 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit");
627 return(status);
628}