mirror of
https://github.com/tuxbox-neutrino/libstb-hal.git
synced 2025-08-28 16:01:22 +02:00
libeplayer3: cleanup
This commit is contained in:
@@ -1,839 +0,0 @@
|
||||
/*
|
||||
* Subtitle output to one registered client.
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
/* ***************************** */
|
||||
/* Includes */
|
||||
/* ***************************** */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <memory.h>
|
||||
#include <asm/types.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "output.h"
|
||||
#include "subtitle.h"
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
|
||||
#define SUBTITLE_DEBUG
|
||||
|
||||
#ifdef SUBTITLE_DEBUG
|
||||
|
||||
static short debug_level = 0;
|
||||
|
||||
#define subtitle_printf(level, fmt, x...) do { \
|
||||
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define subtitle_printf(level, fmt, x...)
|
||||
#endif
|
||||
|
||||
#ifndef SUBTITLE_SILENT
|
||||
#define subtitle_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define subtitle_err(fmt, x...)
|
||||
#endif
|
||||
|
||||
/* Error Constants */
|
||||
#define cERR_SUBTITLE_NO_ERROR 0
|
||||
#define cERR_SUBTITLE_ERROR -1
|
||||
|
||||
static const char FILENAME[] = "subtitle.c";
|
||||
|
||||
/*
|
||||
Number, Style, Name,, MarginL, MarginR, MarginV, Effect,, Text
|
||||
|
||||
1038,0,tdk,,0000,0000,0000,,That's not good.
|
||||
1037,0,tdk,,0000,0000,0000,,{\i1}Rack them up, rack them up,{\i0}\N{\i1}rack them up.{\i0} [90]
|
||||
1036,0,tdk,,0000,0000,0000,,Okay, rack them up.
|
||||
*/
|
||||
|
||||
#define PUFFERSIZE 20
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
struct sub_t {
|
||||
char *text;
|
||||
unsigned long long int pts;
|
||||
unsigned long int milliDuration;
|
||||
};
|
||||
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
static pthread_mutex_t mutex;
|
||||
|
||||
static pthread_t thread_sub;
|
||||
|
||||
void *clientData = NULL;
|
||||
void (*clientFunction) (long int, size_t, char *, void *);
|
||||
|
||||
static struct sub_t subPuffer[PUFFERSIZE];
|
||||
static int readPointer = 0;
|
||||
static int writePointer = 0;
|
||||
static int hasThreadStarted = 0;
|
||||
static int isSubtitleOpened = 0;
|
||||
void (*dvbsubWrite)(AVSubtitle *, int64_t) = NULL;
|
||||
void (*dvbsubAssWrite)(AVCodecContext *, AVSubtitle *, int) = NULL;
|
||||
void (*dvbsubAssClear)(void) = NULL;
|
||||
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* MISC Functions */
|
||||
/* ***************************** */
|
||||
static void getMutex(int line)
|
||||
{
|
||||
subtitle_printf(100, "%d requesting mutex\n", line);
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
subtitle_printf(100, "%d received mutex\n", line);
|
||||
}
|
||||
|
||||
static void releaseMutex(int line)
|
||||
{
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
subtitle_printf(100, "%d released mutex\n", line);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int subtitle_ParseSRT(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, "<EFBFBD>", "oe");
|
||||
replace_all(Line, "<EFBFBD>", "ae");
|
||||
replace_all(Line, "<EFBFBD>", "ue");
|
||||
replace_all(Line, "<EFBFBD>", "Oe");
|
||||
replace_all(Line, "<EFBFBD>", "Ae");
|
||||
replace_all(Line, "<EFBFBD>", "Ue");
|
||||
replace_all(Line, "<EFBFBD>", "ss");
|
||||
|
||||
subtitle_printf(10, "<- Text=%s\n", *Line);
|
||||
|
||||
return cERR_SUBTITLE_NO_ERROR;
|
||||
}
|
||||
|
||||
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, "<EFBFBD>", "oe");
|
||||
replace_all(Line, "<EFBFBD>", "ae");
|
||||
replace_all(Line, "<EFBFBD>", "ue");
|
||||
replace_all(Line, "<EFBFBD>", "Oe");
|
||||
replace_all(Line, "<EFBFBD>", "Ae");
|
||||
replace_all(Line, "<EFBFBD>", "Ue");
|
||||
replace_all(Line, "<EFBFBD>", "ss");
|
||||
|
||||
subtitle_printf(10, "<- Text=%s\n", *Line);
|
||||
|
||||
return cERR_SUBTITLE_NO_ERROR;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* **************************** */
|
||||
/* Worker Thread */
|
||||
/* **************************** */
|
||||
|
||||
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");
|
||||
|
||||
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) {
|
||||
|
||||
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
|
||||
return NULL;
|
||||
|
||||
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) {
|
||||
|
||||
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) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* ***************************** */
|
||||
/* Functions */
|
||||
/* ***************************** */
|
||||
|
||||
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 int subtitle_Open(Context_t * context __attribute__ ((unused)))
|
||||
{
|
||||
int i;
|
||||
|
||||
subtitle_printf(10, "\n");
|
||||
|
||||
if (isSubtitleOpened == 1) {
|
||||
subtitle_err("already opened! ignoring\n");
|
||||
return cERR_SUBTITLE_ERROR;
|
||||
}
|
||||
|
||||
getMutex(__LINE__);
|
||||
|
||||
//Reset all
|
||||
readPointer = 0;
|
||||
writePointer = 0;
|
||||
|
||||
for (i = 0; i < PUFFERSIZE; i++) {
|
||||
subPuffer[i].text = NULL;
|
||||
subPuffer[i].pts = 0;
|
||||
subPuffer[i].milliDuration = 0;
|
||||
}
|
||||
|
||||
isSubtitleOpened = 1;
|
||||
|
||||
releaseMutex(__LINE__);
|
||||
|
||||
subtitle_printf(10, "<\n");
|
||||
|
||||
return cERR_SUBTITLE_NO_ERROR;
|
||||
}
|
||||
|
||||
static int subtitle_Close(Context_t * context __attribute__ ((unused)))
|
||||
{
|
||||
int i;
|
||||
|
||||
subtitle_printf(10, "\n");
|
||||
|
||||
getMutex(__LINE__);
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
isSubtitleOpened = 0;
|
||||
|
||||
releaseMutex(__LINE__);
|
||||
|
||||
subtitle_printf(10, "<\n");
|
||||
|
||||
return cERR_SUBTITLE_NO_ERROR;
|
||||
}
|
||||
|
||||
static int subtitle_Play(Context_t * context)
|
||||
{
|
||||
subtitle_printf(10, "\n");
|
||||
|
||||
if (hasThreadStarted == 0) {
|
||||
pthread_attr_t attr;
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
|
||||
if (pthread_create
|
||||
(&thread_sub, &attr, &SubtitleThread, (void *) context) != 0) {
|
||||
subtitle_err("Error creating thread\n");
|
||||
hasThreadStarted = 0;
|
||||
} else {
|
||||
subtitle_printf(10, "Created thread\n");
|
||||
hasThreadStarted = 1;
|
||||
}
|
||||
} else {
|
||||
subtitle_err("thread already created.\n");
|
||||
return cERR_SUBTITLE_ERROR;
|
||||
}
|
||||
|
||||
subtitle_printf(10, "<\n");
|
||||
|
||||
return cERR_SUBTITLE_NO_ERROR;
|
||||
}
|
||||
|
||||
static int subtitle_Stop(Context_t * context __attribute__ ((unused)))
|
||||
{
|
||||
int wait_time = 20;
|
||||
int i;
|
||||
|
||||
subtitle_printf(10, "\n");
|
||||
|
||||
while ((hasThreadStarted != 0) && (--wait_time) > 0) {
|
||||
subtitle_printf(10,
|
||||
"Waiting for subtitle thread to terminate itself, will try another %d times\n",
|
||||
wait_time);
|
||||
usleep(100000);
|
||||
}
|
||||
|
||||
if (wait_time == 0) {
|
||||
subtitle_err("Timeout waiting for thread!\n");
|
||||
|
||||
return cERR_SUBTITLE_ERROR;
|
||||
}
|
||||
|
||||
hasThreadStarted = 0;
|
||||
|
||||
/* konfetti: thread has ended, so nobody will eat the date...
|
||||
* free the data...
|
||||
*/
|
||||
|
||||
getMutex(__LINE__);
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
releaseMutex(__LINE__);
|
||||
|
||||
subtitle_printf(10, "<\n");
|
||||
|
||||
return cERR_SUBTITLE_NO_ERROR;
|
||||
}
|
||||
|
||||
void subtitle_SignalConnect(void (*fkt) (long int, size_t, char *, void *))
|
||||
{
|
||||
subtitle_printf(10, "%p\n", fkt);
|
||||
|
||||
clientFunction = fkt;
|
||||
}
|
||||
|
||||
void subtitle_SignalConnectBuffer(void *data)
|
||||
{
|
||||
subtitle_printf(10, "%p\n", data);
|
||||
|
||||
clientData = data;
|
||||
}
|
||||
|
||||
static int Command(void *_context, OutputCmd_t command, void *argument)
|
||||
{
|
||||
Context_t *context = (Context_t *) _context;
|
||||
int ret = cERR_SUBTITLE_NO_ERROR;
|
||||
|
||||
subtitle_printf(50, "%d\n", command);
|
||||
|
||||
switch (command) {
|
||||
case OUTPUT_OPEN:{
|
||||
ret = subtitle_Open(context);
|
||||
break;
|
||||
}
|
||||
case OUTPUT_CLOSE:{
|
||||
ret = subtitle_Close(context);
|
||||
break;
|
||||
}
|
||||
case OUTPUT_PLAY:{
|
||||
ret = subtitle_Play(context);
|
||||
break;
|
||||
}
|
||||
case OUTPUT_STOP:{
|
||||
ret = subtitle_Stop(context);
|
||||
break;
|
||||
}
|
||||
case OUTPUT_SWITCH:{
|
||||
subtitle_err("Subtitle Switch not implemented\n");
|
||||
ret = cERR_SUBTITLE_ERROR;
|
||||
break;
|
||||
}
|
||||
case OUTPUT_GET_SUBTITLE_OUTPUT:{
|
||||
SubtitleOutputDef_t *out = (SubtitleOutputDef_t *) argument;
|
||||
out->dvbsubWrite = (void (*)(void *, int64_t))dvbsubWrite;
|
||||
out->dvbsubAssWrite = (void (*)(void *, void *, int))dvbsubAssWrite;
|
||||
out->dvbsubAssClear = (void (*)(void))dvbsubAssClear;
|
||||
break;
|
||||
}
|
||||
case OUTPUT_SET_SUBTITLE_OUTPUT:{
|
||||
SubtitleOutputDef_t *out = (SubtitleOutputDef_t *) argument;
|
||||
dvbsubWrite = (void (*)(AVSubtitle *, int64_t))out->dvbsubWrite;
|
||||
dvbsubAssWrite = (void (*)(AVCodecContext *, AVSubtitle *, int))out->dvbsubAssWrite;
|
||||
dvbsubAssClear = (void (*)(void))out->dvbsubAssClear;
|
||||
break;
|
||||
}
|
||||
case OUTPUT_SUBTITLE_REGISTER_FUNCTION:{
|
||||
subtitle_SignalConnect(argument);
|
||||
break;
|
||||
}
|
||||
case OUTPUT_SUBTITLE_REGISTER_BUFFER:{
|
||||
subtitle_SignalConnectBuffer(argument);
|
||||
break;
|
||||
}
|
||||
case OUTPUT_FLUSH:{
|
||||
subtitle_err("Subtitle Flush not implemented\n");
|
||||
ret = cERR_SUBTITLE_ERROR;
|
||||
break;
|
||||
}
|
||||
case OUTPUT_PAUSE:{
|
||||
subtitle_err("Subtitle Pause not implemented\n");
|
||||
ret = cERR_SUBTITLE_ERROR;
|
||||
break;
|
||||
}
|
||||
case OUTPUT_CONTINUE:{
|
||||
subtitle_err("Subtitle Continue not implemented\n");
|
||||
ret = cERR_SUBTITLE_ERROR;
|
||||
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 char *SubtitleCapabilitis[] = { "subtitle", NULL };
|
||||
|
||||
struct Output_s SubtitleOutput = {
|
||||
"Subtitle",
|
||||
&Command,
|
||||
&Write,
|
||||
SubtitleCapabilitis
|
||||
};
|
@@ -1,187 +0,0 @@
|
||||
/*
|
||||
* framebuffer output/writer handling.
|
||||
*
|
||||
* This is a hacky implementation of a framebuffer output for the subtitling.
|
||||
* This is ment as a POV, later this should be implemented in enigma2 and
|
||||
* neutrino.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
/* ***************************** */
|
||||
/* Includes */
|
||||
/* ***************************** */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <memory.h>
|
||||
#include <asm/types.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "output.h"
|
||||
#include "debug.h"
|
||||
#include "misc.h"
|
||||
#include "writer.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
|
||||
#define FB_DEBUG
|
||||
|
||||
#ifdef FB_DEBUG
|
||||
|
||||
static short debug_level = 0;
|
||||
|
||||
#define fb_printf(level, fmt, x...) do { \
|
||||
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define fb_printf(level, fmt, x...)
|
||||
#endif
|
||||
|
||||
#ifndef FB_SILENT
|
||||
#define fb_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define fb_err(fmt, x...)
|
||||
#endif
|
||||
|
||||
#define _r(c) ((c)>>24)
|
||||
#define _g(c) (((c)>>16)&0xFF)
|
||||
#define _b(c) (((c)>>8)&0xFF)
|
||||
#define _a(c) ((c)&0xFF)
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* MISC Functions */
|
||||
/* ***************************** */
|
||||
|
||||
|
||||
/* ***************************** */
|
||||
/* Writer Functions */
|
||||
/* ***************************** */
|
||||
|
||||
static int reset()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int writeData(void *_call)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
WriterFBCallData_t *call = (WriterFBCallData_t *) _call;
|
||||
|
||||
fb_printf(100, "\n");
|
||||
|
||||
if (!call) {
|
||||
fb_err("call data is NULL...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!call->destination) {
|
||||
fb_err("frame buffer == NULL. ignoring ...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dst_stride = call->destStride / sizeof(uint32_t);
|
||||
int dst_delta = dst_stride - call->Width;
|
||||
uint32_t *dst = call->destination + call->y * dst_stride + call->x;
|
||||
|
||||
if (call->data) {
|
||||
int src_delta = call->Stride - call->Width;
|
||||
unsigned char *src = call->data;
|
||||
static uint32_t last_color = 0, colortable[256];
|
||||
|
||||
if (last_color != call->color) {
|
||||
// call->color is rgba, our spark frame buffer is argb
|
||||
uint32_t c = call->color >> 8, a = 255 - (call->color & 0xff);
|
||||
int i;
|
||||
for (i = 0; i < 256; i++) {
|
||||
uint32_t k = (a * i) >> 8;
|
||||
colortable[i] = k ? (c | (k << 24)) : 0;
|
||||
}
|
||||
last_color = call->color;
|
||||
}
|
||||
|
||||
fb_printf(100, "x %d\n", call->x);
|
||||
fb_printf(100, "y %d\n", call->y);
|
||||
fb_printf(100, "width %d\n", call->Width);
|
||||
fb_printf(100, "height %d\n", call->Height);
|
||||
fb_printf(100, "stride %d\n", call->Stride);
|
||||
fb_printf(100, "color 0x%.8x\n", call->color);
|
||||
fb_printf(100, "data %p\n", call->data);
|
||||
fb_printf(100, "dest %p\n", call->destination);
|
||||
fb_printf(100, "dest.stride %d\n", call->destStride);
|
||||
|
||||
unsigned char *src_final = src + call->Height * call->Width;
|
||||
for (; src < src_final; dst += dst_delta, src += src_delta) {
|
||||
u_char *src_end = src + call->Width;
|
||||
for (; src < src_end; dst++, src++) {
|
||||
uint32_t c = colortable[*src];
|
||||
if (c)
|
||||
*dst = c;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uint32_t *dst_final =
|
||||
dst + call->Width + call->Height * dst_stride;
|
||||
for (; dst < dst_final; dst += dst_delta) {
|
||||
uint32_t *dst_end = dst + call->Width;
|
||||
for (; dst < dst_end; dst++)
|
||||
*dst = 0;
|
||||
}
|
||||
}
|
||||
|
||||
fb_printf(100, "< %d\n", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* ***************************** */
|
||||
/* Writer Definition */
|
||||
/* ***************************** */
|
||||
static WriterCaps_t caps = {
|
||||
"framebuffer",
|
||||
eGfx,
|
||||
"framebuffer",
|
||||
0
|
||||
};
|
||||
|
||||
struct Writer_s WriterFramebuffer = {
|
||||
&reset,
|
||||
&writeData,
|
||||
NULL,
|
||||
&caps
|
||||
};
|
Reference in New Issue
Block a user