Fix 1877061: fix build problem with newer versions of libavformat due to the pb membe...
[synfig.git] / synfig-core / trunk / src / modules / mod_libavcodec / trgt_av.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file trgt_av.cpp
3 **      \brief \writeme
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **
10 **      This package is free software; you can redistribute it and/or
11 **      modify it under the terms of the GNU General Public License as
12 **      published by the Free Software Foundation; either version 2 of
13 **      the License, or (at your option) any later version.
14 **
15 **      This package is distributed in the hope that it will be useful,
16 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 **      General Public License for more details.
19 **      \endlegal
20 */
21 /* ========================================================================= */
22
23 /* === H E A D E R S ======================================================= */
24
25 #define SYNFIG_NO_ANGLE
26
27 #ifdef USING_PCH
28 #       include "pch.h"
29 #else
30 #ifdef HAVE_CONFIG_H
31 #       include <config.h>
32 #endif
33
34 #include "trgt_av.h"
35
36 extern "C"
37 {
38 #include <avformat.h>
39 }
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 compression 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                 //kluge 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                 unsigned 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 #if LIBAVFORMAT_VERSION_INT >= (52<<16)
678                                 url_fclose(formatc->pb);
679 #else
680                                 url_fclose(&formatc->pb);
681 #endif
682                         }
683
684                         /* free the stream */
685                         av_free(formatc);
686                 }
687
688                 initialized = false;
689
690                 format = 0;
691                 formatc = 0;
692
693                 //video settings
694                 video_st = 0;
695                 video_pts = 0;
696
697                 vid.encodable = 0;
698                 //vid.stream_nb_frames = 2;     //reasonable default
699
700                 initialized = false;
701                 picture = 0;
702         }
703
704         //create a video output stream
705         AVStream *add_video_stream(int codec_id, const VideoInfo &info)
706         {
707                 AVCodecContext *context;
708                 AVStream *st;
709
710                 st = av_new_stream(formatc, 0);
711                 if(!st)
712                 {
713                         synfig::warning("video-add_stream: Unable to allocate stream");
714                         return 0;
715                 }
716
717                 context = st->codec;
718                 context->codec_id = (CodecID)codec_id;
719                 context->codec_type = CODEC_TYPE_VIDEO;
720
721                 //PARAMETERS MUST BE PASSED IN SOMEHOW (ANOTHER FUNCTION PARAMETER???)
722
723                 /* resolution must be a multiple of two */
724                 context->width = info.w;
725                 context->height = info.h;
726
727                 //have another way to input these
728                 context->bit_rate = info.bitrate; //TODO: Make dependant on the quality
729
730                 /* frames per second */
731                 // FIXME: Port next two lines to recent libavcodec versions
732                 //context->frame_rate = info.fps;
733                 //context->frame_rate_base = 1;
734
735                 /* "High Quality" */
736                 context->mb_decision=FF_MB_DECISION_BITS;
737
738                 context->gop_size = info.fps/4; /* emit one intra frame every twelve frames at most */
739
740                 //HACK: MPEG requires b frames be set... any better way to do this?
741                 if (context->codec_id == CODEC_ID_MPEG1VIDEO ||
742                         context->codec_id == CODEC_ID_MPEG2VIDEO)
743                 {
744                         /* just for testing, we also add B frames */
745                         context->max_b_frames = 2;
746                 }
747
748                 return st;
749         }
750
751         // add an audio output stream
752         AVStream *add_audio_stream(int codec_id,const AudioInfo &/*aInfo*/)
753         {
754                 AVCodecContext *context;
755                 AVStream *stream;
756
757                 stream = av_new_stream(formatc, 1);
758                 if(!stream)
759                 {
760                         synfig::warning("could not alloc stream");
761                         return 0;
762                 }
763
764                 context = stream->codec;
765                 context->codec_id = (CodecID)codec_id;
766                 context->codec_type = CODEC_TYPE_AUDIO;
767
768                 /* put sample parameters */
769                 context->bit_rate = 64000;
770                 context->sample_rate = 44100;
771                 context->channels = 2;
772
773                 return stream;
774         }
775 };
776
777 /* === M E T H O D S ======================================================= */
778
779 Target_LibAVCodec::Target_LibAVCodec(const char *Filename):
780         filename(Filename)
781 {
782         if(!registered)
783         {
784                 registered = true;
785                 av_register_all();
786         }
787         set_remove_alpha();
788
789         data = new LibAVEncoder;
790 }
791
792 Target_LibAVCodec::~Target_LibAVCodec()
793 {
794         data->CleanUp();
795 }
796
797 bool
798 Target_LibAVCodec::set_rend_desc(RendDesc *given_desc)
799 {
800         // This is where you can determine how you want stuff
801         // to be rendered! given_desc is the suggestion, and
802         // you need to modify it to suit the needs of the codec.
803         // ie: Making the pixel dimensions divisible by 8, etc...
804
805         desc=*given_desc;
806
807         //resize surface (round even)
808         int w = desc.get_w();
809         int h = desc.get_h();
810         Point tl = desc.get_tl();
811         Point br = desc.get_br();
812         Real pw = desc.get_pw();
813         Real ph = desc.get_ph();
814
815         //resize to the size it should be...
816         //desc.set_subwindow(-offx/2,-offy/2, desc.get_w() - offx?(offx + 8):0, desc.get_h() - offy?(offy + 8):0);
817
818         //if resolution is broken, change the size... or something
819         //budge to nearest pixel values
820         if(w&1)
821         {
822                 w += 1;
823                 tl[0] -= pw/2;
824                 br[0] += pw/2;
825         }
826
827         if(h&1)
828         {
829                 h += 1;
830                 tl[1] -= ph/2;
831                 br[1] += ph/2;
832         }
833
834         desc.set_w(w);
835         desc.set_h(h);
836         desc.set_tl(tl);
837         desc.set_br(br);
838
839         data->vInfo.w = w;
840         data->vInfo.h = h;
841
842         //may want to round frame rate
843         data->vInfo.fps = (int)floor(desc.get_frame_rate()+0.5);
844 #define MEGABYTES_PER_HOUR(x)           (((x)*1024/3600*1024*8)/*/640*w/480*h*/)
845         data->vInfo.bitrate = MEGABYTES_PER_HOUR(400);
846         //data->vInfo.bitrate = 800000; //make customizable somehow
847
848         desc.set_frame_rate(data->vInfo.fps);
849
850         data->frame_count = desc.get_frame_start();
851         data->num_frames = desc.get_frame_end()+1; //number of frames should be 1 greater than the last one
852
853         surface.set_wh(data->vInfo.w,data->vInfo.h);
854
855         return true;
856 }
857
858 void
859 Target_LibAVCodec::end_frame()
860 {
861         //AVStream *audio_st = data->audio_st;
862         AVStream *video_st = data->video_st;
863
864         AVFormatContext *formatc = data->formatc;
865
866         //double &audio_pts = data->audio_pts;
867         //double &video_pts = data->video_pts;
868
869         //ignore audio for now
870         /*if (audio_st)
871                 audio_pts = (double)audio_st->pts.val * formatc->pts_num / formatc->pts_den;
872         else
873                 audio_pts = 0.0;
874
875         if (video_st)
876                 video_pts = (double)video_st->pts.val * formatc->pts_num / formatc->pts_den;
877         else
878                 video_pts = 0.0;*/
879
880         //hardcoded crappiness
881         /*if ((!audio_st || audio_pts >= STREAM_DURATION) &&
882                 (!video_st || video_pts >= STREAM_DURATION))
883                 break;*/
884
885         if(data->frame_count >= data->num_frames) return;
886
887         //copy the current surface to the buffer
888         if(data->picture)convert_surface_frame(data->picture,surface,gamma());
889
890         //encode the frame and write it to the file
891         if(!data->vid.write_frame(formatc,video_st,data->picture))
892         {
893                 synfig::warning("Unable to write a frame");
894         }
895
896         data->frame_count++;
897
898         if(data->frame_count >= data->num_frames)
899         {
900                 data->CleanUp();
901         }
902
903         /* write interleaved audio and video frames */
904         /*if (!video_st || (video_st && audio_st && audio_pts < video_pts)) {
905                 data->aud.write_frame(formatc,audio_st);
906         } else {
907                 data->vid.write_frame(formatc,video_st);
908     }*/
909 }
910
911 bool
912 Target_LibAVCodec::start_frame(synfig::ProgressCallback */*callback*/)
913 {
914         //prepare all the color buffer stuff, etc.
915
916         return true;
917 }
918
919 Color *
920 Target_LibAVCodec::start_scanline(int scanline)
921 {
922         return surface[scanline];
923
924         return 0;       // This should kill the render process
925 }
926
927 bool
928 Target_LibAVCodec::end_scanline()
929 {
930         //don't need to do anything until the whole frame is done
931         return true;
932 }
933
934 bool Target_LibAVCodec::init()
935 {
936         //hardcoded test for mpeg
937         if(!data->Initialize(filename.c_str(),NULL))
938         {
939                 synfig::warning("Unable to Initialize the audio video encoders");
940                 return 0;
941         }
942
943         return true;
944 }