1 /* === S Y N F I G ========================================================= */
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
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.
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.
21 /* ========================================================================= */
23 /* === H E A D E R S ======================================================= */
25 #define SYNFIG_NO_ANGLE
39 #ifdef WITH_LIBSWSCALE
44 #include <synfig/general.h>
52 #define snprintf _snprintf
55 /* === U S I N G =========================================================== */
57 using namespace synfig;
61 /* === I N F O ============================================================= */
63 SYNFIG_TARGET_INIT(Target_LibAVCodec);
64 SYNFIG_TARGET_SET_NAME(Target_LibAVCodec,"libav");
65 SYNFIG_TARGET_SET_EXT(Target_LibAVCodec,"avi");
66 SYNFIG_TARGET_SET_VERSION(Target_LibAVCodec,"0.1");
67 SYNFIG_TARGET_SET_CVS_ID(Target_LibAVCodec,"$Id$");
69 /* === C L A S S E S & S T R U C T S ======================================= */
71 bool Target_LibAVCodec::registered = false;
74 //float STREAM_DURATION = 5.0f;
86 int samplerate; //in HZ
87 int samplesize; //in bytes
90 AVFrame *alloc_picture(int pix_fmt, int width, int height)
96 picture = avcodec_alloc_frame();
99 size = avpicture_get_size(pix_fmt, width, height);
100 picture_buf = (uint8_t *)malloc(size);
105 avpicture_fill((AVPicture *)picture, picture_buf,
106 pix_fmt, width, height);
110 void free_picture(AVFrame *pic)
112 av_free(pic->data[0]);
116 //the frame must be RGB24
117 static void convert_surface_frame(AVFrame *pic, const Surface &s, const Gamma &gamma)
120 Surface::const_pen p = s.begin();
131 stride = pic->linesize[0];
133 for(j = 0; j < h; j++, p.inc_y(), ptr += stride)
137 //use convert_color_format instead...
139 const int channels = 3;
141 for(int i = 0; i < w; i++, p.inc_x(), tptr += channels)
145 Color::value_type r = c.get_r();
146 Color::value_type g = c.get_g();
147 Color::value_type b = c.get_b();
148 Color::value_type a = c.get_a();
155 //essentially treats it as if it has a background color of black
157 //we must also clamp the rgb values [0,1]
166 //now scale to range of char [0,255]
167 tptr[0] = (int)(r*255);
168 tptr[1] = (int)(g*255);
169 tptr[2] = (int)(b*255);
175 convert_color_format((unsigned char *)tptr,&p.get_value(),w,PF_RGB,gamma);
181 //Audio Streamer (abstracts the open, write and close operations for audio streams)
189 vector<unsigned char>audiobuffer;
191 int audio_input_frame_size;
193 bool open(AVFormatContext *formatc, AVStream *stream)
195 AVCodecContext *context;
198 context = &stream->codec;
201 codec = avcodec_find_encoder(context->codec_id);
204 synfig::warning("audio-open: could not find codec");
209 if(avcodec_open(context, codec) < 0)
211 synfig::warning("audio-open: could not open codec");
215 /* hardcoded example for generating samples array*/
218 tincr = 2 * M_PI * 110.0 / c->sample_rate;
219 tincr2 = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate;*/
221 audiobuffer.resize(10000);
223 /* ugly hack for PCM codecs (will be removed ASAP with new PCM
224 support to compute the input frame size in samples */
225 if (context->frame_size <= 1) {
226 audio_input_frame_size = audiobuffer.size() / context->channels;
227 switch(stream->codec.codec_id) {
228 case CODEC_ID_PCM_S16LE:
229 case CODEC_ID_PCM_S16BE:
230 case CODEC_ID_PCM_U16LE:
231 case CODEC_ID_PCM_U16BE:
232 audio_input_frame_size >>= 1;
238 audio_input_frame_size = context->frame_size;
242 //samples = (int16_t *)malloc(audio_input_frame_size * 2 * c->channels);
247 bool write_frame(AVFormatContext *formatc, AVStream *stream, void *samples)
250 AVCodecContext *context;
252 context = &stream->codec;
254 //hardcoded in example
255 //must read in from somewhere...
256 //get_audio_frame(samples, audio_input_frame_size, c->channels);
259 const short int*samps=(const short int *)samples; //assuming it's set from somewhere right now
261 size = avcodec_encode_audio(context, &audiobuffer[0], audiobuffer.size(), samps);
263 //write the compressed audio to a file
264 if(av_write_frame(formatc, stream->index, &audiobuffer[0], size) != 0)
266 synfig::warning("audio-write_frame: unable to write the entire audio frame");
273 void close(AVFormatContext *formatc, AVStream *stream)
275 //we may also want to catch delayed frames from here (don't for now)
279 avcodec_close(&stream->codec);
282 //if(samples)av_free(samples);
283 audiobuffer.resize(0);
292 AVFrame *encodable; //for compression and output to a file (in compatible pixel format)
294 vector<unsigned char> videobuffer;
296 bool startedencoding;
298 //int stream_nb_frames;
300 bool open(AVFormatContext *formatc, AVStream *stream)
302 if(!formatc || !stream)
304 synfig::warning("Attempt to open a video codec with a bad format or stream");
310 AVCodecContext *context;
312 //get from inside stream
313 context = stream->codec;
315 //search for desired codec (contained in the stream)
316 codec = avcodec_find_encoder(context->codec_id);
319 synfig::warning("Open_video: could not find desired codec");
323 //try to open the codec
324 if(avcodec_open(context, codec) < 0)
326 synfig::warning("open_video: could not open desired codec");
330 videobuffer.resize(0);
331 if(!(formatc->oformat->flags & AVFMT_RAWPICTURE))
333 //resize buffer to desired buffersize
334 videobuffer.resize(200000); //TODO: need to figure out a good size
337 //allocate the base picture which will be used to encode
338 /*picture = alloc_picture(PIX_FMT_RGBA32, context->width, context->height);
341 synfig::warning("open_video: could not allocate the picture to be encoded");
345 //if our output (rgb) needs to be translated to a different coordinate system, need a temporary picture in that color space
347 /* Should use defaults of RGB
351 PIX_FMT_RGBA32 //stored in cpu endianness (!!!!)
353 (possibly translate directly to required coordinate systems later on... less error)
356 if(context->pix_fmt != PIX_FMT_RGB24)
358 encodable = alloc_picture(context->pix_fmt, context->width, context->height);
361 synfig::warning("open_video: could not allocate encodable picture");
369 //write a frame with the frame passed in
370 bool write_frame(AVFormatContext *formatc, AVStream *stream, AVFrame *pict)
372 if(!formatc || !stream)
374 synfig::warning("Attempt to open a video codec with a bad format or stream");
380 AVCodecContext *context = stream->codec;
383 If pict is invalid (NULL), then we are done compressing frames and we are trying to get
384 the buffer cleared out (or if it's already in the right format) so no transform necessary
388 startedencoding = true;
392 if ( pict && context->pix_fmt != PIX_FMT_RGB24 )
394 //We're using RGBA at the moment, write custom conversion code later (get less accuracy errors)
395 #ifdef WITH_LIBSWSCALE
396 struct SwsContext* img_convert_ctx =
397 sws_getContext(context->width, context->height, PIX_FMT_RGB24,
398 context->width, context->height, context->pix_fmt,
399 SWS_BICUBIC, NULL, NULL, NULL);
401 sws_scale(img_convert_ctx, pict->data, pict->linesize,
403 0, context->height, encodable->data,
404 encodable->linesize);
406 sws_freeContext (img_convert_ctx);
408 img_convert((AVPicture *)encodable, context->pix_fmt,
409 (AVPicture *)pict, PIX_FMT_RGB24,
410 context->width, context->height);
417 av_init_packet(&pkt);
418 pkt.stream_index = stream->index;
419 pkt.data = (uint8_t *)pict;
420 pkt.size = sizeof(AVPicture);
421 if( context->coded_frame )
422 pkt.pts = context->coded_frame->pts;
423 if( context->coded_frame && context->coded_frame->key_frame)
424 pkt.flags |= PKT_FLAG_KEY;
426 //kluge for raw picture format (they said they'd fix)
427 if (formatc->oformat->flags & AVFMT_RAWPICTURE)
429 ret = av_write_frame(formatc, &pkt);
433 //encode our given image
434 size = avcodec_encode_video(context, &videobuffer[0], videobuffer.size(), pict);
436 //if greater than zero we've got stuff to write
439 av_init_packet(&pkt);
440 pkt.stream_index = stream->index;
441 pkt.data = &videobuffer[0];
443 if( context->coded_frame )
444 pkt.pts = context->coded_frame->pts;
445 if( context->coded_frame && context->coded_frame->key_frame)
446 pkt.flags |= PKT_FLAG_KEY;
448 ret = av_write_frame(formatc, &pkt);
450 //error detect - possibly throw later...
453 synfig::warning("write_frame: error while writing video frame");
457 //if 0, it was buffered (if invalid picture we don't have ANY data left)
460 //if we're clearing the buffers and there was no stuff to be written, we're done (like in codec example)
464 startedencoding = false;
474 void close(AVFormatContext */*formatc*/, AVStream *stream)
477 avcodec_close(stream->codec);
481 free_picture(encodable);
485 videobuffer.resize(0);
489 class Target_LibAVCodec::LibAVEncoder
495 AVOutputFormat *format; //reference to global, do not delete
497 AVFormatContext *formatc;
500 //AVStream *audio_st;
511 AVFrame *picture; //for encoding to RGB24 (perhaps RGBA later)
526 //vid.stream_nb_frames = 2; //reasonable default
544 bool Initialize(const char *filename, const char *typestring)
546 //guess if we have a type string, otherwise use filename
549 //formatptr guess_format(type, filename, MIME type)
550 format = guess_format(typestring,NULL,NULL);
554 format = guess_format(NULL, filename, NULL);
559 synfig::warning("Unable to Guess the output, defaulting to mpeg");
560 format = guess_format("mpeg", NULL, NULL);
565 synfig::warning("Unable to find output format");
569 //allocate the output context
570 formatc = (AVFormatContext *)av_mallocz(sizeof(AVFormatContext));
573 synfig::warning("Memory error\n");
576 //set the output format to the one we found
577 formatc->oformat = format;
579 //print the output filename
580 snprintf(formatc->filename, sizeof(formatc->filename), "%s", filename);
587 if(format->video_codec != CODEC_ID_NONE)
589 video_st = add_video_stream(format->video_codec,vInfo);
597 /*if(format->audio_codec != CODEC_ID_NONE)
599 audio_st = add_audio_stream(format->audio_codec,aInfo);
602 //set output parameters: required in ALL cases
604 video_st->codec->time_base= (AVRational){1,vInfo.fps};
605 video_st->codec->width = vInfo.w;
606 video_st->codec->height = vInfo.h;
607 video_st->codec->pix_fmt = PIX_FMT_YUV420P;
609 //dump the formatting information as the file header
610 dump_format(formatc, 0, filename, 1);
612 //open codecs and allocate buffers
615 if(!vid.open(formatc, video_st))
617 synfig::warning("Could not open video encoder");
623 if(!aud.open(formatc, audio_st))
625 synfig::warning("Could not open audio encoder");
631 if(!(format->flags & AVFMT_NOFILE))
633 //use libav's file open function (what does it do differently????)
634 if(url_fopen(&formatc->pb, filename, URL_WRONLY) < 0)
636 synfig::warning("Unable to open file: %s", filename);
641 //allocate the picture to render to
642 //may have to retrieve the width, height from the codec... for resizing...
643 picture = alloc_picture(PIX_FMT_RGB24,vInfo.w,vInfo.h);//video_st->codec.width, video_st->codec.height);
646 synfig::warning("Unable to allocate the temporary AVFrame surface");
651 //vInfo.w = video_st->codec.width;
652 //vInfo.h = video_st->codec.height;
654 //write the stream header
655 av_write_header(formatc);
664 if(picture) free_picture(picture);
666 //do all the clean up file rendering
667 if(formatc && video_st)
669 //want to scan in delayed frames until no longer needed (TODO)
670 if(vid.startedencoding) while( vid.write_frame(formatc, video_st, 0) );
672 //may want to move this... probably to the end of the last frame...
673 av_write_trailer(formatc);
678 vid.close(formatc,video_st);
680 aud.close(formatc,audio_st);*/
682 /* write the trailer, if any */
685 /* free the streams */
686 for(i = 0; i < formatc->nb_streams; i++)
688 av_freep(&formatc->streams[i]);
691 if(!(format->flags & AVFMT_NOFILE))
693 /* close the output file */
694 #if LIBAVFORMAT_VERSION_INT >= (52<<16)
695 url_fclose(formatc->pb);
697 url_fclose(&formatc->pb);
701 /* free the stream */
715 //vid.stream_nb_frames = 2; //reasonable default
721 //create a video output stream
722 AVStream *add_video_stream(int codec_id, const VideoInfo &info)
724 AVCodecContext *context;
727 st = av_new_stream(formatc, 0);
730 synfig::warning("video-add_stream: Unable to allocate stream");
735 context->codec_id = (CodecID)codec_id;
736 context->codec_type = CODEC_TYPE_VIDEO;
738 //PARAMETERS MUST BE PASSED IN SOMEHOW (ANOTHER FUNCTION PARAMETER???)
740 /* resolution must be a multiple of two */
741 context->width = info.w;
742 context->height = info.h;
744 //have another way to input these
745 context->bit_rate = info.bitrate; //TODO: Make dependant on the quality
747 /* frames per second */
748 // FIXME: Port next two lines to recent libavcodec versions
749 //context->frame_rate = info.fps;
750 //context->frame_rate_base = 1;
753 context->mb_decision=FF_MB_DECISION_BITS;
755 context->gop_size = info.fps/4; /* emit one intra frame every twelve frames at most */
757 //HACK: MPEG requires b frames be set... any better way to do this?
758 if (context->codec_id == CODEC_ID_MPEG1VIDEO ||
759 context->codec_id == CODEC_ID_MPEG2VIDEO)
761 /* just for testing, we also add B frames */
762 context->max_b_frames = 2;
768 // add an audio output stream
769 AVStream *add_audio_stream(int codec_id,const AudioInfo &/*aInfo*/)
771 AVCodecContext *context;
774 stream = av_new_stream(formatc, 1);
777 synfig::warning("could not alloc stream");
781 context = stream->codec;
782 context->codec_id = (CodecID)codec_id;
783 context->codec_type = CODEC_TYPE_AUDIO;
785 /* put sample parameters */
786 context->bit_rate = 64000;
787 context->sample_rate = 44100;
788 context->channels = 2;
794 /* === M E T H O D S ======================================================= */
796 Target_LibAVCodec::Target_LibAVCodec(const char *Filename):
806 data = new LibAVEncoder;
809 Target_LibAVCodec::~Target_LibAVCodec()
815 Target_LibAVCodec::set_rend_desc(RendDesc *given_desc)
817 // This is where you can determine how you want stuff
818 // to be rendered! given_desc is the suggestion, and
819 // you need to modify it to suit the needs of the codec.
820 // ie: Making the pixel dimensions divisible by 8, etc...
824 //resize surface (round even)
825 int w = desc.get_w();
826 int h = desc.get_h();
827 Point tl = desc.get_tl();
828 Point br = desc.get_br();
829 Real pw = desc.get_pw();
830 Real ph = desc.get_ph();
832 //resize to the size it should be...
833 //desc.set_subwindow(-offx/2,-offy/2, desc.get_w() - offx?(offx + 8):0, desc.get_h() - offy?(offy + 8):0);
835 //if resolution is broken, change the size... or something
836 //budge to nearest pixel values
859 //may want to round frame rate
860 data->vInfo.fps = (int)floor(desc.get_frame_rate()+0.5);
861 #define MEGABYTES_PER_HOUR(x) (((x)*1024/3600*1024*8)/*/640*w/480*h*/)
862 data->vInfo.bitrate = MEGABYTES_PER_HOUR(400);
863 //data->vInfo.bitrate = 800000; //make customizable somehow
865 desc.set_frame_rate(data->vInfo.fps);
867 data->frame_count = desc.get_frame_start();
868 data->num_frames = desc.get_frame_end()+1; //number of frames should be 1 greater than the last one
870 surface.set_wh(data->vInfo.w,data->vInfo.h);
876 Target_LibAVCodec::end_frame()
878 //AVStream *audio_st = data->audio_st;
879 AVStream *video_st = data->video_st;
881 AVFormatContext *formatc = data->formatc;
883 //double &audio_pts = data->audio_pts;
884 //double &video_pts = data->video_pts;
886 //ignore audio for now
888 audio_pts = (double)audio_st->pts.val * formatc->pts_num / formatc->pts_den;
893 video_pts = (double)video_st->pts.val * formatc->pts_num / formatc->pts_den;
897 //hardcoded crappiness
898 /*if ((!audio_st || audio_pts >= STREAM_DURATION) &&
899 (!video_st || video_pts >= STREAM_DURATION))
902 if(data->frame_count >= data->num_frames) return;
904 //copy the current surface to the buffer
905 if(data->picture)convert_surface_frame(data->picture,surface,gamma());
907 //encode the frame and write it to the file
908 if(!data->vid.write_frame(formatc,video_st,data->picture))
910 synfig::warning("Unable to write a frame");
915 if(data->frame_count >= data->num_frames)
920 /* write interleaved audio and video frames */
921 /*if (!video_st || (video_st && audio_st && audio_pts < video_pts)) {
922 data->aud.write_frame(formatc,audio_st);
924 data->vid.write_frame(formatc,video_st);
929 Target_LibAVCodec::start_frame(synfig::ProgressCallback */*callback*/)
931 //prepare all the color buffer stuff, etc.
937 Target_LibAVCodec::start_scanline(int scanline)
939 return surface[scanline];
941 return 0; // This should kill the render process
945 Target_LibAVCodec::end_scanline()
947 //don't need to do anything until the whole frame is done
951 bool Target_LibAVCodec::init()
953 //hardcoded test for mpeg
954 if(!data->Initialize(filename.c_str(),NULL))
956 synfig::warning("Unable to Initialize the audio video encoders");