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