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