[2890] | 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 | |
---|
| 19 | extern "C" Tcl_AppInitProc Rpvideo_Init; |
---|
| 20 | |
---|
| 21 | #include "RpOp.h" |
---|
| 22 | |
---|
| 23 | static Tcl_ObjCmdProc VideoCmd; |
---|
| 24 | static Tcl_ObjCmdProc VideoCallCmd; |
---|
| 25 | static Tcl_ObjCmdProc GetOp; |
---|
| 26 | static Tcl_ObjCmdProc NextOp; |
---|
| 27 | static Tcl_ObjCmdProc SeekOp; |
---|
| 28 | static Tcl_ObjCmdProc SizeOp; |
---|
| 29 | static Tcl_ObjCmdProc ReleaseOp; |
---|
| 30 | static Tcl_ObjCmdProc FilenameOp; |
---|
| 31 | static Tcl_ObjCmdProc FramerateOp; |
---|
| 32 | static Tcl_ObjCmdProc AspectOp; |
---|
| 33 | |
---|
| 34 | static 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 | |
---|
| 45 | static 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 | */ |
---|
| 55 | int |
---|
| 56 | Rpvideo_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 | */ |
---|
| 68 | static int |
---|
| 69 | VideoCmd(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 | |
---|
| 120 | static int |
---|
| 121 | VideoCallCmd(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 | */ |
---|
| 149 | static int |
---|
| 150 | GetOp (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 | */ |
---|
| 293 | static int |
---|
| 294 | NextOp (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 | */ |
---|
| 317 | static int |
---|
| 318 | SeekOp (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 | */ |
---|
| 369 | static int |
---|
| 370 | SizeOp (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 | */ |
---|
| 408 | static int |
---|
| 409 | FilenameOp (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 | */ |
---|
| 437 | static int |
---|
| 438 | FramerateOp (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 | */ |
---|
| 466 | static int |
---|
| 467 | AspectOp (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 | */ |
---|
| 514 | static int |
---|
| 515 | ReleaseOp (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 | |
---|