== Sequencer ==
[blender.git] / source / blender / blenkernel / intern / writeffmpeg.c
1 /*
2  * ffmpeg-write support
3  *
4  * Partial Copyright (c) 2006 Peter Schlaile
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  */
17
18
19 #ifdef WITH_FFMPEG
20 #include <string.h>
21 #include <stdio.h>
22
23 #if defined(_WIN32) && defined(_DEBUG) && !defined(__MINGW32__) && !defined(__CYGWIN__)
24 /* This does not seem necessary or present on MSVC 8, but may be needed in earlier versions? */
25 #if _MSC_VER < 1400
26 #include <stdint.h>
27 #endif
28 #endif
29
30 #include <stdlib.h>
31
32 #include <ffmpeg/avformat.h>
33 #include <ffmpeg/avcodec.h>
34 #include <ffmpeg/rational.h>
35
36 #if LIBAVFORMAT_VERSION_INT < (49 << 16)
37 #define FFMPEG_OLD_FRAME_RATE 1
38 #else
39 #define FFMPEG_CODEC_IS_POINTER 1
40 #define FFMPEG_CODEC_TIME_BASE  1
41 #endif
42
43 #if defined(WIN32) && (!(defined snprintf))
44 #define snprintf _snprintf
45 #endif
46
47 #include "BKE_writeffmpeg.h"
48
49 #include "MEM_guardedalloc.h"
50 #include "BLI_blenlib.h"
51
52 #include "BKE_bad_level_calls.h"
53 #include "BKE_global.h"
54
55 #include "IMB_imbuf_types.h"
56 #include "IMB_imbuf.h"
57
58 #include "BSE_seqaudio.h"
59
60 #include "DNA_scene_types.h"
61 #include "blendef.h"
62
63 #ifdef HAVE_CONFIG_H
64 #include <config.h>
65 #endif
66
67 extern void do_init_ffmpeg();
68 void makeffmpegstring(char* string);
69
70 static int ffmpeg_type = 0;
71 static int ffmpeg_codec = CODEC_ID_MPEG4;
72 static int ffmpeg_audio_codec = CODEC_ID_MP2;
73 static int ffmpeg_video_bitrate = 1150;
74 static int ffmpeg_audio_bitrate = 128;
75 static int ffmpeg_gop_size = 12;
76 static int ffmpeg_multiplex_audio = 1;
77 static int ffmpeg_autosplit = 0;
78 static int ffmpeg_autosplit_count = 0;
79
80 static AVFormatContext* outfile = 0;
81 static AVStream* video_stream = 0;
82 static AVStream* audio_stream = 0;
83 static AVFrame* current_frame = 0;
84
85 static uint8_t* video_buffer = 0;
86 static int video_buffersize = 0;
87
88 static uint8_t* audio_input_buffer = 0;
89 static int audio_input_frame_size = 0;
90 static uint8_t* audio_output_buffer = 0;
91 static int audio_outbuf_size = 0;
92
93 static RenderData *ffmpeg_renderdata = 0;
94
95 #define FFMPEG_AUTOSPLIT_SIZE 2000000000
96
97 /* Delete a picture buffer */
98
99 static void delete_picture(AVFrame* f)
100 {
101         if (f) {
102                 if (f->data[0]) MEM_freeN(f->data[0]);
103                 av_free(f);
104         }
105 }
106
107 #ifdef FFMPEG_CODEC_IS_POINTER
108 static AVCodecContext* get_codec_from_stream(AVStream* stream)
109 {
110         return stream->codec;
111 }
112 #else
113 static AVCodecContext* get_codec_from_stream(AVStream* stream)
114 {
115         return &stream->codec;
116 }
117 #endif
118
119 static int write_audio_frame(void) 
120 {
121         AVCodecContext* c = NULL;
122         AVPacket pkt;
123
124         c = get_codec_from_stream(audio_stream);
125
126         audiostream_fill(audio_input_buffer, 
127                          audio_input_frame_size 
128                          * sizeof(short) * c->channels);
129
130         av_init_packet(&pkt);
131
132         pkt.size = avcodec_encode_audio(c, audio_output_buffer,
133                                         audio_outbuf_size, 
134                                         (short*) audio_input_buffer);
135         pkt.data = audio_output_buffer;
136 #ifdef FFMPEG_CODEC_TIME_BASE
137         pkt.pts = av_rescale_q(c->coded_frame->pts, 
138                                c->time_base, audio_stream->time_base);
139 #else
140         pkt.pts = c->coded_frame->pts;
141 #endif
142         fprintf(stderr, "Audio Frame PTS: %lld\n", pkt.pts);
143
144         pkt.stream_index = audio_stream->index;
145         pkt.flags |= PKT_FLAG_KEY;
146         if (av_interleaved_write_frame(outfile, &pkt) != 0) {
147                 error("Error writing audio packet");
148                 return -1;
149         }
150         return 0;
151 }
152
153 /* Allocate a temporary frame */
154 static AVFrame* alloc_picture(int pix_fmt, int width, int height) 
155 {
156         AVFrame* f;
157         uint8_t* buf;
158         int size;
159         
160         /* allocate space for the struct */
161         f = avcodec_alloc_frame();
162         if (!f) return NULL;
163         size = avpicture_get_size(pix_fmt, width, height);
164         /* allocate the actual picture buffer */
165         buf = MEM_mallocN(size, "AVFrame buffer");
166         if (!buf) {
167                 free(f);
168                 return NULL;
169         }
170         avpicture_fill((AVPicture*)f, buf, pix_fmt, width, height);
171         return f;
172 }
173
174 /* Get the correct file extensions for the requested format,
175    first is always desired guess_format parameter */
176 static const char** get_file_extensions(int format) 
177 {
178         switch(format) {
179         case FFMPEG_DV: {
180                 static const char * rv[] = { ".dv", NULL };
181                 return rv;
182         }
183         case FFMPEG_MPEG1: {
184                 static const char * rv[] = { ".mpg", ".mpeg", NULL };
185                 return rv;
186         }
187         case FFMPEG_MPEG2: {
188                 static const char * rv[] = { ".dvd", ".vob", ".mpg", ".mpeg",
189                                              NULL };
190                 return rv;
191         }
192         case FFMPEG_MPEG4: {
193                 static const char * rv[] = { ".mp4", ".mpg", ".mpeg", NULL };
194                 return rv;
195         }
196         case FFMPEG_AVI: {
197                 static const char * rv[] = { ".avi", NULL };
198                 return rv;
199         }
200         case FFMPEG_MOV: {
201                 static const char * rv[] = { ".mov", NULL };
202                 return rv;
203         }
204         case FFMPEG_H264: {
205                 /* FIXME: avi for now... */
206                 static const char * rv[] = { ".avi", NULL };
207                 return rv;
208         }
209
210         case FFMPEG_XVID: {
211                 /* FIXME: avi for now... */
212                 static const char * rv[] = { ".avi", NULL };
213                 return rv;
214         }
215         default:
216                 return NULL;
217         }
218 }
219
220 /* Write a frame to the output file */
221 static void write_video_frame(AVFrame* frame) 
222 {
223         int outsize = 0;
224         int ret;
225         AVCodecContext* c = get_codec_from_stream(video_stream);
226 #ifdef FFMPEG_CODEC_TIME_BASE
227         frame->pts = G.scene->r.cfra - G.scene->r.sfra;
228 #endif
229
230         outsize = avcodec_encode_video(c, video_buffer, video_buffersize, 
231                                        frame);
232         if (outsize != 0) {
233                 AVPacket packet;
234                 av_init_packet(&packet);
235
236 #ifdef FFMPEG_CODEC_TIME_BASE
237                 packet.pts = av_rescale_q(c->coded_frame->pts,
238                                           c->time_base,
239                                           video_stream->time_base);
240 #else
241                 packet.pts = c->coded_frame->pts;
242 #endif
243                 fprintf(stderr, "Video Frame PTS: %lld\n", packet.pts);
244                 if (c->coded_frame->key_frame)
245                         packet.flags |= PKT_FLAG_KEY;
246                 packet.stream_index = video_stream->index;
247                 packet.data = video_buffer;
248                 packet.size = outsize;
249                 ret = av_interleaved_write_frame(outfile, &packet);
250         } else ret = 0;
251         if (ret != 0) {
252                 G.afbreek = 1;
253                 error("Error writing frame");
254         }
255 }
256
257 /* read and encode a frame of audio from the buffer */
258 static AVFrame* generate_video_frame(uint8_t* pixels) 
259 {
260         uint8_t* rendered_frame;
261
262         AVCodecContext* c = get_codec_from_stream(video_stream);
263         int width = c->width;
264         int height = c->height;
265         AVFrame* rgb_frame;
266
267         if (c->pix_fmt != PIX_FMT_RGBA32) {
268                 rgb_frame = alloc_picture(PIX_FMT_RGBA32, width, height);
269                 if (!rgb_frame) {
270                         G.afbreek=1;
271                         error("Couldn't allocate temporary frame");
272                         return NULL;
273                 }
274         } else {
275                 rgb_frame = current_frame;
276         }
277
278         rendered_frame = pixels;
279
280         /* Do RGBA-conversion and flipping in one step depending
281            on CPU-Endianess */
282
283         if (G.order == L_ENDIAN) {
284                 int y;
285                 for (y = 0; y < height; y++) {
286                         uint8_t* target = rgb_frame->data[0]
287                                 + width * 4 * (height - y - 1);
288                         uint8_t* src = rendered_frame + width * 4 * y;
289                         uint8_t* end = src + width * 4;
290                         while (src != end) {
291                                 target[3] = src[3];
292                                 target[2] = src[0];
293                                 target[1] = src[1];
294                                 target[0] = src[2];
295
296                                 target += 4;
297                                 src += 4;
298                         }
299                 }
300         } else {
301                 int y;
302                 for (y = 0; y < height; y++) {
303                         uint8_t* target = rgb_frame->data[0]
304                                 + width * 4 * (height - y - 1);
305                         uint8_t* src = rendered_frame + width * 4 * y;
306                         uint8_t* end = src + width * 4;
307                         while (src != end) {
308                                 target[3] = src[2];
309                                 target[2] = src[1];
310                                 target[1] = src[0];
311                                 target[0] = src[3];
312
313                                 target += 4;
314                                 src += 4;
315                         }
316                 }
317         }
318
319         if (c->pix_fmt != PIX_FMT_RGBA32) {
320                 img_convert((AVPicture*)current_frame, c->pix_fmt, 
321                         (AVPicture*)rgb_frame, PIX_FMT_RGBA32, width, height);
322                 delete_picture(rgb_frame);
323         }
324         return current_frame;
325 }
326
327 /* prepare a video stream for the output file */
328
329 static AVStream* alloc_video_stream(int codec_id, AVFormatContext* of,
330                                     int rectx, int recty) 
331 {
332         AVStream* st;
333         AVCodecContext* c;
334         AVCodec* codec;
335         st = av_new_stream(of, 0);
336         if (!st) return NULL;
337
338         /* Set up the codec context */
339         
340         c = get_codec_from_stream(st);
341         c->codec_id = codec_id;
342         c->codec_type = CODEC_TYPE_VIDEO;
343
344
345         /* Get some values from the current render settings */
346         
347         c->width = rectx;
348         c->height = recty;
349
350 #ifdef FFMPEG_CODEC_TIME_BASE
351         /* FIXME: Really bad hack (tm) for NTSC support */
352         if (ffmpeg_type == FFMPEG_DV && G.scene->r.frs_sec != 25) {
353                 c->time_base.den = 2997;
354                 c->time_base.num = 100;
355         } else {
356                 c->time_base.den = G.scene->r.frs_sec;
357                 c->time_base.num = 1;
358         }
359 #else
360         /* FIXME: Really bad hack (tm) for NTSC support */
361         if (ffmpeg_type == FFMPEG_DV && G.scene->r.frs_sec != 25) {
362                 c->frame_rate = 2997;
363                 c->frame_rate_base = 100;
364         } else {
365                 c->frame_rate = G.scene->r.frs_sec;
366                 c->frame_rate_base = 1;
367         }
368 #endif
369         
370         c->gop_size = ffmpeg_gop_size;
371         c->bit_rate = ffmpeg_video_bitrate*1000;
372         c->rc_max_rate = G.scene->r.ffcodecdata.rc_max_rate*1000;
373         c->rc_min_rate = G.scene->r.ffcodecdata.rc_min_rate*1000;
374         c->rc_buffer_size = G.scene->r.ffcodecdata.rc_buffer_size * 1024;
375         c->rc_initial_buffer_occupancy 
376                 = G.scene->r.ffcodecdata.rc_buffer_size*3/4;
377         c->rc_buffer_aggressivity = 1.0;
378         c->me_method = ME_EPZS;
379         
380         codec = avcodec_find_encoder(c->codec_id);
381         if (!codec) return NULL;
382         
383         /* Be sure to use the correct pixel format(e.g. RGB, YUV) */
384         
385         if (codec->pix_fmts) {
386                 c->pix_fmt = codec->pix_fmts[0];
387         } else {
388                 /* makes HuffYUV happy ... */
389                 c->pix_fmt = PIX_FMT_YUV422P;
390         }
391
392         if (codec_id == CODEC_ID_XVID) {
393                 /* arghhhh ... */
394                 c->pix_fmt = PIX_FMT_YUV420P;
395         }
396         
397         if (!strcmp(of->oformat->name, "mp4") || 
398             !strcmp(of->oformat->name, "mov") ||
399             !strcmp(of->oformat->name, "3gp")) {
400                 fprintf(stderr, "Using global header\n");
401                 c->flags |= CODEC_FLAG_GLOBAL_HEADER;
402         }
403         
404         /* Determine whether we are encoding interlaced material or not */
405         if (G.scene->r.mode & (1 << 6)) {
406                 fprintf(stderr, "Encoding interlaced video\n");
407                 c->flags |= CODEC_FLAG_INTERLACED_DCT;
408                 c->flags |= CODEC_FLAG_INTERLACED_ME;
409         }       
410         c->sample_aspect_ratio.num = G.scene->r.xasp;
411         c->sample_aspect_ratio.den = G.scene->r.yasp;
412         
413         if (avcodec_open(c, codec) < 0) {
414                 error("Couldn't initialize codec");
415                 return NULL;
416         }
417
418         video_buffersize = 2000000;
419         video_buffer = (uint8_t*)MEM_mallocN(video_buffersize, 
420                                              "FFMPEG video buffer");
421         
422         current_frame = alloc_picture(c->pix_fmt, c->width, c->height);
423         return st;
424 }
425
426 /* Prepare an audio stream for the output file */
427
428 static AVStream* alloc_audio_stream(int codec_id, AVFormatContext* of) 
429 {
430         AVStream* st;
431         AVCodecContext* c;
432         AVCodec* codec;
433
434         st = av_new_stream(of, 1);
435         if (!st) return NULL;
436
437         c = get_codec_from_stream(st);
438         c->codec_id = codec_id;
439         c->codec_type = CODEC_TYPE_AUDIO;
440
441         c->sample_rate = G.scene->audio.mixrate;
442         c->bit_rate = ffmpeg_audio_bitrate*1000;
443         c->channels = 2;
444         codec = avcodec_find_encoder(c->codec_id);
445         if (!codec) {
446                 error("Couldn't find a valid audio codec");
447                 return NULL;
448         }
449         if (avcodec_open(c, codec) < 0) {
450                 error("Couldn't initialize audio codec");
451                 return NULL;
452         }
453
454         /* FIXME: Should be user configurable */
455         if (ffmpeg_type == FFMPEG_DV) {
456                 /* this is a hack around the poor ffmpeg dv multiplexer. */
457                 /* only fixes PAL for now 
458                    (NTSC is a lot more complicated here...)! */
459                 audio_outbuf_size = 7680;
460         } else {
461                 audio_outbuf_size = 10000;
462         }
463         audio_output_buffer = (uint8_t*)MEM_mallocN(
464                 audio_outbuf_size, "FFMPEG audio encoder input buffer");
465
466        /* ugly hack for PCM codecs */
467
468         if (c->frame_size <= 1) {
469                 audio_input_frame_size = audio_outbuf_size / c->channels;
470                 switch(c->codec_id) {
471                 case CODEC_ID_PCM_S16LE:
472                 case CODEC_ID_PCM_S16BE:
473                 case CODEC_ID_PCM_U16LE:
474                 case CODEC_ID_PCM_U16BE:
475                         audio_input_frame_size >>= 1;
476                         break;
477                 default:
478                         break;
479                 }
480         } else {
481                 audio_input_frame_size = c->frame_size;
482         }
483
484         audio_input_buffer = (uint8_t*)MEM_mallocN(
485                 audio_input_frame_size * sizeof(short) * c->channels, 
486                 "FFMPEG audio encoder output buffer");
487
488         return st;
489 }
490 /* essential functions -- start, append, end */
491
492 void start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty)
493 {
494         /* Handle to the output file */
495         AVFormatContext* of;
496         AVOutputFormat* fmt;
497         char name[256];
498         const char ** exts;
499
500         ffmpeg_type = rd->ffcodecdata.type;
501         ffmpeg_codec = rd->ffcodecdata.codec;
502         ffmpeg_audio_codec = rd->ffcodecdata.audio_codec;
503         ffmpeg_video_bitrate = rd->ffcodecdata.video_bitrate;
504         ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate;
505         ffmpeg_gop_size = rd->ffcodecdata.gop_size;
506         ffmpeg_multiplex_audio = rd->ffcodecdata.flags
507                 & FFMPEG_MULTIPLEX_AUDIO;
508         ffmpeg_autosplit = rd->ffcodecdata.flags
509                 & FFMPEG_AUTOSPLIT_OUTPUT;
510         
511         do_init_ffmpeg();
512
513         /* Determine the correct filename */
514         makeffmpegstring(name);
515         fprintf(stderr, "Starting output to %s(ffmpeg)...\n"
516                 "  Using type=%d, codec=%d, audio_codec=%d,\n"
517                 "  video_bitrate=%d, audio_bitrate=%d,\n"
518                 "  gop_size=%d, multiplex=%d, autosplit=%d\n"
519                 "  render width=%d, render height=%d\n", 
520                 name, ffmpeg_type, ffmpeg_codec, ffmpeg_audio_codec,
521                 ffmpeg_video_bitrate, ffmpeg_audio_bitrate,
522                 ffmpeg_gop_size, ffmpeg_multiplex_audio,
523                 ffmpeg_autosplit, rectx, recty);
524         
525         exts = get_file_extensions(ffmpeg_type);
526         if (!exts) {
527                 G.afbreek = 1; /* Abort render */
528                 error("No valid formats found");
529                 return;
530         }
531         fmt = guess_format(NULL, exts[0], NULL);
532         if (!fmt) {
533                 G.afbreek = 1; /* Abort render */
534                 error("No valid formats found");
535                 return;
536         }
537
538         of = av_alloc_format_context();
539         if (!of) {
540                 G.afbreek = 1;
541                 error("Error opening output file");
542                 return;
543         }
544         
545         of->oformat = fmt;
546         of->packet_size= G.scene->r.ffcodecdata.mux_packet_size;
547         if (ffmpeg_multiplex_audio) {
548                 of->mux_rate = G.scene->r.ffcodecdata.mux_rate;
549         } else {
550                 of->mux_rate = 0;
551         }
552
553         of->preload = (int)(0.5*AV_TIME_BASE);
554         of->max_delay = (int)(0.7*AV_TIME_BASE);
555
556         snprintf(of->filename, sizeof(of->filename), "%s", name);
557         /* set the codec to the user's selection */
558         switch(ffmpeg_type) {
559         case FFMPEG_AVI:
560         case FFMPEG_MOV:
561                 fmt->video_codec = ffmpeg_codec;
562                 break;
563         case FFMPEG_DV:
564                 fmt->video_codec = CODEC_ID_DVVIDEO;
565                 break;
566         case FFMPEG_MPEG1:
567                 fmt->video_codec = CODEC_ID_MPEG1VIDEO;
568                 break;
569         case FFMPEG_MPEG2:
570                 fmt->video_codec = CODEC_ID_MPEG2VIDEO;
571                 break;
572         case FFMPEG_H264:
573                 fmt->video_codec = CODEC_ID_H264;
574                 break;
575         case FFMPEG_XVID:
576                 fmt->video_codec = CODEC_ID_XVID;
577                 break;
578         case FFMPEG_MPEG4:
579         default:
580                 fmt->video_codec = CODEC_ID_MPEG4;
581                 break;
582         }
583         if (fmt->video_codec == CODEC_ID_DVVIDEO) {
584                 if (rectx != 720) {
585                         G.afbreek = 1;
586                         error("Render width has to be 720 pixels for DV!");
587                         return;
588                 }
589                 if (G.scene->r.frs_sec != 25 && recty != 480) {
590                         G.afbreek = 1;
591                         error("Render height has to be 480 pixels "
592                               "for DV-NTSC!");
593                         return;
594                         
595                 }
596                 if (G.scene->r.frs_sec == 25 && recty != 576) {
597                         G.afbreek = 1;
598                         error("Render height has to be 576 pixels "
599                               "for DV-PAL!");
600                         return;
601                 }
602         }
603         if (ffmpeg_type == FFMPEG_DV) {
604                 fmt->audio_codec = CODEC_ID_PCM_S16LE;
605                 if (ffmpeg_multiplex_audio 
606                     && G.scene->audio.mixrate != 48000) {
607                         G.afbreek = 1;
608                         error("FFMPEG only supports 48khz / stereo "
609                               "audio for DV!");
610                         return;
611                 }
612         }
613         
614         video_stream = alloc_video_stream(fmt->video_codec, of, rectx, recty);
615         if (!video_stream) {
616                 G.afbreek = 1;
617                 error("Error initializing video stream");
618                 return;
619         }
620         
621         if (ffmpeg_multiplex_audio) {
622                 audio_stream = alloc_audio_stream(fmt->audio_codec, of);
623                 if (!audio_stream) {
624                         G.afbreek = 1;
625                         error("Error initializing audio stream");
626                         return;
627                 }
628                 audiostream_play(SFRA, 0, 1);
629         }
630         if (av_set_parameters(of, NULL) < 0) {
631                 G.afbreek = 1;
632                 error("Error setting output parameters");
633                 return;
634         }
635         if (!(fmt->flags & AVFMT_NOFILE)) {
636                 if (url_fopen(&of->pb, name, URL_WRONLY) < 0) {
637                         G.afbreek = 1;
638                         error("Could not open file for writing");
639                         return;
640                 }
641         }
642
643         av_write_header(of);
644         outfile = of;
645         dump_format(of, 0, name, 1);
646 }
647
648 /* **********************************************************************
649    * public interface
650    ********************************************************************** */
651
652 /* Get the output filename-- similar to the other output formats */
653 void makeffmpegstring(char* string) {
654         
655         char txt[FILE_MAXDIR+FILE_MAXFILE];
656         char autosplit[20];
657
658         const char ** exts = get_file_extensions(G.scene->r.ffcodecdata.type);
659         const char ** fe = exts;
660
661         if (!string || !exts) return;
662
663         strcpy(string, G.scene->r.pic);
664         BLI_convertstringcode(string, G.sce, G.scene->r.cfra);
665
666         BLI_make_existing_file(string);
667
668         autosplit[0] = 0;
669
670         if ((G.scene->r.ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT) != 0) {
671                 sprintf(autosplit, "_%03d", ffmpeg_autosplit_count);
672         }
673
674         while (*fe) {
675                 if (BLI_strcasecmp(string + strlen(string) - strlen(*fe), 
676                                    *fe) == 0) {
677                         break;
678                 }
679                 fe++;
680         }
681
682         if (!*fe) {
683                 strcat(string, autosplit);
684                 sprintf(txt, "%04d_%04d%s", (G.scene->r.sfra), 
685                         (G.scene->r.efra), *exts);
686                 strcat(string, txt);
687         } else {
688                 *(string + strlen(string) - strlen(*fe)) = 0;
689                 strcat(string, autosplit);
690                 strcat(string, *fe);
691         }
692 }
693
694
695 void start_ffmpeg(RenderData *rd, int rectx, int recty)
696 {
697         ffmpeg_autosplit_count = 0;
698
699         ffmpeg_renderdata = rd;
700
701         start_ffmpeg_impl(rd, rectx, recty);
702 }
703
704 void end_ffmpeg(void);
705
706 static void write_audio_frames()
707 {
708         int finished = 0;
709
710         while (ffmpeg_multiplex_audio && !finished) {
711                 double a_pts = ((double)audio_stream->pts.val 
712                                 * audio_stream->time_base.num 
713                                 / audio_stream->time_base.den);
714                 double v_pts = ((double)video_stream->pts.val 
715                                 * video_stream->time_base.num 
716                                 / video_stream->time_base.den);
717                 
718                 if (a_pts < v_pts) {
719                         write_audio_frame();
720                 } else {
721                         finished = 1;
722                 }
723         }
724 }
725
726 void append_ffmpeg(int frame, int *pixels, int rectx, int recty) 
727 {
728         fprintf(stderr, "Writing frame %i, "
729                 "render width=%d, render height=%d\n", frame,
730                 rectx, recty);
731
732         write_audio_frames();
733         write_video_frame(generate_video_frame((unsigned char*) pixels));
734
735         if (ffmpeg_autosplit) {
736                 if (url_ftell(&outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) {
737                         end_ffmpeg();
738                         ffmpeg_autosplit_count++;
739                         start_ffmpeg_impl(ffmpeg_renderdata,
740                                           rectx, recty);
741                 }
742         }
743 }
744
745
746 void end_ffmpeg(void)
747 {
748         int i;
749         
750         fprintf(stderr, "Closing ffmpeg...\n");
751
752         write_audio_frames();
753
754         if (outfile) {
755                 av_write_trailer(outfile);
756         }
757         
758         /* Close the video codec */
759
760         if (video_stream && get_codec_from_stream(video_stream)) {
761                 avcodec_close(get_codec_from_stream(video_stream));
762                 video_stream = 0;
763         }
764
765         
766         /* Close the output file */
767         if (outfile) {
768                 for (i = 0; i < outfile->nb_streams; i++) {
769                         if (&outfile->streams[i]) {
770                                 av_freep(&outfile->streams[i]);
771                         }
772                 }
773         }
774         /* free the temp buffer */
775         if (current_frame) {
776                 delete_picture(current_frame);
777                 current_frame = 0;
778         }
779         if (outfile && outfile->oformat) {
780                 if (!(outfile->oformat->flags & AVFMT_NOFILE)) {
781                         url_fclose(&outfile->pb);
782                 }
783         }
784         if (outfile) {
785                 av_free(outfile);
786                 outfile = 0;
787         }
788         if (video_buffer) {
789                 MEM_freeN(video_buffer);
790                 video_buffer = 0;
791         }
792         if (audio_output_buffer) {
793                 MEM_freeN(audio_output_buffer);
794                 audio_output_buffer = 0;
795         }
796         if (audio_input_buffer) {
797                 MEM_freeN(audio_input_buffer);
798                 audio_input_buffer = 0;
799         }
800 }
801 #endif
802