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