source: branches/blt4/video/RpVideoTclInterface.cc @ 2936

Last change on this file since 2936 was 2936, checked in by gah, 12 years ago

sync back with trunk

File size: 14.5 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;
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.