1 /* === S Y N F I G ========================================================= */
5 ** $Id: trgt_av.cpp,v 1.1.1.1 2005/01/04 01:23:11 darco Exp $
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
38 #include "libavformat/avformat.h"
41 #include <synfig/general.h>
49 #define snprintf _snprintf
52 /* === U S I N G =========================================================== */
54 using namespace synfig;
58 /* === I N F O ============================================================= */
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: trgt_av.cpp,v 1.1.1.1 2005/01/04 01:23:11 darco Exp $");
66 /* === C L A S S E S & S T R U C T S ======================================= */
68 bool Target_LibAVCodec::registered = false;
71 //float STREAM_DURATION = 5.0f;
83 int samplerate; //in HZ
84 int samplesize; //in bytes
87 AVFrame *alloc_picture(int pix_fmt, int width, int height)
93 picture = avcodec_alloc_frame();
96 size = avpicture_get_size(pix_fmt, width, height);
97 picture_buf = (uint8_t *)malloc(size);
102 avpicture_fill((AVPicture *)picture, picture_buf,
103 pix_fmt, width, height);
107 void free_picture(AVFrame *pic)
109 av_free(pic->data[0]);
113 //the frame must be RGB24
114 static void convert_surface_frame(AVFrame *pic, const Surface &s, const Gamma &gamma)
117 Surface::const_pen p = s.begin();
128 stride = pic->linesize[0];
130 for(j = 0; j < h; j++, p.inc_y(), ptr += stride)
134 //use convert_color_format instead...
136 const int channels = 3;
138 for(int i = 0; i < w; i++, p.inc_x(), tptr += channels)
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();
152 //essentially treats it as if it has a background color of black
154 //we must also clamp the rgb values [0,1]
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);
172 convert_color_format((unsigned char *)tptr,&p.get_value(),w,PF_RGB,gamma);
178 //Audio Streamer (abstracts the open, write and close operations for audio streams)
186 vector<unsigned char>audiobuffer;
188 int audio_input_frame_size;
190 bool open(AVFormatContext *formatc, AVStream *stream)
192 AVCodecContext *context;
195 context = &stream->codec;
198 codec = avcodec_find_encoder(context->codec_id);
201 synfig::warning("audio-open: could not find codec");
206 if(avcodec_open(context, codec) < 0)
208 synfig::warning("audio-open: could not open codec");
212 /* hardcoded example for generating samples array*/
215 tincr = 2 * M_PI * 110.0 / c->sample_rate;
216 tincr2 = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate;*/
218 audiobuffer.resize(10000);
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;
235 audio_input_frame_size = context->frame_size;
239 //samples = (int16_t *)malloc(audio_input_frame_size * 2 * c->channels);
244 bool write_frame(AVFormatContext *formatc, AVStream *stream, void *samples)
247 AVCodecContext *context;
249 context = &stream->codec;
251 //hardcoded in example
252 //must read in from somewhere...
253 //get_audio_frame(samples, audio_input_frame_size, c->channels);
256 const short int*samps=(const short int *)samples; //assuming it's set from somewhere right now
258 size = avcodec_encode_audio(context, &audiobuffer[0], audiobuffer.size(), samps);
260 //write the compressed audio to a file
261 if(av_write_frame(formatc, stream->index, &audiobuffer[0], size) != 0)
263 synfig::warning("audio-write_frame: unable to write the entire audio frame");
270 void close(AVFormatContext *formatc, AVStream *stream)
272 //we may also want to catch delayed frames from here (don't for now)
276 avcodec_close(&stream->codec);
279 //if(samples)av_free(samples);
280 audiobuffer.resize(0);
289 AVFrame *encodable; //for compressiong and output to a file (in compatible pixel format)
291 vector<unsigned char> videobuffer;
293 bool startedencoding;
295 //int stream_nb_frames;
297 bool open(AVFormatContext *formatc, AVStream *stream)
299 if(!formatc || !stream)
301 synfig::warning("Attempt to open a video codec with a bad format or stream");
307 AVCodecContext *context;
309 //get from inside stream
310 context = &stream->codec;
312 //search for desired codec (contained in the stream)
313 codec = avcodec_find_encoder(context->codec_id);
316 synfig::warning("Open_video: could not find desired codec");
320 //try to open the codec
321 if(avcodec_open(context, codec) < 0)
323 synfig::warning("open_video: could not open desired codec");
327 videobuffer.resize(0);
328 if(!(formatc->oformat->flags & AVFMT_RAWPICTURE))
330 //resize buffer to desired buffersize
331 videobuffer.resize(200000); //TODO: need to figure out a good size
334 //allocate the base picture which will be used to encode
335 /*picture = alloc_picture(PIX_FMT_RGBA32, context->width, context->height);
338 synfig::warning("open_video: could not allocate the picture to be encoded");
342 //if our output (rgb) needs to be translated to a different coordinate system, need a temporary picture in that color space
344 /* Should use defaults of RGB
348 PIX_FMT_RGBA32 //stored in cpu endianness (!!!!)
350 (possibly translate directly to required coordinate systems later on... less error)
353 if(context->pix_fmt != PIX_FMT_RGB24)
355 encodable = alloc_picture(context->pix_fmt, context->width, context->height);
358 synfig::warning("open_video: could not allocate encodable picture");
366 //write a frame with the frame passed in
367 bool write_frame(AVFormatContext *formatc, AVStream *stream, AVFrame *pict)
369 if(!formatc || !stream)
371 synfig::warning("Attempt to open a video codec with a bad format or stream");
377 AVCodecContext *context = &stream->codec;
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 transofrm necessary
385 startedencoding = true;
389 if ( pict && context->pix_fmt != PIX_FMT_RGB24 )
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);
399 //cludge for raw picture format (they said they'd fix)
400 if (formatc->oformat->flags & AVFMT_RAWPICTURE)
402 ret = av_write_frame(formatc, stream->index, (uint8_t *)pict, sizeof(AVPicture));
406 //encode our given image
407 size = avcodec_encode_video(context, &videobuffer[0], videobuffer.size(), pict);
409 //if not zero we've got stuff to write
412 ret = av_write_frame(formatc, stream->index, &videobuffer[0], size);
414 //error detect - possibly throw later...
417 synfig::warning("write_frame: error while writing video frame");
421 //if 0, it was buffered (if invalid picture we don't have ANY data left)
424 //if we're clearing the buffers and there was no stuff to be written, we're done (like in codec example)
428 startedencoding = false;
438 void close(AVFormatContext *formatc, AVStream *stream)
441 avcodec_close(&stream->codec);
445 free_picture(encodable);
449 videobuffer.resize(0);
453 class Target_LibAVCodec::LibAVEncoder
459 AVOutputFormat *format; //reference to global, do not delete
461 AVFormatContext *formatc;
464 //AVStream *audio_st;
475 AVFrame *picture; //for encoding to RGB24 (perhaps RGBA later)
490 //vid.stream_nb_frames = 2; //reasonable default
508 bool Initialize(const char *filename, const char *typestring)
510 //guess if we have a type string, otherwise use filename
513 //formatptr guess_format(type, filename, MIME type)
514 format = guess_format(typestring,NULL,NULL);
518 format = guess_format(NULL, filename, NULL);
523 synfig::warning("Unable to Guess the output, defaulting to mpeg");
524 format = guess_format("mpeg", NULL, NULL);
529 synfig::warning("Unable to find output format");
533 //allocate the output context
534 formatc = (AVFormatContext *)av_mallocz(sizeof(AVFormatContext));
537 synfig::warning("Memory error\n");
540 //set the output format to the one we found
541 formatc->oformat = format;
543 //print the output filename
544 snprintf(formatc->filename, sizeof(formatc->filename), "%s", filename);
551 if(format->video_codec != CODEC_ID_NONE)
553 video_st = add_video_stream(format->video_codec,vInfo);
561 /*if(format->audio_codec != CODEC_ID_NONE)
563 audio_st = add_audio_stream(format->audio_codec,aInfo);
566 //set output parameters: required in ALL cases
568 AVFormatParameters fmtparam,*ap = &fmtparam;
569 memset(ap, 0, sizeof(*ap));
570 ap->frame_rate = vInfo.fps;
571 ap->frame_rate_base = 1;
573 ap->height = vInfo.h;
574 //ap->pix_fmt = frame_pix_fmt;
576 if(av_set_parameters(formatc, ap) < 0)
578 synfig::warning("Invalid output formatting parameters");
582 //dump the formatting information as the file header
583 dump_format(formatc, 0, filename, 1);
585 //open codecs and allocate buffers
588 if(!vid.open(formatc, video_st))
590 synfig::warning("Could not open video encoder");
596 if(!aud.open(formatc, audio_st))
598 synfig::warning("Could not open audio encoder");
604 if(!(format->flags & AVFMT_NOFILE))
606 //use libav's file open function (what does it do differently????)
607 if(url_fopen(&formatc->pb, filename, URL_WRONLY) < 0)
609 synfig::warning("Unable to open file: %s", filename);
614 //allocate the picture to render to
615 //may have to retrieve the width, height from the codec... for resizing...
616 picture = alloc_picture(PIX_FMT_RGB24,vInfo.w,vInfo.h);//video_st->codec.width, video_st->codec.height);
619 synfig::warning("Unable to allocate the temporary AVFrame surface");
624 //vInfo.w = video_st->codec.width;
625 //vInfo.h = video_st->codec.height;
627 //write the stream header
628 av_write_header(formatc);
637 if(picture) free_picture(picture);
639 //do all the clean up file rendering
640 if(formatc && video_st)
642 //want to scan in delayed frames until no longer needed (TODO)
643 if(vid.startedencoding) while( vid.write_frame(formatc, video_st, 0) );
645 //may want to move this... probably to the end of the last frame...
646 av_write_trailer(formatc);
651 vid.close(formatc,video_st);
653 aud.close(formatc,audio_st);*/
655 /* write the trailer, if any */
658 /* free the streams */
659 for(i = 0; i < formatc->nb_streams; i++)
661 av_freep(&formatc->streams[i]);
664 if(!(format->flags & AVFMT_NOFILE))
666 /* close the output file */
667 url_fclose(&formatc->pb);
670 /* free the stream */
684 //vid.stream_nb_frames = 2; //reasonable default
690 //create a video output stream
691 AVStream *add_video_stream(int codec_id, const VideoInfo &info)
693 AVCodecContext *context;
696 st = av_new_stream(formatc, 0);
699 synfig::warning("video-add_stream: Unable to allocate stream");
703 context = &st->codec;
704 context->codec_id = (CodecID)codec_id;
705 context->codec_type = CODEC_TYPE_VIDEO;
707 //PARAMETERS MUST BE PASSED IN SOMEHOW (ANOTHER FUNCTION PARAMETER???)
709 /* resolution must be a multiple of two */
710 context->width = info.w;
711 context->height = info.h;
713 //have another way to input these
714 context->bit_rate = info.bitrate; //TODO: Make dependant on the quality
716 /* frames per second */
717 context->frame_rate = info.fps;
718 context->frame_rate_base = 1;
721 context->mb_decision=FF_MB_DECISION_BITS;
723 context->gop_size = info.fps/4; /* emit one intra frame every twelve frames at most */
725 //HACK: MPEG requires b frames be set... any better way to do this?
726 if (context->codec_id == CODEC_ID_MPEG1VIDEO ||
727 context->codec_id == CODEC_ID_MPEG2VIDEO)
729 /* just for testing, we also add B frames */
730 context->max_b_frames = 2;
736 // add an audio output stream
737 AVStream *add_audio_stream(int codec_id,const AudioInfo &aInfo)
739 AVCodecContext *context;
742 stream = av_new_stream(formatc, 1);
745 synfig::warning("could not alloc stream");
749 context = &stream->codec;
750 context->codec_id = (CodecID)codec_id;
751 context->codec_type = CODEC_TYPE_AUDIO;
753 /* put sample parameters */
754 context->bit_rate = 64000;
755 context->sample_rate = 44100;
756 context->channels = 2;
762 /* === M E T H O D S ======================================================= */
764 Target_LibAVCodec::Target_LibAVCodec(const char *Filename):
774 data = new LibAVEncoder;
777 Target_LibAVCodec::~Target_LibAVCodec()
783 Target_LibAVCodec::set_rend_desc(RendDesc *given_desc)
785 // This is where you can determine how you want stuff
786 // to be rendered! given_desc is the suggestion, and
787 // you need to modify it to suit the needs of the codec.
788 // ie: Making the pixel dimensions divisible by 8, etc...
792 //resize surface (round even)
793 int w = desc.get_w();
794 int h = desc.get_h();
795 Point tl = desc.get_tl();
796 Point br = desc.get_br();
797 Real pw = desc.get_pw();
798 Real ph = desc.get_ph();
800 //resize to the size it should be...
801 //desc.set_subwindow(-offx/2,-offy/2, desc.get_w() - offx?(offx + 8):0, desc.get_h() - offy?(offy + 8):0);
803 //if resolution is broken, change the size... or something
804 //budge to nearest pixel values
827 //may want to round frame rate
828 data->vInfo.fps = (int)floor(desc.get_frame_rate()+0.5);
829 #define MEGABYTES_PER_HOUR(x) (((x)*1024/3600*1024*8)/*/640*w/480*h*/)
830 data->vInfo.bitrate = MEGABYTES_PER_HOUR(400);
831 //data->vInfo.bitrate = 800000; //make customizable somehow
833 desc.set_frame_rate(data->vInfo.fps);
835 data->frame_count = desc.get_frame_start();
836 data->num_frames = desc.get_frame_end()+1; //number of frames should be 1 greater than the last one
838 surface.set_wh(data->vInfo.w,data->vInfo.h);
844 Target_LibAVCodec::end_frame()
846 //AVStream *audio_st = data->audio_st;
847 AVStream *video_st = data->video_st;
849 AVFormatContext *formatc = data->formatc;
851 //double &audio_pts = data->audio_pts;
852 //double &video_pts = data->video_pts;
854 //ignore audio for now
856 audio_pts = (double)audio_st->pts.val * formatc->pts_num / formatc->pts_den;
861 video_pts = (double)video_st->pts.val * formatc->pts_num / formatc->pts_den;
865 //hardcoded crappiness
866 /*if ((!audio_st || audio_pts >= STREAM_DURATION) &&
867 (!video_st || video_pts >= STREAM_DURATION))
870 if(data->frame_count >= data->num_frames) return;
872 //copy the current surface to the buffer
873 if(data->picture)convert_surface_frame(data->picture,surface,gamma());
875 //encode the frame and write it to the file
876 if(!data->vid.write_frame(formatc,video_st,data->picture))
878 synfig::warning("Unable to write a frame");
883 if(data->frame_count >= data->num_frames)
888 /* write interleaved audio and video frames */
889 /*if (!video_st || (video_st && audio_st && audio_pts < video_pts)) {
890 data->aud.write_frame(formatc,audio_st);
892 data->vid.write_frame(formatc,video_st);
897 Target_LibAVCodec::start_frame(synfig::ProgressCallback *callback)
899 //prepare all the color buffer stuff, etc.
905 Target_LibAVCodec::start_scanline(int scanline)
907 return surface[scanline];
909 return 0; // This should kill the render process
913 Target_LibAVCodec::end_scanline()
915 //don't need to do anything until the whole frame is done
919 bool Target_LibAVCodec::init()
921 //hardcode test for mpeg
922 if(!data->Initialize(filename.c_str(),NULL))
924 synfig::warning("Unable to Initialize the audio video encoders");