== FFMPEG ==
[plumiferos.git] / source / blender / blenkernel / intern / writeffmpeg.c
blob0f132918faf27d5f6d17a06fc8e5cfec469e7dbe
1 /*
2 * ffmpeg-write support
4 * Partial Copyright (c) 2006 Peter Schlaile
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.
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.
19 #ifdef WITH_FFMPEG
20 #include <string.h>
21 #include <stdio.h>
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
30 #include <stdlib.h>
32 #include <ffmpeg/avformat.h>
33 #include <ffmpeg/avcodec.h>
34 #include <ffmpeg/rational.h>
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
43 #if defined(WIN32) && (!(defined snprintf))
44 #define snprintf _snprintf
45 #endif
47 #include "BKE_writeffmpeg.h"
49 #include "MEM_guardedalloc.h"
50 #include "BLI_blenlib.h"
52 #include "BKE_bad_level_calls.h"
53 #include "BKE_global.h"
55 #include "IMB_imbuf_types.h"
56 #include "IMB_imbuf.h"
58 #include "BSE_seqaudio.h"
60 #include "DNA_scene_types.h"
61 #include "blendef.h"
63 #ifdef HAVE_CONFIG_H
64 #include <config.h>
65 #endif
67 extern void do_init_ffmpeg();
68 void makeffmpegstring(char* string);
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;
80 static AVFormatContext* outfile = 0;
81 static AVStream* video_stream = 0;
82 static AVStream* audio_stream = 0;
83 static AVFrame* current_frame = 0;
85 static uint8_t* video_buffer = 0;
86 static int video_buffersize = 0;
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;
93 static RenderData *ffmpeg_renderdata = 0;
95 #define FFMPEG_AUTOSPLIT_SIZE 2000000000
97 /* Delete a picture buffer */
99 static void delete_picture(AVFrame* f)
101 if (f) {
102 if (f->data[0]) MEM_freeN(f->data[0]);
103 av_free(f);
107 #ifdef FFMPEG_CODEC_IS_POINTER
108 static AVCodecContext* get_codec_from_stream(AVStream* stream)
110 return stream->codec;
112 #else
113 static AVCodecContext* get_codec_from_stream(AVStream* stream)
115 return &stream->codec;
117 #endif
119 static int write_audio_frame(void)
121 AVCodecContext* c = NULL;
122 AVPacket pkt;
124 c = get_codec_from_stream(audio_stream);
126 audiostream_fill(audio_input_buffer,
127 audio_input_frame_size
128 * sizeof(short) * c->channels);
130 av_init_packet(&pkt);
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);
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;
150 return 0;
153 /* Allocate a temporary frame */
154 static AVFrame* alloc_picture(int pix_fmt, int width, int height)
156 AVFrame* f;
157 uint8_t* buf;
158 int size;
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;
170 avpicture_fill((AVPicture*)f, buf, pix_fmt, width, height);
171 return f;
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)
178 switch(format) {
179 case FFMPEG_DV: {
180 static const char * rv[] = { ".dv", NULL };
181 return rv;
183 case FFMPEG_MPEG1: {
184 static const char * rv[] = { ".mpg", ".mpeg", NULL };
185 return rv;
187 case FFMPEG_MPEG2: {
188 static const char * rv[] = { ".dvd", ".vob", ".mpg", ".mpeg",
189 NULL };
190 return rv;
192 case FFMPEG_MPEG4: {
193 static const char * rv[] = { ".mp4", ".mpg", ".mpeg", NULL };
194 return rv;
196 case FFMPEG_AVI: {
197 static const char * rv[] = { ".avi", NULL };
198 return rv;
200 case FFMPEG_MOV: {
201 static const char * rv[] = { ".mov", NULL };
202 return rv;
204 case FFMPEG_H264: {
205 /* FIXME: avi for now... */
206 static const char * rv[] = { ".avi", NULL };
207 return rv;
210 case FFMPEG_XVID: {
211 /* FIXME: avi for now... */
212 static const char * rv[] = { ".avi", NULL };
213 return rv;
215 default:
216 return NULL;
220 /* Write a frame to the output file */
221 static void write_video_frame(AVFrame* frame)
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
230 outsize = avcodec_encode_video(c, video_buffer, video_buffersize,
231 frame);
232 if (outsize != 0) {
233 AVPacket packet;
234 av_init_packet(&packet);
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");
257 /* read and encode a frame of audio from the buffer */
258 static AVFrame* generate_video_frame(uint8_t* pixels)
260 uint8_t* rendered_frame;
262 AVCodecContext* c = get_codec_from_stream(video_stream);
263 int width = c->width;
264 int height = c->height;
265 AVFrame* rgb_frame;
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;
274 } else {
275 rgb_frame = current_frame;
278 rendered_frame = pixels;
280 /* Do RGBA-conversion and flipping in one step depending
281 on CPU-Endianess */
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];
296 target += 4;
297 src += 4;
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];
313 target += 4;
314 src += 4;
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);
324 return current_frame;
327 /* prepare a video stream for the output file */
329 static AVStream* alloc_video_stream(int codec_id, AVFormatContext* of,
330 int rectx, int recty)
332 AVStream* st;
333 AVCodecContext* c;
334 AVCodec* codec;
335 st = av_new_stream(of, 0);
336 if (!st) return NULL;
338 /* Set up the codec context */
340 c = get_codec_from_stream(st);
341 c->codec_id = codec_id;
342 c->codec_type = CODEC_TYPE_VIDEO;
345 /* Get some values from the current render settings */
347 c->width = rectx;
348 c->height = recty;
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 if ((double) ((int) G.scene->r.frs_sec_base) ==
356 G.scene->r.frs_sec_base) {
357 c->time_base.den = G.scene->r.frs_sec;
358 c->time_base.num = (int) G.scene->r.frs_sec_base;
359 } else {
360 c->time_base.den = G.scene->r.frs_sec * 100000;
361 c->time_base.num = ((double) G.scene->r.frs_sec_base) * 100000;
363 #else
364 /* FIXME: Really bad hack (tm) for NTSC support */
365 if (ffmpeg_type == FFMPEG_DV && G.scene->r.frs_sec != 25) {
366 c->frame_rate = 2997;
367 c->frame_rate_base = 100;
368 } else if ((double) ((int) G.scene->r.frs_sec_base) ==
369 G.scene->r.frs_sec_base) {
370 c->frame_rate = G.scene->r.frs_sec;
371 c->frame_rate_base = G.scene->r.frs_sec_base;
372 } else {
373 c->frame_rate = G.scene->r.frs_sec * 100000;
374 c->frame_rate_base = ((double) G.scene->r.frs_sec_base)*100000;
376 #endif
378 c->gop_size = ffmpeg_gop_size;
379 c->bit_rate = ffmpeg_video_bitrate*1000;
380 c->rc_max_rate = G.scene->r.ffcodecdata.rc_max_rate*1000;
381 c->rc_min_rate = G.scene->r.ffcodecdata.rc_min_rate*1000;
382 c->rc_buffer_size = G.scene->r.ffcodecdata.rc_buffer_size * 1024;
383 c->rc_initial_buffer_occupancy
384 = G.scene->r.ffcodecdata.rc_buffer_size*3/4;
385 c->rc_buffer_aggressivity = 1.0;
386 c->me_method = ME_EPZS;
388 codec = avcodec_find_encoder(c->codec_id);
389 if (!codec) return NULL;
391 /* Be sure to use the correct pixel format(e.g. RGB, YUV) */
393 if (codec->pix_fmts) {
394 c->pix_fmt = codec->pix_fmts[0];
395 } else {
396 /* makes HuffYUV happy ... */
397 c->pix_fmt = PIX_FMT_YUV422P;
400 if (codec_id == CODEC_ID_XVID) {
401 /* arghhhh ... */
402 c->pix_fmt = PIX_FMT_YUV420P;
405 if (!strcmp(of->oformat->name, "mp4") ||
406 !strcmp(of->oformat->name, "mov") ||
407 !strcmp(of->oformat->name, "3gp")) {
408 fprintf(stderr, "Using global header\n");
409 c->flags |= CODEC_FLAG_GLOBAL_HEADER;
412 /* Determine whether we are encoding interlaced material or not */
413 if (G.scene->r.mode & (1 << 6)) {
414 fprintf(stderr, "Encoding interlaced video\n");
415 c->flags |= CODEC_FLAG_INTERLACED_DCT;
416 c->flags |= CODEC_FLAG_INTERLACED_ME;
418 c->sample_aspect_ratio.num = G.scene->r.xasp;
419 c->sample_aspect_ratio.den = G.scene->r.yasp;
421 if (avcodec_open(c, codec) < 0) {
422 error("Couldn't initialize codec");
423 return NULL;
426 video_buffersize = 2000000;
427 video_buffer = (uint8_t*)MEM_mallocN(video_buffersize,
428 "FFMPEG video buffer");
430 current_frame = alloc_picture(c->pix_fmt, c->width, c->height);
431 return st;
434 /* Prepare an audio stream for the output file */
436 static AVStream* alloc_audio_stream(int codec_id, AVFormatContext* of)
438 AVStream* st;
439 AVCodecContext* c;
440 AVCodec* codec;
442 st = av_new_stream(of, 1);
443 if (!st) return NULL;
445 c = get_codec_from_stream(st);
446 c->codec_id = codec_id;
447 c->codec_type = CODEC_TYPE_AUDIO;
449 c->sample_rate = G.scene->audio.mixrate;
450 c->bit_rate = ffmpeg_audio_bitrate*1000;
451 c->channels = 2;
452 codec = avcodec_find_encoder(c->codec_id);
453 if (!codec) {
454 error("Couldn't find a valid audio codec");
455 return NULL;
457 if (avcodec_open(c, codec) < 0) {
458 error("Couldn't initialize audio codec");
459 return NULL;
462 /* FIXME: Should be user configurable */
463 if (ffmpeg_type == FFMPEG_DV) {
464 /* this is a hack around the poor ffmpeg dv multiplexer. */
465 /* only fixes PAL for now
466 (NTSC is a lot more complicated here...)! */
467 audio_outbuf_size = 7680;
468 } else {
469 audio_outbuf_size = 10000;
471 audio_output_buffer = (uint8_t*)MEM_mallocN(
472 audio_outbuf_size, "FFMPEG audio encoder input buffer");
474 /* ugly hack for PCM codecs */
476 if (c->frame_size <= 1) {
477 audio_input_frame_size = audio_outbuf_size / c->channels;
478 switch(c->codec_id) {
479 case CODEC_ID_PCM_S16LE:
480 case CODEC_ID_PCM_S16BE:
481 case CODEC_ID_PCM_U16LE:
482 case CODEC_ID_PCM_U16BE:
483 audio_input_frame_size >>= 1;
484 break;
485 default:
486 break;
488 } else {
489 audio_input_frame_size = c->frame_size;
492 audio_input_buffer = (uint8_t*)MEM_mallocN(
493 audio_input_frame_size * sizeof(short) * c->channels,
494 "FFMPEG audio encoder output buffer");
496 return st;
498 /* essential functions -- start, append, end */
500 void start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty)
502 /* Handle to the output file */
503 AVFormatContext* of;
504 AVOutputFormat* fmt;
505 char name[256];
506 const char ** exts;
508 ffmpeg_type = rd->ffcodecdata.type;
509 ffmpeg_codec = rd->ffcodecdata.codec;
510 ffmpeg_audio_codec = rd->ffcodecdata.audio_codec;
511 ffmpeg_video_bitrate = rd->ffcodecdata.video_bitrate;
512 ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate;
513 ffmpeg_gop_size = rd->ffcodecdata.gop_size;
514 ffmpeg_multiplex_audio = rd->ffcodecdata.flags
515 & FFMPEG_MULTIPLEX_AUDIO;
516 ffmpeg_autosplit = rd->ffcodecdata.flags
517 & FFMPEG_AUTOSPLIT_OUTPUT;
519 do_init_ffmpeg();
521 /* Determine the correct filename */
522 makeffmpegstring(name);
523 fprintf(stderr, "Starting output to %s(ffmpeg)...\n"
524 " Using type=%d, codec=%d, audio_codec=%d,\n"
525 " video_bitrate=%d, audio_bitrate=%d,\n"
526 " gop_size=%d, multiplex=%d, autosplit=%d\n"
527 " render width=%d, render height=%d\n",
528 name, ffmpeg_type, ffmpeg_codec, ffmpeg_audio_codec,
529 ffmpeg_video_bitrate, ffmpeg_audio_bitrate,
530 ffmpeg_gop_size, ffmpeg_multiplex_audio,
531 ffmpeg_autosplit, rectx, recty);
533 exts = get_file_extensions(ffmpeg_type);
534 if (!exts) {
535 G.afbreek = 1; /* Abort render */
536 error("No valid formats found");
537 return;
539 fmt = guess_format(NULL, exts[0], NULL);
540 if (!fmt) {
541 G.afbreek = 1; /* Abort render */
542 error("No valid formats found");
543 return;
546 of = av_alloc_format_context();
547 if (!of) {
548 G.afbreek = 1;
549 error("Error opening output file");
550 return;
553 of->oformat = fmt;
554 of->packet_size= G.scene->r.ffcodecdata.mux_packet_size;
555 if (ffmpeg_multiplex_audio) {
556 of->mux_rate = G.scene->r.ffcodecdata.mux_rate;
557 } else {
558 of->mux_rate = 0;
561 of->preload = (int)(0.5*AV_TIME_BASE);
562 of->max_delay = (int)(0.7*AV_TIME_BASE);
564 snprintf(of->filename, sizeof(of->filename), "%s", name);
565 /* set the codec to the user's selection */
566 switch(ffmpeg_type) {
567 case FFMPEG_AVI:
568 case FFMPEG_MOV:
569 fmt->video_codec = ffmpeg_codec;
570 break;
571 case FFMPEG_DV:
572 fmt->video_codec = CODEC_ID_DVVIDEO;
573 break;
574 case FFMPEG_MPEG1:
575 fmt->video_codec = CODEC_ID_MPEG1VIDEO;
576 break;
577 case FFMPEG_MPEG2:
578 fmt->video_codec = CODEC_ID_MPEG2VIDEO;
579 break;
580 case FFMPEG_H264:
581 fmt->video_codec = CODEC_ID_H264;
582 break;
583 case FFMPEG_XVID:
584 fmt->video_codec = CODEC_ID_XVID;
585 break;
586 case FFMPEG_MPEG4:
587 default:
588 fmt->video_codec = CODEC_ID_MPEG4;
589 break;
591 if (fmt->video_codec == CODEC_ID_DVVIDEO) {
592 if (rectx != 720) {
593 G.afbreek = 1;
594 error("Render width has to be 720 pixels for DV!");
595 return;
597 if (G.scene->r.frs_sec != 25 && recty != 480) {
598 G.afbreek = 1;
599 error("Render height has to be 480 pixels "
600 "for DV-NTSC!");
601 return;
604 if (G.scene->r.frs_sec == 25 && recty != 576) {
605 G.afbreek = 1;
606 error("Render height has to be 576 pixels "
607 "for DV-PAL!");
608 return;
612 fmt->audio_codec = ffmpeg_audio_codec;
614 if (ffmpeg_type == FFMPEG_DV) {
615 fmt->audio_codec = CODEC_ID_PCM_S16LE;
616 if (ffmpeg_multiplex_audio
617 && G.scene->audio.mixrate != 48000) {
618 G.afbreek = 1;
619 error("FFMPEG only supports 48khz / stereo "
620 "audio for DV!");
621 return;
625 video_stream = alloc_video_stream(fmt->video_codec, of, rectx, recty);
626 if (!video_stream) {
627 G.afbreek = 1;
628 error("Error initializing video stream");
629 return;
632 if (ffmpeg_multiplex_audio) {
633 audio_stream = alloc_audio_stream(fmt->audio_codec, of);
634 if (!audio_stream) {
635 G.afbreek = 1;
636 error("Error initializing audio stream");
637 return;
639 audiostream_play(SFRA, 0, 1);
641 if (av_set_parameters(of, NULL) < 0) {
642 G.afbreek = 1;
643 error("Error setting output parameters");
644 return;
646 if (!(fmt->flags & AVFMT_NOFILE)) {
647 if (url_fopen(&of->pb, name, URL_WRONLY) < 0) {
648 G.afbreek = 1;
649 error("Could not open file for writing");
650 return;
654 av_write_header(of);
655 outfile = of;
656 dump_format(of, 0, name, 1);
659 /* **********************************************************************
660 * public interface
661 ********************************************************************** */
663 /* Get the output filename-- similar to the other output formats */
664 void makeffmpegstring(char* string) {
666 char txt[FILE_MAXDIR+FILE_MAXFILE];
667 char autosplit[20];
669 const char ** exts = get_file_extensions(G.scene->r.ffcodecdata.type);
670 const char ** fe = exts;
672 if (!string || !exts) return;
674 strcpy(string, G.scene->r.pic);
675 BLI_convertstringcode(string, G.sce, G.scene->r.cfra);
677 BLI_make_existing_file(string);
679 autosplit[0] = 0;
681 if ((G.scene->r.ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT) != 0) {
682 sprintf(autosplit, "_%03d", ffmpeg_autosplit_count);
685 while (*fe) {
686 if (BLI_strcasecmp(string + strlen(string) - strlen(*fe),
687 *fe) == 0) {
688 break;
690 fe++;
693 if (!*fe) {
694 strcat(string, autosplit);
695 sprintf(txt, "%04d_%04d%s", (G.scene->r.sfra),
696 (G.scene->r.efra), *exts);
697 strcat(string, txt);
698 } else {
699 *(string + strlen(string) - strlen(*fe)) = 0;
700 strcat(string, autosplit);
701 strcat(string, *fe);
706 void start_ffmpeg(RenderData *rd, int rectx, int recty)
708 ffmpeg_autosplit_count = 0;
710 ffmpeg_renderdata = rd;
712 start_ffmpeg_impl(rd, rectx, recty);
715 void end_ffmpeg(void);
717 static void write_audio_frames()
719 int finished = 0;
721 while (ffmpeg_multiplex_audio && !finished) {
722 double a_pts = ((double)audio_stream->pts.val
723 * audio_stream->time_base.num
724 / audio_stream->time_base.den);
725 double v_pts = ((double)video_stream->pts.val
726 * video_stream->time_base.num
727 / video_stream->time_base.den);
729 if (a_pts < v_pts) {
730 write_audio_frame();
731 } else {
732 finished = 1;
737 void append_ffmpeg(int frame, int *pixels, int rectx, int recty)
739 fprintf(stderr, "Writing frame %i, "
740 "render width=%d, render height=%d\n", frame,
741 rectx, recty);
743 write_audio_frames();
744 write_video_frame(generate_video_frame((unsigned char*) pixels));
746 if (ffmpeg_autosplit) {
747 if (url_ftell(&outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) {
748 end_ffmpeg();
749 ffmpeg_autosplit_count++;
750 start_ffmpeg_impl(ffmpeg_renderdata,
751 rectx, recty);
757 void end_ffmpeg(void)
759 int i;
761 fprintf(stderr, "Closing ffmpeg...\n");
763 write_audio_frames();
765 if (outfile) {
766 av_write_trailer(outfile);
769 /* Close the video codec */
771 if (video_stream && get_codec_from_stream(video_stream)) {
772 avcodec_close(get_codec_from_stream(video_stream));
773 video_stream = 0;
777 /* Close the output file */
778 if (outfile) {
779 for (i = 0; i < outfile->nb_streams; i++) {
780 if (&outfile->streams[i]) {
781 av_freep(&outfile->streams[i]);
785 /* free the temp buffer */
786 if (current_frame) {
787 delete_picture(current_frame);
788 current_frame = 0;
790 if (outfile && outfile->oformat) {
791 if (!(outfile->oformat->flags & AVFMT_NOFILE)) {
792 url_fclose(&outfile->pb);
795 if (outfile) {
796 av_free(outfile);
797 outfile = 0;
799 if (video_buffer) {
800 MEM_freeN(video_buffer);
801 video_buffer = 0;
803 if (audio_output_buffer) {
804 MEM_freeN(audio_output_buffer);
805 audio_output_buffer = 0;
807 if (audio_input_buffer) {
808 MEM_freeN(audio_input_buffer);
809 audio_input_buffer = 0;
812 #endif