source: trunk/lang/tcl/src/RpVideoTclInterface.cc @ 2028

Last change on this file since 2028 was 2028, checked in by dkearney, 10 years ago

video widget updates
various bug fixes

File size: 10.8 KB
Line 
1/*
2 * ----------------------------------------------------------------------
3 *  Rappture::MediaPlayer
4 *
5 *  This is an interface to the rappture movieplayer module.
6 *  It allows you to grab image frames from mpeg movies using ffmpeg.
7 * ======================================================================
8 *  AUTHOR:  Derrick Kearney, Purdue University
9 *  Copyright (c) 2005-2010  Purdue Research Foundation
10 *
11 *  See the file "license.terms" for information on usage and
12 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13 * ======================================================================
14 */
15#include <tcl.h>
16#include <string.h>
17#include "RpVideo.h"
18
19extern "C" Tcl_AppInitProc RpVideo_Init;
20
21#include "RpOp.h"
22
23static Tcl_ObjCmdProc VideoCmd;
24static Tcl_ObjCmdProc VideoCallCmd;
25static Tcl_ObjCmdProc GetOp;
26static Tcl_ObjCmdProc NextOp;
27static Tcl_ObjCmdProc SeekOp;
28static Tcl_ObjCmdProc SizeOp;
29static Tcl_ObjCmdProc ReleaseOp;
30
31static Rp_OpSpec rpVideoOps[] = {
32    {"get",   1, (void *)GetOp, 3, 5, "[image ?width height?]|[position cur|end]|[framerate]",},
33    {"next",  1, (void *)NextOp, 2, 2, "",},
34    {"release", 1, (void *)ReleaseOp, 2, 2, "",},
35    {"seek",  1, (void *)SeekOp, 3, 3, "+n|-n|n",},
36    {"size",  1, (void *)SizeOp, 2, 2, "",},
37};
38
39static int nRpVideoOps = sizeof(rpVideoOps) / sizeof(Rp_OpSpec);
40
41/*
42 * ------------------------------------------------------------------------
43 *  RpVideo_Init()
44 *
45 *  Called in Rappture_Init() to initialize the commands defined
46 *  in this file.
47 * ------------------------------------------------------------------------
48 */
49int
50RpVideo_Init(Tcl_Interp *interp)
51{
52
53    Tcl_CreateObjCommand(interp, "::Rappture::Video",
54        VideoCmd, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
55
56    return TCL_OK;
57}
58
59/*
60 * USAGE: Video <type> <data>
61 */
62static int
63VideoCmd(ClientData clientData, Tcl_Interp *interp, int objc,
64       Tcl_Obj* const *objv)
65{
66    char cmdName[64];
67    static int movieCount = 0;
68    const char *type = NULL;
69    const char *data = NULL;
70    int err = 0;
71
72    if (objc != 3) {
73        Tcl_AppendResult(interp, "wrong # args: should be \"",
74            "Video <type> <data>\"", (char*)NULL);
75        return TCL_ERROR;
76    }
77
78    type = Tcl_GetString(objv[1]);
79    data = Tcl_GetString(objv[2]);
80
81    // create a new command
82    VideoObj *movie = NULL;
83    movie = VideoInitCmd();
84    if (movie == NULL) {
85        Tcl_AppendResult(interp, "error while creating movie object", "\n",
86                         "VideoInitCmd(movie);", (char*)NULL);
87        return TCL_ERROR;
88    }
89
90    if ((*type == 'd') && (strcmp(type,"data") == 0)) {
91        Tcl_AppendResult(interp, "error while creating movie: type == data not supported",
92                         "\n", "VideoInitCmd(movie);", (char*)NULL);
93        return TCL_ERROR;
94    } else if ((*type == 'f') && (strcmp(type,"file") == 0)) {
95        err = VideoOpenFile(movie,data,"r");
96        if (err) {
97            Tcl_AppendResult(interp, "error while creating movie object: ",
98                             "\n", "VideoInitCmd(movie);", (char*)NULL);
99            return TCL_ERROR;
100        }
101    }
102
103    sprintf(cmdName,"::movieObj%d",movieCount);
104    movieCount++;
105
106    Tcl_CreateObjCommand(interp, cmdName, VideoCallCmd,
107        (ClientData)movie, (Tcl_CmdDeleteProc*)NULL);
108
109    Tcl_AppendResult(interp, cmdName, (char*)NULL);
110    return TCL_OK;
111}
112
113
114static int
115VideoCallCmd(ClientData clientData, Tcl_Interp *interp, int objc,
116           Tcl_Obj *const *objv)
117{
118    Tcl_ObjCmdProc *proc;
119
120    proc = (Tcl_ObjCmdProc *)Rp_GetOpFromObj(interp, nRpVideoOps, rpVideoOps,
121        RP_OP_ARG1, objc, objv, 0);
122
123    if (proc == NULL) {
124        return TCL_ERROR;
125    }
126    return (*proc)(clientData, interp, objc, objv);
127}
128
129/**********************************************************************/
130// FUNCTION: GetOp()
131/// Get info about the video
132/**
133 * Full function call:
134 *
135 * get position cur
136 * get position end
137 * get image ?width height?
138 * get framerate
139 * get filename
140 *
141 */
142static int
143GetOp (ClientData clientData, Tcl_Interp *interp, int objc,
144         Tcl_Obj *const *objv)
145{
146    const char *cmd = Tcl_GetString(objv[1]);
147
148    /*
149     * Decode the first arg and figure out how we're supposed to advance.
150     */
151    if (objc > 5) {
152        Tcl_AppendResult(interp, "wrong # args: should be \"", cmd,
153            " [image width height]|[position cur|end]\"", (char*)NULL);
154        return TCL_ERROR;
155    }
156
157    const char *info = Tcl_GetString(objv[2]);
158    if ((*info == 'p') && (strcmp(info,"position") == 0)) {
159        if (objc != 4) {
160            Tcl_AppendResult(interp, "wrong # args: should be \"", cmd,
161                " position cur|end\"", (char*)NULL);
162            return TCL_ERROR;
163        }
164        const char *which = Tcl_GetString(objv[3]);
165        if ((*which == 'c') && (strcmp(which,"cur") == 0)) {
166            int pos = 0;
167            VideoGetPositionCur((VideoObj *)clientData,&pos);
168            Tcl_SetObjResult(interp, Tcl_NewIntObj(pos));
169        }
170        else if ((*which == 'e') && (strcmp(which,"end") == 0)) {
171            int pos = 0;
172            VideoGetPositionEnd((VideoObj *)clientData,&pos);
173            Tcl_SetObjResult(interp, Tcl_NewIntObj(pos));
174        }
175        else {
176            Tcl_AppendResult(interp, "unrecognized command: \"", which,
177                "\" should be one of cur,end ", (char*)NULL);
178            return TCL_ERROR;
179        }
180    }
181    else if ((*info == 'i') && (strcmp(info,"image") == 0)) {
182        if ((objc != 3) && (objc != 5)) {
183            Tcl_AppendResult(interp, "wrong # args: should be \"", cmd,
184                " image ?width height?\"", (char*)NULL);
185            return TCL_ERROR;
186        }
187
188        void *img = NULL;
189        int width = -1;
190        int height = -1;
191        int bufSize = 0;
192
193        if (objc == 5) {
194            Tcl_GetIntFromObj(interp, objv[3], &width);
195            Tcl_GetIntFromObj(interp, objv[4], &height);
196        }
197
198        VideoGetImage((VideoObj *)clientData, width, height, &img, &bufSize);
199
200        Tcl_SetByteArrayObj(Tcl_GetObjResult(interp),
201                            (const unsigned char*)img, bufSize);
202    }
203    else if ((*info == 'f') && (strcmp(info,"framerate") == 0)) {
204        if (objc != 3) {
205            Tcl_AppendResult(interp, "wrong # args: should be \"", cmd,
206                " framerate\"", (char*)NULL);
207            return TCL_ERROR;
208        }
209
210        double fr = 0;
211        int err = 0;
212
213        err = VideoGetFrameRate((VideoObj *)clientData, &fr);
214        if (err) {
215            Tcl_AppendResult(interp, "error while calculating framerate",
216                (char*)NULL);
217            return TCL_ERROR;
218        }
219        Tcl_SetObjResult(interp, Tcl_NewDoubleObj(fr));
220    }
221    else if ((*info == 'f') && (strcmp(info,"filename") == 0)) {
222        if (objc != 3) {
223            Tcl_AppendResult(interp, "wrong # args: should be \"", cmd,
224                " filename\"", (char*)NULL);
225            return TCL_ERROR;
226        }
227
228        const char *fname = NULL;
229        int err = 0;
230
231        err = VideoGetFileName((VideoObj *)clientData, &fname);
232        if (err) {
233            Tcl_AppendResult(interp, "error while retrieving filename",
234                (char*)NULL);
235            return TCL_ERROR;
236        }
237        Tcl_AppendResult(interp, fname, (char*)NULL);
238    }
239    else {
240        Tcl_AppendResult(interp, "unrecognized command \"", info, "\": should be \"", cmd,
241            " [image width height]|[position cur|end]|[framerate]\"", (char*)NULL);
242        return TCL_ERROR;
243    }
244
245
246    return TCL_OK;
247}
248
249
250/**********************************************************************/
251// FUNCTION: NextOp()
252/// Get the next frame from a video
253/**
254 * Return the next frame from a video as an image
255 * Full function call:
256 *
257 * next
258 *
259 */
260static int
261NextOp (ClientData clientData, Tcl_Interp *interp, int objc,
262         Tcl_Obj *const *objv)
263{
264    int pos = 0;
265    VideoGoNext((VideoObj *)clientData);
266    VideoGetPositionCur((VideoObj *)clientData,&pos);
267    Tcl_SetObjResult(interp, Tcl_NewIntObj(pos));
268
269    return TCL_OK;
270}
271
272/**********************************************************************/
273// FUNCTION: SeekOp()
274/// Get the next frame from a video
275/**
276 * Return the frame specified, or at the specified offset, as an image
277 * Full function call:
278 *
279 * seek +5
280 * seek -5
281 * seek 22
282 *
283 */
284static int
285SeekOp (ClientData clientData, Tcl_Interp *interp, int objc,
286         Tcl_Obj *const *objv)
287{
288    const char *val_s = NULL;
289    int val = 0;
290    int pos = 0;
291
292    val_s = Tcl_GetString(objv[2]);
293    if (*val_s == '+') {
294        if (Tcl_GetInt(interp, val_s+1, &val) != TCL_OK) {
295            Tcl_AppendResult(interp, "bad value \"", val_s,
296                "\": should be next, +n, -n, or n", (char*)NULL);
297            return TCL_ERROR;
298        }
299        VideoGoPlusMinusN((VideoObj *)clientData, val);
300    }
301    else if (*val_s == '-') {
302        if (Tcl_GetInt(interp, val_s, &val) != TCL_OK) {
303            Tcl_AppendResult(interp, "bad value \"", val_s,
304                "\": should be next, +n, -n, or n", (char*)NULL);
305            return TCL_ERROR;
306        }
307        VideoGoPlusMinusN((VideoObj *)clientData, val);
308    }
309    else if (Tcl_GetInt(interp, val_s, &val) != TCL_OK) {
310        Tcl_AppendResult(interp, "bad value \"", val_s,
311            "\": should be next, +n, -n, or n", (char*)NULL);
312        return TCL_ERROR;
313    }
314    else {
315        int c = 0;
316        c = VideoGoToN((VideoObj *)clientData, val);
317    }
318
319    VideoGetPositionCur((VideoObj *)clientData,&pos);
320    Tcl_SetObjResult(interp, Tcl_NewIntObj(pos));
321
322    return TCL_OK;
323}
324
325/**********************************************************************/
326// FUNCTION: SizeOp()
327/// Get the size of the video
328/**
329 * Return the original size of the video frame
330 *
331 * Full function call:
332 *
333 * size
334 *
335 */
336static int
337SizeOp (ClientData clientData, Tcl_Interp *interp, int objc,
338         Tcl_Obj *const *objv)
339{
340
341    int width = 0;
342    int height = 0;
343    int err = 0;
344    Tcl_Obj *dim = NULL;
345
346
347    err = VideoSizeCmd((VideoObj *)clientData,&width,&height);
348
349    if (err) {
350        Tcl_AppendResult(interp, "error while calculating size of video",
351            (char*)NULL);
352        return TCL_ERROR;
353    }
354
355
356    dim = Tcl_NewListObj(0, NULL);
357    Tcl_ListObjAppendElement(interp, dim, Tcl_NewIntObj(width));
358    Tcl_ListObjAppendElement(interp, dim, Tcl_NewIntObj(height));
359    Tcl_SetObjResult(interp, dim);
360
361    return TCL_OK;
362}
363
364/**********************************************************************/
365// FUNCTION: ReleaseOp()
366/// Clean up memory from an open video in a movie player object
367/**
368 * Close all file handles and free allocated memory associated with an
369 * open video in a movie player object.
370 * Full function call:
371 *
372 * close
373 *
374 */
375static int
376ReleaseOp (ClientData clientData, Tcl_Interp *interp, int objc,
377         Tcl_Obj *const *objv)
378{
379    VideoClose((VideoObj *)clientData);
380
381    Tcl_ResetResult(interp);
382    return TCL_OK;
383}
Note: See TracBrowser for help on using the repository browser.