// TI #include #include #include #include #include #include #include #include #include // TinyScheme #define USE_INTERFACE 1 #include #include // C #include #include // ERRORS pointer scheme_call(scheme*, pointer, pointer); // SCHEME EXTENSIONS // TI SCHEME EXT // http://tiexpressdsp.com/index.php/Codec_Engine_Application_Developers_Guide void free_engine(void *data,scheme *sc) { printf("free_engine(%p)\n", data); Engine_close(data); } DEFINE_TYPE(engine) const char *ppsz_engine_error[] = { [Engine_EOK] = "Ok", [Engine_EEXIST] = "Engine name doesn't exist", [Engine_ENOMEM] = "Can't allocate engine memory", [Engine_EDSPLOAD] = "Unable to load the DSP image (used from other process?)", [Engine_ENOCOMM] = "Can't create communication connection to DSP", [Engine_ENOSERVER] = "Can't locate the server on the DSP", [Engine_ECOMALLOC] = "Can't allocate communication buffer", [Engine_ERUNTIME] = "Engine runtime failure", [Engine_ECODECCREATE] = "Engine codec creation failed", [Engine_ECODECSTART] = "Engine codec start failed", [Engine_EINVAL] = "Bad parameter", [Engine_EBADSERVER] = "Incompatible server specified", [Engine_ENOTAVAIL] = "Service not available", //[Engine_EWRONGSTATE] = "Call can't be made at this time", //[Engine_EINUSE] = "Call can't be made at this time because a required resource is in use", //[Engine_ENOTFOUND] = "Entity was not found", }; /* An `engine' is a handle to the global Codec Engine. Only one process at a time can access the DSP. */ pointer make_engine(scheme *sc, pointer args) { argument a[] = {{a_string}, {}}; a_check(sc, args, a); char *name = a[0].v.string; Engine_Error err; Engine_Handle e = Engine_open(name, NULL, &err); if( err != Engine_EOK ) { fprintf(stderr, "Error while opening engine `%s': %s\n", name, ppsz_engine_error[err]); return sc->F; } return wrap_engine(sc, e); } pointer algo_info(scheme *sc, pointer args) { argument a[] = {{a_string}, {}}; a_check(sc, args, a); Engine_AlgInfo info; info.algInfoSize = sizeof(info); int i = 0; // pointer rv = sc->NIL; while (Engine_EOK == Engine_getAlgInfo((String)a[0].v.string, &info, i)) { scheme_yield(sc, wrap_string(sc, info.name)); scheme_yield(sc, info.isLocal ? sc->T : sc->F); char **tt; for (tt = info.typeTab; *tt; tt++) { scheme_yield(sc, wrap_string(sc, *tt)); } scheme_yield(sc, sc->NIL); // end of line i++; } return sc->NIL; // return reverse_in_place(sc, sc->NIL, rv); } void free_viddec(void *x, scheme *sc) { fprintf(stderr, "free_viddec(%p)\n", x); VIDDEC_delete((VIDDEC_Handle)x); } void free_videnc(void *x, scheme *sc) { fprintf(stderr, "free_videnc(%p)\n", x); VIDENC_delete((VIDENC_Handle)x); } DEFINE_TYPE(viddec) DEFINE_TYPE(videnc) #define XDAS_INIT(data) {memset(&data, 0, sizeof(data)); data.size = sizeof(data);} pointer make_videnc(scheme *sc, pointer args) { argument a[] = {{a_engine}, {a_string}, {a_integer}, {a_integer}, // h w {a_integer}, {a_integer}, // fr br {}}; a_check(sc, args, a); VIDENC_Params p; XDAS_INIT(p); // ti/xdais/dm/ividenc.h p.encodingPreset = XDM_DEFAULT; // XDM_HIGH_QUALITY // XDM_HIGH_SPEED // XDM_USER_DEFINED p.rateControlPreset = IVIDEO_RATECONTROLPRESET_DEFAULT; // IVIDEO_LOW_DELAY; // IVIDEO_STORAGE // IVIDEO_TWOPASS // IVIDEO_NONE // IVIDEO_USER_DEFINED p.maxWidth = a[2].v.integer; // 720; p.maxHeight = a[3].v.integer; // 576; p.maxFrameRate = a[4].v.integer; // 50000; // frames per 1000 sec p.maxBitRate = a[5].v.integer; // 1000; p.dataEndianness = XDM_BYTE; p.inputChromaFormat = XDM_YUV_422ILE; // XDM_GRAY; // XDM_YUV_420P p.inputContentType = IVIDEO_PROGRESSIVE; // IVIDEO_INTERLACED VIDENC_Handle ve = VIDENC_create((Engine_Handle)a[0].v.data, (String)a[1].v.string, &p); if (!ve) { scheme_error(sc, "Can't create VIDENC", NULL); } return wrap_videnc(sc, ve); } pointer make_viddec(scheme *sc, pointer args) { argument a[] = {{a_engine}, {a_string}, {}}; a_check(sc, args, a); VIDDEC_Params p; XDAS_INIT(p); // ti/xdais/dm/ividdec.h p.maxWidth = 720; p.maxHeight = 576; p.maxFrameRate = 0; p.maxBitRate = 0; p.dataEndianness = XDM_BYTE; p.forceChromaFormat = XDM_YUV_422ILE; // XDM_GRAY; // XDM_YUV_420P VIDDEC_Handle vd = VIDDEC_create((Engine_Handle)a[0].v.data, (String)a[1].v.string, &p); if (!vd) { scheme_error(sc, "Can't create VIDDEC", NULL); } return wrap_viddec(sc, vd); } void free_bufdesc(void *data, scheme *sc) { fprintf(stderr, "free_bufdesc(%p)\n", data); XDM_BufDesc *buf = (XDM_BufDesc *)data; int i; for (i=0; inumBufs; i++) { void *b = buf->bufs[i]; if (b) Memory_contigFree(b, buf->bufSizes[i]); } free(buf->bufs); free(buf->bufSizes); free(data); } DEFINE_TYPE(bufdesc); pointer create_bufdesc(scheme *sc, XDAS_Int32 n, XDAS_Int32 *size) { XDM_BufDesc *buf = (XDM_BufDesc *)malloc(sizeof(*buf)); buf->numBufs = n; buf->bufs = calloc(n, sizeof(XDAS_Int8*)); buf->bufSizes = calloc(n, sizeof(XDAS_Int32)); int i; for (i=0; ibufSizes[i] = size[i]; /* The DSP needs physically contiguous pages from GPP/DSP shared memory. */ if (!(buf->bufs[i] = Memory_contigAlloc(size[i],Memory_DEFAULTALIGNMENT))) { free_bufdesc(buf, sc); scheme_error(sc, "Can't allocate contiguous memory.", NULL); } } return wrap_bufdesc(sc, buf); } #define LET(type, name, ai) type name = (type)ai.v.data pointer bufdesc_saw_bang(scheme *sc, pointer args) { argument a[] = {{a_bufdesc}, {a_integer}, {}}; a_check(sc, args, a); int fill = a[1].v.integer; LET(XDM_BufDesc*, bd, a[0]); int i,j; for(i=0; inumBufs; i++){ // printf("filling %d starting %d\n", i, fill); for(j=0; jbufSizes[i]; j++) { (bd->bufs[i])[j] = fill++; } } return sc->T; } pointer bufdesc_dump(scheme *sc, pointer args) { argument a[] = {{a_bufdesc}, {a_string}, {}}; a_check(sc, args, a); LET(XDM_BufDesc*, bd, a[0]); FILE *f = fopen(a[1].v.string, "a"); if (!f) { scheme_error(sc, "Can't create file", args); } fwrite(bd->bufs[0], 1, bd->bufSizes[0], f); fclose(f); return sc->T; } void yield_io_bufdescs (scheme *sc, XDM_AlgBufInfo *i) { scheme_yield(sc, create_bufdesc(sc, i->minNumOutBufs, i->minOutBufSize)); scheme_yield(sc, create_bufdesc(sc, i->minNumInBufs, i->minInBufSize)); } // query viddec and create IO buffers static void viddec_control(scheme *sc, VIDDEC_Handle vd, int msg, VIDDEC_DynamicParams *dp, VIDDEC_Status *s, const char *err) { if (VIDDEC_EOK != VIDDEC_control(vd, msg, dp, s)) { scheme_error(sc, err, NULL); }; } pointer viddec_iobufs(scheme *sc, pointer args) { argument a[] = {{a_viddec}, {}}; a_check(sc, args, a); VIDDEC_Handle vd = (VIDDEC_Handle)a[0].v.data; VIDDEC_DynamicParams dp; XDAS_INIT(dp); // ividdec.h VIDDEC_Status s; XDAS_INIT(s); // ividdec.h viddec_control(sc, vd, XDM_GETBUFINFO, &dp, &s, "Failed to get buffer info"); yield_io_bufdescs(sc, &s.bufInfo); viddec_control(sc, vd, XDM_GETSTATUS, &dp, &s, "Failed to get decoder status."); return sc->NIL; } static void videnc_control(scheme *sc, VIDENC_Handle ve, int msg, VIDENC_DynamicParams *dp, VIDENC_Status *s, const char *err) { if (VIDENC_EOK != VIDENC_control(ve, msg, dp, s)) { scheme_error(sc, err, NULL); }; } pointer videnc_iobufs(scheme *sc, pointer args) { argument a[] = {{a_videnc}, {}}; a_check(sc, args, a); VIDENC_Handle ve = (VIDENC_Handle)a[0].v.data; VIDENC_DynamicParams dp; XDAS_INIT(dp); // ividenc.h VIDENC_Status s; XDAS_INIT(s); // ividenc.h dp.inputWidth = 720; dp.inputHeight = 576; dp.refFrameRate = dp.targetFrameRate = 25000; dp.targetBitRate = 1000; dp.intraFrameInterval = 1; // ?? dp.generateHeader = XDM_ENCODE_AU; dp.captureWidth = 0; dp.forceIFrame = 0; // FIXME! videnc_control(sc, ve, XDM_SETPARAMS, &dp, &s, "Failed to set encoder params."); videnc_control(sc, ve, XDM_GETBUFINFO, &dp, &s, "Failed to get buffer info."); yield_io_bufdescs(sc, &s.bufInfo); videnc_control(sc, ve, XDM_GETSTATUS, &dp, &s, "Failed to get encoder status"); return sc->NIL; } // see ti/include/xdais/dm/xdm.h static pointer extended_error(scheme *sc, XDAS_Int32 e) { char msg[1000]; sprintf(msg, "%08lx", e); #define EXT_ERR(pred,x) if(pred(e)) {strcat(msg, ", "); strcat(msg, x);} EXT_ERR(XDM_ISAPPLIEDCONCEALMENT, "Applied bit concealment"); EXT_ERR(XDM_ISINSUFFICIENTDATA, "Insufficient data"); EXT_ERR(XDM_ISCORRUPTEDDATA, "Corrupted data"); EXT_ERR(XDM_ISCORRUPTEDHEADER, "Corrupted header"); EXT_ERR(XDM_ISUNSUPPORTEDINPUT, "Unsupported input"); EXT_ERR(XDM_ISUNSUPPORTEDPARAM, "Unsupported param"); EXT_ERR(XDM_ISFATALERROR, "Fatal error"); return wrap_string(sc, msg); } pointer videnc_process(scheme *sc, pointer args) { argument a[] = {{a_videnc}, {a_bufdesc}, {a_bufdesc}, {}}; a_check(sc, args, a); VIDENC_Handle ve = (VIDENC_Handle)a[0].v.data; VIDENC_InArgs in_args; XDAS_INIT(in_args); VIDENC_OutArgs out_args; XDAS_INIT(out_args); XDM_BufDesc *in = (XDM_BufDesc *)a[1].v.data; XDM_BufDesc *out = (XDM_BufDesc *)a[2].v.data; if (VIDENC_EOK != VIDENC_process(ve, in, out, &in_args, &out_args)) { scheme_error(sc, "Video encoding failed", extended_error(sc, out_args.extendedError)); } scheme_yield(sc, wrap_integer(sc, out_args.bytesGenerated)); scheme_yield(sc, wrap_integer(sc, out_args.encodedFrameType)); scheme_yield(sc, wrap_integer(sc, out_args.inputFrameSkip)); return sc->NIL; } // SCHEME TOP scheme *sc = NULL; void eval(char *str) { scheme_load_string(sc, str); } void repl(void) { scheme_load_file(sc, stdin); } void load(scheme *sc, char *filename) { FILE *f = fopen(filename, "r"); scheme_load_file(sc, f); fclose(f); } pointer scm_load_ext(scheme*, pointer); void scheme_boot(void) { /* init.scm */ sc = scheme_init_new(); defun(sc, "load-extension", scm_load_ext); scheme_set_output_port_file(sc, stdout); load(sc, "init.scm"); /* ffi */ defun(sc, "make-engine", make_engine); defun(sc, "algo-info", algo_info); defun(sc, "make-videnc", make_videnc); defun(sc, "make-viddec", make_viddec); defun(sc, "viddec-iobufs", viddec_iobufs); defun(sc, "videnc-iobufs", videnc_iobufs); defun(sc, "videnc-process", videnc_process); defun(sc, "bufdesc-saw!", bufdesc_saw_bang); defun(sc, "bufdesc-dump", bufdesc_dump); load(sc, "test.scm"); } void scheme_shutdown(void) { scheme_deinit(sc); printf("scheme_deinit() DONE\n"); } // TEST try point void debug() { printf("debug()\n"); } int main(int argc, char **argv){ CERuntime_init(); scheme_boot(); if (argc > 1) { if (!strcmp(argv[1], "debug")) { for (;;) { repl(); debug(); } } else { load(sc, argv[1]); } } else { repl(); } scheme_shutdown(); return 0; }