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 Robert B. Quattlebaum Jr.
10 ** This software and associated documentation
11 ** are CONFIDENTIAL and PROPRIETARY property of
12 ** the above-mentioned copyright holder.
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.
20 /* ========================================================================= */
22 /* === H E A D E R S ======================================================= */
24 #define SYNFIG_NO_ANGLE
37 #include "libavformat/avformat.h"
40 #include <synfig/general.h>
48 #define snprintf _snprintf
51 /* === U S I N G =========================================================== */
53 using namespace synfig;
57 /* === I N F O ============================================================= */
59 SYNFIG_TARGET_INIT(Target_LibAVCodec);
60 SYNFIG_TARGET_SET_NAME(Target_LibAVCodec,"libav");
61 SYNFIG_TARGET_SET_EXT(Target_LibAVCodec,"avi");
62 SYNFIG_TARGET_SET_VERSION(Target_LibAVCodec,"0.1");
63 SYNFIG_TARGET_SET_CVS_ID(Target_LibAVCodec,"$Id: trgt_av.cpp,v 1.1.1.1 2005/01/04 01:23:11 darco Exp $");
65 /* === C L A S S E S & S T R U C T S ======================================= */
67 bool Target_LibAVCodec::registered = false;
70 //float STREAM_DURATION = 5.0f;
82 int samplerate; //in HZ
83 int samplesize; //in bytes
86 AVFrame *alloc_picture(int pix_fmt, int width, int height)
92 picture = avcodec_alloc_frame();
95 size = avpicture_get_size(pix_fmt, width, height);
96 picture_buf = (uint8_t *)malloc(size);
101 avpicture_fill((AVPicture *)picture, picture_buf,
102 pix_fmt, width, height);
106 void free_picture(AVFrame *pic)
108 av_free(pic->data[0]);
112 //the frame must be RGB24
113 static void convert_surface_frame(AVFrame *pic, const Surface &s, const Gamma &gamma)
116 Surface::const_pen p = s.begin();
127 stride = pic->linesize[0];
129 for(j = 0; j < h; j++, p.inc_y(), ptr += stride)
133 //use convert_color_format instead...
135 const int channels = 3;
137 for(int i = 0; i < w; i++, p.inc_x(), tptr += channels)
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();
151 //essentially treats it as if it has a background color of black
153 //we must also clamp the rgb values [0,1]
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);
171 convert_color_format((unsigned char *)tptr,&p.get_value(),w,PF_RGB,gamma);
177 //Audio Streamer (abstracts the open, write and close operations for audio streams)
185 vector<unsigned char>audiobuffer;
187 int audio_input_frame_size;
189 bool open(AVFormatContext *formatc, AVStream *stream)
191 AVCodecContext *context;
194 context = &stream->codec;
197 codec = avcodec_find_encoder(context->codec_id);
200 synfig::warning("audio-open: could not find codec");
205 if(avcodec_open(context, codec) < 0)
207 synfig::warning("audio-open: could not open codec");
211 /* hardcoded example for generating samples array*/
214 tincr = 2 * M_PI * 110.0 / c->sample_rate;
215 tincr2 = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate;*/
217 audiobuffer.resize(10000);
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;
234 audio_input_frame_size = context->frame_size;
238 //samples = (int16_t *)malloc(audio_input_frame_size * 2 * c->channels);
243 bool write_frame(AVFormatContext *formatc, AVStream *stream, void *samples)
246 AVCodecContext *context;
248 context = &stream->codec;
250 //hardcoded in example
251 //must read in from somewhere...
252 //get_audio_frame(samples, audio_input_frame_size, c->channels);
255 const short int*samps=(const short int *)samples; //assuming it's set from somewhere right now
257 size = avcodec_encode_audio(context, &audiobuffer[0], audiobuffer.size(), samps);
259 //write the compressed audio to a file
260 if(av_write_frame(formatc, stream->index, &audiobuffer[0], size) != 0)
262 synfig::warning("audio-write_frame: unable to write the entire audio frame");
269 void close(AVFormatContext *formatc, AVStream *stream)
271 //we may also want to catch delayed frames from here (don't for now)
275 avcodec_close(&stream->codec);
278 //if(samples)av_free(samples);
279 audiobuffer.resize(0);
288 AVFrame *encodable; //for compressiong and output to a file (in compatible pixel format)
290 vector<unsigned char> videobuffer;
292 bool startedencoding;
294 //int stream_nb_frames;
296 bool open(AVFormatContext *formatc, AVStream *stream)
298 if(!formatc || !stream)
300 synfig::warning("Attempt to open a video codec with a bad format or stream");
306 AVCodecContext *context;
308 //get from inside stream
309 context = &stream->codec;
311 //search for desired codec (contained in the stream)
312 codec = avcodec_find_encoder(context->codec_id);
315 synfig::warning("Open_video: could not find desired codec");
319 //try to open the codec
320 if(avcodec_open(context, codec) < 0)
322 synfig::warning("open_video: could not open desired codec");
326 videobuffer.resize(0);
327 if(!(formatc->oformat->flags & AVFMT_RAWPICTURE))
329 //resize buffer to desired buffersize
330 videobuffer.resize(200000); //TODO: need to figure out a good size
333 //allocate the base picture which will be used to encode
334 /*picture = alloc_picture(PIX_FMT_RGBA32, context->width, context->height);
337 synfig::warning("open_video: could not allocate the picture to be encoded");
341 //if our output (rgb) needs to be translated to a different coordinate system, need a temporary picture in that color space
343 /* Should use defaults of RGB
347 PIX_FMT_RGBA32 //stored in cpu endianness (!!!!)
349 (possibly translate directly to required coordinate systems later on... less error)
352 if(context->pix_fmt != PIX_FMT_RGB24)
354 encodable = alloc_picture(context->pix_fmt, context->width, context->height);
357 synfig::warning("open_video: could not allocate encodable picture");
365 //write a frame with the frame passed in
366 bool write_frame(AVFormatContext *formatc, AVStream *stream, AVFrame *pict)
368 if(!formatc || !stream)
370 synfig::warning("Attempt to open a video codec with a bad format or stream");
376 AVCodecContext *context = &stream->codec;
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
384 startedencoding = true;
388 if ( pict && context->pix_fmt != PIX_FMT_RGB24 )
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);
398 //cludge for raw picture format (they said they'd fix)
399 if (formatc->oformat->flags & AVFMT_RAWPICTURE)
401 ret = av_write_frame(formatc, stream->index, (uint8_t *)pict, sizeof(AVPicture));
405 //encode our given image
406 size = avcodec_encode_video(context, &videobuffer[0], videobuffer.size(), pict);
408 //if not zero we've got stuff to write
411 ret = av_write_frame(formatc, stream->index, &videobuffer[0], size);
413 //error detect - possibly throw later...
416 synfig::warning("write_frame: error while writing video frame");
420 //if 0, it was buffered (if invalid picture we don't have ANY data left)
423 //if we're clearing the buffers and there was no stuff to be written, we're done (like in codec example)
427 startedencoding = false;
437 void close(AVFormatContext *formatc, AVStream *stream)
440 avcodec_close(&stream->codec);
444 free_picture(encodable);
448 videobuffer.resize(0);
452 class Target_LibAVCodec::LibAVEncoder
458 AVOutputFormat *format; //reference to global, do not delete
460 AVFormatContext *formatc;
463 //AVStream *audio_st;
474 AVFrame *picture; //for encoding to RGB24 (perhaps RGBA later)
489 //vid.stream_nb_frames = 2; //reasonable default
507 bool Initialize(const char *filename, const char *typestring)
509 //guess if we have a type string, otherwise use filename
512 //formatptr guess_format(type, filename, MIME type)
513 format = guess_format(typestring,NULL,NULL);
517 format = guess_format(NULL, filename, NULL);
522 synfig::warning("Unable to Guess the output, defaulting to mpeg");
523 format = guess_format("mpeg", NULL, NULL);
528 synfig::warning("Unable to find output format");
532 //allocate the output context
533 formatc = (AVFormatContext *)av_mallocz(sizeof(AVFormatContext));
536 synfig::warning("Memory error\n");
539 //set the output format to the one we found
540 formatc->oformat = format;
542 //print the output filename
543 snprintf(formatc->filename, sizeof(formatc->filename), "%s", filename);
550 if(format->video_codec != CODEC_ID_NONE)
552 video_st = add_video_stream(format->video_codec,vInfo);
560 /*if(format->audio_codec != CODEC_ID_NONE)
562 audio_st = add_audio_stream(format->audio_codec,aInfo);
565 //set output parameters: required in ALL cases
567 AVFormatParameters fmtparam,*ap = &fmtparam;
568 memset(ap, 0, sizeof(*ap));
569 ap->frame_rate = vInfo.fps;
570 ap->frame_rate_base = 1;
572 ap->height = vInfo.h;
573 //ap->pix_fmt = frame_pix_fmt;
575 if(av_set_parameters(formatc, ap) < 0)
577 synfig::warning("Invalid output formatting parameters");
581 //dump the formatting information as the file header
582 dump_format(formatc, 0, filename, 1);
584 //open codecs and allocate buffers
587 if(!vid.open(formatc, video_st))
589 synfig::warning("Could not open video encoder");
595 if(!aud.open(formatc, audio_st))
597 synfig::warning("Could not open audio encoder");
603 if(!(format->flags & AVFMT_NOFILE))
605 //use libav's file open function (what does it do differently????)
606 if(url_fopen(&formatc->pb, filename, URL_WRONLY) < 0)
608 synfig::warning("Unable to open file: %s", filename);
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);
618 synfig::warning("Unable to allocate the temporary AVFrame surface");
623 //vInfo.w = video_st->codec.width;
624 //vInfo.h = video_st->codec.height;
626 //write the stream header
627 av_write_header(formatc);
636 if(picture) free_picture(picture);
638 //do all the clean up file rendering
639 if(formatc && video_st)
641 //want to scan in delayed frames until no longer needed (TODO)
642 if(vid.startedencoding) while( vid.write_frame(formatc, video_st, 0) );
644 //may want to move this... probably to the end of the last frame...
645 av_write_trailer(formatc);
650 vid.close(formatc,video_st);
652 aud.close(formatc,audio_st);*/
654 /* write the trailer, if any */
657 /* free the streams */
658 for(i = 0; i < formatc->nb_streams; i++)
660 av_freep(&formatc->streams[i]);
663 if(!(format->flags & AVFMT_NOFILE))
665 /* close the output file */
666 url_fclose(&formatc->pb);
669 /* free the stream */
683 //vid.stream_nb_frames = 2; //reasonable default
689 //create a video output stream
690 AVStream *add_video_stream(int codec_id, const VideoInfo &info)
692 AVCodecContext *context;
695 st = av_new_stream(formatc, 0);
698 synfig::warning("video-add_stream: Unable to allocate stream");
702 context = &st->codec;
703 context->codec_id = (CodecID)codec_id;
704 context->codec_type = CODEC_TYPE_VIDEO;
706 //PARAMETERS MUST BE PASSED IN SOMEHOW (ANOTHER FUNCTION PARAMETER???)
708 /* resolution must be a multiple of two */
709 context->width = info.w;
710 context->height = info.h;
712 //have another way to input these
713 context->bit_rate = info.bitrate; //TODO: Make dependant on the quality
715 /* frames per second */
716 context->frame_rate = info.fps;
717 context->frame_rate_base = 1;
720 context->mb_decision=FF_MB_DECISION_BITS;
722 context->gop_size = info.fps/4; /* emit one intra frame every twelve frames at most */
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)
728 /* just for testing, we also add B frames */
729 context->max_b_frames = 2;
735 // add an audio output stream
736 AVStream *add_audio_stream(int codec_id,const AudioInfo &aInfo)
738 AVCodecContext *context;
741 stream = av_new_stream(formatc, 1);
744 synfig::warning("could not alloc stream");
748 context = &stream->codec;
749 context->codec_id = (CodecID)codec_id;
750 context->codec_type = CODEC_TYPE_AUDIO;
752 /* put sample parameters */
753 context->bit_rate = 64000;
754 context->sample_rate = 44100;
755 context->channels = 2;
761 /* === M E T H O D S ======================================================= */
763 Target_LibAVCodec::Target_LibAVCodec(const char *Filename):
773 data = new LibAVEncoder;
776 Target_LibAVCodec::~Target_LibAVCodec()
782 Target_LibAVCodec::set_rend_desc(RendDesc *given_desc)
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...
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();
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);
802 //if resolution is broken, change the size... or something
803 //budge to nearest pixel values
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
832 desc.set_frame_rate(data->vInfo.fps);
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
837 surface.set_wh(data->vInfo.w,data->vInfo.h);
843 Target_LibAVCodec::end_frame()
845 //AVStream *audio_st = data->audio_st;
846 AVStream *video_st = data->video_st;
848 AVFormatContext *formatc = data->formatc;
850 //double &audio_pts = data->audio_pts;
851 //double &video_pts = data->video_pts;
853 //ignore audio for now
855 audio_pts = (double)audio_st->pts.val * formatc->pts_num / formatc->pts_den;
860 video_pts = (double)video_st->pts.val * formatc->pts_num / formatc->pts_den;
864 //hardcoded crappiness
865 /*if ((!audio_st || audio_pts >= STREAM_DURATION) &&
866 (!video_st || video_pts >= STREAM_DURATION))
869 if(data->frame_count >= data->num_frames) return;
871 //copy the current surface to the buffer
872 if(data->picture)convert_surface_frame(data->picture,surface,gamma());
874 //encode the frame and write it to the file
875 if(!data->vid.write_frame(formatc,video_st,data->picture))
877 synfig::warning("Unable to write a frame");
882 if(data->frame_count >= data->num_frames)
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);
891 data->vid.write_frame(formatc,video_st);
896 Target_LibAVCodec::start_frame(synfig::ProgressCallback *callback)
898 //prepare all the color buffer stuff, etc.
904 Target_LibAVCodec::start_scanline(int scanline)
906 return surface[scanline];
908 return 0; // This should kill the render process
912 Target_LibAVCodec::end_scanline()
914 //don't need to do anything until the whole frame is done
918 bool Target_LibAVCodec::init()
920 //hardcode test for mpeg
921 if(!data->Initialize(filename.c_str(),NULL))
923 synfig::warning("Unable to Initialize the audio video encoders");