首页 > 其他 > 详细

motion源码分析(二)——录像

时间:2014-04-11 17:53:41      阅读:673      评论:0      收藏:0      [点我收藏+]

前言:

之前的博文将ffmpeg编入motion的结尾,提到了motion的一些简单的应用。本文将以录像为契入点,分析这部分的代码。


正文:

刷照片的效果实在太挫了,让我们看看如何打开ffmpeg录像的配置。这里需要修改motion-dist.conf中的两个选项(采用默认值则不会录像):

# Use ffmpeg to encode a timelapse movie 
# Default value 0 = off - else save frame every Nth second
ffmpeg_timelapse 1


# Enables and defines variable bitrate for the ffmpeg encoder.
# ffmpeg_bps is ignored if variable bitrate is enabled.
# Valid values: 0 (default) = fixed bitrate defined by ffmpeg_bps,
# or the range 2 - 31 where 2 means best quality and 31 is worst.
ffmpeg_variable_bitrate 1
第一个选项是设置每一秒保存帧(帧的数量由配置文件中的framerate决定 ),第二个选项设置ffmpeg编码的比特率。下面还有个选项:
# Codec to used by ffmpeg for the video compression.
# Timelapse mpegs are always made in mpeg1 format independent from this option.
# Supported formats are: mpeg1 (ffmpeg-0.4.8 only), mpeg4 (default), and msmpeg4.
# mpeg1 - gives you files with extension .mpg
# mpeg4 or msmpeg4 - gives you files with extension .avi
# msmpeg4 is recommended for use with Windows Media Player because
# it requires no installation of codec on the Windows client.
# swf - gives you a flash film with extension .swf
# flv - gives you a flash video with extension .flv
# ffv1 - FF video codec 1 for Lossless Encoding ( experimental )
# mov - QuickTime ( testing )
ffmpeg_video_codec mpeg4

这个其实该不该无所谓,因为编码器的格式在里面是写死的,稍后会提到。motion的录像在motion_loop(motion.c:1698)当中:

#ifdef HAVE_FFMPEG



        if (cnt->conf.timelapse) {

            /* Check to see if we should start a new timelapse file. We start one when
             * we are on the first shot, and and the seconds are zero. We must use the seconds
             * to prevent the timelapse file from getting reset multiple times during the minute.
             */
            if (cnt->current_image->timestamp_tm.tm_min == 0 &&
                (time_current_frame % 60 < time_last_frame % 60) &&
                cnt->shots == 0) {

                if (strcasecmp(cnt->conf.timelapse_mode,"manual") == 0) {
                    ;/* No action */

                /* If we are daily, raise timelapseend event at midnight */
                } else if (strcasecmp(cnt->conf.timelapse_mode, "daily") == 0) {  //根据配置文件中ffmpeg_timelapse_mode的选则执行相应代码
                    if (cnt->current_image->timestamp_tm.tm_hour == 0)
                        event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, 
                              &cnt->current_image->timestamp_tm);

                /* handle the hourly case */
                } else if (strcasecmp(cnt->conf.timelapse_mode, "hourly") == 0) {
                    event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, 
                          &cnt->current_image->timestamp_tm);

                /* If we are weekly-sunday, raise timelapseend event at midnight on sunday */
                } else if (strcasecmp(cnt->conf.timelapse_mode, "weekly-sunday") == 0) {
                    if (cnt->current_image->timestamp_tm.tm_wday == 0 && cnt->current_image->timestamp_tm.tm_hour == 0)
                        event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tm);

                /* If we are weekly-monday, raise timelapseend event at midnight on monday */    
                } else if (strcasecmp(cnt->conf.timelapse_mode, "weekly-monday") == 0) {
                    if (cnt->current_image->timestamp_tm.tm_wday == 1 && cnt->current_image->timestamp_tm.tm_hour == 0)
                        event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tm);

                /* If we are monthly, raise timelapseend event at midnight on first day of month */    
                } else if (strcasecmp(cnt->conf.timelapse_mode, "monthly") == 0) {
                    if (cnt->current_image->timestamp_tm.tm_mday == 1 && cnt->current_image->timestamp_tm.tm_hour == 0)
                        event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tm);

                /* If invalid we report in syslog once and continue in manual mode */    
                } else {
                    motion_log(LOG_ERR, 0, "Invalid timelapse_mode argument ‘%s‘",
                               cnt->conf.timelapse_mode);
                    motion_log(LOG_ERR, 0, "Defaulting to manual timelapse mode");
                    conf_cmdparse(&cnt, (char *)"ffmpeg_timelapse_mode",(char *)"manual");
                }
            }

            /* If ffmpeg timelapse is enabled and time since epoch MOD ffmpeg_timelaps = 0
             * add a timelapse frame to the timelapse mpeg.
             */
            if (cnt->shots == 0 &&
                time_current_frame % cnt->conf.timelapse <= time_last_frame % cnt->conf.timelapse)
                event(cnt, EVENT_TIMELAPSE, cnt->current_image->image, NULL, NULL, 
                      &cnt->current_image->timestamp_tm);     // Line:1757 在这里创建并保存录制的视频
        } else if (cnt->ffmpeg_timelapse) {
        /* if timelapse mpeg is in progress but conf.timelapse is zero then close timelapse file
         * This is an important feature that allows manual roll-over of timelapse file using the http
         * remote control via a cron job.
         */
            event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, cnt->currenttime_tm); 
        }

