Fix bugs in previous commit that caused FTBFS in synfig and ETL FTBFS with older...
[synfig.git] / synfig-core / tags / synfig_0_61_03 / synfig-core / 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 "libavformat/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                 //cludge for raw picture format (they said they'd fix)
400                 if (formatc->oformat->flags & AVFMT_RAWPICTURE)
401                 {
402                         ret = av_write_frame(formatc, stream->index, (uint8_t *)pict, sizeof(AVPicture));
403                 }
404                 else 
405                 {
406                         //encode our given image
407                         size = avcodec_encode_video(context, &videobuffer[0], videobuffer.size(), pict);
408                         
409                         //if not zero we've got stuff to write
410                         if (size != 0)
411                         {
412                                 ret = av_write_frame(formatc, stream->index, &videobuffer[0], size);
413                                 
414                                 //error detect - possibly throw later...
415                                 if(ret != 0)
416                                 {
417                                         synfig::warning("write_frame: error while writing video frame");
418                                         return false;                                   
419                                 }
420                         }
421                         //if 0, it was buffered (if invalid picture we don't have ANY data left)
422                         else
423                         {
424                                 //if we're clearing the buffers and there was no stuff to be written, we're done (like in codec example)
425                                 if(pict == NULL)
426                                 {
427                                         return false;
428                                         startedencoding = false;
429                                 }
430                                 
431                                 //buffered picture
432                         }
433                 }
434                 
435                 return true;
436         }
437         
438         void close(AVFormatContext *formatc, AVStream *stream)
439         {
440                 if(stream)
441                         avcodec_close(&stream->codec);
442                 
443                 if (encodable) 
444                 {
445                         free_picture(encodable);
446                         encodable = 0;
447                 }
448                 
449                 videobuffer.resize(0);
450         }
451 };
452
453 class Target_LibAVCodec::LibAVEncoder
454 {
455 public:
456         
457         bool initialized;
458         
459         AVOutputFormat *format; //reference to global, do not delete
460
461     AVFormatContext *formatc;
462     
463         AVStream *video_st;
464         //AVStream *audio_st;
465     
466         double video_pts;
467         //double audio_pts;
468
469         VideoEncoder    vid;
470         VideoInfo               vInfo;
471         
472         /*AudioEncoder  aud;
473         AudioInfo               aInfo;*/
474
475         AVFrame                 *picture;       //for encoding to RGB24 (perhaps RGBA later)
476
477         int                             frame_count;
478         int                             num_frames;
479
480         LibAVEncoder()
481         {
482                 format = 0;
483                 formatc = 0;
484                 
485                 //video settings
486                 video_st = 0;
487                 video_pts = 0;
488                         
489                 vid.encodable = 0;
490                 //vid.stream_nb_frames = 2;     //reasonable default
491                 
492                 initialized = false;
493                 picture = 0;
494
495                 frame_count = 0;
496                 num_frames = 0;         
497                 
498                 //aud.samples = 0;              
499                 //audio_st = 0;
500                 //audio_pts = 0;
501         }
502
503         ~LibAVEncoder()
504         {
505                 CleanUp();
506         }
507         
508         bool Initialize(const char *filename, const char *typestring)
509         {
510                 //guess if we have a type string, otherwise use filename
511                 if (typestring)
512                 {
513                         //formatptr guess_format(type, filename, MIME type)
514                         format = guess_format(typestring,NULL,NULL);
515                 }
516                 else
517                 {
518                         format = guess_format(NULL, filename, NULL);
519                 }
520                 
521                 if(!format)
522                 {
523                         synfig::warning("Unable to Guess the output, defaulting to mpeg");
524                         format = guess_format("mpeg", NULL, NULL);
525                 }
526                 
527                 if(!format) 
528                 {
529                         synfig::warning("Unable to find output format");
530                         return 0;
531                 }
532                 
533                 //allocate the output context
534                 formatc = (AVFormatContext *)av_mallocz(sizeof(AVFormatContext));
535                 if(!formatc)
536                 {
537                         synfig::warning("Memory error\n");
538                         return 0;
539                 }
540                 //set the output format to the one we found
541                 formatc->oformat = format;
542                 
543                 //print the output filename
544                 snprintf(formatc->filename, sizeof(formatc->filename), "%s", filename);
545         
546                 //initial
547                 video_st = NULL;
548                 //audio_st = NULL;
549                 
550                 //video stream
551                 if(format->video_codec != CODEC_ID_NONE) 
552                 {
553                         video_st = add_video_stream(format->video_codec,vInfo);
554                         if(!video_st)
555                         {
556                                 av_free(formatc);
557                         }
558                 }
559                 
560                 //audio stream
561                 /*if(format->audio_codec != CODEC_ID_NONE)
562                 {
563                         audio_st = add_audio_stream(format->audio_codec,aInfo);
564                 }*/
565         
566                 //set output parameters: required in ALL cases
567                 
568                 AVFormatParameters      fmtparam,*ap = &fmtparam;
569                 memset(ap, 0, sizeof(*ap));
570                 ap->frame_rate = vInfo.fps;
571                 ap->frame_rate_base = 1;
572                 ap->width = vInfo.w;
573                 ap->height = vInfo.h;
574                 //ap->pix_fmt = frame_pix_fmt;
575                 
576                 if(av_set_parameters(formatc, ap) < 0)
577                 {
578                         synfig::warning("Invalid output formatting parameters");
579                         return 0;
580                 }
581         
582                 //dump the formatting information as the file header
583                 dump_format(formatc, 0, filename, 1);
584                 
585                 //open codecs and allocate buffers
586                 if(video_st)
587                 {
588                         if(!vid.open(formatc, video_st))
589                         {
590                                 synfig::warning("Could not open video encoder");
591                                 return 0;
592                         }
593                 }
594                 /*if(audio_st)
595                 {
596                         if(!aud.open(formatc, audio_st))
597                         {
598                                 synfig::warning("Could not open audio encoder");
599                                 return 0;
600                         }                       
601                 }*/
602         
603                 //open output file
604                 if(!(format->flags & AVFMT_NOFILE))
605                 {
606                         //use libav's file open function (what does it do differently????)
607                         if(url_fopen(&formatc->pb, filename, URL_WRONLY) < 0)
608                         {
609                                 synfig::warning("Unable to open file: %s", filename);
610                                 return 0;
611                         }
612                 }
613                 
614                 //allocate the picture to render to
615                 //may have to retrieve the width, height from the codec... for resizing...
616                 picture = alloc_picture(PIX_FMT_RGB24,vInfo.w,vInfo.h);//video_st->codec.width, video_st->codec.height);
617                 if(!picture)
618                 {
619                         synfig::warning("Unable to allocate the temporary AVFrame surface");
620                         return 0;
621                 }
622                 
623                 initialized = true;
624                 //vInfo.w = video_st->codec.width;
625                 //vInfo.h = video_st->codec.height;
626                 
627                 //write the stream header
628                 av_write_header(formatc);
629                 
630                 return true;
631         }
632         
633         void CleanUp()
634         {
635                 int i;
636                 
637                 if(picture) free_picture(picture);
638                 
639                 //do all the clean up file rendering
640                 if(formatc && video_st)
641                 {
642                         //want to scan in delayed frames until no longer needed (TODO)          
643                         if(vid.startedencoding) while( vid.write_frame(formatc, video_st, 0) );
644                         
645                         //may want to move this... probably to the end of the last frame...
646                         av_write_trailer(formatc);
647                 }
648                 
649                 //close codecs
650                 if (video_st)
651                         vid.close(formatc,video_st);
652                 /*if (audio_st)
653                         aud.close(formatc,audio_st);*/
654         
655                 /* write the trailer, if any */
656                 if(formatc)
657                 {
658                         /* free the streams */
659                         for(i = 0; i < formatc->nb_streams; i++)
660                         {
661                                 av_freep(&formatc->streams[i]);
662                         }
663         
664                         if(!(format->flags & AVFMT_NOFILE))
665                         {
666                                 /* close the output file */
667                                 url_fclose(&formatc->pb);
668                         }
669         
670                         /* free the stream */
671                         av_free(formatc);
672                 }
673                 
674                 initialized = false;
675                 
676                 format = 0;
677                 formatc = 0;
678                 
679                 //video settings
680                 video_st = 0;
681                 video_pts = 0;
682                         
683                 vid.encodable = 0;
684                 //vid.stream_nb_frames = 2;     //reasonable default
685                 
686                 initialized = false;
687                 picture = 0;            
688         }
689
690         //create a video output stream
691         AVStream *add_video_stream(int codec_id, const VideoInfo &info)
692         {
693                 AVCodecContext *context;
694                 AVStream *st;
695         
696                 st = av_new_stream(formatc, 0);
697                 if(!st)
698                 {
699                         synfig::warning("video-add_stream: Unable to allocate stream");
700                         return 0;
701                 }
702                 
703                 context = &st->codec;
704                 context->codec_id = (CodecID)codec_id;
705                 context->codec_type = CODEC_TYPE_VIDEO;
706         
707                 //PARAMETERS MUST BE PASSED IN SOMEHOW (ANOTHER FUNCTION PARAMETER???)
708                 
709                 /* resolution must be a multiple of two */
710                 context->width = info.w;
711                 context->height = info.h;
712                 
713                 //have another way to input these
714                 context->bit_rate = info.bitrate; //TODO: Make dependant on the quality
715                 
716                 /* frames per second */
717                 context->frame_rate = info.fps;
718                 context->frame_rate_base = 1;
719                 
720                 /* "High Quality" */
721                 context->mb_decision=FF_MB_DECISION_BITS;
722                 
723                 context->gop_size = info.fps/4; /* emit one intra frame every twelve frames at most */
724                 
725                 //HACK: MPEG requires b frames be set... any better way to do this?
726                 if (context->codec_id == CODEC_ID_MPEG1VIDEO ||
727                         context->codec_id == CODEC_ID_MPEG2VIDEO)
728                 {
729                         /* just for testing, we also add B frames */
730                         context->max_b_frames = 2;
731                 }
732                 
733                 return st;
734         }
735         
736         // add an audio output stream
737         AVStream *add_audio_stream(int codec_id,const AudioInfo &aInfo)
738         {
739                 AVCodecContext *context;
740                 AVStream *stream;
741         
742                 stream = av_new_stream(formatc, 1);
743                 if(!stream)
744                 {
745                         synfig::warning("could not alloc stream");
746                         return 0;
747                 }
748         
749                 context = &stream->codec;
750                 context->codec_id = (CodecID)codec_id;  
751                 context->codec_type = CODEC_TYPE_AUDIO;
752         
753                 /* put sample parameters */
754                 context->bit_rate = 64000;
755                 context->sample_rate = 44100;
756                 context->channels = 2;
757                 
758                 return stream;
759         }
760 };
761
762 /* === M E T H O D S ======================================================= */
763
764 Target_LibAVCodec::Target_LibAVCodec(const char *Filename):
765         filename(Filename)
766 {
767         if(!registered)
768         {
769                 registered = true;
770                 av_register_all();
771         }
772         set_remove_alpha();
773         
774         data = new LibAVEncoder;
775 }
776
777 Target_LibAVCodec::~Target_LibAVCodec()
778 {
779         data->CleanUp();
780 }
781
782 bool
783 Target_LibAVCodec::set_rend_desc(RendDesc *given_desc)
784 {
785         // This is where you can determine how you want stuff
786         // to be rendered! given_desc is the suggestion, and
787         // you need to modify it to suit the needs of the codec.
788         // ie: Making the pixel dimensions divisible by 8, etc...
789         
790         desc=*given_desc;
791         
792         //resize surface (round even)
793         int w = desc.get_w();
794         int h = desc.get_h();
795         Point tl = desc.get_tl();
796         Point br = desc.get_br();
797         Real pw = desc.get_pw();
798         Real ph = desc.get_ph();
799         
800         //resize to the size it should be...
801         //desc.set_subwindow(-offx/2,-offy/2, desc.get_w() - offx?(offx + 8):0, desc.get_h() - offy?(offy + 8):0);
802
803         //if resolution is broken, change the size... or something      
804         //budge to nearest pixel values
805         if(w&1)
806         {
807                 w += 1;
808                 tl[0] -= pw/2;
809                 br[0] += pw/2;          
810         }
811         
812         if(h&1)
813         {
814                 h += 1;
815                 tl[1] -= ph/2;
816                 br[1] += ph/2;
817         }
818         
819         desc.set_w(w);
820         desc.set_h(h);
821         desc.set_tl(tl);
822         desc.set_br(br);
823         
824         data->vInfo.w = w;
825         data->vInfo.h = h;
826         
827         //may want to round frame rate
828         data->vInfo.fps = (int)floor(desc.get_frame_rate()+0.5);
829 #define MEGABYTES_PER_HOUR(x)           (((x)*1024/3600*1024*8)/*/640*w/480*h*/)
830         data->vInfo.bitrate = MEGABYTES_PER_HOUR(400);
831         //data->vInfo.bitrate = 800000; //make customizable somehow
832         
833         desc.set_frame_rate(data->vInfo.fps);
834         
835         data->frame_count = desc.get_frame_start();
836         data->num_frames = desc.get_frame_end()+1; //number of frames should be 1 greater than the last one
837                 
838         surface.set_wh(data->vInfo.w,data->vInfo.h);
839         
840         return true;
841 }
842
843 void
844 Target_LibAVCodec::end_frame()
845 {
846         //AVStream *audio_st = data->audio_st;
847         AVStream *video_st = data->video_st;
848         
849         AVFormatContext *formatc = data->formatc;
850         
851         //double &audio_pts = data->audio_pts;
852         //double &video_pts = data->video_pts;
853         
854         //ignore audio for now  
855         /*if (audio_st)
856                 audio_pts = (double)audio_st->pts.val * formatc->pts_num / formatc->pts_den;
857         else
858                 audio_pts = 0.0;
859         
860         if (video_st)
861                 video_pts = (double)video_st->pts.val * formatc->pts_num / formatc->pts_den;
862         else
863                 video_pts = 0.0;*/
864
865         //hardcoded crappiness
866         /*if ((!audio_st || audio_pts >= STREAM_DURATION) && 
867                 (!video_st || video_pts >= STREAM_DURATION))
868                 break;*/
869         
870         if(data->frame_count >= data->num_frames) return;
871                 
872         //copy the current surface to the buffer
873         if(data->picture)convert_surface_frame(data->picture,surface,gamma());
874         
875         //encode the frame and write it to the file
876         if(!data->vid.write_frame(formatc,video_st,data->picture))
877         {
878                 synfig::warning("Unable to write a frame");
879         }
880         
881         data->frame_count++;
882
883         if(data->frame_count >= data->num_frames)
884         {
885                 data->CleanUp();
886         }
887         
888         /* write interleaved audio and video frames */
889         /*if (!video_st || (video_st && audio_st && audio_pts < video_pts)) {
890                 data->aud.write_frame(formatc,audio_st);
891         } else {
892                 data->vid.write_frame(formatc,video_st);
893     }*/
894 }
895
896 bool
897 Target_LibAVCodec::start_frame(synfig::ProgressCallback *callback)
898 {       
899         //prepare all the color buffer stuff, etc.
900         
901         return true;
902 }
903
904 Color *
905 Target_LibAVCodec::start_scanline(int scanline)
906 {
907         return surface[scanline];
908         
909         return 0;       // This should kill the render process
910 }
911
912 bool
913 Target_LibAVCodec::end_scanline()
914 {
915         //don't need to do anything until the whole frame is done
916         return true;
917 }
918
919 bool Target_LibAVCodec::init()
920 {
921         //hardcode test for mpeg
922         if(!data->Initialize(filename.c_str(),NULL))
923         {
924                 synfig::warning("Unable to Initialize the audio video encoders");
925                 return 0;
926         }
927         
928         return true;
929 }