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