int subtitle_ParseSSA (char **Line) { if ((Line == NULL) || (*Line == NULL)) { subtitle_err("null pointer passed\n"); return cERR_SUBTITLE_ERROR; } subtitle_printf(20, "-> Text=%s\n", *Line); replace_all(Line, "\x0d", ""); replace_all(Line, "\n\n", "\\N"); replace_all(Line, "\n", ""); replace_all(Line, "\\N", "\n"); replace_all(Line, "ö", "oe"); replace_all(Line, "ä", "ae"); replace_all(Line, "ü", "ue"); replace_all(Line, "Ö", "Oe"); replace_all(Line, "Ä", "Ae"); replace_all(Line, "Ü", "Ue"); replace_all(Line, "ß", "ss"); subtitle_printf(10, "<- Text=%s\n", *Line); return cERR_SUBTITLE_NO_ERROR; }
static int Command(Context_t *context, OutputCmd_t command, void *argument) { int ret = cERR_SUBTITLE_NO_ERROR; subtitle_printf(50, "%d\n", command); switch(command) { case OUTPUT_GET_SUBTITLE_DATA: *((Subtitle_Out_t **)argument) = (Subtitle_Out_t *) &subtitleData[readPointer]; subtitle_printf(50, "Get data %d Text:%s [%lld] -> [%lld]\n", readPointer, (const char *)subtitleData[readPointer].data, subtitleData[readPointer].pts, subtitleData[readPointer].pts + subtitleData[readPointer].duration); break; case OUTPUT_DEL_SUBTITLE_DATA: ret = subtitle_DelData(); break; case OUTPUT_OPEN: ret = subtitle_Open(); break; case OUTPUT_CLOSE: ret = subtitle_Close(); break; default: subtitle_err("OutputCmd %d not supported!\n", command); ret = cERR_SUBTITLE_ERROR; break; } subtitle_printf(50, "exiting with value %d\n", ret); return ret; }
static int subtitle_DelData() { subtitle_printf(10, " %d\n", readPointer); if (subtitleData[readPointer].data == NULL) { subtitle_err("null pointer in data\n"); } else { free(subtitleData[readPointer].data); subtitleData[readPointer].data = NULL; } subtitleData[readPointer].pts = 0; subtitleData[readPointer].duration = 0; readPointer++; if (readPointer == PUFFERSIZE) { readPointer = 0; } return cERR_SUBTITLE_NO_ERROR; }
int getNextSub(char ** text, unsigned long long int * pts, long int * milliDuration) { subtitle_printf(50, "index %d\n", readPointer); if (text == NULL) { subtitle_err("null pointer passed\n"); return cERR_SUBTITLE_ERROR; } getMutex(__LINE__); if (subPuffer[readPointer].text == NULL) { /* this is acutally not an error, because it may happen * that there is no subtitle for a while */ subtitle_printf(200, "null in subPuffer\n"); releaseMutex(__LINE__); return cERR_SUBTITLE_ERROR; } *text = strdup(subPuffer[readPointer].text); free(subPuffer[readPointer].text); subPuffer[readPointer].text = NULL; *pts = subPuffer[readPointer].pts; subPuffer[readPointer].pts = 0; *milliDuration = subPuffer[readPointer].milliDuration; subPuffer[readPointer].milliDuration = 0; readPointer++; if (readPointer == PUFFERSIZE) readPointer = 0; if (writePointer == readPointer) { /* this may happen, in normal case the reader is ones ahead the * writer. So this is the normal case that we eat the data * and have the reader reached. */ subtitle_printf(20, "ups something went wrong. no more writers? \n"); } releaseMutex(__LINE__); subtitle_printf(20, "readPointer %d\n",readPointer); subtitle_printf(10, "<\n"); return cERR_SUBTITLE_NO_ERROR; }
int subtitle_ParseASS (char **Line) { char* Text; int i; char* ptr1; if ((Line == NULL) || (*Line == NULL)) { subtitle_err("null pointer passed\n"); return cERR_SUBTITLE_ERROR; } Text = strdup(*Line); subtitle_printf(10, "-> Text = %s\n", *Line); ptr1 = Text; for (i=0; i < 9 && *ptr1 != '\0'; ptr1++) { subtitle_printf(20, "%s",ptr1); if (*ptr1 == ',') i++; } free(*Line); *Line = strdup(ptr1); free(Text); replace_all(Line, "\\N", "\n"); replace_all(Line, "{\\i1}", "<i>"); replace_all(Line, "{\\i0}", "</i>"); subtitle_printf(10, "<- Text=%s\n", *Line); return cERR_SUBTITLE_NO_ERROR; }
void replace_all(char ** string, char * search, char * replace) { int len = 0; char * ptr = NULL; char tempString[512]; char newString[512]; newString[0] = '\0'; if ((string == NULL) || (*string == NULL) || (search == NULL) || (replace == NULL)) { subtitle_err("null pointer passed\n"); return; } strncpy(tempString, *string, 511); tempString[511] = '\0'; free(*string); while ((ptr = strstr(tempString, search)) != NULL) { len = ptr - tempString; strncpy(newString, tempString, len); newString[len] = '\0'; strcat(newString, replace); len += strlen(search); strcat(newString, tempString+len); strcpy(tempString, newString); } subtitle_printf(20, "strdup in line %d\n", __LINE__); if(newString[0] != '\0') *string = strdup(newString); else *string = strdup(tempString); }
static int Write(void* _context, void *data) { Context_t * context = (Context_t *) _context; char * Encoding = NULL; char * Text; SubtitleOut_t * out; int DataLength; unsigned long long int Pts; float Duration; subtitle_printf(10, "\n"); if (data == NULL) { subtitle_err("null pointer passed\n"); return cERR_SUBTITLE_ERROR; } out = (SubtitleOut_t*) data; if (out->type == eSub_Txt) { Text = strdup((const char*) out->u.text.data); } else { /* fixme handle gfx subs from container_ass and send it to * the callback. this must be implemented also in e2/neutrino * then. */ subtitle_err("subtitle gfx currently not handled\n"); return cERR_SUBTITLE_ERROR; } DataLength = out->u.text.len; Pts = out->pts; Duration = out->duration; context->manager->subtitle->Command(context, MANAGER_GETENCODING, &Encoding); if (Encoding == NULL) { subtitle_err("encoding unknown\n"); free(Text); return cERR_SUBTITLE_ERROR; } subtitle_printf(20, "Encoding:%s Text:%s Len:%d\n", Encoding,Text, DataLength); if ( !strncmp("S_TEXT/SSA", Encoding, 10) || !strncmp("S_SSA", Encoding, 5)) subtitle_ParseSSA(&Text); else if(!strncmp("S_TEXT/ASS", Encoding, 10) || !strncmp("S_AAS", Encoding, 5)) subtitle_ParseASS(&Text); else if(!strncmp("S_TEXT/SRT", Encoding, 10) || !strncmp("S_SRT", Encoding, 5)) subtitle_ParseSRT(&Text); else { subtitle_err("unknown encoding %s\n", Encoding); return cERR_SUBTITLE_ERROR; } subtitle_printf(10, "Text:%s Duration:%f\n", Text,Duration); addSub(context, Text, Pts, Duration * 1000); free(Text); free(Encoding); subtitle_printf(10, "<\n"); return cERR_SUBTITLE_NO_ERROR; }
static void* SubtitleThread(void* data) { Context_t *context = (Context_t*) data; char * subText = NULL; long int subMilliDuration = 0; unsigned long long int subPts = 0; unsigned long long int Pts = 0; subtitle_printf(10, "\n"); hasThreadStarted = 1; while ( context->playback->isCreationPhase ) { subtitle_err("Thread waiting for end of init phase...\n"); usleep(1000); } subtitle_printf(10, "done\n"); while ( context && context->playback && context->playback->isPlaying && hasThreadStarted == 1) { int curtrackid = -1; if (context && context->manager && context->manager->subtitle) context->manager->subtitle->Command(context, MANAGER_GET, &curtrackid); subtitle_printf(50, "curtrackid %d\n", curtrackid); if (curtrackid >= 0) { if (getNextSub(&subText, &subPts, &subMilliDuration) != 0) { usleep(500000); continue; } if (context && context->playback) context->playback->Command(context, PLAYBACK_PTS, &Pts); else break; if(Pts > subPts) { subtitle_printf(10,"subtitle is to late, ignoring\n"); if(subText != NULL) free(subText); continue; } subtitle_printf(20, "Pts:%llu < subPts%llu duration %ld\n", Pts, subPts,subMilliDuration); while ( context && context->playback && context->playback->isPlaying && Pts < subPts && hasThreadStarted == 1) { unsigned long int diff = subPts - Pts; diff = (diff*1000)/90.0; subtitle_printf(50, "DIFF: %lud\n", diff); if(diff > 100) usleep(diff); if (context && context->playback) context->playback->Command(context, PLAYBACK_PTS, &Pts); else { subtitle_err("no playback ? terminated?\n"); break; } subtitle_printf(20, "cur: %llu wanted: %llu\n", Pts, subPts); } if ( context && context->playback && context->playback->isPlaying && subText != NULL && hasThreadStarted == 1) { if(clientFunction != NULL) clientFunction(subMilliDuration, strlen(subText), subText, clientData); else subtitle_printf(10, "writing Sub failed (%ld) (%d) \"%s\"\n", subMilliDuration, strlen(subText), subText); free(subText); } } /* trackID >= 0 */ else //Wait usleep(500000); } /* outer while */ subtitle_printf(0, "has ended\n"); hasThreadStarted = 0; return NULL; }
void addSub(Context_t *context, char * text, unsigned long long int pts, unsigned long int milliDuration) { int count = 20; subtitle_printf(50, "index %d\n", writePointer); if(context && context->playback && !context->playback->isPlaying) { subtitle_err("1. aborting ->no playback\n"); return; } if (text == NULL) { subtitle_err("null pointer passed\n"); return; } if (pts == 0) { subtitle_err("pts 0\n"); return; } if (milliDuration == 0) { subtitle_err("duration 0\n"); return; } while (subPuffer[writePointer].text != NULL) { //List is full, wait till we got some free space if(context && context->playback && !context->playback->isPlaying) { subtitle_err("2. aborting ->no playback\n"); return; } /* konfetti: we dont want to block forever here. if no buffer * is available we start ring from the beginning and loose some stuff * which is acceptable! */ subtitle_printf(10, "waiting on free buffer %d - %d (%d) ...\n", writePointer, readPointer, count); usleep(10000); count--; if (count == 0) { subtitle_err("abort waiting on buffer...\n"); break; } } subtitle_printf(20, "from mkv: %s pts:%lld milliDuration:%lud\n",text,pts,milliDuration); getMutex(__LINE__); if (count == 0) { int i; subtitle_err("freeing not delivered data\n"); //Reset all readPointer = 0; writePointer = 0; for (i = 0; i < PUFFERSIZE; i++) { if (subPuffer[i].text != NULL) free(subPuffer[i].text); subPuffer[i].text = NULL; subPuffer[i].pts = 0; subPuffer[i].milliDuration = 0; } } subPuffer[writePointer].text = strdup(text); subPuffer[writePointer].pts = pts; subPuffer[writePointer].milliDuration = milliDuration; writePointer++; if (writePointer == PUFFERSIZE) writePointer = 0; if (writePointer == readPointer) { /* this should not happen, and means that there is nor reader or * the reader has performance probs ;) * the recovery is done at startup of this function - but next time */ subtitle_err("ups something went wrong. no more readers? \n"); } releaseMutex(__LINE__); subtitle_printf(10, "<\n"); }
static int Write(Context_t *context, void *data) { subtitle_printf(10, "\n"); char *Encoding = NULL; int msg = 0; if (data == NULL) { subtitle_err("null pointer passed\n"); return cERR_SUBTITLE_ERROR; } context->manager->subtitle->Command(context, MANAGER_GETENCODING, &Encoding); if (Encoding == NULL) { subtitle_err("encoding unknown\n"); return cERR_SUBTITLE_ERROR; } Subtitle_Out_t* out = (Subtitle_Out_t*) data; if (subtitleData[writePointer].data != NULL) { subtitle_err("subtitle list is full, dlete %d\n", writePointer); free(subtitleData[writePointer].data); subtitleData[writePointer].data = NULL; subtitleData[writePointer].pts = 0; subtitleData[writePointer].duration = 0; } if (!strncmp("S_TEXT/ASS", Encoding, 10)) { subtitleData[writePointer].data = (uint8_t *)strdup(ass_get_text((char *)out->data)); } else if (!strncmp("S_TEXT/SUBRIP", Encoding, 13) || !strncmp("S_TEXT/SRT", Encoding, 10) || !strncmp("S_TEXT/SSA", Encoding, 10)) { subtitleData[writePointer].data = (uint8_t *)strdup((const char *)out->data); } else { subtitle_err("unknown encoding %s\n", Encoding); return cERR_SUBTITLE_ERROR; } subtitleData[writePointer].pts = out->pts; subtitleData[writePointer].duration = out->duration; subtitle_printf(10, "Encoding:%s Text:%s [%lld] -> [%lld]\n", Encoding, (const char *)subtitleData[writePointer].data, subtitleData[writePointer].pts, subtitleData[writePointer].pts + subtitleData[writePointer].duration); writePointer++; if (writePointer == PUFFERSIZE) { writePointer = 0; } /* Tell enigma2 that we have subtitles */ context->playback->Command(context, PLAYBACK_SEND_MESSAGE, (void *) &msg); subtitle_printf(10, "<\n"); return cERR_SUBTITLE_NO_ERROR; }