#endif /* HAVE_FFMPEG */
执行录制视频的方法在1757行,根据EVENT_TIMELAPSE,它对应的方法叫event_ffmpeg_timelapse

// event.c:673

{
EVENT_TIMELAPSE,
event_ffmpeg_timelapse
},
// event.c:461

static void event_ffmpeg_timelapse(struct context *cnt,
            int type ATTRIBUTE_UNUSED, unsigned char *img,
            char *dummy1 ATTRIBUTE_UNUSED, void *dummy2 ATTRIBUTE_UNUSED,
            struct tm *currenttime_tm)
{
    int width = cnt->imgs.width;
    int height = cnt->imgs.height;
    unsigned char *convbuf, *y, *u, *v;

    if (!cnt->ffmpeg_timelapse) {  //只在第一次创建时执行
        char tmp[PATH_MAX];
        const char *timepath;

        /* conf.timepath would normally be defined but if someone deleted it by control interface
           it is better to revert to the default than fail */
        if (cnt->conf.timepath)
            timepath = cnt->conf.timepath;
        else
            timepath = DEF_TIMEPATH;
        
        mystrftime(cnt, tmp, sizeof(tmp), timepath, currenttime_tm, NULL, 0);
        
        /* PATH_MAX - 4 to allow for .mpg to be appended without overflow */
        snprintf(cnt->timelapsefilename, PATH_MAX - 4, "%s/%s", cnt->conf.filepath, tmp);
        
        if (cnt->imgs.type == VIDEO_PALETTE_GREY) {
            convbuf = mymalloc((width * height) / 2);
            y = img;
            u = convbuf;
            v = convbuf+(width * height) / 4;
            grey2yuv420p(u, v, width, height);
        } else {
            convbuf = NULL;
            y = img;
            u = img + width * height;
            v = u + (width * height) / 4;
        }
        
        if ((cnt->ffmpeg_timelapse =
             ffmpeg_open((char *)TIMELAPSE_CODEC, cnt->timelapsefilename, y, u, v,   //#define TIMELAPSE_CODEC "mpeg1_tl"
                         cnt->imgs.width, cnt->imgs.height, 24, cnt->conf.ffmpeg_bps,
                         cnt->conf.ffmpeg_vbr)) == NULL) {   // 创建录像文件
            motion_log(LOG_ERR, 1, "ffopen_open error creating (timelapse) file [%s]", cnt->timelapsefilename);
            cnt->finish = 1;
            return;
        }
        
        cnt->ffmpeg_timelapse->udata = convbuf;
        event(cnt, EVENT_FILECREATE, NULL, cnt->timelapsefilename, (void *)FTYPE_MPEG_TIMELAPSE, NULL);
    }
    
    y = img;
    
    if (cnt->imgs.type == VIDEO_PALETTE_GREY)
        u = cnt->ffmpeg_timelapse->udata;
    else
        u = img + width * height;
    
    v = u + (width * height) / 4;
    ffmpeg_put_other_image(cnt->ffmpeg_timelapse, y, u, v);  //put图像进录像
    
}
其中Line:500,如果是第一次进入,则执行ffmpeg_open:

ffmpeg_open((char *)TIMELAPSE_CODEC,                                // #define TIMELAPSE_CODEC "mpeg1_tl"
                     cnt->timelapsefilename,                                    // 录像文件名
                      y, u, v,//#define TIMELAPSE_CODEC "mpeg1_tl" 
                      cnt->imgs.width, cnt->imgs.height,                   // 录像的宽高
                      24,                                                                 // fps 
                      cnt->conf.ffmpeg_bps,                                    // bps
                      cnt->conf.ffmpeg_vbr)) == NULL)
如果不是第一次进入,则会直接执行ffmpeg_put_other_image将图像加入录像。






motion源码分析(二)——录像,布布扣,bubuko.com

motion源码分析(二)——录像

原文:http://blog.csdn.net/sakaue/article/details/23338471

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!