| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * ffmpeg-write support | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Partial Copyright (c) 2006 Peter Schlaile | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  * it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |  * the Free Software Foundation; either version 2 of the License, or | 
					
						
							|  |  |  |  * (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef WITH_FFMPEG
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-18 02:48:18 +00:00
										 |  |  | #if defined(_WIN32) && defined(_DEBUG) && !defined(__MINGW32__) && !defined(__CYGWIN__)
 | 
					
						
							| 
									
										
										
										
											2006-12-06 09:48:27 +00:00
										 |  |  | /* This does not seem necessary or present on MSVC 8, but may be needed in earlier versions? */ | 
					
						
							|  |  |  | #if _MSC_VER < 1400
 | 
					
						
							| 
									
										
										
										
											2006-03-12 14:11:23 +00:00
										 |  |  | #include <stdint.h>
 | 
					
						
							| 
									
										
										
										
											2006-11-18 02:48:18 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2006-12-06 09:48:27 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2006-11-18 02:48:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | #include <stdlib.h>
 | 
					
						
							| 
									
										
										
										
											2006-11-18 02:48:18 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-20 15:06:46 +00:00
										 |  |  | #include <libavformat/avformat.h>
 | 
					
						
							|  |  |  | #include <libavcodec/avcodec.h>
 | 
					
						
							|  |  |  | #include <libavutil/rational.h>
 | 
					
						
							|  |  |  | #include <libswscale/swscale.h>
 | 
					
						
							|  |  |  | #include <libavcodec/opt.h>
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if LIBAVFORMAT_VERSION_INT < (49 << 16)
 | 
					
						
							|  |  |  | #define FFMPEG_OLD_FRAME_RATE 1
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #define FFMPEG_CODEC_IS_POINTER 1
 | 
					
						
							| 
									
										
										
										
											2006-03-07 20:01:12 +00:00
										 |  |  | #define FFMPEG_CODEC_TIME_BASE  1
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-06 22:45:46 +00:00
										 |  |  | #if LIBAVFORMAT_VERSION_INT >= (52 << 16)
 | 
					
						
							|  |  |  | #define OUTFILE_PB (outfile->pb)
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #define OUTFILE_PB (&outfile->pb)
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-18 02:48:18 +00:00
										 |  |  | #if defined(WIN32) && (!(defined snprintf))
 | 
					
						
							|  |  |  | #define snprintf _snprintf
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | #include "MEM_guardedalloc.h"
 | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "DNA_scene_types.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | #include "BLI_blenlib.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | #include "AUD_C-API.h" /* must be before BKE_sound.h for define */
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | #include "BKE_global.h"
 | 
					
						
							| 
									
										
										
										
											2008-05-11 20:40:55 +00:00
										 |  |  | #include "BKE_idprop.h"
 | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | #include "BKE_main.h"
 | 
					
						
							|  |  |  | #include "BKE_report.h"
 | 
					
						
							|  |  |  | #include "BKE_sound.h"
 | 
					
						
							|  |  |  | #include "BKE_writeffmpeg.h"
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "IMB_imbuf_types.h"
 | 
					
						
							|  |  |  | #include "IMB_imbuf.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef HAVE_CONFIG_H
 | 
					
						
							|  |  |  | #include <config.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extern void do_init_ffmpeg(); | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | static void makeffmpegstring(RenderData* rd, char* string); | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static int ffmpeg_type = 0; | 
					
						
							|  |  |  | static int ffmpeg_codec = CODEC_ID_MPEG4; | 
					
						
							|  |  |  | static int ffmpeg_audio_codec = CODEC_ID_MP2; | 
					
						
							|  |  |  | static int ffmpeg_video_bitrate = 1150; | 
					
						
							|  |  |  | static int ffmpeg_audio_bitrate = 128; | 
					
						
							|  |  |  | static int ffmpeg_gop_size = 12; | 
					
						
							|  |  |  | static int ffmpeg_multiplex_audio = 1; | 
					
						
							|  |  |  | static int ffmpeg_autosplit = 0; | 
					
						
							|  |  |  | static int ffmpeg_autosplit_count = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-04 18:05:47 +00:00
										 |  |  | static AVFormatContext* outfile = 0; | 
					
						
							|  |  |  | static AVStream* video_stream = 0; | 
					
						
							|  |  |  | static AVStream* audio_stream = 0; | 
					
						
							|  |  |  | static AVFrame* current_frame = 0; | 
					
						
							| 
									
										
										
										
											2007-09-23 14:05:22 +00:00
										 |  |  | static struct SwsContext *img_convert_ctx = 0; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static uint8_t* video_buffer = 0; | 
					
						
							|  |  |  | static int video_buffersize = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static uint8_t* audio_input_buffer = 0; | 
					
						
							|  |  |  | static int audio_input_frame_size = 0; | 
					
						
							|  |  |  | static uint8_t* audio_output_buffer = 0; | 
					
						
							|  |  |  | static int audio_outbuf_size = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-09 21:16:39 +00:00
										 |  |  | static AUD_Device* audio_mixdown_device = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | #define FFMPEG_AUTOSPLIT_SIZE 2000000000
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Delete a picture buffer */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-09 13:05:09 +00:00
										 |  |  | static void delete_picture(AVFrame* f) | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	if (f) { | 
					
						
							|  |  |  | 		if (f->data[0]) MEM_freeN(f->data[0]); | 
					
						
							|  |  |  | 		av_free(f); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-07 20:01:12 +00:00
										 |  |  | #ifdef FFMPEG_CODEC_IS_POINTER
 | 
					
						
							|  |  |  | static AVCodecContext* get_codec_from_stream(AVStream* stream) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return stream->codec; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | static AVCodecContext* get_codec_from_stream(AVStream* stream) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return &stream->codec; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-09 13:05:09 +00:00
										 |  |  | static int write_audio_frame(void)  | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	AVCodecContext* c = NULL; | 
					
						
							|  |  |  | 	AVPacket pkt; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-07 20:01:12 +00:00
										 |  |  | 	c = get_codec_from_stream(audio_stream); | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-09 21:16:39 +00:00
										 |  |  | 	if(audio_mixdown_device) | 
					
						
							|  |  |  | 		AUD_readDevice(audio_mixdown_device, audio_input_buffer, audio_input_frame_size); | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	av_init_packet(&pkt); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pkt.size = avcodec_encode_audio(c, audio_output_buffer, | 
					
						
							|  |  |  | 					audio_outbuf_size,  | 
					
						
							|  |  |  | 					(short*) audio_input_buffer); | 
					
						
							|  |  |  | 	pkt.data = audio_output_buffer; | 
					
						
							| 
									
										
										
										
											2006-03-07 20:01:12 +00:00
										 |  |  | #ifdef FFMPEG_CODEC_TIME_BASE
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	pkt.pts = av_rescale_q(c->coded_frame->pts,  | 
					
						
							|  |  |  | 			       c->time_base, audio_stream->time_base); | 
					
						
							| 
									
										
										
										
											2006-03-07 20:01:12 +00:00
										 |  |  | #else
 | 
					
						
							|  |  |  | 	pkt.pts = c->coded_frame->pts; | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2009-09-17 14:46:22 +00:00
										 |  |  | 	fprintf(stderr, "Audio Frame PTS: %d\n", (int)pkt.pts); | 
					
						
							| 
									
										
										
										
											2006-07-09 13:05:09 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	pkt.stream_index = audio_stream->index; | 
					
						
							|  |  |  | 	pkt.flags |= PKT_FLAG_KEY; | 
					
						
							| 
									
										
										
										
											2007-01-28 18:45:53 +00:00
										 |  |  | 	if (av_interleaved_write_frame(outfile, &pkt) != 0) { | 
					
						
							| 
									
										
										
										
											2008-01-02 12:35:30 +00:00
										 |  |  | 		//XXX error("Error writing audio packet");
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Allocate a temporary frame */ | 
					
						
							| 
									
										
										
										
											2006-07-09 13:05:09 +00:00
										 |  |  | static AVFrame* alloc_picture(int pix_fmt, int width, int height)  | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	AVFrame* f; | 
					
						
							|  |  |  | 	uint8_t* buf; | 
					
						
							|  |  |  | 	int size; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	/* allocate space for the struct */ | 
					
						
							|  |  |  | 	f = avcodec_alloc_frame(); | 
					
						
							|  |  |  | 	if (!f) return NULL; | 
					
						
							|  |  |  | 	size = avpicture_get_size(pix_fmt, width, height); | 
					
						
							|  |  |  | 	/* allocate the actual picture buffer */ | 
					
						
							|  |  |  | 	buf = MEM_mallocN(size, "AVFrame buffer"); | 
					
						
							|  |  |  | 	if (!buf) { | 
					
						
							|  |  |  | 		free(f); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	avpicture_fill((AVPicture*)f, buf, pix_fmt, width, height); | 
					
						
							|  |  |  | 	return f; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-09 13:05:09 +00:00
										 |  |  | /* Get the correct file extensions for the requested format,
 | 
					
						
							|  |  |  |    first is always desired guess_format parameter */ | 
					
						
							|  |  |  | static const char** get_file_extensions(int format)  | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	switch(format) { | 
					
						
							| 
									
										
										
										
											2006-07-09 13:05:09 +00:00
										 |  |  | 	case FFMPEG_DV: { | 
					
						
							|  |  |  | 		static const char * rv[] = { ".dv", NULL }; | 
					
						
							|  |  |  | 		return rv; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-07-09 13:05:09 +00:00
										 |  |  | 	case FFMPEG_MPEG1: { | 
					
						
							|  |  |  | 		static const char * rv[] = { ".mpg", ".mpeg", NULL }; | 
					
						
							|  |  |  | 		return rv; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	case FFMPEG_MPEG2: { | 
					
						
							|  |  |  | 		static const char * rv[] = { ".dvd", ".vob", ".mpg", ".mpeg", | 
					
						
							|  |  |  | 					     NULL }; | 
					
						
							|  |  |  | 		return rv; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	case FFMPEG_MPEG4: { | 
					
						
							|  |  |  | 		static const char * rv[] = { ".mp4", ".mpg", ".mpeg", NULL }; | 
					
						
							|  |  |  | 		return rv; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	case FFMPEG_AVI: { | 
					
						
							|  |  |  | 		static const char * rv[] = { ".avi", NULL }; | 
					
						
							|  |  |  | 		return rv; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	case FFMPEG_MOV: { | 
					
						
							|  |  |  | 		static const char * rv[] = { ".mov", NULL }; | 
					
						
							|  |  |  | 		return rv; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	case FFMPEG_H264: { | 
					
						
							|  |  |  | 		/* FIXME: avi for now... */ | 
					
						
							|  |  |  | 		static const char * rv[] = { ".avi", NULL }; | 
					
						
							|  |  |  | 		return rv; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-09 13:05:09 +00:00
										 |  |  | 	case FFMPEG_XVID: { | 
					
						
							|  |  |  | 		/* FIXME: avi for now... */ | 
					
						
							|  |  |  | 		static const char * rv[] = { ".avi", NULL }; | 
					
						
							|  |  |  | 		return rv; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-04-13 18:50:16 +00:00
										 |  |  | 	case FFMPEG_FLV: { | 
					
						
							|  |  |  | 		static const char * rv[] = { ".flv", NULL }; | 
					
						
							| 
									
										
										
										
											2008-05-12 09:01:15 +00:00
										 |  |  | 		return rv; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	case FFMPEG_MKV: { | 
					
						
							|  |  |  | 		static const char * rv[] = { ".mkv", NULL }; | 
					
						
							| 
									
										
										
										
											2008-04-13 18:50:16 +00:00
										 |  |  | 		return rv; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-10-05 17:31:33 +00:00
										 |  |  | 	case FFMPEG_OGG: { | 
					
						
							|  |  |  | 		static const char * rv[] = { ".ogg", ".ogv", NULL }; | 
					
						
							|  |  |  | 		return rv; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-07-09 13:05:09 +00:00
										 |  |  | 	default: | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Write a frame to the output file */ | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | static int write_video_frame(RenderData *rd, AVFrame* frame, ReportList *reports) | 
					
						
							| 
									
										
										
										
											2006-07-09 13:05:09 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	int outsize = 0; | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 	int ret, success= 1; | 
					
						
							| 
									
										
										
										
											2006-03-07 20:01:12 +00:00
										 |  |  | 	AVCodecContext* c = get_codec_from_stream(video_stream); | 
					
						
							| 
									
										
										
										
											2006-06-09 19:48:50 +00:00
										 |  |  | #ifdef FFMPEG_CODEC_TIME_BASE
 | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 	frame->pts = rd->cfra - rd->sfra; | 
					
						
							| 
									
										
										
										
											2006-06-09 19:48:50 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2009-06-09 10:30:16 +00:00
										 |  |  | 	if (rd->mode & R_FIELDS) { | 
					
						
							|  |  |  | 		frame->top_field_first = ((rd->mode & R_ODDFIELD) != 0); | 
					
						
							| 
									
										
										
										
											2009-06-08 20:08:19 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	outsize = avcodec_encode_video(c, video_buffer, video_buffersize,  | 
					
						
							|  |  |  | 				       frame); | 
					
						
							|  |  |  | 	if (outsize != 0) { | 
					
						
							|  |  |  | 		AVPacket packet; | 
					
						
							|  |  |  | 		av_init_packet(&packet); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-10-05 17:31:33 +00:00
										 |  |  | 		if (c->coded_frame->pts != AV_NOPTS_VALUE) { | 
					
						
							| 
									
										
										
										
											2006-03-07 20:01:12 +00:00
										 |  |  | #ifdef FFMPEG_CODEC_TIME_BASE
 | 
					
						
							| 
									
										
										
										
											2008-10-05 17:31:33 +00:00
										 |  |  | 			packet.pts = av_rescale_q(c->coded_frame->pts, | 
					
						
							|  |  |  | 						  c->time_base, | 
					
						
							|  |  |  | 						  video_stream->time_base); | 
					
						
							| 
									
										
										
										
											2006-03-07 20:01:12 +00:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2008-10-05 17:31:33 +00:00
										 |  |  | 			packet.pts = c->coded_frame->pts; | 
					
						
							| 
									
										
										
										
											2006-03-07 20:01:12 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2009-09-17 14:46:22 +00:00
										 |  |  | 			fprintf(stderr, "Video Frame PTS: %d\n", (int)packet.pts); | 
					
						
							| 
									
										
										
										
											2008-10-05 17:31:33 +00:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			fprintf(stderr, "Video Frame PTS: not set\n"); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 		if (c->coded_frame->key_frame) | 
					
						
							|  |  |  | 			packet.flags |= PKT_FLAG_KEY; | 
					
						
							|  |  |  | 		packet.stream_index = video_stream->index; | 
					
						
							|  |  |  | 		packet.data = video_buffer; | 
					
						
							|  |  |  | 		packet.size = outsize; | 
					
						
							| 
									
										
										
										
											2007-01-28 18:45:53 +00:00
										 |  |  | 		ret = av_interleaved_write_frame(outfile, &packet); | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	} else ret = 0; | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	if (ret != 0) { | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 		success= 0; | 
					
						
							|  |  |  | 		BKE_report(reports, RPT_ERROR, "Error writing frame."); | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return success; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* read and encode a frame of audio from the buffer */ | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | static AVFrame* generate_video_frame(uint8_t* pixels, ReportList *reports)  | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	uint8_t* rendered_frame; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-07 20:01:12 +00:00
										 |  |  | 	AVCodecContext* c = get_codec_from_stream(video_stream); | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	int width = c->width; | 
					
						
							|  |  |  | 	int height = c->height; | 
					
						
							|  |  |  | 	AVFrame* rgb_frame; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-20 15:06:46 +00:00
										 |  |  | 	if (c->pix_fmt != PIX_FMT_BGR32) { | 
					
						
							|  |  |  | 		rgb_frame = alloc_picture(PIX_FMT_BGR32, width, height); | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 		if (!rgb_frame) { | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 			BKE_report(reports, RPT_ERROR, "Couldn't allocate temporary frame."); | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 			return NULL; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		rgb_frame = current_frame; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rendered_frame = pixels; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Do RGBA-conversion and flipping in one step depending
 | 
					
						
							|  |  |  | 	   on CPU-Endianess */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-19 19:11:02 +00:00
										 |  |  | 	if (ENDIAN_ORDER == L_ENDIAN) { | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 		int y; | 
					
						
							|  |  |  | 		for (y = 0; y < height; y++) { | 
					
						
							|  |  |  | 			uint8_t* target = rgb_frame->data[0] | 
					
						
							|  |  |  | 				+ width * 4 * (height - y - 1); | 
					
						
							|  |  |  | 			uint8_t* src = rendered_frame + width * 4 * y; | 
					
						
							|  |  |  | 			uint8_t* end = src + width * 4; | 
					
						
							|  |  |  | 			while (src != end) { | 
					
						
							|  |  |  | 				target[3] = src[3]; | 
					
						
							| 
									
										
										
										
											2009-04-20 15:06:46 +00:00
										 |  |  | 				target[2] = src[2]; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 				target[1] = src[1]; | 
					
						
							| 
									
										
										
										
											2009-04-20 15:06:46 +00:00
										 |  |  | 				target[0] = src[0]; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				target += 4; | 
					
						
							|  |  |  | 				src += 4; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		int y; | 
					
						
							|  |  |  | 		for (y = 0; y < height; y++) { | 
					
						
							|  |  |  | 			uint8_t* target = rgb_frame->data[0] | 
					
						
							|  |  |  | 				+ width * 4 * (height - y - 1); | 
					
						
							|  |  |  | 			uint8_t* src = rendered_frame + width * 4 * y; | 
					
						
							|  |  |  | 			uint8_t* end = src + width * 4; | 
					
						
							|  |  |  | 			while (src != end) { | 
					
						
							| 
									
										
										
										
											2009-04-20 15:06:46 +00:00
										 |  |  | 				target[3] = src[0]; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 				target[2] = src[1]; | 
					
						
							| 
									
										
										
										
											2009-04-20 15:06:46 +00:00
										 |  |  | 				target[1] = src[2]; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 				target[0] = src[3]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				target += 4; | 
					
						
							|  |  |  | 				src += 4; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-20 15:06:46 +00:00
										 |  |  | 	if (c->pix_fmt != PIX_FMT_BGR32) { | 
					
						
							| 
									
										
										
										
											2007-09-23 14:05:22 +00:00
										 |  |  | 		sws_scale(img_convert_ctx, rgb_frame->data, | 
					
						
							|  |  |  | 			  rgb_frame->linesize, 0, c->height,  | 
					
						
							|  |  |  | 			  current_frame->data, current_frame->linesize); | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 		delete_picture(rgb_frame); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return current_frame; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-11 20:40:55 +00:00
										 |  |  | static void set_ffmpeg_property_option(AVCodecContext* c, IDProperty * prop) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char name[128]; | 
					
						
							|  |  |  | 	char * param; | 
					
						
							| 
									
										
										
										
											2008-05-11 22:51:56 +00:00
										 |  |  | 	const AVOption * rv = NULL; | 
					
						
							| 
									
										
										
										
											2008-05-11 20:40:55 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	fprintf(stderr, "FFMPEG expert option: %s: ", prop->name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	strncpy(name, prop->name, 128); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	param = strchr(name, ':'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (param) { | 
					
						
							|  |  |  | 		*param++ = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch(prop->type) { | 
					
						
							|  |  |  | 	case IDP_STRING: | 
					
						
							|  |  |  | 		fprintf(stderr, "%s.\n", IDP_String(prop)); | 
					
						
							|  |  |  | 		rv = av_set_string(c, prop->name, IDP_String(prop)); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case IDP_FLOAT: | 
					
						
							|  |  |  | 		fprintf(stderr, "%g.\n", IDP_Float(prop)); | 
					
						
							|  |  |  | 		rv = av_set_double(c, prop->name, IDP_Float(prop)); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case IDP_INT: | 
					
						
							|  |  |  | 		fprintf(stderr, "%d.\n", IDP_Int(prop)); | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		if (param) { | 
					
						
							|  |  |  | 			if (IDP_Int(prop)) { | 
					
						
							|  |  |  | 				rv = av_set_string(c, name, param); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			rv = av_set_int(c, prop->name, IDP_Int(prop)); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!rv) { | 
					
						
							|  |  |  | 		fprintf(stderr, "ffmpeg-option not supported: %s! Skipping.\n", | 
					
						
							|  |  |  | 			prop->name); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | static void set_ffmpeg_properties(RenderData *rd, AVCodecContext *c, const char * prop_name) | 
					
						
							| 
									
										
										
										
											2008-05-11 20:40:55 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	IDProperty * prop; | 
					
						
							|  |  |  | 	void * iter; | 
					
						
							|  |  |  | 	IDProperty * curr; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 	if (!rd->ffcodecdata.properties) { | 
					
						
							| 
									
										
										
										
											2008-05-11 20:40:55 +00:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	prop = IDP_GetPropertyFromGroup( | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 		rd->ffcodecdata.properties, (char*) prop_name); | 
					
						
							| 
									
										
										
										
											2008-05-11 20:40:55 +00:00
										 |  |  | 	if (!prop) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	iter = IDP_GetGroupIterator(prop); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while ((curr = IDP_GroupIterNext(iter)) != NULL) { | 
					
						
							|  |  |  | 		set_ffmpeg_property_option(c, curr); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | /* prepare a video stream for the output file */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | static AVStream* alloc_video_stream(RenderData *rd, int codec_id, AVFormatContext* of, | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 				    int rectx, int recty)  | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	AVStream* st; | 
					
						
							|  |  |  | 	AVCodecContext* c; | 
					
						
							|  |  |  | 	AVCodec* codec; | 
					
						
							|  |  |  | 	st = av_new_stream(of, 0); | 
					
						
							|  |  |  | 	if (!st) return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Set up the codec context */ | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2006-03-07 20:01:12 +00:00
										 |  |  | 	c = get_codec_from_stream(st); | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	c->codec_id = codec_id; | 
					
						
							|  |  |  | 	c->codec_type = CODEC_TYPE_VIDEO; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Get some values from the current render settings */ | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	c->width = rectx; | 
					
						
							|  |  |  | 	c->height = recty; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-07 20:01:12 +00:00
										 |  |  | #ifdef FFMPEG_CODEC_TIME_BASE
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	/* FIXME: Really bad hack (tm) for NTSC support */ | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 	if (ffmpeg_type == FFMPEG_DV && rd->frs_sec != 25) { | 
					
						
							| 
									
										
										
										
											2006-02-06 19:27:24 +00:00
										 |  |  | 		c->time_base.den = 2997; | 
					
						
							|  |  |  | 		c->time_base.num = 100; | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 	} else if ((double) ((int) rd->frs_sec_base) ==  | 
					
						
							|  |  |  | 		   rd->frs_sec_base) { | 
					
						
							|  |  |  | 		c->time_base.den = rd->frs_sec; | 
					
						
							|  |  |  | 		c->time_base.num = (int) rd->frs_sec_base; | 
					
						
							| 
									
										
											  
											
												== Core ==
This adds fractional FPS support to blender and should finally
make NTSC work correctly.
NTSC has an FPS of 30.0/1.001 which is approximately 29.97 FPS.
Therefore, it is not enough to simply make frs_sec a float, since
you can't represent this accurately enough. 
I added a seperate variable frs_sec_base and FPS is now 
frs_sec / frs_sec_base.
I changed all the places, where frs_sec was used to my best knowledge.
For convenience sake, I added several macros, that should make life
easier in the future:
FRA2TIME(a) : convert frame number to a double precision time in seconds
TIME2FRA(a) : the same in the opposite direction
FPS         : return current FPS as a double precision number 
              (last resort)
This closes bug #6715 
Standard framerates not supported / breaks sync -- 23.967 29.967 etc.
https://projects.blender.org/tracker/?func=detail&aid=6715&group_id=9&atid=125
Please give this heavy testing with NTSC files, quicktime in/export
and the python interface.
Errors are most probably only spotted on longer timelines, so that is
also important.
The patch was tested by Troy Sobotka and me, so it most probably should
work out of the box, but wider testing is important, since errors are
very subtle.
Enjoy!
											
										 
											2007-10-21 15:42:08 +00:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 		c->time_base.den = rd->frs_sec * 100000; | 
					
						
							|  |  |  | 		c->time_base.num = ((double) rd->frs_sec_base) * 100000; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-03-07 20:01:12 +00:00
										 |  |  | #else
 | 
					
						
							|  |  |  | 	/* FIXME: Really bad hack (tm) for NTSC support */ | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 	if (ffmpeg_type == FFMPEG_DV && rd->frs_sec != 25) { | 
					
						
							| 
									
										
										
										
											2006-03-07 20:01:12 +00:00
										 |  |  | 		c->frame_rate = 2997; | 
					
						
							|  |  |  | 		c->frame_rate_base = 100; | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 	} else if ((double) ((int) rd->frs_sec_base) ==  | 
					
						
							|  |  |  | 		   rd->frs_sec_base) { | 
					
						
							|  |  |  | 		c->frame_rate = rd->frs_sec; | 
					
						
							|  |  |  | 		c->frame_rate_base = rd->frs_sec_base; | 
					
						
							| 
									
										
											  
											
												== Core ==
This adds fractional FPS support to blender and should finally
make NTSC work correctly.
NTSC has an FPS of 30.0/1.001 which is approximately 29.97 FPS.
Therefore, it is not enough to simply make frs_sec a float, since
you can't represent this accurately enough. 
I added a seperate variable frs_sec_base and FPS is now 
frs_sec / frs_sec_base.
I changed all the places, where frs_sec was used to my best knowledge.
For convenience sake, I added several macros, that should make life
easier in the future:
FRA2TIME(a) : convert frame number to a double precision time in seconds
TIME2FRA(a) : the same in the opposite direction
FPS         : return current FPS as a double precision number 
              (last resort)
This closes bug #6715 
Standard framerates not supported / breaks sync -- 23.967 29.967 etc.
https://projects.blender.org/tracker/?func=detail&aid=6715&group_id=9&atid=125
Please give this heavy testing with NTSC files, quicktime in/export
and the python interface.
Errors are most probably only spotted on longer timelines, so that is
also important.
The patch was tested by Troy Sobotka and me, so it most probably should
work out of the box, but wider testing is important, since errors are
very subtle.
Enjoy!
											
										 
											2007-10-21 15:42:08 +00:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 		c->frame_rate = rd->frs_sec * 100000; | 
					
						
							|  |  |  | 		c->frame_rate_base = ((double) rd->frs_sec_base)*100000; | 
					
						
							| 
									
										
										
										
											2006-03-07 20:01:12 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	c->gop_size = ffmpeg_gop_size; | 
					
						
							|  |  |  | 	c->bit_rate = ffmpeg_video_bitrate*1000; | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 	c->rc_max_rate = rd->ffcodecdata.rc_max_rate*1000; | 
					
						
							|  |  |  | 	c->rc_min_rate = rd->ffcodecdata.rc_min_rate*1000; | 
					
						
							|  |  |  | 	c->rc_buffer_size = rd->ffcodecdata.rc_buffer_size * 1024; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	c->rc_initial_buffer_occupancy  | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 		= rd->ffcodecdata.rc_buffer_size*3/4; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	c->rc_buffer_aggressivity = 1.0; | 
					
						
							|  |  |  | 	c->me_method = ME_EPZS; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	codec = avcodec_find_encoder(c->codec_id); | 
					
						
							|  |  |  | 	if (!codec) return NULL; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	/* Be sure to use the correct pixel format(e.g. RGB, YUV) */ | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	if (codec->pix_fmts) { | 
					
						
							|  |  |  | 		c->pix_fmt = codec->pix_fmts[0]; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		/* makes HuffYUV happy ... */ | 
					
						
							|  |  |  | 		c->pix_fmt = PIX_FMT_YUV422P; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-06-09 19:48:50 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (codec_id == CODEC_ID_XVID) { | 
					
						
							|  |  |  | 		/* arghhhh ... */ | 
					
						
							|  |  |  | 		c->pix_fmt = PIX_FMT_YUV420P; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2009-04-20 15:06:46 +00:00
										 |  |  | 	if ((of->oformat->flags & AVFMT_GLOBALHEADER) | 
					
						
							|  |  |  | //		|| !strcmp(of->oformat->name, "mp4")
 | 
					
						
							|  |  |  | //	    || !strcmp(of->oformat->name, "mov")
 | 
					
						
							|  |  |  | //	    || !strcmp(of->oformat->name, "3gp")
 | 
					
						
							|  |  |  | 		) { | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 		fprintf(stderr, "Using global header\n"); | 
					
						
							|  |  |  | 		c->flags |= CODEC_FLAG_GLOBAL_HEADER; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	/* Determine whether we are encoding interlaced material or not */ | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 	if (rd->mode & R_FIELDS) { | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 		fprintf(stderr, "Encoding interlaced video\n"); | 
					
						
							|  |  |  | 		c->flags |= CODEC_FLAG_INTERLACED_DCT; | 
					
						
							|  |  |  | 		c->flags |= CODEC_FLAG_INTERLACED_ME; | 
					
						
							| 
									
										
										
										
											2008-05-11 20:40:55 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* xasp & yasp got float lately... */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-20 15:06:46 +00:00
										 |  |  | 	st->sample_aspect_ratio = c->sample_aspect_ratio = av_d2q( | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 		((double) rd->xasp / (double) rd->yasp), 255); | 
					
						
							| 
									
										
										
										
											2008-05-11 20:40:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 	set_ffmpeg_properties(rd, c, "video"); | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	if (avcodec_open(c, codec) < 0) { | 
					
						
							| 
									
										
										
										
											2008-01-02 12:35:30 +00:00
										 |  |  | 		//
 | 
					
						
							|  |  |  | 		//XXX error("Couldn't initialize codec");
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	video_buffersize = 2000000; | 
					
						
							|  |  |  | 	video_buffer = (uint8_t*)MEM_mallocN(video_buffersize,  | 
					
						
							|  |  |  | 					     "FFMPEG video buffer"); | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	current_frame = alloc_picture(c->pix_fmt, c->width, c->height); | 
					
						
							| 
									
										
										
										
											2007-09-23 14:05:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	img_convert_ctx = sws_getContext(c->width, c->height, | 
					
						
							| 
									
										
										
										
											2009-04-20 15:06:46 +00:00
										 |  |  | 					 PIX_FMT_BGR32, | 
					
						
							| 
									
										
										
										
											2007-09-23 14:05:22 +00:00
										 |  |  | 					 c->width, c->height, | 
					
						
							|  |  |  | 					 c->pix_fmt, | 
					
						
							|  |  |  | 					 SWS_BICUBIC, | 
					
						
							|  |  |  | 					 NULL, NULL, NULL); | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	return st; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Prepare an audio stream for the output file */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | static AVStream* alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContext* of)  | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	AVStream* st; | 
					
						
							|  |  |  | 	AVCodecContext* c; | 
					
						
							|  |  |  | 	AVCodec* codec; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	st = av_new_stream(of, 1); | 
					
						
							|  |  |  | 	if (!st) return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-07 20:01:12 +00:00
										 |  |  | 	c = get_codec_from_stream(st); | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	c->codec_id = codec_id; | 
					
						
							|  |  |  | 	c->codec_type = CODEC_TYPE_AUDIO; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-20 14:00:00 +00:00
										 |  |  | 	c->sample_rate = rd->ffcodecdata.audio_mixrate; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	c->bit_rate = ffmpeg_audio_bitrate*1000; | 
					
						
							|  |  |  | 	c->channels = 2; | 
					
						
							|  |  |  | 	codec = avcodec_find_encoder(c->codec_id); | 
					
						
							|  |  |  | 	if (!codec) { | 
					
						
							| 
									
										
										
										
											2008-01-02 12:35:30 +00:00
										 |  |  | 		//XXX error("Couldn't find a valid audio codec");
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-05-11 20:40:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-04 18:16:34 +00:00
										 |  |  | 	set_ffmpeg_properties(rd, c, "audio"); | 
					
						
							| 
									
										
										
										
											2008-05-11 20:40:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	if (avcodec_open(c, codec) < 0) { | 
					
						
							| 
									
										
										
										
											2008-01-02 12:35:30 +00:00
										 |  |  | 		//XXX error("Couldn't initialize audio codec");
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* FIXME: Should be user configurable */ | 
					
						
							| 
									
										
										
										
											2007-01-28 18:45:53 +00:00
										 |  |  | 	if (ffmpeg_type == FFMPEG_DV) { | 
					
						
							|  |  |  | 		/* this is a hack around the poor ffmpeg dv multiplexer. */ | 
					
						
							|  |  |  | 		/* only fixes PAL for now 
 | 
					
						
							|  |  |  | 		   (NTSC is a lot more complicated here...)! */ | 
					
						
							|  |  |  | 		audio_outbuf_size = 7680; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		audio_outbuf_size = 10000; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	audio_output_buffer = (uint8_t*)MEM_mallocN( | 
					
						
							|  |  |  | 		audio_outbuf_size, "FFMPEG audio encoder input buffer"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |        /* ugly hack for PCM codecs */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (c->frame_size <= 1) { | 
					
						
							|  |  |  | 		audio_input_frame_size = audio_outbuf_size / c->channels; | 
					
						
							| 
									
										
										
										
											2006-03-07 20:01:12 +00:00
										 |  |  | 		switch(c->codec_id) { | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 		case CODEC_ID_PCM_S16LE: | 
					
						
							|  |  |  | 		case CODEC_ID_PCM_S16BE: | 
					
						
							|  |  |  | 		case CODEC_ID_PCM_U16LE: | 
					
						
							|  |  |  | 		case CODEC_ID_PCM_U16BE: | 
					
						
							|  |  |  | 			audio_input_frame_size >>= 1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		audio_input_frame_size = c->frame_size; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	audio_input_buffer = (uint8_t*)MEM_mallocN( | 
					
						
							|  |  |  | 		audio_input_frame_size * sizeof(short) * c->channels,  | 
					
						
							|  |  |  | 		"FFMPEG audio encoder output buffer"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return st; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /* essential functions -- start, append, end */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, ReportList *reports) | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	/* Handle to the output file */ | 
					
						
							|  |  |  | 	AVFormatContext* of; | 
					
						
							|  |  |  | 	AVOutputFormat* fmt; | 
					
						
							| 
									
										
										
										
											2006-03-27 22:20:24 +00:00
										 |  |  | 	char name[256]; | 
					
						
							| 
									
										
										
										
											2006-07-09 13:05:09 +00:00
										 |  |  | 	const char ** exts; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ffmpeg_type = rd->ffcodecdata.type; | 
					
						
							|  |  |  | 	ffmpeg_codec = rd->ffcodecdata.codec; | 
					
						
							|  |  |  | 	ffmpeg_audio_codec = rd->ffcodecdata.audio_codec; | 
					
						
							|  |  |  | 	ffmpeg_video_bitrate = rd->ffcodecdata.video_bitrate; | 
					
						
							|  |  |  | 	ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate; | 
					
						
							|  |  |  | 	ffmpeg_gop_size = rd->ffcodecdata.gop_size; | 
					
						
							|  |  |  | 	ffmpeg_multiplex_audio = rd->ffcodecdata.flags | 
					
						
							|  |  |  | 		& FFMPEG_MULTIPLEX_AUDIO; | 
					
						
							|  |  |  | 	ffmpeg_autosplit = rd->ffcodecdata.flags | 
					
						
							|  |  |  | 		& FFMPEG_AUTOSPLIT_OUTPUT; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	do_init_ffmpeg(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Determine the correct filename */ | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 	makeffmpegstring(rd, name); | 
					
						
							| 
									
										
										
										
											2006-06-07 12:53:51 +00:00
										 |  |  | 	fprintf(stderr, "Starting output to %s(ffmpeg)...\n" | 
					
						
							|  |  |  | 		"  Using type=%d, codec=%d, audio_codec=%d,\n" | 
					
						
							|  |  |  | 		"  video_bitrate=%d, audio_bitrate=%d,\n" | 
					
						
							|  |  |  | 		"  gop_size=%d, multiplex=%d, autosplit=%d\n" | 
					
						
							|  |  |  | 		"  render width=%d, render height=%d\n",  | 
					
						
							|  |  |  | 		name, ffmpeg_type, ffmpeg_codec, ffmpeg_audio_codec, | 
					
						
							|  |  |  | 		ffmpeg_video_bitrate, ffmpeg_audio_bitrate, | 
					
						
							|  |  |  | 		ffmpeg_gop_size, ffmpeg_multiplex_audio, | 
					
						
							|  |  |  | 		ffmpeg_autosplit, rectx, recty); | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2006-07-09 13:05:09 +00:00
										 |  |  | 	exts = get_file_extensions(ffmpeg_type); | 
					
						
							|  |  |  | 	if (!exts) { | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 		BKE_report(reports, RPT_ERROR, "No valid formats found."); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2006-07-09 13:05:09 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	fmt = guess_format(NULL, exts[0], NULL); | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	if (!fmt) { | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 		BKE_report(reports, RPT_ERROR, "No valid formats found."); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	of = av_alloc_format_context(); | 
					
						
							|  |  |  | 	if (!of) { | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 		BKE_report(reports, RPT_ERROR, "Error opening output file"); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	of->oformat = fmt; | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 	of->packet_size= rd->ffcodecdata.mux_packet_size; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	if (ffmpeg_multiplex_audio) { | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 		of->mux_rate = rd->ffcodecdata.mux_rate; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		of->mux_rate = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	of->preload = (int)(0.5*AV_TIME_BASE); | 
					
						
							|  |  |  | 	of->max_delay = (int)(0.7*AV_TIME_BASE); | 
					
						
							| 
									
										
										
										
											2006-05-21 12:20:45 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	snprintf(of->filename, sizeof(of->filename), "%s", name); | 
					
						
							|  |  |  | 	/* set the codec to the user's selection */ | 
					
						
							|  |  |  | 	switch(ffmpeg_type) { | 
					
						
							| 
									
										
										
										
											2006-06-09 19:48:50 +00:00
										 |  |  | 	case FFMPEG_AVI: | 
					
						
							|  |  |  | 	case FFMPEG_MOV: | 
					
						
							| 
									
										
										
										
											2008-10-05 17:31:33 +00:00
										 |  |  | 	case FFMPEG_OGG: | 
					
						
							|  |  |  | 	case FFMPEG_MKV: | 
					
						
							| 
									
										
										
										
											2006-06-09 19:48:50 +00:00
										 |  |  | 		fmt->video_codec = ffmpeg_codec; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case FFMPEG_DV: | 
					
						
							|  |  |  | 		fmt->video_codec = CODEC_ID_DVVIDEO; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case FFMPEG_MPEG1: | 
					
						
							|  |  |  | 		fmt->video_codec = CODEC_ID_MPEG1VIDEO; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case FFMPEG_MPEG2: | 
					
						
							|  |  |  | 		fmt->video_codec = CODEC_ID_MPEG2VIDEO; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case FFMPEG_H264: | 
					
						
							|  |  |  | 		fmt->video_codec = CODEC_ID_H264; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case FFMPEG_XVID: | 
					
						
							|  |  |  | 		fmt->video_codec = CODEC_ID_XVID; | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2008-04-13 18:50:16 +00:00
										 |  |  | 	case FFMPEG_FLV: | 
					
						
							|  |  |  | 		fmt->video_codec = CODEC_ID_FLV1; | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2006-06-09 19:48:50 +00:00
										 |  |  | 	case FFMPEG_MPEG4: | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		fmt->video_codec = CODEC_ID_MPEG4; | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-06-07 12:53:51 +00:00
										 |  |  | 	if (fmt->video_codec == CODEC_ID_DVVIDEO) { | 
					
						
							|  |  |  | 		if (rectx != 720) { | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 			BKE_report(reports, RPT_ERROR, "Render width has to be 720 pixels for DV!"); | 
					
						
							|  |  |  | 			return 0; | 
					
						
							| 
									
										
										
										
											2006-06-07 12:53:51 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 		if (rd->frs_sec != 25 && recty != 480) { | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 			BKE_report(reports, RPT_ERROR, "Render height has to be 480 pixels for DV-NTSC!"); | 
					
						
							|  |  |  | 			return 0; | 
					
						
							| 
									
										
										
										
											2006-06-07 12:53:51 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 		if (rd->frs_sec == 25 && recty != 576) { | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 			BKE_report(reports, RPT_ERROR, "Render height has to be 576 pixels for DV-PAL!"); | 
					
						
							|  |  |  | 			return 0; | 
					
						
							| 
									
										
										
										
											2006-06-07 12:53:51 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-04-22 07:40:04 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	fmt->audio_codec = ffmpeg_audio_codec; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	if (ffmpeg_type == FFMPEG_DV) { | 
					
						
							|  |  |  | 		fmt->audio_codec = CODEC_ID_PCM_S16LE; | 
					
						
							| 
									
										
										
										
											2009-09-20 14:00:00 +00:00
										 |  |  | 		if (ffmpeg_multiplex_audio && rd->ffcodecdata.audio_mixrate != 48000) { | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 			BKE_report(reports, RPT_ERROR, "FFMPEG only supports 48khz / stereo audio for DV!"); | 
					
						
							|  |  |  | 			return 0; | 
					
						
							| 
									
										
										
										
											2006-06-07 12:53:51 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 	video_stream = alloc_video_stream(rd, fmt->video_codec, of, rectx, recty); | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 	printf("alloc video stream %p\n", video_stream); | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	if (!video_stream) { | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 		BKE_report(reports, RPT_ERROR, "Error initializing video stream."); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	if (ffmpeg_multiplex_audio) { | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 		audio_stream = alloc_audio_stream(rd, fmt->audio_codec, of); | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 		if (!audio_stream) { | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 			BKE_report(reports, RPT_ERROR, "Error initializing audio stream."); | 
					
						
							|  |  |  | 			return 0; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-01-02 12:35:30 +00:00
										 |  |  | 		//XXX audiostream_play(SFRA, 0, 1);
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if (av_set_parameters(of, NULL) < 0) { | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 		BKE_report(reports, RPT_ERROR, "Error setting output parameters."); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if (!(fmt->flags & AVFMT_NOFILE)) { | 
					
						
							|  |  |  | 		if (url_fopen(&of->pb, name, URL_WRONLY) < 0) { | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 			BKE_report(reports, RPT_ERROR, "Could not open file for writing."); | 
					
						
							|  |  |  | 			return 0; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	av_write_header(of); | 
					
						
							|  |  |  | 	outfile = of; | 
					
						
							|  |  |  | 	dump_format(of, 0, name, 1); | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 1; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-09 13:05:09 +00:00
										 |  |  | /* **********************************************************************
 | 
					
						
							|  |  |  |    * public interface | 
					
						
							|  |  |  |    ********************************************************************** */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Get the output filename-- similar to the other output formats */ | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | static void makeffmpegstring(RenderData* rd, char* string) { | 
					
						
							| 
									
										
										
										
											2008-01-02 12:35:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// XXX quick define, solve!
 | 
					
						
							|  |  |  | #define FILE_MAXDIR 256
 | 
					
						
							|  |  |  | #define FILE_MAXFILE 126
 | 
					
						
							|  |  |  | 		 | 
					
						
							| 
									
										
										
										
											2006-07-09 13:05:09 +00:00
										 |  |  | 	char txt[FILE_MAXDIR+FILE_MAXFILE]; | 
					
						
							| 
									
										
										
										
											2008-01-02 12:35:30 +00:00
										 |  |  | 	// XXX
 | 
					
						
							|  |  |  | #undef FILE_MAXDIR
 | 
					
						
							|  |  |  | #undef FILE_MAXFILE
 | 
					
						
							| 
									
										
										
										
											2006-07-09 13:05:09 +00:00
										 |  |  | 	char autosplit[20]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 	const char ** exts = get_file_extensions(rd->ffcodecdata.type); | 
					
						
							| 
									
										
										
										
											2006-07-09 13:05:09 +00:00
										 |  |  | 	const char ** fe = exts; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!string || !exts) return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 	strcpy(string, rd->pic); | 
					
						
							| 
									
										
										
										
											2008-05-04 10:28:10 +00:00
										 |  |  | 	BLI_convertstringcode(string, G.sce); | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 	BLI_convertstringframe(string, rd->cfra); | 
					
						
							| 
									
										
										
										
											2006-07-09 13:05:09 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	BLI_make_existing_file(string); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	autosplit[0] = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 	if ((rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT) != 0) { | 
					
						
							| 
									
										
										
										
											2006-07-09 13:05:09 +00:00
										 |  |  | 		sprintf(autosplit, "_%03d", ffmpeg_autosplit_count); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (*fe) { | 
					
						
							|  |  |  | 		if (BLI_strcasecmp(string + strlen(string) - strlen(*fe),  | 
					
						
							|  |  |  | 				   *fe) == 0) { | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		fe++; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!*fe) { | 
					
						
							|  |  |  | 		strcat(string, autosplit); | 
					
						
							| 
									
										
										
										
											2009-01-04 14:14:06 +00:00
										 |  |  | 		sprintf(txt, "%04d_%04d%s", (rd->sfra),  | 
					
						
							|  |  |  | 			(rd->efra), *exts); | 
					
						
							| 
									
										
										
										
											2006-07-09 13:05:09 +00:00
										 |  |  | 		strcat(string, txt); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		*(string + strlen(string) - strlen(*fe)) = 0; | 
					
						
							|  |  |  | 		strcat(string, autosplit); | 
					
						
							|  |  |  | 		strcat(string, *fe); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | int start_ffmpeg(struct Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports) | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 	int success; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	ffmpeg_autosplit_count = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 	success = start_ffmpeg_impl(rd, rectx, recty, reports); | 
					
						
							| 
									
										
										
										
											2009-08-09 21:16:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if(ffmpeg_multiplex_audio && audio_stream) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		AVCodecContext* c = get_codec_from_stream(audio_stream); | 
					
						
							|  |  |  | 		AUD_Specs specs; | 
					
						
							|  |  |  | 		specs.channels = c->channels; | 
					
						
							|  |  |  | 		specs.format = AUD_FORMAT_S16; | 
					
						
							| 
									
										
										
										
											2009-09-20 14:00:00 +00:00
										 |  |  | 		specs.rate = rd->ffcodecdata.audio_mixrate; | 
					
						
							|  |  |  | 		audio_mixdown_device = sound_mixdown(scene, specs, rd->sfra, rd->efra, rd->ffcodecdata.audio_volume); | 
					
						
							| 
									
										
										
										
											2009-08-09 21:16:39 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return success; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void end_ffmpeg(void); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-01-28 18:45:53 +00:00
										 |  |  | static void write_audio_frames() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int finished = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (ffmpeg_multiplex_audio && !finished) { | 
					
						
							|  |  |  | 		double a_pts = ((double)audio_stream->pts.val  | 
					
						
							|  |  |  | 				* audio_stream->time_base.num  | 
					
						
							|  |  |  | 				/ audio_stream->time_base.den); | 
					
						
							|  |  |  | 		double v_pts = ((double)video_stream->pts.val  | 
					
						
							|  |  |  | 				* video_stream->time_base.num  | 
					
						
							|  |  |  | 				/ video_stream->time_base.den); | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		if (a_pts < v_pts) { | 
					
						
							|  |  |  | 			write_audio_frame(); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			finished = 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | int append_ffmpeg(RenderData *rd, int frame, int *pixels, int rectx, int recty, ReportList *reports)  | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 	AVFrame* avframe; | 
					
						
							|  |  |  | 	int success; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-07 12:53:51 +00:00
										 |  |  | 	fprintf(stderr, "Writing frame %i, " | 
					
						
							|  |  |  | 		"render width=%d, render height=%d\n", frame, | 
					
						
							|  |  |  | 		rectx, recty); | 
					
						
							| 
									
										
										
										
											2007-01-28 18:45:53 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	write_audio_frames(); | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	avframe= generate_video_frame((unsigned char*) pixels, reports); | 
					
						
							|  |  |  | 	success= (avframe && write_video_frame(rd, avframe, reports)); | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (ffmpeg_autosplit) { | 
					
						
							| 
									
										
										
										
											2008-02-06 22:45:46 +00:00
										 |  |  | 		if (url_ftell(OUTFILE_PB) > FFMPEG_AUTOSPLIT_SIZE) { | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 			end_ffmpeg(); | 
					
						
							|  |  |  | 			ffmpeg_autosplit_count++; | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 			success &= start_ffmpeg_impl(rd, rectx, recty, reports); | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return success; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void end_ffmpeg(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	fprintf(stderr, "Closing ffmpeg...\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-01 14:37:09 +00:00
										 |  |  | 	if (audio_stream && video_stream) { | 
					
						
							| 
									
										
										
										
											2007-09-23 14:05:22 +00:00
										 |  |  | 		write_audio_frames(); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-08-09 21:16:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if(audio_mixdown_device) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		AUD_closeReadDevice(audio_mixdown_device); | 
					
						
							|  |  |  | 		audio_mixdown_device = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-09-23 14:05:22 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	if (outfile) { | 
					
						
							|  |  |  | 		av_write_trailer(outfile); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	/* Close the video codec */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-03-07 20:01:12 +00:00
										 |  |  | 	if (video_stream && get_codec_from_stream(video_stream)) { | 
					
						
							|  |  |  | 		avcodec_close(get_codec_from_stream(video_stream)); | 
					
						
							| 
									
										
										
										
											2006-06-07 12:53:51 +00:00
										 |  |  | 		video_stream = 0; | 
					
						
							| 
									
										
										
										
											2009-12-22 12:01:32 +00:00
										 |  |  | 		printf("zero video stream %p\n", video_stream); | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	/* Close the output file */ | 
					
						
							|  |  |  | 	if (outfile) { | 
					
						
							|  |  |  | 		for (i = 0; i < outfile->nb_streams; i++) { | 
					
						
							|  |  |  | 			if (&outfile->streams[i]) { | 
					
						
							|  |  |  | 				av_freep(&outfile->streams[i]); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	/* free the temp buffer */ | 
					
						
							|  |  |  | 	if (current_frame) { | 
					
						
							|  |  |  | 		delete_picture(current_frame); | 
					
						
							| 
									
										
										
										
											2006-06-04 18:05:47 +00:00
										 |  |  | 		current_frame = 0; | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if (outfile && outfile->oformat) { | 
					
						
							|  |  |  | 		if (!(outfile->oformat->flags & AVFMT_NOFILE)) { | 
					
						
							| 
									
										
										
										
											2008-02-06 22:45:46 +00:00
										 |  |  | 			url_fclose(OUTFILE_PB); | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (outfile) { | 
					
						
							|  |  |  | 		av_free(outfile); | 
					
						
							|  |  |  | 		outfile = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (video_buffer) { | 
					
						
							|  |  |  | 		MEM_freeN(video_buffer); | 
					
						
							|  |  |  | 		video_buffer = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (audio_output_buffer) { | 
					
						
							|  |  |  | 		MEM_freeN(audio_output_buffer); | 
					
						
							|  |  |  | 		audio_output_buffer = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (audio_input_buffer) { | 
					
						
							|  |  |  | 		MEM_freeN(audio_input_buffer); | 
					
						
							|  |  |  | 		audio_input_buffer = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-09-23 14:05:22 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (img_convert_ctx) { | 
					
						
							|  |  |  | 		sws_freeContext(img_convert_ctx); | 
					
						
							|  |  |  | 		img_convert_ctx = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | } | 
					
						
							| 
									
										
											  
											
												2.5: Render
* UI layout for scene buttons has quite some changes, I tried to
  better organize things according to the pipeline, and also showing
  important properties by default, and collapsing less important ones.
Some changes compared to 2.4x:
* Panorama is now a Camera property.
* Sequence and Compositing are now enabled by default, but will only
  do something when there is a node tree using nodes, or a strip in the
  sequence editor.
* Enabling Full Sample now automatically enables Save Buffers too.
* Stamp option to include info in file is removed, it now simply always
  does this if one of the stamp infos is enabled.
* Xvid, H.264 and Ogg Theora are now directly in the file format menu,
  but still using FFMPEG. Unfortunately Ogg is broken at the moment
  (also in 2.4x), so that's disabled. And Xvid crashes on 64bit linux,
  maybe solvable by upgrading extern/xvidcore/, using ubuntu libs makes
  it work.
* Organized file format menu by image/movie types.
Added:
* Render layers RNA wrapped, operatorized, layouted.
* FFMPEG format/codec options are now working.
Defaults changed:
* Compositing & Sequencer enabled.
* Tiles set to 8x8.
* Time/Date/Frame/Scene/Camera/Filename enabled for stamp.
											
										 
											2009-07-13 19:09:13 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* properties */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ffmpeg_property_del(RenderData *rd, void *type, void *prop_) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct IDProperty *prop = (struct IDProperty *) prop_; | 
					
						
							|  |  |  | 	IDProperty * group; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	if (!rd->ffcodecdata.properties) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	group = IDP_GetPropertyFromGroup( | 
					
						
							|  |  |  | 		rd->ffcodecdata.properties, (char*) type); | 
					
						
							|  |  |  | 	if (group && prop) { | 
					
						
							|  |  |  | 		IDP_RemFromGroup(group, prop); | 
					
						
							|  |  |  | 		IDP_FreeProperty(prop); | 
					
						
							|  |  |  | 		MEM_freeN(prop); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | IDProperty *ffmpeg_property_add(RenderData *rd, char * type, int opt_index, int parent_index) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	AVCodecContext c; | 
					
						
							|  |  |  | 	const AVOption * o; | 
					
						
							|  |  |  | 	const AVOption * parent; | 
					
						
							|  |  |  | 	IDProperty * group; | 
					
						
							|  |  |  | 	IDProperty * prop; | 
					
						
							|  |  |  | 	IDPropertyTemplate val; | 
					
						
							|  |  |  | 	int idp_type; | 
					
						
							|  |  |  | 	char name[256]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	avcodec_get_context_defaults(&c); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	o = c.av_class->option + opt_index; | 
					
						
							|  |  |  | 	parent = c.av_class->option + parent_index; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!rd->ffcodecdata.properties) { | 
					
						
							|  |  |  | 		IDPropertyTemplate val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		rd->ffcodecdata.properties  | 
					
						
							|  |  |  | 			= IDP_New(IDP_GROUP, val, "ffmpeg");  | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	group = IDP_GetPropertyFromGroup( | 
					
						
							|  |  |  | 		rd->ffcodecdata.properties, (char*) type); | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	if (!group) { | 
					
						
							|  |  |  | 		IDPropertyTemplate val; | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		group = IDP_New(IDP_GROUP, val, (char*) type);  | 
					
						
							|  |  |  | 		IDP_AddToGroup(rd->ffcodecdata.properties, group); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (parent_index) { | 
					
						
							|  |  |  | 		sprintf(name, "%s:%s", parent->name, o->name); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		strcpy(name, o->name); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	fprintf(stderr, "ffmpeg_property_add: %s %d %d %s\n", | 
					
						
							|  |  |  | 		type, parent_index, opt_index, name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	prop = IDP_GetPropertyFromGroup(group, name); | 
					
						
							|  |  |  | 	if (prop) { | 
					
						
							|  |  |  | 		return prop; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (o->type) { | 
					
						
							|  |  |  | 	case FF_OPT_TYPE_INT: | 
					
						
							|  |  |  | 	case FF_OPT_TYPE_INT64: | 
					
						
							|  |  |  | 		val.i = o->default_val; | 
					
						
							|  |  |  | 		idp_type = IDP_INT; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case FF_OPT_TYPE_DOUBLE: | 
					
						
							|  |  |  | 	case FF_OPT_TYPE_FLOAT: | 
					
						
							|  |  |  | 		val.f = o->default_val; | 
					
						
							|  |  |  | 		idp_type = IDP_FLOAT; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case FF_OPT_TYPE_STRING: | 
					
						
							|  |  |  | 		val.str = "                                                                               "; | 
					
						
							|  |  |  | 		idp_type = IDP_STRING; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case FF_OPT_TYPE_CONST: | 
					
						
							|  |  |  | 		val.i = 1; | 
					
						
							|  |  |  | 		idp_type = IDP_INT; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	prop = IDP_New(idp_type, val, name); | 
					
						
							|  |  |  | 	IDP_AddToGroup(group, prop); | 
					
						
							|  |  |  | 	return prop; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* not all versions of ffmpeg include that, so here we go ... */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const AVOption *my_av_find_opt(void *v, const char *name,  | 
					
						
							|  |  |  | 				      const char *unit, int mask, int flags){ | 
					
						
							|  |  |  | 	AVClass *c= *(AVClass**)v;  | 
					
						
							|  |  |  | 	const AVOption *o= c->option; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for(;o && o->name; o++){ | 
					
						
							|  |  |  | 		if(!strcmp(o->name, name) &&  | 
					
						
							|  |  |  | 		   (!unit || (o->unit && !strcmp(o->unit, unit))) &&  | 
					
						
							|  |  |  | 		   (o->flags & mask) == flags ) | 
					
						
							|  |  |  | 			return o; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ffmpeg_property_add_string(RenderData *rd, const char * type, const char * str) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	AVCodecContext c; | 
					
						
							|  |  |  | 	const AVOption * o = 0; | 
					
						
							|  |  |  | 	const AVOption * p = 0; | 
					
						
							|  |  |  | 	char name_[128]; | 
					
						
							|  |  |  | 	char * name; | 
					
						
							|  |  |  | 	char * param; | 
					
						
							|  |  |  | 	IDProperty * prop; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	avcodec_get_context_defaults(&c); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	strncpy(name_, str, 128); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	name = name_; | 
					
						
							|  |  |  | 	while (*name == ' ') name++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	param = strchr(name, ':'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!param) { | 
					
						
							|  |  |  | 		param = strchr(name, ' '); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (param) { | 
					
						
							|  |  |  | 		*param++ = 0; | 
					
						
							|  |  |  | 		while (*param == ' ') param++; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	o = my_av_find_opt(&c, name, NULL, 0, 0);	 | 
					
						
							|  |  |  | 	if (!o) { | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (param && o->type == FF_OPT_TYPE_CONST) { | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (param && o->type != FF_OPT_TYPE_CONST && o->unit) { | 
					
						
							|  |  |  | 		p = my_av_find_opt(&c, param, o->unit, 0, 0);	 | 
					
						
							|  |  |  | 		prop = ffmpeg_property_add(rd, | 
					
						
							|  |  |  | 			(char*) type, p - c.av_class->option,  | 
					
						
							|  |  |  | 			o - c.av_class->option); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		prop = ffmpeg_property_add(rd, | 
					
						
							|  |  |  | 			(char*) type, o - c.av_class->option, 0); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!prop) { | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (param && !p) { | 
					
						
							|  |  |  | 		switch (prop->type) { | 
					
						
							|  |  |  | 		case IDP_INT: | 
					
						
							|  |  |  | 			IDP_Int(prop) = atoi(param); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case IDP_FLOAT: | 
					
						
							|  |  |  | 			IDP_Float(prop) = atof(param); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case IDP_STRING: | 
					
						
							|  |  |  | 			strncpy(IDP_String(prop), param, prop->len); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ffmpeg_set_preset(RenderData *rd, int preset) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int isntsc = (rd->frs_sec != 25); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (preset) { | 
					
						
							|  |  |  | 	case FFMPEG_PRESET_VCD: | 
					
						
							|  |  |  | 		rd->ffcodecdata.type = FFMPEG_MPEG1; | 
					
						
							|  |  |  | 		rd->ffcodecdata.video_bitrate = 1150; | 
					
						
							|  |  |  | 		rd->xsch = 352; | 
					
						
							|  |  |  | 		rd->ysch = isntsc ? 240 : 288; | 
					
						
							|  |  |  | 		rd->ffcodecdata.gop_size = isntsc ? 18 : 15; | 
					
						
							|  |  |  | 		rd->ffcodecdata.rc_max_rate = 1150; | 
					
						
							|  |  |  | 		rd->ffcodecdata.rc_min_rate = 1150; | 
					
						
							|  |  |  | 		rd->ffcodecdata.rc_buffer_size = 40*8; | 
					
						
							|  |  |  | 		rd->ffcodecdata.mux_packet_size = 2324; | 
					
						
							|  |  |  | 		rd->ffcodecdata.mux_rate = 2352 * 75 * 8; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case FFMPEG_PRESET_SVCD: | 
					
						
							|  |  |  | 		rd->ffcodecdata.type = FFMPEG_MPEG2; | 
					
						
							|  |  |  | 		rd->ffcodecdata.video_bitrate = 2040; | 
					
						
							|  |  |  | 		rd->xsch = 480; | 
					
						
							|  |  |  | 		rd->ysch = isntsc ? 480 : 576; | 
					
						
							|  |  |  | 		rd->ffcodecdata.gop_size = isntsc ? 18 : 15; | 
					
						
							|  |  |  | 		rd->ffcodecdata.rc_max_rate = 2516; | 
					
						
							|  |  |  | 		rd->ffcodecdata.rc_min_rate = 0; | 
					
						
							|  |  |  | 		rd->ffcodecdata.rc_buffer_size = 224*8; | 
					
						
							|  |  |  | 		rd->ffcodecdata.mux_packet_size = 2324; | 
					
						
							|  |  |  | 		rd->ffcodecdata.mux_rate = 0; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case FFMPEG_PRESET_DVD: | 
					
						
							|  |  |  | 		rd->ffcodecdata.type = FFMPEG_MPEG2; | 
					
						
							|  |  |  | 		rd->ffcodecdata.video_bitrate = 6000; | 
					
						
							|  |  |  | 		rd->xsch = 720; | 
					
						
							|  |  |  | 		rd->ysch = isntsc ? 480 : 576; | 
					
						
							|  |  |  | 		rd->ffcodecdata.gop_size = isntsc ? 18 : 15; | 
					
						
							|  |  |  | 		rd->ffcodecdata.rc_max_rate = 9000; | 
					
						
							|  |  |  | 		rd->ffcodecdata.rc_min_rate = 0; | 
					
						
							|  |  |  | 		rd->ffcodecdata.rc_buffer_size = 224*8; | 
					
						
							|  |  |  | 		rd->ffcodecdata.mux_packet_size = 2048; | 
					
						
							|  |  |  | 		rd->ffcodecdata.mux_rate = 10080000; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case FFMPEG_PRESET_DV: | 
					
						
							|  |  |  | 		rd->ffcodecdata.type = FFMPEG_DV; | 
					
						
							|  |  |  | 		rd->xsch = 720; | 
					
						
							|  |  |  | 		rd->ysch = isntsc ? 480 : 576; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case FFMPEG_PRESET_H264: | 
					
						
							|  |  |  | 		rd->ffcodecdata.type = FFMPEG_AVI; | 
					
						
							|  |  |  | 		rd->ffcodecdata.codec = CODEC_ID_H264; | 
					
						
							|  |  |  | 		rd->ffcodecdata.video_bitrate = 6000; | 
					
						
							|  |  |  | 		rd->ffcodecdata.gop_size = isntsc ? 18 : 15; | 
					
						
							|  |  |  | 		rd->ffcodecdata.rc_max_rate = 9000; | 
					
						
							|  |  |  | 		rd->ffcodecdata.rc_min_rate = 0; | 
					
						
							|  |  |  | 		rd->ffcodecdata.rc_buffer_size = 224*8; | 
					
						
							|  |  |  | 		rd->ffcodecdata.mux_packet_size = 2048; | 
					
						
							|  |  |  | 		rd->ffcodecdata.mux_rate = 10080000; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ffmpeg_property_add_string(rd, "video", "coder:vlc"); | 
					
						
							|  |  |  | 		ffmpeg_property_add_string(rd, "video", "flags:loop"); | 
					
						
							|  |  |  | 		ffmpeg_property_add_string(rd, "video", "cmp:chroma"); | 
					
						
							|  |  |  | 		ffmpeg_property_add_string(rd, "video", "partitions:parti4x4"); | 
					
						
							|  |  |  | 		ffmpeg_property_add_string(rd, "video", "partitions:partp8x8"); | 
					
						
							|  |  |  | 		ffmpeg_property_add_string(rd, "video", "partitions:partb8x8"); | 
					
						
							|  |  |  | 		ffmpeg_property_add_string(rd, "video", "me:hex"); | 
					
						
							|  |  |  | 		ffmpeg_property_add_string(rd, "video", "subq:5"); | 
					
						
							|  |  |  | 		ffmpeg_property_add_string(rd, "video", "me_range:16"); | 
					
						
							|  |  |  | 		ffmpeg_property_add_string(rd, "video", "keyint_min:25"); | 
					
						
							|  |  |  | 		ffmpeg_property_add_string(rd, "video", "sc_threshold:40"); | 
					
						
							|  |  |  | 		ffmpeg_property_add_string(rd, "video", "i_qfactor:0.71"); | 
					
						
							|  |  |  | 		ffmpeg_property_add_string(rd, "video", "b_strategy:1"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case FFMPEG_PRESET_THEORA: | 
					
						
							|  |  |  | 	case FFMPEG_PRESET_XVID: | 
					
						
							|  |  |  | 		if(preset == FFMPEG_PRESET_XVID) { | 
					
						
							|  |  |  | 			rd->ffcodecdata.type = FFMPEG_AVI; | 
					
						
							|  |  |  | 			rd->ffcodecdata.codec = CODEC_ID_XVID; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		else if(preset == FFMPEG_PRESET_THEORA) { | 
					
						
							|  |  |  | 			rd->ffcodecdata.type = FFMPEG_OGG; // XXX broken
 | 
					
						
							|  |  |  | 			rd->ffcodecdata.codec = CODEC_ID_THEORA; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		rd->ffcodecdata.video_bitrate = 6000; | 
					
						
							|  |  |  | 		rd->ffcodecdata.gop_size = isntsc ? 18 : 15; | 
					
						
							|  |  |  | 		rd->ffcodecdata.rc_max_rate = 9000; | 
					
						
							|  |  |  | 		rd->ffcodecdata.rc_min_rate = 0; | 
					
						
							|  |  |  | 		rd->ffcodecdata.rc_buffer_size = 224*8; | 
					
						
							|  |  |  | 		rd->ffcodecdata.mux_packet_size = 2048; | 
					
						
							|  |  |  | 		rd->ffcodecdata.mux_rate = 10080000; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ffmpeg_verify_image_type(RenderData *rd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int audio= 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(rd->imtype == R_FFMPEG) { | 
					
						
							|  |  |  | 		if(rd->ffcodecdata.type <= 0 || | 
					
						
							|  |  |  | 		   rd->ffcodecdata.codec <= 0 || | 
					
						
							|  |  |  | 		   rd->ffcodecdata.audio_codec <= 0 || | 
					
						
							|  |  |  | 		   rd->ffcodecdata.video_bitrate <= 1) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			rd->ffcodecdata.codec = CODEC_ID_MPEG2VIDEO; | 
					
						
							|  |  |  | 			ffmpeg_set_preset(rd, FFMPEG_PRESET_DVD); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		audio= 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else if(rd->imtype == R_H264) { | 
					
						
							|  |  |  | 		if(rd->ffcodecdata.codec != CODEC_ID_H264) { | 
					
						
							|  |  |  | 			ffmpeg_set_preset(rd, FFMPEG_PRESET_H264); | 
					
						
							|  |  |  | 			audio= 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else if(rd->imtype == R_XVID) { | 
					
						
							|  |  |  | 		if(rd->ffcodecdata.codec != CODEC_ID_XVID) { | 
					
						
							|  |  |  | 			ffmpeg_set_preset(rd, FFMPEG_PRESET_XVID); | 
					
						
							|  |  |  | 			audio= 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else if(rd->imtype == R_THEORA) { | 
					
						
							|  |  |  | 		if(rd->ffcodecdata.codec != CODEC_ID_THEORA) { | 
					
						
							|  |  |  | 			ffmpeg_set_preset(rd, FFMPEG_PRESET_THEORA); | 
					
						
							|  |  |  | 			audio= 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(audio && rd->ffcodecdata.audio_codec <= 0) { | 
					
						
							|  |  |  | 		rd->ffcodecdata.audio_codec = CODEC_ID_MP2; | 
					
						
							|  |  |  | 		rd->ffcodecdata.audio_bitrate = 128; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-05 19:14:46 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 |