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