⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ffmpeg.c

📁 video motion detection of linux base
💻 C
📖 第 1 页 / 共 2 页
字号:
/********************************************************************** * * ffmpeg.c * * This software is distributed under the GNU Public License version 2 * See also the file 'COPYING'. * * The contents of this file has been derived from output_example.c  * and apiexample.c from the FFmpeg distribution. * **********************************************************************/#ifdef HAVE_FFMPEG#include "ffmpeg.h"#include "motion.h"#if LIBAVCODEC_BUILD > 4680/* FFmpeg after build 4680 doesn't have support for mpeg1 videos with  * non-standard framerates. Previous builds contained a broken hack  * that padded with B frames to obtain the correct framerate. */#	define FFMPEG_NO_NONSTD_MPEG1#	ifdef __GNUC__/* #warning is a non-standard gcc extension */#		warning **************************************************#		warning Your version of FFmpeg is newer than version 0.4.8#		warning Newer versions of ffmpeg do not support MPEG1 with#		warning non-standard framerate. MPEG1 will be disabled for#		warning normal video output. You can still use mpeg4 and#		warning and mpeg4ms which are both better in terms of size#		warning and quality. MPEG1 is always used for timelapse.#		warning Please read the Motion Guide for more information.#		warning Note that this is not an error message!#		warning **************************************************#	endif /* __GNUC__ */#endif /* LIBAVCODEC_BUILD > 4680 */#if LIBAVFORMAT_BUILD >= 4616/* The API for av_write_frame changed with FFmpeg version 0.4.9pre1. * It now uses an AVPacket struct instead of direct parameters to the * function. The */#	define FFMPEG_AVWRITEFRAME_NEWAPI#endif /* LIBAVFORMAT_BUILD >= 4616 */#if LIBAVFORMAT_BUILD >= 4629/* In this build/header version, the codec member of struct AVStream * was changed to a pointer so changes to AVCodecContext shouldn't * break binary compatibility with AVStream. */#	define AVSTREAM_CODEC_PTR(avs_ptr) (avs_ptr->codec)#else#	define AVSTREAM_CODEC_PTR(avs_ptr) (&avs_ptr->codec)#endif /* LIBAVFORMAT_BUILD >= 4629 *//* Name of custom file protocol for appending to existing files instead * of truncating. */#define APPEND_PROTO "appfile"/* Some forward-declarations. */void ffmpeg_put_frame(struct ffmpeg *, AVFrame *);void ffmpeg_cleanups(struct ffmpeg *);AVFrame *ffmpeg_prepare_frame(struct ffmpeg *, unsigned char *,                               unsigned char *, unsigned char *);/* This is the trailer used to end mpeg1 videos. */static unsigned char mpeg1_trailer[] = {0x00, 0x00, 0x01, 0xb7};/* Append version of the file open function used in libavformat when opening * an ordinary file. The original file open function truncates an existing * file, but this version appends to it instead. */static int file_open_append(URLContext *h, const char *filename, int flags){	const char *colon;	int access_flags, fd;	/* Skip past the protocol part of filename. */	colon = strchr(filename, ':');	if (colon) {		filename = colon + 1;	}	if (flags & URL_RDWR) {		access_flags = O_CREAT | O_APPEND | O_RDWR;	} else if (flags & URL_WRONLY) {		access_flags = O_CREAT | O_APPEND | O_WRONLY;	} else {		access_flags = O_RDONLY;	}	fd = open(filename, access_flags, 0666);	if (fd < 0) {		return -ENOENT;	}	h->priv_data = (void *)(size_t)fd;	return 0;}/* URLProtocol entry for the append file protocol, which we use for mpeg1 videos * in order to get append behavior with url_fopen. * * Libavformat uses protocols for achieving flexibility when handling files * and other resources. A call to url_fopen will eventually be redirected to * a protocol-specific open function. * * The remaining functions (for writing, seeking etc.) are set in ffmpeg_init. */URLProtocol mpeg1_file_protocol = {	.name     = APPEND_PROTO,	.url_open = file_open_append};/* We set AVOutputFormat->write_trailer to this function for mpeg1. That way, * the mpeg1 video gets a proper trailer when it is closed. */static int mpeg1_write_trailer(AVFormatContext *s){	put_buffer(&s->pb, mpeg1_trailer, 4);	put_flush_packet(&s->pb);	return 0; /* success */}/* ffmpeg_init initializes for libavformat. */void ffmpeg_init(){	av_register_all();	av_log_set_callback( (void *)ffmpeg_avcodec_log );	/* Copy the functions to use for the append file protocol from the standard	 * file protocol.	 */	mpeg1_file_protocol.url_read  = file_protocol.url_read;	mpeg1_file_protocol.url_write = file_protocol.url_write;	mpeg1_file_protocol.url_seek  = file_protocol.url_seek;	mpeg1_file_protocol.url_close = file_protocol.url_close;	/* Register the append file protocol. */	register_protocol(&mpeg1_file_protocol);}/* Obtains the output format used for the specified codec. For mpeg4 codecs, * the format is avi; for mpeg1 codec, the format is mpeg. The filename has * to be passed, because it gets the appropriate extension appended onto it. */static AVOutputFormat *get_oformat(const char *codec, char *filename){	const char *ext;	AVOutputFormat *of = NULL;	/* Here, we use guess_format to automatically setup the codec information.	 * If we are using msmpeg4, manually set that codec here.	 * We also dynamically add the file extension to the filename here. This was	 * done to support both mpeg1 and mpeg4 codecs since they have different extensions.	 */	if ((strcmp(codec, TIMELAPSE_CODEC) == 0)#ifndef FFMPEG_NO_NONSTD_MPEG1		|| (strcmp(codec, "mpeg1") == 0)#endif 	) {		ext = ".mpg";		/* We use "mpeg1video" for raw mpeg1 format. Using "mpeg" would		 * result in a muxed output file, which isn't appropriate here.		 */		of = guess_format("mpeg1video", NULL, NULL);		if (of) {			/* But we want the trailer to be correctly written. */			of->write_trailer = mpeg1_write_trailer;		}#ifdef FFMPEG_NO_NONSTD_MPEG1	} else if (strcmp(codec, "mpeg1") == 0) {		motion_log(LOG_ERR, 0, "*** mpeg1 support for normal videos has been disabled ***");		return NULL;#endif	} else if (strcmp(codec, "mpeg4") == 0) {		ext = ".avi";		of = guess_format("avi", NULL, NULL);	} else if (strcmp(codec, "msmpeg4") == 0) {		ext = ".avi";		of = guess_format("avi", NULL, NULL);		if (of) {			/* Manually override the codec id. */			of->video_codec = CODEC_ID_MSMPEG4V2;		}	} else {		motion_log(LOG_ERR, 0, "ffmpeg_video_codec option value %s is not supported", codec);		return NULL;	}	if (!of) {		motion_log(LOG_ERR, 0, "Could not guess format for %s", codec);		return NULL;	}	/* The 4 allows for ".avi" or ".mpg" to be appended */	strncat(filename, ext, 4);	return of;}/* This function opens an mpeg file using the new libavformat method. Both mpeg1 * and mpeg4 are supported. However, if the current ffmpeg version doesn't allow * mpeg1 with non-standard framerate, the open will fail. Timelapse is a special * case and is tested separately. */struct ffmpeg *ffmpeg_open(char *ffmpeg_video_codec, char *filename,                           unsigned char *y, unsigned char *u, unsigned char *v,                           int width, int height, int rate, int bps, int vbr){	AVCodecContext *c;	AVCodec *codec;	struct ffmpeg *ffmpeg;	int is_mpeg1;	/* Allocate space for our ffmpeg structure. This structure contains all the 	 * codec and image information we need to generate movies.	 * FIXME when motion exits we should close the movie to ensure that	 * ffmpeg is freed.	 */	ffmpeg = mymalloc(sizeof(struct ffmpeg));	memset(ffmpeg, 0, sizeof(struct ffmpeg));	ffmpeg->vbr = vbr;		/* store codec name in ffmpeg->codec, with buffer overflow check */	snprintf(ffmpeg->codec, sizeof(ffmpeg->codec), "%s", ffmpeg_video_codec);	/* allocation the output media context */	ffmpeg->oc = av_mallocz(sizeof(AVFormatContext));	if (!ffmpeg->oc) {		motion_log(LOG_ERR, 1, "Memory error while allocating output media context");		ffmpeg_cleanups(ffmpeg);		return (NULL);	}	/* Setup output format */	ffmpeg->oc->oformat = get_oformat(ffmpeg_video_codec, filename);	if (!ffmpeg->oc->oformat) {		ffmpeg_cleanups(ffmpeg);		return NULL;	}	snprintf(ffmpeg->oc->filename, sizeof(ffmpeg->oc->filename), "%s", filename);	/* Create a new video stream and initialize the codecs */	ffmpeg->video_st = NULL;	if (ffmpeg->oc->oformat->video_codec != CODEC_ID_NONE) {		ffmpeg->video_st = av_new_stream(ffmpeg->oc, 0);		if (!ffmpeg->video_st) {			motion_log(LOG_ERR, 1, "av_new_stream - could not alloc stream");			ffmpeg_cleanups(ffmpeg);			return (NULL);		}	} else {		/* We did not get a proper video codec. */		motion_log(LOG_ERR, 0, "Failed to obtain a proper video codec");		ffmpeg_cleanups(ffmpeg);		return (NULL);	}	ffmpeg->c     = c = AVSTREAM_CODEC_PTR(ffmpeg->video_st);	c->codec_id   = ffmpeg->oc->oformat->video_codec;	c->codec_type = CODEC_TYPE_VIDEO;	is_mpeg1      = c->codec_id == CODEC_ID_MPEG1VIDEO;	/* Uncomment to allow non-standard framerates. */	//c->strict_std_compliance = -1;	/* Set default parameters */	c->bit_rate = bps;	c->width    = width;	c->height   = height;#if LIBAVCODEC_BUILD >= 4754	/* frame rate = 1/time_base, so we set 1/rate, not rate/1 */	c->time_base.num = 1;	c->time_base.den = rate;#else	c->frame_rate      = rate;	c->frame_rate_base = 1;#endif /* LIBAVCODEC_BUILD >= 4754 */		if (vbr)		c->flags |= CODEC_FLAG_QSCALE;	/* Set codec specific parameters. */	/* set intra frame distance in frames depending on codec */	c->gop_size = is_mpeg1 ? 10 : 12;		/* some formats want stream headers to be separate */	if(!strcmp(ffmpeg->oc->oformat->name, "mp4") || 	   !strcmp(ffmpeg->oc->oformat->name, "mov") ||	   !strcmp(ffmpeg->oc->oformat->name, "3gp")) {		c->flags |= CODEC_FLAG_GLOBAL_HEADER;	}	/* set the output parameters (must be done even if no parameters). */	if (av_set_parameters(ffmpeg->oc, NULL) < 0) {		motion_log(LOG_ERR, 0, "ffmpeg av_set_parameters error: Invalid output format parameters");		ffmpeg_cleanups(ffmpeg);		return (NULL);	}	/* Dump the format settings.  This shows how the various streams relate to each other */	//dump_format(ffmpeg->oc, 0, filename, 1);	/* Now that all the parameters are set, we can open the video		codec and allocate the necessary encode buffers */	codec = avcodec_find_encoder(c->codec_id);	if (!codec) {		motion_log(LOG_ERR, 1, "Codec not found");		ffmpeg_cleanups(ffmpeg);		return (NULL);	}		/* Set the picture format - need in ffmpeg starting round April-May 2005 */	c->pix_fmt = PIX_FMT_YUV420P;	/* Get a mutex lock. */	pthread_mutex_lock(&global_lock);	/* open the codec */	if (avcodec_open(c, codec) < 0) {		/* Release the lock. */		pthread_mutex_unlock(&global_lock);		motion_log(LOG_ERR, 1, "avcodec_open - could not open codec");		ffmpeg_cleanups(ffmpeg);		return (NULL);	}	/* Release the lock. */	pthread_mutex_unlock(&global_lock);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -