Fix some error handling in mod_libavcodec. Still crashes though.
[synfig.git] / synfig-core / trunk / src / modules / mod_libavcodec / trgt_av.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file trgt.cpp
3 **      \brief \writeme
4 **
5 **      $Id: trgt_av.cpp,v 1.1.1.1 2005/01/04 01:23:11 darco Exp $
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **
10 **      This package is free software; you can redistribute it and/or
11 **      modify it under the terms of the GNU General Public License as
12 **      published by the Free Software Foundation; either version 2 of
13 **      the License, or (at your option) any later version.
14 **
15 **      This package is distributed in the hope that it will be useful,
16 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 **      General Public License for more details.
19 **      \endlegal
20 */
21 /* ========================================================================= */
22
23 /* === H E A D E R S ======================================================= */
24
25 #define SYNFIG_NO_ANGLE
26
27 #ifdef USING_PCH
28 #       include "pch.h"
29 #else
30 #ifdef HAVE_CONFIG_H
31 #       include <config.h>
32 #endif
33
34 #include "trgt_av.h"
35
36 extern "C"
37 {
38 #include <avformat.h>
39 }
40
41 #include <synfig/general.h>
42
43 #include <cstdio>
44 #include <algorithm>
45 #include <functional>
46 #endif
47
48 #ifdef WIN32
49 #define snprintf        _snprintf
50 #endif
51
52 /* === U S I N G =========================================================== */
53
54 using namespace synfig;
55 using namespace std;
56 using namespace etl;
57
58 /* === I N F O ============================================================= */
59
60 SYNFIG_TARGET_INIT(Target_LibAVCodec);
61 SYNFIG_TARGET_SET_NAME(Target_LibAVCodec,"libav");
62 SYNFIG_TARGET_SET_EXT(Target_LibAVCodec,"avi");
63 SYNFIG_TARGET_SET_VERSION(Target_LibAVCodec,"0.1");
64 SYNFIG_TARGET_SET_CVS_ID(Target_LibAVCodec,"$Id: trgt_av.cpp,v 1.1.1.1 2005/01/04 01:23:11 darco Exp $");
65
66 /* === C L A S S E S & S T R U C T S ======================================= */
67
68 bool Target_LibAVCodec::registered = false;
69
70 //for now compilation
71 //float STREAM_DURATION = 5.0f;
72
73 struct VideoInfo
74 {
75         int     w,h;
76         int     fps;
77         
78         int bitrate;            
79 };
80
81 struct AudioInfo
82 {
83         int     samplerate;     //in HZ
84         int     samplesize;     //in bytes
85 };
86
87 AVFrame *alloc_picture(int pix_fmt, int width, int height)
88 {
89     AVFrame *picture;
90     uint8_t *picture_buf;
91     int size;
92     
93     picture = avcodec_alloc_frame();
94     if (!picture)
95         return NULL;
96     size = avpicture_get_size(pix_fmt, width, height);
97     picture_buf = (uint8_t *)malloc(size);
98     if (!picture_buf) {
99         av_free(picture);
100         return NULL;
101     }
102     avpicture_fill((AVPicture *)picture, picture_buf, 
103                    pix_fmt, width, height);
104     return picture;
105 }
106
107 void free_picture(AVFrame *pic)
108 {
109         av_free(pic->data[0]);
110         av_free(pic);
111 }
112
113 //the frame must be RGB24
114 static void convert_surface_frame(AVFrame *pic, const Surface &s, const Gamma &gamma)
115 {
116         unsigned int j;
117         Surface::const_pen p = s.begin();
118         unsigned int w,h;
119         Color c;
120         
121         uint8_t *ptr;
122         int stride;
123                 
124         w = s.size().x;
125         h = s.size().y;
126         
127         ptr = pic->data[0];
128         stride = pic->linesize[0];
129
130         for(j = 0; j < h; j++, p.inc_y(), ptr += stride)
131         {
132                 uint8_t *tptr = ptr;
133                 
134                 //use convert_color_format instead...
135                 #if 0
136                 const int channels = 3;
137                 
138                 for(int i = 0; i < w; i++, p.inc_x(), tptr += channels)
139                 {
140                         c = p.get_value();
141                         
142                         Color::value_type r = c.get_r();
143                         Color::value_type g = c.get_g();
144                         Color::value_type b = c.get_b();
145                         Color::value_type a = c.get_a();
146                         
147                         //premultiply alpha
148                         r *= a;
149                         g *= a;
150                         b *= a;
151                         
152                         //essentially treats it as if it has a background color of black
153                         
154                         //we must also clamp the rgb values [0,1]
155                         r = min(1.0f,r);
156                         g = min(1.0f,g);
157                         b = min(1.0f,b);
158                         
159                         r = max(0.0f,r);
160                         g = max(0.0f,g);
161                         b = max(0.0f,b);
162
163                         //now scale to range of char [0,255]
164                         tptr[0] = (int)(r*255);
165                         tptr[1] = (int)(g*255);
166                         tptr[2] = (int)(b*255);
167                 }
168                 
169                 p.dec_x(w);
170                 #else
171                 
172                 convert_color_format((unsigned char *)tptr,&p.get_value(),w,PF_RGB,gamma);
173                 
174                 #endif
175         }
176 }
177
178 //Audio Streamer (abstracts the open, write and close operations for audio streams)
179 #if 0
180 class AudioEncoder
181 {
182 public:
183
184         void *samples;
185
186         vector<unsigned char>audiobuffer;
187         
188         int audio_input_frame_size;
189         
190         bool open(AVFormatContext *formatc, AVStream *stream)
191         {
192                 AVCodecContext *context;
193                 AVCodec *codec;
194         
195                 context = &stream->codec;
196         
197                 //find audio encoder
198                 codec = avcodec_find_encoder(context->codec_id);
199                 if(!codec)
200                 {
201                         synfig::warning("audio-open: could not find codec");
202                         return 0;
203                 }
204         
205                 //open the codec
206                 if(avcodec_open(context, codec) < 0)
207                 {
208                         synfig::warning("audio-open: could not open codec");
209                         return 0;
210                 }
211         
212                 /* hardcoded example for generating samples array*/
213                 /*
214                 t = 0;
215                 tincr = 2 * M_PI * 110.0 / c->sample_rate;
216                 tincr2 = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate;*/
217         
218                 audiobuffer.resize(10000);
219         
220                 /* ugly hack for PCM codecs (will be removed ASAP with new PCM
221                    support to compute the input frame size in samples */
222                 if (context->frame_size <= 1) {
223                         audio_input_frame_size = audiobuffer.size() / context->channels;
224                         switch(stream->codec.codec_id) {
225                         case CODEC_ID_PCM_S16LE:
226                         case CODEC_ID_PCM_S16BE:
227                         case CODEC_ID_PCM_U16LE:
228                         case CODEC_ID_PCM_U16BE:
229                                 audio_input_frame_size >>= 1;
230                                 break;
231                         default:
232                                 break;
233                         }
234                 } else {
235                         audio_input_frame_size = context->frame_size;
236                 }
237                 
238                 //hardcoded array
239                 //samples = (int16_t *)malloc(audio_input_frame_size * 2 * c->channels);
240                 
241                 return true;
242         }
243         
244         bool write_frame(AVFormatContext *formatc, AVStream *stream, void *samples)
245         {
246                 int size;
247                 AVCodecContext *context;
248         
249                 context = &stream->codec;
250         
251                 //hardcoded in example
252                 //must read in from somewhere...
253                 //get_audio_frame(samples, audio_input_frame_size, c->channels);
254         
255                 //encode the audio
256                 const short int*samps=(const short int *)samples;       //assuming it's set from somewhere right now
257                 
258                 size = avcodec_encode_audio(context, &audiobuffer[0], audiobuffer.size(), samps);
259         
260                 //write the compressed audio to a file
261                 if(av_write_frame(formatc, stream->index, &audiobuffer[0], size) != 0)
262                 {
263                         synfig::warning("audio-write_frame: unable to write the entire audio frame");
264                         return 0;
265                 }
266                 
267                 return true;
268         }
269         
270         void close(AVFormatContext *formatc, AVStream *stream)
271         {
272                 //we may also want to catch delayed frames from here (don't for now)
273                 
274                 if(stream)
275                 {
276                         avcodec_close(&stream->codec);
277                 }
278                 
279                 //if(samples)av_free(samples);
280                 audiobuffer.resize(0);
281         }
282 };
283
284 #endif
285
286 class VideoEncoder
287 {
288 public:
289         AVFrame *encodable;     //for compressiong and output to a file (in compatible pixel format)
290         
291         vector<unsigned char>   videobuffer;
292         
293         bool    startedencoding;
294         
295         //int           stream_nb_frames;
296         
297         bool open(AVFormatContext *formatc, AVStream *stream)
298         {
299                 if(!formatc || !stream)
300                 {
301                         synfig::warning("Attempt to open a video codec with a bad format or stream");
302                         return false;
303                 }
304                 
305                 //codec and context
306                 AVCodec *codec;
307                 AVCodecContext *context;
308         
309                 //get from inside stream
310                 context = stream->codec;
311         
312                 //search for desired codec (contained in the stream)
313                 codec = avcodec_find_encoder(context->codec_id);
314                 if(!codec)
315                 {
316                         synfig::warning("Open_video: could not find desired codec");
317                         return 0;
318                 }
319         
320                 //try to open the codec
321                 if(avcodec_open(context, codec) < 0) 
322                 {
323                         synfig::warning("open_video: could not open desired codec");
324                         return 0;
325                 }
326         
327                 videobuffer.resize(0);          
328                 if(!(formatc->oformat->flags & AVFMT_RAWPICTURE))
329                 {
330                         //resize buffer to desired buffersize
331                         videobuffer.resize(200000); //TODO: need to figure out a good size
332                 }
333         
334                 //allocate the base picture which will be used to encode
335                 /*picture = alloc_picture(PIX_FMT_RGBA32, context->width, context->height);
336                 if(!picture)
337                 {
338                         synfig::warning("open_video: could not allocate the picture to be encoded");
339                         return 0;
340                 }*/
341         
342                 //if our output (rgb) needs to be translated to a different coordinate system, need a temporary picture in that color space
343                 
344                 /*      Should use defaults of RGB
345                         Possible formats:
346                                 PIX_FMT_RGB24
347                                 PIX_FMT_BGR24
348                                 PIX_FMT_RGBA32 //stored in cpu endianness (!!!!)
349                 
350                         (possibly translate directly to required coordinate systems later on... less error)
351                 */
352                 encodable = NULL;
353                 if(context->pix_fmt != PIX_FMT_RGB24)
354                 {
355                         encodable = alloc_picture(context->pix_fmt, context->width, context->height);
356                         if(!encodable) 
357                         {
358                                 synfig::warning("open_video: could not allocate encodable picture");
359                                 return 0;
360                         }
361                 }
362                 
363                 return true;
364         }
365         
366         //write a frame with the frame passed in
367         bool write_frame(AVFormatContext *formatc, AVStream *stream, AVFrame *pict)
368         {
369                 if(!formatc || !stream)
370                 {
371                         synfig::warning("Attempt to open a video codec with a bad format or stream");
372                         return false;
373                 }
374                 
375                 int                     size, 
376                                                 ret = 0;
377                 AVCodecContext  *context = stream->codec;
378                 
379                 /*
380                 If pict is invalid (NULL), then we are done compressing frames and we are trying to get
381                 the buffer cleared out (or if it's already in the right format) so no transofrm necessary 
382                 */
383                 if ( pict )
384                 {
385                         startedencoding = true;
386                 }
387                         
388                 
389                 if ( pict && context->pix_fmt != PIX_FMT_RGB24 )
390                 {
391                         //We're using RGBA at the moment, write custom conversion code later (get less accuracy errors)
392                         img_convert((AVPicture *)encodable, context->pix_fmt, 
393                                                 (AVPicture *)pict, PIX_FMT_RGB24,
394                                                 context->width, context->height);
395                         
396                         pict = encodable;
397                 }
398                 
399                 AVPacket pkt;
400                 av_init_packet(&pkt);
401                 pkt.stream_index = stream->index;
402                 pkt.data = (uint8_t *)pict;
403                 pkt.size = sizeof(AVPicture);
404                 if( context->coded_frame )
405                         pkt.pts = context->coded_frame->pts;
406                 if( context->coded_frame && context->coded_frame->key_frame)
407                         pkt.flags |= PKT_FLAG_KEY;
408                 
409                 //cludge for raw picture format (they said they'd fix)
410                 if (formatc->oformat->flags & AVFMT_RAWPICTURE)
411                 {
412                         ret = av_write_frame(formatc, &pkt);
413                 }
414                 else 
415                 {
416                         //encode our given image
417                         size = avcodec_encode_video(context, &videobuffer[0], videobuffer.size(), pict);
418                         
419                         //if greater than zero we've got stuff to write
420                         if (size > 0)
421                         {
422                                 av_init_packet(&pkt);
423                                 pkt.stream_index = stream->index;
424                                 pkt.data = &videobuffer[0];
425                                 pkt.size = size;
426                                 if( context->coded_frame )
427                                         pkt.pts = context->coded_frame->pts;
428                                 if( context->coded_frame && context->coded_frame->key_frame)
429                                         pkt.flags |= PKT_FLAG_KEY;
430
431                                 ret = av_write_frame(formatc, &pkt);
432                                 
433                                 //error detect - possibly throw later...
434                                 if(ret < 0)
435                                 {
436                                         synfig::warning("write_frame: error while writing video frame");
437                                         return false;                                   
438                                 }
439                         }
440                         //if 0, it was buffered (if invalid picture we don't have ANY data left)
441                         else
442                         {
443                                 //if we're clearing the buffers and there was no stuff to be written, we're done (like in codec example)
444                                 if(pict == NULL)
445                                 {
446                                         return false;
447                                         startedencoding = false;
448                                 }
449                                 
450                                 //buffered picture
451                         }
452                 }
453                 
454                 return true;
455         }
456         
457         void close(AVFormatContext *formatc, AVStream *stream)
458         {
459                 if(stream)
460                         avcodec_close(stream->codec);
461                 
462                 if (encodable) 
463                 {
464                         free_picture(encodable);
465                         encodable = 0;
466                 }
467                 
468                 videobuffer.resize(0);
469         }
470 };
471
472 class Target_LibAVCodec::LibAVEncoder
473 {
474 public:
475         
476         bool initialized;
477         
478         AVOutputFormat *format; //reference to global, do not delete
479
480     AVFormatContext *formatc;
481     
482         AVStream *video_st;
483         //AVStream *audio_st;
484     
485         double video_pts;
486         //double audio_pts;
487
488         VideoEncoder    vid;
489         VideoInfo               vInfo;
490         
491         /*AudioEncoder  aud;
492         AudioInfo               aInfo;*/
493
494         AVFrame                 *picture;       //for encoding to RGB24 (perhaps RGBA later)
495
496         int                             frame_count;
497         int                             num_frames;
498
499         LibAVEncoder()
500         {
501                 format = 0;
502                 formatc = 0;
503                 
504                 //video settings
505                 video_st = 0;
506                 video_pts = 0;
507                         
508                 vid.encodable = 0;
509                 //vid.stream_nb_frames = 2;     //reasonable default
510                 
511                 initialized = false;
512                 picture = 0;
513
514                 frame_count = 0;
515                 num_frames = 0;         
516                 
517                 //aud.samples = 0;              
518                 //audio_st = 0;
519                 //audio_pts = 0;
520         }
521
522         ~LibAVEncoder()
523         {
524                 CleanUp();
525         }
526         
527         bool Initialize(const char *filename, const char *typestring)
528         {
529                 //guess if we have a type string, otherwise use filename
530                 if (typestring)
531                 {
532                         //formatptr guess_format(type, filename, MIME type)
533                         format = guess_format(typestring,NULL,NULL);
534                 }
535                 else
536                 {
537                         format = guess_format(NULL, filename, NULL);
538                 }
539                 
540                 if(!format)
541                 {
542                         synfig::warning("Unable to Guess the output, defaulting to mpeg");
543                         format = guess_format("mpeg", NULL, NULL);
544                 }
545                 
546                 if(!format) 
547                 {
548                         synfig::warning("Unable to find output format");
549                         return 0;
550                 }
551                 
552                 //allocate the output context
553                 formatc = (AVFormatContext *)av_mallocz(sizeof(AVFormatContext));
554                 if(!formatc)
555                 {
556                         synfig::warning("Memory error\n");
557                         return 0;
558                 }
559                 //set the output format to the one we found
560                 formatc->oformat = format;
561                 
562                 //print the output filename
563                 snprintf(formatc->filename, sizeof(formatc->filename), "%s", filename);
564         
565                 //initial
566                 video_st = NULL;
567                 //audio_st = NULL;
568                 
569                 //video stream
570                 if(format->video_codec != CODEC_ID_NONE) 
571                 {
572                         video_st = add_video_stream(format->video_codec,vInfo);
573                         if(!video_st)
574                         {
575                                 av_free(formatc);
576                         }
577                 }
578                 
579                 //audio stream
580                 /*if(format->audio_codec != CODEC_ID_NONE)
581                 {
582                         audio_st = add_audio_stream(format->audio_codec,aInfo);
583                 }*/
584         
585                 //set output parameters: required in ALL cases
586                 
587                 AVFormatParameters      fmtparam,*ap = &fmtparam;
588                 memset(ap, 0, sizeof(*ap));
589                 // FIXME: Port next two lines to recent libavcodec versions
590                 //ap->frame_rate = vInfo.fps;
591                 //ap->frame_rate_base = 1;
592                 ap->width = vInfo.w;
593                 ap->height = vInfo.h;
594                 //ap->pix_fmt = frame_pix_fmt;
595                 
596                 if(av_set_parameters(formatc, ap) < 0)
597                 {
598                         synfig::warning("Invalid output formatting parameters");
599                         return 0;
600                 }
601         
602                 //dump the formatting information as the file header
603                 dump_format(formatc, 0, filename, 1);
604                 
605                 //open codecs and allocate buffers
606                 if(video_st)
607                 {
608                         if(!vid.open(formatc, video_st))
609                         {
610                                 synfig::warning("Could not open video encoder");
611                                 return 0;
612                         }
613                 }
614                 /*if(audio_st)
615                 {
616                         if(!aud.open(formatc, audio_st))
617                         {
618                                 synfig::warning("Could not open audio encoder");
619                                 return 0;
620                         }                       
621                 }*/
622         
623                 //open output file
624                 if(!(format->flags & AVFMT_NOFILE))
625                 {
626                         //use libav's file open function (what does it do differently????)
627                         if(url_fopen(&formatc->pb, filename, URL_WRONLY) < 0)
628                         {
629                                 synfig::warning("Unable to open file: %s", filename);
630                                 return 0;
631                         }
632                 }
633                 
634                 //allocate the picture to render to
635                 //may have to retrieve the width, height from the codec... for resizing...
636                 picture = alloc_picture(PIX_FMT_RGB24,vInfo.w,vInfo.h);//video_st->codec.width, video_st->codec.height);
637                 if(!picture)
638                 {
639                         synfig::warning("Unable to allocate the temporary AVFrame surface");
640                         return 0;
641                 }
642                 
643                 initialized = true;
644                 //vInfo.w = video_st->codec.width;
645                 //vInfo.h = video_st->codec.height;
646                 
647                 //write the stream header
648                 av_write_header(formatc);
649                 
650                 return true;
651         }
652         
653         void CleanUp()
654         {
655                 int i;
656                 
657                 if(picture) free_picture(picture);
658                 
659                 //do all the clean up file rendering
660                 if(formatc && video_st)
661                 {
662                         //want to scan in delayed frames until no longer needed (TODO)          
663                         if(vid.startedencoding) while( vid.write_frame(formatc, video_st, 0) );
664                         
665                         //may want to move this... probably to the end of the last frame...
666                         av_write_trailer(formatc);
667                 }
668                 
669                 //close codecs
670                 if (video_st)
671                         vid.close(formatc,video_st);
672                 /*if (audio_st)
673                         aud.close(formatc,audio_st);*/
674         
675                 /* write the trailer, if any */
676                 if(formatc)
677                 {
678                         /* free the streams */
679                         for(i = 0; i < formatc->nb_streams; i++)
680                         {
681                                 av_freep(&formatc->streams[i]);
682                         }
683         
684                         if(!(format->flags & AVFMT_NOFILE))
685                         {
686                                 /* close the output file */
687                                 url_fclose(&formatc->pb);
688                         }
689         
690                         /* free the stream */
691                         av_free(formatc);
692                 }
693                 
694                 initialized = false;
695                 
696                 format = 0;
697                 formatc = 0;
698                 
699                 //video settings
700                 video_st = 0;
701                 video_pts = 0;
702                         
703                 vid.encodable = 0;
704                 //vid.stream_nb_frames = 2;     //reasonable default
705                 
706                 initialized = false;
707                 picture = 0;            
708         }
709
710         //create a video output stream
711         AVStream *add_video_stream(int codec_id, const VideoInfo &info)
712         {
713                 AVCodecContext *context;
714                 AVStream *st;
715         
716                 st = av_new_stream(formatc, 0);
717                 if(!st)
718                 {
719                         synfig::warning("video-add_stream: Unable to allocate stream");
720                         return 0;
721                 }
722                 
723                 context = st->codec;
724                 context->codec_id = (CodecID)codec_id;
725                 context->codec_type = CODEC_TYPE_VIDEO;
726         
727                 //PARAMETERS MUST BE PASSED IN SOMEHOW (ANOTHER FUNCTION PARAMETER???)
728                 
729                 /* resolution must be a multiple of two */
730                 context->width = info.w;
731                 context->height = info.h;
732                 
733                 //have another way to input these
734                 context->bit_rate = info.bitrate; //TODO: Make dependant on the quality
735                 
736                 /* frames per second */
737                 // FIXME: Port next two lines to recent libavcodec versions
738                 //context->frame_rate = info.fps;
739                 //context->frame_rate_base = 1;
740                 
741                 /* "High Quality" */
742                 context->mb_decision=FF_MB_DECISION_BITS;
743                 
744                 context->gop_size = info.fps/4; /* emit one intra frame every twelve frames at most */
745                 
746                 //HACK: MPEG requires b frames be set... any better way to do this?
747                 if (context->codec_id == CODEC_ID_MPEG1VIDEO ||
748                         context->codec_id == CODEC_ID_MPEG2VIDEO)
749                 {
750                         /* just for testing, we also add B frames */
751                         context->max_b_frames = 2;
752                 }
753                 
754                 return st;
755         }
756         
757         // add an audio output stream
758         AVStream *add_audio_stream(int codec_id,const AudioInfo &aInfo)
759         {
760                 AVCodecContext *context;
761                 AVStream *stream;
762         
763                 stream = av_new_stream(formatc, 1);
764                 if(!stream)
765                 {
766                         synfig::warning("could not alloc stream");
767                         return 0;
768                 }
769         
770                 context = stream->codec;
771                 context->codec_id = (CodecID)codec_id;  
772                 context->codec_type = CODEC_TYPE_AUDIO;
773         
774                 /* put sample parameters */
775                 context->bit_rate = 64000;
776                 context->sample_rate = 44100;
777                 context->channels = 2;
778                 
779                 return stream;
780         }
781 };
782
783 /* === M E T H O D S ======================================================= */
784
785 Target_LibAVCodec::Target_LibAVCodec(const char *Filename):
786         filename(Filename)
787 {
788         if(!registered)
789         {
790                 registered = true;
791                 av_register_all();
792         }
793         set_remove_alpha();
794         
795         data = new LibAVEncoder;
796 }
797
798 Target_LibAVCodec::~Target_LibAVCodec()
799 {
800         data->CleanUp();
801 }
802
803 bool
804 Target_LibAVCodec::set_rend_desc(RendDesc *given_desc)
805 {
806         // This is where you can determine how you want stuff
807         // to be rendered! given_desc is the suggestion, and
808         // you need to modify it to suit the needs of the codec.
809         // ie: Making the pixel dimensions divisible by 8, etc...
810         
811         desc=*given_desc;
812         
813         //resize surface (round even)
814         int w = desc.get_w();
815         int h = desc.get_h();
816         Point tl = desc.get_tl();
817         Point br = desc.get_br();
818         Real pw = desc.get_pw();
819         Real ph = desc.get_ph();
820         
821         //resize to the size it should be...
822         //desc.set_subwindow(-offx/2,-offy/2, desc.get_w() - offx?(offx + 8):0, desc.get_h() - offy?(offy + 8):0);
823
824         //if resolution is broken, change the size... or something      
825         //budge to nearest pixel values
826         if(w&1)
827         {
828                 w += 1;
829                 tl[0] -= pw/2;
830                 br[0] += pw/2;          
831         }
832         
833         if(h&1)
834         {
835                 h += 1;
836                 tl[1] -= ph/2;
837                 br[1] += ph/2;
838         }
839         
840         desc.set_w(w);
841         desc.set_h(h);
842         desc.set_tl(tl);
843         desc.set_br(br);
844         
845         data->vInfo.w = w;
846         data->vInfo.h = h;
847         
848         //may want to round frame rate
849         data->vInfo.fps = (int)floor(desc.get_frame_rate()+0.5);
850 #define MEGABYTES_PER_HOUR(x)           (((x)*1024/3600*1024*8)/*/640*w/480*h*/)
851         data->vInfo.bitrate = MEGABYTES_PER_HOUR(400);
852         //data->vInfo.bitrate = 800000; //make customizable somehow
853         
854         desc.set_frame_rate(data->vInfo.fps);
855         
856         data->frame_count = desc.get_frame_start();
857         data->num_frames = desc.get_frame_end()+1; //number of frames should be 1 greater than the last one
858                 
859         surface.set_wh(data->vInfo.w,data->vInfo.h);
860         
861         return true;
862 }
863
864 void
865 Target_LibAVCodec::end_frame()
866 {
867         //AVStream *audio_st = data->audio_st;
868         AVStream *video_st = data->video_st;
869         
870         AVFormatContext *formatc = data->formatc;
871         
872         //double &audio_pts = data->audio_pts;
873         //double &video_pts = data->video_pts;
874         
875         //ignore audio for now  
876         /*if (audio_st)
877                 audio_pts = (double)audio_st->pts.val * formatc->pts_num / formatc->pts_den;
878         else
879                 audio_pts = 0.0;
880         
881         if (video_st)
882                 video_pts = (double)video_st->pts.val * formatc->pts_num / formatc->pts_den;
883         else
884                 video_pts = 0.0;*/
885
886         //hardcoded crappiness
887         /*if ((!audio_st || audio_pts >= STREAM_DURATION) && 
888                 (!video_st || video_pts >= STREAM_DURATION))
889                 break;*/
890         
891         if(data->frame_count >= data->num_frames) return;
892                 
893         //copy the current surface to the buffer
894         if(data->picture)convert_surface_frame(data->picture,surface,gamma());
895         
896         //encode the frame and write it to the file
897         if(!data->vid.write_frame(formatc,video_st,data->picture))
898         {
899                 synfig::warning("Unable to write a frame");
900         }
901         
902         data->frame_count++;
903
904         if(data->frame_count >= data->num_frames)
905         {
906                 data->CleanUp();
907         }
908         
909         /* write interleaved audio and video frames */
910         /*if (!video_st || (video_st && audio_st && audio_pts < video_pts)) {
911                 data->aud.write_frame(formatc,audio_st);
912         } else {
913                 data->vid.write_frame(formatc,video_st);
914     }*/
915 }
916
917 bool
918 Target_LibAVCodec::start_frame(synfig::ProgressCallback *callback)
919 {       
920         //prepare all the color buffer stuff, etc.
921         
922         return true;
923 }
924
925 Color *
926 Target_LibAVCodec::start_scanline(int scanline)
927 {
928         return surface[scanline];
929         
930         return 0;       // This should kill the render process
931 }
932
933 bool
934 Target_LibAVCodec::end_scanline()
935 {
936         //don't need to do anything until the whole frame is done
937         return true;
938 }
939
940 bool Target_LibAVCodec::init()
941 {
942         //hardcode test for mpeg
943         if(!data->Initialize(filename.c_str(),NULL))
944         {
945                 synfig::warning("Unable to Initialize the audio video encoders");
946                 return 0;
947         }
948         
949         return true;
950 }