📄 ffmpeg.c
字号:
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); ffmpeg->video_outbuf = NULL; if (!(ffmpeg->oc->oformat->flags & AVFMT_RAWPICTURE)) { /* allocate output buffer */ /* XXX: API change will be done */ ffmpeg->video_outbuf_size = 200000; ffmpeg->video_outbuf = mymalloc(ffmpeg->video_outbuf_size); } /* allocate the encoded raw picture */ ffmpeg->picture = avcodec_alloc_frame(); if (!ffmpeg->picture) { motion_log(LOG_ERR, 1, "avcodec_alloc_frame - could not alloc frame"); ffmpeg_cleanups(ffmpeg); return (NULL); } /* set variable bitrate if requested */ if (ffmpeg->vbr) { ffmpeg->picture->quality = ffmpeg->vbr; } /* set the frame data */ ffmpeg->picture->data[0] = y; ffmpeg->picture->data[1] = u; ffmpeg->picture->data[2] = v; ffmpeg->picture->linesize[0] = ffmpeg->c->width; ffmpeg->picture->linesize[1] = ffmpeg->c->width / 2; ffmpeg->picture->linesize[2] = ffmpeg->c->width / 2; /* open the output file, if needed */ if (!(ffmpeg->oc->oformat->flags & AVFMT_NOFILE)) { char file_proto[256]; /* Use append file protocol for mpeg1, to get the append behavior from * url_fopen, but no protocol (=> default) for other codecs. */ if(is_mpeg1) { snprintf(file_proto, sizeof(file_proto), APPEND_PROTO ":%s", filename); } else { snprintf(file_proto, sizeof(file_proto), "%s", filename); } if (url_fopen(&ffmpeg->oc->pb, file_proto, URL_WRONLY) < 0) { /* path did not exist? */ if (errno == ENOENT) { /* create path for file (don't use file_proto)... */ if (create_path(filename) == -1) { ffmpeg_cleanups(ffmpeg); return (NULL); } /* and retry opening the file (use file_proto) */ if (url_fopen(&ffmpeg->oc->pb, file_proto, URL_WRONLY) < 0) { motion_log(LOG_ERR, 1, "url_fopen - error opening file %s",filename); ffmpeg_cleanups(ffmpeg); return (NULL); } /* Permission denied */ } else if (errno == EACCES) { motion_log(LOG_ERR, 1, "url_fopen - error opening file %s" " ... check access rights to target directory", filename); /* create path for file... */ ffmpeg_cleanups(ffmpeg); return (NULL); } else { motion_log(LOG_ERR, 1, "Error opening file %s", filename); ffmpeg_cleanups(ffmpeg); return (NULL); } } } /* write the stream header, if any */ av_write_header(ffmpeg->oc); return ffmpeg;}/* Clean up ffmpeg struct if something was wrong*/void ffmpeg_cleanups(struct ffmpeg *ffmpeg){ unsigned int i; /* close each codec */ if (ffmpeg->video_st) { pthread_mutex_lock(&global_lock);#if LIBAVCODEC_BUILD > 4680 if (ffmpeg->video_st->codec->priv_data != NULL)#endif avcodec_close(AVSTREAM_CODEC_PTR(ffmpeg->video_st)); pthread_mutex_unlock(&global_lock); av_freep(&ffmpeg->picture); free(ffmpeg->video_outbuf); } /* free the streams */ for (i = 0; i < ffmpeg->oc->nb_streams; i++) { av_freep(&ffmpeg->oc->streams[i]); }/* if (!(ffmpeg->oc->oformat->flags & AVFMT_NOFILE)) { // close the output file if (ffmpeg->oc->pb) url_fclose(&ffmpeg->oc->pb); }*/ /* free the stream */ av_free(ffmpeg->oc);#if LIBAVFORMAT_BUILD >= 4629 av_free(ffmpeg->c);#endif free(ffmpeg);}/* Closes a video file. */void ffmpeg_close(struct ffmpeg *ffmpeg){ unsigned int i; /* close each codec */ if (ffmpeg->video_st) { pthread_mutex_lock(&global_lock); avcodec_close(AVSTREAM_CODEC_PTR(ffmpeg->video_st)); pthread_mutex_unlock(&global_lock); av_freep(&ffmpeg->picture); free(ffmpeg->video_outbuf); } /* write the trailer, if any */ av_write_trailer(ffmpeg->oc); /* free the streams */ for (i = 0; i < ffmpeg->oc->nb_streams; i++) { av_freep(&ffmpeg->oc->streams[i]); } if (!(ffmpeg->oc->oformat->flags & AVFMT_NOFILE)) { /* close the output file */#if LIBAVFORMAT_BUILD >= (52<<16) url_fclose(ffmpeg->oc->pb);#else url_fclose(&ffmpeg->oc->pb);#endif /* LIBAVFORMAT_BUILD >= (52<<16) */ } /* free the stream */ av_free(ffmpeg->oc);#if LIBAVFORMAT_BUILD >= 4629 av_free(ffmpeg->c);#endif free(ffmpeg);}/* Puts the image pointed to by ffmpeg->picture. */void ffmpeg_put_image(struct ffmpeg *ffmpeg) { ffmpeg_put_frame(ffmpeg, ffmpeg->picture);}/* Puts an arbitrary picture defined by y, u and v. */void ffmpeg_put_other_image(struct ffmpeg *ffmpeg, unsigned char *y, unsigned char *u, unsigned char *v){ AVFrame *picture; /* allocate the encoded raw picture */ picture = ffmpeg_prepare_frame(ffmpeg, y, u, v); if (picture) { ffmpeg_put_frame(ffmpeg, picture); av_free(picture); }}/* Encodes and writes a video frame using the av_write_frame API. This is * a helper function for ffmpeg_put_image and ffmpeg_put_other_image. */void ffmpeg_put_frame(struct ffmpeg *ffmpeg, AVFrame *pic){ int out_size, ret;#ifdef FFMPEG_AVWRITEFRAME_NEWAPI AVPacket pkt; av_init_packet(&pkt); /* init static structure */ pkt.stream_index = ffmpeg->video_st->index;#endif /* FFMPEG_AVWRITEFRAME_NEWAPI */ if (ffmpeg->oc->oformat->flags & AVFMT_RAWPICTURE) { /* raw video case. The API will change slightly in the near future for that */#ifdef FFMPEG_AVWRITEFRAME_NEWAPI pkt.flags |= PKT_FLAG_KEY; pkt.data = (uint8_t *)pic; pkt.size = sizeof(AVPicture); ret = av_write_frame(ffmpeg->oc, &pkt);#else ret = av_write_frame(ffmpeg->oc, ffmpeg->video_st->index, (uint8_t *)pic, sizeof(AVPicture));#endif /* FFMPEG_AVWRITEFRAME_NEWAPI */ } else { /* encode the image */ out_size = avcodec_encode_video(AVSTREAM_CODEC_PTR(ffmpeg->video_st), ffmpeg->video_outbuf, ffmpeg->video_outbuf_size, pic); /* if zero size, it means the image was buffered */ if (out_size != 0) { /* write the compressed frame in the media file */ /* XXX: in case of B frames, the pts is not yet valid */#ifdef FFMPEG_AVWRITEFRAME_NEWAPI pkt.pts = AVSTREAM_CODEC_PTR(ffmpeg->video_st)->coded_frame->pts; if (AVSTREAM_CODEC_PTR(ffmpeg->video_st)->coded_frame->key_frame) { pkt.flags |= PKT_FLAG_KEY; } pkt.data = ffmpeg->video_outbuf; pkt.size = out_size; ret = av_write_frame(ffmpeg->oc, &pkt);#else ret = av_write_frame(ffmpeg->oc, ffmpeg->video_st->index, ffmpeg->video_outbuf, out_size);#endif /* FFMPEG_AVWRITEFRAME_NEWAPI */ } else { ret = 0; } } if (ret != 0) { motion_log(LOG_ERR, 1, "Error while writing video frame"); return; }}/* Allocates and prepares a picture frame by setting up the U, Y and V pointers in * the frame according to the passed pointers. * * Returns NULL If the allocation fails. * * The returned AVFrame pointer must be freed after use. */AVFrame *ffmpeg_prepare_frame(struct ffmpeg *ffmpeg, unsigned char *y, unsigned char *u, unsigned char *v){ AVFrame *picture; picture = avcodec_alloc_frame(); if (!picture) { motion_log(LOG_ERR, 1, "Could not alloc frame"); return NULL; } /* take care of variable bitrate setting */ if (ffmpeg->vbr) { picture->quality = ffmpeg->vbr; } /* setup pointers and line widths */ picture->data[0] = y; picture->data[1] = u; picture->data[2] = v; picture->linesize[0] = ffmpeg->c->width; picture->linesize[1] = ffmpeg->c->width / 2; picture->linesize[2] = ffmpeg->c->width / 2; return picture;}/** ffmpeg_deinterlace * Make the image suitable for deinterlacing using ffmpeg, then deinterlace the picture. * * Parameters * img image in YUV420P format * width image width in pixels * height image height in pixels * * Returns * Function returns nothing. * img contains deinterlaced image */void ffmpeg_deinterlace(unsigned char *img, int width, int height){ AVFrame *picture; int width2 = width / 2; picture = avcodec_alloc_frame(); if (!picture) { motion_log(LOG_ERR, 1, "Could not alloc frame"); return; } picture->data[0] = img; picture->data[1] = img+width*height; picture->data[2] = picture->data[1]+(width*height)/4; picture->linesize[0] = width; picture->linesize[1] = width2; picture->linesize[2] = width2; /* We assume using 'PIX_FMT_YUV420P' always */ avpicture_deinterlace((AVPicture *)picture, (AVPicture *)picture, PIX_FMT_YUV420P, width, height); av_free(picture); return;}/** ffmpeg_avcodec_log * Handle any logging output from the ffmpeg library avcodec. * * Parameters * *ignoreme A pointer we will ignore * errno_flag The error number value * fmt Text message to be used for log entry in printf() format. * ap List of variables to be used in formatted message text. * * Returns * Function returns nothing. */void ffmpeg_avcodec_log(void *ignoreme ATTRIBUTE_UNUSED, int errno_flag, const char *fmt, va_list vl){ char buf[1024]; /* Do not log the message coming from avcodec if the debug_level is not set. */ if (debug_level) { /* Flatten the message coming in from avcodec */ vsnprintf(buf, sizeof(buf), fmt, vl); /* If the debug_level is correct then send the message to the motion logging routine. */ motion_log(LOG_ERR, 0, "ffmpeg_avcodec_log: %s - flag %d", buf, errno_flag); }}#endif /* HAVE_FFMPEG */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -