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

Last change on this file since 2023 was 2023, checked in by dkearney, 13 years ago

updates for video widgets
two new video dials
video chooser widget for selecting movies
video preview widget is a no frills movie player.
updated c code to more correctly report the last frame of the movie.
new video speed widget which allows for fractional values between 0x and 1.0x
updated piv/pve example application
fixed "release" function in tcl bindings for RpVideo?

File size: 10.2 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 *
140 */
141static int
142GetOp (ClientData clientData, Tcl_Interp *interp, int objc,
143         Tcl_Obj *const *objv)
144{
145    const char *cmd = Tcl_GetString(objv[1]);
146
147    /*
148     * Decode the first arg and figure out how we're supposed to advance.
149     */
150    if (objc > 5) {
151        Tcl_AppendResult(interp, "wrong # args: should be \"", cmd,
152            " [image width height]|[position cur|end]\"", (char*)NULL);
153        return TCL_ERROR;
154    }
155
156    const char *info = Tcl_GetString(objv[2]);
157    if ((*info == 'p') && (strcmp(info,"position") == 0)) {
158        if (objc != 4) {
159            Tcl_AppendResult(interp, "wrong # args: should be \"", cmd,
160                " position cur|end\"", (char*)NULL);
161            return TCL_ERROR;
162        }
163        const char *which = Tcl_GetString(objv[3]);
164        if ((*which == 'c') && (strcmp(which,"cur") == 0)) {
165            int pos = 0;
166            VideoGetPositionCur((VideoObj *)clientData,&pos);
167            Tcl_SetObjResult(interp, Tcl_NewIntObj(pos));
168        }
169        else if ((*which == 'e') && (strcmp(which,"end") == 0)) {
170            int pos = 0;
171            VideoGetPositionEnd((VideoObj *)clientData,&pos);
172            Tcl_SetObjResult(interp, Tcl_NewIntObj(pos));
173        }
174        else {
175            Tcl_AppendResult(interp, "unrecognized command: \"", which,
176                "\" should be one of cur,end ", (char*)NULL);
177            return TCL_ERROR;
178        }
179    }
180    else if ((*info == 'i') && (strcmp(info,"image") == 0)) {
181        if ((objc != 3) && (objc != 5)) {
182            Tcl_AppendResult(interp, "wrong # args: should be \"", cmd,
183                " image ?width height?\"", (char*)NULL);
184            return TCL_ERROR;
185        }
186
187        void *img = NULL;
188        int width = -1;
189        int height = -1;
190        int bufSize = 0;
191
192        if (objc == 5) {
193            Tcl_GetIntFromObj(interp, objv[3], &width);
194            Tcl_GetIntFromObj(interp, objv[4], &height);
195        }
196
197        VideoGetImage((VideoObj *)clientData, width, height, &img, &bufSize);
198
199        Tcl_SetByteArrayObj(Tcl_GetObjResult(interp),
200                            (const unsigned char*)img, bufSize);
201    }
202    else if ((*info == 'f') && (strcmp(info,"framerate") == 0)) {
203        if (objc != 3) {
204            Tcl_AppendResult(interp, "wrong # args: should be \"", cmd,
205                " framerate\"", (char*)NULL);
206            return TCL_ERROR;
207        }
208
209        double fr = 0;
210        int err = 0;
211
212        err = VideoGetFrameRate((VideoObj *)clientData, &fr);
213        if (err) {
214            Tcl_AppendResult(interp, "error while calculating framerate",
215                (char*)NULL);
216            return TCL_ERROR;
217        }
218        Tcl_SetObjResult(interp, Tcl_NewDoubleObj(fr));
219    }
220    else {
221        Tcl_AppendResult(interp, "unrecognized command \"", info, "\": should be \"", cmd,
222            " [image width height]|[position cur|end]|[framerate]\"", (char*)NULL);
223        return TCL_ERROR;
224    }
225
226
227    return TCL_OK;
228}
229
230
231/**********************************************************************/
232// FUNCTION: NextOp()
233/// Get the next frame from a video
234/**
235 * Return the next frame from a video as an image
236 * Full function call:
237 *
238 * next
239 *
240 */
241static int
242NextOp (ClientData clientData, Tcl_Interp *interp, int objc,
243         Tcl_Obj *const *objv)
244{
245    int pos = 0;
246    VideoGoNext((VideoObj *)clientData);
247    VideoGetPositionCur((VideoObj *)clientData,&pos);
248    Tcl_SetObjResult(interp, Tcl_NewIntObj(pos));
249
250    return TCL_OK;
251}
252
253/**********************************************************************/
254// FUNCTION: SeekOp()
255/// Get the next frame from a video
256/**
257 * Return the frame specified, or at the specified offset, as an image
258 * Full function call:
259 *
260 * seek +5
261 * seek -5
262 * seek 22
263 *
264 */
265static int
266SeekOp (ClientData clientData, Tcl_Interp *interp, int objc,
267         Tcl_Obj *const *objv)
268{
269    const char *val_s = NULL;
270    int val = 0;
271    int pos = 0;
272
273    val_s = Tcl_GetString(objv[2]);
274    if (*val_s == '+') {
275        if (Tcl_GetInt(interp, val_s+1, &val) != TCL_OK) {
276            Tcl_AppendResult(interp, "bad value \"", val_s,
277                "\": should be next, +n, -n, or n", (char*)NULL);
278            return TCL_ERROR;
279        }
280        VideoGoPlusMinusN((VideoObj *)clientData, val);
281    }
282    else if (*val_s == '-') {
283        if (Tcl_GetInt(interp, val_s, &val) != TCL_OK) {
284            Tcl_AppendResult(interp, "bad value \"", val_s,
285                "\": should be next, +n, -n, or n", (char*)NULL);
286            return TCL_ERROR;
287        }
288        VideoGoPlusMinusN((VideoObj *)clientData, val);
289    }
290    else if (Tcl_GetInt(interp, val_s, &val) != TCL_OK) {
291        Tcl_AppendResult(interp, "bad value \"", val_s,
292            "\": should be next, +n, -n, or n", (char*)NULL);
293        return TCL_ERROR;
294    }
295    else {
296        int c = 0;
297        c = VideoGoToN((VideoObj *)clientData, val);
298    }
299
300    VideoGetPositionCur((VideoObj *)clientData,&pos);
301    Tcl_SetObjResult(interp, Tcl_NewIntObj(pos));
302
303    return TCL_OK;
304}
305
306/**********************************************************************/
307// FUNCTION: SizeOp()
308/// Get the size of the video
309/**
310 * Return the original size of the video frame
311 *
312 * Full function call:
313 *
314 * size
315 *
316 */
317static int
318SizeOp (ClientData clientData, Tcl_Interp *interp, int objc,
319         Tcl_Obj *const *objv)
320{
321
322    int width = 0;
323    int height = 0;
324    int err = 0;
325    Tcl_Obj *dim = NULL;
326
327
328    err = VideoSizeCmd((VideoObj *)clientData,&width,&height);
329
330    if (err) {
331        Tcl_AppendResult(interp, "error while calculating size of video",
332            (char*)NULL);
333        return TCL_ERROR;
334    }
335
336
337    dim = Tcl_NewListObj(0, NULL);
338    Tcl_ListObjAppendElement(interp, dim, Tcl_NewIntObj(width));
339    Tcl_ListObjAppendElement(interp, dim, Tcl_NewIntObj(height));
340    Tcl_SetObjResult(interp, dim);
341
342    return TCL_OK;
343}
344
345/**********************************************************************/
346// FUNCTION: ReleaseOp()
347/// Clean up memory from an open video in a movie player object
348/**
349 * Close all file handles and free allocated memory associated with an
350 * open video in a movie player object.
351 * Full function call:
352 *
353 * close
354 *
355 */
356static int
357ReleaseOp (ClientData clientData, Tcl_Interp *interp, int objc,
358         Tcl_Obj *const *objv)
359{
360    VideoClose((VideoObj *)clientData);
361
362    Tcl_ResetResult(interp);
363    return TCL_OK;
364}
Note: See TracBrowser for help on using the repository browser.