~ubuntu-branches/ubuntu/intrepid/zoneminder/intrepid

« back to all changes in this revision

Viewing changes to src/zm_stream.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Peter Howard
  • Date: 2008-09-18 01:02:50 UTC
  • mfrom: (3.1.4 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080918010250-4w7nrqu48pv32l5b
Tags: 1.23.3-3
* ffmpeg confirmed  working
  (closes: #475145)
* Fix upgrade problem intrudouced in 1.23.3-1
  (closes: #481637)
* Include libmime-lite-perl in dependencies
  (closes: #486312)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// ZoneMinder Stream Class Implementation, $Date: 2008-03-13 13:36:12 +0000 (Thu, 13 Mar 2008) $, $Revision: 2357 $
 
3
// Copyright (C) 2003, 2004, 2005, 2006  Philip Coombes
 
4
//
 
5
// This program is free software; you can redistribute it and/or
 
6
// modify it under the terms of the GNU General Public License
 
7
// as published by the Free Software Foundation; either version 2
 
8
// of the License, or (at your option) any later version.
 
9
//
 
10
// This program is distributed in the hope that it will be useful,
 
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
// GNU General Public License for more details.
 
14
//
 
15
// You should have received a copy of the GNU General Public License
 
16
// along with this program; if not, write to the Free Software
 
17
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
18
//
 
19
 
 
20
#include <sys/un.h>
 
21
 
 
22
#include "zm.h"
 
23
#include "zm_mpeg.h"
 
24
#include "zm_monitor.h"
 
25
 
 
26
#include "zm_stream.h"
 
27
 
 
28
StreamBase::~StreamBase()
 
29
{
 
30
    closeComms();
 
31
}
 
32
 
 
33
bool StreamBase::loadMonitor( int monitor_id )
 
34
{
 
35
    if ( !(monitor = Monitor::Load( monitor_id, false, Monitor::QUERY )) )
 
36
    {
 
37
        Fatal(( "Unable to load monitor id %d for streaming", monitor_id ));
 
38
        return( false );
 
39
    }
 
40
    return( true );
 
41
}
 
42
 
 
43
bool StreamBase::checkInitialised()
 
44
{
 
45
    if ( !monitor )
 
46
    {
 
47
        Fatal(( "Cannot stream, not initialised" ));
 
48
        return( false );
 
49
    }
 
50
    return( true );
 
51
}
 
52
 
 
53
void StreamBase::updateFrameRate( double fps )
 
54
{
 
55
    base_fps = (int)(fps);
 
56
    effective_fps = (base_fps*abs(replay_rate))/ZM_RATE_BASE;
 
57
    frame_mod = 1;
 
58
    Debug( 3, ( "FPS:%.2f, MXFPS:%d, BFPS:%d, EFPS:%d, FM:%d", fps, maxfps, base_fps, effective_fps, frame_mod ));
 
59
    // Min frame repeat?
 
60
    while( effective_fps > maxfps )
 
61
    {
 
62
        effective_fps /= 2;
 
63
        frame_mod *= 2;
 
64
    }
 
65
    Debug( 3, ( "aEFPS:%d, aFM:%d", effective_fps, frame_mod ));
 
66
}
 
67
 
 
68
bool StreamBase::checkCommandQueue()
 
69
{
 
70
    if ( sd >= 0 )
 
71
    {
 
72
        CmdMsg msg;
 
73
        memset( &msg, 0, sizeof(msg) );
 
74
        int nbytes = recvfrom( sd, &msg, sizeof(msg), MSG_DONTWAIT, 0, 0 );
 
75
        if ( nbytes < 0 )
 
76
        {
 
77
            if ( errno != EAGAIN )
 
78
            {
 
79
                Fatal(( "recvfrom(), errno = %d, error = %s", errno, strerror(errno) ));
 
80
            }
 
81
        }
 
82
        //else if ( (nbytes != sizeof(msg)) )
 
83
        //{
 
84
            //Error(( "Partial message received, expected %d bytes, got %d", sizeof(msg), nbytes ));
 
85
        //}
 
86
        else
 
87
        {
 
88
            processCommand( &msg );
 
89
            return( true );
 
90
        }
 
91
    }
 
92
    return( false );
 
93
}
 
94
 
 
95
Image *StreamBase::prepareImage( Image *image )
 
96
{
 
97
    static int last_scale = 0;
 
98
    static int last_zoom = 0;
 
99
    static int last_x = 0;
 
100
    static int last_y = 0;
 
101
 
 
102
    if ( !last_scale )
 
103
        last_scale = scale;
 
104
    if ( !last_zoom )
 
105
        last_zoom = zoom;
 
106
 
 
107
    bool image_copied = false;
 
108
 
 
109
    int mag = (scale * zoom) / ZM_SCALE_BASE;
 
110
    int act_mag = mag > ZM_SCALE_BASE?ZM_SCALE_BASE:mag;
 
111
    Debug( 3, ( "Scaling by %d, zooming by %d = magnifying by %d(%d)", scale, zoom, mag, act_mag ));
 
112
 
 
113
    int last_mag = (last_scale * last_zoom) / ZM_SCALE_BASE;
 
114
    int last_act_mag = last_mag > ZM_SCALE_BASE?ZM_SCALE_BASE:last_mag;
 
115
    Debug( 3, ( "Last scaling by %d, zooming by %d = magnifying by %d(%d)", last_scale, last_zoom, last_mag, last_act_mag ));
 
116
 
 
117
    int base_image_width = image->Width(), base_image_height = image->Height();
 
118
    Debug( 3, ( "Base image width = %d, height = %d", base_image_width, base_image_height ));
 
119
 
 
120
    int virt_image_width = (base_image_width * mag) / ZM_SCALE_BASE, virt_image_height = (base_image_height * mag) / ZM_SCALE_BASE;
 
121
    Debug( 3, ( "Virtual image width = %d, height = %d", virt_image_width, virt_image_height ));
 
122
 
 
123
    int last_virt_image_width = (base_image_width * last_mag) / ZM_SCALE_BASE, last_virt_image_height = (base_image_height * last_mag) / ZM_SCALE_BASE;
 
124
    Debug( 3, ( "Last virtual image width = %d, height = %d", last_virt_image_width, last_virt_image_height ));
 
125
 
 
126
    int act_image_width = (base_image_width * act_mag ) / ZM_SCALE_BASE, act_image_height = (base_image_height * act_mag ) / ZM_SCALE_BASE;
 
127
    Debug( 3, ( "Actual image width = %d, height = %d", act_image_width, act_image_height ));
 
128
 
 
129
    int last_act_image_width = (base_image_width * last_act_mag ) / ZM_SCALE_BASE, last_act_image_height = (base_image_height * last_act_mag ) / ZM_SCALE_BASE;
 
130
    Debug( 3, ( "Last actual image width = %d, height = %d", last_act_image_width, last_act_image_height ));
 
131
 
 
132
    int disp_image_width = (image->Width() * scale) / ZM_SCALE_BASE, disp_image_height = (image->Height() * scale) / ZM_SCALE_BASE;
 
133
    Debug( 3, ( "Display image width = %d, height = %d", disp_image_width, disp_image_height ));
 
134
 
 
135
    int last_disp_image_width = (image->Width() * last_scale) / ZM_SCALE_BASE, last_disp_image_height = (image->Height() * last_scale) / ZM_SCALE_BASE;
 
136
    Debug( 3, ( "Last display image width = %d, height = %d", last_disp_image_width, last_disp_image_height ));
 
137
 
 
138
    int send_image_width = (disp_image_width * act_mag ) / mag, send_image_height = (disp_image_height * act_mag ) / mag;
 
139
    Debug( 3, ( "Send image width = %d, height = %d", send_image_width, send_image_height ));
 
140
 
 
141
    int last_send_image_width = (last_disp_image_width * last_act_mag ) / last_mag, last_send_image_height = (last_disp_image_height * last_act_mag ) / last_mag;
 
142
    Debug( 3, ( "Last send image width = %d, height = %d", last_send_image_width, last_send_image_height ));
 
143
 
 
144
    if ( mag != ZM_SCALE_BASE )
 
145
    {
 
146
        Debug( 3, ( "Magnifying by %d", mag ));
 
147
        if ( act_mag < ZM_SCALE_BASE )
 
148
        {
 
149
            if ( !image_copied )
 
150
            {
 
151
                    static Image copy_image;
 
152
                copy_image.Assign( *image );
 
153
                image = &copy_image;
 
154
                image_copied = true;
 
155
            }
 
156
            image->Scale( mag );
 
157
        }
 
158
    }
 
159
 
 
160
    Debug( 3, ( "Real image width = %d, height = %d", image->Width(), image->Height() ));
 
161
 
 
162
    if ( disp_image_width < virt_image_width || disp_image_height < virt_image_height )
 
163
    {
 
164
        Debug( 3, ( "Got click at %d,%d", x, y ));
 
165
        static Box last_crop;
 
166
 
 
167
        if ( mag != last_mag || x != last_x || y != last_y )
 
168
        {
 
169
            //if ( !last_mag )
 
170
                //last_mag = mag;
 
171
 
 
172
            if ( !(last_disp_image_width < last_virt_image_width || last_disp_image_height < last_virt_image_height) )
 
173
                last_crop = Box();
 
174
 
 
175
            Debug( 3, ( "Recalculating crop" ));
 
176
            // Recalculate crop parameters, as %ges
 
177
            int click_x = (last_crop.LoX() * 100 ) / last_act_image_width; // Initial crop offset from last image
 
178
            click_x += ( x * 100 ) / last_virt_image_width;
 
179
            int click_y = (last_crop.LoY() * 100 ) / last_act_image_height; // Initial crop offset from last image
 
180
            click_y += ( y * 100 ) / last_virt_image_height;
 
181
            Debug( 3, ( "Got adjusted click at %d%%,%d%%", click_x, click_y ));
 
182
 
 
183
            // Convert the click locations to the current image pixels
 
184
            click_x = ( click_x * act_image_width ) / 100;
 
185
            click_y = ( click_y * act_image_height ) / 100;
 
186
            Debug( 3, ( "Got readjusted click at %d,%d", click_x, click_y ));
 
187
 
 
188
            int lo_x = click_x - (send_image_width/2);
 
189
            if ( lo_x < 0 )
 
190
                lo_x = 0;
 
191
            int hi_x = lo_x + (send_image_width-1);
 
192
            if ( hi_x >= act_image_width )
 
193
            {
 
194
                hi_x = act_image_width - 1;
 
195
                lo_x = hi_x - (send_image_width - 1);
 
196
            }
 
197
 
 
198
            int lo_y = click_y - (send_image_height/2);
 
199
            if ( lo_y < 0 )
 
200
                lo_y = 0;
 
201
            int hi_y = lo_y + (send_image_height-1);
 
202
            if ( hi_y >= act_image_height )
 
203
            {
 
204
                hi_y = act_image_height - 1;
 
205
                lo_y = hi_y - (send_image_height - 1);
 
206
            }
 
207
            last_crop = Box( lo_x, lo_y, hi_x, hi_y );
 
208
        }
 
209
        Debug( 3, ( "Cropping to %d,%d -> %d,%d", last_crop.LoX(), last_crop.LoY(), last_crop.HiX(), last_crop.HiY() ));
 
210
        if ( !image_copied )
 
211
        {
 
212
                static Image copy_image;
 
213
            copy_image.Assign( *image );
 
214
            image = &copy_image;
 
215
            image_copied = true;
 
216
        }
 
217
        image->Crop( last_crop );
 
218
    }
 
219
    last_scale = scale;
 
220
    last_zoom = zoom;
 
221
    last_x = x;
 
222
    last_y = y;
 
223
 
 
224
    return( image );
 
225
}
 
226
 
 
227
void StreamBase::sendTextFrame( const char *frame_text )
 
228
{
 
229
    Debug( 2, ( "Sending text frame '%s'", frame_text ));
 
230
 
 
231
    Image image( monitor->Width(), monitor->Height(), monitor->Colours() );
 
232
    image.Annotate( frame_text, image.centreCoord( frame_text ) );
 
233
 
 
234
    if ( scale != 100 )
 
235
    {
 
236
        image.Scale( scale );
 
237
    }
 
238
#if HAVE_LIBAVCODEC
 
239
    if ( type == STREAM_MPEG )
 
240
    {
 
241
        if ( !vid_stream )
 
242
        {
 
243
            vid_stream = new VideoStream( "pipe:", format, bitrate, effective_fps, image.Colours(), image.Width(), image.Height() );
 
244
            fprintf( stdout, "Content-type: %s\r\n\r\n", vid_stream->MimeType() );
 
245
            vid_stream->OpenStream();
 
246
        }
 
247
        /* double pts = */ vid_stream->EncodeFrame( image.Buffer(), image.Size() );
 
248
    }
 
249
    else
 
250
#endif // HAVE_LIBAVCODEC
 
251
    {
 
252
        static unsigned char buffer[ZM_MAX_IMAGE_SIZE];
 
253
        int n_bytes = 0;
 
254
 
 
255
        image.EncodeJpeg( buffer, &n_bytes );
 
256
 
 
257
        fprintf( stdout, "--ZoneMinderFrame\r\n" );
 
258
        fprintf( stdout, "Content-Length: %d\r\n", n_bytes );
 
259
        fprintf( stdout, "Content-Type: image/jpeg\r\n\r\n" );
 
260
        fwrite( buffer, n_bytes, 1, stdout );
 
261
        fprintf( stdout, "\r\n\r\n" );
 
262
        fflush( stdout );
 
263
    }
 
264
    last_frame_sent = TV_2_FLOAT( now );
 
265
}
 
266
 
 
267
void StreamBase::openComms()
 
268
{
 
269
    if ( connkey > 0 )
 
270
    {
 
271
        sd = socket( AF_UNIX, SOCK_DGRAM, 0 );
 
272
        if ( sd < 0 )
 
273
        {
 
274
            Fatal(( "Can't create socket: %s", strerror(errno) ));
 
275
        }
 
276
 
 
277
        snprintf( loc_sock_path, sizeof(loc_sock_path), "%s/zms-%06ds.sock", config.path_socks, connkey );
 
278
        unlink( loc_sock_path );
 
279
 
 
280
        strncpy( loc_addr.sun_path, loc_sock_path, sizeof(loc_addr.sun_path) );
 
281
        loc_addr.sun_family = AF_UNIX;
 
282
        if ( bind( sd, (struct sockaddr *)&loc_addr, strlen(loc_addr.sun_path)+sizeof(loc_addr.sun_family)) < 0 )
 
283
        {
 
284
            Fatal(( "Can't bind: %s", strerror(errno) ));
 
285
        }
 
286
 
 
287
        snprintf( rem_sock_path, sizeof(rem_sock_path), "%s/zms-%06dw.sock", config.path_socks, connkey );
 
288
        strncpy( rem_addr.sun_path, rem_sock_path, sizeof(rem_addr.sun_path) );
 
289
        rem_addr.sun_family = AF_UNIX;
 
290
    }
 
291
}
 
292
 
 
293
void StreamBase::closeComms()
 
294
{
 
295
    if ( connkey > 0 )
 
296
    {
 
297
        if ( sd >= 0 )
 
298
        {
 
299
            close( sd );
 
300
            sd = -1;
 
301
        }
 
302
        if ( loc_sock_path[0] )
 
303
        {
 
304
            unlink( loc_sock_path );
 
305
        }
 
306
    }
 
307
}
 
308