source: branches/1.4/video/RpVideoTclInterface.cc @ 4983

Last change on this file since 4983 was 4223, checked in by ldelgass, 10 years ago

merge r3919:3920 from trunk

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        VideoGoToN((VideoObj *)clientData, val);
349    }
350
351    VideoGetPositionCur((VideoObj *)clientData,&pos);
352    Tcl_SetObjResult(interp, Tcl_NewIntObj(pos));
353
354    return TCL_OK;
355}
356
357/**********************************************************************/
358// FUNCTION: SizeOp()
359/// Get the width height of the video
360/**
361 * Return the original width and height of the video frame
362 *
363 * Full function call:
364 *
365 * size
366 *
367 */
368static int
369SizeOp (ClientData clientData, Tcl_Interp *interp, int objc,
370         Tcl_Obj *const *objv)
371{
372
373    int width = 0;
374    int height = 0;
375    int err = 0;
376    Tcl_Obj *dim = NULL;
377
378
379    err = VideoSize((VideoObj *)clientData,&width,&height);
380
381    if (err) {
382        Tcl_AppendResult(interp, "error while calculating size of video",
383            (char*)NULL);
384        return TCL_ERROR;
385    }
386
387
388    dim = Tcl_NewListObj(0, NULL);
389    Tcl_ListObjAppendElement(interp, dim, Tcl_NewIntObj(width));
390    Tcl_ListObjAppendElement(interp, dim, Tcl_NewIntObj(height));
391    Tcl_SetObjResult(interp, dim);
392
393    return TCL_OK;
394}
395
396/**********************************************************************/
397// FUNCTION: FilenameOp()
398/// Get the filename of the video
399/**
400 * Return the original filename of the video
401 *
402 * Full function call:
403 *
404 * filename
405 *
406 */
407static int
408FilenameOp (ClientData clientData, Tcl_Interp *interp, int objc,
409         Tcl_Obj *const *objv)
410{
411    const char *fname = NULL;
412    int err = 0;
413
414    err = VideoFileName((VideoObj *)clientData, &fname);
415    if (err) {
416        Tcl_AppendResult(interp, "error while retrieving filename",
417            (char*)NULL);
418        return TCL_ERROR;
419    }
420    Tcl_AppendResult(interp, fname, (char*)NULL);
421
422    return TCL_OK;
423}
424
425/**********************************************************************/
426// FUNCTION: FramerateOp()
427/// Get the framerate of the video
428/**
429 * Return the framerate of the video
430 *
431 * Full function call:
432 *
433 * framerate
434 *
435 */
436static int
437FramerateOp (ClientData clientData, Tcl_Interp *interp, int objc,
438         Tcl_Obj *const *objv)
439{
440    double fr = 0;
441    int err = 0;
442
443    err = VideoFrameRate((VideoObj *)clientData, &fr);
444    if (err) {
445        Tcl_AppendResult(interp, "error while calculating framerate",
446            (char*)NULL);
447        return TCL_ERROR;
448    }
449    Tcl_SetObjResult(interp, Tcl_NewDoubleObj(fr));
450
451    return TCL_OK;
452}
453
454/**********************************************************************/
455// FUNCTION: AspectOp()
456/// Get the aspect ratio of the video
457/**
458 * Return either the pixel or display aspect ratio of the video
459 * Full function call:
460 *
461 * aspect pixel
462 * aspect display
463 *
464 */
465static int
466AspectOp (ClientData clientData, Tcl_Interp *interp, int objc,
467         Tcl_Obj *const *objv)
468{
469    int err = 0;
470    int num = 0;
471    int den = 1;
472    Tcl_Obj *dim = NULL;
473
474    const char *cmd = Tcl_GetString(objv[1]);
475    const char *info = Tcl_GetString(objv[2]);
476
477    if ((*cmd == 'p') && (strcmp(info,"pixel") == 0)) {
478        err = VideoPixelAspectRatio((VideoObj *)clientData, &num, &den);
479    }
480    else if ((*info == 'd') && (strcmp(info,"display") == 0)) {
481        err = VideoDisplayAspectRatio((VideoObj *)clientData, &num, &den);
482    }
483    else {
484        Tcl_AppendResult(interp, "unrecognized command \"", info, "\": should be \"", cmd,
485            " pixel|display\"", (char*)NULL);
486        return TCL_ERROR;
487    }
488
489    if (err) {
490        Tcl_AppendResult(interp, "error while retrieving ", info,
491            " aspect ratio", (char*)NULL);
492        return TCL_ERROR;
493    }
494
495    dim = Tcl_NewListObj(0, NULL);
496    Tcl_ListObjAppendElement(interp, dim, Tcl_NewIntObj(num));
497    Tcl_ListObjAppendElement(interp, dim, Tcl_NewIntObj(den));
498    Tcl_SetObjResult(interp, dim);
499
500    return TCL_OK;
501}
502/**********************************************************************/
503// FUNCTION: ReleaseOp()
504/// Clean up memory from an open video in a movie player object
505/**
506 * Close all file handles and free allocated memory associated with an
507 * open video in a movie player object.
508 * Full function call:
509 *
510 * close
511 *
512 */
513static int
514ReleaseOp (ClientData clientData, Tcl_Interp *interp, int objc,
515         Tcl_Obj *const *objv)
516{
517    VideoClose((VideoObj *)clientData);
518
519    Tcl_ResetResult(interp);
520    return TCL_OK;
521}
522
Note: See TracBrowser for help on using the repository browser.