Thread: [Redbutton-devel] SF.net SVN: redbutton: [10] redbutton-browser/trunk
Brought to you by:
skilvington
|
From: <ski...@us...> - 2006-03-02 17:10:33
|
Revision: 10 Author: skilvington Date: 2006-03-02 09:10:15 -0800 (Thu, 02 Mar 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=10&view=rev Log Message: ----------- allow rb-browser to use remote backends Modified Paths: -------------- redbutton-browser/trunk/MHEGApp.c redbutton-browser/trunk/MHEGApp.h redbutton-browser/trunk/MHEGBackend.c redbutton-browser/trunk/MHEGBackend.h redbutton-browser/trunk/MHEGDisplay.c redbutton-browser/trunk/MHEGDisplay.h redbutton-browser/trunk/MHEGEngine.c redbutton-browser/trunk/MHEGEngine.h redbutton-browser/trunk/TODO redbutton-browser/trunk/rb-browser.c redbutton-browser/trunk/utils.c redbutton-browser/trunk/utils.h redbutton-download/trunk/listen.c Modified: redbutton-browser/trunk/MHEGApp.c =================================================================== --- redbutton-browser/trunk/MHEGApp.c 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/MHEGApp.c 2006-03-02 17:10:15 UTC (rev 10) @@ -21,7 +21,7 @@ } void -MHEGApp_stop(MHEGApp *m) +MHEGApp_fini(MHEGApp *m) { if(m->app != NULL) free_InterchangedObject(m->app); @@ -63,7 +63,7 @@ if((der = MHEGEngine_openFile(derfile, "r")) == NULL) { - error("Unable to open '%.*s': %s", derfile->size, derfile->data, strerror(errno)); + error("Unable to open '%.*s'", derfile->size, derfile->data); safe_free(m->app); m->app = NULL; return NULL; @@ -118,7 +118,7 @@ if((der = MHEGEngine_openFile(derfile, "r")) == NULL) { - error("Unable to open '%.*s': %s", derfile->size, derfile->data, strerror(errno)); + error("Unable to open '%.*s'", derfile->size, derfile->data); safe_free(m->scene); m->scene = NULL; return NULL; Modified: redbutton-browser/trunk/MHEGApp.h =================================================================== --- redbutton-browser/trunk/MHEGApp.h 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/MHEGApp.h 2006-03-02 17:10:15 UTC (rev 10) @@ -14,7 +14,7 @@ } MHEGApp; void MHEGApp_init(MHEGApp *); -void MHEGApp_stop(MHEGApp *); +void MHEGApp_fini(MHEGApp *); ApplicationClass *MHEGApp_loadApplication(MHEGApp *, OctetString *); SceneClass *MHEGApp_loadScene(MHEGApp *, OctetString *); Modified: redbutton-browser/trunk/MHEGBackend.c =================================================================== --- redbutton-browser/trunk/MHEGBackend.c 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/MHEGBackend.c 2006-03-02 17:10:15 UTC (rev 10) @@ -2,62 +2,211 @@ * MHEGBackend.c */ +#include <unistd.h> #include <stdio.h> #include <string.h> #include <errno.h> +#include <netdb.h> +#include <arpa/inet.h> +#include <sys/socket.h> #include "MHEGEngine.h" #include "utils.h" +/* local backend funcs */ bool local_checkContentRef(MHEGBackend *, ContentReference *); bool local_loadFile(MHEGBackend *, OctetString *, OctetString *); FILE *local_openFile(MHEGBackend *, OctetString *, char *); int local_closeFile(MHEGBackend *, FILE *); -static MHEGBackend local_backend = +static struct MHEGBackendFns local_backend_fns = { - NULL, /* base_dir */ local_checkContentRef, /* checkContentRef */ local_loadFile, /* loadFile */ local_openFile, /* openFile */ local_closeFile /* closeFile */ }; -MHEGBackend * -new_MHEGBackend(bool remote, char *srg_loc) +/* remote backend funcs */ +bool remote_checkContentRef(MHEGBackend *, ContentReference *); +bool remote_loadFile(MHEGBackend *, OctetString *, OctetString *); +FILE *remote_openFile(MHEGBackend *, OctetString *, char *); +int remote_closeFile(MHEGBackend *, FILE *); + +static struct MHEGBackendFns remote_backend_fns = { - MHEGBackend *b = NULL; + remote_checkContentRef, /* checkContentRef */ + remote_loadFile, /* loadFile */ + remote_openFile, /* openFile */ + remote_closeFile /* closeFile */ +}; +/* internal functions */ +static int parse_addr(char *, struct in_addr *, in_port_t *); +static int get_host_addr(char *, struct in_addr *); + +static int remote_command(MHEGBackend *, char *); +static unsigned int remote_response(int); + +/* public interface */ +void +MHEGBackend_init(MHEGBackend *b, bool remote, char *srg_loc) +{ + bzero(b, sizeof(MHEGBackend)); + if(remote) { - /* backend is on a different host, srg_loc is the remote host */ -/* TODO */ -fatal("TODO: remote backends not supported: %s", srg_loc); + /* backend is on a different host, srg_loc is the remote host[:port] */ + b->fns = &remote_backend_fns; + b->addr.sin_family = AF_INET; + b->addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + b->addr.sin_port = htons(DEFAULT_REMOTE_PORT); + if(parse_addr(srg_loc, &b->addr.sin_addr, &b->addr.sin_port) < 0) + fatal("Unable to resolve host %s", srg_loc); + verbose("Remote backend at %s:%u", inet_ntoa(b->addr.sin_addr), ntohs(b->addr.sin_port)); } else { /* backend and frontend on same host, srg_loc is the base directory */ - b = &local_backend; + b->fns = &local_backend_fns; b->base_dir = srg_loc; + verbose("Local backend; carousel file root '%s'", srg_loc); } - return b; + return; } void -free_MHEGBackend(MHEGBackend *b) +MHEGBackend_fini(MHEGBackend *b) { return; } /* + * extract the IP addr and port number from a string in one of these forms: + * host:port + * ip-addr:port + * host + * ip-addr + * if the port is not defined in the string, the value passed to this routine is unchanged + * ip and port are both returned in network byte order + * returns -1 on error (can't resolve host name) + */ + +static int +parse_addr(char *str, struct in_addr *ip, in_port_t *port) +{ + char *p; + + if((p = strchr(str, ':')) != NULL) + { + /* its either host:port or ip:port */ + *(p++) = '\0'; + if(get_host_addr(str, ip) < 0) + return -1; + *port = htons(atoi(p)); + /* reconstruct the string */ + *(--p) = ':'; + } + else if(get_host_addr(str, ip) < 0) + { + return -1; + } + + return 0; +} + +/* + * puts the IP address associated with the given host into output buffer + * host can be a.b.c.d or a host name + * returns 0 if successful, -1 on error + */ + +static int +get_host_addr(char *host, struct in_addr *output) +{ + struct hostent *he; + int error = 0; + + if(((he = gethostbyname(host)) != NULL) && (he->h_addrtype == AF_INET)) + memcpy(output, he->h_addr, sizeof(struct in_addr)); + else + error = -1; + + return error; +} + +/* + * send the given command to the remote backend + * returns a socket fd to read the response from + * returns <0 if it can't contact the backend + */ + +static int +remote_command(MHEGBackend *t, char *cmd) +{ + int sock; + + /* connect to the backend */ + if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + error("Unable to create backend socket: %s", strerror(errno)); + return -1; + } + + if(connect(sock, (struct sockaddr *) &t->addr, sizeof(struct sockaddr_in)) < 0) + { + error("Unable to connect to backend: %s", strerror(errno)); + return -1; + } + + /* send the command */ + write_string(sock, cmd); + + return sock; +} + +/* + * read the backend response from the given socket fd + * returns the OK/error code + */ + +#define BACKEND_RESPONSE_OK 200 + +static unsigned int +remote_response(int sock) +{ + char buf[1024]; + char byte; + unsigned int total; + ssize_t nread; + unsigned int rc; + + /* read upto \n */ + total = 0; + do + { + if((nread = read(sock, &byte, 1)) == 1) + buf[total++] = byte; + } + while(nread == 1 && byte != '\n' && total < (sizeof(buf) - 1)); + + /* \0 terminate it */ + buf[total] = '\0'; + + rc = atoi(buf); + + return rc; +} + +/* * local routines */ /* * returns a filename that can be loaded from the file system * ie ~// at the start of the absolute name is replaced with base_dir - * returns a ptr to static string that will be overwritten by the next call to this routine + * returns a ptr to a static string that will be overwritten by the next call to this routine */ static char _external[PATH_MAX]; @@ -71,7 +220,7 @@ absolute = MHEGEngine_absoluteFilename(name); /* construct the filename */ - snprintf(_external, sizeof(_external), "%s%s", t->base_dir, &absolute[1]); + snprintf(_external, sizeof(_external), "%s%s", t->base_dir, &absolute[2]); return _external; } @@ -98,6 +247,7 @@ /* * file contents are stored in out (out->data will need to be free'd) * returns false if it can't load the file (out will be {0,NULL}) + * out should be {0,NULL} before calling this */ bool @@ -106,16 +256,6 @@ char *fullname; FILE *file; - out->size = 0; - out->data = NULL; - - /* just in case */ - if(name->size == 0) - { - verbose("local_loadFile: no filename given"); - return false; - } - fullname = external_filename(t, name); /* open it */ @@ -162,3 +302,136 @@ return fclose(file); } +/* + * remote routines + */ + +/* + * returns true if the file exists on the carousel + */ + +bool +remote_checkContentRef(MHEGBackend *t, ContentReference *name) +{ + char cmd[PATH_MAX]; + int sock; + bool exists; + + snprintf(cmd, sizeof(cmd), "check %s\n", MHEGEngine_absoluteFilename(name)); + + if((sock = remote_command(t, cmd)) < 0) + return false; + + exists = (remote_response(sock) == BACKEND_RESPONSE_OK); + + close(sock); + + return exists; +} + +/* + * file contents are stored in out (out->data will need to be free'd) + * returns false if it can't load the file (out will be {0,NULL}) + * out should be {0,NULL} before calling this + */ + +bool +remote_loadFile(MHEGBackend *t, OctetString *name, OctetString *out) +{ + char cmd[PATH_MAX]; + int sock; + char buf[8 * 1024]; + ssize_t nread; + bool success = false; + + snprintf(cmd, sizeof(cmd), "file %s\n", MHEGEngine_absoluteFilename(name)); + + if((sock = remote_command(t, cmd)) < 0) + return false; + + /* does it exist */ + if(remote_response(sock) == BACKEND_RESPONSE_OK) + { + verbose("Loading '%.*s'", name->size, name->data); + /* read from the socket until EOF */ + do + { + if((nread = read(sock, buf, sizeof(buf))) > 0) + { + out->data = safe_realloc(out->data, out->size + nread); + memcpy(out->data + out->size, buf, nread); + out->size += nread; + } + } + while(nread > 0); + success = true; + } + else + { + error("Unable to load '%.*s'", name->size, name->data); + } + + close(sock); + + return success; +} + +FILE * +remote_openFile(MHEGBackend *t, OctetString *name, char *mode) +{ + char cmd[PATH_MAX]; + int sock; + char buf[8 * 1024]; + ssize_t nread; + size_t nwritten; + FILE *file = NULL; + + snprintf(cmd, sizeof(cmd), "file %s\n", MHEGEngine_absoluteFilename(name)); + + if((sock = remote_command(t, cmd)) < 0) + return NULL; + + /* does it exist */ + if(remote_response(sock) == BACKEND_RESPONSE_OK) + { + if((file = tmpfile()) != NULL) + { + /* read from the socket until EOF */ + do + { + if((nread = read(sock, buf, sizeof(buf))) > 0) + nwritten = fwrite(buf, 1, nread, file); + else + nwritten = 0; + } + while(nread > 0 && nread == nwritten); + /* could we write the file ok */ + if(nread != nwritten) + { + error("Unable to write to local file"); + fclose(file); + file = NULL; + } + } + } + + close(sock); + + /* rewind the file */ + if(file != NULL) + rewind(file); + + return file; +} + +/* + * close a FILE opened with MHEGEngine_openFile() + */ + +int +remote_closeFile(MHEGBackend *t, FILE *file) +{ + /* tmpfile() will delete the file for us */ + return fclose(file); +} + Modified: redbutton-browser/trunk/MHEGBackend.h =================================================================== --- redbutton-browser/trunk/MHEGBackend.h 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/MHEGBackend.h 2006-03-02 17:10:15 UTC (rev 10) @@ -7,17 +7,26 @@ #include <stdio.h> #include <stdbool.h> +#include <netinet/in.h> +/* default TCP port to contact backend on */ +#define DEFAULT_REMOTE_PORT 10101 + typedef struct MHEGBackend { - char *base_dir; /* Service Gateway root directory */ - bool (*checkContentRef)(struct MHEGBackend *, ContentReference *); /* check a file exists */ - bool (*loadFile)(struct MHEGBackend *, OctetString *, OctetString *); /* load a file */ - FILE *(*openFile)(struct MHEGBackend *, OctetString *, char *); /* open a file */ - int (*closeFile)(struct MHEGBackend *, FILE *); /* close a file */ + char *base_dir; /* local Service Gateway root directory */ + struct sockaddr_in addr; /* remote backend IP and port */ + /* function pointers */ + struct MHEGBackendFns + { + bool (*checkContentRef)(struct MHEGBackend *, ContentReference *); /* check a file exists */ + bool (*loadFile)(struct MHEGBackend *, OctetString *, OctetString *); /* load a file */ + FILE *(*openFile)(struct MHEGBackend *, OctetString *, char *); /* open a file */ + int (*closeFile)(struct MHEGBackend *, FILE *); /* close a file */ + } *fns; } MHEGBackend; -MHEGBackend *new_MHEGBackend(bool, char *); -void free_MHEGBackend(MHEGBackend *); +void MHEGBackend_init(MHEGBackend *, bool, char *); +void MHEGBackend_fini(MHEGBackend *); #endif /* __MHEGBACKEND_H__ */ Modified: redbutton-browser/trunk/MHEGDisplay.c =================================================================== --- redbutton-browser/trunk/MHEGDisplay.c 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/MHEGDisplay.c 2006-03-02 17:10:15 UTC (rev 10) @@ -240,7 +240,7 @@ } void -MHEGDisplay_stop(MHEGDisplay *d) +MHEGDisplay_fini(MHEGDisplay *d) { /* calls XCloseDisplay for us which free's all our Windows, Pixmaps, etc */ XtDestroyApplicationContext(d->app); Modified: redbutton-browser/trunk/MHEGDisplay.h =================================================================== --- redbutton-browser/trunk/MHEGDisplay.h 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/MHEGDisplay.h 2006-03-02 17:10:15 UTC (rev 10) @@ -52,7 +52,7 @@ } MHEGDisplay; void MHEGDisplay_init(MHEGDisplay *, bool, char *); -void MHEGDisplay_stop(MHEGDisplay *); +void MHEGDisplay_fini(MHEGDisplay *); bool MHEGDisplay_processEvents(MHEGDisplay *, bool); Modified: redbutton-browser/trunk/MHEGEngine.c =================================================================== --- redbutton-browser/trunk/MHEGEngine.c 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/MHEGEngine.c 2006-03-02 17:10:15 UTC (rev 10) @@ -173,7 +173,7 @@ MHEGDisplay_init(&engine.display, fullscreen, keymap); - engine.backend = new_MHEGBackend(remote, srg_loc); + MHEGBackend_init(&engine.backend, remote, srg_loc); MHEGApp_init(&engine.active_app); @@ -223,7 +223,7 @@ ApplicationClass_Deactivation(app); ApplicationClass_Destruction(app); /* clean up */ - MHEGApp_stop(&engine.active_app); + MHEGApp_fini(&engine.active_app); LIST_FREE(&engine.objects, RootClassPtr, safe_free); LIST_FREE(&engine.missing_content, MissingContent, free_MissingContentListItem); LIST_FREE(&engine.active_links, LinkClassPtr, safe_free); @@ -264,15 +264,15 @@ } void -MHEGEngine_stop(void) +MHEGEngine_fini(void) { - MHEGDisplay_stop(&engine.display); + MHEGDisplay_fini(&engine.display); LIST_FREE(&engine.persistent, PersistentData, free_PersistentDataListItem); si_free(); - free_MHEGBackend(engine.backend); + MHEGBackend_fini(&engine.backend); return; } @@ -1293,18 +1293,30 @@ bool MHEGEngine_checkContentRef(ContentReference *name) { - return (*(engine.backend->checkContentRef))(engine.backend, name); + return (*(engine.backend.fns->checkContentRef))(&engine.backend, name); } /* * file contents are stored in out (out->data will need to be free'd) * returns false if it can't load the file (out will be {0,NULL}) + * out should be uninitialised before calling this */ bool MHEGEngine_loadFile(OctetString *name, OctetString *out) { - return (*(engine.backend->loadFile))(engine.backend, name, out); + /* in case it fails */ + out->size = 0; + out->data = NULL; + + /* just in case */ + if(name->size == 0) + { + verbose("MHEGEngine_loadFile: no filename given"); + return false; + } + + return (*(engine.backend.fns->loadFile))(&engine.backend, name, out); } /* @@ -1316,7 +1328,7 @@ FILE * MHEGEngine_openFile(OctetString *name, char *mode) { - return (*(engine.backend->openFile))(engine.backend, name, mode); + return (*(engine.backend.fns->openFile))(&engine.backend, name, mode); } /* @@ -1326,7 +1338,7 @@ int MHEGEngine_closeFile(FILE *file) { - return (*(engine.backend->closeFile))(engine.backend, file); + return (*(engine.backend.fns->closeFile))(&engine.backend, file); } /* Modified: redbutton-browser/trunk/MHEGEngine.h =================================================================== --- redbutton-browser/trunk/MHEGEngine.h 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/MHEGEngine.h 2006-03-02 17:10:15 UTC (rev 10) @@ -154,7 +154,7 @@ int verbose; /* -v cmd line flag */ unsigned int timeout; /* how long to poll for missing content before generating an error */ MHEGDisplay display; /* make porting easier */ - MHEGBackend *backend; /* local or remote access to DSMCC carousel and MPEG streams */ + MHEGBackend backend; /* local or remote access to DSMCC carousel and MPEG streams */ MHEGApp active_app; /* application we are currently running */ QuitReason quit_reason; /* do we need to stop the current app */ OctetString quit_data; /* new app to Launch or Spawn, or channel to Retune to */ @@ -171,7 +171,7 @@ /* prototypes */ void MHEGEngine_init(bool, char *, int, unsigned int, bool, char *); int MHEGEngine_run(OctetString *); -void MHEGEngine_stop(); +void MHEGEngine_fini(); MHEGDisplay *MHEGEngine_getDisplay(void); Modified: redbutton-browser/trunk/TODO =================================================================== --- redbutton-browser/trunk/TODO 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/TODO 2006-03-02 17:10:15 UTC (rev 10) @@ -1,3 +1,6 @@ +handle SIGPIPE - default handler terminates the process + + are all inherited instance vars added to classes? @@ -12,7 +15,8 @@ cope with DSM: and CI: filename prefixes -cope with .. in filenames +cope with .. in filenames (may not be needed, remote backend does it for us, +for local backend filesystem does it for us) see 8.3.2 in UK MHEG Profile Modified: redbutton-browser/trunk/rb-browser.c =================================================================== --- redbutton-browser/trunk/rb-browser.c 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/rb-browser.c 2006-03-02 17:10:15 UTC (rev 10) @@ -113,7 +113,7 @@ } /* clean up */ - MHEGEngine_stop(); + MHEGEngine_fini(); return rc; } Modified: redbutton-browser/trunk/utils.c =================================================================== --- redbutton-browser/trunk/utils.c 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/utils.c 2006-03-02 17:10:15 UTC (rev 10) @@ -20,14 +20,57 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> +#include <string.h> #include <ctype.h> +#include <errno.h> #include "utils.h" /* + * write the given string (ie upto \0) to the given fd + */ + +void +write_string(int fd, const char *str) +{ + write_all(fd, str, strlen(str)); + + return; +} + +/* + * guarantee writing count bytes from buf to fd + * W. Richard Stevens + */ + +void +write_all(int fd, const void *buf, size_t count) +{ + size_t nwritten; + const char *buf_ptr; + + buf_ptr = buf; + while(count > 0) + { + if((nwritten = write(fd, buf_ptr, count)) < 0) + { + if(errno == EINTR || errno == EAGAIN) + nwritten = 0; + else + fatal("write: %s\n", strerror(errno)); + } + count -= nwritten; + buf_ptr += nwritten; + } + + return; +} + +/* * returns 15 for 'f' etc */ @@ -38,7 +81,7 @@ return 0; else if(c >= '0' && c <= '9') return c - '0'; - else + else return 10 + (tolower(c) - 'a'); } Modified: redbutton-browser/trunk/utils.h =================================================================== --- redbutton-browser/trunk/utils.h 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-browser/trunk/utils.h 2006-03-02 17:10:15 UTC (rev 10) @@ -33,6 +33,9 @@ #define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif +void write_string(int, const char *); +void write_all(int, const void *, size_t); + unsigned int char2hex(unsigned char); int next_utf8(unsigned char *, int, int *); Modified: redbutton-download/trunk/listen.c =================================================================== --- redbutton-download/trunk/listen.c 2006-03-02 11:50:43 UTC (rev 9) +++ redbutton-download/trunk/listen.c 2006-03-02 17:10:15 UTC (rev 10) @@ -192,8 +192,9 @@ quit = handle_connection(listen_data, accept_sock, &client_addr); close(accept_sock); /* TODO */ -if(quit) printf("QUIT!!!\n"); - exit(EXIT_SUCCESS); +if(quit) printf("TODO: QUIT\n"); + /* use _exit in child so stdio etc don't clean up twice */ + _exit(EXIT_SUCCESS); } else { @@ -226,7 +227,7 @@ { /* \0 terminate the buffer */ cmd[nread] = '\0'; - /* strip off an trailing \n (only needed when testing with telnet etc) */ + /* strip off any trailing \n */ nread --; while(nread > 0 && (cmd[nread] == '\n' || cmd[nread] == '\r')) cmd[nread--] = '\0'; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-03-03 12:17:13
|
Revision: 13 Author: skilvington Date: 2006-03-03 04:17:06 -0800 (Fri, 03 Mar 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=13&view=rev Log Message: ----------- wrap socket to backend in a FILE Modified Paths: -------------- redbutton-browser/trunk/MHEGApp.c redbutton-browser/trunk/MHEGBackend.c redbutton-browser/trunk/MHEGBackend.h redbutton-browser/trunk/MHEGEngine.c redbutton-browser/trunk/MHEGEngine.h redbutton-browser/trunk/utils.c redbutton-browser/trunk/utils.h Modified: redbutton-browser/trunk/MHEGApp.c =================================================================== --- redbutton-browser/trunk/MHEGApp.c 2006-03-03 12:11:41 UTC (rev 12) +++ redbutton-browser/trunk/MHEGApp.c 2006-03-03 12:17:06 UTC (rev 13) @@ -76,7 +76,7 @@ len = ftell(der); rewind(der); rc = der_decode_InterchangedObject(der, m->app, len); - MHEGEngine_closeFile(der); + fclose(der); if(rc < 0 || m->app->choice != InterchangedObject_application) { @@ -131,7 +131,7 @@ len = ftell(der); rewind(der); rc = der_decode_InterchangedObject(der, m->scene, len); - MHEGEngine_closeFile(der); + fclose(der); if(rc < 0 || m->scene->choice != InterchangedObject_scene) { Modified: redbutton-browser/trunk/MHEGBackend.c =================================================================== --- redbutton-browser/trunk/MHEGBackend.c 2006-03-03 12:11:41 UTC (rev 12) +++ redbutton-browser/trunk/MHEGBackend.c 2006-03-03 12:17:06 UTC (rev 13) @@ -17,37 +17,35 @@ bool local_checkContentRef(MHEGBackend *, ContentReference *); bool local_loadFile(MHEGBackend *, OctetString *, OctetString *); FILE *local_openFile(MHEGBackend *, OctetString *, char *); -int local_closeFile(MHEGBackend *, FILE *); static struct MHEGBackendFns local_backend_fns = { local_checkContentRef, /* checkContentRef */ local_loadFile, /* loadFile */ local_openFile, /* openFile */ - local_closeFile /* closeFile */ }; /* remote backend funcs */ bool remote_checkContentRef(MHEGBackend *, ContentReference *); bool remote_loadFile(MHEGBackend *, OctetString *, OctetString *); FILE *remote_openFile(MHEGBackend *, OctetString *, char *); -int remote_closeFile(MHEGBackend *, FILE *); static struct MHEGBackendFns remote_backend_fns = { remote_checkContentRef, /* checkContentRef */ remote_loadFile, /* loadFile */ remote_openFile, /* openFile */ - remote_closeFile /* closeFile */ }; /* internal functions */ static int parse_addr(char *, struct in_addr *, in_port_t *); static int get_host_addr(char *, struct in_addr *); -static int remote_command(MHEGBackend *, char *); -static unsigned int remote_response(int); +static FILE *remote_command(MHEGBackend *, char *); +static unsigned int remote_response(FILE *); +static char *external_filename(MHEGBackend *, OctetString *); + /* public interface */ void MHEGBackend_init(MHEGBackend *b, bool remote, char *srg_loc) @@ -138,72 +136,69 @@ /* * send the given command to the remote backend - * returns a socket fd to read the response from - * returns <0 if it can't contact the backend + * returns a socket FILE to read the response from + * returns NULL if it can't contact the backend */ -static int +static FILE * remote_command(MHEGBackend *t, char *cmd) { int sock; + FILE *file; /* connect to the backend */ if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { error("Unable to create backend socket: %s", strerror(errno)); - return -1; + return NULL; } if(connect(sock, (struct sockaddr *) &t->addr, sizeof(struct sockaddr_in)) < 0) { error("Unable to connect to backend: %s", strerror(errno)); - return -1; + close(sock); + return NULL; } - /* send the command */ - write_string(sock, cmd); + /* associate a FILE with the socket (so stdio can do buffering) */ + if((file = fdopen(sock, "r+")) != NULL) + { + /* send the command */ + fputs(cmd, file); + } + else + { + error("Unable to buffer backend connection: %s", strerror(errno)); + close(sock); + } - return sock; + return file; } /* - * read the backend response from the given socket fd + * read the backend response from the given socket FILE * returns the OK/error code */ #define BACKEND_RESPONSE_OK 200 +#define BACKEND_RESPONSE_ERROR 500 static unsigned int -remote_response(int sock) +remote_response(FILE *file) { char buf[1024]; - char byte; - unsigned int total; - ssize_t nread; unsigned int rc; /* read upto \n */ - total = 0; - do - { - if((nread = read(sock, &byte, 1)) == 1) - buf[total++] = byte; - } - while(nread == 1 && byte != '\n' && total < (sizeof(buf) - 1)); + if(fgets(buf, sizeof(buf), file) == NULL) + return BACKEND_RESPONSE_ERROR; - /* \0 terminate it */ - buf[total] = '\0'; - rc = atoi(buf); return rc; } /* - * local routines - */ - -/* * returns a filename that can be loaded from the file system * ie ~// at the start of the absolute name is replaced with base_dir * returns a ptr to a static string that will be overwritten by the next call to this routine @@ -226,6 +221,10 @@ } /* + * local routines + */ + +/* * returns true if the file exists on the carousel */ @@ -293,16 +292,6 @@ } /* - * close a FILE opened with MHEGEngine_openFile() - */ - -int -local_closeFile(MHEGBackend *t, FILE *file) -{ - return fclose(file); -} - -/* * remote routines */ @@ -314,17 +303,17 @@ remote_checkContentRef(MHEGBackend *t, ContentReference *name) { char cmd[PATH_MAX]; - int sock; + FILE *sock; bool exists; snprintf(cmd, sizeof(cmd), "check %s\n", MHEGEngine_absoluteFilename(name)); - if((sock = remote_command(t, cmd)) < 0) + if((sock = remote_command(t, cmd)) == NULL) return false; exists = (remote_response(sock) == BACKEND_RESPONSE_OK); - close(sock); + fclose(sock); return exists; } @@ -339,14 +328,14 @@ remote_loadFile(MHEGBackend *t, OctetString *name, OctetString *out) { char cmd[PATH_MAX]; - int sock; + FILE *sock; char buf[8 * 1024]; - ssize_t nread; + size_t nread; bool success = false; snprintf(cmd, sizeof(cmd), "file %s\n", MHEGEngine_absoluteFilename(name)); - if((sock = remote_command(t, cmd)) < 0) + if((sock = remote_command(t, cmd)) == NULL) return false; /* does it exist */ @@ -354,16 +343,17 @@ { verbose("Loading '%.*s'", name->size, name->data); /* read from the socket until EOF */ - do + while(!feof(sock)) { - if((nread = read(sock, buf, sizeof(buf))) > 0) +/* TODO */ +/* could read straight into out->data rather than doing memcpy */ + if((nread = fread(buf, 1, sizeof(buf), sock)) > 0) { out->data = safe_realloc(out->data, out->size + nread); memcpy(out->data + out->size, buf, nread); out->size += nread; } } - while(nread > 0); success = true; } else @@ -371,7 +361,7 @@ error("Unable to load '%.*s'", name->size, name->data); } - close(sock); + fclose(sock); return success; } @@ -380,58 +370,48 @@ remote_openFile(MHEGBackend *t, OctetString *name, char *mode) { char cmd[PATH_MAX]; - int sock; + FILE *sock; char buf[8 * 1024]; - ssize_t nread; + size_t nread; size_t nwritten; - FILE *file = NULL; + FILE *out = NULL; snprintf(cmd, sizeof(cmd), "file %s\n", MHEGEngine_absoluteFilename(name)); - if((sock = remote_command(t, cmd)) < 0) + if((sock = remote_command(t, cmd)) == NULL) return NULL; /* does it exist */ if(remote_response(sock) == BACKEND_RESPONSE_OK) { - if((file = tmpfile()) != NULL) + /* tmpfile() will delete the file when we fclose() it */ + if((out = tmpfile()) != NULL) { /* read from the socket until EOF */ do { - if((nread = read(sock, buf, sizeof(buf))) > 0) - nwritten = fwrite(buf, 1, nread, file); + if((nread = fread(buf, 1, sizeof(buf), sock)) > 0) + nwritten = fwrite(buf, 1, nread, out); else nwritten = 0; } - while(nread > 0 && nread == nwritten); + while(!feof(sock) && nread == nwritten); /* could we write the file ok */ if(nread != nwritten) { error("Unable to write to local file"); - fclose(file); - file = NULL; + fclose(out); + out = NULL; } } } - close(sock); + fclose(sock); /* rewind the file */ - if(file != NULL) - rewind(file); + if(out != NULL) + rewind(out); - return file; + return out; } -/* - * close a FILE opened with MHEGEngine_openFile() - */ - -int -remote_closeFile(MHEGBackend *t, FILE *file) -{ - /* tmpfile() will delete the file for us */ - return fclose(file); -} - Modified: redbutton-browser/trunk/MHEGBackend.h =================================================================== --- redbutton-browser/trunk/MHEGBackend.h 2006-03-03 12:11:41 UTC (rev 12) +++ redbutton-browser/trunk/MHEGBackend.h 2006-03-03 12:17:06 UTC (rev 13) @@ -22,7 +22,6 @@ bool (*checkContentRef)(struct MHEGBackend *, ContentReference *); /* check a file exists */ bool (*loadFile)(struct MHEGBackend *, OctetString *, OctetString *); /* load a file */ FILE *(*openFile)(struct MHEGBackend *, OctetString *, char *); /* open a file */ - int (*closeFile)(struct MHEGBackend *, FILE *); /* close a file */ } *fns; } MHEGBackend; Modified: redbutton-browser/trunk/MHEGEngine.c =================================================================== --- redbutton-browser/trunk/MHEGEngine.c 2006-03-03 12:11:41 UTC (rev 12) +++ redbutton-browser/trunk/MHEGEngine.c 2006-03-03 12:17:06 UTC (rev 13) @@ -1332,16 +1332,6 @@ } /* - * close a FILE opened with MHEGEngine_openFile() - */ - -int -MHEGEngine_closeFile(FILE *file) -{ - return (*(engine.backend.fns->closeFile))(&engine.backend, file); -} - -/* * returns the absolute group ID, ie it always starts with "~//" * returns a ptr to static string that will be overwritten by the next call to this routine * section 8.3.2 of the UK MHEG Profile says the filename prefixes are: Modified: redbutton-browser/trunk/MHEGEngine.h =================================================================== --- redbutton-browser/trunk/MHEGEngine.h 2006-03-03 12:11:41 UTC (rev 12) +++ redbutton-browser/trunk/MHEGEngine.h 2006-03-03 12:17:06 UTC (rev 13) @@ -221,7 +221,7 @@ bool MHEGEngine_checkContentRef(ContentReference *); bool MHEGEngine_loadFile(OctetString *, OctetString *); FILE *MHEGEngine_openFile(OctetString *, char *); -int MHEGEngine_closeFile(FILE *); + char *MHEGEngine_absoluteFilename(OctetString *); /* convert PNG to internal format */ Modified: redbutton-browser/trunk/utils.c =================================================================== --- redbutton-browser/trunk/utils.c 2006-03-03 12:11:41 UTC (rev 12) +++ redbutton-browser/trunk/utils.c 2006-03-03 12:17:06 UTC (rev 13) @@ -31,46 +31,6 @@ #include "utils.h" /* - * write the given string (ie upto \0) to the given fd - */ - -void -write_string(int fd, const char *str) -{ - write_all(fd, str, strlen(str)); - - return; -} - -/* - * guarantee writing count bytes from buf to fd - * W. Richard Stevens - */ - -void -write_all(int fd, const void *buf, size_t count) -{ - size_t nwritten; - const char *buf_ptr; - - buf_ptr = buf; - while(count > 0) - { - if((nwritten = write(fd, buf_ptr, count)) < 0) - { - if(errno == EINTR || errno == EAGAIN) - nwritten = 0; - else - fatal("write: %s\n", strerror(errno)); - } - count -= nwritten; - buf_ptr += nwritten; - } - - return; -} - -/* * returns 15 for 'f' etc */ Modified: redbutton-browser/trunk/utils.h =================================================================== --- redbutton-browser/trunk/utils.h 2006-03-03 12:11:41 UTC (rev 12) +++ redbutton-browser/trunk/utils.h 2006-03-03 12:17:06 UTC (rev 13) @@ -33,9 +33,6 @@ #define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif -void write_string(int, const char *); -void write_all(int, const void *, size_t); - unsigned int char2hex(unsigned char); int next_utf8(unsigned char *, int, int *); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-03-03 16:51:28
|
Revision: 15 Author: skilvington Date: 2006-03-03 08:51:20 -0800 (Fri, 03 Mar 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=15&view=rev Log Message: ----------- add openStream() to frontend Modified Paths: -------------- redbutton-browser/trunk/MHEGApp.c redbutton-browser/trunk/MHEGBackend.c redbutton-browser/trunk/MHEGBackend.h redbutton-browser/trunk/MHEGEngine.c redbutton-browser/trunk/MHEGEngine.h Modified: redbutton-browser/trunk/MHEGApp.c =================================================================== --- redbutton-browser/trunk/MHEGApp.c 2006-03-03 13:45:56 UTC (rev 14) +++ redbutton-browser/trunk/MHEGApp.c 2006-03-03 16:51:20 UTC (rev 15) @@ -61,7 +61,7 @@ m->app = safe_malloc(sizeof(InterchangedObject)); bzero(m->app, sizeof(InterchangedObject)); - if((der = MHEGEngine_openFile(derfile, "r")) == NULL) + if((der = MHEGEngine_openFile(derfile)) == NULL) { error("Unable to open '%.*s'", derfile->size, derfile->data); safe_free(m->app); @@ -116,7 +116,7 @@ m->scene = safe_malloc(sizeof(InterchangedObject)); bzero(m->scene, sizeof(InterchangedObject)); - if((der = MHEGEngine_openFile(derfile, "r")) == NULL) + if((der = MHEGEngine_openFile(derfile)) == NULL) { error("Unable to open '%.*s'", derfile->size, derfile->data); safe_free(m->scene); Modified: redbutton-browser/trunk/MHEGBackend.c =================================================================== --- redbutton-browser/trunk/MHEGBackend.c 2006-03-03 13:45:56 UTC (rev 14) +++ redbutton-browser/trunk/MHEGBackend.c 2006-03-03 16:51:20 UTC (rev 15) @@ -16,25 +16,29 @@ /* local backend funcs */ bool local_checkContentRef(MHEGBackend *, ContentReference *); bool local_loadFile(MHEGBackend *, OctetString *, OctetString *); -FILE *local_openFile(MHEGBackend *, OctetString *, char *); +FILE *local_openFile(MHEGBackend *, OctetString *); +FILE *local_openStream(MHEGBackend *, bool, int, bool, int); static struct MHEGBackendFns local_backend_fns = { local_checkContentRef, /* checkContentRef */ local_loadFile, /* loadFile */ local_openFile, /* openFile */ + local_openStream, /* openStream */ }; /* remote backend funcs */ bool remote_checkContentRef(MHEGBackend *, ContentReference *); bool remote_loadFile(MHEGBackend *, OctetString *, OctetString *); -FILE *remote_openFile(MHEGBackend *, OctetString *, char *); +FILE *remote_openFile(MHEGBackend *, OctetString *); +FILE *remote_openStream(MHEGBackend *, bool, int, bool, int); static struct MHEGBackendFns remote_backend_fns = { remote_checkContentRef, /* checkContentRef */ remote_loadFile, /* loadFile */ remote_openFile, /* openFile */ + remote_openStream, /* openStream */ }; /* internal functions */ @@ -283,15 +287,42 @@ return (out->data != NULL); } +/* + * return a read-only FILE handle for the given carousel file + * returns NULL on error + */ + FILE * -local_openFile(MHEGBackend *t, OctetString *name, char *mode) +local_openFile(MHEGBackend *t, OctetString *name) { char *external = external_filename(t, name); - return fopen(external, mode); + return fopen(external, "r"); } /* + * return a read-only FILE handle for an MPEG Transport Stream + * the TS will contain an audio stream (if have_audio is true) and a video stream (if have_video is true) + * the audio_tag and video_tag numbers refer to Component/Association Tag values from the DVB PMT + * if audio_tag or video_tag is -1, the default audio and/or video stream for the current Service ID is used + * returns NULL on error + */ + +FILE * +local_openStream(MHEGBackend *t, bool have_audio, int audio_tag, bool have_video, int video_tag) +{ + /* + * we need to convert the audio/video_tag into PIDs + * we could either: + * 1. parse the PMT ourselves, and open the DVB device ourselves + * 2. have a backend command to convert Component Tags to PIDs, then open the DVB device ourselves + * 3. just stream the TS from the backend + * we choose 3, to avoid duplicating code and having to pass "-d <device>" options etc + */ + return remote_openStream(t, have_audio, audio_tag, have_video, video_tag); +} + +/* * remote routines */ @@ -366,8 +397,13 @@ return success; } +/* + * return a read-only FILE handle for the given carousel file + * returns NULL on error + */ + FILE * -remote_openFile(MHEGBackend *t, OctetString *name, char *mode) +remote_openFile(MHEGBackend *t, OctetString *name) { char cmd[PATH_MAX]; FILE *sock; @@ -415,3 +451,43 @@ return out; } +/* + * return a read-only FILE handle for an MPEG Transport Stream + * the TS will contain an audio stream (if have_audio is true) and a video stream (if have_video is true) + * the audio_tag and video_tag numbers refer to Component/Association Tag values from the DVB PMT + * if audio_tag or video_tag is -1, the default audio and/or video stream for the current Service ID is used + * returns NULL on error + */ + +FILE * +remote_openStream(MHEGBackend *t, bool have_audio, int audio_tag, bool have_video, int video_tag) +{ + char cmd[PATH_MAX]; + FILE *sock; + + /* no PIDs required */ + if(!have_audio && !have_video) + return NULL; + /* video and audio */ + else if(have_audio && have_video) + snprintf(cmd, sizeof(cmd), "avstream %d %d\n", audio_tag, video_tag); + /* audio only */ + else if(have_audio) + snprintf(cmd, sizeof(cmd), "astream %d\n", audio_tag); + /* video only */ + else + snprintf(cmd, sizeof(cmd), "vstream %d\n", video_tag); + + if((sock = remote_command(t, cmd)) == NULL) + return NULL; + + /* did it work */ + if(remote_response(sock) != BACKEND_RESPONSE_OK) + { + fclose(sock); + sock = NULL; + } + + return sock; +} + Modified: redbutton-browser/trunk/MHEGBackend.h =================================================================== --- redbutton-browser/trunk/MHEGBackend.h 2006-03-03 13:45:56 UTC (rev 14) +++ redbutton-browser/trunk/MHEGBackend.h 2006-03-03 16:51:20 UTC (rev 15) @@ -19,9 +19,10 @@ /* function pointers */ struct MHEGBackendFns { - bool (*checkContentRef)(struct MHEGBackend *, ContentReference *); /* check a file exists */ - bool (*loadFile)(struct MHEGBackend *, OctetString *, OctetString *); /* load a file */ - FILE *(*openFile)(struct MHEGBackend *, OctetString *, char *); /* open a file */ + bool (*checkContentRef)(struct MHEGBackend *, ContentReference *); /* check a carousel file exists */ + bool (*loadFile)(struct MHEGBackend *, OctetString *, OctetString *); /* load a carousel file */ + FILE *(*openFile)(struct MHEGBackend *, OctetString *); /* open a carousel file */ + FILE *(*openStream)(struct MHEGBackend *, bool, int, bool, int); /* open an MPEG Transport Stream */ } *fns; } MHEGBackend; Modified: redbutton-browser/trunk/MHEGEngine.c =================================================================== --- redbutton-browser/trunk/MHEGEngine.c 2006-03-03 13:45:56 UTC (rev 14) +++ redbutton-browser/trunk/MHEGEngine.c 2006-03-03 16:51:20 UTC (rev 15) @@ -1320,15 +1320,14 @@ } /* - * returns a FILE handle for the given carousel file - * mode is an fopen() mode, ie "r", "w", etc + * returns a read-only FILE handle for the given carousel file * returns NULL on error */ FILE * -MHEGEngine_openFile(OctetString *name, char *mode) +MHEGEngine_openFile(OctetString *name) { - return (*(engine.backend.fns->openFile))(&engine.backend, name, mode); + return (*(engine.backend.fns->openFile))(&engine.backend, name); } /* Modified: redbutton-browser/trunk/MHEGEngine.h =================================================================== --- redbutton-browser/trunk/MHEGEngine.h 2006-03-03 13:45:56 UTC (rev 14) +++ redbutton-browser/trunk/MHEGEngine.h 2006-03-03 16:51:20 UTC (rev 15) @@ -220,7 +220,7 @@ bool MHEGEngine_checkContentRef(ContentReference *); bool MHEGEngine_loadFile(OctetString *, OctetString *); -FILE *MHEGEngine_openFile(OctetString *, char *); +FILE *MHEGEngine_openFile(OctetString *); char *MHEGEngine_absoluteFilename(OctetString *); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-03-18 09:57:03
|
Revision: 22 Author: skilvington Date: 2006-03-18 01:56:46 -0800 (Sat, 18 Mar 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=22&view=rev Log Message: ----------- return audio/video PIDs to stream player Modified Paths: -------------- redbutton-browser/trunk/MHEGBackend.c redbutton-browser/trunk/MHEGBackend.h redbutton-browser/trunk/MHEGEngine.c redbutton-browser/trunk/MHEGEngine.h redbutton-browser/trunk/MHEGStreamPlayer.c redbutton-browser/trunk/MHEGStreamPlayer.h Modified: redbutton-browser/trunk/MHEGBackend.c =================================================================== --- redbutton-browser/trunk/MHEGBackend.c 2006-03-15 16:03:26 UTC (rev 21) +++ redbutton-browser/trunk/MHEGBackend.c 2006-03-18 09:56:46 UTC (rev 22) @@ -17,7 +17,7 @@ bool local_checkContentRef(MHEGBackend *, ContentReference *); bool local_loadFile(MHEGBackend *, OctetString *, OctetString *); FILE *local_openFile(MHEGBackend *, OctetString *); -FILE *local_openStream(MHEGBackend *, bool, int, bool, int); +FILE *local_openStream(MHEGBackend *, bool, int *, bool, int *); static struct MHEGBackendFns local_backend_fns = { @@ -31,7 +31,7 @@ bool remote_checkContentRef(MHEGBackend *, ContentReference *); bool remote_loadFile(MHEGBackend *, OctetString *, OctetString *); FILE *remote_openFile(MHEGBackend *, OctetString *); -FILE *remote_openStream(MHEGBackend *, bool, int, bool, int); +FILE *remote_openStream(MHEGBackend *, bool, int *, bool, int *); static struct MHEGBackendFns remote_backend_fns = { @@ -305,13 +305,14 @@ /* * return a read-only FILE handle for an MPEG Transport Stream * the TS will contain an audio stream (if have_audio is true) and a video stream (if have_video is true) - * the audio_tag and video_tag numbers refer to Component/Association Tag values from the DVB PMT - * if audio_tag or video_tag is -1, the default audio and/or video stream for the current Service ID is used + * the *audio_tag and *video_tag numbers refer to Component/Association Tag values from the DVB PMT + * if *audio_tag or *video_tag is -1, the default audio and/or video stream for the current Service ID is used + * updates *audio_tag and/or *video_tag to the actual PIDs in the Transport Stream * returns NULL on error */ FILE * -local_openStream(MHEGBackend *t, bool have_audio, int audio_tag, bool have_video, int video_tag) +local_openStream(MHEGBackend *t, bool have_audio, int *audio_tag, bool have_video, int *video_tag) { /* * we need to convert the audio/video_tag into PIDs @@ -456,40 +457,67 @@ /* * return a read-only FILE handle for an MPEG Transport Stream * the TS will contain an audio stream (if have_audio is true) and a video stream (if have_video is true) - * the audio_tag and video_tag numbers refer to Component/Association Tag values from the DVB PMT - * if audio_tag or video_tag is -1, the default audio and/or video stream for the current Service ID is used + * the *audio_tag and *video_tag numbers refer to Component/Association Tag values from the DVB PMT + * if *audio_tag or *video_tag is -1, the default audio and/or video stream for the current Service ID is used + * updates *audio_tag and/or *video_tag to the actual PIDs in the Transport Stream * returns NULL on error */ FILE * -remote_openStream(MHEGBackend *t, bool have_audio, int audio_tag, bool have_video, int video_tag) +remote_openStream(MHEGBackend *t, bool have_audio, int *audio_tag, bool have_video, int *video_tag) { char cmd[PATH_MAX]; FILE *sock; + char pids[128]; + unsigned int audio_pid = 0; + unsigned int video_pid = 0; + bool err; /* no PIDs required */ if(!have_audio && !have_video) return NULL; /* video and audio */ else if(have_audio && have_video) - snprintf(cmd, sizeof(cmd), "avstream %d %d\n", audio_tag, video_tag); + snprintf(cmd, sizeof(cmd), "avstream %d %d\n", *audio_tag, *video_tag); /* audio only */ else if(have_audio) - snprintf(cmd, sizeof(cmd), "astream %d\n", audio_tag); + snprintf(cmd, sizeof(cmd), "astream %d\n", *audio_tag); /* video only */ else - snprintf(cmd, sizeof(cmd), "vstream %d\n", video_tag); + snprintf(cmd, sizeof(cmd), "vstream %d\n", *video_tag); if((sock = remote_command(t, cmd)) == NULL) return NULL; /* did it work */ - if(remote_response(sock) != BACKEND_RESPONSE_OK) + if(remote_response(sock) != BACKEND_RESPONSE_OK + || fgets(pids, sizeof(pids), sock) == NULL) { fclose(sock); sock = NULL; } + /* update the PID variables */ + if(have_audio && have_video) + err = (sscanf(pids, "AudioPID %u VideoPID %u", &audio_pid, &video_pid) != 2); + else if(have_audio) + err = (sscanf(pids, "AudioPID %u", &audio_pid) != 1); + else + err = (sscanf(pids, "VideoPID %u", &video_pid) != 1); + + if(!err) + { + if(have_audio) + *audio_tag = audio_pid; + if(have_video) + *video_tag = video_pid; + } + else + { + fclose(sock); + sock = NULL; + } + return sock; } Modified: redbutton-browser/trunk/MHEGBackend.h =================================================================== --- redbutton-browser/trunk/MHEGBackend.h 2006-03-15 16:03:26 UTC (rev 21) +++ redbutton-browser/trunk/MHEGBackend.h 2006-03-18 09:56:46 UTC (rev 22) @@ -22,7 +22,7 @@ bool (*checkContentRef)(struct MHEGBackend *, ContentReference *); /* check a carousel file exists */ bool (*loadFile)(struct MHEGBackend *, OctetString *, OctetString *); /* load a carousel file */ FILE *(*openFile)(struct MHEGBackend *, OctetString *); /* open a carousel file */ - FILE *(*openStream)(struct MHEGBackend *, bool, int, bool, int); /* open an MPEG Transport Stream */ + FILE *(*openStream)(struct MHEGBackend *, bool, int *, bool, int *); /* open an MPEG Transport Stream */ } *fns; } MHEGBackend; Modified: redbutton-browser/trunk/MHEGEngine.c =================================================================== --- redbutton-browser/trunk/MHEGEngine.c 2006-03-15 16:03:26 UTC (rev 21) +++ redbutton-browser/trunk/MHEGEngine.c 2006-03-18 09:56:46 UTC (rev 22) @@ -1331,6 +1331,21 @@ } /* + * return a read-only FILE handle for an MPEG Transport Stream + * the TS will contain an audio stream (if have_audio is true) and a video stream (if have_video is true) + * the *audio_tag and *video_tag numbers refer to Component/Association Tag values from the DVB PMT + * if *audio_tag or *video_tag is -1, the default audio and/or video stream for the current Service ID is used + * updates *audio_tag and/or *video_tag to the actual PIDs in the Transport Stream + * returns NULL on error + */ + +FILE * +MHEGEngine_openStream(bool have_audio, int *audio_tag, bool have_video, int *video_tag) +{ + return (*(engine.backend.fns->openStream))(&engine.backend, have_audio, audio_tag, have_video, video_tag); +} + +/* * returns the absolute group ID, ie it always starts with "~//" * returns a ptr to static string that will be overwritten by the next call to this routine * section 8.3.2 of the UK MHEG Profile says the filename prefixes are: Modified: redbutton-browser/trunk/MHEGEngine.h =================================================================== --- redbutton-browser/trunk/MHEGEngine.h 2006-03-15 16:03:26 UTC (rev 21) +++ redbutton-browser/trunk/MHEGEngine.h 2006-03-18 09:56:46 UTC (rev 22) @@ -221,6 +221,7 @@ bool MHEGEngine_checkContentRef(ContentReference *); bool MHEGEngine_loadFile(OctetString *, OctetString *); FILE *MHEGEngine_openFile(OctetString *); +FILE *MHEGEngine_openStream(bool, int *, bool, int *); char *MHEGEngine_absoluteFilename(OctetString *); Modified: redbutton-browser/trunk/MHEGStreamPlayer.c =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.c 2006-03-15 16:03:26 UTC (rev 21) +++ redbutton-browser/trunk/MHEGStreamPlayer.c 2006-03-18 09:56:46 UTC (rev 22) @@ -5,6 +5,7 @@ #include <string.h> #include <stdio.h> +#include "MHEGEngine.h" #include "MHEGStreamPlayer.h" #include "utils.h" @@ -35,6 +36,7 @@ p->have_video = true; p->video_tag = tag; + p->video_pid = -1; return; } @@ -47,6 +49,7 @@ p->have_audio = true; p->audio_tag = tag; + p->audio_pid = -1; return; } @@ -54,10 +57,14 @@ void MHEGStreamPlayer_play(MHEGStreamPlayer *p) { + verbose("MHEGStreamPlayer_play: audio_tag=%d video_tag=%d", p->audio_tag, p->video_tag); + + p->audio_pid = p->audio_tag; + p->video_pid = p->video_tag; +// if((p->ts = MHEGEngine_openStream(p->have_audio, &p->audio_pid, p->have_video, &p->video_pid)) == NULL) +// error("Unable to open MPEG stream"); /* TODO */ printf("TODO: MHEGStreamPlayer_play: not yet implemented\n"); -if(p->have_audio) printf("TODO: audio tag=%d\n", p->audio_tag); -if(p->have_video) printf("TODO: video tag=%d\n", p->video_tag); return; } @@ -65,9 +72,11 @@ void MHEGStreamPlayer_stop(MHEGStreamPlayer *p) { -/* TODO */ -printf("TODO: MHEGStreamPlayer_stop: not yet implemented\n"); + verbose("MHEGStreamPlayer_stop"); + if(p->ts != NULL) + fclose(p->ts); + return; } Modified: redbutton-browser/trunk/MHEGStreamPlayer.h =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.h 2006-03-15 16:03:26 UTC (rev 21) +++ redbutton-browser/trunk/MHEGStreamPlayer.h 2006-03-18 09:56:46 UTC (rev 22) @@ -13,6 +13,9 @@ bool have_audio; /* false if we have no audio stream */ int video_tag; /* video stream component tag (-1 => default for current service ID) */ int audio_tag; /* audio stream component tag (-1 => default for current service ID) */ + int video_pid; /* PID in MPEG Transport Stream (-1 => not yet known) */ + int audio_pid; /* PID in MPEG Transport Stream (-1 => not yet known) */ + FILE *ts; /* MPEG Transport Stream */ } MHEGStreamPlayer; void MHEGStreamPlayer_init(MHEGStreamPlayer *); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-03-25 10:43:26
|
Revision: 26 Author: skilvington Date: 2006-03-25 02:43:15 -0800 (Sat, 25 Mar 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=26&view=rev Log Message: ----------- backend returns file size Modified Paths: -------------- redbutton-browser/trunk/MHEGBackend.c redbutton-download/trunk/command.c Modified: redbutton-browser/trunk/MHEGBackend.c =================================================================== --- redbutton-browser/trunk/MHEGBackend.c 2006-03-21 16:52:10 UTC (rev 25) +++ redbutton-browser/trunk/MHEGBackend.c 2006-03-25 10:43:15 UTC (rev 26) @@ -363,41 +363,46 @@ { char cmd[PATH_MAX]; FILE *sock; - char buf[8 * 1024]; + unsigned int size; size_t nread; - bool success = false; snprintf(cmd, sizeof(cmd), "file %s\n", MHEGEngine_absoluteFilename(name)); if((sock = remote_command(t, cmd)) == NULL) return false; - /* does it exist */ - if(remote_response(sock) == BACKEND_RESPONSE_OK) + /* if it exists, read the file size */ + if(remote_response(sock) != BACKEND_RESPONSE_OK + || fgets(cmd, sizeof(cmd), sock) == NULL + || sscanf(cmd, "Length %u", &size) != 1) { - verbose("Loading '%.*s'", name->size, name->data); - /* read from the socket until EOF */ - while(!feof(sock)) - { -/* TODO */ -/* could read straight into out->data rather than doing memcpy */ - if((nread = fread(buf, 1, sizeof(buf), sock)) > 0) - { - out->data = safe_realloc(out->data, out->size + nread); - memcpy(out->data + out->size, buf, nread); - out->size += nread; - } - } - success = true; + error("Unable to load '%.*s'", name->size, name->data); + fclose(sock); + return false; } - else + + verbose("Loading '%.*s'", name->size, name->data); + + out->size = size; + out->data = safe_malloc(size); + + nread = 0; + while(!feof(sock) && nread < size) + nread += fread(out->data + nread, 1, size - nread, sock); + + fclose(sock); + + /* did we read it all */ + if(nread < size) { error("Unable to load '%.*s'", name->size, name->data); + safe_free(out->data); + out->data = NULL; + out->size = 0; + return false; } - fclose(sock); - - return success; + return true; } /* @@ -410,39 +415,38 @@ { char cmd[PATH_MAX]; FILE *sock; + unsigned int size; char buf[8 * 1024]; size_t nread; - size_t nwritten; - FILE *out = NULL; + FILE *out; snprintf(cmd, sizeof(cmd), "file %s\n", MHEGEngine_absoluteFilename(name)); if((sock = remote_command(t, cmd)) == NULL) return NULL; - /* does it exist */ - if(remote_response(sock) == BACKEND_RESPONSE_OK) + /* if it exists, read the file size */ + if(remote_response(sock) != BACKEND_RESPONSE_OK + || fgets(cmd, sizeof(cmd), sock) == NULL + || sscanf(cmd, "Length %u", &size) != 1) { - /* tmpfile() will delete the file when we fclose() it */ - if((out = tmpfile()) != NULL) + fclose(sock); + return NULL; + } + + /* tmpfile() will delete the file when we fclose() it */ + out = tmpfile(); + while(out != NULL && size > 0) + { + nread = (size < sizeof(buf)) ? size : sizeof(buf); + nread = fread(buf, 1, nread, sock); + if(fwrite(buf, 1, nread, out) != nread) { - /* read from the socket until EOF */ - do - { - if((nread = fread(buf, 1, sizeof(buf), sock)) > 0) - nwritten = fwrite(buf, 1, nread, out); - else - nwritten = 0; - } - while(!feof(sock) && nread == nwritten); - /* could we write the file ok */ - if(nread != nwritten) - { - error("Unable to write to local file"); - fclose(out); - out = NULL; - } + error("Unable to write to local file"); + fclose(out); + out = NULL; } + size -= nread; } fclose(sock); Modified: redbutton-download/trunk/command.c =================================================================== --- redbutton-download/trunk/command.c 2006-03-21 16:52:10 UTC (rev 25) +++ redbutton-download/trunk/command.c 2006-03-25 10:43:15 UTC (rev 26) @@ -367,6 +367,9 @@ { char *filename; FILE *file; + long size; + char hdr[64]; + long left; size_t nread; char buff[1024 * 8]; @@ -384,15 +387,29 @@ return false; } + /* find the file length */ + if(fseek(file, 0, SEEK_END) < 0 + || (size = ftell(file)) < 0) + { + SEND_RESPONSE(500, "Error reading file"); + return false; + } + rewind(file); + SEND_RESPONSE(200, "OK"); + /* send the file length */ + snprintf(hdr, sizeof(hdr), "Length %ld\n", size); + write_string(client_sock, hdr); + /* send the file contents */ - do + left = size; + while(left > 0) { nread = fread(buff, 1, sizeof(buff), file); write_all(client_sock, buff, nread); + left -= nread; } - while(nread == sizeof(buff)); fclose(file); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-03-25 14:20:17
|
Revision: 27 Author: skilvington Date: 2006-03-25 06:19:43 -0800 (Sat, 25 Mar 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=27&view=rev Log Message: ----------- keep the connection to the backend open Modified Paths: -------------- redbutton-browser/trunk/MHEGBackend.c redbutton-browser/trunk/MHEGBackend.h redbutton-download/trunk/command.c redbutton-download/trunk/command.h redbutton-download/trunk/listen.c redbutton-download/trunk/stream.c redbutton-download/trunk/stream.h redbutton-download/trunk/utils.c redbutton-download/trunk/utils.h Modified: redbutton-browser/trunk/MHEGBackend.c =================================================================== --- redbutton-browser/trunk/MHEGBackend.c 2006-03-25 10:43:15 UTC (rev 26) +++ redbutton-browser/trunk/MHEGBackend.c 2006-03-25 14:19:43 UTC (rev 27) @@ -45,7 +45,7 @@ static int parse_addr(char *, struct in_addr *, in_port_t *); static int get_host_addr(char *, struct in_addr *); -static FILE *remote_command(MHEGBackend *, char *); +static FILE *remote_command(MHEGBackend *, bool, char *); static unsigned int remote_response(FILE *); static char *external_filename(MHEGBackend *, OctetString *); @@ -61,6 +61,9 @@ b->addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); b->addr.sin_port = htons(DEFAULT_REMOTE_PORT); + /* no connection to the backend yet */ + b->be_sock = NULL; + if(remote) { /* backend is on a different host, srg_loc is the remote host[:port] */ @@ -83,6 +86,11 @@ void MHEGBackend_fini(MHEGBackend *b) { + /* send quit command */ + if(b->be_sock != NULL + && remote_command(b, true, "quit\n") != NULL) + fclose(b->be_sock); + return; } @@ -142,23 +150,30 @@ /* * send the given command to the remote backend + * if reuse is true, reuse the existing connection to the backend * returns a socket FILE to read the response from * returns NULL if it can't contact the backend */ static FILE * -remote_command(MHEGBackend *t, char *cmd) +remote_command(MHEGBackend *t, bool reuse, char *cmd) { int sock; FILE *file; - /* connect to the backend */ + /* can we use the existing connection */ + if(reuse && t->be_sock != NULL) + { + fputs(cmd, t->be_sock); + return t->be_sock; + } + + /* need to connect to the backend */ if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { error("Unable to create backend socket: %s", strerror(errno)); return NULL; } - if(connect(sock, (struct sockaddr *) &t->addr, sizeof(struct sockaddr_in)) < 0) { error("Unable to connect to backend: %s", strerror(errno)); @@ -178,6 +193,10 @@ close(sock); } + /* remember it if we need to reuse it */ + if(reuse) + t->be_sock = file; + return file; } @@ -342,13 +361,11 @@ snprintf(cmd, sizeof(cmd), "check %s\n", MHEGEngine_absoluteFilename(name)); - if((sock = remote_command(t, cmd)) == NULL) + if((sock = remote_command(t, true, cmd)) == NULL) return false; exists = (remote_response(sock) == BACKEND_RESPONSE_OK); - fclose(sock); - return exists; } @@ -368,7 +385,7 @@ snprintf(cmd, sizeof(cmd), "file %s\n", MHEGEngine_absoluteFilename(name)); - if((sock = remote_command(t, cmd)) == NULL) + if((sock = remote_command(t, true, cmd)) == NULL) return false; /* if it exists, read the file size */ @@ -377,7 +394,6 @@ || sscanf(cmd, "Length %u", &size) != 1) { error("Unable to load '%.*s'", name->size, name->data); - fclose(sock); return false; } @@ -390,8 +406,6 @@ while(!feof(sock) && nread < size) nread += fread(out->data + nread, 1, size - nread, sock); - fclose(sock); - /* did we read it all */ if(nread < size) { @@ -422,7 +436,7 @@ snprintf(cmd, sizeof(cmd), "file %s\n", MHEGEngine_absoluteFilename(name)); - if((sock = remote_command(t, cmd)) == NULL) + if((sock = remote_command(t, true, cmd)) == NULL) return NULL; /* if it exists, read the file size */ @@ -430,7 +444,6 @@ || fgets(cmd, sizeof(cmd), sock) == NULL || sscanf(cmd, "Length %u", &size) != 1) { - fclose(sock); return NULL; } @@ -449,8 +462,6 @@ size -= nread; } - fclose(sock); - /* rewind the file */ if(out != NULL) rewind(out); @@ -490,7 +501,8 @@ else snprintf(cmd, sizeof(cmd), "vstream %d\n", *video_tag); - if((sock = remote_command(t, cmd)) == NULL) + /* false => create a new connection to the backend */ + if((sock = remote_command(t, false, cmd)) == NULL) return NULL; /* did it work */ Modified: redbutton-browser/trunk/MHEGBackend.h =================================================================== --- redbutton-browser/trunk/MHEGBackend.h 2006-03-25 10:43:15 UTC (rev 26) +++ redbutton-browser/trunk/MHEGBackend.h 2006-03-25 14:19:43 UTC (rev 27) @@ -16,6 +16,7 @@ { char *base_dir; /* local Service Gateway root directory */ struct sockaddr_in addr; /* remote backend IP and port */ + FILE *be_sock; /* connection to remote backend */ /* function pointers */ struct MHEGBackendFns { Modified: redbutton-download/trunk/command.c =================================================================== --- redbutton-download/trunk/command.c 2006-03-25 10:43:15 UTC (rev 26) +++ redbutton-download/trunk/command.c 2006-03-25 14:19:43 UTC (rev 27) @@ -19,35 +19,35 @@ #define ARGV_MAX 10 /* the commands */ -bool cmd_astream(struct listen_data *, int, int, char **); -bool cmd_avstream(struct listen_data *, int, int, char **); -bool cmd_check(struct listen_data *, int, int, char **); -bool cmd_file(struct listen_data *, int, int, char **); -bool cmd_help(struct listen_data *, int, int, char **); -bool cmd_quit(struct listen_data *, int, int, char **); -bool cmd_vstream(struct listen_data *, int, int, char **); +bool cmd_astream(struct listen_data *, FILE *, int, char **); +bool cmd_avstream(struct listen_data *, FILE *, int, char **); +bool cmd_check(struct listen_data *, FILE *, int, char **); +bool cmd_file(struct listen_data *, FILE *, int, char **); +bool cmd_help(struct listen_data *, FILE *, int, char **); +bool cmd_quit(struct listen_data *, FILE *, int, char **); +bool cmd_vstream(struct listen_data *, FILE *, int, char **); static struct { char *name; char *args; - bool (*proc)(struct listen_data *, int, int, char **); + bool (*proc)(struct listen_data *, FILE *, int, char **); char *help; } command[] = { { "astream", "<ComponentTag>", cmd_astream, "Stream the given audio component tag" }, { "avstream", "<AudioTag> <VideoTag>", cmd_avstream, "Stream the given audio and video component tags" }, { "check", "<ContentReference>", cmd_check, "Check if the given file exists on the carousel" }, - { "exit", "", cmd_quit, "Kill the programme" }, + { "exit", "", cmd_quit, "close the connection" }, { "file", "<ContentReference>", cmd_file, "Retrieve the given file from the carousel" }, { "help", "", cmd_help, "List available commands" }, - { "quit", "", cmd_quit, "Kill the programme" }, + { "quit", "", cmd_quit, "close the connection" }, { "vstream", "<ComponentTag>", cmd_vstream, "Stream the given video component tag" }, { NULL, NULL, NULL, NULL } }; /* send an OK/error code etc response down client_sock */ -#define SEND_RESPONSE(RC, MESSAGE) write_string(client_sock, #RC " " MESSAGE "\n") +#define SEND_RESPONSE(RC, MESSAGE) fputs(#RC " " MESSAGE "\n", client) /* internal routines */ char *external_filename(struct listen_data *, char *); @@ -55,11 +55,11 @@ /* * process the given command - * return true if we should quit the programme + * return true if we should close the connection */ bool -process_command(struct listen_data *listen_data, int client_sock, char *cmd) +process_command(struct listen_data *listen_data, FILE *client, char *cmd) { int argc; char *argv[ARGV_MAX]; @@ -102,7 +102,7 @@ for(i=0; command[i].name != NULL; i++) { if(strncmp(argv[0], command[i].name, cmd_len) == 0) - return (command[i].proc)(listen_data, client_sock, argc, argv); + return (command[i].proc)(listen_data, client, argc, argv); } SEND_RESPONSE(500, "Unrecognised command"); @@ -113,10 +113,10 @@ /* * the commands * listen_data is global data needed by listener commands - * client_sock is where any response data should go + * client is where any response data should go * argc is the number of arguments passed to it * argv[0] is the command name (or the abreviation the user used) - * return true if we should quit the programme + * return true if we should close the connection */ #define CHECK_USAGE(ARGC, SYNTAX) \ @@ -135,7 +135,7 @@ */ bool -cmd_astream(struct listen_data *listen_data, int client_sock, int argc, char *argv[]) +cmd_astream(struct listen_data *listen_data, FILE *client, int argc, char *argv[]) { struct carousel *car = listen_data->carousel; int tag; @@ -174,16 +174,17 @@ /* tell the client what PID the component tag resolved to */ snprintf(hdr, sizeof(hdr), "AudioPID %u\n", pid); - write_string(client_sock, hdr); + fputs(hdr, client); - /* shovel the transport stream down client_sock until the client closes it or we get an error */ - stream_ts(ts_fd, client_sock); + /* shovel the transport stream to client until the client closes or we get an error */ + stream_ts(ts_fd, client); /* clean up */ close(ts_fd); close(audio_fd); - return false; + /* close the connection */ + return true; } /* @@ -195,7 +196,7 @@ */ bool -cmd_vstream(struct listen_data *listen_data, int client_sock, int argc, char *argv[]) +cmd_vstream(struct listen_data *listen_data, FILE *client, int argc, char *argv[]) { struct carousel *car = listen_data->carousel; int tag; @@ -234,16 +235,17 @@ /* tell the client what PID the component tag resolved to */ snprintf(hdr, sizeof(hdr), "VideoPID %u\n", pid); - write_string(client_sock, hdr); + fputs(hdr, client); /* shovel the transport stream down client_sock until the client closes it or we get an error */ - stream_ts(ts_fd, client_sock); + stream_ts(ts_fd, client); /* clean up */ close(ts_fd); close(video_fd); - return false; + /* close the connection */ + return true; } /* @@ -255,7 +257,7 @@ */ bool -cmd_avstream(struct listen_data *listen_data, int client_sock, int argc, char *argv[]) +cmd_avstream(struct listen_data *listen_data, FILE *client, int argc, char *argv[]) { struct carousel *car = listen_data->carousel; int audio_tag; @@ -310,17 +312,18 @@ /* tell the client what PIDs the component tags resolved to */ snprintf(hdr, sizeof(hdr), "AudioPID %u VideoPID %u\n", audio_pid, video_pid); - write_string(client_sock, hdr); + fputs(hdr, client); /* shovel the transport stream down client_sock until the client closes it or we get an error */ - stream_ts(ts_fd, client_sock); + stream_ts(ts_fd, client); /* clean up */ close(ts_fd); close(audio_fd); close(video_fd); - return false; + /* close the connection */ + return true; } /* @@ -330,7 +333,7 @@ */ bool -cmd_check(struct listen_data *listen_data, int client_sock, int argc, char *argv[]) +cmd_check(struct listen_data *listen_data, FILE *client, int argc, char *argv[]) { char *filename; FILE *file; @@ -363,7 +366,7 @@ */ bool -cmd_file(struct listen_data *listen_data, int client_sock, int argc, char *argv[]) +cmd_file(struct listen_data *listen_data, FILE *client, int argc, char *argv[]) { char *filename; FILE *file; @@ -400,14 +403,14 @@ /* send the file length */ snprintf(hdr, sizeof(hdr), "Length %ld\n", size); - write_string(client_sock, hdr); + fputs(hdr, client); /* send the file contents */ left = size; while(left > 0) { nread = fread(buff, 1, sizeof(buff), file); - write_all(client_sock, buff, nread); + fwrite(buff, 1, nread, client); left -= nread; } @@ -421,7 +424,7 @@ */ bool -cmd_help(struct listen_data *listen_data, int client_sock, int argc, char *argv[]) +cmd_help(struct listen_data *listen_data, FILE *client, int argc, char *argv[]) { int i; char name_args[64]; @@ -433,7 +436,7 @@ { snprintf(name_args, sizeof(name_args), "%s %s", command[i].name, command[i].args); snprintf(help_line, sizeof(help_line), "%-30s %s\n", name_args, command[i].help); - write_string(client_sock, help_line); + fputs(help_line, client); } return false; @@ -444,7 +447,7 @@ */ bool -cmd_quit(struct listen_data *listen_data, int client_sock, int argc, char *argv[]) +cmd_quit(struct listen_data *listen_data, FILE *client, int argc, char *argv[]) { return true; } Modified: redbutton-download/trunk/command.h =================================================================== --- redbutton-download/trunk/command.h 2006-03-25 10:43:15 UTC (rev 26) +++ redbutton-download/trunk/command.h 2006-03-25 14:19:43 UTC (rev 27) @@ -7,6 +7,6 @@ #include "listen.h" -bool process_command(struct listen_data *, int, char *); +bool process_command(struct listen_data *, FILE *, char *); #endif Modified: redbutton-download/trunk/listen.c =================================================================== --- redbutton-download/trunk/listen.c 2006-03-25 10:43:15 UTC (rev 26) +++ redbutton-download/trunk/listen.c 2006-03-25 14:19:43 UTC (rev 27) @@ -25,7 +25,7 @@ /* internal functions */ static int get_host_addr(char *, struct in_addr *); -static bool handle_connection(struct listen_data *, int, struct sockaddr_in *); +static void handle_connection(struct listen_data *, int, struct sockaddr_in *); static void dead_child(int); /* @@ -117,7 +117,6 @@ fd_set read_fds; socklen_t addr_len; struct sockaddr_in client_addr; - bool quit; /* * fork: @@ -189,10 +188,8 @@ { /* child */ close(listen_sock); - quit = handle_connection(listen_data, accept_sock, &client_addr); + handle_connection(listen_data, accept_sock, &client_addr); close(accept_sock); -/* TODO */ -if(quit) printf("TODO: QUIT\n"); /* use _exit in child so stdio etc don't clean up twice */ _exit(EXIT_SUCCESS); } @@ -213,31 +210,44 @@ * handle a connection from a remote rb-browser */ -static bool +static void handle_connection(struct listen_data *listen_data, int client_sock, struct sockaddr_in *client_addr) { + FILE *client; char cmd[1024]; - ssize_t nread; - bool quit = false; + size_t len; + bool quit; printf("Connection from %s:%d\n", inet_ntoa(client_addr->sin_addr), ntohs(client_addr->sin_port)); - /* read the command from the client */ - if((nread = read(client_sock, cmd, sizeof(cmd)-1)) > 0) + if((client = fdopen(client_sock, "r+")) == NULL) + return; + + /* read commands from the client */ + quit = false; + while(!feof(client) && !quit) { - /* \0 terminate the buffer */ - cmd[nread] = '\0'; - /* strip off any trailing \n */ - nread --; - while(nread > 0 && (cmd[nread] == '\n' || cmd[nread] == '\r')) - cmd[nread--] = '\0'; - /* process the command */ - quit = process_command(listen_data, client_sock, cmd); + if(fgets(cmd, sizeof(cmd), client) == NULL) + { + quit = true; + } + else + { + /* strip off any trailing \n */ + len = strlen(cmd); + len = (len > 0) ? len -1 : len; + while(len > 0 && (cmd[len] == '\n' || cmd[len] == '\r')) + cmd[len--] = '\0'; + /* process the command */ + quit = process_command(listen_data, client, cmd); + } } + fclose(client); + printf("Connection from %s:%d closed\n", inet_ntoa(client_addr->sin_addr), ntohs(client_addr->sin_port)); - return quit; + return; } static void Modified: redbutton-download/trunk/stream.c =================================================================== --- redbutton-download/trunk/stream.c 2006-03-25 10:43:15 UTC (rev 26) +++ redbutton-download/trunk/stream.c 2006-03-25 14:19:43 UTC (rev 27) @@ -44,20 +44,20 @@ static unsigned char _ts_buf[8 * 1024]; void -stream_ts(int ts_fd, int client_sock) +stream_ts(int ts_fd, FILE *client) { ssize_t nread; - ssize_t nwritten; + size_t nwritten; do { nread = read(ts_fd, _ts_buf, sizeof(_ts_buf)); if(nread > 0) - nwritten = write(client_sock, _ts_buf, nread); + nwritten = fwrite(_ts_buf, 1, nread, client); else nwritten = nread; } - while(nread == nwritten); + while(!feof(client) && nread == nwritten); return; } Modified: redbutton-download/trunk/stream.h =================================================================== --- redbutton-download/trunk/stream.h 2006-03-25 10:43:15 UTC (rev 26) +++ redbutton-download/trunk/stream.h 2006-03-25 14:19:43 UTC (rev 27) @@ -5,11 +5,12 @@ #ifndef __STREAM_H__ #define __STREAM_H__ +#include <stdio.h> #include <stdint.h> #include <linux/dvb/dmx.h> int add_demux_filter(char *, uint16_t, dmx_pes_type_t); -void stream_ts(int, int); +void stream_ts(int, FILE *); #endif /* __STREAM_H__ */ Modified: redbutton-download/trunk/utils.c =================================================================== --- redbutton-download/trunk/utils.c 2006-03-25 10:43:15 UTC (rev 26) +++ redbutton-download/trunk/utils.c 2006-03-25 14:19:43 UTC (rev 27) @@ -31,46 +31,6 @@ #include "utils.h" /* - * write the given string (ie upto \0) to the given fd - */ - -void -write_string(int fd, const char *str) -{ - write_all(fd, str, strlen(str)); - - return; -} - -/* - * guarantee writing count bytes from buf to fd - * W. Richard Stevens - */ - -void -write_all(int fd, const void *buf, size_t count) -{ - size_t nwritten; - const char *buf_ptr; - - buf_ptr = buf; - while(count > 0) - { - if((nwritten = write(fd, buf_ptr, count)) < 0) - { - if(errno == EINTR || errno == EAGAIN) - nwritten = 0; - else - fatal("write: %s\n", strerror(errno)); - } - count -= nwritten; - buf_ptr += nwritten; - } - - return; -} - -/* * move str to the next non-white space character (or the end of the string) */ Modified: redbutton-download/trunk/utils.h =================================================================== --- redbutton-download/trunk/utils.h 2006-03-25 10:43:15 UTC (rev 26) +++ redbutton-download/trunk/utils.h 2006-03-25 14:19:43 UTC (rev 27) @@ -37,9 +37,6 @@ /* DVB dvr device - %u is card number */ #define DVR_DEVICE "/dev/dvb/adapter%u/dvr0" -void write_string(int, const char *); -void write_all(int, const void *, size_t); - char *skip_ws(char *); char hex_digit(uint8_t); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-04-03 11:03:00
|
Revision: 37 Author: skilvington Date: 2006-04-03 04:02:48 -0700 (Mon, 03 Apr 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=37&view=rev Log Message: ----------- fix tar make targets Modified Paths: -------------- redbutton-browser/trunk/Makefile redbutton-download/trunk/Makefile Modified: redbutton-browser/trunk/Makefile =================================================================== --- redbutton-browser/trunk/Makefile 2006-04-03 10:55:20 UTC (rev 36) +++ redbutton-browser/trunk/Makefile 2006-04-03 11:02:48 UTC (rev 37) @@ -110,9 +110,8 @@ rm -f rb-browser rb-keymap xsd2c dertest dertest-mheg.[ch] berdecode *.o ISO13522-MHEG-5.[ch] clone.[ch] rtti.h core TARDIR=`basename ${PWD}` -DATE=`date +%Y%m%d` tar: make clean - (cd ..; tar zcvf ${TARDIR}-${DATE}.tar.gz ${TARDIR}) + (cd ..; tar zcvf ${TARDIR}.tar.gz --exclude .svn ${TARDIR}) Modified: redbutton-download/trunk/Makefile =================================================================== --- redbutton-download/trunk/Makefile 2006-04-03 10:55:20 UTC (rev 36) +++ redbutton-download/trunk/Makefile 2006-04-03 11:02:48 UTC (rev 37) @@ -19,7 +19,6 @@ LIBS=-lz TARDIR=`basename ${PWD}` -DATE=`date +%Y%m%d` rb-download: ${OBJS} ${CC} ${CFLAGS} -o rb-download ${OBJS} ${LIBS} @@ -32,6 +31,5 @@ tar: make clean - (cd ..; tar zcvf ${TARDIR}-${DATE}.tar.gz ${TARDIR}) + (cd ..; tar zcvf ${TARDIR}.tar.gz --exclude .svn ${TARDIR}) - This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-05-02 11:29:54
|
Revision: 38 Author: skilvington Date: 2006-05-02 04:29:45 -0700 (Tue, 02 May 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=38&view=rev Log Message: ----------- add safe_mallocz Modified Paths: -------------- redbutton-browser/trunk/utils.c redbutton-browser/trunk/utils.h Modified: redbutton-browser/trunk/utils.c =================================================================== --- redbutton-browser/trunk/utils.c 2006-04-03 11:02:48 UTC (rev 37) +++ redbutton-browser/trunk/utils.c 2006-05-02 11:29:45 UTC (rev 38) @@ -113,6 +113,16 @@ return buf; } +void * +safe_mallocz(size_t nbytes) +{ + void *buf = safe_malloc(nbytes); + + bzero(buf, nbytes); + + return buf; +} + /* * safe_realloc(NULL, n) == safe_malloc(n) * safe_realloc(x, 0) == safe_free(x) and returns NULL Modified: redbutton-browser/trunk/utils.h =================================================================== --- redbutton-browser/trunk/utils.h 2006-04-03 11:02:48 UTC (rev 37) +++ redbutton-browser/trunk/utils.h 2006-05-02 11:29:45 UTC (rev 38) @@ -38,6 +38,7 @@ int next_utf8(unsigned char *, int, int *); void *safe_malloc(size_t); +void *safe_mallocz(size_t); void *safe_realloc(void *, size_t); void safe_free(void *); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-05-02 12:53:46
|
Revision: 39 Author: skilvington Date: 2006-05-02 05:53:37 -0700 (Tue, 02 May 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=39&view=rev Log Message: ----------- import MPEG transport stream demuxer Modified Paths: -------------- redbutton-browser/trunk/Makefile Added Paths: ----------- redbutton-browser/trunk/mpegts.c redbutton-browser/trunk/mpegts.h Modified: redbutton-browser/trunk/Makefile =================================================================== --- redbutton-browser/trunk/Makefile 2006-05-02 11:29:45 UTC (rev 38) +++ redbutton-browser/trunk/Makefile 2006-05-02 12:53:37 UTC (rev 39) @@ -3,7 +3,7 @@ #DEFS=-DDEBUG_ALLOC INCS=`freetype-config --cflags` -LIBS=-lm -lz -L/usr/X11R6/lib -lX11 -lXt -lXrender -lXft -lpng -lmpeg2 -lmpeg2convert +LIBS=-lm -lz -L/usr/X11R6/lib -lX11 -lXt -lXrender -lXft -lpng -lmpeg2 -lmpeg2convert -lavformat -lavcodec CLASSES=ActionClass.o \ ApplicationClass.o \ @@ -71,6 +71,7 @@ clone.o \ si.o \ readpng.o \ + mpegts.o \ utils.o default: rb-browser rb-keymap Added: redbutton-browser/trunk/mpegts.c =================================================================== --- redbutton-browser/trunk/mpegts.c (rev 0) +++ redbutton-browser/trunk/mpegts.c 2006-05-02 12:53:37 UTC (rev 39) @@ -0,0 +1,445 @@ +/* + * mpegts.c + */ + +/* + * MPEG2 Transport Stream demuxer + * based on ffmpeg/libavformat code + * changed to avoid any seeking on the input + */ + +/* + * MPEG2 transport stream (aka DVB) demux + * Copyright (c) 2002-2003 Fabrice Bellard. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <ffmpeg/avformat.h> + +#include "mpegts.h" +#include "utils.h" + +#define TS_PACKET_SIZE 188 +#define NB_PID_MAX 2 + +typedef struct PESContext PESContext; + +struct MpegTSContext +{ + FILE *ts_stream; /* transport stream we are reading from */ + AVPacket *pkt; /* packet containing av data */ + int stop_parse; /* stop parsing loop */ + PESContext *pids[NB_PID_MAX]; /* PIDs we are demuxing */ + int is_start; /* is the current packet the first of a frame */ +}; + +/* TS stream handling */ +enum MpegTSState +{ + MPEGTS_SKIP = 0, /* must be 0, => don't start getting data until we have set is_start flag */ + MPEGTS_HEADER, + MPEGTS_PESHEADER_FILL, + MPEGTS_PAYLOAD, +}; + +/* enough for PES header + length */ +#define PES_START_SIZE 9 +#define MAX_PES_HEADER_SIZE (9 + 255) + +struct PESContext +{ + int pid; + MpegTSContext *ts; + enum MpegTSState state; + /* used to get the format */ + int data_index; + int total_size; + int pes_header_size; + int64_t pts, dts; + uint8_t header[MAX_PES_HEADER_SIZE]; + /* frame we are currently building for this stream */ + int64_t frame_pts; + int64_t frame_dts; + uint8_t *frame_data; + unsigned int frame_size; +}; + +static int read_packet(FILE *, uint8_t *); +static void handle_packet(MpegTSContext *, const uint8_t *); +static PESContext *add_pes_stream(MpegTSContext *, int); +static void mpegts_push_data(PESContext *, const uint8_t *, int, int); +static int64_t get_pts(const uint8_t *); + +/* my interface */ + +MpegTSContext * +mpegts_open(FILE *ts) +{ + MpegTSContext *ctx; + + if((ctx = av_mallocz(sizeof(MpegTSContext))) == NULL) + return NULL; + + ctx->ts_stream = ts; + + ctx->is_start = 0; + + return ctx; +} + +int +mpegts_demux_frame(MpegTSContext *ctx, AVPacket *frame) +{ + AVPacket packet; + PESContext *pes; + + do + { + mpegts_demux_packet(ctx, &packet); + /* find the stream */ + if((pes = add_pes_stream(ctx, packet.stream_index)) == NULL) + fatal("mpegts_demux_frame: internal error"); + /* is it the first packet of the next frame */ + if(ctx->is_start != 0) + { + /* a new frame, remember its PTS (or calc from the previous one) */ + if(packet.pts == AV_NOPTS_VALUE && pes->frame_pts != AV_NOPTS_VALUE) + pes->frame_pts += 3600; + else + pes->frame_pts = packet.pts; + if(packet.dts == AV_NOPTS_VALUE && pes->frame_dts != AV_NOPTS_VALUE) + pes->frame_dts += 3600; + else + pes->frame_dts = packet.dts; + } + else + { + /* not a new frame, add data to the exisiting one */ + pes->frame_data = safe_realloc(pes->frame_data, pes->frame_size + packet.size); + memcpy(pes->frame_data + pes->frame_size, packet.data, packet.size); + pes->frame_size += packet.size; + av_free_packet(&packet); + } + } + while(ctx->is_start == 0); + + /* + * pes->frame_data contains the last frame + * packet contains the first packet of the next frame + */ + if(av_new_packet(frame, pes->frame_size) != 0) + return -1; + memcpy(frame->data, pes->frame_data, pes->frame_size); + + frame->stream_index = pes->pid; + frame->pts = pes->frame_pts; + frame->dts = pes->frame_dts; + + /* copy the first packet of the next frame into PES context */ + pes->frame_data = safe_realloc(pes->frame_data, packet.size); + pes->frame_size = packet.size; + memcpy(pes->frame_data, packet.data, packet.size); + + av_free_packet(&packet); + + return 0; +} + +int +mpegts_demux_packet(MpegTSContext *ctx, AVPacket *pkt) +{ + uint8_t packet[TS_PACKET_SIZE]; + int ret; + + ctx->pkt = pkt; + + ctx->stop_parse = 0; + for(;;) + { + if(ctx->stop_parse) + break; + if((ret = read_packet(ctx->ts_stream, packet)) != 0) + return ret; + handle_packet(ctx, packet); + } + + return 0; +} + +void +mpegts_close(MpegTSContext *ctx) +{ + int i; + + for(i=0; i<NB_PID_MAX; i++) + { + safe_free(ctx->pids[i]->frame_data); + av_free(ctx->pids[i]); + } + av_free(ctx); + + return; +} + +/* internal functions */ + +/* return -1 if error or EOF. Return 0 if OK. */ +#define TS_SYNC_BYTE 0x47 + +static int +read_packet(FILE *ts, uint8_t *buf) +{ + size_t nread; + + /* find the next sync byte */ + nread = 0; + do + { + /* read the whole of the next packet */ + while(nread != TS_PACKET_SIZE && !feof(ts)) + nread += fread(buf + nread, 1, TS_PACKET_SIZE - nread, ts); + if(*buf != TS_SYNC_BYTE && !feof(ts)) + { + printf("Bad sync byte: 0x%02x\n", *buf); + memmove(buf, buf + 1, TS_PACKET_SIZE - 1); + nread = TS_PACKET_SIZE - 1; + } + } + while(*buf != TS_SYNC_BYTE && !feof(ts)); + + if(feof(ts)) + return -1; + + return 0; +} + +/* handle one TS packet */ +static void +handle_packet(MpegTSContext *ctx, const uint8_t *packet) +{ + PESContext *pes; + int pid, afc; + const uint8_t *p, *p_end; + + pid = ((packet[1] & 0x1f) << 8) | packet[2]; + + if((pes = add_pes_stream(ctx, pid)) == NULL) + return; + + ctx->is_start = packet[1] & 0x40; + +#if 0 + /* continuity check (currently not used) */ + cc = (packet[3] & 0xf); + cc_ok = (tss->last_cc < 0) || ((((tss->last_cc + 1) & 0x0f) == cc)); + tss->last_cc = cc; +#endif + + /* skip adaptation field */ + afc = (packet[3] >> 4) & 3; + p = packet + 4; + if(afc == 0) /* reserved value */ + return; + if(afc == 2) /* adaptation field only */ + return; + if(afc == 3) /* skip adapation field */ + p += p[0] + 1; + + /* if past the end of packet, ignore */ + p_end = packet + TS_PACKET_SIZE; + if(p >= p_end) + return; + + mpegts_push_data(pes, p, p_end - p, ctx->is_start); + + return; +} + +static PESContext * +add_pes_stream(MpegTSContext *ctx, int pid) +{ + PESContext *pes; + int i; + + /* have we already added this PID */ + for(i=0; i<NB_PID_MAX && ctx->pids[i]!=NULL; i++) + if(ctx->pids[i]->pid == pid) + return ctx->pids[i]; + if(i == NB_PID_MAX) + return NULL; + + /* if no pid found, then add a pid context */ + if((pes = av_mallocz(sizeof(PESContext))) == NULL) + return NULL; + pes->ts = ctx; + pes->pid = pid; + + pes->frame_pts = AV_NOPTS_VALUE; + pes->frame_dts = AV_NOPTS_VALUE; + + ctx->pids[i] = pes; + + return pes; +} + +/* return non zero if a packet could be constructed */ +static void +mpegts_push_data(PESContext *pes, const uint8_t *buf, int buf_size, int is_start) +{ + MpegTSContext *ts = pes->ts; + const uint8_t *p; + int len, code; + + if(is_start) + { + pes->state = MPEGTS_HEADER; + pes->data_index = 0; + } + p = buf; + while(buf_size > 0) + { + switch(pes->state) + { + case MPEGTS_HEADER: + len = PES_START_SIZE - pes->data_index; + if(len > buf_size) + len = buf_size; + memcpy(pes->header + pes->data_index, p, len); + pes->data_index += len; + p += len; + buf_size -= len; + if(pes->data_index == PES_START_SIZE) + { + /* we got all the PES or section header. We can now decide */ + if(pes->header[0] == 0x00 + && pes->header[1] == 0x00 + && pes->header[2] == 0x01) + { + /* it must be an mpeg2 PES stream */ + code = pes->header[3] | 0x100; + if(!((code >= 0x1c0 && code <= 0x1df) + || (code >= 0x1e0 && code <= 0x1ef) + || (code == 0x1bd))) + goto skip; + pes->state = MPEGTS_PESHEADER_FILL; + pes->total_size = (pes->header[4] << 8) | pes->header[5]; + /* NOTE: a zero total size means the PES size is unbounded */ + if (pes->total_size) + pes->total_size += 6; + pes->pes_header_size = pes->header[8] + 9; + } + else + { + /* otherwise, it should be a table */ + /* skip packet */ + skip: + pes->state = MPEGTS_SKIP; + continue; + } + } + break; + + case MPEGTS_PESHEADER_FILL: + /* PES packing parsing */ + len = pes->pes_header_size - pes->data_index; + if(len > buf_size) + len = buf_size; + memcpy(pes->header + pes->data_index, p, len); + pes->data_index += len; + p += len; + buf_size -= len; + if(pes->data_index == pes->pes_header_size) + { + const uint8_t *r; + unsigned int flags; + flags = pes->header[7]; + r = pes->header + 9; + pes->pts = AV_NOPTS_VALUE; + pes->dts = AV_NOPTS_VALUE; + if((flags & 0xc0) == 0x80) + { + pes->pts = get_pts(r); + r += 5; + } + else if((flags & 0xc0) == 0xc0) + { + pes->pts = get_pts(r); + r += 5; + pes->dts = get_pts(r); + r += 5; + } + /* we got the full header. We parse it and get the payload */ + pes->state = MPEGTS_PAYLOAD; + } + break; + + case MPEGTS_PAYLOAD: + if(pes->total_size) + { + len = pes->total_size - pes->data_index; + if(len > buf_size) + len = buf_size; + } + else + { + len = buf_size; + } + if(len > 0) + { + AVPacket *pkt = ts->pkt; + if(av_new_packet(pkt, len) == 0) + { + memcpy(pkt->data, p, len); + pkt->stream_index = pes->pid; + pkt->pts = pes->pts; + pkt->dts = pes->dts; + /* reset pts values */ + pes->pts = AV_NOPTS_VALUE; + pes->dts = AV_NOPTS_VALUE; + ts->stop_parse = 1; + return; + } + } + buf_size = 0; + break; + + case MPEGTS_SKIP: + buf_size = 0; + break; + } + } + + return; +} + +static int64_t +get_pts(const uint8_t *p) +{ + int64_t pts; + int val; + + pts = (int64_t)((p[0] >> 1) & 0x07) << 30; + val = (p[1] << 8) | p[2]; + pts |= (int64_t)(val >> 1) << 15; + val = (p[3] << 8) | p[4]; + pts |= (int64_t)(val >> 1); + + return pts; +} + Added: redbutton-browser/trunk/mpegts.h =================================================================== --- redbutton-browser/trunk/mpegts.h (rev 0) +++ redbutton-browser/trunk/mpegts.h 2006-05-02 12:53:37 UTC (rev 39) @@ -0,0 +1,15 @@ +/* + * mpegts.h + */ + +#ifndef __MPEGTS_H__ +#define __MPEGTS_H__ + +typedef struct MpegTSContext MpegTSContext; + +MpegTSContext *mpegts_open(FILE *); +int mpegts_demux_frame(MpegTSContext *, AVPacket *); +int mpegts_demux_packet(MpegTSContext *, AVPacket *); +void mpegts_close(MpegTSContext *); + +#endif /* __MPEGTS_H__ */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-05-11 11:02:56
|
Revision: 52 Author: skilvington Date: 2006-05-11 04:02:42 -0700 (Thu, 11 May 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=52&view=rev Log Message: ----------- return MPEG stream types to client Modified Paths: -------------- redbutton-browser/trunk/MHEGBackend.c redbutton-browser/trunk/MHEGBackend.h redbutton-browser/trunk/MHEGEngine.c redbutton-browser/trunk/MHEGEngine.h redbutton-download/trunk/assoc.c redbutton-download/trunk/assoc.h redbutton-download/trunk/command.c redbutton-download/trunk/findmheg.c redbutton-download/trunk/module.h Modified: redbutton-browser/trunk/MHEGBackend.c =================================================================== --- redbutton-browser/trunk/MHEGBackend.c 2006-05-11 08:54:07 UTC (rev 51) +++ redbutton-browser/trunk/MHEGBackend.c 2006-05-11 11:02:42 UTC (rev 52) @@ -17,7 +17,7 @@ bool local_checkContentRef(MHEGBackend *, ContentReference *); bool local_loadFile(MHEGBackend *, OctetString *, OctetString *); FILE *local_openFile(MHEGBackend *, OctetString *); -FILE *local_openStream(MHEGBackend *, bool, int *, bool, int *); +FILE *local_openStream(MHEGBackend *, bool, int *, int *, bool, int *, int *); static struct MHEGBackendFns local_backend_fns = { @@ -31,7 +31,7 @@ bool remote_checkContentRef(MHEGBackend *, ContentReference *); bool remote_loadFile(MHEGBackend *, OctetString *, OctetString *); FILE *remote_openFile(MHEGBackend *, OctetString *); -FILE *remote_openStream(MHEGBackend *, bool, int *, bool, int *); +FILE *remote_openStream(MHEGBackend *, bool, int *, int *, bool, int *, int *); static struct MHEGBackendFns remote_backend_fns = { @@ -327,11 +327,12 @@ * the *audio_tag and *video_tag numbers refer to Component/Association Tag values from the DVB PMT * if *audio_tag or *video_tag is -1, the default audio and/or video stream for the current Service ID is used * updates *audio_tag and/or *video_tag to the actual PIDs in the Transport Stream + * updates *audio_type and/or *video_type to the stream type IDs * returns NULL on error */ FILE * -local_openStream(MHEGBackend *t, bool have_audio, int *audio_tag, bool have_video, int *video_tag) +local_openStream(MHEGBackend *t, bool have_audio, int *audio_tag, int *audio_type, bool have_video, int *video_tag, int *video_type) { /* * we need to convert the audio/video_tag into PIDs @@ -341,7 +342,7 @@ * 3. just stream the TS from the backend * we choose 3, to avoid duplicating code and having to pass "-d <device>" options etc */ - return remote_openStream(t, have_audio, audio_tag, have_video, video_tag); + return remote_openStream(t, have_audio, audio_tag, audio_type, have_video, video_tag, video_type); } /* @@ -475,11 +476,12 @@ * the *audio_tag and *video_tag numbers refer to Component/Association Tag values from the DVB PMT * if *audio_tag or *video_tag is -1, the default audio and/or video stream for the current Service ID is used * updates *audio_tag and/or *video_tag to the actual PIDs in the Transport Stream + * updates *audio_type and/or *video_type to the stream type IDs * returns NULL on error */ FILE * -remote_openStream(MHEGBackend *t, bool have_audio, int *audio_tag, bool have_video, int *video_tag) +remote_openStream(MHEGBackend *t, bool have_audio, int *audio_tag, int *audio_type, bool have_video, int *video_tag, int *video_type) { char cmd[PATH_MAX]; FILE *sock; @@ -515,11 +517,12 @@ /* update the PID variables */ if(have_audio && have_video) - err = (sscanf(pids, "AudioPID %u VideoPID %u", &audio_pid, &video_pid) != 2); + err = (sscanf(pids, "AudioPID %u AudioType %u VideoPID %u VideoType %u", + &audio_pid, audio_type, &video_pid, video_type) != 4); else if(have_audio) - err = (sscanf(pids, "AudioPID %u", &audio_pid) != 1); + err = (sscanf(pids, "AudioPID %u AudioType %u", &audio_pid, audio_type) != 2); else - err = (sscanf(pids, "VideoPID %u", &video_pid) != 1); + err = (sscanf(pids, "VideoPID %u VideoType %u", &video_pid, video_type) != 2); if(!err) { Modified: redbutton-browser/trunk/MHEGBackend.h =================================================================== --- redbutton-browser/trunk/MHEGBackend.h 2006-05-11 08:54:07 UTC (rev 51) +++ redbutton-browser/trunk/MHEGBackend.h 2006-05-11 11:02:42 UTC (rev 52) @@ -20,10 +20,14 @@ /* function pointers */ struct MHEGBackendFns { - bool (*checkContentRef)(struct MHEGBackend *, ContentReference *); /* check a carousel file exists */ - bool (*loadFile)(struct MHEGBackend *, OctetString *, OctetString *); /* load a carousel file */ - FILE *(*openFile)(struct MHEGBackend *, OctetString *); /* open a carousel file */ - FILE *(*openStream)(struct MHEGBackend *, bool, int *, bool, int *); /* open an MPEG Transport Stream */ + /* check a carousel file exists */ + bool (*checkContentRef)(struct MHEGBackend *, ContentReference *); + /* load a carousel file */ + bool (*loadFile)(struct MHEGBackend *, OctetString *, OctetString *); + /* open a carousel file */ + FILE *(*openFile)(struct MHEGBackend *, OctetString *); + /* open an MPEG Transport Stream */ + FILE *(*openStream)(struct MHEGBackend *, bool, int *, int *, bool, int *, int *); } *fns; } MHEGBackend; Modified: redbutton-browser/trunk/MHEGEngine.c =================================================================== --- redbutton-browser/trunk/MHEGEngine.c 2006-05-11 08:54:07 UTC (rev 51) +++ redbutton-browser/trunk/MHEGEngine.c 2006-05-11 11:02:42 UTC (rev 52) @@ -1340,9 +1340,11 @@ */ FILE * -MHEGEngine_openStream(bool have_audio, int *audio_tag, bool have_video, int *video_tag) +MHEGEngine_openStream(bool have_audio, int *audio_tag, int *audio_type, bool have_video, int *video_tag, int *video_type) { - return (*(engine.backend.fns->openStream))(&engine.backend, have_audio, audio_tag, have_video, video_tag); + return (*(engine.backend.fns->openStream))(&engine.backend, + have_audio, audio_tag, audio_type, + have_video, video_tag, video_type); } /* Modified: redbutton-browser/trunk/MHEGEngine.h =================================================================== --- redbutton-browser/trunk/MHEGEngine.h 2006-05-11 08:54:07 UTC (rev 51) +++ redbutton-browser/trunk/MHEGEngine.h 2006-05-11 11:02:42 UTC (rev 52) @@ -221,7 +221,7 @@ bool MHEGEngine_checkContentRef(ContentReference *); bool MHEGEngine_loadFile(OctetString *, OctetString *); FILE *MHEGEngine_openFile(OctetString *); -FILE *MHEGEngine_openStream(bool, int *, bool, int *); +FILE *MHEGEngine_openStream(bool, int *, int *, bool, int *, int *); char *MHEGEngine_absoluteFilename(OctetString *); Modified: redbutton-download/trunk/assoc.c =================================================================== --- redbutton-download/trunk/assoc.c 2006-05-11 08:54:07 UTC (rev 51) +++ redbutton-download/trunk/assoc.c 2006-05-11 11:02:42 UTC (rev 52) @@ -35,20 +35,23 @@ a->nassocs = 0; a->pids = NULL; a->sids = NULL; + a->types = NULL; return; } void -add_assoc(struct assoc *a, uint16_t elementary_pid, uint16_t stream_id) +add_assoc(struct assoc *a, uint16_t elementary_pid, uint16_t stream_id, uint8_t stream_type) { a->nassocs ++; a->pids = safe_realloc(a->pids, a->nassocs * sizeof(uint16_t)); a->sids = safe_realloc(a->sids, a->nassocs * sizeof(uint16_t)); + a->types = safe_realloc(a->types, a->nassocs * sizeof(uint8_t)); a->pids[a->nassocs - 1] = elementary_pid; a->sids[a->nassocs - 1] = stream_id; + a->types[a->nassocs - 1] = stream_type; return; } @@ -69,4 +72,19 @@ return 0; } +uint8_t +stream2type(struct assoc *a, uint16_t stream_id) +{ + unsigned int i; + for(i=0; i<a->nassocs; i++) + { + if(a->sids[i] == stream_id) + return a->types[i]; + } + + error("Unknown stream type for association tag 0x%x", stream_id); + + return 0; +} + Modified: redbutton-download/trunk/assoc.h =================================================================== --- redbutton-download/trunk/assoc.h 2006-05-11 08:54:07 UTC (rev 51) +++ redbutton-download/trunk/assoc.h 2006-05-11 11:02:42 UTC (rev 52) @@ -32,12 +32,14 @@ unsigned int nassocs; uint16_t *pids; uint16_t *sids; + uint8_t *types; /* stream type */ }; void init_assoc(struct assoc *); -void add_assoc(struct assoc *, uint16_t, uint16_t); +void add_assoc(struct assoc *, uint16_t, uint16_t, uint8_t); uint16_t stream2pid(struct assoc *, uint16_t); +uint8_t stream2type(struct assoc *, uint16_t); #endif /* __ASSOC_H__ */ Modified: redbutton-download/trunk/command.c =================================================================== --- redbutton-download/trunk/command.c 2006-05-11 08:54:07 UTC (rev 51) +++ redbutton-download/trunk/command.c 2006-05-11 11:02:42 UTC (rev 52) @@ -140,6 +140,7 @@ struct carousel *car = listen_data->carousel; int tag; uint16_t pid; + uint8_t type; int audio_fd; int ts_fd; char hdr[64]; @@ -148,11 +149,17 @@ tag = strtol(argv[1], NULL, 0); - /* map the tag to a PID, or use the default */ + /* map the tag to a PID and stream type, or use the default */ if(tag == -1) + { pid = car->audio_pid; + type = car->audio_type; + } else + { pid = stream2pid(&car->assoc, tag); + type = stream2type(&car->assoc, tag); + } /* add the PID to the demux device */ if((audio_fd = add_demux_filter(car->demux_device, pid, DMX_PES_AUDIO)) < 0) @@ -172,8 +179,8 @@ /* send the OK code */ SEND_RESPONSE(200, "OK"); - /* tell the client what PID the component tag resolved to */ - snprintf(hdr, sizeof(hdr), "AudioPID %u\n", pid); + /* tell the client what PID and stream type the component tag resolved to */ + snprintf(hdr, sizeof(hdr), "AudioPID %u AudioType %u\n", pid, type); fputs(hdr, client); /* shovel the transport stream to client until the client closes or we get an error */ @@ -201,6 +208,7 @@ struct carousel *car = listen_data->carousel; int tag; uint16_t pid; + uint8_t type; int video_fd; int ts_fd; char hdr[64]; @@ -209,11 +217,17 @@ tag = strtol(argv[1], NULL, 0); - /* map the tag to a PID, or use the default */ + /* map the tag to a PID and stream type, or use the default */ if(tag == -1) + { pid = car->video_pid; + type = car->video_type; + } else + { pid = stream2pid(&car->assoc, tag); + type = stream2type(&car->assoc, tag); + } /* add the PID to the demux device */ if((video_fd = add_demux_filter(car->demux_device, pid, DMX_PES_VIDEO)) < 0) @@ -233,8 +247,8 @@ /* send the OK code */ SEND_RESPONSE(200, "OK"); - /* tell the client what PID the component tag resolved to */ - snprintf(hdr, sizeof(hdr), "VideoPID %u\n", pid); + /* tell the client what PID and stream type the component tag resolved to */ + snprintf(hdr, sizeof(hdr), "VideoPID %u VideoType %u\n", pid, type); fputs(hdr, client); /* shovel the transport stream down client_sock until the client closes it or we get an error */ @@ -264,6 +278,8 @@ int video_tag; uint16_t audio_pid; uint16_t video_pid; + uint8_t audio_type; + uint8_t video_type; int audio_fd; int video_fd; int ts_fd; @@ -274,16 +290,28 @@ audio_tag = strtol(argv[1], NULL, 0); video_tag = strtol(argv[2], NULL, 0); - /* map the tags to PIDs, or use the defaults */ + /* map the tags to PIDs and stream types, or use the defaults */ if(audio_tag == -1) + { audio_pid = car->audio_pid; + audio_type = car->audio_type; + } else + { audio_pid = stream2pid(&car->assoc, audio_tag); + audio_type = stream2type(&car->assoc, audio_tag); + } if(video_tag == -1) + { video_pid = car->video_pid; + video_type = car->video_type; + } else + { video_pid = stream2pid(&car->assoc, video_tag); + video_type = stream2type(&car->assoc, video_tag); + } /* add the PIDs to the demux device */ if((audio_fd = add_demux_filter(car->demux_device, audio_pid, DMX_PES_AUDIO)) < 0) @@ -310,8 +338,8 @@ /* send the OK code */ SEND_RESPONSE(200, "OK"); - /* tell the client what PIDs the component tags resolved to */ - snprintf(hdr, sizeof(hdr), "AudioPID %u VideoPID %u\n", audio_pid, video_pid); + /* tell the client what PIDs and stream types the component tags resolved to */ + snprintf(hdr, sizeof(hdr), "AudioPID %u AudioType %u VideoPID %uVideoType %u\n", audio_pid, audio_type, video_pid, video_type); fputs(hdr, client); /* shovel the transport stream down client_sock until the client closes it or we get an error */ Modified: redbutton-download/trunk/findmheg.c =================================================================== --- redbutton-download/trunk/findmheg.c 2006-05-11 08:54:07 UTC (rev 51) +++ redbutton-download/trunk/findmheg.c 2006-05-11 11:02:42 UTC (rev 52) @@ -111,7 +111,9 @@ /* unknown */ _car.carousel_id = 0; _car.audio_pid = 0; + _car.audio_type = 0; _car.video_pid = 0; + _car.video_type = 0; _car.current_pid = 0; /* map between stream_id_descriptors and elementary_PIDs */ init_assoc(&_car.assoc); @@ -173,7 +175,10 @@ offset += 2; /* is it the default video stream for this service */ if(stream_type == STREAM_TYPE_VIDEO_MPEG2) + { _car.video_pid = elementary_pid; + _car.video_type = stream_type; + } /* read the descriptors */ info_length = ((pmt[offset] & 0x0f) << 8) + pmt[offset+1]; offset += 2; @@ -200,7 +205,7 @@ desc = (struct stream_id_descriptor *) &pmt[offset]; component_tag = desc->component_tag; // printf("pid=0x%x component_tag=0x%x\n", elementary_pid, component_tag); - add_assoc(&_car.assoc, elementary_pid, desc->component_tag); + add_assoc(&_car.assoc, elementary_pid, desc->component_tag, stream_type); } else if(desc_tag == TAG_LANGUAGE_DESCRIPTOR && is_audio_stream(stream_type)) { @@ -208,7 +213,10 @@ desc = (struct language_descriptor *) &pmt[offset]; /* only remember the normal audio stream (not visually impaired stream) */ if(desc->audio_type == 0) + { _car.audio_pid = elementary_pid; + _car.audio_type = stream_type; + } } offset += desc_length; info_length -= desc_length; Modified: redbutton-download/trunk/module.h =================================================================== --- redbutton-download/trunk/module.h 2006-05-11 08:54:07 UTC (rev 51) +++ redbutton-download/trunk/module.h 2006-05-11 11:02:42 UTC (rev 52) @@ -61,7 +61,9 @@ uint16_t service_id; uint32_t carousel_id; uint16_t audio_pid; /* PID of default audio stream for this service_id */ + uint8_t audio_type; /* type ID of default audio stream */ uint16_t video_pid; /* PID of default video stream for this service_id */ + uint8_t video_type; /* type ID of default video stream */ uint16_t current_pid; /* PID we downloaded the last table from */ struct assoc assoc; /* map stream_id's to elementary_pid's */ int32_t npids; /* PIDs we are reading data from */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-05-11 13:00:26
|
Revision: 54 Author: skilvington Date: 2006-05-11 06:00:18 -0700 (Thu, 11 May 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=54&view=rev Log Message: ----------- add video decoder (output disabled until we can overlay the other MHEG objects) Modified Paths: -------------- redbutton-browser/trunk/MHEGDisplay.c redbutton-browser/trunk/MHEGStreamPlayer.c redbutton-browser/trunk/MHEGStreamPlayer.h redbutton-browser/trunk/Makefile redbutton-browser/trunk/StreamComponent.c Modified: redbutton-browser/trunk/MHEGDisplay.c =================================================================== --- redbutton-browser/trunk/MHEGDisplay.c 2006-05-11 11:40:42 UTC (rev 53) +++ redbutton-browser/trunk/MHEGDisplay.c 2006-05-11 13:00:18 UTC (rev 54) @@ -15,6 +15,7 @@ #include <X11/keysym.h> #include <mpeg2dec/mpeg2.h> #include <mpeg2dec/mpeg2convert.h> +#include <ffmpeg/avformat.h> #include "MHEGEngine.h" #include "MHEGDisplay.h" @@ -93,6 +94,9 @@ else d->keymap = default_keymap; + /* so X requests/replies in different threads don't get interleaved */ + XInitThreads(); + if((d->dpy = XOpenDisplay(NULL)) == NULL) fatal("Unable to open display"); @@ -236,6 +240,9 @@ d->app = XtCreateApplicationContext(); XtDisplayInitialize(d->app, d->dpy, APP_NAME, APP_CLASS, NULL, 0, &argc, argv); + /* init ffmpeg */ + av_register_all(); + return; } Modified: redbutton-browser/trunk/MHEGStreamPlayer.c =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.c 2006-05-11 11:40:42 UTC (rev 53) +++ redbutton-browser/trunk/MHEGStreamPlayer.c 2006-05-11 13:00:18 UTC (rev 54) @@ -4,19 +4,76 @@ #include <string.h> #include <stdio.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#include <X11/Xlib.h> +#include <X11/extensions/XShm.h> #include "MHEGEngine.h" #include "MHEGStreamPlayer.h" +#include "mpegts.h" #include "utils.h" +/* internal routines */ +static void *decode_thread(void *); +static void *video_thread(void *); + +static void thread_usleep(unsigned long); +static enum PixelFormat find_av_pix_fmt(int, unsigned long, unsigned long, unsigned long); +static enum CodecID find_av_codec_id(int); + +LIST_TYPE(VideoFrame) * +new_VideoFrameListItem(double pts, enum PixelFormat pix_fmt, unsigned int width, unsigned int height, AVFrame *frame) +{ + LIST_TYPE(VideoFrame) *vf = safe_malloc(sizeof(LIST_TYPE(VideoFrame))); + int frame_size; + + vf->item.pts = pts; + vf->item.pix_fmt = pix_fmt; + vf->item.width = width; + vf->item.height = height; + + /* + * take a copy of the frame, + * the actual data is inside the video codec somewhere and will be overwritten by the next frame we decode + */ + if((frame_size = avpicture_get_size(pix_fmt, width, height)) < 0) + fatal("Invalid frame_size"); + vf->item.frame_data = safe_malloc(frame_size); + avpicture_fill(&vf->item.frame, vf->item.frame_data, pix_fmt, width, height); + img_copy(&vf->item.frame, (AVPicture*) frame, pix_fmt, width, height); + + return vf; +} + void +free_VideoFrameListItem(LIST_TYPE(VideoFrame) *vf) +{ + safe_free(vf->item.frame_data); + + safe_free(vf); + + return; +} + +void MHEGStreamPlayer_init(MHEGStreamPlayer *p) { bzero(p, sizeof(MHEGStreamPlayer)); + p->playing = false; + p->stop = false; + p->have_video = false; p->have_audio = false; + p->video = NULL; + + pthread_mutex_init(&p->videoq_lock, NULL); + p->videoq = NULL; + + pthread_mutex_init(&p->current_frame_lock, NULL); + return; } @@ -25,11 +82,14 @@ { MHEGStreamPlayer_stop(p); + pthread_mutex_destroy(&p->videoq_lock); + pthread_mutex_destroy(&p->current_frame_lock); + return; } void -MHEGStreamPlayer_setVideoTag(MHEGStreamPlayer *p, int tag) +MHEGStreamPlayer_setVideoTag(MHEGStreamPlayer *p, VideoClass *video, int tag) { if(p->have_video) error("MHEGStreamPlayer: more than one video stream; only using the last one (%d)", tag); @@ -37,7 +97,11 @@ p->have_video = true; p->video_tag = tag; p->video_pid = -1; + p->video_type = -1; + /* output size/position */ + p->video = video; + return; } @@ -50,6 +114,7 @@ p->have_audio = true; p->audio_tag = tag; p->audio_pid = -1; + p->audio_type = -1; return; } @@ -61,11 +126,27 @@ p->audio_pid = p->audio_tag; p->video_pid = p->video_tag; -// if((p->ts = MHEGEngine_openStream(p->have_audio, &p->audio_pid, p->have_video, &p->video_pid)) == NULL) -// error("Unable to open MPEG stream"); -/* TODO */ -printf("TODO: MHEGStreamPlayer_play: not yet implemented\n"); + if((p->ts = MHEGEngine_openStream(p->have_audio, &p->audio_pid, &p->audio_type, + p->have_video, &p->video_pid, &p->video_type)) == NULL) + { + error("Unable to open MPEG stream"); + return; + } + p->playing = true; + p->stop = false; + + /* + * we have two threads: + * decode_thread reads MPEG data from the TS and decodes it into YUV video frames + * video_thread takes YUV frames off the videoq list, converts them to RGB and displays them on the screen + */ + if(pthread_create(&p->decode_tid, NULL, decode_thread, p) != 0) + fatal("Unable to create MPEG decoder thread"); + + if(pthread_create(&p->video_tid, NULL, video_thread, p) != 0) + fatal("Unable to create video output thread"); + return; } @@ -74,12 +155,473 @@ { verbose("MHEGStreamPlayer_stop"); + /* are we playing */ + if(!p->playing) + return; + + /* signal the threads to stop */ + p->stop = true; + + /* wait for them to finish */ + pthread_join(p->decode_tid, NULL); + pthread_join(p->video_tid, NULL); + + /* clean up */ + LIST_FREE(&p->videoq, VideoFrame, free_VideoFrameListItem); + if(p->ts != NULL) { fclose(p->ts); p->ts = NULL; } + p->playing = false; + return; } +/* + * decode_thread + * reads the MPEG TS file + * decodes the data into YUV video frames + * adds them to the tail of the videoq list + */ + +static void * +decode_thread(void *arg) +{ + MHEGStreamPlayer *p = (MHEGStreamPlayer *) arg; + MpegTSContext *tsdemux; + AVPacket pkt; + AVCodecContext *audio_codec_ctx = NULL; + AVCodecContext *video_codec_ctx = NULL; + enum CodecID codec_id; + AVCodec *codec = NULL; + double video_time_base = 90000.0; + double pts; + AVFrame *frame; + LIST_TYPE(VideoFrame) *video_frame; + int got_picture; + + verbose("MHEGStreamPlayer: decode thread started"); + + if(p->video_pid != -1) + { + if((video_codec_ctx = avcodec_alloc_context()) == NULL) + fatal("Out of memory"); + if((codec_id = find_av_codec_id(p->video_type)) == CODEC_ID_NONE + || (codec = avcodec_find_decoder(codec_id)) == NULL) + fatal("Unsupported video codec"); + if(avcodec_open(video_codec_ctx, codec) < 0) + fatal("Unable to open video codec"); + verbose("MHEGStreamPlayer: Video: stream type=%d codec=%s\n", p->video_type, codec->name); + } + + if(p->audio_pid != -1) + { + if((audio_codec_ctx = avcodec_alloc_context()) == NULL) + fatal("Out of memory"); + if((codec_id = find_av_codec_id(p->audio_type)) == CODEC_ID_NONE + || (codec = avcodec_find_decoder(codec_id)) == NULL) + fatal("Unsupported audio codec"); + if(avcodec_open(audio_codec_ctx, codec) < 0) + fatal("Unable to open audio codec"); + verbose("MHEGStreamPlayer: Audio: stream type=%d codec=%s\n", p->audio_type, codec->name); + } + + if((frame = avcodec_alloc_frame()) == NULL) + fatal("Out of memory"); + + if((tsdemux = mpegts_open(p->ts)) == NULL) + fatal("Out of memory"); + + while(!p->stop && !feof(p->ts)) + { + /* get the next complete packet for one of the streams */ + if(mpegts_demux_frame(tsdemux, &pkt) < 0) + continue; +//if(pkt.dts == AV_NOPTS_VALUE) printf("NO DTS on PID %d!\n", pkt.stream_index); +//if(pkt.pts == AV_NOPTS_VALUE) printf("NO PTS on PID %d!\n", pkt.stream_index); +//printf("PTS=%lld DTS=%lld\n", pkt.pts, pkt.dts); + /* see what stream we got a packet for */ + if(pkt.stream_index == p->audio_pid && pkt.dts != AV_NOPTS_VALUE) + { +//printf("decode: got audio packet\n"); + } + else if(pkt.stream_index == p->video_pid && pkt.dts != AV_NOPTS_VALUE) + { +//printf("decode: got video packet\n"); + (void) avcodec_decode_video(video_codec_ctx, frame, &got_picture, pkt.data, pkt.size); + if(got_picture) + { + pts = pkt.dts / video_time_base; + video_frame = new_VideoFrameListItem(pts, video_codec_ctx->pix_fmt, video_codec_ctx->width, video_codec_ctx->height, frame); + pthread_mutex_lock(&p->videoq_lock); + LIST_APPEND(&p->videoq, video_frame); + pthread_mutex_unlock(&p->videoq_lock); +//printf("decode: got video frame: pts=%f (real pts=%f) width=%d height=%d\n", pts, pkt.pts / video_time_base, video_codec_ctx->width, video_codec_ctx->height); + } + } + else + { +//printf("decode: got unknown/untimed packet\n"); + } + av_free_packet(&pkt); + } + + /* clean up */ + mpegts_close(tsdemux); + + av_free(frame); + + if(video_codec_ctx != NULL) + avcodec_close(video_codec_ctx); + if(audio_codec_ctx != NULL) + avcodec_close(audio_codec_ctx); + + verbose("MHEGStreamPlayer: decode thread stopped"); + + return NULL; +} + +/* + * video_thread + * takes YUV frames off the videoq list + * scales them (if necessary) to fit the output size + * converts them to RGB + * waits for the correct time, then displays them on the screen + */ + +static void * +video_thread(void *arg) +{ + MHEGStreamPlayer *p = (MHEGStreamPlayer *) arg; + MHEGDisplay *d = MHEGEngine_getDisplay(); + unsigned int out_width = 0; /* keep the compiler happy */ + unsigned int out_height = 0; + VideoFrame *vf; + AVPicture rgb_frame; + int rgb_size; + XShmSegmentInfo shm; + enum PixelFormat out_format; + double buffered; + double last_pts; + int64_t last_time, this_time, now; + int usecs; + bool drop_frame; + ImgReSampleContext *resize_ctx = NULL; + AVPicture resized_frame; + AVPicture *yuv_frame; + int tmpbuf_size; + uint8_t *tmpbuf_data = NULL; + unsigned int nframes = 0; + + verbose("MHEGStreamPlayer: video thread started"); + + /* assert */ + if(p->video == NULL) + fatal("video_thread: VideoClass is NULL"); + + /* wait until we have some frames buffered up */ + do + { + pthread_mutex_lock(&p->videoq_lock); + if(p->videoq != NULL) + buffered = p->videoq->prev->item.pts - p->videoq->item.pts; + else + buffered = 0.0; + pthread_mutex_unlock(&p->videoq_lock); + verbose("MHEGStreamPlayer: buffered %f seconds", buffered); + /* let the decoder have a go */ + if(buffered < INIT_VIDEO_BUFFER_WAIT) + pthread_yield(); + } + while(!p->stop && buffered < INIT_VIDEO_BUFFER_WAIT); + + /* do we need to bomb out early */ + if(p->stop) + return NULL; + + /* assert */ + if(p->videoq == NULL) + fatal("video_thread: no frames!"); + + /* size of first frame, no need to lock as item won't change */ + out_width = p->videoq->item.width; + out_height = p->videoq->item.height; +/* TODO */ +/* also scale if ScaleVideo has been called */ + if(d->fullscreen) + { + out_width = (out_width * d->xres) / MHEG_XRES; + out_height = (out_height * d->yres) / MHEG_YRES; + } + + if((p->current_frame = XShmCreateImage(d->dpy, d->vis, d->depth, ZPixmap, NULL, &shm, out_width, out_height)) == NULL) + fatal("XShmCreateImage failed"); + + /* work out what ffmpeg pixel format matches our XImage format */ + if((out_format = find_av_pix_fmt(p->current_frame->bits_per_pixel, + d->vis->red_mask, d->vis->green_mask, d->vis->blue_mask)) == PIX_FMT_NONE) + fatal("Unsupported XImage pixel format"); + + rgb_size = p->current_frame->bytes_per_line * out_height; + + if(rgb_size != avpicture_get_size(out_format, out_width, out_height)) + fatal("XImage and ffmpeg pixel formats differ"); + + if((shm.shmid = shmget(IPC_PRIVATE, rgb_size, IPC_CREAT | 0777)) == -1) + fatal("shmget failed"); + if((shm.shmaddr = shmat(shm.shmid, NULL, 0)) == (void *) -1) + fatal("shmat failed"); + shm.readOnly = True; + if(!XShmAttach(d->dpy, &shm)) + fatal("XShmAttach failed"); + + /* we made sure these pixel formats are the same */ + p->current_frame->data = shm.shmaddr; + avpicture_fill(&rgb_frame, shm.shmaddr, out_format, out_width, out_height); + + /* the time that we displayed the previous frame */ + last_time = 0; + last_pts = 0; + + /* until we are told to stop... */ + while(!p->stop) + { + /* get the next frame */ + pthread_mutex_lock(&p->videoq_lock); + vf = (p->videoq != NULL) ? &p->videoq->item : NULL; + /* only we delete items from the videoq, so vf will stay valid */ + pthread_mutex_unlock(&p->videoq_lock); + if(vf == NULL) + { + verbose("MHEGStreamPlayer: videoq is empty"); + /* give the decoder a bit of time to catch up */ + pthread_yield(); + continue; + } + /* + * keep track of how many frames we've played + * just so the dropped frame verbose message below is more useful + * don't care if it wraps back to 0 again + */ + nframes ++; + /* see if we should drop this frame or not */ + now = av_gettime(); + /* work out when this frame should be displayed based on when the last one was */ + if(last_time != 0) + this_time = last_time + ((vf->pts - last_pts) * 1000000.0); + else + this_time = now; + /* how many usecs do we need to wait */ + usecs = this_time - now; + /* + * we've still got to convert it to RGB and maybe scale it too + * so don't bother allowing any error here + */ + drop_frame = (usecs < 0); + if(drop_frame) + verbose("MHEGStreamPlayer: dropped frame %u (usecs=%d)", nframes, usecs); +//if(drop_frame) +//printf("dropped frame %d: pts=%f last_pts=%f last_time=%lld this_time=%lld usecs=%d\n", nframes, vf->pts, last_pts, last_time, this_time, usecs); + if(!drop_frame) + { + /* see if the output size has changed */ +/* TODO */ + /* scale the next frame if necessary */ + if(vf->width != out_width || vf->height != out_height) + { +/* TODO */ +/* need to change resize_ctx if vf->width or vf->height have changed since last time */ +/* dont forget: img_resample_close(resize_ctx); */ +/* and to free or realloc tmpbuf_data */ + if(resize_ctx == NULL) + { + resize_ctx = img_resample_init(out_width, out_height, vf->width, vf->height); + tmpbuf_size = avpicture_get_size(vf->pix_fmt, out_width, out_height); + tmpbuf_data = safe_malloc(tmpbuf_size); + avpicture_fill(&resized_frame, tmpbuf_data, vf->pix_fmt, out_width, out_height); + } + img_resample(resize_ctx, &resized_frame, &vf->frame); + yuv_frame = &resized_frame; + } + else + { + yuv_frame = &vf->frame; + } + /* make sure no-one else is using the RGB frame */ + pthread_mutex_lock(&p->current_frame_lock); + /* convert the next frame to RGB */ + img_convert(&rgb_frame, out_format, yuv_frame, vf->pix_fmt, out_width, out_height); +/* TODO */ +/* overlay any MHEG objects above it */ + /* we've finished changing the RGB frame now */ + pthread_mutex_unlock(&p->current_frame_lock); + /* wait until it's time to display the frame */ + now = av_gettime(); + /* don't wait if this is the first frame */ + if(last_time != 0) + { + /* how many usecs do we need to wait */ + usecs = this_time - now; +//printf("last_time=%lld this_time=%lld now=%lld sleep=%d\n", last_time, this_time, now, usecs); + if(usecs > 0) + thread_usleep(usecs); + /* remember when we should have displayed this frame */ + last_time = this_time; + } + else + { + /* remember when we displayed this frame */ + last_time = now; + } + /* remember the time stamp for this frame */ + last_pts = vf->pts; +//now=av_gettime(); +//printf("display frame %d: pts=%f this_time=%lld real_time=%lld (diff=%lld)\n", ++nframes, vf->pts, last_time, now, now-last_time); +/* TODO */ +/* take p->video size/position into account */ +/* redraw objects above the video */ +// disable output until we can overlay the MHEG objects +// XShmPutImage(d->dpy, d->win, d->win_gc, p->current_frame, 0, 0, 0, 0, out_width, out_height, False); + /* get it drawn straight away */ + XFlush(d->dpy); + } + /* we can delete the frame from the queue now */ + pthread_mutex_lock(&p->videoq_lock); + LIST_FREE_HEAD(&p->videoq, VideoFrame, free_VideoFrameListItem); + pthread_mutex_unlock(&p->videoq_lock); + } + + if(resize_ctx != NULL) + { + img_resample_close(resize_ctx); + safe_free(tmpbuf_data); + } + + /* the XImage data is our shared memory, make sure XDestroyImage doesn't try to free it */ + p->current_frame->data = NULL; + XDestroyImage(p->current_frame); + + XShmDetach(d->dpy, &shm); + shmdt(shm.shmaddr); + shmctl(shm.shmid, IPC_RMID, NULL); + + verbose("MHEGStreamPlayer: video thread stopped"); + + return NULL; +} + +/* + * usleep(usecs) + * need to make sure the other threads get a go while we are sleeping + */ + +static void +thread_usleep(unsigned long usecs) +{ + struct timespec ts; + + ts.tv_sec = (usecs / 1000000); + ts.tv_nsec = (usecs % 1000000) * 1000; + + nanosleep(&ts, NULL); + + return; +} + +/* + * returns a PIX_FMT_xxx type that matches the given bits per pixel and RGB bit mask values + * returns PIX_FMT_NONE if none match + */ + +static enum PixelFormat +find_av_pix_fmt(int bpp, unsigned long rmask, unsigned long gmask, unsigned long bmask) +{ + enum PixelFormat fmt; + + fmt = PIX_FMT_NONE; + switch(bpp) + { + case 32: + if(rmask == 0xff0000 && gmask == 0xff00 && bmask == 0xff) + fmt = PIX_FMT_RGBA32; + break; + + case 24: + if(rmask == 0xff0000 && gmask == 0xff00 && bmask == 0xff) + fmt = PIX_FMT_RGB24; + else if(rmask == 0xff && gmask == 0xff00 && bmask == 0xff0000) + fmt = PIX_FMT_BGR24; + break; + + case 16: + if(rmask == 0xf800 && gmask == 0x07e0 && bmask == 0x001f) + fmt = PIX_FMT_RGB565; + else if(rmask == 0x7c00 && gmask == 0x03e0 && bmask == 0x001f) + fmt = PIX_FMT_RGB555; + break; + + default: + break; + } + + if(fmt == PIX_FMT_NONE) + error("Unsupported pixel format (bpp=%d r=%lx g=%lx b=%lx)", bpp, rmask, gmask, bmask); + + return fmt; +} + +/* + * from libavformat/mpegts.c + */ + +static enum CodecID +find_av_codec_id(int stream_type) +{ + enum CodecID codec_id; + + codec_id = CODEC_ID_NONE; + switch(stream_type) + { + case STREAM_TYPE_AUDIO_MPEG1: + case STREAM_TYPE_AUDIO_MPEG2: + codec_id = CODEC_ID_MP3; + break; + + case STREAM_TYPE_VIDEO_MPEG1: + case STREAM_TYPE_VIDEO_MPEG2: + codec_id = CODEC_ID_MPEG2VIDEO; + break; + + case STREAM_TYPE_VIDEO_MPEG4: + codec_id = CODEC_ID_MPEG4; + break; + + case STREAM_TYPE_VIDEO_H264: + codec_id = CODEC_ID_H264; + break; + + case STREAM_TYPE_AUDIO_AAC: + codec_id = CODEC_ID_AAC; + break; + + case STREAM_TYPE_AUDIO_AC3: + codec_id = CODEC_ID_AC3; + break; + + case STREAM_TYPE_AUDIO_DTS: + codec_id = CODEC_ID_DTS; + break; + + default: + break; + } + + if(codec_id == CODEC_ID_NONE) + error("Unsupported audio/video codec (MPEG stream type=%d)", stream_type); + + return codec_id; +} + Modified: redbutton-browser/trunk/MHEGStreamPlayer.h =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.h 2006-05-11 11:40:42 UTC (rev 53) +++ redbutton-browser/trunk/MHEGStreamPlayer.h 2006-05-11 13:00:18 UTC (rev 54) @@ -6,22 +6,59 @@ #define __MHEGSTREAMPLAYER_H__ #include <stdbool.h> +#include <pthread.h> +#include <X11/Xlib.h> +#include <ffmpeg/avformat.h> +#include <ffmpeg/avcodec.h> +#include "ISO13522-MHEG-5.h" + +/* seconds of video to buffer before we start playing it */ +#define INIT_VIDEO_BUFFER_WAIT 1.0 + +/* list of decoded video frames to be displayed */ typedef struct { - bool have_video; /* false if we have no video stream */ - bool have_audio; /* false if we have no audio stream */ - int video_tag; /* video stream component tag (-1 => default for current service ID) */ - int audio_tag; /* audio stream component tag (-1 => default for current service ID) */ - int video_pid; /* PID in MPEG Transport Stream (-1 => not yet known) */ - int audio_pid; /* PID in MPEG Transport Stream (-1 => not yet known) */ - FILE *ts; /* MPEG Transport Stream */ + double pts; /* presentation time stamp */ + enum PixelFormat pix_fmt; + unsigned int width; + unsigned int height; + AVPicture frame; + unsigned char *frame_data; +} VideoFrame; + +DEFINE_LIST_OF(VideoFrame); + +LIST_TYPE(VideoFrame) *new_VideoFrameListItem(double, enum PixelFormat, unsigned int, unsigned int, AVFrame *); +void free_VideoFrameListItem(LIST_TYPE(VideoFrame) *); + +/* player state */ +typedef struct +{ + bool playing; /* true when our threads are active */ + bool stop; /* true => stop playback */ + bool have_video; /* false if we have no video stream */ + bool have_audio; /* false if we have no audio stream */ + int video_tag; /* video stream component tag (-1 => default for current service ID) */ + int video_pid; /* PID in MPEG Transport Stream (-1 => not yet known) */ + int video_type; /* video stream type (-1 => not yet known) */ + int audio_tag; /* audio stream component tag (-1 => default for current service ID) */ + int audio_pid; /* PID in MPEG Transport Stream (-1 => not yet known) */ + int audio_type; /* audio stream type (-1 => not yet known) */ + FILE *ts; /* MPEG Transport Stream */ + VideoClass *video; /* output size/position, maybe NULL if audio only */ + pthread_t decode_tid; /* thread decoding the MPEG stream into frames */ + pthread_t video_tid; /* thread displaying frames on the screen */ + pthread_mutex_t videoq_lock; /* list of decoded video frames */ + LIST_OF(VideoFrame) *videoq; /* head of list is next to be displayed */ + pthread_mutex_t current_frame_lock; /* locked when we are updating current frame */ + XImage *current_frame; /* frame we are currently displaying */ } MHEGStreamPlayer; void MHEGStreamPlayer_init(MHEGStreamPlayer *); void MHEGStreamPlayer_fini(MHEGStreamPlayer *); -void MHEGStreamPlayer_setVideoTag(MHEGStreamPlayer *, int); +void MHEGStreamPlayer_setVideoTag(MHEGStreamPlayer *, VideoClass *, int); void MHEGStreamPlayer_setAudioTag(MHEGStreamPlayer *, int); void MHEGStreamPlayer_play(MHEGStreamPlayer *); Modified: redbutton-browser/trunk/Makefile =================================================================== --- redbutton-browser/trunk/Makefile 2006-05-11 11:40:42 UTC (rev 53) +++ redbutton-browser/trunk/Makefile 2006-05-11 13:00:18 UTC (rev 54) @@ -1,9 +1,10 @@ CC=gcc CFLAGS=-Wall -O2 -#DEFS=-DDEBUG_ALLOC +DEFS=-D_REENTRANT -D_GNU_SOURCE +#DEFS=-DDEBUG_ALLOC -D_REENTRANT -D_GNU_SOURCE INCS=`freetype-config --cflags` -LIBS=-lm -lz -L/usr/X11R6/lib -lX11 -lXt -lXrender -lXft -lpng -lmpeg2 -lmpeg2convert -lavformat -lavcodec +LIBS=-lm -lz -L/usr/X11R6/lib -lX11 -lXt -lXrender -lXft -lpng -lmpeg2 -lmpeg2convert -lavformat -lavcodec -lpthread CLASSES=ActionClass.o \ ApplicationClass.o \ Modified: redbutton-browser/trunk/StreamComponent.c =================================================================== --- redbutton-browser/trunk/StreamComponent.c 2006-05-11 11:40:42 UTC (rev 53) +++ redbutton-browser/trunk/StreamComponent.c 2006-05-11 13:00:18 UTC (rev 54) @@ -109,7 +109,7 @@ break; case StreamComponent_video: - MHEGStreamPlayer_setVideoTag(player, s->u.video.component_tag); + MHEGStreamPlayer_setVideoTag(player, &s->u.video, s->u.video.component_tag); break; case StreamComponent_rtgraphics: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-05-14 09:56:38
|
Revision: 56 Author: skilvington Date: 2006-05-14 02:56:06 -0700 (Sun, 14 May 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=56&view=rev Log Message: ----------- enable video display (too slow to be practical yet) Modified Paths: -------------- redbutton-browser/trunk/MHEGDisplay.c redbutton-browser/trunk/MHEGDisplay.h redbutton-browser/trunk/MHEGStreamPlayer.c redbutton-browser/trunk/MHEGStreamPlayer.h redbutton-browser/trunk/StreamComponent.c redbutton-browser/trunk/TODO redbutton-browser/trunk/VideoClass.c redbutton-browser/trunk/VideoClass.h redbutton-browser/trunk/add_instance_vars.conf Modified: redbutton-browser/trunk/MHEGDisplay.c =================================================================== --- redbutton-browser/trunk/MHEGDisplay.c 2006-05-12 12:46:29 UTC (rev 55) +++ redbutton-browser/trunk/MHEGDisplay.c 2006-05-14 09:56:06 UTC (rev 56) @@ -80,6 +80,7 @@ XGCValues gcvals; XRenderPictFormat *pic_format; XRenderPictureAttributes pa; + Pixmap overlay; Pixmap textfg; /* fake argc, argv for XtDisplayInitialize */ int argc = 0; @@ -216,13 +217,21 @@ wm_delete_window = XInternAtom(d->dpy, "WM_DELETE_WINDOW", False); XSetWMProtocols(d->dpy, d->win, &wm_delete_window, 1); - /* create an XRender Picture to do the drawing on */ + /* + * create an XRender Picture for the Window contents + * we composite the video frame and the MHEG overlay onto this, then copy it onto the Window + */ + pic_format = XRenderFindVisualFormat(d->dpy, d->vis); d->contents = XCreatePixmap(d->dpy, d->win, d->xres, d->yres, d->depth); - pic_format = XRenderFindVisualFormat(d->dpy, d->vis); d->contents_pic = XRenderCreatePicture(d->dpy, d->contents, pic_format, 0, NULL); + /* create a 32-bit XRender Picture to draw the MHEG objects on */ + pic_format = XRenderFindStandardFormat(d->dpy, PictStandardARGB32); + overlay = XCreatePixmap(d->dpy, d->win, d->xres, d->yres, 32); + d->overlay_pic = XRenderCreatePicture(d->dpy, overlay, pic_format, 0, NULL); + /* a 1x1 Picture to hold the text foreground colour */ - textfg = XCreatePixmap(d->dpy, d->win, 1, 1, d->depth); + textfg = XCreatePixmap(d->dpy, d->win, 1, 1, 32); pa.repeat = True; d->textfg_pic = XRenderCreatePicture(d->dpy, textfg, pic_format, CPRepeat, &pa); @@ -360,6 +369,14 @@ w = (box->x_length * d->xres) / MHEG_XRES; h = (box->y_length * d->yres) / MHEG_YRES; + /* + * if video is being displayed, the current frame will already be in d->contents + * (drawn by the video thread or VideoClass_render) + * overlay the MHEG objects onto the video in d->contents + */ + XRenderComposite(d->dpy, PictOpOver, d->overlay_pic, None, d->contents_pic, x, y, x, y, x, y, w, h); + + /* copy the Window contents onto the screen */ XCopyArea(d->dpy, d->contents, d->win, d->win_gc, x, y, w, h, x, y); return; @@ -397,7 +414,7 @@ printf("TODO: LineStyle %d\n", style); /* draw a rectangle */ - XRenderFillRectangle(d->dpy, PictOpOver, d->contents_pic, &rcol, x, y, w, h); + XRenderFillRectangle(d->dpy, PictOpOver, d->overlay_pic, &rcol, x, y, w, h); return; } @@ -434,7 +451,7 @@ printf("TODO: LineStyle %d\n", style); /* draw a rectangle */ - XRenderFillRectangle(d->dpy, PictOpOver, d->contents_pic, &rcol, x, y, w, h); + XRenderFillRectangle(d->dpy, PictOpOver, d->overlay_pic, &rcol, x, y, w, h); return; } @@ -463,12 +480,36 @@ w = (box->x_length * d->xres) / MHEG_XRES; h = (box->y_length * d->yres) / MHEG_YRES; - XRenderFillRectangle(d->dpy, PictOpOver, d->contents_pic, &rcol, x, y, w, h); + XRenderFillRectangle(d->dpy, PictOpOver, d->overlay_pic, &rcol, x, y, w, h); return; } /* + * explicitly make a transparent rectangle in the MHEG overlay + * MHEGDisplay_fillRectangle() uses PictOpOver => it can't create a transparent box in the output + * this uses PictOpSrc + */ + +void +MHEGDisplay_fillTransparentRectangle(MHEGDisplay *d, XYPosition *pos, OriginalBoxSize *box) +{ + XRenderColor rcol = {0, 0, 0, 0}; + int x, y; + unsigned int w, h; + + /* scale if fullscreen */ + x = (pos->x_position * d->xres) / MHEG_XRES; + y = (pos->y_position * d->yres) / MHEG_YRES; + w = (box->x_length * d->xres) / MHEG_XRES; + h = (box->y_length * d->yres) / MHEG_YRES; + + XRenderFillRectangle(d->dpy, PictOpSrc, d->overlay_pic, &rcol, x, y, w, h); + + return; +} + +/* * coords should be in the range 0-MHEG_XRES, 0-MHEG_YRES */ @@ -494,7 +535,7 @@ dst_x = (dst->x_position * d->xres) / MHEG_XRES; dst_y = (dst->y_position * d->yres) / MHEG_YRES; - XRenderComposite(d->dpy, PictOpOver, bitmap->image_pic, None, d->contents_pic, + XRenderComposite(d->dpy, PictOpOver, bitmap->image_pic, None, d->overlay_pic, src_x, src_y, src_x, src_y, dst_x, dst_y, w, h); @@ -594,7 +635,7 @@ /* round up/down the X coord */ scrn_x = (x * d->xres) / MHEG_XRES; scrn_x = (scrn_x + (face->units_per_EM / 2)) / face->units_per_EM; - XftGlyphRender(d->dpy, PictOpOver, d->textfg_pic, font->font, d->contents_pic, + XftGlyphRender(d->dpy, PictOpOver, d->textfg_pic, font->font, d->overlay_pic, 0, 0, orig_x + scrn_x, y, &glyph, 1); face = XftLockFace(font->font); Modified: redbutton-browser/trunk/MHEGDisplay.h =================================================================== --- redbutton-browser/trunk/MHEGDisplay.h 2006-05-12 12:46:29 UTC (rev 55) +++ redbutton-browser/trunk/MHEGDisplay.h 2006-05-14 09:56:06 UTC (rev 56) @@ -46,7 +46,8 @@ Visual *vis; /* Visual (ie pixel format) used by the Window */ Colormap cmap; /* None, unless we needed to create a Colormap for our Visual */ Pixmap contents; /* current contents of the Window */ - Picture contents_pic; /* XRender wrapper for the contents, this is what we draw on */ + Picture contents_pic; /* XRender wrapper for the contents, this is what we composite on */ + Picture overlay_pic; /* draw MHEG objects on here and overlay it on any video */ Picture textfg_pic; /* 1x1 solid foreground colour for text */ MHEGKeyMapEntry *keymap; /* keyboard mapping */ } MHEGDisplay; @@ -61,6 +62,7 @@ /* drawing routines */ void MHEGDisplay_drawHoriLine(MHEGDisplay *, XYPosition *, unsigned int, int, int, MHEGColour *); void MHEGDisplay_drawVertLine(MHEGDisplay *, XYPosition *, unsigned int, int, int, MHEGColour *); +void MHEGDisplay_fillTransparentRectangle(MHEGDisplay *, XYPosition *, OriginalBoxSize *); void MHEGDisplay_fillRectangle(MHEGDisplay *, XYPosition *, OriginalBoxSize *, MHEGColour *); void MHEGDisplay_drawBitmap(MHEGDisplay *, XYPosition *, OriginalBoxSize *, MHEGBitmap *, XYPosition *); void MHEGDisplay_drawTextElement(MHEGDisplay *, XYPosition *, MHEGFont *, MHEGTextElement *, bool); Modified: redbutton-browser/trunk/MHEGStreamPlayer.c =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.c 2006-05-12 12:46:29 UTC (rev 55) +++ redbutton-browser/trunk/MHEGStreamPlayer.c 2006-05-14 09:56:06 UTC (rev 56) @@ -73,6 +73,7 @@ p->videoq = NULL; pthread_mutex_init(&p->current_frame_lock, NULL); + p->current_frame = NULL; return; } @@ -316,6 +317,9 @@ uint8_t *tmpbuf_data = NULL; unsigned int nframes = 0; + if(!p->have_video) + return NULL; + verbose("MHEGStreamPlayer: video thread started"); /* assert */ @@ -454,8 +458,6 @@ pthread_mutex_lock(&p->current_frame_lock); /* convert the next frame to RGB */ img_convert(&rgb_frame, out_format, yuv_frame, vf->pix_fmt, out_width, out_height); -/* TODO */ -/* overlay any MHEG objects above it */ /* we've finished changing the RGB frame now */ pthread_mutex_unlock(&p->current_frame_lock); /* wait until it's time to display the frame */ @@ -480,11 +482,10 @@ last_pts = vf->pts; //now=av_gettime(); //printf("display frame %d: pts=%f this_time=%lld real_time=%lld (diff=%lld)\n", ++nframes, vf->pts, last_time, now, now-last_time); -/* TODO */ -/* take p->video size/position into account */ -/* redraw objects above the video */ -// disable output until we can overlay the MHEG objects -// XShmPutImage(d->dpy, d->win, d->win_gc, p->current_frame, 0, 0, 0, 0, out_width, out_height, False); + /* draw the current frame */ + MHEGStreamPlayer_drawCurrentFrame(p); + /* redraw objects above the video */ + MHEGDisplay_refresh(d, &p->video->inst.Position, &p->video->inst.BoxSize); /* get it drawn straight away */ XFlush(d->dpy); } @@ -500,9 +501,14 @@ safe_free(tmpbuf_data); } + /* get rid of the current frame */ + pthread_mutex_lock(&p->current_frame_lock); /* the XImage data is our shared memory, make sure XDestroyImage doesn't try to free it */ p->current_frame->data = NULL; XDestroyImage(p->current_frame); + /* make sure no-one tries to use it */ + p->current_frame = NULL; + pthread_mutex_unlock(&p->current_frame_lock); XShmDetach(d->dpy, &shm); shmdt(shm.shmaddr); @@ -513,6 +519,34 @@ return NULL; } +void +MHEGStreamPlayer_drawCurrentFrame(MHEGStreamPlayer *p) +{ + MHEGDisplay *d = MHEGEngine_getDisplay(); + int x, y; + unsigned int out_width; + unsigned int out_height; + + pthread_mutex_lock(&p->current_frame_lock); + if(p->current_frame != NULL) + { +/* TODO */ +/* take p->video size/position into account */ +/* remeber fullscreen scaling */ + x = 0; /* origin of p->video */ + y = 0; + out_width = p->current_frame->width; + out_height = p->current_frame->height; + /* draw it onto the Window contents Pixmap */ + XShmPutImage(d->dpy, d->contents, d->win_gc, p->current_frame, 0, 0, x, y, out_width, out_height, False); + /* get it drawn straight away */ + XFlush(d->dpy); + } + pthread_mutex_unlock(&p->current_frame_lock); + + return; +} + /* * usleep(usecs) * need to make sure the other threads get a go while we are sleeping Modified: redbutton-browser/trunk/MHEGStreamPlayer.h =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.h 2006-05-12 12:46:29 UTC (rev 55) +++ redbutton-browser/trunk/MHEGStreamPlayer.h 2006-05-14 09:56:06 UTC (rev 56) @@ -33,7 +33,7 @@ void free_VideoFrameListItem(LIST_TYPE(VideoFrame) *); /* player state */ -typedef struct +typedef struct MHEGStreamPlayer { bool playing; /* true when our threads are active */ bool stop; /* true => stop playback */ @@ -64,4 +64,6 @@ void MHEGStreamPlayer_play(MHEGStreamPlayer *); void MHEGStreamPlayer_stop(MHEGStreamPlayer *); +void MHEGStreamPlayer_drawCurrentFrame(MHEGStreamPlayer *); + #endif /* __MHEGSTREAMPLAYER_H__ */ Modified: redbutton-browser/trunk/StreamComponent.c =================================================================== --- redbutton-browser/trunk/StreamComponent.c 2006-05-12 12:46:29 UTC (rev 55) +++ redbutton-browser/trunk/StreamComponent.c 2006-05-14 09:56:06 UTC (rev 56) @@ -109,6 +109,7 @@ break; case StreamComponent_video: + VideoClass_setStreamPlayer(&s->u.video, player); MHEGStreamPlayer_setVideoTag(player, &s->u.video, s->u.video.component_tag); break; @@ -127,6 +128,24 @@ void StreamComponent_stop(StreamComponent *s, MHEGStreamPlayer *player) { + switch(s->choice) + { + case StreamComponent_audio: + break; + + case StreamComponent_video: + VideoClass_setStreamPlayer(&s->u.video, NULL); + break; + + case StreamComponent_rtgraphics: + error("RTGraphics streams not supported"); + break; + + default: + error("Unknown StreamComponent type: %d", s->choice); + break; + } + return; } Modified: redbutton-browser/trunk/TODO =================================================================== --- redbutton-browser/trunk/TODO 2006-05-12 12:46:29 UTC (rev 55) +++ redbutton-browser/trunk/TODO 2006-05-14 09:56:06 UTC (rev 56) @@ -1,3 +1,10 @@ +check if default audio/video PID is 0 in rb-download +if it is, avstream fails + + +print avstream error message in rb-browser if openStream fails + + use -t timeout when searching for initial object to boot Modified: redbutton-browser/trunk/VideoClass.c =================================================================== --- redbutton-browser/trunk/VideoClass.c 2006-05-12 12:46:29 UTC (rev 55) +++ redbutton-browser/trunk/VideoClass.c 2006-05-14 09:56:06 UTC (rev 56) @@ -354,6 +354,14 @@ } void +VideoClass_setStreamPlayer(VideoClass *t, MHEGStreamPlayer *p) +{ + t->inst.player = p; + + return; +} + +void VideoClass_render(VideoClass *t, MHEGDisplay *d, XYPosition *pos, OriginalBoxSize *box) { XYPosition ins_pos; @@ -364,14 +372,13 @@ if(!intersects(pos, box, &t->inst.Position, &t->inst.BoxSize, &ins_pos, &ins_box)) return; -/* TODO */ -//printf("TODO: VideoClass_render; component_tag=%d\n", t->component_tag); -/* so we can see where it is for now */ -{ -MHEGColour col = { 0, 255, 0, 0 }; -MHEGDisplay_fillRectangle(d, &ins_pos, &ins_box, &col); -} + /* draw the video frame onto the Window contents Pixmap */ + if(t->inst.player != NULL) + MHEGStreamPlayer_drawCurrentFrame(t->inst.player); + /* make a transparent hole in the MHEG overlay so we can see the video below it */ + MHEGDisplay_fillTransparentRectangle(d, &ins_pos, &ins_box); + return; } Modified: redbutton-browser/trunk/VideoClass.h =================================================================== --- redbutton-browser/trunk/VideoClass.h 2006-05-12 12:46:29 UTC (rev 55) +++ redbutton-browser/trunk/VideoClass.h 2006-05-14 09:56:06 UTC (rev 56) @@ -25,6 +25,7 @@ void VideoClass_GetVideoDecodeOffset(VideoClass *, GetVideoDecodeOffset *, OctetString *); void VideoClass_ScaleVideo(VideoClass *, ScaleVideo *, OctetString *); +void VideoClass_setStreamPlayer(VideoClass *, MHEGStreamPlayer *); void VideoClass_render(VideoClass *, MHEGDisplay *, XYPosition *, OriginalBoxSize *); #endif /* __VIDEOCLASS_H__ */ Modified: redbutton-browser/trunk/add_instance_vars.conf =================================================================== --- redbutton-browser/trunk/add_instance_vars.conf 2006-05-12 12:46:29 UTC (rev 55) +++ redbutton-browser/trunk/add_instance_vars.conf 2006-05-14 09:56:06 UTC (rev 56) @@ -175,6 +175,8 @@ /* VideoClass */ /* UK MHEG Profile adds this */ XYPosition VideoDecodeOffset; + /* we add this */ + struct MHEGStreamPlayer *player; } VideoClassInstanceVars; </VideoClass> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-05-15 08:50:05
|
Revision: 58 Author: skilvington Date: 2006-05-15 01:49:45 -0700 (Mon, 15 May 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=58&view=rev Log Message: ----------- remove unused code Modified Paths: -------------- redbutton-browser/trunk/MHEGStreamPlayer.h redbutton-browser/trunk/StreamComponent.c redbutton-browser/trunk/VideoClass.c redbutton-browser/trunk/VideoClass.h redbutton-browser/trunk/add_instance_vars.conf Modified: redbutton-browser/trunk/MHEGStreamPlayer.h =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.h 2006-05-14 11:29:37 UTC (rev 57) +++ redbutton-browser/trunk/MHEGStreamPlayer.h 2006-05-15 08:49:45 UTC (rev 58) @@ -33,7 +33,7 @@ void free_VideoFrameListItem(LIST_TYPE(VideoFrame) *); /* player state */ -typedef struct MHEGStreamPlayer +typedef struct { bool playing; /* true when our threads are active */ bool stop; /* true => stop playback */ Modified: redbutton-browser/trunk/StreamComponent.c =================================================================== --- redbutton-browser/trunk/StreamComponent.c 2006-05-14 11:29:37 UTC (rev 57) +++ redbutton-browser/trunk/StreamComponent.c 2006-05-15 08:49:45 UTC (rev 58) @@ -109,7 +109,6 @@ break; case StreamComponent_video: - VideoClass_setStreamPlayer(&s->u.video, player); MHEGStreamPlayer_setVideoTag(player, &s->u.video, s->u.video.component_tag); break; @@ -134,7 +133,6 @@ break; case StreamComponent_video: - VideoClass_setStreamPlayer(&s->u.video, NULL); break; case StreamComponent_rtgraphics: Modified: redbutton-browser/trunk/VideoClass.c =================================================================== --- redbutton-browser/trunk/VideoClass.c 2006-05-14 11:29:37 UTC (rev 57) +++ redbutton-browser/trunk/VideoClass.c 2006-05-15 08:49:45 UTC (rev 58) @@ -354,14 +354,6 @@ } void -VideoClass_setStreamPlayer(VideoClass *t, MHEGStreamPlayer *p) -{ - t->inst.player = p; - - return; -} - -void VideoClass_render(VideoClass *t, MHEGDisplay *d, XYPosition *pos, OriginalBoxSize *box) { XYPosition ins_pos; Modified: redbutton-browser/trunk/VideoClass.h =================================================================== --- redbutton-browser/trunk/VideoClass.h 2006-05-14 11:29:37 UTC (rev 57) +++ redbutton-browser/trunk/VideoClass.h 2006-05-15 08:49:45 UTC (rev 58) @@ -25,7 +25,6 @@ void VideoClass_GetVideoDecodeOffset(VideoClass *, GetVideoDecodeOffset *, OctetString *); void VideoClass_ScaleVideo(VideoClass *, ScaleVideo *, OctetString *); -void VideoClass_setStreamPlayer(VideoClass *, MHEGStreamPlayer *); void VideoClass_render(VideoClass *, MHEGDisplay *, XYPosition *, OriginalBoxSize *); #endif /* __VIDEOCLASS_H__ */ Modified: redbutton-browser/trunk/add_instance_vars.conf =================================================================== --- redbutton-browser/trunk/add_instance_vars.conf 2006-05-14 11:29:37 UTC (rev 57) +++ redbutton-browser/trunk/add_instance_vars.conf 2006-05-15 08:49:45 UTC (rev 58) @@ -175,8 +175,6 @@ /* VideoClass */ /* UK MHEG Profile adds this */ XYPosition VideoDecodeOffset; - /* we add this */ - struct MHEGStreamPlayer *player; } VideoClassInstanceVars; </VideoClass> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-05-16 13:01:45
|
Revision: 64 Author: skilvington Date: 2006-05-16 06:01:32 -0700 (Tue, 16 May 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=64&view=rev Log Message: ----------- don't redraw overlay if screen is already unlocked Modified Paths: -------------- redbutton-browser/trunk/ApplicationClass.c redbutton-browser/trunk/MHEGEngine.c Modified: redbutton-browser/trunk/ApplicationClass.c =================================================================== --- redbutton-browser/trunk/ApplicationClass.c 2006-05-15 19:23:59 UTC (rev 63) +++ redbutton-browser/trunk/ApplicationClass.c 2006-05-16 13:01:32 UTC (rev 64) @@ -456,17 +456,19 @@ verbose("ApplicationClass: %s; UnlockScreen", ExternalReference_name(&t->rootClass.inst.ref)); + /* if it is not already unlocked */ if(t->inst.LockCount > 0) + { t->inst.LockCount --; - - /* update the screen if it is now unlocked */ - if(t->inst.LockCount == 0) - { - pos.x_position = 0; - pos.y_position = 0; - box.x_length = MHEG_XRES; - box.y_length = MHEG_YRES; - MHEGEngine_redrawArea(&pos, &box); + /* update the screen if it is now unlocked */ + if(t->inst.LockCount == 0) + { + pos.x_position = 0; + pos.y_position = 0; + box.x_length = MHEG_XRES; + box.y_length = MHEG_YRES; + MHEGEngine_redrawArea(&pos, &box); + } } return; Modified: redbutton-browser/trunk/MHEGEngine.c =================================================================== --- redbutton-browser/trunk/MHEGEngine.c 2006-05-15 19:23:59 UTC (rev 63) +++ redbutton-browser/trunk/MHEGEngine.c 2006-05-16 13:01:32 UTC (rev 64) @@ -645,10 +645,14 @@ app = MHEGEngine_getActiveApplication(); +printf("redrawArea: LockCount=%d\n", app->inst.LockCount); + /* only redraw if the display is not locked */ if(app->inst.LockCount > 0) return; +printf("redrawArea: %d: %d,%d %d,%d: start\n", time(NULL), pos->x_position, pos->y_position, box->x_length, box->y_length); + /**************************************************************************************/ /* could do: */ /* MHEGDisplay_setClipRectangle(pos, box); */ @@ -673,9 +677,13 @@ stack = stack->next; } +printf("redrawArea: refresh\n"); + /* refresh the screen */ MHEGDisplay_refresh(&engine.display, pos, box); +printf("redrawArea: end\n"); + return; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-05-17 14:12:47
|
Revision: 68 Author: skilvington Date: 2006-05-17 07:12:37 -0700 (Wed, 17 May 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=68&view=rev Log Message: ----------- keep track of the number of frames on the videoq Modified Paths: -------------- redbutton-browser/trunk/MHEGStreamPlayer.c redbutton-browser/trunk/MHEGStreamPlayer.h Modified: redbutton-browser/trunk/MHEGStreamPlayer.c =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.c 2006-05-16 15:41:12 UTC (rev 67) +++ redbutton-browser/trunk/MHEGStreamPlayer.c 2006-05-17 14:12:37 UTC (rev 68) @@ -70,6 +70,7 @@ p->video = NULL; pthread_mutex_init(&p->videoq_lock, NULL); + p->videoq_len = 0; p->videoq = NULL; pthread_mutex_init(&p->current_frame_lock, NULL); @@ -168,6 +169,7 @@ pthread_join(p->video_tid, NULL); /* clean up */ + p->videoq_len = 0; LIST_FREE(&p->videoq, VideoFrame, free_VideoFrameListItem); if(p->ts != NULL) @@ -258,6 +260,7 @@ pts = pkt.dts / video_time_base; video_frame = new_VideoFrameListItem(pts, video_codec_ctx->pix_fmt, video_codec_ctx->width, video_codec_ctx->height, frame); pthread_mutex_lock(&p->videoq_lock); + p->videoq_len ++; LIST_APPEND(&p->videoq, video_frame); pthread_mutex_unlock(&p->videoq_lock); //printf("decode: got video frame: pts=%f (real pts=%f) width=%d height=%d\n", pts, pkt.pts / video_time_base, video_codec_ctx->width, video_codec_ctx->height); @@ -491,6 +494,10 @@ } /* we can delete the frame from the queue now */ pthread_mutex_lock(&p->videoq_lock); + /* assert */ + if(p->videoq_len == 0) + fatal("video_thread: videoq_len is 0"); + p->videoq_len --; LIST_FREE_HEAD(&p->videoq, VideoFrame, free_VideoFrameListItem); pthread_mutex_unlock(&p->videoq_lock); } Modified: redbutton-browser/trunk/MHEGStreamPlayer.h =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.h 2006-05-16 15:41:12 UTC (rev 67) +++ redbutton-browser/trunk/MHEGStreamPlayer.h 2006-05-17 14:12:37 UTC (rev 68) @@ -50,6 +50,7 @@ pthread_t decode_tid; /* thread decoding the MPEG stream into frames */ pthread_t video_tid; /* thread displaying frames on the screen */ pthread_mutex_t videoq_lock; /* list of decoded video frames */ + unsigned int videoq_len; /* number of frames on the videoq */ LIST_OF(VideoFrame) *videoq; /* head of list is next to be displayed */ pthread_mutex_t current_frame_lock; /* locked when we are updating current frame */ XImage *current_frame; /* frame we are currently displaying */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-05-22 08:31:33
|
Revision: 71 Author: skilvington Date: 2006-05-22 01:31:19 -0700 (Mon, 22 May 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=71&view=rev Log Message: ----------- abstract out the video output method Modified Paths: -------------- redbutton-browser/trunk/MHEGStreamPlayer.c redbutton-browser/trunk/MHEGStreamPlayer.h redbutton-browser/trunk/Makefile Added Paths: ----------- redbutton-browser/trunk/MHEGVideoOutput.c redbutton-browser/trunk/MHEGVideoOutput.h Modified: redbutton-browser/trunk/MHEGStreamPlayer.c =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.c 2006-05-19 16:13:56 UTC (rev 70) +++ redbutton-browser/trunk/MHEGStreamPlayer.c 2006-05-22 08:31:19 UTC (rev 71) @@ -4,13 +4,12 @@ #include <string.h> #include <stdio.h> -#include <sys/ipc.h> -#include <sys/shm.h> #include <X11/Xlib.h> #include <X11/extensions/XShm.h> #include "MHEGEngine.h" #include "MHEGStreamPlayer.h" +#include "MHEGVideoOutput.h" #include "mpegts.h" #include "utils.h" @@ -19,7 +18,6 @@ static void *video_thread(void *); static void thread_usleep(unsigned long); -static enum PixelFormat find_av_pix_fmt(int, unsigned long, unsigned long, unsigned long); static enum CodecID find_av_codec_id(int); LIST_TYPE(VideoFrame) * @@ -73,9 +71,6 @@ p->videoq_len = 0; p->videoq = NULL; - pthread_mutex_init(&p->current_frame_lock, NULL); - p->current_frame = NULL; - return; } @@ -85,7 +80,6 @@ MHEGStreamPlayer_stop(p); pthread_mutex_destroy(&p->videoq_lock); - pthread_mutex_destroy(&p->current_frame_lock); return; } @@ -311,23 +305,17 @@ { MHEGStreamPlayer *p = (MHEGStreamPlayer *) arg; MHEGDisplay *d = MHEGEngine_getDisplay(); - unsigned int out_width = 0; /* keep the compiler happy */ - unsigned int out_height = 0; + MHEGVideoOutput vo; + int out_x; + int out_y; + unsigned int out_width; + unsigned int out_height; VideoFrame *vf; - AVPicture rgb_frame; - int rgb_size; - XShmSegmentInfo shm; - enum PixelFormat out_format; double buffered; double last_pts; int64_t last_time, this_time, now; int usecs; bool drop_frame; - ImgReSampleContext *resize_ctx = NULL; - AVPicture resized_frame; - AVPicture *yuv_frame; - int tmpbuf_size; - uint8_t *tmpbuf_data = NULL; unsigned int nframes = 0; if(!p->have_video) @@ -363,42 +351,22 @@ if(p->videoq == NULL) fatal("video_thread: no frames!"); + /* initialise the video output method */ + MHEGVideoOutput_init(&vo); + /* size of first frame, no need to lock as item won't change */ out_width = p->videoq->item.width; out_height = p->videoq->item.height; /* TODO */ -/* also scale if ScaleVideo has been called */ +/* use scaled values if ScaleVideo has been called */ + /* scale up if fullscreen */ if(d->fullscreen) { out_width = (out_width * d->xres) / MHEG_XRES; out_height = (out_height * d->yres) / MHEG_YRES; } - if((p->current_frame = XShmCreateImage(d->dpy, d->vis, d->depth, ZPixmap, NULL, &shm, out_width, out_height)) == NULL) - fatal("XShmCreateImage failed"); - /* work out what ffmpeg pixel format matches our XImage format */ - if((out_format = find_av_pix_fmt(p->current_frame->bits_per_pixel, - d->vis->red_mask, d->vis->green_mask, d->vis->blue_mask)) == PIX_FMT_NONE) - fatal("Unsupported XImage pixel format"); - - rgb_size = p->current_frame->bytes_per_line * out_height; - - if(rgb_size != avpicture_get_size(out_format, out_width, out_height)) - fatal("XImage and ffmpeg pixel formats differ"); - - if((shm.shmid = shmget(IPC_PRIVATE, rgb_size, IPC_CREAT | 0777)) == -1) - fatal("shmget failed"); - if((shm.shmaddr = shmat(shm.shmid, NULL, 0)) == (void *) -1) - fatal("shmat failed"); - shm.readOnly = True; - if(!XShmAttach(d->dpy, &shm)) - fatal("XShmAttach failed"); - - /* we made sure these pixel formats are the same */ - p->current_frame->data = shm.shmaddr; - avpicture_fill(&rgb_frame, shm.shmaddr, out_format, out_width, out_height); - /* the time that we displayed the previous frame */ last_time = 0; last_pts = 0; @@ -444,35 +412,8 @@ //printf("dropped frame %d: pts=%f last_pts=%f last_time=%lld this_time=%lld usecs=%d\n", nframes, vf->pts, last_pts, last_time, this_time, usecs); if(!drop_frame) { - /* see if the output size has changed */ -/* TODO */ /* scale the next frame if necessary */ - if(vf->width != out_width || vf->height != out_height) - { -/* TODO */ -/* need to change resize_ctx if vf->width or vf->height have changed since last time */ -/* dont forget: img_resample_close(resize_ctx); */ -/* and to free or realloc tmpbuf_data */ - if(resize_ctx == NULL) - { - resize_ctx = img_resample_init(out_width, out_height, vf->width, vf->height); - tmpbuf_size = avpicture_get_size(vf->pix_fmt, out_width, out_height); - tmpbuf_data = safe_malloc(tmpbuf_size); - avpicture_fill(&resized_frame, tmpbuf_data, vf->pix_fmt, out_width, out_height); - } - img_resample(resize_ctx, &resized_frame, &vf->frame); - yuv_frame = &resized_frame; - } - else - { - yuv_frame = &vf->frame; - } - /* make sure no-one else is using the RGB frame */ - pthread_mutex_lock(&p->current_frame_lock); - /* convert the next frame to RGB */ - img_convert(&rgb_frame, out_format, yuv_frame, vf->pix_fmt, out_width, out_height); - /* we've finished changing the RGB frame now */ - pthread_mutex_unlock(&p->current_frame_lock); + MHEGVideoOutput_prepareFrame(&vo, vf, out_width, out_height); /* wait until it's time to display the frame */ now = av_gettime(); /* don't wait if this is the first frame */ @@ -495,8 +436,18 @@ last_pts = vf->pts; //now=av_gettime(); //printf("display frame %d: pts=%f this_time=%lld real_time=%lld (diff=%lld)\n", ++nframes, vf->pts, last_time, now, now-last_time); + /* origin of VideoClass */ +/* TODO should probably have a lock for this in case we are doing SetPosition in another thread */ + out_x = p->video->inst.Position.x_position; + out_y = p->video->inst.Position.y_position; + /* scale if fullscreen */ + if(d->fullscreen) + { + out_x = (out_x * d->xres) / MHEG_XRES; + out_y = (out_y * d->yres) / MHEG_YRES; + } /* draw the current frame */ - MHEGStreamPlayer_drawCurrentFrame(p); + MHEGVideoOutput_drawFrame(&vo, out_x, out_y); /* redraw objects above the video */ MHEGDisplay_refresh(d, &p->video->inst.Position, &p->video->inst.BoxSize); /* get it drawn straight away */ @@ -515,64 +466,13 @@ pthread_yield(); } - if(resize_ctx != NULL) - { - img_resample_close(resize_ctx); - safe_free(tmpbuf_data); - } + MHEGVideoOutput_fini(&vo); - /* get rid of the current frame */ - pthread_mutex_lock(&p->current_frame_lock); - /* the XImage data is our shared memory, make sure XDestroyImage doesn't try to free it */ - p->current_frame->data = NULL; - XDestroyImage(p->current_frame); - /* make sure no-one tries to use it */ - p->current_frame = NULL; - pthread_mutex_unlock(&p->current_frame_lock); - - XShmDetach(d->dpy, &shm); - shmdt(shm.shmaddr); - shmctl(shm.shmid, IPC_RMID, NULL); - verbose("MHEGStreamPlayer: video thread stopped"); return NULL; } -void -MHEGStreamPlayer_drawCurrentFrame(MHEGStreamPlayer *p) -{ - MHEGDisplay *d = MHEGEngine_getDisplay(); - int x, y; - unsigned int out_width; - unsigned int out_height; - - pthread_mutex_lock(&p->current_frame_lock); - if(p->current_frame != NULL) - { - /* origin of VideoClass */ -/* TODO should probably have a lock for this in case we are doing SetPosition in another thread */ - x = p->video->inst.Position.x_position; - y = p->video->inst.Position.y_position; - /* scale if fullscreen */ - if(d->fullscreen) - { - x = (x * d->xres) / MHEG_XRES; - y = (y * d->yres) / MHEG_YRES; - } - /* video frame is already scaled as needed */ - out_width = p->current_frame->width; - out_height = p->current_frame->height; - /* draw it onto the Window contents Pixmap */ - XShmPutImage(d->dpy, d->contents, d->win_gc, p->current_frame, 0, 0, x, y, out_width, out_height, False); - /* get it drawn straight away */ - XFlush(d->dpy); - } - pthread_mutex_unlock(&p->current_frame_lock); - - return; -} - /* * usleep(usecs) * need to make sure the other threads get a go while we are sleeping @@ -592,48 +492,6 @@ } /* - * returns a PIX_FMT_xxx type that matches the given bits per pixel and RGB bit mask values - * returns PIX_FMT_NONE if none match - */ - -static enum PixelFormat -find_av_pix_fmt(int bpp, unsigned long rmask, unsigned long gmask, unsigned long bmask) -{ - enum PixelFormat fmt; - - fmt = PIX_FMT_NONE; - switch(bpp) - { - case 32: - if(rmask == 0xff0000 && gmask == 0xff00 && bmask == 0xff) - fmt = PIX_FMT_RGBA32; - break; - - case 24: - if(rmask == 0xff0000 && gmask == 0xff00 && bmask == 0xff) - fmt = PIX_FMT_RGB24; - else if(rmask == 0xff && gmask == 0xff00 && bmask == 0xff0000) - fmt = PIX_FMT_BGR24; - break; - - case 16: - if(rmask == 0xf800 && gmask == 0x07e0 && bmask == 0x001f) - fmt = PIX_FMT_RGB565; - else if(rmask == 0x7c00 && gmask == 0x03e0 && bmask == 0x001f) - fmt = PIX_FMT_RGB555; - break; - - default: - break; - } - - if(fmt == PIX_FMT_NONE) - error("Unsupported pixel format (bpp=%d r=%lx g=%lx b=%lx)", bpp, rmask, gmask, bmask); - - return fmt; -} - -/* * from libavformat/mpegts.c */ Modified: redbutton-browser/trunk/MHEGStreamPlayer.h =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.h 2006-05-19 16:13:56 UTC (rev 70) +++ redbutton-browser/trunk/MHEGStreamPlayer.h 2006-05-22 08:31:19 UTC (rev 71) @@ -35,25 +35,23 @@ /* player state */ typedef struct { - bool playing; /* true when our threads are active */ - bool stop; /* true => stop playback */ - bool have_video; /* false if we have no video stream */ - bool have_audio; /* false if we have no audio stream */ - int video_tag; /* video stream component tag (-1 => default for current service ID) */ - int video_pid; /* PID in MPEG Transport Stream (-1 => not yet known) */ - int video_type; /* video stream type (-1 => not yet known) */ - int audio_tag; /* audio stream component tag (-1 => default for current service ID) */ - int audio_pid; /* PID in MPEG Transport Stream (-1 => not yet known) */ - int audio_type; /* audio stream type (-1 => not yet known) */ - FILE *ts; /* MPEG Transport Stream */ - VideoClass *video; /* output size/position, maybe NULL if audio only */ - pthread_t decode_tid; /* thread decoding the MPEG stream into frames */ - pthread_t video_tid; /* thread displaying frames on the screen */ - pthread_mutex_t videoq_lock; /* list of decoded video frames */ - unsigned int videoq_len; /* number of frames on the videoq */ - LIST_OF(VideoFrame) *videoq; /* head of list is next to be displayed */ - pthread_mutex_t current_frame_lock; /* locked when we are updating current frame */ - XImage *current_frame; /* frame we are currently displaying */ + bool playing; /* true when our threads are active */ + bool stop; /* true => stop playback */ + bool have_video; /* false if we have no video stream */ + bool have_audio; /* false if we have no audio stream */ + int video_tag; /* video stream component tag (-1 => default for current service ID) */ + int video_pid; /* PID in MPEG Transport Stream (-1 => not yet known) */ + int video_type; /* video stream type (-1 => not yet known) */ + int audio_tag; /* audio stream component tag (-1 => default for current service ID) */ + int audio_pid; /* PID in MPEG Transport Stream (-1 => not yet known) */ + int audio_type; /* audio stream type (-1 => not yet known) */ + FILE *ts; /* MPEG Transport Stream */ + VideoClass *video; /* output size/position, maybe NULL if audio only */ + pthread_t decode_tid; /* thread decoding the MPEG stream into frames */ + pthread_t video_tid; /* thread displaying frames on the screen */ + pthread_mutex_t videoq_lock; /* list of decoded video frames */ + unsigned int videoq_len; /* number of frames on the videoq */ + LIST_OF(VideoFrame) *videoq; /* head of list is next to be displayed */ } MHEGStreamPlayer; void MHEGStreamPlayer_init(MHEGStreamPlayer *); Added: redbutton-browser/trunk/MHEGVideoOutput.c =================================================================== --- redbutton-browser/trunk/MHEGVideoOutput.c (rev 0) +++ redbutton-browser/trunk/MHEGVideoOutput.c 2006-05-22 08:31:19 UTC (rev 71) @@ -0,0 +1,246 @@ +/* + * MHEGVideoOutput.h + */ + +#include <pthread.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/extensions/XShm.h> +#include <ffmpeg/avformat.h> + +#include "MHEGEngine.h" +#include "MHEGVideoOutput.h" +#include "utils.h" + +void x11_shm_init(MHEGVideoOutput *); +void x11_shm_fini(MHEGVideoOutput *); +void x11_shm_prepareFrame(MHEGVideoOutput *, VideoFrame *, unsigned int, unsigned int); +void x11_shm_drawFrame(MHEGVideoOutput *, int, int); + +static void x11_shm_create_frame(MHEGVideoOutput *, unsigned int, unsigned int); +static void x11_shm_destroy_frame(MHEGVideoOutput *); + +static enum PixelFormat find_av_pix_fmt(int, unsigned long, unsigned long, unsigned long); + +void +MHEGVideoOutput_init(MHEGVideoOutput *v) +{ + return x11_shm_init(v); +} + +void +MHEGVideoOutput_fini(MHEGVideoOutput *v) +{ + return x11_shm_fini(v); +} + +void +MHEGVideoOutput_prepareFrame(MHEGVideoOutput *v, VideoFrame *f, unsigned int out_width, unsigned int out_height) +{ + return x11_shm_prepareFrame(v, f, out_width, out_height); +} + +void +MHEGVideoOutput_drawFrame(MHEGVideoOutput *v, int x, int y) +{ + return x11_shm_drawFrame(v, x, y); +} + +void +x11_shm_init(MHEGVideoOutput *v) +{ + pthread_mutex_init(&v->current_frame_lock, NULL); + v->current_frame = NULL; + + v->resize_ctx = NULL; + + v->tmpbuf_data = NULL; + + return; +} + +void +x11_shm_fini(MHEGVideoOutput *v) +{ + if(v->resize_ctx != NULL) + { + img_resample_close(v->resize_ctx); + safe_free(v->tmpbuf_data); + } + + if(v->current_frame != NULL) + x11_shm_destroy_frame(v); + + pthread_mutex_destroy(&v->current_frame_lock); + + return; +} + +void +x11_shm_prepareFrame(MHEGVideoOutput *v, VideoFrame *f, unsigned int out_width, unsigned int out_height) +{ + AVPicture resized_frame; + AVPicture *yuv_frame; + int tmpbuf_size; + + /* see if the output size has changed since the last frame */ +/* TODO if it has, delete the old one or just resize shm etc */ +/* will also need to delete resize_ctx */ + + if(v->current_frame == NULL) + x11_shm_create_frame(v, out_width, out_height); + + /* see if the input size is different than the output size */ + if(f->width != out_width || f->height != out_height) + { +/* TODO */ +/* need to change resize_ctx if vf->width or vf->height have changed since last time */ +/* dont forget: img_resample_close(resize_ctx); */ +/* and to free or realloc tmpbuf_data */ + if(v->resize_ctx == NULL) + { + v->resize_ctx = img_resample_init(out_width, out_height, f->width, f->height); + tmpbuf_size = avpicture_get_size(f->pix_fmt, out_width, out_height); + v->tmpbuf_data = safe_malloc(tmpbuf_size); + avpicture_fill(&resized_frame, v->tmpbuf_data, f->pix_fmt, out_width, out_height); + } + img_resample(v->resize_ctx, &resized_frame, &f->frame); + yuv_frame = &resized_frame; + } + else + { + yuv_frame = &f->frame; + } + + /* convert the frame to RGB */ + pthread_mutex_lock(&v->current_frame_lock); + img_convert(&v->rgb_frame, v->out_format, yuv_frame, f->pix_fmt, out_width, out_height); + pthread_mutex_unlock(&v->current_frame_lock); + + return; +} + +void +x11_shm_drawFrame(MHEGVideoOutput *v, int x, int y) +{ + MHEGDisplay *d = MHEGEngine_getDisplay(); + unsigned int out_width; + unsigned int out_height; + +/* TODO */ +/* probably dont need this lock anymore, only we use v->current_frame */ + pthread_mutex_lock(&v->current_frame_lock); + if(v->current_frame != NULL) + { + /* video frame is already scaled as needed */ + out_width = v->current_frame->width; + out_height = v->current_frame->height; + /* draw it onto the Window contents Pixmap */ + XShmPutImage(d->dpy, d->contents, d->win_gc, v->current_frame, 0, 0, x, y, out_width, out_height, False); + /* get it drawn straight away */ + XFlush(d->dpy); + } + pthread_mutex_unlock(&v->current_frame_lock); + + return; +} + +static void +x11_shm_create_frame(MHEGVideoOutput *v, unsigned int out_width, unsigned int out_height) +{ + MHEGDisplay *d = MHEGEngine_getDisplay(); + int rgb_size; + + if((v->current_frame = XShmCreateImage(d->dpy, d->vis, d->depth, ZPixmap, NULL, &v->shm, out_width, out_height)) == NULL) + fatal("XShmCreateImage failed"); + + /* work out what ffmpeg pixel format matches our XImage format */ + if((v->out_format = find_av_pix_fmt(v->current_frame->bits_per_pixel, + d->vis->red_mask, d->vis->green_mask, d->vis->blue_mask)) == PIX_FMT_NONE) + fatal("Unsupported XImage pixel format"); + + rgb_size = v->current_frame->bytes_per_line * out_height; + + if(rgb_size != avpicture_get_size(v->out_format, out_width, out_height)) + fatal("XImage and ffmpeg pixel formats differ"); + + if((v->shm.shmid = shmget(IPC_PRIVATE, rgb_size, IPC_CREAT | 0777)) == -1) + fatal("shmget failed"); + if((v->shm.shmaddr = shmat(v->shm.shmid, NULL, 0)) == (void *) -1) + fatal("shmat failed"); + v->shm.readOnly = True; + if(!XShmAttach(d->dpy, &v->shm)) + fatal("XShmAttach failed"); + + /* we made sure these pixel formats are the same */ + v->current_frame->data = v->shm.shmaddr; + avpicture_fill(&v->rgb_frame, v->shm.shmaddr, v->out_format, out_width, out_height); + + return; +} + +static void +x11_shm_destroy_frame(MHEGVideoOutput *v) +{ + MHEGDisplay *d = MHEGEngine_getDisplay(); + + /* get rid of the current frame */ + pthread_mutex_lock(&v->current_frame_lock); + /* the XImage data is our shared memory, make sure XDestroyImage doesn't try to free it */ + v->current_frame->data = NULL; + XDestroyImage(v->current_frame); + /* make sure no-one tries to use it */ + v->current_frame = NULL; + pthread_mutex_unlock(&v->current_frame_lock); + + XShmDetach(d->dpy, &v->shm); + shmdt(v->shm.shmaddr); + shmctl(v->shm.shmid, IPC_RMID, NULL); + + return; +} + +/* + * returns a PIX_FMT_xxx type that matches the given bits per pixel and RGB bit mask values + * returns PIX_FMT_NONE if none match + */ + +static enum PixelFormat +find_av_pix_fmt(int bpp, unsigned long rmask, unsigned long gmask, unsigned long bmask) +{ + enum PixelFormat fmt; + + fmt = PIX_FMT_NONE; + switch(bpp) + { + case 32: + if(rmask == 0xff0000 && gmask == 0xff00 && bmask == 0xff) + fmt = PIX_FMT_RGBA32; + break; + + case 24: + if(rmask == 0xff0000 && gmask == 0xff00 && bmask == 0xff) + fmt = PIX_FMT_RGB24; + else if(rmask == 0xff && gmask == 0xff00 && bmask == 0xff0000) + fmt = PIX_FMT_BGR24; + break; + + case 16: + if(rmask == 0xf800 && gmask == 0x07e0 && bmask == 0x001f) + fmt = PIX_FMT_RGB565; + else if(rmask == 0x7c00 && gmask == 0x03e0 && bmask == 0x001f) + fmt = PIX_FMT_RGB555; + break; + + default: + break; + } + + if(fmt == PIX_FMT_NONE) + error("Unsupported pixel format (bpp=%d r=%lx g=%lx b=%lx)", bpp, rmask, gmask, bmask); + + return fmt; +} + Added: redbutton-browser/trunk/MHEGVideoOutput.h =================================================================== --- redbutton-browser/trunk/MHEGVideoOutput.h (rev 0) +++ redbutton-browser/trunk/MHEGVideoOutput.h 2006-05-22 08:31:19 UTC (rev 71) @@ -0,0 +1,26 @@ +/* + * MHEGVideoOutput.h + */ + +#ifndef __MHEGVIDEOOUTPUT_H__ +#define __MHEGVIDEOOUTPUT_H__ + +typedef struct +{ + XShmSegmentInfo shm; + AVPicture rgb_frame; + enum PixelFormat out_format; + ImgReSampleContext *resize_ctx; + uint8_t *tmpbuf_data; + pthread_mutex_t current_frame_lock; /* locked when we are updating current frame */ + XImage *current_frame; /* frame we are currently displaying */ +} MHEGVideoOutput; + +void MHEGVideoOutput_init(MHEGVideoOutput *); +void MHEGVideoOutput_fini(MHEGVideoOutput *); + +void MHEGVideoOutput_prepareFrame(MHEGVideoOutput *, VideoFrame *, unsigned int, unsigned int); +void MHEGVideoOutput_drawFrame(MHEGVideoOutput *, int, int); + +#endif /* __MHEGVIDEOOUTPUT_H__ */ + Modified: redbutton-browser/trunk/Makefile =================================================================== --- redbutton-browser/trunk/Makefile 2006-05-19 16:13:56 UTC (rev 70) +++ redbutton-browser/trunk/Makefile 2006-05-22 08:31:19 UTC (rev 71) @@ -66,6 +66,7 @@ MHEGFont.o \ MHEGTimer.o \ MHEGStreamPlayer.o \ + MHEGVideoOutput.o \ ${CLASSES} \ ISO13522-MHEG-5.o \ der_decode.o \ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-05-22 13:31:01
|
Revision: 74 Author: skilvington Date: 2006-05-22 06:30:46 -0700 (Mon, 22 May 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=74&view=rev Log Message: ----------- bug fix Modified Paths: -------------- redbutton-browser/trunk/MHEGVideoOutput.c redbutton-browser/trunk/MHEGVideoOutput.h Modified: redbutton-browser/trunk/MHEGVideoOutput.c =================================================================== --- redbutton-browser/trunk/MHEGVideoOutput.c 2006-05-22 12:58:15 UTC (rev 73) +++ redbutton-browser/trunk/MHEGVideoOutput.c 2006-05-22 13:30:46 UTC (rev 74) @@ -82,7 +82,6 @@ void x11_shm_prepareFrame(MHEGVideoOutput *v, VideoFrame *f, unsigned int out_width, unsigned int out_height) { - AVPicture resized_frame; AVPicture *yuv_frame; int tmpbuf_size; @@ -106,10 +105,10 @@ v->resize_ctx = img_resample_init(out_width, out_height, f->width, f->height); tmpbuf_size = avpicture_get_size(f->pix_fmt, out_width, out_height); v->tmpbuf_data = safe_malloc(tmpbuf_size); - avpicture_fill(&resized_frame, v->tmpbuf_data, f->pix_fmt, out_width, out_height); + avpicture_fill(&v->resized_frame, v->tmpbuf_data, f->pix_fmt, out_width, out_height); } - img_resample(v->resize_ctx, &resized_frame, &f->frame); - yuv_frame = &resized_frame; + img_resample(v->resize_ctx, &v->resized_frame, &f->frame); + yuv_frame = &v->resized_frame; } else { Modified: redbutton-browser/trunk/MHEGVideoOutput.h =================================================================== --- redbutton-browser/trunk/MHEGVideoOutput.h 2006-05-22 12:58:15 UTC (rev 73) +++ redbutton-browser/trunk/MHEGVideoOutput.h 2006-05-22 13:30:46 UTC (rev 74) @@ -11,6 +11,7 @@ AVPicture rgb_frame; enum PixelFormat out_format; ImgReSampleContext *resize_ctx; + AVPicture resized_frame; uint8_t *tmpbuf_data; pthread_mutex_t current_frame_lock; /* locked when we are updating current frame */ XImage *current_frame; /* frame we are currently displaying */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-05-22 13:57:28
|
Revision: 75 Author: skilvington Date: 2006-05-22 06:57:21 -0700 (Mon, 22 May 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=75&view=rev Log Message: ----------- no need for current_frame_lock Modified Paths: -------------- redbutton-browser/trunk/MHEGVideoOutput.c redbutton-browser/trunk/MHEGVideoOutput.h Modified: redbutton-browser/trunk/MHEGVideoOutput.c =================================================================== --- redbutton-browser/trunk/MHEGVideoOutput.c 2006-05-22 13:30:46 UTC (rev 74) +++ redbutton-browser/trunk/MHEGVideoOutput.c 2006-05-22 13:57:21 UTC (rev 75) @@ -52,7 +52,6 @@ void x11_shm_init(MHEGVideoOutput *v) { - pthread_mutex_init(&v->current_frame_lock, NULL); v->current_frame = NULL; v->resize_ctx = NULL; @@ -74,8 +73,6 @@ if(v->current_frame != NULL) x11_shm_destroy_frame(v); - pthread_mutex_destroy(&v->current_frame_lock); - return; } @@ -116,9 +113,7 @@ } /* convert the frame to RGB */ - pthread_mutex_lock(&v->current_frame_lock); img_convert(&v->rgb_frame, v->out_format, yuv_frame, f->pix_fmt, out_width, out_height); - pthread_mutex_unlock(&v->current_frame_lock); return; } @@ -130,9 +125,6 @@ unsigned int out_width; unsigned int out_height; -/* TODO */ -/* probably dont need this lock anymore, only we use v->current_frame */ - pthread_mutex_lock(&v->current_frame_lock); if(v->current_frame != NULL) { /* video frame is already scaled as needed */ @@ -143,7 +135,6 @@ /* get it drawn straight away */ XFlush(d->dpy); } - pthread_mutex_unlock(&v->current_frame_lock); return; } @@ -203,13 +194,11 @@ MHEGDisplay *d = MHEGEngine_getDisplay(); /* get rid of the current frame */ - pthread_mutex_lock(&v->current_frame_lock); /* the XImage data is our shared memory, make sure XDestroyImage doesn't try to free it */ v->current_frame->data = NULL; XDestroyImage(v->current_frame); /* make sure no-one tries to use it */ v->current_frame = NULL; - pthread_mutex_unlock(&v->current_frame_lock); XShmDetach(d->dpy, &v->shm); shmdt(v->shm.shmaddr); Modified: redbutton-browser/trunk/MHEGVideoOutput.h =================================================================== --- redbutton-browser/trunk/MHEGVideoOutput.h 2006-05-22 13:30:46 UTC (rev 74) +++ redbutton-browser/trunk/MHEGVideoOutput.h 2006-05-22 13:57:21 UTC (rev 75) @@ -13,7 +13,6 @@ ImgReSampleContext *resize_ctx; AVPicture resized_frame; uint8_t *tmpbuf_data; - pthread_mutex_t current_frame_lock; /* locked when we are updating current frame */ XImage *current_frame; /* frame we are currently displaying */ } MHEGVideoOutput; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-05-22 16:04:05
|
Revision: 76 Author: skilvington Date: 2006-05-22 09:03:57 -0700 (Mon, 22 May 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=76&view=rev Log Message: ----------- allow video output resizing to change mid-stream Modified Paths: -------------- redbutton-browser/trunk/MHEGStreamPlayer.c redbutton-browser/trunk/MHEGVideoOutput.c redbutton-browser/trunk/MHEGVideoOutput.h Modified: redbutton-browser/trunk/MHEGStreamPlayer.c =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.c 2006-05-22 13:57:21 UTC (rev 75) +++ redbutton-browser/trunk/MHEGStreamPlayer.c 2006-05-22 16:03:57 UTC (rev 76) @@ -404,6 +404,7 @@ out_height = vf->height; /* TODO */ /* use scaled values if ScaleVideo has been called */ +/* have a lock incase we are doing ScaleVideo in another thread */ /* scale up if fullscreen */ if(d->fullscreen) { @@ -432,7 +433,7 @@ /* remember the time stamp for this frame */ last_pts = vf->pts; //now=av_gettime(); -//printf("display frame %d: pts=%f this_time=%lld real_time=%lld (diff=%lld)\n", ++nframes, vf->pts, last_time, now, now-last_time); +//printf("display frame %d: pts=%f this_time=%lld real_time=%lld (diff=%lld)\n", nframes, vf->pts, last_time, now, now-last_time); /* origin of VideoClass */ /* TODO should probably have a lock for this in case we are doing SetPosition in another thread */ out_x = p->video->inst.Position.x_position; Modified: redbutton-browser/trunk/MHEGVideoOutput.c =================================================================== --- redbutton-browser/trunk/MHEGVideoOutput.c 2006-05-22 13:57:21 UTC (rev 75) +++ redbutton-browser/trunk/MHEGVideoOutput.c 2006-05-22 16:03:57 UTC (rev 76) @@ -2,7 +2,6 @@ * MHEGVideoOutput.h */ -#include <pthread.h> #include <sys/ipc.h> #include <sys/shm.h> #include <X11/Xlib.h> @@ -37,12 +36,20 @@ return x11_shm_fini(v); } +/* + * get ready to draw the given frame at the given output size + */ + void MHEGVideoOutput_prepareFrame(MHEGVideoOutput *v, VideoFrame *f, unsigned int out_width, unsigned int out_height) { return x11_shm_prepareFrame(v, f, out_width, out_height); } +/* + * draw the frame set up by MHEGVideoOutput_prepareFrame() at the given position on the contents Pixmap + */ + void MHEGVideoOutput_drawFrame(MHEGVideoOutput *v, int x, int y) { @@ -55,9 +62,8 @@ v->current_frame = NULL; v->resize_ctx = NULL; + v->resized_data = NULL; - v->tmpbuf_data = NULL; - return; } @@ -67,7 +73,7 @@ if(v->resize_ctx != NULL) { img_resample_close(v->resize_ctx); - safe_free(v->tmpbuf_data); + safe_free(v->resized_data); } if(v->current_frame != NULL) @@ -80,9 +86,9 @@ x11_shm_prepareFrame(MHEGVideoOutput *v, VideoFrame *f, unsigned int out_width, unsigned int out_height) { AVPicture *yuv_frame; - int tmpbuf_size; + int resized_size; - /* have we create the output frame yet */ + /* have we created the output frame yet */ if(v->current_frame == NULL) x11_shm_create_frame(v, out_width, out_height); @@ -93,17 +99,28 @@ /* see if the input size is different than the output size */ if(f->width != out_width || f->height != out_height) { -/* TODO */ -/* need to change resize_ctx if the input or output sizes have changed since last time */ -/* dont forget: img_resample_close(resize_ctx); */ -/* and to free or realloc tmpbuf_data */ - if(v->resize_ctx == NULL) + /* have the resize input or output dimensions changed */ + if(v->resize_ctx == NULL + || v->resize_in.width != f->width || v->resize_in.height != f->height + || v->resize_out.width != out_width || v->resize_out.height != out_height) { - v->resize_ctx = img_resample_init(out_width, out_height, f->width, f->height); - tmpbuf_size = avpicture_get_size(f->pix_fmt, out_width, out_height); - v->tmpbuf_data = safe_malloc(tmpbuf_size); - avpicture_fill(&v->resized_frame, v->tmpbuf_data, f->pix_fmt, out_width, out_height); + /* get rid of any existing resize context */ + if(v->resize_ctx != NULL) + img_resample_close(v->resize_ctx); + if((v->resize_ctx = img_resample_init(out_width, out_height, f->width, f->height)) == NULL) + fatal("Out of memory"); + /* remember the resize input and output dimensions */ + v->resize_in.width = f->width; + v->resize_in.height = f->height; + v->resize_out.width = out_width; + v->resize_out.height = out_height; + /* somewhere to store the resized frame */ + if((resized_size = avpicture_get_size(f->pix_fmt, out_width, out_height)) < 0) + fatal("x11_shm_prepareFrame: invalid frame size"); + v->resized_data = safe_realloc(v->resized_data, resized_size); + avpicture_fill(&v->resized_frame, v->resized_data, f->pix_fmt, out_width, out_height); } + /* resize it */ img_resample(v->resize_ctx, &v->resized_frame, &f->frame); yuv_frame = &v->resized_frame; } @@ -200,6 +217,7 @@ /* make sure no-one tries to use it */ v->current_frame = NULL; + /* get rid of the shared memory */ XShmDetach(d->dpy, &v->shm); shmdt(v->shm.shmaddr); shmctl(v->shm.shmid, IPC_RMID, NULL); Modified: redbutton-browser/trunk/MHEGVideoOutput.h =================================================================== --- redbutton-browser/trunk/MHEGVideoOutput.h 2006-05-22 13:57:21 UTC (rev 75) +++ redbutton-browser/trunk/MHEGVideoOutput.h 2006-05-22 16:03:57 UTC (rev 76) @@ -7,13 +7,21 @@ typedef struct { - XShmSegmentInfo shm; - AVPicture rgb_frame; - enum PixelFormat out_format; - ImgReSampleContext *resize_ctx; - AVPicture resized_frame; - uint8_t *tmpbuf_data; + unsigned int width; + unsigned int height; +} FrameSize; + +typedef struct +{ XImage *current_frame; /* frame we are currently displaying */ + XShmSegmentInfo shm; /* shared memory used by current_frame */ + AVPicture rgb_frame; /* ffmpeg wrapper for current_frame SHM data */ + enum PixelFormat out_format; /* rgb_frame ffmpeg pixel format */ + ImgReSampleContext *resize_ctx; /* NULL if we do not need to resize the frame */ + FrameSize resize_in; /* resize_ctx input dimensions */ + FrameSize resize_out; /* resize_ctx output dimensions */ + AVPicture resized_frame; /* resized output frame */ + uint8_t *resized_data; /* resized_frame data buffer */ } MHEGVideoOutput; void MHEGVideoOutput_init(MHEGVideoOutput *); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-05-22 16:24:15
|
Revision: 77 Author: skilvington Date: 2006-05-22 09:24:08 -0700 (Mon, 22 May 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=77&view=rev Log Message: ----------- implement ScaleVideo Modified Paths: -------------- redbutton-browser/trunk/MHEGStreamPlayer.c redbutton-browser/trunk/VideoClass.c redbutton-browser/trunk/add_instance_vars.conf Modified: redbutton-browser/trunk/MHEGStreamPlayer.c =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.c 2006-05-22 16:03:57 UTC (rev 76) +++ redbutton-browser/trunk/MHEGStreamPlayer.c 2006-05-22 16:24:08 UTC (rev 77) @@ -400,11 +400,19 @@ if(!drop_frame) { /* scale the next frame if necessary */ - out_width = vf->width; - out_height = vf->height; -/* TODO */ -/* use scaled values if ScaleVideo has been called */ -/* have a lock incase we are doing ScaleVideo in another thread */ + pthread_mutex_lock(&p->video->inst.scaled_lock); + /* use scaled values if ScaleVideo has been called */ + if(p->video->inst.scaled) + { + out_width = p->video->inst.scaled_width; + out_height = p->video->inst.scaled_height; + } + else + { + out_width = vf->width; + out_height = vf->height; + } + pthread_mutex_unlock(&p->video->inst.scaled_lock); /* scale up if fullscreen */ if(d->fullscreen) { @@ -435,9 +443,10 @@ //now=av_gettime(); //printf("display frame %d: pts=%f this_time=%lld real_time=%lld (diff=%lld)\n", nframes, vf->pts, last_time, now, now-last_time); /* origin of VideoClass */ -/* TODO should probably have a lock for this in case we are doing SetPosition in another thread */ + pthread_mutex_lock(&p->video->inst.bbox_lock); out_x = p->video->inst.Position.x_position; out_y = p->video->inst.Position.y_position; + pthread_mutex_unlock(&p->video->inst.bbox_lock); /* scale if fullscreen */ if(d->fullscreen) { @@ -447,7 +456,9 @@ /* draw the current frame */ MHEGVideoOutput_drawFrame(&vo, out_x, out_y); /* redraw objects above the video */ + pthread_mutex_lock(&p->video->inst.bbox_lock); MHEGDisplay_refresh(d, &p->video->inst.Position, &p->video->inst.BoxSize); + pthread_mutex_unlock(&p->video->inst.bbox_lock); /* get it drawn straight away */ XFlush(d->dpy); } Modified: redbutton-browser/trunk/VideoClass.c =================================================================== --- redbutton-browser/trunk/VideoClass.c 2006-05-22 16:03:57 UTC (rev 76) +++ redbutton-browser/trunk/VideoClass.c 2006-05-22 16:24:08 UTC (rev 77) @@ -30,6 +30,10 @@ v->VideoDecodeOffset.x_position = 0; v->VideoDecodeOffset.y_position = 0; + pthread_mutex_init(&v->bbox_lock, NULL); + pthread_mutex_init(&v->scaled_lock, NULL); + v->scaled = false; + return; } @@ -39,6 +43,9 @@ if(v->have_PaletteRef) free_ObjectReference(&v->PaletteRef); + pthread_mutex_destroy(&v->bbox_lock); + pthread_mutex_destroy(&v->scaled_lock); + return; } @@ -137,8 +144,10 @@ old.x_position = t->inst.Position.x_position; old.y_position = t->inst.Position.y_position; + pthread_mutex_lock(&t->inst.bbox_lock); t->inst.Position.x_position = GenericInteger_getInteger(¶ms->new_x_position, caller_gid); t->inst.Position.y_position = GenericInteger_getInteger(¶ms->new_y_position, caller_gid); + pthread_mutex_unlock(&t->inst.bbox_lock); /* if it is active, redraw it */ if(t->rootClass.inst.RunningStatus) @@ -196,8 +205,10 @@ old.x_length = t->inst.BoxSize.x_length; old.y_length = t->inst.BoxSize.y_length; + pthread_mutex_lock(&t->inst.bbox_lock); t->inst.BoxSize.x_length = GenericInteger_getInteger(¶ms->x_new_box_size, caller_gid); t->inst.BoxSize.y_length = GenericInteger_getInteger(¶ms->y_new_box_size, caller_gid); + pthread_mutex_unlock(&t->inst.bbox_lock); /* if it is active, redraw it */ if(t->rootClass.inst.RunningStatus) @@ -346,16 +357,14 @@ void VideoClass_ScaleVideo(VideoClass *t, ScaleVideo *params, OctetString *caller_gid) { - int x_scale; - int y_scale; - verbose("VideoClass: %s; ScaleVideo", ExternalReference_name(&t->rootClass.inst.ref)); - x_scale = GenericInteger_getInteger(¶ms->x_scale, caller_gid); - y_scale = GenericInteger_getInteger(¶ms->y_scale, caller_gid); + pthread_mutex_lock(&t->inst.scaled_lock); + t->inst.scaled = true; + t->inst.scaled_width = GenericInteger_getInteger(¶ms->x_scale, caller_gid); + t->inst.scaled_height = GenericInteger_getInteger(¶ms->y_scale, caller_gid); + pthread_mutex_unlock(&t->inst.scaled_lock); -/* TODO */ -printf("TODO: VideoClass_ScaleVideo(%d, %d) not yet implemented\n", x_scale, y_scale); return; } Modified: redbutton-browser/trunk/add_instance_vars.conf =================================================================== --- redbutton-browser/trunk/add_instance_vars.conf 2006-05-22 16:03:57 UTC (rev 76) +++ redbutton-browser/trunk/add_instance_vars.conf 2006-05-22 16:24:08 UTC (rev 77) @@ -165,6 +165,8 @@ </TextClass> <VideoClass> +#include <pthread.h> + typedef struct { /* inherited from VisibleClass */ @@ -175,6 +177,13 @@ /* VideoClass */ /* UK MHEG Profile adds this */ XYPosition VideoDecodeOffset; + /* we add a lock for the size/position */ + pthread_mutex_t bbox_lock; + /* and the scaled size */ + pthread_mutex_t scaled_lock; + bool scaled; + unsigned int scaled_width; + unsigned int scaled_height; } VideoClassInstanceVars; </VideoClass> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-06-02 11:01:54
|
Revision: 84 Author: skilvington Date: 2006-06-02 04:01:46 -0700 (Fri, 02 Jun 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=84&view=rev Log Message: ----------- pass the AudioClass to the stream player Modified Paths: -------------- redbutton-browser/trunk/MHEGStreamPlayer.c redbutton-browser/trunk/MHEGStreamPlayer.h redbutton-browser/trunk/StreamComponent.c Modified: redbutton-browser/trunk/MHEGStreamPlayer.c =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.c 2006-05-31 13:35:40 UTC (rev 83) +++ redbutton-browser/trunk/MHEGStreamPlayer.c 2006-06-02 11:01:46 UTC (rev 84) @@ -66,6 +66,7 @@ p->have_audio = false; p->video = NULL; + p->audio = NULL; pthread_mutex_init(&p->videoq_lock, NULL); p->videoq_len = 0; @@ -85,30 +86,37 @@ } void -MHEGStreamPlayer_setVideoTag(MHEGStreamPlayer *p, VideoClass *video, int tag) +MHEGStreamPlayer_setVideoStream(MHEGStreamPlayer *p, VideoClass *video) { if(p->have_video) - error("MHEGStreamPlayer: more than one video stream; only using the last one (%d)", tag); + error("MHEGStreamPlayer: more than one video stream; only using the last one (%d)", video->component_tag); p->have_video = true; - p->video_tag = tag; - p->video_pid = -1; - p->video_type = -1; /* output size/position */ p->video = video; + /* the backend will tell us the PID and stream type when we start streaming it */ + p->video_tag = video->component_tag; + p->video_pid = -1; + p->video_type = -1; + return; } void -MHEGStreamPlayer_setAudioTag(MHEGStreamPlayer *p, int tag) +MHEGStreamPlayer_setAudioStream(MHEGStreamPlayer *p, AudioClass *audio) { if(p->have_audio) - error("MHEGStreamPlayer: more than one audio stream; only using the last one (%d)", tag); + error("MHEGStreamPlayer: more than one audio stream; only using the last one (%d)", audio->component_tag); p->have_audio = true; - p->audio_tag = tag; + + /* volume */ + p->audio = audio; + + /* the backend will tell us the PID and stream type when we start streaming it */ + p->audio_tag = audio->component_tag; p->audio_pid = -1; p->audio_type = -1; Modified: redbutton-browser/trunk/MHEGStreamPlayer.h =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.h 2006-05-31 13:35:40 UTC (rev 83) +++ redbutton-browser/trunk/MHEGStreamPlayer.h 2006-06-02 11:01:46 UTC (rev 84) @@ -39,6 +39,8 @@ bool stop; /* true => stop playback */ bool have_video; /* false if we have no video stream */ bool have_audio; /* false if we have no audio stream */ + VideoClass *video; /* output size/position, maybe NULL if audio only */ + AudioClass *audio; /* output volume, maybe NULL if video only */ int video_tag; /* video stream component tag (-1 => default for current service ID) */ int video_pid; /* PID in MPEG Transport Stream (-1 => not yet known) */ int video_type; /* video stream type (-1 => not yet known) */ @@ -46,7 +48,6 @@ int audio_pid; /* PID in MPEG Transport Stream (-1 => not yet known) */ int audio_type; /* audio stream type (-1 => not yet known) */ FILE *ts; /* MPEG Transport Stream */ - VideoClass *video; /* output size/position, maybe NULL if audio only */ pthread_t decode_tid; /* thread decoding the MPEG stream into frames */ pthread_t video_tid; /* thread displaying frames on the screen */ pthread_mutex_t videoq_lock; /* list of decoded video frames */ @@ -57,8 +58,8 @@ void MHEGStreamPlayer_init(MHEGStreamPlayer *); void MHEGStreamPlayer_fini(MHEGStreamPlayer *); -void MHEGStreamPlayer_setVideoTag(MHEGStreamPlayer *, VideoClass *, int); -void MHEGStreamPlayer_setAudioTag(MHEGStreamPlayer *, int); +void MHEGStreamPlayer_setVideoStream(MHEGStreamPlayer *, VideoClass *); +void MHEGStreamPlayer_setAudioStream(MHEGStreamPlayer *, AudioClass *); void MHEGStreamPlayer_play(MHEGStreamPlayer *); void MHEGStreamPlayer_stop(MHEGStreamPlayer *); Modified: redbutton-browser/trunk/StreamComponent.c =================================================================== --- redbutton-browser/trunk/StreamComponent.c 2006-05-31 13:35:40 UTC (rev 83) +++ redbutton-browser/trunk/StreamComponent.c 2006-06-02 11:01:46 UTC (rev 84) @@ -105,11 +105,11 @@ switch(s->choice) { case StreamComponent_audio: - MHEGStreamPlayer_setAudioTag(player, s->u.audio.component_tag); + MHEGStreamPlayer_setAudioStream(player, &s->u.audio); break; case StreamComponent_video: - MHEGStreamPlayer_setVideoTag(player, &s->u.video, s->u.video.component_tag); + MHEGStreamPlayer_setVideoStream(player, &s->u.video); break; case StreamComponent_rtgraphics: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-06-08 02:43:32
|
Revision: 87 Author: skilvington Date: 2006-06-07 09:09:27 -0700 (Wed, 07 Jun 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=87&view=rev Log Message: ----------- avoid unnecessary memcpy when decoding audio Modified Paths: -------------- redbutton-browser/trunk/MHEGStreamPlayer.c redbutton-browser/trunk/MHEGStreamPlayer.h Modified: redbutton-browser/trunk/MHEGStreamPlayer.c =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.c 2006-06-02 15:38:18 UTC (rev 86) +++ redbutton-browser/trunk/MHEGStreamPlayer.c 2006-06-07 16:09:27 UTC (rev 87) @@ -54,7 +54,27 @@ return; } +LIST_TYPE(AudioFrame) * +new_AudioFrameListItem(void) +{ + LIST_TYPE(AudioFrame) *af = safe_malloc(sizeof(LIST_TYPE(AudioFrame))); + + af->item.pts = AV_NOPTS_VALUE; + + af->item.size = 0; + + return af; +} + void +free_AudioFrameListItem(LIST_TYPE(AudioFrame) *af) +{ + safe_free(af); + + return; +} + +void MHEGStreamPlayer_init(MHEGStreamPlayer *p) { bzero(p, sizeof(MHEGStreamPlayer)); @@ -72,6 +92,9 @@ p->videoq_len = 0; p->videoq = NULL; + pthread_mutex_init(&p->audioq_lock, NULL); + p->audioq = NULL; + return; } @@ -81,6 +104,7 @@ MHEGStreamPlayer_stop(p); pthread_mutex_destroy(&p->videoq_lock); + pthread_mutex_destroy(&p->audioq_lock); return; } @@ -215,8 +239,8 @@ AVFrame *frame; LIST_TYPE(VideoFrame) *video_frame; int got_picture; - uint16_t audio_data[AVCODEC_MAX_AUDIO_FRAME_SIZE]; - int audio_size; + LIST_TYPE(AudioFrame) *audio_frame; + AudioFrame *af; int used; unsigned char *data; int size; @@ -264,27 +288,35 @@ /* see what stream we got a packet for */ if(pkt.stream_index == p->audio_pid && pkt.pts != AV_NOPTS_VALUE) { +#if 0 //printf("decode: got audio packet\n"); pts = pkt.pts; data = pkt.data; size = pkt.size; while(size > 0) { - used = avcodec_decode_audio(audio_codec_ctx, audio_data, &audio_size, data, size); -//printf("decode audio: pts=%f used=%d (size=%d) audio_size=%d\n", pts / audio_time_base, used, size, audio_size); + audio_frame = new_AudioFrameListItem(); + af = &audio_frame->item; + used = avcodec_decode_audio(audio_codec_ctx, af->data, &af->size, data, size); +//printf("decode audio: pts=%f used=%d (size=%d) audio_size=%d\n", pts / audio_time_base, used, size, af->size); data += used; size -= used; - if(audio_size > 0) + if(af->size > 0) { - pts += (audio_size * 1000.0) / ((audio_codec_ctx->channels * 2) * audio_codec_ctx->sample_rate); -// audio_frame = new_AudioFrameListItem(pts / audio_time_base, audio_data, audio_size); -// pthread_mutex_lock(&opts->audioq_lock); -// LIST_APPEND(&opts->audioq, audio_frame); -// pthread_mutex_unlock(&opts->audioq_lock); + pts += (af->size * 1000.0) / ((audio_codec_ctx->channels * 2) * audio_codec_ctx->sample_rate); + af->pts = pts / audio_time_base; + pthread_mutex_lock(&p->audioq_lock); + LIST_APPEND(&p->audioq, audio_frame); + pthread_mutex_unlock(&p->audioq_lock); } + else + { + free_AudioFrameListItem(audio_frame); + } } /* don't want one thread hogging the CPU time */ pthread_yield(); +#endif } else if(pkt.stream_index == p->video_pid && pkt.dts != AV_NOPTS_VALUE) { Modified: redbutton-browser/trunk/MHEGStreamPlayer.h =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.h 2006-06-02 15:38:18 UTC (rev 86) +++ redbutton-browser/trunk/MHEGStreamPlayer.h 2006-06-07 16:09:27 UTC (rev 87) @@ -32,6 +32,19 @@ LIST_TYPE(VideoFrame) *new_VideoFrameListItem(double, enum PixelFormat, unsigned int, unsigned int, AVFrame *); void free_VideoFrameListItem(LIST_TYPE(VideoFrame) *); +/* list of decoded audio samples to play */ +typedef struct +{ + double pts; /* presentation time stamp */ + unsigned int size; /* size of data in bytes (not uint16_t's) */ + uint16_t data[AVCODEC_MAX_AUDIO_FRAME_SIZE]; +} AudioFrame; + +DEFINE_LIST_OF(AudioFrame); + +LIST_TYPE(AudioFrame) *new_AudioFrameListItem(void); +void free_AudioFrameListItem(LIST_TYPE(AudioFrame) *); + /* player state */ typedef struct { @@ -53,6 +66,8 @@ pthread_mutex_t videoq_lock; /* list of decoded video frames */ unsigned int videoq_len; /* number of frames on the videoq */ LIST_OF(VideoFrame) *videoq; /* head of list is next to be displayed */ + pthread_mutex_t audioq_lock; /* list of decoded audio samples */ + LIST_OF(AudioFrame) *audioq; /* head of list is next to be played */ } MHEGStreamPlayer; void MHEGStreamPlayer_init(MHEGStreamPlayer *); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-06-08 11:35:26
|
Revision: 90 Author: skilvington Date: 2006-06-08 04:35:12 -0700 (Thu, 08 Jun 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=90&view=rev Log Message: ----------- don't need to keep track of length of videoq Modified Paths: -------------- redbutton-browser/trunk/MHEGStreamPlayer.c redbutton-browser/trunk/MHEGStreamPlayer.h Modified: redbutton-browser/trunk/MHEGStreamPlayer.c =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.c 2006-06-08 11:01:51 UTC (rev 89) +++ redbutton-browser/trunk/MHEGStreamPlayer.c 2006-06-08 11:35:12 UTC (rev 90) @@ -89,7 +89,6 @@ p->audio = NULL; pthread_mutex_init(&p->videoq_lock, NULL); - p->videoq_len = 0; p->videoq = NULL; pthread_mutex_init(&p->audioq_lock, NULL); @@ -202,7 +201,6 @@ pthread_join(p->video_tid, NULL); /* clean up */ - p->videoq_len = 0; LIST_FREE(&p->videoq, VideoFrame, free_VideoFrameListItem); LIST_FREE(&p->audioq, AudioFrame, free_AudioFrameListItem); @@ -329,9 +327,7 @@ pts = pkt.dts / video_time_base; video_frame = new_VideoFrameListItem(pts, video_codec_ctx->pix_fmt, video_codec_ctx->width, video_codec_ctx->height, frame); pthread_mutex_lock(&p->videoq_lock); - p->videoq_len ++; LIST_APPEND(&p->videoq, video_frame); -//printf("decode_thread: add frame: len=%u\n", p->videoq_len); pthread_mutex_unlock(&p->videoq_lock); //printf("decode: got video frame: pts=%f (real pts=%f) width=%d height=%d\n", pts, pkt.pts / video_time_base, video_codec_ctx->width, video_codec_ctx->height); /* don't want one thread hogging the CPU time */ @@ -532,11 +528,6 @@ } /* we can delete the frame from the queue now */ pthread_mutex_lock(&p->videoq_lock); -//printf("video_thread: free frame: len=%u\n", p->videoq_len); - /* assert */ - if(p->videoq_len == 0) - fatal("video_thread: videoq_len is 0"); - p->videoq_len --; LIST_FREE_HEAD(&p->videoq, VideoFrame, free_VideoFrameListItem); pthread_mutex_unlock(&p->videoq_lock); /* don't want one thread hogging the CPU time */ Modified: redbutton-browser/trunk/MHEGStreamPlayer.h =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.h 2006-06-08 11:01:51 UTC (rev 89) +++ redbutton-browser/trunk/MHEGStreamPlayer.h 2006-06-08 11:35:12 UTC (rev 90) @@ -64,7 +64,6 @@ pthread_t decode_tid; /* thread decoding the MPEG stream into frames */ pthread_t video_tid; /* thread displaying frames on the screen */ pthread_mutex_t videoq_lock; /* list of decoded video frames */ - unsigned int videoq_len; /* number of frames on the videoq */ LIST_OF(VideoFrame) *videoq; /* head of list is next to be displayed */ pthread_mutex_t audioq_lock; /* list of decoded audio samples */ LIST_OF(AudioFrame) *audioq; /* head of list is next to be played */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-06-09 15:25:44
|
Revision: 91 Author: skilvington Date: 2006-06-09 08:25:30 -0700 (Fri, 09 Jun 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=91&view=rev Log Message: ----------- rationalise includes Modified Paths: -------------- redbutton-browser/trunk/MHEGStreamPlayer.c redbutton-browser/trunk/MHEGStreamPlayer.h redbutton-browser/trunk/MHEGVideoOutput.h Modified: redbutton-browser/trunk/MHEGStreamPlayer.c =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.c 2006-06-08 11:35:12 UTC (rev 90) +++ redbutton-browser/trunk/MHEGStreamPlayer.c 2006-06-09 15:25:30 UTC (rev 91) @@ -5,7 +5,6 @@ #include <string.h> #include <stdio.h> #include <X11/Xlib.h> -#include <X11/extensions/XShm.h> #include "MHEGEngine.h" #include "MHEGStreamPlayer.h" Modified: redbutton-browser/trunk/MHEGStreamPlayer.h =================================================================== --- redbutton-browser/trunk/MHEGStreamPlayer.h 2006-06-08 11:35:12 UTC (rev 90) +++ redbutton-browser/trunk/MHEGStreamPlayer.h 2006-06-09 15:25:30 UTC (rev 91) @@ -5,9 +5,9 @@ #ifndef __MHEGSTREAMPLAYER_H__ #define __MHEGSTREAMPLAYER_H__ +#include <stdint.h> #include <stdbool.h> #include <pthread.h> -#include <X11/Xlib.h> #include <ffmpeg/avformat.h> #include <ffmpeg/avcodec.h> Modified: redbutton-browser/trunk/MHEGVideoOutput.h =================================================================== --- redbutton-browser/trunk/MHEGVideoOutput.h 2006-06-08 11:35:12 UTC (rev 90) +++ redbutton-browser/trunk/MHEGVideoOutput.h 2006-06-09 15:25:30 UTC (rev 91) @@ -5,6 +5,11 @@ #ifndef __MHEGVIDEOOUTPUT_H__ #define __MHEGVIDEOOUTPUT_H__ +#include <stdint.h> +#include <X11/Xlib.h> +#include <X11/extensions/XShm.h> +#include <ffmpeg/avcodec.h> + typedef struct { unsigned int width; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
|
From: <ski...@us...> - 2006-06-11 09:05:36
|
Revision: 92 Author: skilvington Date: 2006-06-11 02:05:19 -0700 (Sun, 11 Jun 2006) ViewCVS: http://svn.sourceforge.net/redbutton/?rev=92&view=rev Log Message: ----------- add ALSA audio output method (still doesn't play sound yet) Modified Paths: -------------- redbutton-browser/trunk/Makefile Added Paths: ----------- redbutton-browser/trunk/MHEGAudioOutput.c redbutton-browser/trunk/MHEGAudioOutput.h Added: redbutton-browser/trunk/MHEGAudioOutput.c =================================================================== --- redbutton-browser/trunk/MHEGAudioOutput.c (rev 0) +++ redbutton-browser/trunk/MHEGAudioOutput.c 2006-06-11 09:05:19 UTC (rev 92) @@ -0,0 +1,120 @@ +/* + * MHEGAudioOutput.c + */ + +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <alsa/asoundlib.h> + +#include "MHEGAudioOutput.h" +#include "MHEGEngine.h" +#include "utils.h" + +bool +MHEGAudioOutput_init(MHEGAudioOutput *a) +{ + int err; + + a->ctx = NULL; + + if((err = snd_pcm_open(&a->ctx, ALSA_AUDIO_DEVICE, SND_PCM_STREAM_PLAYBACK, 0)) < 0) + { + error("Unable to open audio device '%s': %s", ALSA_AUDIO_DEVICE, snd_strerror(err)); + return false; + } + + return true; +} + +void +MHEGAudioOutput_fini(MHEGAudioOutput *a) +{ + if(a->ctx != NULL) + { + snd_pcm_close(a->ctx); + a->ctx = NULL; + } + + return; +} + +bool +MHEGAudioOutput_setParams(MHEGAudioOutput *a, snd_pcm_format_t format, unsigned int rate, unsigned int channels) +{ + snd_pcm_hw_params_t *hw_params; + int err; + int dir; + + if(a->ctx == NULL) + return false; + + if((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) + { + error("Unable to set audio parameters: %s", snd_strerror(err)); + return false; + } + + if((err = snd_pcm_hw_params_any(a->ctx, hw_params)) < 0) + { + error("Unable to set audio parameters: %s", snd_strerror(err)); + return false; + } + + /* interleaved samples */ + if((err = snd_pcm_hw_params_set_access(a->ctx, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) + { + error("Unable to set audio parameters: %s", snd_strerror(err)); + return false; + } + + if((err = snd_pcm_hw_params_set_format(a->ctx, hw_params, format)) < 0) + { + error("Unable to set audio parameters: %s", snd_strerror(err)); + return false; + } + + if((err = snd_pcm_hw_params_set_rate_near(a->ctx, hw_params, &rate, &dir)) < 0) + { + error("Unable to set audio parameters: %s", snd_strerror(err)); + return false; + } + + if((err = snd_pcm_hw_params_set_channels(a->ctx, hw_params, channels)) < 0) + { + error("Unable to set audio parameters: %s", snd_strerror(err)); + return false; + } + + if((err = snd_pcm_hw_params(a->ctx, hw_params)) < 0) + { + error("Unable to set audio parameters: %s", snd_strerror(err)); + return false; + } + + snd_pcm_hw_params_free(hw_params); + + return true; +} + +void +MHEGAudioOutput_addSamples(MHEGAudioOutput *a, uint16_t *samples, unsigned int nbytes) +{ + unsigned int nsamples; + + if(a->ctx == NULL) + return; + + /* convert bytes to samples */ + nsamples = snd_pcm_bytes_to_frames(a->ctx, nbytes); + + /* interleaved samples */ + while(snd_pcm_writei(a->ctx, samples, nsamples) < 0) + { + snd_pcm_prepare(a->ctx); + verbose("MHEGAudioOutput: buffer underrun"); + } + + return; +} + Added: redbutton-browser/trunk/MHEGAudioOutput.h =================================================================== --- redbutton-browser/trunk/MHEGAudioOutput.h (rev 0) +++ redbutton-browser/trunk/MHEGAudioOutput.h 2006-06-11 09:05:19 UTC (rev 92) @@ -0,0 +1,27 @@ +/* + * MHEGAudioOutput.h + */ + +#include <stdbool.h> +#include <stdint.h> +#include <alsa/asoundlib.h> + +#ifndef __MHEGAUDIOOUTPUT_H__ +#define __MHEGAUDIOOUTPUT_H__ + +typedef struct +{ + snd_pcm_t *ctx; +} MHEGAudioOutput; + +/* default ALSA device */ +#define ALSA_AUDIO_DEVICE "plughw" + +bool MHEGAudioOutput_init(MHEGAudioOutput *); +void MHEGAudioOutput_fini(MHEGAudioOutput *); + +bool MHEGAudioOutput_setParams(MHEGAudioOutput *, snd_pcm_format_t, unsigned int, unsigned int); + +void MHEGAudioOutput_addSamples(MHEGAudioOutput *, uint16_t *, unsigned int); + +#endif /* __MHEGAUDIOOUTPUT_H__ */ Modified: redbutton-browser/trunk/Makefile =================================================================== --- redbutton-browser/trunk/Makefile 2006-06-09 15:25:30 UTC (rev 91) +++ redbutton-browser/trunk/Makefile 2006-06-11 09:05:19 UTC (rev 92) @@ -4,7 +4,7 @@ DEFS=-D_REENTRANT -D_GNU_SOURCE #DEFS=-DDEBUG_ALLOC -D_REENTRANT -D_GNU_SOURCE INCS=`freetype-config --cflags` -LIBS=-lm -lz -L/usr/X11R6/lib -lX11 -lXt -lXrender -lXft -lpng -lmpeg2 -lmpeg2convert -lavformat -lavcodec -lpthread +LIBS=-lm -lz -L/usr/X11R6/lib -lX11 -lXt -lXrender -lXft -lpng -lmpeg2 -lmpeg2convert -lavformat -lavcodec -lasound -lpthread CLASSES=ActionClass.o \ ApplicationClass.o \ @@ -67,6 +67,7 @@ MHEGTimer.o \ MHEGStreamPlayer.o \ MHEGVideoOutput.o \ + MHEGAudioOutput.o \ ${CLASSES} \ ISO13522-MHEG-5.o \ der_decode.o \ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |