/* Speex Xmms plugin * (c) Jens Burkal, license: GPL * * config.c: Configuration setup file * */ #include #include #include #include #include #include #include "speexutil.h" int speex_seek(FILE* spxfile, int time, char direction, int freq) { // time: time in seconds (as provided by xmms) // direction: 0 for backward, 1 for forward // returns the position (i msecs) where it seeked to char *data; int readbytes, result; int res; int granulepos = 0, prev_granulepos = 0; int seekback = 0, prev_seekback = 0; ogg_sync_state oy; ogg_page og; #ifdef DEBUG fprintf(stderr, PACKAGE ": seek to: %d\n", time); #endif if (direction == 0) fseek(spxfile, 0, SEEK_SET); ogg_sync_init(&oy); do { // Submit data to the sync-layer until we get a page while ((res = ogg_sync_pageseek(&oy, &og)) <= 0) { data = ogg_sync_buffer(&oy, 200); readbytes = fread(data, 1, 200, spxfile); ogg_sync_wrote(&oy, readbytes); } prev_granulepos = granulepos; granulepos = ogg_page_granulepos(&og); prev_seekback = seekback; seekback = res; } while (granulepos < time * freq); if (granulepos > (time+1) * freq && prev_granulepos != 0) { seekback += prev_seekback; result = prev_granulepos / (freq / 1000); #ifdef DEBUG fprintf(stderr, PACKAGE ": cons seek\n"); #endif } else result = granulepos / (freq / 1000); // round seekback off to the highest 200's ;) seekback = ((seekback / 200) + 1) * 200; #ifdef DEBUG fprintf(stderr, PACKAGE ": seeked to: %d.%d\n", result / 1000, result % 1000); fprintf(stderr, PACKAGE ": rewind: %d\n", seekback); #endif // Rewind a little bit fseek(spxfile, -seekback, SEEK_CUR); ogg_sync_clear(&oy); return result; } int speex_file_info (char* filename, SpeexHeader** header, speex_comment_t* comment, int* length) { // This could be simpler since we don't actually need stream_state and packets // (just like when seeking). However we do need the samplerate, so we need to // get the header-packet FILE *spxfile; int eof = 0; int rbytes; char init = 0; int maxsize = 0; char *data; ogg_sync_state oy; ogg_stream_state os; ogg_page og; ogg_packet op; SpeexHeader *intheader = NULL; ogg_sync_init(&oy); if (!(spxfile = fopen(filename, "rb"))) { #ifdef DEBUG fprintf(stderr, PACKAGE ": could not open file\n"); #endif return 0; } while (!eof) { data = ogg_sync_buffer(&oy, 200); rbytes = fread(data, 1, 200, spxfile); ogg_sync_wrote(&oy, rbytes); if (rbytes < 200 || feof(spxfile)) eof = 1; while (ogg_sync_pageout(&oy, &og) == 1) { if (init == 0) { ogg_stream_init(&os, ogg_page_serialno(&og)); init = 1; } ogg_stream_pagein(&os, &og); while (ogg_stream_packetout(&os, &op) == 1) { if (op.b_o_s) { intheader = speex_packet_to_header((char*)op.packet, op.bytes); if (header != NULL) { *header = intheader; } } else if (op.packetno == 1) { if (comment != NULL) { if (!speex_comment_init(op.packet, op.bytes, comment)) { #ifdef DEBUG fprintf(stderr,"Warning: invalid comment struct\n"); #endif memset(comment, 0, sizeof(speex_comment_t)); } } } else if (op.e_o_s) { ogg_stream_clear(&os); ogg_sync_clear(&oy); fclose(spxfile); if (intheader == NULL) { fprintf(stderr, PACKAGE ": no header found (eos)\n"); return 0; } #ifdef DEBUG fprintf(stderr, PACKAGE ": length: %d (eos)\n", maxsize / intheader->rate); #endif *length = maxsize / intheader->rate; return 1; } else if (op.granulepos != -1) { maxsize = op.granulepos; } } } } fclose(spxfile); ogg_stream_clear(&os); ogg_sync_clear(&oy); if (intheader == NULL) { fprintf(stderr, PACKAGE ": no header found (eof)\n"); return 0; } #ifdef DEBUG fprintf(stderr, PACKAGE ": length: %d (eof)\n", maxsize / intheader->rate); #endif *length = maxsize / intheader->rate; return 1; } int speex_comment_init(char *packet, int len, speex_comment_t* comment) { // Vorbiscomments are not null terminated // In order to avoid malloc'ing and copying data, // lets return pointers to the internal data. int i, this_length; // Check for smallest possible comment if (len < 2*sizeof(int)) return 0; // Vendor length comment->vendor_length = *(int*) packet; //fwd vendor-length ((int*) packet)++; len -= sizeof(int); if (comment->vendor_length > len) return 0; // Vendor-string comment->vendor = malloc(comment->vendor_length+1); memcpy(comment->vendor, packet, comment->vendor_length); *((char*)comment->vendor+comment->vendor_length) = 0; //fwd vendorstring packet = packet + comment->vendor_length; len -= comment->vendor_length; if (len < sizeof(int)) return 0; // number of comments comment->comment_num = *(int*) packet; comment->comments = calloc(comment->comment_num, sizeof(int)); //fwd number of comments ((int*) packet)++; len -= sizeof(int); if (comment->comment_num > 0 && len < sizeof(int)) return 0; for (i = 0; i < comment->comment_num; i++) { this_length = *(int*) packet; //fwd comment-length ((int*) packet)++; len -= sizeof(int); if (len < this_length) return 0; // Save comment *(comment->comments+i) = malloc(this_length+1); memcpy(*(comment->comments+i), packet, this_length); *(char*) ((*(comment->comments+i))+this_length) = 0; #ifdef DEBUG fprintf(stderr, PACKAGE " comment %d, length: %d, value: %s\n", i, this_length, *(comment->comments+i)); #endif //fwd comment packet = packet + this_length; len -= this_length; } return 1; } char *speex_comment_get_vendor(speex_comment_t* comment) { return comment->vendor; } int speex_comment_get_count(speex_comment_t* comment) { return comment->comment_num; } void speex_comment_free(speex_comment_t* comment) { int i; // Free vendor-string free(comment->vendor); // Free comments for(i=0; i < comment->comment_num; i++) { free( *(comment->comments+i)); } // Free comment index free(comment->comments); return; } // Iterator pattern for fetching all comments void speex_comment_first(speex_comment_t* comment) { comment->icount = 0; return; } char* speex_comment_get_next(speex_comment_t *comment) { char* ret; if (comment->icount >= comment->comment_num) return NULL; ret = *(comment->comments+comment->icount); comment->icount++; return ret; } int speex_comment_isdone(speex_comment_t *comment) { return (comment->icount >= comment->comment_num); } char* speex_comment_get(char* title, speex_comment_t *comment) { char *mod_title; int title_len, i; char* result = NULL; title_len = strlen(title); mod_title = malloc(title_len+2); memcpy(mod_title, title, title_len); *(mod_title+title_len) = '='; *(mod_title+title_len+1) = 0; for (i=0; i < comment->comment_num; i++) { if (strncasecmp(mod_title, *(comment->comments+i), title_len+1) == 0) { result = (*(comment->comments+i))+title_len+1 ; break; } } free(mod_title); return result; }