source: trunk/video/RpVideoTclInterface.cc @ 3919

Last change on this file since 3919 was 3177, checked in by mmc, 12 years ago

Updated all of the copyright notices to reference the transfer to
the new HUBzero Foundation, LLC.

File size: 14.4 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) 2004-2012  HUBzero Foundation, LLC
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;
30static Tcl_ObjCmdProc FilenameOp;
31static Tcl_ObjCmdProc FramerateOp;
32static Tcl_ObjCmdProc AspectOp;
33
34static Rp_OpSpec rpVideoOps[] = {
35    {"aspect",    1, (void *)AspectOp, 3, 3, "type",},
36    {"filename",  1, (void *)FilenameOp, 2, 2, "",},
37    {"framerate", 1, (void *)FramerateOp, 2, 2, "",},
38    {"get",       1, (void *)GetOp, 3, 5, "[image ?width height?]|[position cur|end]",},
39    {"next",      1, (void *)NextOp, 2, 2, "",},
40    {"release",   1, (void *)ReleaseOp, 2, 2, "",},
41    {"seek",      1, (void *)SeekOp, 3, 3, "+n|-n|n",},
42    {"size",      1, (void *)SizeOp, 2, 2, "",},
43};
44
45static int nRpVideoOps = sizeof(rpVideoOps) / sizeof(Rp_OpSpec);
46
47/*
48 * ------------------------------------------------------------------------
49 *  RpVideo_Init()
50 *
51 *  Called in Rappture_Init() to initialize the commands defined
52 *  in this file.
53 * ------------------------------------------------------------------------
54 */
55int
56Rpvideo_Init(Tcl_Interp *interp)
57{
58
59    Tcl_CreateObjCommand(interp, "::Rappture::Video",
60        VideoCmd, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
61
62    return TCL_OK;
63}
64
65/*
66 * USAGE: Video <type> <data>
67 */
68static int
69VideoCmd(ClientData clientData, Tcl_Interp *interp, int objc,
70       Tcl_Obj* const *objv)
71{
72    char cmdName[64];
73    static int movieCount = 0;
74    const char *type = NULL;
75    const char *data = NULL;
76    int err = 0;
77
78    if (objc != 3) {
79        Tcl_AppendResult(interp, "wrong # args: should be \"",
80            "Video <type> <data>\"", (char*)NULL);
81        return TCL_ERROR;
82    }
83
84    type = Tcl_GetString(objv[1]);
85    data = Tcl_GetString(objv[2]);
86
87    // create a new command
88    VideoObj *movie = NULL;
89    movie = VideoInit();
90    if (movie == NULL) {
91        Tcl_AppendResult(interp, "error while creating movie object", "\n",
92                         "VideoInit(movie);", (char*)NULL);
93        return TCL_ERROR;
94    }
95
96    if ((*type == 'd') && (strcmp(type,"data") == 0)) {
97        Tcl_AppendResult(interp, "error while creating movie: type == data not supported",
98                         "\n", "VideoInit(movie);", (char*)NULL);
99        return TCL_ERROR;
100    } else if ((*type == 'f') && (strcmp(type,"file") == 0)) {
101        err = VideoOpenFile(movie,data,"r");
102        if (err) {
103            Tcl_AppendResult(interp, "error while creating movie object: ",
104                             "\n", "VideoInit(movie);", (char*)NULL);
105            return TCL_ERROR;
106        }
107    }
108
109    sprintf(cmdName,"::movieObj%d",movieCount);
110    movieCount++;
111
112    Tcl_CreateObjCommand(interp, cmdName, VideoCallCmd,
113        (ClientData)movie, (Tcl_CmdDeleteProc*)NULL);
114
115    Tcl_AppendResult(interp, cmdName, (char*)NULL);
116    return TCL_OK;
117}
118
119
120static int
121VideoCallCmd(ClientData clientData, Tcl_Interp *interp, int objc,
122           Tcl_Obj *const *objv)
123{
124    Tcl_ObjCmdProc *proc;
125
126    proc = (Tcl_ObjCmdProc *)Rp_GetOpFromObj(interp, nRpVideoOps, rpVideoOps,
127        RP_OP_ARG1, objc, objv, 0);
128
129    if (proc == NULL) {
130        return TCL_ERROR;
131    }
132    return (*proc)(clientData, interp, objc, objv);
133}
134
135/**********************************************************************/
136// FUNCTION: GetOp()
137/// Get info about the video
138/**
139 * Full function call:
140 *
141 * get position cur
142 * get position end
143 * get image ?width height?
144 * get framerate
145 * get filename
146 * get aspectratio
147 *
148 */
149static int
150GetOp (ClientData clientData, Tcl_Interp *interp, int objc,
151         Tcl_Obj *const *objv)
152{
153    const char *cmd = Tcl_GetString(objv[1]);
154
155    /*
156     * Decode the first arg and figure out how we're supposed to advance.
157     */
158    if (objc > 5) {
159        Tcl_AppendResult(interp, "wrong # args: should be \"", cmd,
160            " [image width height]|[position cur|end]\"", (char*)NULL);
161        return TCL_ERROR;
162    }
163
164    const char *info = Tcl_GetString(objv[2]);
165    if ((*info == 'p') && (strcmp(info,"position") == 0)) {
166        if (objc != 4) {
167            Tcl_AppendResult(interp, "wrong # args: should be \"", cmd,
168                " position cur|end\"", (char*)NULL);
169            return TCL_ERROR;
170        }
171        const char *which = Tcl_GetString(objv[3]);
172        if ((*which == 'c') && (strcmp(which,"cur") == 0)) {
173            int pos = 0;
174            VideoGetPositionCur((VideoObj *)clientData,&pos);
175            Tcl_SetObjResult(interp, Tcl_NewIntObj(pos));
176        }
177        else if ((*which == 'e') && (strcmp(which,"end") == 0)) {
178            int pos = 0;
179            VideoGetPositionEnd((VideoObj *)clientData,&pos);
180            Tcl_SetObjResult(interp, Tcl_NewIntObj(pos));
181        }
182        else {
183            Tcl_AppendResult(interp, "unrecognized command: \"", which,
184                "\" should be one of cur,end ", (char*)NULL);
185            return TCL_ERROR;
186        }
187    }
188    else if ((*info == 'i') && (strcmp(info,"image") == 0)) {
189        if ((objc != 3) && (objc != 5)) {
190            Tcl_AppendResult(interp, "wrong # args: should be \"", cmd,
191                " image ?width height?\"", (char*)NULL);
192            return TCL_ERROR;
193        }
194
195        void *img = NULL;
196        int width = -1;
197        int height = -1;
198        int bufSize = 0;
199
200        if (objc == 5) {
201            Tcl_GetIntFromObj(interp, objv[3], &width);
202            Tcl_GetIntFromObj(interp, objv[4], &height);
203        }
204
205        VideoGetImage((VideoObj *)clientData, width, height, &img, &bufSize);
206
207        Tcl_SetByteArrayObj(Tcl_GetObjResult(interp),
208                            (const unsigned char*)img, bufSize);
209    }
210/*
211    else if ((*info == 'f') && (strcmp(info,"framerate") == 0)) {
212        if (objc != 3) {
213            Tcl_AppendResult(interp, "wrong # args: should be \"", cmd,
214                " framerate\"", (char*)NULL);
215            return TCL_ERROR;
216        }
217
218        double fr = 0;
219        int err = 0;
220
221        err = VideoGetFrameRate((VideoObj *)clientData, &fr);
222        if (err) {
223            Tcl_AppendResult(interp, "error while calculating framerate",
224                (char*)NULL);
225            return TCL_ERROR;
226        }
227        Tcl_SetObjResult(interp, Tcl_NewDoubleObj(fr));
228    }
229    else if ((*info == 'f') && (strcmp(info,"filename") == 0)) {
230        if (objc != 3) {
231            Tcl_AppendResult(interp, "wrong # args: should be \"", cmd,
232                " filename\"", (char*)NULL);
233            return TCL_ERROR;
234        }
235
236        const char *fname = NULL;
237        int err = 0;
238
239        err = VideoGetFileName((VideoObj *)clientData, &fname);
240        if (err) {
241            Tcl_AppendResult(interp, "error while retrieving filename",
242                (char*)NULL);
243            return TCL_ERROR;
244        }
245        Tcl_AppendResult(interp, fname, (char*)NULL);
246    }
247    else if ((*info == 'a') && (strcmp(info,"aspectratio") == 0)) {
248        if (objc != 3) {
249            Tcl_AppendResult(interp, "wrong # args: should be \"", cmd,
250                " aspectratio\"", (char*)NULL);
251            return TCL_ERROR;
252        }
253
254        int num = 0;
255        int den = 0;
256        int err = 0;
257
258        err = VideoGetAspectRatio((VideoObj *)clientData, &num, &den);
259        if (err) {
260            Tcl_AppendResult(interp, "error while retrieving aspectratio",
261                (char*)NULL);
262            return TCL_ERROR;
263        }
264
265        Tcl_Obj *dim = NULL;
266        dim = Tcl_NewListObj(0, NULL);
267        Tcl_ListObjAppendElement(interp, dim, Tcl_NewIntObj(num));
268        Tcl_ListObjAppendElement(interp, dim, Tcl_NewIntObj(den));
269        Tcl_SetObjResult(interp, dim);
270    }
271*/
272    else {
273        Tcl_AppendResult(interp, "unrecognized command \"", info, "\": should be \"", cmd,
274            " [image width height]|[position cur|end]|[framerate]\"", (char*)NULL);
275        return TCL_ERROR;
276    }
277
278
279    return TCL_OK;
280}
281
282
283/**********************************************************************/
284// FUNCTION: NextOp()
285/// Get the next frame from a video
286/**
287 * Return the next frame from a video as an image
288 * Full function call:
289 *
290 * next
291 *
292 */
293static int
294NextOp (ClientData clientData, Tcl_Interp *interp, int objc,
295         Tcl_Obj *const *objv)
296{
297    int pos = 0;
298    VideoGoNext((VideoObj *)clientData);
299    VideoGetPositionCur((VideoObj *)clientData,&pos);
300    Tcl_SetObjResult(interp, Tcl_NewIntObj(pos));
301
302    return TCL_OK;
303}
304
305/**********************************************************************/
306// FUNCTION: SeekOp()
307/// Get the next frame from a video
308/**
309 * Return the frame specified, or at the specified offset, as an image
310 * Full function call:
311 *
312 * seek +5
313 * seek -5
314 * seek 22
315 *
316 */
317static int
318SeekOp (ClientData clientData, Tcl_Interp *interp, int objc,
319         Tcl_Obj *const *objv)
320{
321    const char *val_s = NULL;
322    int val = 0;
323    int pos = 0;
324
325    val_s = Tcl_GetString(objv[2]);
326    if (*val_s == '+') {
327        if (Tcl_GetInt(interp, val_s+1, &val) != TCL_OK) {
328            Tcl_AppendResult(interp, "bad value \"", val_s,
329                "\": should be next, +n, -n, or n", (char*)NULL);
330            return TCL_ERROR;
331        }
332        VideoGoPlusMinusN((VideoObj *)clientData, val);
333    }
334    else if (*val_s == '-') {
335        if (Tcl_GetInt(interp, val_s, &val) != TCL_OK) {
336            Tcl_AppendResult(interp, "bad value \"", val_s,
337                "\": should be next, +n, -n, or n", (char*)NULL);
338            return TCL_ERROR;
339        }
340        VideoGoPlusMinusN((VideoObj *)clientData, val);
341    }
342    else if (Tcl_GetInt(interp, val_s, &val) != TCL_OK) {
343        Tcl_AppendResult(interp, "bad value \"", val_s,
344            "\": should be next, +n, -n, or n", (char*)NULL);
345        return TCL_ERROR;
346    }
347    else {
348        int c = 0;
349        c = VideoGoToN((VideoObj *)clientData, val);
350    }
351
352    VideoGetPositionCur((VideoObj *)clientData,&pos);
353    Tcl_SetObjResult(interp, Tcl_NewIntObj(pos));
354
355    return TCL_OK;
356}
357
358/**********************************************************************/
359// FUNCTION: SizeOp()
360/// Get the width height of the video
361/**
362 * Return the original width and height of the video frame
363 *
364 * Full function call:
365 *
366 * size
367 *
368 */
369static int
370SizeOp (ClientData clientData, Tcl_Interp *interp, int objc,
371         Tcl_Obj *const *objv)
372{
373
374    int width = 0;
375    int height = 0;
376    int err = 0;
377    Tcl_Obj *dim = NULL;
378
379
380    err = VideoSize((VideoObj *)clientData,&width,&height);
381
382    if (err) {
383        Tcl_AppendResult(interp, "error while calculating size of video",
384            (char*)NULL);
385        return TCL_ERROR;
386    }
387
388
389    dim = Tcl_NewListObj(0, NULL);
390    Tcl_ListObjAppendElement(interp, dim, Tcl_NewIntObj(width));
391    Tcl_ListObjAppendElement(interp, dim, Tcl_NewIntObj(height));
392    Tcl_SetObjResult(interp, dim);
393
394    return TCL_OK;
395}
396
397/**********************************************************************/
398// FUNCTION: FilenameOp()
399/// Get the filename of the video
400/**
401 * Return the original filename of the video
402 *
403 * Full function call:
404 *
405 * filename
406 *
407 */
408static int
409FilenameOp (ClientData clientData, Tcl_Interp *interp, int objc,
410         Tcl_Obj *const *objv)
411{
412    const char *fname = NULL;
413    int err = 0;
414
415    err = VideoFileName((VideoObj *)clientData, &fname);
416    if (err) {
417        Tcl_AppendResult(interp, "error while retrieving filename",
418            (char*)NULL);
419        return TCL_ERROR;
420    }
421    Tcl_AppendResult(interp, fname, (char*)NULL);
422
423    return TCL_OK;
424}
425
426/**********************************************************************/
427// FUNCTION: FramerateOp()
428/// Get the framerate of the video
429/**
430 * Return the framerate of the video
431 *
432 * Full function call:
433 *
434 * framerate
435 *
436 */
437static int
438FramerateOp (ClientData clientData, Tcl_Interp *interp, int objc,
439         Tcl_Obj *const *objv)
440{
441    double fr = 0;
442    int err = 0;
443
444    err = VideoFrameRate((VideoObj *)clientData, &fr);
445    if (err) {
446        Tcl_AppendResult(interp, "error while calculating framerate",
447            (char*)NULL);
448        return TCL_ERROR;
449    }
450    Tcl_SetObjResult(interp, Tcl_NewDoubleObj(fr));
451
452    return TCL_OK;
453}
454
455/**********************************************************************/
456// FUNCTION: AspectOp()
457/// Get the aspect ratio of the video
458/**
459 * Return either the pixel or display aspect ratio of the video
460 * Full function call:
461 *
462 * aspect pixel
463 * aspect display
464 *
465 */
466static int
467AspectOp (ClientData clientData, Tcl_Interp *interp, int objc,
468         Tcl_Obj *const *objv)
469{
470    int err = 0;
471    int num = 0;
472    int den = 1;
473    Tcl_Obj *dim = NULL;
474
475    const char *cmd = Tcl_GetString(objv[1]);
476    const char *info = Tcl_GetString(objv[2]);
477
478    if ((*cmd == 'p') && (strcmp(info,"pixel") == 0)) {
479        err = VideoPixelAspectRatio((VideoObj *)clientData, &num, &den);
480    }
481    else if ((*info == 'd') && (strcmp(info,"display") == 0)) {
482        err = VideoDisplayAspectRatio((VideoObj *)clientData, &num, &den);
483    }
484    else {
485        Tcl_AppendResult(interp, "unrecognized command \"", info, "\": should be \"", cmd,
486            " pixel|display\"", (char*)NULL);
487        return TCL_ERROR;
488    }
489
490    if (err) {
491        Tcl_AppendResult(interp, "error while retrieving ", info,
492            " aspect ratio", (char*)NULL);
493        return TCL_ERROR;
494    }
495
496    dim = Tcl_NewListObj(0, NULL);
497    Tcl_ListObjAppendElement(interp, dim, Tcl_NewIntObj(num));
498    Tcl_ListObjAppendElement(interp, dim, Tcl_NewIntObj(den));
499    Tcl_SetObjResult(interp, dim);
500
501    return TCL_OK;
502}
503/**********************************************************************/
504// FUNCTION: ReleaseOp()
505/// Clean up memory from an open video in a movie player object
506/**
507 * Close all file handles and free allocated memory associated with an
508 * open video in a movie player object.
509 * Full function call:
510 *
511 * close
512 *
513 */
514static int
515ReleaseOp (ClientData clientData, Tcl_Interp *interp, int objc,
516         Tcl_Obj *const *objv)
517{
518    VideoClose((VideoObj *)clientData);
519
520    Tcl_ResetResult(interp);
521    return TCL_OK;
522}
523
Note: See TracBrowser for help on using the repository browser.